1 /*
2  * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /**
18  * DOC: contains EPCS APIs
19  */
20 
21 #include <wlan_objmgr_pdev_obj.h>
22 #include <wlan_objmgr_vdev_obj.h>
23 #include <wlan_objmgr_peer_obj.h>
24 #include <wlan_mlo_mgr_public_structs.h>
25 #include <wlan_mlo_mgr_cmn.h>
26 #include <qdf_util.h>
27 #include <wlan_cm_api.h>
28 #include <utils_mlo.h>
29 #include <wlan_mlo_epcs.h>
30 
31 /**
32  * wlan_mlo_is_node_epcs_authorized() - API to check mac address is
33  * EPCS authorized or not
34  * @ml_peer: pointer to mlo context of peer
35  *
36  * Return: QDF_STATUS
37  */
38 static QDF_STATUS
wlan_mlo_is_node_epcs_authorized(struct wlan_mlo_peer_context * ml_peer)39 wlan_mlo_is_node_epcs_authorized(struct wlan_mlo_peer_context *ml_peer)
40 {
41 	struct wlan_mlo_dev_context *mlo_dev_ctx;
42 	struct wlan_epcs_context *epcs_ctx;
43 	enum QDF_OPMODE opmode;
44 	struct wlan_objmgr_vdev *vdev = NULL;
45 	int i;
46 
47 	if (!ml_peer) {
48 		epcs_err("ml_peer is null");
49 		return QDF_STATUS_E_INVAL;
50 	}
51 
52 	mlo_dev_ctx = ml_peer->ml_dev;
53 	if (!mlo_dev_ctx) {
54 		epcs_err("mlo dev ctx is null");
55 		return QDF_STATUS_E_INVAL;
56 	}
57 
58 	/* Get first valid vdev */
59 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
60 		if (!mlo_dev_ctx->wlan_vdev_list[i])
61 			continue;
62 
63 		vdev = mlo_dev_ctx->wlan_vdev_list[i];
64 		opmode = wlan_vdev_mlme_get_opmode(vdev);
65 		break;
66 	}
67 
68 	if (!vdev) {
69 		epcs_err("no valid vdev entry found");
70 		return QDF_STATUS_E_INVAL;
71 	}
72 
73 	epcs_debug("ml peer type %d", opmode);
74 	if (opmode != QDF_SAP_MODE)
75 		return QDF_STATUS_SUCCESS;
76 
77 	epcs_ctx = &mlo_dev_ctx->epcs_ctx;
78 	if (!epcs_ctx) {
79 		epcs_err("epcs info is null");
80 		return QDF_STATUS_E_INVAL;
81 	}
82 
83 	epcs_dev_lock_acquire(epcs_ctx);
84 	for (i = 0; i < EPCS_MAX_AUTHORIZE_MAC_ADDR; i++) {
85 		if (epcs_ctx->authorize_info[i].valid &&
86 		    !qdf_mem_cmp(epcs_ctx->authorize_info[i].peer_mld_mac,
87 				 ml_peer->peer_mld_addr.bytes,
88 				 QDF_MAC_ADDR_SIZE)) {
89 			epcs_dev_lock_release(epcs_ctx);
90 			return QDF_STATUS_SUCCESS;
91 		}
92 	}
93 	epcs_dev_lock_release(epcs_ctx);
94 
95 	return QDF_STATUS_E_INVAL;
96 }
97 
98 /**
99  * mlo_process_ml_priorityaccess_ie() - API to parse Priority access ML IE
100  * @ml_ie: Pointer to start of ML IE
101  * @ml_ie_len: Length of ML IE
102  * @priority_access_info: pointer to fill multi link priority access information
103  *
104  * Return: QDF_STATUS
105  */
106 static QDF_STATUS
mlo_process_ml_priorityaccess_ie(uint8_t * ml_ie,qdf_size_t ml_ie_len,struct ml_pa_info * priority_access_info)107 mlo_process_ml_priorityaccess_ie(uint8_t *ml_ie, qdf_size_t ml_ie_len,
108 				 struct ml_pa_info *priority_access_info)
109 {
110 	uint8_t *ml_pa_ie = NULL;
111 	qdf_size_t ml_pa_ie_len = 0;
112 	QDF_STATUS status;
113 
114 	if (!ml_ie) {
115 		mlo_err("NULL ml_ie");
116 		return QDF_STATUS_E_INVAL;
117 	}
118 
119 	if (!priority_access_info) {
120 		mlo_err("NULL priority_access_info");
121 		return QDF_STATUS_E_INVAL;
122 	}
123 
124 	status = util_find_mlie_by_variant(ml_ie,
125 					   ml_ie_len,
126 					   &ml_pa_ie,
127 					   &ml_pa_ie_len,
128 					   WLAN_ML_VARIANT_PRIORITYACCESS);
129 
130 	if (QDF_IS_STATUS_ERROR(status) || !ml_pa_ie) {
131 		mlo_debug("ML IE for reconfig variant not found");
132 		return QDF_STATUS_E_INVAL;
133 	}
134 	epcs_debug("PAV ML IE with length %zu is present", ml_pa_ie_len);
135 
136 	status = util_get_pav_mlie_link_info(ml_pa_ie, ml_pa_ie_len,
137 					     priority_access_info);
138 	if (QDF_IS_STATUS_ERROR(status)) {
139 		mlo_err("Unable to get sta link info from ML PAV IE");
140 		return QDF_STATUS_E_INVAL;
141 	}
142 	return QDF_STATUS_SUCCESS;
143 }
144 
145 /**
146  * wlan_mlo_parse_epcs_request_action_frame() - API to parse EPCS request action
147  * frame.
148  * @epcs: Pointer to EPCS structure
149  * @action_frm: Pointer to action frame
150  * @frm_len: frame length
151  *
152  * Return: QDF_STATUS
153  */
154 static QDF_STATUS
wlan_mlo_parse_epcs_request_action_frame(struct wlan_epcs_info * epcs,struct wlan_action_frame * action_frm,uint32_t frm_len)155 wlan_mlo_parse_epcs_request_action_frame(struct wlan_epcs_info *epcs,
156 					 struct wlan_action_frame *action_frm,
157 					 uint32_t frm_len)
158 {
159 	struct epcs_frm *epcs_action_frm;
160 	struct ml_pa_info *priority_access_info = &epcs->pa_info;
161 	uint8_t *pa_ie;
162 	uint16_t pa_ie_len;
163 
164 	/*
165 	 * EPCS request action frame
166 	 *
167 	 *   1-byte     1-byte     1-byte    variable
168 	 *--------------------------------------------
169 	 * |         |           |        |          |
170 	 * | Category| Protected | Dialog | PA ML IE |
171 	 * |         |    EHT    | token  |          |
172 	 * |         |  Action   |        |          |
173 	 *--------------------------------------------
174 	 */
175 
176 	epcs_action_frm = (struct epcs_frm *)action_frm;
177 
178 	epcs->cat = epcs_action_frm->protected_eht_action;
179 	epcs->dialog_token = epcs_action_frm->dialog_token;
180 	epcs_info("EPCS frame rcv : category:%d action:%d dialog_token:%d frmlen %d",
181 		  epcs_action_frm->category,
182 		  epcs_action_frm->protected_eht_action,
183 		  epcs_action_frm->dialog_token, frm_len);
184 
185 	if (frm_len > EPCS_REQ_MIN_LENGTH) {
186 		pa_ie = (uint8_t *)epcs_action_frm + EPCS_REQ_MIN_LENGTH;
187 		pa_ie_len = frm_len - EPCS_REQ_MIN_LENGTH;
188 		return mlo_process_ml_priorityaccess_ie(pa_ie,
189 							pa_ie_len,
190 							priority_access_info);
191 	} else {
192 		return QDF_STATUS_SUCCESS;
193 	}
194 }
195 
196 /**
197  * wlan_mlo_parse_epcs_response_action_frame() - API to parse EPCS response
198  * action frame.
199  * @epcs: Pointer to EPCS structure
200  * @action_frm: Pointer to action frame
201  * @frm_len: frame length
202  *
203  * Return: QDF_STATUS
204  */
205 static QDF_STATUS
wlan_mlo_parse_epcs_response_action_frame(struct wlan_epcs_info * epcs,struct wlan_action_frame * action_frm,uint32_t frm_len)206 wlan_mlo_parse_epcs_response_action_frame(struct wlan_epcs_info *epcs,
207 					  struct wlan_action_frame *action_frm,
208 					  uint32_t frm_len)
209 {
210 	struct epcs_frm *epcs_action_frm;
211 	struct ml_pa_info *priority_access_info = &epcs->pa_info;
212 	uint8_t *pa_ie;
213 	uint16_t pa_ie_len;
214 
215 	/*
216 	 * EPCS response action frame
217 	 *
218 	 *   1-byte     1-byte     1-byte   1-byte   variable
219 	 *----------------------------------------------------
220 	 * |         |           |        |        |         |
221 	 * | Category| Protected | Dialog | Status | PA   IE |
222 	 * |         |    EHT    | token  |  code  |         |
223 	 * |         |  Action   |        |        |         |
224 	 *----------------------------------------------------
225 	 */
226 
227 	epcs_action_frm = (struct epcs_frm *)action_frm;
228 
229 	epcs->cat = epcs_action_frm->protected_eht_action;
230 	epcs->dialog_token = epcs_action_frm->dialog_token;
231 	QDF_SET_BITS(epcs->status, 0, 8, epcs_action_frm->resp.status_code[0]);
232 	QDF_SET_BITS(epcs->status, 8, 8, epcs_action_frm->resp.status_code[1]);
233 	epcs_info("EPCS frame rcv : category:%d action:%d dialog_token:%d status %x %x frmlen %d",
234 		  epcs_action_frm->category,
235 		  epcs_action_frm->protected_eht_action,
236 		  epcs_action_frm->dialog_token,
237 		  epcs_action_frm->resp.status_code[0],
238 		  epcs_action_frm->resp.status_code[1], frm_len);
239 
240 	if (frm_len > EPCS_RESP_MIN_LENGTH) {
241 		pa_ie = (uint8_t *)epcs_action_frm + EPCS_RESP_MIN_LENGTH;
242 		pa_ie_len = frm_len - EPCS_RESP_MIN_LENGTH;
243 		return mlo_process_ml_priorityaccess_ie(pa_ie,
244 							pa_ie_len,
245 							priority_access_info);
246 	} else {
247 		return QDF_STATUS_SUCCESS;
248 	}
249 }
250 
251 /**
252  * wlan_mlo_parse_epcs_teardown_action_frame() - API to parse EPCS teardown
253  * action frame.
254  * @epcs: Pointer to EPCS structure
255  * @action_frm: Pointer to action frame
256  * @frm_len: frame length
257  *
258  * Return: QDF_STATUS
259  */
260 static QDF_STATUS
wlan_mlo_parse_epcs_teardown_action_frame(struct wlan_epcs_info * epcs,struct wlan_action_frame * action_frm,uint32_t frm_len)261 wlan_mlo_parse_epcs_teardown_action_frame(struct wlan_epcs_info *epcs,
262 					  struct wlan_action_frame *action_frm,
263 					  uint32_t frm_len)
264 {
265 	struct epcs_frm *epcs_action_frm;
266 
267 	/*
268 	 * EPCS teardown action frame
269 	 *
270 	 *   1-byte     1-byte
271 	 *------------------------
272 	 * |         |           |
273 	 * | Category| Protected |
274 	 * |         |    EHT    |
275 	 * |         |  Action   |
276 	 *------------------------
277 	 */
278 
279 	epcs_action_frm = (struct epcs_frm *)action_frm;
280 
281 	epcs->cat = epcs_action_frm->protected_eht_action;
282 	epcs_info("EPCS frame rcv : category:%d action:%d frmlen %d",
283 		  epcs_action_frm->category,
284 		  epcs_action_frm->protected_eht_action, frm_len);
285 
286 	return QDF_STATUS_SUCCESS;
287 }
288 
289 QDF_STATUS
wlan_mlo_parse_epcs_action_frame(struct wlan_epcs_info * epcs,struct wlan_action_frame * action_frm,uint32_t frm_len)290 wlan_mlo_parse_epcs_action_frame(struct wlan_epcs_info *epcs,
291 				 struct wlan_action_frame *action_frm,
292 				 uint32_t frm_len)
293 {
294 	QDF_STATUS ret_val = QDF_STATUS_SUCCESS;
295 
296 	switch (action_frm->action) {
297 	case WLAN_EPCS_CATEGORY_REQUEST:
298 		return wlan_mlo_parse_epcs_request_action_frame(
299 				epcs, action_frm, frm_len);
300 	case WLAN_EPCS_CATEGORY_RESPONSE:
301 		return wlan_mlo_parse_epcs_response_action_frame(
302 				epcs, action_frm, frm_len);
303 	case WLAN_EPCS_CATEGORY_TEARDOWN:
304 		return wlan_mlo_parse_epcs_teardown_action_frame(
305 				epcs, action_frm, frm_len);
306 	default:
307 		ret_val = QDF_STATUS_E_INVAL;
308 			epcs_err("Invalid action :%d", action_frm->action);
309 	}
310 
311 	return ret_val;
312 }
313 
314 static uint8_t *
wlan_mlo_add_epcs_request_action_frame(uint8_t * frm,struct wlan_action_frame_args * args,uint8_t * buf)315 wlan_mlo_add_epcs_request_action_frame(uint8_t *frm,
316 				       struct wlan_action_frame_args *args,
317 				       uint8_t *buf)
318 {
319 	*frm++ = args->category;
320 	*frm++ = args->action;
321 	/* Dialog token*/
322 	*frm++ = args->arg1;
323 
324 	epcs_info("EPCS frame: category:%d action:%d dialog_token:%d",
325 		  args->category, args->action, args->arg1);
326 
327 	/* Add priority access ml ie in caller for AP mode */
328 	return frm;
329 }
330 
331 static uint8_t *
wlan_mlo_add_epcs_response_action_frame(uint8_t * frm,struct wlan_action_frame_args * args,uint8_t * buf)332 wlan_mlo_add_epcs_response_action_frame(uint8_t *frm,
333 					struct wlan_action_frame_args *args,
334 					uint8_t *buf)
335 {
336 	*frm++ = args->category;
337 	*frm++ = args->action;
338 	/* Dialog token*/
339 	*frm++ = args->arg1;
340 	/* Status code (2 bytes) */
341 	*frm++ = QDF_GET_BITS(args->arg2, 0, 8);
342 	*frm++ = QDF_GET_BITS(args->arg2, 8, 8);
343 
344 	epcs_info("EPCS response frame: category:%d action:%d dialog_token:%d status_code:%d",
345 		  args->category, args->action, args->arg1, args->arg2);
346 
347 	/* Add priority access ml ie for AP mode */
348 	return frm;
349 }
350 
351 uint8_t *
wlan_mlo_add_epcs_action_frame(uint8_t * frm,struct wlan_action_frame_args * args,uint8_t * buf)352 wlan_mlo_add_epcs_action_frame(uint8_t *frm,
353 			       struct wlan_action_frame_args *args,
354 			       uint8_t *buf)
355 {
356 	switch (args->action) {
357 	case WLAN_EPCS_CATEGORY_REQUEST:
358 		return wlan_mlo_add_epcs_request_action_frame(frm, args,
359 							      buf);
360 	case WLAN_EPCS_CATEGORY_RESPONSE:
361 		return wlan_mlo_add_epcs_response_action_frame(frm, args,
362 							      buf);
363 	case WLAN_EPCS_CATEGORY_TEARDOWN:
364 		*frm++ = args->category;
365 		*frm++ = args->action;
366 		return frm;
367 	default:
368 		epcs_err("Invalid category:%d", args->category);
369 	}
370 
371 	return frm;
372 }
373 
374 QDF_STATUS
wlan_mlo_peer_rcv_cmd(struct wlan_mlo_peer_context * ml_peer,struct wlan_epcs_info * epcs,bool * updparam)375 wlan_mlo_peer_rcv_cmd(struct wlan_mlo_peer_context *ml_peer,
376 		      struct wlan_epcs_info *epcs,
377 		      bool *updparam)
378 {
379 	uint32_t cur_state;
380 	uint32_t new_state;
381 	QDF_STATUS status = QDF_STATUS_E_INVAL;
382 
383 	if (!ml_peer) {
384 		epcs_err("Null MLO peer");
385 		return QDF_STATUS_E_INVAL;
386 	}
387 
388 	*updparam = false;
389 
390 	epcs_dev_peer_lock_acquire(&ml_peer->epcs_info);
391 	cur_state = ml_peer->epcs_info.state;
392 	switch (ml_peer->epcs_info.state) {
393 	case EPCS_DOWN:
394 		if (epcs->cat == WLAN_EPCS_CATEGORY_REQUEST) {
395 		/* check authorization */
396 			if (wlan_mlo_is_node_epcs_authorized(ml_peer) ==
397 			   QDF_STATUS_SUCCESS) {
398 				status = QDF_STATUS_SUCCESS;
399 				epcs->dialog_token =
400 				  ++ml_peer->epcs_info.self_gen_dialog_token;
401 			} else {
402 				epcs_info("peer not authorized to enable EPCS");
403 			}
404 		} else if (epcs->cat == WLAN_EPCS_CATEGORY_TEARDOWN) {
405 			epcs_info("peer already in EPCS down state");
406 		} else if (epcs->cat == WLAN_EPCS_CATEGORY_RESPONSE) {
407 			epcs_err("Invalid command");
408 		}
409 		break;
410 	case EPCS_ENABLE:
411 		if (epcs->cat == WLAN_EPCS_CATEGORY_TEARDOWN) {
412 			ml_peer->epcs_info.state = EPCS_DOWN;
413 			status = QDF_STATUS_SUCCESS;
414 			*updparam = true;
415 		} else if (epcs->cat == WLAN_EPCS_CATEGORY_REQUEST) {
416 			epcs_info("peer already in EPCS enable state");
417 		} else if (epcs->cat == WLAN_EPCS_CATEGORY_RESPONSE) {
418 			epcs_err("Invalid command");
419 		}
420 		break;
421 	default:
422 		epcs_err("Invalid peer state %d",
423 			 ml_peer->epcs_info.state);
424 	}
425 
426 	new_state = ml_peer->epcs_info.state;
427 	epcs_debug("cmd:old state %d new state %d ev cat %d dialog token %d status %d",
428 		   cur_state, new_state, epcs->cat,
429 		   epcs->dialog_token, epcs->status);
430 
431 	epcs_dev_peer_lock_release(&ml_peer->epcs_info);
432 
433 	return status;
434 }
435 
436 QDF_STATUS
wlan_mlo_peer_rcv_action_frame(struct wlan_mlo_peer_context * ml_peer,struct wlan_epcs_info * epcs,bool * respond,bool * updparam)437 wlan_mlo_peer_rcv_action_frame(struct wlan_mlo_peer_context *ml_peer,
438 			       struct wlan_epcs_info *epcs,
439 			       bool *respond,
440 			       bool *updparam)
441 {
442 	uint32_t cur_state;
443 	uint32_t new_state;
444 	QDF_STATUS status = QDF_STATUS_E_INVAL;
445 
446 	if (!ml_peer) {
447 		epcs_err("Null MLO peer");
448 		return QDF_STATUS_E_INVAL;
449 	}
450 
451 	*respond = false;
452 	*updparam = false;
453 
454 	epcs_dev_peer_lock_acquire(&ml_peer->epcs_info);
455 	cur_state = ml_peer->epcs_info.state;
456 	switch (ml_peer->epcs_info.state) {
457 	case EPCS_DOWN:
458 		if (epcs->cat == WLAN_EPCS_CATEGORY_RESPONSE) {
459 			if (epcs->status == STATUS_SUCCESS) {
460 				if (epcs->dialog_token ==
461 				    ml_peer->epcs_info.self_gen_dialog_token) {
462 					ml_peer->epcs_info.state = EPCS_ENABLE;
463 					status = QDF_STATUS_SUCCESS;
464 					*updparam = true;
465 				} else {
466 					epcs_err("Response dialog token mismatch self_gen_dialog_token %d response token %d", ml_peer->epcs_info.self_gen_dialog_token, epcs->dialog_token);
467 				}
468 			} else {
469 				epcs_info("epcs rejected with status code %d",
470 					  epcs->status);
471 			}
472 		} else if (epcs->cat == WLAN_EPCS_CATEGORY_REQUEST) {
473 			/* check authorization */
474 			if (wlan_mlo_is_node_epcs_authorized(ml_peer) ==
475 			   QDF_STATUS_SUCCESS) {
476 				ml_peer->epcs_info.state = EPCS_ENABLE;
477 				status = QDF_STATUS_SUCCESS;
478 				*respond = true;
479 				*updparam = true;
480 			} else {
481 				epcs_info("peer not authorized to enable EPCS");
482 			}
483 		} else if (epcs->cat == WLAN_EPCS_CATEGORY_TEARDOWN) {
484 			epcs_info("peer not in EPCS enable state");
485 		}
486 		break;
487 	case EPCS_ENABLE:
488 		if (epcs->cat == WLAN_EPCS_CATEGORY_TEARDOWN) {
489 			ml_peer->epcs_info.state = EPCS_DOWN;
490 			status = QDF_STATUS_SUCCESS;
491 			*updparam = true;
492 		} else if (epcs->cat == WLAN_EPCS_CATEGORY_REQUEST) {
493 			epcs_info("peer already in EPCS enable state");
494 		} else if (epcs->cat == WLAN_EPCS_CATEGORY_RESPONSE) {
495 			epcs_info("peer already in EPCS enable state");
496 		}
497 		break;
498 	default:
499 		epcs_err("Invalid peer state %d", ml_peer->epcs_info.state);
500 	}
501 
502 	new_state = ml_peer->epcs_info.state;
503 	epcs_debug("action:old state %d new state %d ev cat %d dialog token %d status %d",
504 		   cur_state, new_state, epcs->cat,
505 		   epcs->dialog_token, epcs->status);
506 
507 	epcs_dev_peer_lock_release(&ml_peer->epcs_info);
508 
509 	return status;
510 }
511 
512 QDF_STATUS
wlan_mlo_update_authorize_epcs_mac_addr(struct wlan_objmgr_vdev * vdev,uint8_t * peer_mld_mac)513 wlan_mlo_update_authorize_epcs_mac_addr(struct wlan_objmgr_vdev *vdev,
514 					uint8_t *peer_mld_mac)
515 {
516 	bool found_entry = false;
517 	int free_index = -1;
518 	int i = 0;
519 	struct wlan_epcs_context *epcs_ctx;
520 
521 	if (!vdev) {
522 		epcs_err("vdev is null");
523 		return QDF_STATUS_E_INVAL;
524 	}
525 
526 	epcs_ctx = &vdev->mlo_dev_ctx->epcs_ctx;
527 
528 	epcs_dev_lock_acquire(epcs_ctx);
529 	for (i = 0; i < EPCS_MAX_AUTHORIZE_MAC_ADDR; i++) {
530 		/* Finding first available slot */
531 		if ((!epcs_ctx->authorize_info[i].valid) && (free_index < 0))
532 			free_index = i;
533 
534 		/* Checking for already available valid entry */
535 		if (epcs_ctx->authorize_info[i].valid &&
536 		    !qdf_mem_cmp(epcs_ctx->authorize_info[i].peer_mld_mac,
537 				 peer_mld_mac,
538 				 QDF_MAC_ADDR_SIZE)) {
539 			found_entry = true;
540 			break;
541 		}
542 	}
543 
544 	if (found_entry) {
545 		epcs_debug("Mac add "QDF_MAC_ADDR_FMT" is already authorized",
546 			   QDF_MAC_ADDR_REF(peer_mld_mac));
547 		epcs_dev_lock_release(epcs_ctx);
548 		return QDF_STATUS_E_INVAL;
549 	}
550 
551 	if (free_index < 0) {
552 		epcs_debug("EPCS authorize database is full");
553 		epcs_dev_lock_release(epcs_ctx);
554 		return QDF_STATUS_E_INVAL;
555 	}
556 
557 	epcs_ctx->authorize_info[free_index].valid = true;
558 	qdf_mem_copy(epcs_ctx->authorize_info[free_index]. peer_mld_mac,
559 		     peer_mld_mac,
560 		     QDF_MAC_ADDR_SIZE);
561 	epcs_dev_lock_release(epcs_ctx);
562 
563 	epcs_debug("EPCS Stored authorize mac addr is"QDF_MAC_ADDR_FMT" at index %d",
564 		   QDF_MAC_ADDR_REF(peer_mld_mac), free_index);
565 
566 	return QDF_STATUS_SUCCESS;
567 }
568 
569 QDF_STATUS
wlan_mlo_update_deauthorize_epcs_mac_addr(struct wlan_objmgr_vdev * vdev,uint8_t * peer_mld_mac)570 wlan_mlo_update_deauthorize_epcs_mac_addr(struct wlan_objmgr_vdev *vdev,
571 					  uint8_t *peer_mld_mac)
572 {
573 	int i = 0;
574 	struct wlan_epcs_context *epcs_ctx;
575 	bool found_entry = false;
576 
577 	if (!vdev) {
578 		epcs_err("vdev is null");
579 		return QDF_STATUS_E_INVAL;
580 	}
581 
582 	epcs_ctx = &vdev->mlo_dev_ctx->epcs_ctx;
583 
584 	epcs_dev_lock_acquire(epcs_ctx);
585 	for (i = 0; i < EPCS_MAX_AUTHORIZE_MAC_ADDR; i++) {
586 		if (!qdf_mem_cmp(epcs_ctx->authorize_info[i].peer_mld_mac,
587 				 peer_mld_mac,
588 				 QDF_MAC_ADDR_SIZE)) {
589 			found_entry = true;
590 			break;
591 		}
592 	}
593 
594 	if (!found_entry) {
595 		epcs_debug("Mac addr "QDF_MAC_ADDR_FMT" not found in authorized database",
596 			   QDF_MAC_ADDR_REF(peer_mld_mac));
597 		epcs_dev_lock_release(epcs_ctx);
598 		return QDF_STATUS_E_INVAL;
599 	}
600 
601 	if (found_entry && !epcs_ctx->authorize_info[i].valid) {
602 		epcs_debug("Mac addr "QDF_MAC_ADDR_FMT" is already deauthorized in database",
603 			   QDF_MAC_ADDR_REF(peer_mld_mac));
604 		epcs_dev_lock_release(epcs_ctx);
605 		return QDF_STATUS_E_INVAL;
606 	}
607 
608 	epcs_ctx->authorize_info[i].valid = false;
609 	epcs_dev_lock_release(epcs_ctx);
610 	epcs_debug("EPCS Stored authorize mac addr is "QDF_MAC_ADDR_FMT" at idx %d is removed",
611 		   QDF_MAC_ADDR_REF(peer_mld_mac), i);
612 
613 	return QDF_STATUS_SUCCESS;
614 }
615