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