xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlo_mgr/src/wlan_mlo_mgr_peer.c (revision 2888b71da71bce103343119fa1b31f4a0cee07c8)
1 /*
2  * Copyright (c) 2021, The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include "wlan_mlo_mgr_main.h"
19 #include "qdf_module.h"
20 #include "qdf_types.h"
21 #include "wlan_cmn.h"
22 #include "wlan_mlo_mgr_msgq.h"
23 #include "wlan_objmgr_peer_obj.h"
24 #include "wlan_mlo_mgr_peer.h"
25 #include "wlan_mlo_mgr_ap.h"
26 #include "wlan_crypto_global_api.h"
27 
28 static void mlo_partner_peer_create_post(struct wlan_mlo_dev_context *ml_dev,
29 					 struct wlan_objmgr_vdev *vdev_link,
30 					 struct wlan_mlo_peer_context *ml_peer,
31 					 qdf_nbuf_t frm_buf,
32 					 struct mlo_partner_info *ml_info)
33 {
34 	struct peer_create_notif_s peer_create;
35 	QDF_STATUS status;
36 	uint8_t i;
37 	uint8_t link_id;
38 
39 	if (wlan_objmgr_vdev_try_get_ref(vdev_link, WLAN_MLO_MGR_ID) ==
40 							QDF_STATUS_SUCCESS) {
41 		peer_create.vdev_link = vdev_link;
42 	} else {
43 		mlo_err("VDEV is not in created state");
44 		return;
45 	}
46 
47 	wlan_mlo_peer_get_ref(ml_peer);
48 	peer_create.ml_peer = ml_peer;
49 	link_id = wlan_vdev_get_link_id(vdev_link);
50 	for (i = 0; i < ml_info->num_partner_links; i++) {
51 		if (link_id != ml_info->partner_link_info[i].link_id)
52 			continue;
53 
54 		qdf_copy_macaddr(&peer_create.addr,
55 				 &ml_info->partner_link_info[i].link_addr);
56 		break;
57 	}
58 
59 	status = mlo_peer_create_get_frm_buf(ml_peer, &peer_create, frm_buf);
60 
61 	if (QDF_IS_STATUS_ERROR(status)) {
62 		wlan_mlo_peer_release_ref(ml_peer);
63 		wlan_objmgr_vdev_release_ref(vdev_link, WLAN_MLO_MGR_ID);
64 		mlo_err("nbuf clone is failed");
65 		return;
66 	}
67 
68 	status = mlo_msgq_post(MLO_PEER_CREATE, ml_dev, &peer_create);
69 	if (status != QDF_STATUS_SUCCESS) {
70 		qdf_nbuf_free(frm_buf);
71 		wlan_mlo_peer_release_ref(ml_peer);
72 		wlan_objmgr_vdev_release_ref(vdev_link, WLAN_MLO_MGR_ID);
73 	}
74 }
75 
76 static void mlo_link_peer_assoc_notify(struct wlan_mlo_dev_context *ml_dev,
77 				       struct wlan_objmgr_peer *peer)
78 {
79 	struct peer_assoc_notify_s peer_assoc;
80 	QDF_STATUS status;
81 
82 	peer_assoc.peer = peer;
83 	status = mlo_msgq_post(MLO_PEER_ASSOC, ml_dev, &peer_assoc);
84 	if (status != QDF_STATUS_SUCCESS)
85 		wlan_objmgr_peer_release_ref(peer, WLAN_MLO_MGR_ID);
86 }
87 
88 static void mlo_link_peer_send_assoc_fail(struct wlan_mlo_dev_context *ml_dev,
89 					  struct wlan_objmgr_peer *peer)
90 {
91 	struct peer_assoc_fail_notify_s peer_assoc_fail;
92 	QDF_STATUS status;
93 
94 	peer_assoc_fail.peer = peer;
95 	status = mlo_msgq_post(MLO_PEER_ASSOC_FAIL, ml_dev, &peer_assoc_fail);
96 	if (status != QDF_STATUS_SUCCESS)
97 		wlan_objmgr_peer_release_ref(peer, WLAN_MLO_MGR_ID);
98 }
99 
100 static void mlo_link_peer_disconnect_notify(struct wlan_mlo_dev_context *ml_dev,
101 					    struct wlan_objmgr_peer *peer)
102 {
103 	struct peer_discon_notify_s peer_disconn;
104 	QDF_STATUS status;
105 	struct wlan_objmgr_vdev *vdev;
106 	enum QDF_OPMODE opmode;
107 
108 	vdev = wlan_peer_get_vdev(peer);
109 	opmode = wlan_vdev_mlme_get_opmode(vdev);
110 
111 	if (opmode == QDF_SAP_MODE) {
112 		peer_disconn.peer = peer;
113 		status = mlo_msgq_post(MLO_PEER_DISCONNECT, ml_dev,
114 				       &peer_disconn);
115 		if (status != QDF_STATUS_SUCCESS)
116 			wlan_objmgr_peer_release_ref(peer, WLAN_MLO_MGR_ID);
117 	} else {
118 		wlan_objmgr_peer_release_ref(peer, WLAN_MLO_MGR_ID);
119 	}
120 }
121 
122 static void mlo_link_peer_deauth_init(struct wlan_mlo_dev_context *ml_dev,
123 				      struct wlan_objmgr_peer *peer)
124 {
125 	struct peer_deauth_notify_s peer_deauth;
126 	QDF_STATUS status;
127 
128 	peer_deauth.peer = peer;
129 	status = mlo_msgq_post(MLO_PEER_DEAUTH, ml_dev, &peer_deauth);
130 	if (status != QDF_STATUS_SUCCESS)
131 		wlan_objmgr_peer_release_ref(peer, WLAN_MLO_MGR_ID);
132 }
133 
134 #ifdef UMAC_MLO_AUTH_DEFER
135 static void mlo_peer_process_pending_auth(struct wlan_mlo_dev_context *ml_dev,
136 					  struct wlan_mlo_peer_context *ml_peer)
137 {
138 	struct peer_auth_process_notif_s peer_auth;
139 	struct mlpeer_auth_params *recv_auth;
140 	uint8_t i;
141 	QDF_STATUS status;
142 
143 	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
144 		mlo_peer_lock_acquire(ml_peer);
145 		recv_auth = ml_peer->pending_auth[i];
146 		if (!recv_auth) {
147 			mlo_peer_lock_release(ml_peer);
148 			continue;
149 		}
150 		peer_auth.auth_params = recv_auth;
151 		ml_peer->pending_auth[i] = NULL;
152 
153 		mlo_peer_lock_release(ml_peer);
154 
155 		status = mlo_msgq_post(MLO_PEER_PENDING_AUTH, ml_dev,
156 				       &peer_auth);
157 		if (QDF_IS_STATUS_ERROR(status))
158 			mlo_peer_free_auth_param(peer_auth.auth_params);
159 	}
160 }
161 #else
162 static void mlo_peer_process_pending_auth(struct wlan_mlo_dev_context *ml_dev,
163 					  struct wlan_mlo_peer_context *ml_peer)
164 {
165 }
166 #endif
167 
168 QDF_STATUS
169 wlan_mlo_peer_is_disconnect_progress(struct wlan_mlo_peer_context *ml_peer)
170 {
171 	QDF_STATUS status;
172 
173 	if (!ml_peer)
174 		return QDF_STATUS_E_FAILURE;
175 
176 	mlo_peer_lock_acquire(ml_peer);
177 
178 	if (ml_peer->mlpeer_state == ML_PEER_DISCONN_INITIATED)
179 		status = QDF_STATUS_SUCCESS;
180 	else
181 		status = QDF_STATUS_E_FAILURE;
182 
183 	mlo_peer_lock_release(ml_peer);
184 
185 	return status;
186 }
187 
188 QDF_STATUS wlan_mlo_peer_is_assoc_done(struct wlan_mlo_peer_context *ml_peer)
189 {
190 	QDF_STATUS status;
191 
192 	if (!ml_peer)
193 		return QDF_STATUS_E_FAILURE;
194 
195 	mlo_peer_lock_acquire(ml_peer);
196 
197 	if (ml_peer->mlpeer_state == ML_PEER_ASSOC_DONE)
198 		status = QDF_STATUS_SUCCESS;
199 	else
200 		status = QDF_STATUS_E_FAILURE;
201 
202 	mlo_peer_lock_release(ml_peer);
203 
204 	return status;
205 }
206 
207 struct wlan_objmgr_peer *wlan_mlo_peer_get_assoc_peer(
208 					struct wlan_mlo_peer_context *ml_peer)
209 {
210 	struct wlan_mlo_link_peer_entry *peer_entry;
211 	struct wlan_objmgr_peer *assoc_peer = NULL;
212 
213 	if (!ml_peer)
214 		return NULL;
215 
216 	mlo_peer_lock_acquire(ml_peer);
217 
218 	peer_entry = &ml_peer->peer_list[0];
219 
220 	if (peer_entry->link_peer)
221 		assoc_peer = peer_entry->link_peer;
222 
223 	mlo_peer_lock_release(ml_peer);
224 
225 	return assoc_peer;
226 }
227 
228 bool mlo_peer_is_assoc_peer(struct wlan_mlo_peer_context *ml_peer,
229 			    struct wlan_objmgr_peer *peer)
230 {
231 	struct wlan_mlo_link_peer_entry *peer_entry;
232 	bool is_assoc_peer = false;
233 
234 	if (!ml_peer || !peer)
235 		return is_assoc_peer;
236 
237 	peer_entry = &ml_peer->peer_list[0];
238 
239 	if (peer_entry->link_peer != peer)
240 		is_assoc_peer = true;
241 
242 	return is_assoc_peer;
243 }
244 
245 bool wlan_mlo_peer_is_assoc_peer(struct wlan_mlo_peer_context *ml_peer,
246 				 struct wlan_objmgr_peer *peer)
247 {
248 	bool is_assoc_peer = false;
249 
250 	if (!ml_peer || !peer)
251 		return is_assoc_peer;
252 
253 	mlo_peer_lock_acquire(ml_peer);
254 
255 	is_assoc_peer = mlo_peer_is_assoc_peer(ml_peer, peer);
256 
257 	mlo_peer_lock_release(ml_peer);
258 
259 	return is_assoc_peer;
260 }
261 
262 void wlan_mlo_partner_peer_assoc_post(struct wlan_objmgr_peer *assoc_peer)
263 {
264 	struct wlan_mlo_dev_context *ml_dev;
265 	struct wlan_mlo_peer_context *ml_peer;
266 	struct wlan_objmgr_peer *link_peer;
267 	struct wlan_objmgr_peer *link_peers[MAX_MLO_LINK_PEERS];
268 	struct wlan_mlo_link_peer_entry *peer_entry;
269 	uint16_t i;
270 
271 	ml_peer = assoc_peer->mlo_peer_ctx;
272 	if (!ml_peer)
273 		return;
274 
275 	mlo_peer_lock_acquire(ml_peer);
276 
277 	if (ml_peer->mlpeer_state != ML_PEER_CREATED) {
278 		mlo_peer_lock_release(ml_peer);
279 		return;
280 	}
281 
282 	ml_peer->mlpeer_state = ML_PEER_ASSOC_DONE;
283 	ml_dev = ml_peer->ml_dev;
284 
285 	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
286 		link_peers[i] = NULL;
287 		peer_entry = &ml_peer->peer_list[i];
288 
289 		if (!peer_entry->link_peer)
290 			continue;
291 
292 		if (peer_entry->link_peer == assoc_peer)
293 			continue;
294 
295 		link_peer = peer_entry->link_peer;
296 
297 		if (wlan_objmgr_peer_try_get_ref(link_peer, WLAN_MLO_MGR_ID) !=
298 						 QDF_STATUS_SUCCESS)
299 			continue;
300 
301 		link_peers[i] = link_peer;
302 	}
303 	mlo_peer_lock_release(ml_peer);
304 
305 	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
306 		if (!link_peers[i])
307 			continue;
308 
309 		/* Prepare and queue message */
310 		mlo_link_peer_assoc_notify(ml_dev, link_peers[i]);
311 	}
312 }
313 
314 void
315 wlan_mlo_peer_deauth_init(struct wlan_mlo_peer_context *ml_peer)
316 {
317 	struct wlan_mlo_dev_context *ml_dev;
318 	struct wlan_objmgr_peer *link_peer;
319 	struct wlan_objmgr_peer *link_peers[MAX_MLO_LINK_PEERS];
320 	struct wlan_mlo_link_peer_entry *peer_entry;
321 	uint16_t i;
322 
323 	if (!ml_peer)
324 		return;
325 
326 	mlo_peer_lock_acquire(ml_peer);
327 
328 	if (ml_peer->mlpeer_state == ML_PEER_DISCONN_INITIATED) {
329 		mlo_peer_lock_release(ml_peer);
330 		return;
331 	}
332 
333 	ml_dev = ml_peer->ml_dev;
334 
335 	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
336 		link_peers[i] = NULL;
337 		peer_entry = &ml_peer->peer_list[i];
338 		if (!peer_entry->link_peer)
339 			continue;
340 
341 		link_peer = peer_entry->link_peer;
342 		/* Skip Deauth if PMF is enabled for the station */
343 		if ((i == 0) &&
344 		    (wlan_crypto_is_pmf_enabled(wlan_peer_get_vdev(link_peer),
345 					       link_peer))) {
346 			mlo_peer_lock_release(ml_peer);
347 			return;
348 		}
349 
350 		if (wlan_objmgr_peer_try_get_ref(link_peer, WLAN_MLO_MGR_ID) !=
351 						QDF_STATUS_SUCCESS)
352 			continue;
353 
354 		link_peers[i] = link_peer;
355 	}
356 
357 	ml_peer->mlpeer_state = ML_PEER_DISCONN_INITIATED;
358 
359 	mlo_peer_lock_release(ml_peer);
360 
361 	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
362 		if (!link_peers[i])
363 			continue;
364 
365 		/* Prepare and queue message */
366 		if (i == 0)
367 			mlo_link_peer_deauth_init(ml_dev, link_peers[i]);
368 		else
369 			mlo_link_peer_disconnect_notify(ml_dev, link_peers[i]);
370 	}
371 
372 	return;
373 }
374 
375 void
376 wlan_mlo_partner_peer_create_failed_notify(
377 				struct wlan_mlo_peer_context *ml_peer)
378 {
379 	struct wlan_mlo_dev_context *ml_dev;
380 	struct wlan_objmgr_peer *link_peer;
381 	struct wlan_objmgr_peer *link_peers[MAX_MLO_LINK_PEERS];
382 	struct wlan_mlo_link_peer_entry *peer_entry;
383 	uint16_t i;
384 
385 	if (!ml_peer)
386 		return;
387 
388 	mlo_peer_lock_acquire(ml_peer);
389 
390 	if (ml_peer->mlpeer_state == ML_PEER_DISCONN_INITIATED) {
391 		mlo_peer_lock_release(ml_peer);
392 		return;
393 	}
394 
395 	ml_peer->mlpeer_state = ML_PEER_DISCONN_INITIATED;
396 	ml_dev = ml_peer->ml_dev;
397 
398 	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
399 		link_peers[i] = NULL;
400 		peer_entry = &ml_peer->peer_list[i];
401 		if (!peer_entry->link_peer)
402 			continue;
403 
404 		link_peer = peer_entry->link_peer;
405 		if (wlan_objmgr_peer_try_get_ref(link_peer, WLAN_MLO_MGR_ID) !=
406 						QDF_STATUS_SUCCESS)
407 			continue;
408 
409 		link_peers[i] = link_peer;
410 	}
411 	mlo_peer_lock_release(ml_peer);
412 
413 	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
414 		if (!link_peers[i])
415 			continue;
416 
417 		/* Prepare and queue message */
418 		if (i == 0)
419 			mlo_link_peer_send_assoc_fail(ml_dev, link_peers[i]);
420 		else
421 			mlo_link_peer_disconnect_notify(ml_dev, link_peers[i]);
422 	}
423 }
424 
425 void wlan_mlo_partner_peer_disconnect_notify(struct wlan_objmgr_peer *src_peer)
426 {
427 	struct wlan_mlo_dev_context *ml_dev;
428 	struct wlan_mlo_peer_context *ml_peer;
429 	struct wlan_objmgr_peer *link_peer;
430 	struct wlan_objmgr_peer *link_peers[MAX_MLO_LINK_PEERS];
431 	struct wlan_mlo_link_peer_entry *peer_entry;
432 	struct wlan_objmgr_vdev *vdev = NULL;
433 	uint16_t i;
434 
435 	ml_peer = src_peer->mlo_peer_ctx;
436 	if (!ml_peer)
437 		return;
438 
439 	mlo_peer_lock_acquire(ml_peer);
440 
441 	if (ml_peer->mlpeer_state == ML_PEER_DISCONN_INITIATED) {
442 		mlo_peer_lock_release(ml_peer);
443 		return;
444 	}
445 
446 	ml_peer->mlpeer_state = ML_PEER_DISCONN_INITIATED;
447 
448 	vdev = wlan_peer_get_vdev(src_peer);
449 	if (!vdev || wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE) {
450 		mlo_peer_lock_release(ml_peer);
451 		return;
452 	}
453 
454 	ml_dev = ml_peer->ml_dev;
455 	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
456 		link_peers[i] = NULL;
457 		peer_entry = &ml_peer->peer_list[i];
458 		if (!peer_entry->link_peer) {
459 			mlo_debug("link peer is null");
460 			continue;
461 		}
462 
463 		if (peer_entry->link_peer == src_peer)
464 			continue;
465 
466 		link_peer = peer_entry->link_peer;
467 		if (wlan_objmgr_peer_try_get_ref(link_peer, WLAN_MLO_MGR_ID) !=
468 						QDF_STATUS_SUCCESS)
469 			continue;
470 
471 		link_peers[i] = link_peer;
472 	}
473 	mlo_peer_lock_release(ml_peer);
474 
475 	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
476 		if (!link_peers[i])
477 			continue;
478 
479 		/* Prepare and queue message */
480 		mlo_link_peer_disconnect_notify(ml_dev, link_peers[i]);
481 	}
482 }
483 
484 static void mlo_peer_populate_link_peer(
485 			struct wlan_mlo_peer_context *ml_peer,
486 			struct wlan_objmgr_peer *link_peer)
487 {
488 	mlo_peer_lock_acquire(ml_peer);
489 	wlan_mlo_peer_get_ref(ml_peer);
490 	link_peer->mlo_peer_ctx = ml_peer;
491 	mlo_peer_lock_release(ml_peer);
492 }
493 
494 static void mlo_reset_link_peer(
495 			struct wlan_mlo_peer_context *ml_peer,
496 			struct wlan_objmgr_peer *link_peer)
497 {
498 	mlo_peer_lock_acquire(ml_peer);
499 	link_peer->mlo_peer_ctx = NULL;
500 	wlan_peer_clear_mlo(link_peer);
501 	mlo_peer_lock_release(ml_peer);
502 }
503 
504 static void mlo_peer_free(struct wlan_mlo_peer_context *ml_peer)
505 {
506 	struct wlan_mlo_dev_context *ml_dev;
507 
508 	ml_dev = ml_peer->ml_dev;
509 	if (!ml_dev) {
510 		mlo_err("ML DEV is NULL");
511 		return;
512 	}
513 
514 	mlo_peer_lock_destroy(ml_peer);
515 	mlo_ap_ml_peerid_free(ml_peer->mlo_peer_id);
516 	mlo_peer_free_aid(ml_dev, ml_peer);
517 	mlo_peer_free_primary_umac(ml_dev, ml_peer);
518 	qdf_mem_free(ml_peer);
519 }
520 
521 void mlo_peer_cleanup(struct wlan_mlo_peer_context *ml_peer)
522 {
523 	struct wlan_mlo_dev_context *ml_dev;
524 
525 	if (!ml_peer) {
526 		mlo_err("ML PEER is NULL");
527 		return;
528 	}
529 	ml_dev = ml_peer->ml_dev;
530 	if (!ml_dev) {
531 		mlo_err("ML DEV is NULL");
532 		return;
533 	}
534 
535 	mlo_dev_mlpeer_detach(ml_dev, ml_peer);
536 	/* If any Auth req is received during ML peer delete */
537 	mlo_peer_process_pending_auth(ml_dev, ml_peer);
538 	mlo_peer_free(ml_peer);
539 }
540 
541 static QDF_STATUS mlo_peer_attach_link_peer(
542 		struct wlan_mlo_peer_context *ml_peer,
543 		struct wlan_objmgr_peer *link_peer,
544 		qdf_nbuf_t frm_buf)
545 {
546 	struct wlan_mlo_link_peer_entry *peer_entry;
547 	QDF_STATUS status = QDF_STATUS_E_RESOURCES;
548 	struct wlan_objmgr_pdev *pdev;
549 	struct wlan_objmgr_vdev *vdev;
550 	uint16_t i;
551 
552 	if (!link_peer)
553 		return QDF_STATUS_E_FAILURE;
554 
555 	vdev = wlan_peer_get_vdev(link_peer);
556 	if (!vdev)
557 		return QDF_STATUS_E_FAILURE;
558 
559 	mlo_peer_lock_acquire(ml_peer);
560 
561 	if (ml_peer->mlpeer_state != ML_PEER_CREATED) {
562 		mlo_peer_lock_release(ml_peer);
563 		mlo_err("ML Peer " QDF_MAC_ADDR_FMT " is not in created state (state %d)",
564 			QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes),
565 			ml_peer->mlpeer_state);
566 		return status;
567 	}
568 
569 	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
570 		peer_entry = &ml_peer->peer_list[i];
571 		if (peer_entry->link_peer)
572 			continue;
573 
574 		if (wlan_objmgr_peer_try_get_ref(link_peer, WLAN_MLO_MGR_ID) !=
575 						QDF_STATUS_SUCCESS) {
576 			mlo_err("ML Peer " QDF_MAC_ADDR_FMT ", link peer " QDF_MAC_ADDR_FMT " is not in valid state",
577 				QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes),
578 				QDF_MAC_ADDR_REF
579 					(wlan_peer_get_macaddr(link_peer)));
580 			break;
581 		}
582 		peer_entry->link_peer = link_peer;
583 		qdf_copy_macaddr(&peer_entry->link_addr,
584 				 (struct qdf_mac_addr *)&link_peer->macaddr[0]);
585 
586 		peer_entry->link_ix = wlan_vdev_get_link_id(vdev);
587 		pdev = wlan_vdev_get_pdev(wlan_peer_get_vdev(link_peer));
588 		peer_entry->hw_link_id = wlan_mlo_get_pdev_hw_link_id(pdev);
589 		mlo_peer_assign_primary_umac(ml_peer, peer_entry);
590 		if (frm_buf)
591 			peer_entry->assoc_rsp_buf = frm_buf;
592 		else
593 			peer_entry->assoc_rsp_buf = NULL;
594 
595 		status = QDF_STATUS_SUCCESS;
596 		break;
597 	}
598 	if (QDF_IS_STATUS_SUCCESS(status))
599 		ml_peer->link_peer_cnt++;
600 
601 	mlo_peer_lock_release(ml_peer);
602 
603 	return status;
604 }
605 
606 qdf_nbuf_t mlo_peer_get_link_peer_assoc_resp_buf(
607 		struct wlan_mlo_peer_context *ml_peer,
608 		uint8_t link_ix)
609 {
610 	struct wlan_mlo_link_peer_entry *peer_entry;
611 	qdf_nbuf_t frm_buf = NULL;
612 	uint8_t i;
613 
614 	if (!ml_peer)
615 		return NULL;
616 
617 	if (link_ix > MAX_MLO_LINK_PEERS)
618 		return NULL;
619 
620 	mlo_peer_lock_acquire(ml_peer);
621 	if ((ml_peer->mlpeer_state != ML_PEER_CREATED) &&
622 	    (ml_peer->mlpeer_state != ML_PEER_ASSOC_DONE)) {
623 		mlo_peer_lock_release(ml_peer);
624 		return NULL;
625 	}
626 
627 	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
628 		peer_entry = &ml_peer->peer_list[i];
629 
630 		if (!peer_entry->link_peer)
631 			continue;
632 
633 		if (peer_entry->link_ix == link_ix) {
634 			frm_buf = qdf_nbuf_clone(peer_entry->assoc_rsp_buf);
635 			break;
636 		}
637 	}
638 	mlo_peer_lock_release(ml_peer);
639 
640 	return frm_buf;
641 }
642 
643 void wlan_mlo_peer_free_all_link_assoc_resp_buf(
644 			struct wlan_objmgr_peer *link_peer)
645 {
646 	struct wlan_mlo_link_peer_entry *peer_entry;
647 	struct wlan_mlo_peer_context *ml_peer;
648 	uint8_t i;
649 
650 	ml_peer = link_peer->mlo_peer_ctx;
651 	if (!ml_peer)
652 		return;
653 
654 	mlo_peer_lock_acquire(ml_peer);
655 
656 	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
657 		peer_entry = &ml_peer->peer_list[i];
658 
659 		if (peer_entry->assoc_rsp_buf) {
660 			qdf_nbuf_free(peer_entry->assoc_rsp_buf);
661 			peer_entry->assoc_rsp_buf = NULL;
662 		}
663 	}
664 	mlo_peer_lock_release(ml_peer);
665 }
666 
667 static QDF_STATUS mlo_peer_detach_link_peer(
668 		struct wlan_mlo_peer_context *ml_peer,
669 		struct wlan_objmgr_peer *link_peer)
670 {
671 	struct wlan_mlo_link_peer_entry *peer_entry;
672 	QDF_STATUS status = QDF_STATUS_E_RESOURCES;
673 	uint16_t i;
674 
675 	mlo_peer_lock_acquire(ml_peer);
676 
677 	if (ml_peer->mlpeer_state != ML_PEER_DISCONN_INITIATED) {
678 		mlo_peer_lock_release(ml_peer);
679 		return status;
680 	}
681 
682 	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
683 		peer_entry = &ml_peer->peer_list[i];
684 		if (!peer_entry->link_peer)
685 			continue;
686 
687 		if (peer_entry->link_peer != link_peer)
688 			continue;
689 
690 		if (peer_entry->assoc_rsp_buf) {
691 			qdf_nbuf_free(peer_entry->assoc_rsp_buf);
692 			peer_entry->assoc_rsp_buf = NULL;
693 		}
694 
695 		wlan_objmgr_peer_release_ref(link_peer, WLAN_MLO_MGR_ID);
696 		peer_entry->link_peer = NULL;
697 		ml_peer->link_peer_cnt--;
698 		status = QDF_STATUS_SUCCESS;
699 		break;
700 	}
701 	mlo_peer_lock_release(ml_peer);
702 
703 	return status;
704 }
705 
706 static QDF_STATUS mlo_dev_get_link_vdevs(
707 			struct wlan_objmgr_vdev *vdev,
708 			struct wlan_mlo_dev_context *ml_dev,
709 			struct mlo_partner_info *ml_info,
710 			struct wlan_objmgr_vdev *link_vdevs[])
711 {
712 	uint16_t i, j;
713 	struct wlan_objmgr_vdev *vdev_link;
714 	uint8_t link_id;
715 
716 	if (!ml_dev) {
717 		mlo_err("ml_dev is null");
718 		return QDF_STATUS_E_INVAL;
719 	}
720 
721 	if (!ml_info) {
722 		mlo_err("ml_info is null");
723 		return QDF_STATUS_E_INVAL;
724 	}
725 
726 	mlo_debug("num_partner_links %d", ml_info->num_partner_links);
727 	for (i = 0; i < ml_info->num_partner_links; i++) {
728 		link_id = ml_info->partner_link_info[i].link_id;
729 		vdev_link = mlo_get_vdev_by_link_id(vdev, link_id);
730 		if (vdev_link) {
731 			link_vdevs[i] = vdev_link;
732 		} else {
733 			/* release ref which were taken before failure */
734 			for (j = 0; j < i; j++) {
735 				vdev_link = link_vdevs[j];
736 				if (!vdev_link)
737 					continue;
738 
739 				wlan_objmgr_vdev_release_ref(vdev_link,
740 							     WLAN_MLO_MGR_ID);
741 			}
742 			return QDF_STATUS_E_INVAL;
743 		}
744 	}
745 
746 	return QDF_STATUS_SUCCESS;
747 }
748 
749 static void mlo_dev_release_link_vdevs(
750 			struct wlan_objmgr_vdev *link_vdevs[])
751 {
752 	uint16_t i;
753 	struct wlan_objmgr_vdev *vdev_link;
754 
755 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
756 		vdev_link = link_vdevs[i];
757 		if (!vdev_link)
758 			continue;
759 
760 		wlan_objmgr_vdev_release_ref(vdev_link, WLAN_MLO_MGR_ID);
761 	}
762 }
763 
764 #ifdef WLAN_FEATURE_11BE
765 static void
766 wlan_mlo_peer_set_t2lm_enable_val(struct wlan_mlo_peer_context *ml_peer,
767 				  struct mlo_partner_info *ml_info)
768 {
769 	ml_peer->t2lm_policy.t2lm_enable_val = ml_info->t2lm_enable_val;
770 }
771 #else
772 static void
773 wlan_mlo_peer_set_t2lm_enable_val(struct wlan_mlo_peer_context *ml_peer,
774 				  struct mlo_partner_info *ml_info)
775 {}
776 #endif /* WLAN_FEATURE_11BE */
777 
778 QDF_STATUS wlan_mlo_peer_create(struct wlan_objmgr_vdev *vdev,
779 				struct wlan_objmgr_peer *link_peer,
780 				struct mlo_partner_info *ml_info,
781 				qdf_nbuf_t frm_buf,
782 				uint16_t aid)
783 {
784 	struct wlan_mlo_dev_context *ml_dev;
785 	struct wlan_mlo_peer_context *ml_peer = NULL;
786 	struct wlan_objmgr_vdev *link_vdevs[WLAN_UMAC_MLO_MAX_VDEVS] = { NULL };
787 	struct wlan_objmgr_vdev *vdev_link;
788 	QDF_STATUS status;
789 	uint16_t i;
790 	struct wlan_objmgr_peer *assoc_peer;
791 	bool is_ml_peer_attached = false;
792 
793 	/* get ML VDEV from VDEV */
794 	ml_dev = vdev->mlo_dev_ctx;
795 
796 	if (!ml_dev) {
797 		mlo_err("ML dev ctx is NULL");
798 		return QDF_STATUS_E_NULL_VALUE;
799 	}
800 
801 	/* Check resources of Partner VDEV */
802 	if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE) {
803 		if (wlan_mlo_is_mld_ctx_exist(
804 		    (struct qdf_mac_addr *)&link_peer->mldaddr[0])) {
805 			mlo_err("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " is matching with one of the MLD address in the system",
806 				ml_dev->mld_id,
807 				QDF_MAC_ADDR_REF(link_peer->mldaddr));
808 			return QDF_STATUS_E_FAILURE;
809 		}
810 		status = mlo_dev_get_link_vdevs(vdev, ml_dev,
811 						ml_info, link_vdevs);
812 		if (QDF_IS_STATUS_ERROR(status)) {
813 			mlo_err("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " get link vdevs failed",
814 				ml_dev->mld_id,
815 				QDF_MAC_ADDR_REF(link_peer->mldaddr));
816 			return QDF_STATUS_E_FAILURE;
817 		}
818 
819 		for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
820 			vdev_link = link_vdevs[i];
821 			if (!vdev_link) {
822 				mlo_debug("vdev_link is null");
823 				continue;
824 			}
825 
826 			if (wlan_vdev_is_mlo_peer_create_allowed(vdev_link)
827 					!= QDF_STATUS_SUCCESS) {
828 				mlo_dev_release_link_vdevs(link_vdevs);
829 
830 				mlo_err("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " create not allowed on link vdev %d",
831 					ml_dev->mld_id,
832 					QDF_MAC_ADDR_REF
833 						(link_peer->mldaddr),
834 					wlan_vdev_get_id(vdev_link));
835 				return QDF_STATUS_E_INVAL;
836 			}
837 		}
838 
839 		for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
840 			vdev_link = link_vdevs[i];
841 			if (vdev_link && (vdev_link != vdev) &&
842 			    (wlan_vdev_get_peer_count(vdev_link) >
843 			     wlan_vdev_get_max_peer_count(vdev_link))) {
844 				mlo_dev_release_link_vdevs(link_vdevs);
845 				mlo_err("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " Max peer count reached on link vdev %d",
846 					ml_dev->mld_id,
847 					QDF_MAC_ADDR_REF
848 						(link_peer->mldaddr),
849 					wlan_vdev_get_id(vdev_link));
850 				return QDF_STATUS_E_RESOURCES;
851 			}
852 		}
853 	}
854 
855 	if (wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE) {
856 		ml_peer = wlan_mlo_get_mlpeer(ml_dev,
857 				 (struct qdf_mac_addr *)&link_peer->mldaddr[0]);
858 		if (ml_peer)
859 			is_ml_peer_attached = true;
860 	}
861 	if (!ml_peer) {
862 		/* Allocate MLO peer */
863 		ml_peer = qdf_mem_malloc(sizeof(*ml_peer));
864 		if (!ml_peer) {
865 			mlo_err("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " mem alloc failed",
866 				ml_dev->mld_id,
867 				QDF_MAC_ADDR_REF(link_peer->mldaddr));
868 			mlo_dev_release_link_vdevs(link_vdevs);
869 			return QDF_STATUS_E_NOMEM;
870 		}
871 
872 		qdf_atomic_init(&ml_peer->ref_cnt);
873 		mlo_peer_lock_create(ml_peer);
874 		ml_peer->ml_dev = ml_dev;
875 		ml_peer->mlpeer_state = ML_PEER_CREATED;
876 		ml_peer->max_links = ml_info->num_partner_links;
877 		ml_peer->primary_umac_psoc_id = ML_PRIMARY_UMAC_ID_INVAL;
878 
879 		ml_peer->mlo_peer_id = mlo_ap_ml_peerid_alloc();
880 		if (ml_peer->mlo_peer_id == MLO_INVALID_PEER_ID) {
881 			mlo_err("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " invalid ml peer id",
882 				ml_dev->mld_id,
883 				QDF_MAC_ADDR_REF
884 				(ml_peer->peer_mld_addr.bytes));
885 			mlo_peer_free(ml_peer);
886 			mlo_dev_release_link_vdevs(link_vdevs);
887 			return QDF_STATUS_E_RESOURCES;
888 		}
889 
890 		qdf_copy_macaddr((struct qdf_mac_addr *)&ml_peer->peer_mld_addr,
891 				 (struct qdf_mac_addr *)&link_peer->mldaddr[0]);
892 		wlan_mlo_peer_set_t2lm_enable_val(ml_peer, ml_info);
893 
894 		/* Allocate AID */
895 		if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE) {
896 			if (aid == (uint16_t)-1) {
897 				status = mlo_peer_allocate_aid(ml_dev, ml_peer);
898 				if (status != QDF_STATUS_SUCCESS) {
899 					mlo_err("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " aid alloc failed",
900 						ml_dev->mld_id,
901 						QDF_MAC_ADDR_REF
902 						(ml_peer->peer_mld_addr.bytes));
903 					mlo_peer_free(ml_peer);
904 					mlo_dev_release_link_vdevs(link_vdevs);
905 					return status;
906 				}
907 			} else {
908 				ml_peer->assoc_id = aid;
909 			}
910 		}
911 	}
912 
913 	/* Populate Link peer pointer, peer MAC address,
914 	 * MLD address. HW link ID, update ref count
915 	 */
916 	status = mlo_peer_attach_link_peer(ml_peer, link_peer, NULL);
917 	if (QDF_IS_STATUS_ERROR(status)) {
918 		mlo_err("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " link peer attach failed",
919 			ml_dev->mld_id,
920 			QDF_MAC_ADDR_REF
921 			(ml_peer->peer_mld_addr.bytes));
922 		mlo_peer_free(ml_peer);
923 		mlo_dev_release_link_vdevs(link_vdevs);
924 		return status;
925 	}
926 
927 	/* Allocate Primary UMAC */
928 	mlo_peer_allocate_primary_umac(ml_dev, ml_peer, link_vdevs);
929 
930 	/* Store AID, MLO Peer pointer in link peer, take link peer ref count */
931 	mlo_peer_populate_link_peer(ml_peer, link_peer);
932 
933 	mlo_peer_populate_nawds_params(ml_peer, ml_info);
934 
935 	if ((wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE) ||
936 		((wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE) &&
937 			!is_ml_peer_attached)) {
938 		/* Attach MLO peer to ML Peer table */
939 		status = mlo_dev_mlpeer_attach(ml_dev, ml_peer);
940 		if (status != QDF_STATUS_SUCCESS) {
941 			mlo_err("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " attach failed",
942 				ml_dev->mld_id,
943 				QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes));
944 			mlo_reset_link_peer(ml_peer, link_peer);
945 			wlan_objmgr_peer_release_ref(link_peer,
946 						     WLAN_MLO_MGR_ID);
947 			mlo_peer_free(ml_peer);
948 			mlo_dev_release_link_vdevs(link_vdevs);
949 			return status;
950 		}
951 	}
952 
953 	wlan_mlo_peer_get_ref(ml_peer);
954 
955 	if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE) {
956 		/* Notify other vdevs about link peer creation */
957 		for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
958 			vdev_link = link_vdevs[i];
959 			if (!vdev_link)
960 				continue;
961 
962 			if (vdev_link == vdev)
963 				continue;
964 
965 			mlo_partner_peer_create_post(ml_dev, vdev_link,
966 						     ml_peer, frm_buf, ml_info);
967 		}
968 	}
969 	mlo_dev_release_link_vdevs(link_vdevs);
970 
971 	if (ml_peer->mlpeer_state == ML_PEER_DISCONN_INITIATED) {
972 		mlo_info("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " allocation failed",
973 			 ml_dev->mld_id,
974 			 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes));
975 		wlan_mlo_peer_release_ref(ml_peer);
976 		return QDF_STATUS_E_FAILURE;
977 	}
978 
979 	mlo_info("MLD ID %d ML Peer " QDF_MAC_ADDR_FMT " allocated %pK",
980 		 ml_dev->mld_id,
981 		 QDF_MAC_ADDR_REF(ml_peer->peer_mld_addr.bytes),
982 		 ml_peer);
983 
984 	/*
985 	 * wlan_mlo_peer_create() is trigggered after getting peer
986 	 * assoc confirm from FW. For single link MLO connection, it is
987 	 * OK to trigger assoc response from here.
988 	 */
989 	if ((wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE) &&
990 	    (!wlan_mlo_peer_is_nawds(ml_peer))) {
991 		if (ml_peer->max_links == ml_peer->link_peer_cnt) {
992 			assoc_peer = ml_peer->peer_list[0].link_peer;
993 			if (assoc_peer)
994 				mlo_mlme_peer_assoc_resp(assoc_peer);
995 		}
996 	}
997 
998 	wlan_mlo_peer_release_ref(ml_peer);
999 
1000 	return QDF_STATUS_SUCCESS;
1001 }
1002 
1003 QDF_STATUS wlan_mlo_link_peer_attach(struct wlan_mlo_peer_context *ml_peer,
1004 				     struct wlan_objmgr_peer *peer,
1005 				     qdf_nbuf_t frm_buf)
1006 {
1007 	QDF_STATUS status;
1008 	struct wlan_objmgr_peer *assoc_peer;
1009 	struct wlan_objmgr_vdev *vdev = NULL;
1010 
1011 	if (!ml_peer)
1012 		return QDF_STATUS_E_FAILURE;
1013 
1014 	vdev = wlan_peer_get_vdev(peer);
1015 	if (!vdev)
1016 		return QDF_STATUS_E_FAILURE;
1017 
1018 	/* Populate Link peer pointer, peer MAC address,
1019 	 * MLD address. HW link ID, update ref count
1020 	 */
1021 	status = mlo_peer_attach_link_peer(ml_peer, peer, frm_buf);
1022 	if (QDF_IS_STATUS_ERROR(status))
1023 		return status;
1024 
1025 	/* Store AID, MLO Peer pointer in link peer, take link peer ref count */
1026 	mlo_peer_populate_link_peer(ml_peer, peer);
1027 
1028 	if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE) {
1029 		if (ml_peer->max_links == ml_peer->link_peer_cnt) {
1030 			assoc_peer = ml_peer->peer_list[0].link_peer;
1031 			if (assoc_peer)
1032 				mlo_mlme_peer_assoc_resp(assoc_peer);
1033 		}
1034 	}
1035 
1036 	return status;
1037 }
1038 
1039 QDF_STATUS wlan_mlo_link_peer_delete(struct wlan_objmgr_peer *peer)
1040 {
1041 	struct wlan_mlo_peer_context *ml_peer;
1042 
1043 	ml_peer = peer->mlo_peer_ctx;
1044 
1045 	if (!ml_peer)
1046 		return QDF_STATUS_E_NOENT;
1047 
1048 	mlo_reset_link_peer(ml_peer, peer);
1049 	mlo_peer_detach_link_peer(ml_peer, peer);
1050 	wlan_mlo_peer_release_ref(ml_peer);
1051 
1052 	return QDF_STATUS_SUCCESS;
1053 }
1054 
1055 qdf_export_symbol(wlan_mlo_link_peer_delete);
1056 
1057 qdf_nbuf_t mlo_peer_get_link_peer_assoc_req_buf(
1058 			struct wlan_mlo_peer_context *ml_peer,
1059 			uint8_t link_ix)
1060 {
1061 	struct wlan_objmgr_peer *peer = NULL;
1062 	qdf_nbuf_t assocbuf = NULL;
1063 
1064 	if (!ml_peer)
1065 		return NULL;
1066 
1067 	peer = wlan_mlo_peer_get_assoc_peer(ml_peer);
1068 	if (!peer)
1069 		return NULL;
1070 
1071 	assocbuf = mlo_mlme_get_link_assoc_req(peer, link_ix);
1072 
1073 	return assocbuf;
1074 }
1075 
1076 void wlan_mlo_peer_get_links_info(struct wlan_objmgr_peer *peer,
1077 				  struct mlo_tgt_partner_info *ml_links)
1078 {
1079 	struct wlan_mlo_peer_context *ml_peer;
1080 	struct wlan_mlo_link_peer_entry *peer_entry;
1081 	struct wlan_objmgr_peer *link_peer;
1082 	struct wlan_objmgr_vdev *link_vdev;
1083 	uint8_t i, ix;
1084 
1085 	ml_peer = peer->mlo_peer_ctx;
1086 	ml_links->num_partner_links = 0;
1087 
1088 	if (!ml_peer)
1089 		return;
1090 
1091 	mlo_peer_lock_acquire(ml_peer);
1092 
1093 	if ((ml_peer->mlpeer_state != ML_PEER_CREATED) &&
1094 	    (ml_peer->mlpeer_state != ML_PEER_ASSOC_DONE)) {
1095 		mlo_peer_lock_release(ml_peer);
1096 		return;
1097 	}
1098 
1099 	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
1100 		peer_entry = &ml_peer->peer_list[i];
1101 		link_peer = peer_entry->link_peer;
1102 
1103 		if (!link_peer)
1104 			continue;
1105 
1106 		if (link_peer == peer)
1107 			continue;
1108 
1109 		link_vdev = wlan_peer_get_vdev(link_peer);
1110 		if (!link_vdev)
1111 			continue;
1112 
1113 		if (ml_links->num_partner_links >= WLAN_UMAC_MLO_MAX_VDEVS)
1114 			break;
1115 
1116 		ix = ml_links->num_partner_links;
1117 		ml_links->link_info[ix].vdev_id = wlan_vdev_get_id(link_vdev);
1118 		ml_links->link_info[ix].hw_mld_link_id = peer_entry->hw_link_id;
1119 		ml_links->num_partner_links++;
1120 	}
1121 	mlo_peer_lock_release(ml_peer);
1122 }
1123 
1124 qdf_export_symbol(wlan_mlo_peer_get_links_info);
1125 
1126 void wlan_mlo_peer_get_partner_links_info(struct wlan_objmgr_peer *peer,
1127 					  struct mlo_partner_info *ml_links)
1128 {
1129 	struct wlan_mlo_peer_context *ml_peer;
1130 	struct wlan_mlo_link_peer_entry *peer_entry;
1131 	struct wlan_objmgr_peer *link_peer;
1132 	struct wlan_objmgr_vdev *link_vdev;
1133 	uint8_t i, ix;
1134 
1135 	ml_peer = peer->mlo_peer_ctx;
1136 	ml_links->num_partner_links = 0;
1137 
1138 	if (!ml_peer)
1139 		return;
1140 
1141 	mlo_peer_lock_acquire(ml_peer);
1142 
1143 	if ((ml_peer->mlpeer_state != ML_PEER_CREATED) &&
1144 	    (ml_peer->mlpeer_state != ML_PEER_ASSOC_DONE)) {
1145 		mlo_peer_lock_release(ml_peer);
1146 		return;
1147 	}
1148 
1149 	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
1150 		peer_entry = &ml_peer->peer_list[i];
1151 		link_peer = peer_entry->link_peer;
1152 
1153 		if (!link_peer)
1154 			continue;
1155 
1156 		if (link_peer == peer)
1157 			continue;
1158 
1159 		link_vdev = wlan_peer_get_vdev(link_peer);
1160 		if (!link_vdev)
1161 			continue;
1162 
1163 		if (ml_links->num_partner_links >= WLAN_UMAC_MLO_MAX_VDEVS)
1164 			break;
1165 
1166 		ix = ml_links->num_partner_links;
1167 		ml_links->partner_link_info[ix].link_id = peer_entry->link_ix;
1168 
1169 		qdf_copy_macaddr(&ml_links->partner_link_info[ix].link_addr,
1170 				 &peer_entry->link_addr);
1171 		ml_links->num_partner_links++;
1172 	}
1173 	mlo_peer_lock_release(ml_peer);
1174 }
1175 
1176 qdf_export_symbol(wlan_mlo_peer_get_partner_links_info);
1177 
1178 #ifdef UMAC_SUPPORT_MLNAWDS
1179 bool wlan_mlo_peer_is_nawds(struct wlan_mlo_peer_context *ml_peer)
1180 {
1181 	bool status = false;
1182 
1183 	if (!ml_peer)
1184 		return status;
1185 
1186 	mlo_peer_lock_acquire(ml_peer);
1187 	if (ml_peer->is_nawds_ml_peer)
1188 		status = true;
1189 	mlo_peer_lock_release(ml_peer);
1190 
1191 	return status;
1192 }
1193 
1194 qdf_export_symbol(wlan_mlo_peer_is_nawds);
1195 #endif
1196 
1197 #ifdef UMAC_MLO_AUTH_DEFER
1198 void mlo_peer_free_auth_param(struct mlpeer_auth_params *auth_params)
1199 {
1200 	if (auth_params->rs)
1201 		qdf_mem_free(auth_params->rs);
1202 
1203 	if (auth_params->wbuf)
1204 		qdf_nbuf_free(auth_params->wbuf);
1205 
1206 	qdf_mem_free(auth_params);
1207 }
1208 
1209 QDF_STATUS mlo_peer_link_auth_defer(struct wlan_mlo_peer_context *ml_peer,
1210 				    struct qdf_mac_addr *link_mac,
1211 				    struct mlpeer_auth_params *auth_params)
1212 {
1213 	uint8_t i;
1214 	uint8_t free_entries = 0;
1215 	struct mlpeer_auth_params *recv_auth;
1216 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
1217 
1218 	if (!ml_peer)
1219 		return status;
1220 
1221 	mlo_peer_lock_acquire(ml_peer);
1222 	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
1223 		recv_auth = ml_peer->pending_auth[i];
1224 		if (!recv_auth) {
1225 			free_entries++;
1226 			continue;
1227 		}
1228 		/* overwrite the entry with latest entry */
1229 		if (qdf_is_macaddr_equal(link_mac, &recv_auth->link_addr)) {
1230 			mlo_peer_free_auth_param(recv_auth);
1231 			ml_peer->pending_auth[i] = auth_params;
1232 			mlo_peer_lock_release(ml_peer);
1233 
1234 			return QDF_STATUS_SUCCESS;
1235 		}
1236 	}
1237 
1238 	if (!free_entries) {
1239 		mlo_peer_lock_release(ml_peer);
1240 		return QDF_STATUS_E_FAILURE;
1241 	}
1242 
1243 	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
1244 		recv_auth = ml_peer->pending_auth[i];
1245 		if (!recv_auth) {
1246 			ml_peer->pending_auth[i] = auth_params;
1247 			status = QDF_STATUS_SUCCESS;
1248 			break;
1249 		}
1250 	}
1251 	mlo_peer_lock_release(ml_peer);
1252 
1253 	return status;
1254 }
1255 #endif
1256