xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlo_mgr/src/wlan_mlo_mgr_peer.c (revision 2f4b444fb7e689b83a4ab0e7b3b38f0bf4def8e0)
1 /*
2  * Copyright (c) 2021, The Linux Foundation. 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 #include "wlan_mlo_mgr_main.h"
18 #include "qdf_types.h"
19 #include "wlan_cmn.h"
20 #include "wlan_mlo_mgr_msgq.h"
21 #include "wlan_objmgr_peer_obj.h"
22 #include "wlan_mlo_mgr_peer.h"
23 #include "wlan_mlo_mgr_ap.h"
24 
25 static void mlo_partner_peer_create_post(struct wlan_mlo_dev_context *ml_dev,
26 					 struct wlan_objmgr_vdev *vdev_link,
27 					 struct wlan_mlo_peer_context *ml_peer,
28 					 qdf_nbuf_t frm_buf,
29 					 struct mlo_partner_info *ml_info)
30 {
31 	struct peer_create_notif_s peer_create;
32 	QDF_STATUS status;
33 	uint8_t i;
34 	uint8_t link_id;
35 
36 	if (wlan_objmgr_vdev_try_get_ref(vdev_link, WLAN_MLO_MGR_ID) ==
37 							QDF_STATUS_SUCCESS) {
38 		peer_create.vdev_link = vdev_link;
39 	} else {
40 		mlo_err("VDEV is not in created state");
41 		return;
42 	}
43 
44 	wlan_mlo_peer_get_ref(ml_peer);
45 	peer_create.ml_peer = ml_peer;
46 	link_id = wlan_vdev_get_link_id(vdev_link);
47 	for (i = 0; i < ml_info->num_partner_links; i++) {
48 		if (link_id != ml_info->partner_link_info[i].link_id)
49 			continue;
50 
51 		qdf_copy_macaddr(&peer_create.addr,
52 				 &ml_info->partner_link_info[i].link_addr);
53 		break;
54 	}
55 
56 	peer_create.frm_buf = qdf_nbuf_clone(frm_buf);
57 	if (!peer_create.frm_buf) {
58 		wlan_mlo_peer_release_ref(ml_peer);
59 		wlan_objmgr_vdev_release_ref(vdev_link, WLAN_MLO_MGR_ID);
60 		mlo_err("nbuf clone is failed");
61 		return;
62 	}
63 
64 	status = mlo_msgq_post(MLO_PEER_CREATE, ml_dev, &peer_create);
65 	if (status != QDF_STATUS_SUCCESS) {
66 		qdf_nbuf_free(frm_buf);
67 		wlan_mlo_peer_release_ref(ml_peer);
68 		wlan_objmgr_vdev_release_ref(vdev_link, WLAN_MLO_MGR_ID);
69 	}
70 }
71 
72 static void mlo_link_peer_assoc_notify(struct wlan_mlo_dev_context *ml_dev,
73 				       struct wlan_objmgr_peer *peer)
74 {
75 	struct peer_assoc_notify_s peer_assoc;
76 	QDF_STATUS status;
77 
78 	peer_assoc.peer = peer;
79 	status = mlo_msgq_post(MLO_PEER_ASSOC, ml_dev, &peer_assoc);
80 	if (status != QDF_STATUS_SUCCESS)
81 		wlan_objmgr_peer_release_ref(peer, WLAN_MLO_MGR_ID);
82 }
83 
84 static void mlo_link_peer_send_assoc_fail(struct wlan_mlo_dev_context *ml_dev,
85 					  struct wlan_objmgr_peer *peer)
86 {
87 	struct peer_assoc_fail_notify_s peer_assoc_fail;
88 	QDF_STATUS status;
89 
90 	peer_assoc_fail.peer = peer;
91 	status = mlo_msgq_post(MLO_PEER_ASSOC_FAIL, ml_dev, &peer_assoc_fail);
92 	if (status != QDF_STATUS_SUCCESS)
93 		wlan_objmgr_peer_release_ref(peer, WLAN_MLO_MGR_ID);
94 }
95 
96 static void mlo_link_peer_disconnect_notify(struct wlan_mlo_dev_context *ml_dev,
97 					    struct wlan_objmgr_peer *peer)
98 {
99 	struct peer_discon_notify_s peer_disconn;
100 	QDF_STATUS status;
101 
102 	peer_disconn.peer = peer;
103 	status = mlo_msgq_post(MLO_PEER_DISCONNECT, ml_dev, &peer_disconn);
104 	if (status != QDF_STATUS_SUCCESS)
105 		wlan_objmgr_peer_release_ref(peer, WLAN_MLO_MGR_ID);
106 }
107 
108 QDF_STATUS
109 wlan_mlo_peer_is_disconnect_progress(struct wlan_mlo_peer_context *ml_peer)
110 {
111 	QDF_STATUS status;
112 
113 	mlo_peer_lock_acquire(ml_peer);
114 
115 	if (ml_peer->mlpeer_state == ML_PEER_DISCONN_INITIATED)
116 		status = QDF_STATUS_SUCCESS;
117 	else
118 		status = QDF_STATUS_E_FAILURE;
119 
120 	mlo_peer_lock_release(ml_peer);
121 
122 	return status;
123 }
124 
125 QDF_STATUS wlan_mlo_peer_is_assoc_done(struct wlan_mlo_peer_context *ml_peer)
126 {
127 	QDF_STATUS status;
128 
129 	mlo_peer_lock_acquire(ml_peer);
130 
131 	if (ml_peer->mlpeer_state == ML_PEER_ASSOC_DONE)
132 		status = QDF_STATUS_SUCCESS;
133 	else
134 		status = QDF_STATUS_E_FAILURE;
135 
136 	mlo_peer_lock_release(ml_peer);
137 
138 	return status;
139 }
140 
141 struct wlan_objmgr_peer *wlan_mlo_peer_get_assoc_peer(
142 					struct wlan_mlo_peer_context *ml_peer)
143 {
144 	struct wlan_mlo_link_peer_entry *peer_entry;
145 	struct wlan_objmgr_peer *assoc_peer = NULL;
146 
147 	mlo_peer_lock_acquire(ml_peer);
148 
149 	peer_entry = &ml_peer->peer_list[0];
150 
151 	if (peer_entry->link_peer)
152 		assoc_peer = peer_entry->link_peer;
153 
154 	mlo_peer_lock_release(ml_peer);
155 
156 	return assoc_peer;
157 }
158 
159 void wlan_mlo_partner_peer_assoc_post(struct wlan_objmgr_peer *assoc_peer)
160 {
161 	struct wlan_mlo_dev_context *ml_dev;
162 	struct wlan_mlo_peer_context *ml_peer;
163 	struct wlan_objmgr_peer *link_peer;
164 	struct wlan_objmgr_peer *link_peers[MAX_MLO_LINK_PEERS];
165 	struct wlan_mlo_link_peer_entry *peer_entry;
166 	uint16_t i;
167 
168 	ml_peer = assoc_peer->mlo_peer_ctx;
169 	mlo_peer_lock_acquire(ml_peer);
170 
171 	if (ml_peer->mlpeer_state != ML_PEER_CREATED) {
172 		mlo_peer_lock_release(ml_peer);
173 		return;
174 	}
175 
176 	ml_peer->mlpeer_state = ML_PEER_ASSOC_DONE;
177 	ml_dev = ml_peer->ml_dev;
178 
179 	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
180 		link_peers[i] = NULL;
181 		peer_entry = &ml_peer->peer_list[i];
182 
183 		if (!peer_entry->link_peer)
184 			continue;
185 
186 		if (peer_entry->link_peer == assoc_peer)
187 			continue;
188 
189 		link_peer = peer_entry->link_peer;
190 
191 		if (wlan_objmgr_peer_try_get_ref(link_peer, WLAN_MLO_MGR_ID) !=
192 						 QDF_STATUS_SUCCESS)
193 			continue;
194 
195 		link_peers[i] = link_peer;
196 	}
197 	mlo_peer_lock_release(ml_peer);
198 
199 	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
200 		if (!link_peers[i])
201 			continue;
202 
203 		/* Prepare and queue message */
204 		mlo_link_peer_assoc_notify(ml_dev, link_peers[i]);
205 	}
206 }
207 
208 void
209 wlan_mlo_partner_peer_create_failed_notify(
210 				struct wlan_mlo_peer_context *ml_peer)
211 {
212 	struct wlan_mlo_dev_context *ml_dev;
213 	struct wlan_objmgr_peer *link_peer;
214 	struct wlan_objmgr_peer *link_peers[MAX_MLO_LINK_PEERS];
215 	struct wlan_mlo_link_peer_entry *peer_entry;
216 	uint16_t i;
217 
218 	mlo_peer_lock_acquire(ml_peer);
219 
220 	if (ml_peer->mlpeer_state == ML_PEER_DISCONN_INITIATED) {
221 		mlo_peer_lock_release(ml_peer);
222 		return;
223 	}
224 
225 	ml_peer->mlpeer_state = ML_PEER_DISCONN_INITIATED;
226 	ml_dev = ml_peer->ml_dev;
227 
228 	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
229 		link_peers[i] = NULL;
230 		peer_entry = &ml_peer->peer_list[i];
231 		if (!peer_entry->link_peer)
232 			continue;
233 
234 		link_peer = peer_entry->link_peer;
235 		if (wlan_objmgr_peer_try_get_ref(link_peer, WLAN_MLO_MGR_ID) !=
236 						QDF_STATUS_SUCCESS)
237 			continue;
238 
239 		link_peers[i] = link_peer;
240 	}
241 	mlo_peer_lock_release(ml_peer);
242 
243 	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
244 		if (!link_peers[i])
245 			continue;
246 
247 		/* Prepare and queue message */
248 		if (i == 0)
249 			mlo_link_peer_send_assoc_fail(ml_dev, link_peers[i]);
250 		else
251 			mlo_link_peer_disconnect_notify(ml_dev, link_peers[i]);
252 	}
253 }
254 
255 void wlan_mlo_partner_peer_disconnect_notify(struct wlan_objmgr_peer *src_peer)
256 {
257 	struct wlan_mlo_dev_context *ml_dev;
258 	struct wlan_mlo_peer_context *ml_peer;
259 	struct wlan_objmgr_peer *link_peer;
260 	struct wlan_objmgr_peer *link_peers[MAX_MLO_LINK_PEERS];
261 	struct wlan_mlo_link_peer_entry *peer_entry;
262 	uint16_t i;
263 
264 	ml_peer = src_peer->mlo_peer_ctx;
265 	mlo_peer_lock_acquire(ml_peer);
266 
267 	if (ml_peer->mlpeer_state == ML_PEER_DISCONN_INITIATED) {
268 		mlo_peer_lock_release(ml_peer);
269 		return;
270 	}
271 
272 	ml_peer->mlpeer_state = ML_PEER_DISCONN_INITIATED;
273 	ml_dev = ml_peer->ml_dev;
274 	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
275 		link_peers[i] = NULL;
276 		peer_entry = &ml_peer->peer_list[i];
277 		if (!peer_entry->link_peer) {
278 			mlo_debug("link peer is null");
279 			continue;
280 		}
281 
282 		if (peer_entry->link_peer == src_peer)
283 			continue;
284 
285 		link_peer = peer_entry->link_peer;
286 		if (wlan_objmgr_peer_try_get_ref(link_peer, WLAN_MLO_MGR_ID) !=
287 						QDF_STATUS_SUCCESS)
288 			continue;
289 
290 		link_peers[i] = link_peer;
291 	}
292 	mlo_peer_lock_release(ml_peer);
293 
294 	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
295 		if (!link_peers[i])
296 			continue;
297 
298 		/* Prepare and queue message */
299 		mlo_link_peer_disconnect_notify(ml_dev, link_peers[i]);
300 	}
301 }
302 
303 static void mlo_peer_populate_link_peer(
304 			struct wlan_mlo_peer_context *ml_peer,
305 			struct wlan_objmgr_peer *link_peer)
306 {
307 	mlo_peer_lock_acquire(ml_peer);
308 	wlan_mlo_peer_get_ref(ml_peer);
309 	link_peer->mlo_peer_ctx = ml_peer;
310 	mlo_peer_lock_release(ml_peer);
311 }
312 
313 static void mlo_reset_link_peer(
314 			struct wlan_mlo_peer_context *ml_peer,
315 			struct wlan_objmgr_peer *link_peer)
316 {
317 	mlo_peer_lock_acquire(ml_peer);
318 	link_peer->mlo_peer_ctx = NULL;
319 	mlo_peer_lock_release(ml_peer);
320 }
321 
322 void mlo_peer_free(struct wlan_mlo_peer_context *ml_peer)
323 {
324 	struct wlan_mlo_dev_context *ml_dev;
325 
326 	ml_dev = ml_peer->ml_dev;
327 	if (!ml_dev) {
328 		mlo_err("ML DEV is NULL");
329 		return;
330 	}
331 
332 	mlo_peer_lock_destroy(ml_peer);
333 	mlo_ap_ml_peerid_free(ml_peer->mlo_peer_id);
334 	mlo_peer_free_aid(ml_dev, ml_peer);
335 	mlo_peer_free_primary_umac(ml_dev, ml_peer);
336 	mlo_dev_mlpeer_detach(ml_dev, ml_peer);
337 	qdf_mem_free(ml_peer);
338 }
339 
340 static QDF_STATUS mlo_peer_attach_link_peer(
341 		struct wlan_mlo_peer_context *ml_peer,
342 		struct wlan_objmgr_peer *link_peer)
343 {
344 	struct wlan_mlo_link_peer_entry *peer_entry;
345 	QDF_STATUS status = QDF_STATUS_E_RESOURCES;
346 	uint16_t i;
347 
348 	mlo_peer_lock_acquire(ml_peer);
349 
350 	if (ml_peer->mlpeer_state != ML_PEER_CREATED) {
351 		mlo_peer_lock_release(ml_peer);
352 		return status;
353 	}
354 
355 	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
356 		peer_entry = &ml_peer->peer_list[i];
357 		if (peer_entry->link_peer)
358 			continue;
359 
360 		if (wlan_objmgr_peer_try_get_ref(link_peer, WLAN_MLO_MGR_ID) !=
361 						QDF_STATUS_SUCCESS)
362 			break;
363 
364 		peer_entry->link_peer = link_peer;
365 		qdf_copy_macaddr(&peer_entry->link_addr,
366 				 (struct qdf_mac_addr *)&link_peer->macaddr[0]);
367 
368 		peer_entry->link_ix = i + 1;
369 		peer_entry->hw_link_id = 1;
370 		/*wlan_peer_get_hw_link_id(link_peer)TODO*/
371 		mlo_peer_assign_primary_umac(ml_peer, peer_entry);
372 
373 		status = QDF_STATUS_SUCCESS;
374 		break;
375 	}
376 	if (QDF_IS_STATUS_SUCCESS(status))
377 		ml_peer->link_peer_cnt++;
378 
379 	mlo_peer_lock_release(ml_peer);
380 
381 	return status;
382 }
383 
384 static QDF_STATUS mlo_peer_detach_link_peer(
385 		struct wlan_mlo_peer_context *ml_peer,
386 		struct wlan_objmgr_peer *link_peer)
387 {
388 	struct wlan_mlo_link_peer_entry *peer_entry;
389 	QDF_STATUS status = QDF_STATUS_E_RESOURCES;
390 	uint16_t i;
391 
392 	mlo_peer_lock_acquire(ml_peer);
393 
394 	if (ml_peer->mlpeer_state != ML_PEER_DISCONN_INITIATED) {
395 		mlo_peer_lock_release(ml_peer);
396 		return status;
397 	}
398 
399 	for (i = 0; i < MAX_MLO_LINK_PEERS; i++) {
400 		peer_entry = &ml_peer->peer_list[i];
401 		if (!peer_entry->link_peer)
402 			continue;
403 
404 		if (peer_entry->link_peer != link_peer)
405 			continue;
406 
407 		wlan_objmgr_peer_release_ref(link_peer, WLAN_MLO_MGR_ID);
408 		peer_entry->link_peer = NULL;
409 		ml_peer->link_peer_cnt--;
410 		status = QDF_STATUS_SUCCESS;
411 		break;
412 	}
413 	mlo_peer_lock_release(ml_peer);
414 
415 	return status;
416 }
417 
418 static QDF_STATUS mlo_dev_get_link_vdevs(
419 			struct wlan_objmgr_vdev *vdev,
420 			struct wlan_mlo_dev_context *ml_dev,
421 			struct mlo_partner_info *ml_info,
422 			struct wlan_objmgr_vdev *link_vdevs[])
423 {
424 	uint16_t i, j;
425 	struct wlan_objmgr_vdev *vdev_link;
426 	uint8_t link_id;
427 
428 	if (!ml_dev) {
429 		mlo_err("ml_dev is null");
430 		return QDF_STATUS_E_INVAL;
431 	}
432 
433 	if (!ml_info) {
434 		mlo_err("ml_info is null");
435 		return QDF_STATUS_E_INVAL;
436 	}
437 
438 	mlo_debug("num_partner_links %d", ml_info->num_partner_links);
439 	for (i = 0; i < ml_info->num_partner_links; i++) {
440 		link_id = ml_info->partner_link_info[i].link_id;
441 		vdev_link = mlo_get_vdev_by_link_id(vdev, link_id);
442 		if (vdev_link) {
443 			link_vdevs[i] = vdev_link;
444 		} else {
445 			/* release ref which were taken before failure */
446 			for (j = 0; j < i; j++) {
447 				vdev_link = link_vdevs[j];
448 				if (!vdev_link)
449 					continue;
450 
451 				wlan_objmgr_vdev_release_ref(vdev_link,
452 							     WLAN_MLO_MGR_ID);
453 			}
454 			return QDF_STATUS_E_INVAL;
455 		}
456 	}
457 
458 	return QDF_STATUS_SUCCESS;
459 }
460 
461 static void mlo_dev_release_link_vdevs(
462 			struct wlan_objmgr_vdev *link_vdevs[])
463 {
464 	uint16_t i;
465 	struct wlan_objmgr_vdev *vdev_link;
466 
467 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
468 		vdev_link = link_vdevs[i];
469 		if (!vdev_link)
470 			continue;
471 
472 		wlan_objmgr_vdev_release_ref(vdev_link, WLAN_MLO_MGR_ID);
473 	}
474 }
475 
476 QDF_STATUS wlan_mlo_peer_create(struct wlan_objmgr_vdev *vdev,
477 				struct wlan_objmgr_peer *link_peer,
478 				struct mlo_partner_info *ml_info,
479 				qdf_nbuf_t frm_buf,
480 				uint16_t aid)
481 {
482 	struct wlan_mlo_dev_context *ml_dev;
483 	struct wlan_mlo_peer_context *ml_peer;
484 	struct wlan_objmgr_vdev *link_vdevs[WLAN_UMAC_MLO_MAX_VDEVS] = { NULL };
485 	struct wlan_objmgr_vdev *vdev_link;
486 	QDF_STATUS status;
487 	uint16_t i;
488 
489 	/* get ML VDEV from VDEV */
490 	ml_dev = vdev->mlo_dev_ctx;
491 
492 	/* Check resources of Partner VDEV */
493 	status = mlo_dev_get_link_vdevs(vdev, ml_dev, ml_info, link_vdevs);
494 	if (QDF_IS_STATUS_ERROR(status))
495 		return QDF_STATUS_E_FAILURE;
496 
497 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
498 		vdev_link = link_vdevs[i];
499 		if (!vdev_link) {
500 			mlo_debug("vdev_link is null");
501 			continue;
502 		}
503 
504 		if (wlan_vdev_is_peer_create_allowed(vdev_link)
505 			!= QDF_STATUS_SUCCESS) {
506 			mlo_dev_release_link_vdevs(link_vdevs);
507 			return QDF_STATUS_E_INVAL;
508 		}
509 	}
510 
511 	for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
512 		vdev_link = link_vdevs[i];
513 		if (vdev_link && (vdev_link != vdev) &&
514 		    (wlan_vdev_get_peer_count(vdev_link) >
515 		     wlan_vdev_get_max_peer_count(vdev_link))) {
516 			mlo_dev_release_link_vdevs(link_vdevs);
517 			return QDF_STATUS_E_RESOURCES;
518 		}
519 	}
520 
521 	/* Allocate MLO peer */
522 	ml_peer = qdf_mem_malloc(sizeof(*ml_peer));
523 	if (!ml_peer) {
524 		mlo_dev_release_link_vdevs(link_vdevs);
525 		return QDF_STATUS_E_NOMEM;
526 	}
527 
528 	qdf_atomic_init(&ml_peer->ref_cnt);
529 	mlo_peer_lock_create(ml_peer);
530 	ml_peer->ml_dev = ml_dev;
531 	ml_peer->mlpeer_state = ML_PEER_CREATED;
532 	ml_peer->max_links = ml_info->num_partner_links;
533 	ml_peer->primary_umac_psoc_id = ML_PRIMARY_UMAC_ID_INVAL;
534 	ml_peer->mlo_peer_id = mlo_ap_ml_peerid_alloc();
535 	qdf_copy_macaddr((struct qdf_mac_addr *)&ml_peer->peer_mld_addr,
536 			 (struct qdf_mac_addr *)&link_peer->mldaddr[0]);
537 	/* Allocate AID */
538 	if (aid == (uint16_t)-1)
539 		mlo_peer_allocate_aid(ml_dev, ml_peer);
540 	else
541 		ml_peer->assoc_id = aid;
542 
543 	/* Populate Link peer pointer, peer MAC address,
544 	 * MLD address. HW link ID, update ref count
545 	 */
546 	mlo_peer_attach_link_peer(ml_peer, link_peer);
547 
548 	/* Allocate Primary UMAC */
549 	mlo_peer_allocate_primary_umac(ml_dev, ml_peer, link_vdevs);
550 
551 	/* Store AID, MLO Peer pointer in link peer, take link peer ref count */
552 	mlo_peer_populate_link_peer(ml_peer, link_peer);
553 
554 	/* Attach MLO peer to ML Peer table */
555 	status = mlo_dev_mlpeer_attach(ml_dev, ml_peer);
556 	if (status != QDF_STATUS_SUCCESS) {
557 		mlo_reset_link_peer(ml_peer, link_peer);
558 		mlo_peer_free(ml_peer);
559 		mlo_dev_release_link_vdevs(link_vdevs);
560 		return status;
561 	}
562 
563 	if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE) {
564 		/* Notify other vdevs about link peer creation */
565 		for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) {
566 			vdev_link = link_vdevs[i];
567 			if (!vdev_link)
568 				continue;
569 
570 			if (vdev_link == vdev)
571 				continue;
572 
573 			mlo_partner_peer_create_post(ml_dev, vdev_link,
574 						     ml_peer, frm_buf, ml_info);
575 		}
576 	}
577 	mlo_dev_release_link_vdevs(link_vdevs);
578 
579 	return QDF_STATUS_SUCCESS;
580 }
581 
582 QDF_STATUS wlan_mlo_link_peer_attach(struct wlan_mlo_peer_context *ml_peer,
583 				     struct wlan_objmgr_peer *peer)
584 {
585 	QDF_STATUS status;
586 	struct wlan_objmgr_peer *assoc_peer;
587 
588 	/* Populate Link peer pointer, peer MAC address,
589 	 * MLD address. HW link ID, update ref count
590 	 */
591 	status = mlo_peer_attach_link_peer(ml_peer, peer);
592 	if (QDF_IS_STATUS_ERROR(status))
593 		return status;
594 
595 	/* Store AID, MLO Peer pointer in link peer, take link peer ref count */
596 	mlo_peer_populate_link_peer(ml_peer, peer);
597 
598 	if (ml_peer->max_links == ml_peer->link_peer_cnt) {
599 		assoc_peer = ml_peer->peer_list[0].link_peer;
600 		if (assoc_peer)
601 			mlo_mlme_peer_assoc_resp(assoc_peer);
602 	}
603 
604 	return status;
605 }
606 
607 QDF_STATUS wlan_mlo_link_peer_delete(struct wlan_objmgr_peer *peer)
608 {
609 	struct wlan_mlo_peer_context *ml_peer;
610 
611 	ml_peer = peer->mlo_peer_ctx;
612 
613 	if (!ml_peer)
614 		return QDF_STATUS_E_NOENT;
615 
616 	mlo_reset_link_peer(ml_peer, peer);
617 	mlo_peer_detach_link_peer(ml_peer, peer);
618 	wlan_mlo_peer_release_ref(ml_peer);
619 
620 	return QDF_STATUS_SUCCESS;
621 }
622