xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlo_mgr/src/wlan_mlo_mgr_main.c (revision d0c05845839e5f2ba5a8dcebe0cd3e4cd4e8dfcf)
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 /*
19  * DOC: contains MLO manager init/deinit api's
20  */
21 #include "wlan_cmn.h"
22 #include <wlan_objmgr_cmn.h>
23 #include <wlan_objmgr_global_obj.h>
24 #include "wlan_mlo_mgr_cmn.h"
25 #include "wlan_mlo_mgr_main.h"
26 #include <wlan_mlo_mgr_ap.h>
27 #include <wlan_mlo_mgr_peer.h>
28 #include <wlan_mlo_mgr_setup.h>
29 #include <wlan_cm_public_struct.h>
30 #include "wlan_mlo_mgr_msgq.h"
31 #include <target_if_mlo_mgr.h>
32 
33 static void mlo_global_ctx_deinit(void)
34 {
35 	struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx();
36 
37 	if (!mlo_mgr_ctx)
38 		return;
39 
40 	if (qdf_list_empty(&mlo_mgr_ctx->ml_dev_list))
41 		mlo_err("ML dev list is not empty");
42 
43 	mlo_setup_deinit();
44 	mlo_msgq_free();
45 	ml_peerid_lock_destroy(mlo_mgr_ctx);
46 	ml_link_lock_destroy(mlo_mgr_ctx);
47 	ml_aid_lock_destroy(mlo_mgr_ctx);
48 	qdf_list_destroy(&mlo_mgr_ctx->ml_dev_list);
49 
50 	qdf_mem_free(mlo_mgr_ctx);
51 	wlan_objmgr_set_mlo_ctx(NULL);
52 }
53 
54 static void mlo_global_ctx_init(void)
55 {
56 	struct mlo_mgr_context *mlo_mgr_ctx;
57 
58 	/* If it is already created, ignore */
59 	if (wlan_objmgr_get_mlo_ctx()) {
60 		mlo_err("Global object is already created");
61 		return;
62 	}
63 
64 	/* Allocation of memory for Global object */
65 	mlo_mgr_ctx = (struct mlo_mgr_context *)
66 			qdf_mem_malloc(sizeof(*mlo_mgr_ctx));
67 	if (!mlo_mgr_ctx)
68 		return;
69 
70 	wlan_objmgr_set_mlo_ctx(mlo_mgr_ctx);
71 
72 	qdf_list_create(&mlo_mgr_ctx->ml_dev_list, WLAN_UMAC_MLO_MAX_DEV);
73 	mlo_mgr_ctx->max_mlo_peer_id = MAX_MLO_PEER_ID;
74 	ml_peerid_lock_create(mlo_mgr_ctx);
75 	ml_link_lock_create(mlo_mgr_ctx);
76 	ml_aid_lock_create(mlo_mgr_ctx);
77 	mlo_mgr_ctx->mlo_is_force_primary_umac = 0;
78 	mlo_msgq_init();
79 	mlo_setup_init();
80 }
81 
82 QDF_STATUS wlan_mlo_mgr_psoc_enable(struct wlan_objmgr_psoc *psoc)
83 {
84 	struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops;
85 
86 	if (!psoc) {
87 		mlo_err("psoc is null");
88 		return QDF_STATUS_E_NULL_VALUE;
89 	}
90 
91 	mlo_tx_ops = target_if_mlo_get_tx_ops(psoc);
92 	if (!mlo_tx_ops) {
93 		mlo_err("tx_ops is null!");
94 		return QDF_STATUS_E_NULL_VALUE;
95 	}
96 
97 	if (!mlo_tx_ops->register_events) {
98 		mlo_err("register_events function is null!");
99 		return QDF_STATUS_E_NULL_VALUE;
100 	}
101 
102 	return mlo_tx_ops->register_events(psoc);
103 }
104 
105 QDF_STATUS wlan_mlo_mgr_psoc_disable(struct wlan_objmgr_psoc *psoc)
106 {
107 	struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops;
108 
109 	if (!psoc) {
110 		mlo_err("psoc is null");
111 		return QDF_STATUS_E_NULL_VALUE;
112 	}
113 
114 	mlo_tx_ops = target_if_mlo_get_tx_ops(psoc);
115 	if (!mlo_tx_ops) {
116 		mlo_err("tx_ops is null!");
117 		return QDF_STATUS_E_NULL_VALUE;
118 	}
119 
120 	if (!mlo_tx_ops->unregister_events) {
121 		mlo_err("unregister_events function is null!");
122 		return QDF_STATUS_E_NULL_VALUE;
123 	}
124 
125 	return mlo_tx_ops->unregister_events(psoc);
126 }
127 
128 QDF_STATUS wlan_mlo_mgr_init(void)
129 {
130 	QDF_STATUS status;
131 
132 	mlo_global_ctx_init();
133 
134 	status = wlan_objmgr_register_vdev_create_handler(
135 		WLAN_UMAC_COMP_MLO_MGR,
136 		wlan_mlo_mgr_vdev_created_notification, NULL);
137 	if (QDF_IS_STATUS_ERROR(status)) {
138 		mlo_err("Failed to register vdev create handler");
139 		return QDF_STATUS_E_FAILURE;
140 	}
141 
142 	status = wlan_objmgr_register_vdev_destroy_handler(WLAN_UMAC_COMP_MLO_MGR,
143 		wlan_mlo_mgr_vdev_destroyed_notification, NULL);
144 	if (QDF_IS_STATUS_SUCCESS(status)) {
145 		mlo_debug("MLO vdev create and delete handler registered with objmgr");
146 		return QDF_STATUS_SUCCESS;
147 	}
148 	wlan_objmgr_unregister_vdev_create_handler(WLAN_UMAC_COMP_MLO_MGR,
149 				wlan_mlo_mgr_vdev_created_notification, NULL);
150 
151 	return status;
152 }
153 
154 QDF_STATUS wlan_mlo_mgr_deinit(void)
155 {
156 	QDF_STATUS status;
157 	struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx();
158 
159 	if (!mlo_mgr_ctx) {
160 		mlo_err("MLO global object is not allocated");
161 		return QDF_STATUS_E_FAILURE;
162 	}
163 
164 	mlo_global_ctx_deinit();
165 
166 	status = wlan_objmgr_unregister_vdev_create_handler(
167 		WLAN_UMAC_COMP_MLO_MGR,
168 		wlan_mlo_mgr_vdev_created_notification, NULL);
169 	if (status != QDF_STATUS_SUCCESS)
170 		mlo_err("Failed to unregister vdev create handler");
171 
172 	status = wlan_objmgr_unregister_vdev_destroy_handler(
173 			WLAN_UMAC_COMP_MLO_MGR,
174 			wlan_mlo_mgr_vdev_destroyed_notification, NULL);
175 	if (status != QDF_STATUS_SUCCESS)
176 		mlo_err("Failed to unregister vdev delete handler");
177 
178 	return status;
179 }
180 
181 static inline struct wlan_mlo_dev_context *mlo_list_peek_head(
182 					qdf_list_t *ml_list)
183 {
184 	struct wlan_mlo_dev_context *mld_ctx;
185 	qdf_list_node_t *ml_node = NULL;
186 
187 	/* This API is invoked with lock acquired, do not add log prints */
188 	if (qdf_list_peek_front(ml_list, &ml_node) != QDF_STATUS_SUCCESS)
189 		return NULL;
190 
191 	mld_ctx = qdf_container_of(ml_node, struct wlan_mlo_dev_context,
192 				   node);
193 
194 	return mld_ctx;
195 }
196 
197 static inline
198 struct wlan_mlo_dev_context *mlo_get_next_mld_ctx(qdf_list_t *ml_list,
199 					struct wlan_mlo_dev_context *mld_cur)
200 {
201 	struct wlan_mlo_dev_context *mld_next;
202 	qdf_list_node_t *node = &mld_cur->node;
203 	qdf_list_node_t *next_node = NULL;
204 
205 	/* This API is invoked with lock acquired, do not add log prints */
206 	if (!node)
207 		return NULL;
208 
209 	if (qdf_list_peek_next(ml_list, node, &next_node) !=
210 						QDF_STATUS_SUCCESS)
211 		return NULL;
212 
213 	mld_next = qdf_container_of(next_node, struct wlan_mlo_dev_context,
214 				    node);
215 	return mld_next;
216 }
217 
218 struct wlan_mlo_dev_context
219 *wlan_mlo_get_mld_ctx_by_mldaddr(struct qdf_mac_addr *mldaddr)
220 {
221 	struct wlan_mlo_dev_context *mld_cur;
222 	struct wlan_mlo_dev_context *mld_next;
223 	qdf_list_t *ml_list;
224 	struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx();
225 
226 	if (!mlo_mgr_ctx)
227 		return NULL;
228 
229 	ml_link_lock_acquire(mlo_mgr_ctx);
230 	ml_list = &mlo_mgr_ctx->ml_dev_list;
231 	/* Get first mld context */
232 	mld_cur = mlo_list_peek_head(ml_list);
233 	/**
234 	 * Iterate through ml list, till ml mldaddr matches with
235 	 * entry of list
236 	 */
237 	while (mld_cur) {
238 		if (QDF_IS_STATUS_SUCCESS(WLAN_ADDR_EQ(&mld_cur->mld_addr,
239 					  mldaddr))) {
240 			ml_link_lock_release(mlo_mgr_ctx);
241 			return mld_cur;
242 		}
243 		/* get next mld node */
244 		mld_next = mlo_get_next_mld_ctx(ml_list, mld_cur);
245 		mld_cur = mld_next;
246 	}
247 	ml_link_lock_release(mlo_mgr_ctx);
248 
249 	return NULL;
250 }
251 
252 bool wlan_mlo_is_mld_ctx_exist(struct qdf_mac_addr *mldaddr)
253 {
254 	struct wlan_mlo_dev_context *mld_ctx = NULL;
255 
256 	mld_ctx = wlan_mlo_get_mld_ctx_by_mldaddr(mldaddr);
257 	if (mld_ctx)
258 		return true;
259 
260 	return false;
261 }
262 
263 static QDF_STATUS mlo_ap_ctx_deinit(struct wlan_mlo_dev_context *ml_dev)
264 {
265 	wlan_mlo_vdev_aid_mgr_deinit(ml_dev);
266 	qdf_mem_free(ml_dev->ap_ctx);
267 	ml_dev->ap_ctx = NULL;
268 
269 	return QDF_STATUS_SUCCESS;
270 }
271 
272 static QDF_STATUS mlo_ap_ctx_init(struct wlan_mlo_dev_context *ml_dev)
273 {
274 	struct wlan_mlo_ap *ap_ctx;
275 
276 	ap_ctx = qdf_mem_malloc(sizeof(*ap_ctx));
277 	if (!ap_ctx) {
278 		mlo_err("MLO AP ctx alloc failure");
279 		return QDF_STATUS_E_NOMEM;
280 	}
281 
282 	ml_dev->ap_ctx = ap_ctx;
283 	if (wlan_mlo_vdev_aid_mgr_init(ml_dev) != QDF_STATUS_SUCCESS) {
284 		mlo_ap_ctx_deinit(ml_dev);
285 		return QDF_STATUS_E_NOMEM;
286 	}
287 
288 	return QDF_STATUS_SUCCESS;
289 }
290 
291 #ifdef CONFIG_AP_PLATFORM
292 static inline
293 QDF_STATUS wlan_mlo_pdev_check(struct wlan_objmgr_pdev *ref_pdev,
294 			       struct wlan_objmgr_vdev *vdev)
295 {
296 	struct wlan_objmgr_pdev *pdev = NULL;
297 	struct wlan_objmgr_psoc *psoc = NULL;
298 
299 	pdev = wlan_vdev_get_pdev(vdev);
300 
301 	psoc = wlan_pdev_get_psoc(ref_pdev);
302 	if (mlo_check_all_pdev_state(psoc, MLO_LINK_SETUP_DONE)) {
303 		mlo_err("Pdev link is not in ready state, initial link setup failed");
304 		return QDF_STATUS_E_FAILURE;
305 	}
306 
307 	if (ref_pdev == pdev) {
308 		mlo_err("MLD vdev for this pdev already found, investigate config");
309 		return QDF_STATUS_E_FAILURE;
310 	}
311 
312 	return QDF_STATUS_SUCCESS;
313 }
314 
315 static inline
316 QDF_STATUS mlo_dev_config_check(struct wlan_mlo_dev_context *ml_dev,
317 				struct wlan_objmgr_vdev *vdev)
318 {
319 	return QDF_STATUS_SUCCESS;
320 }
321 
322 #else
323 static inline
324 QDF_STATUS mlo_dev_config_check(struct wlan_mlo_dev_context *ml_dev,
325 				struct wlan_objmgr_vdev *vdev)
326 {
327 	enum QDF_OPMODE opmode = wlan_vdev_mlme_get_opmode(vdev);
328 
329 	if (wlan_mlo_check_valid_config(ml_dev, wlan_vdev_get_pdev(vdev),
330 					opmode) != QDF_STATUS_SUCCESS)
331 		return QDF_STATUS_E_FAILURE;
332 
333 	return QDF_STATUS_SUCCESS;
334 }
335 
336 static inline
337 QDF_STATUS wlan_mlo_pdev_check(struct wlan_objmgr_pdev *ref_pdev,
338 			       struct wlan_objmgr_vdev *vdev)
339 {
340 	return QDF_STATUS_SUCCESS;
341 }
342 #endif
343 
344 QDF_STATUS wlan_mlo_check_valid_config(struct wlan_mlo_dev_context *ml_dev,
345 				       struct wlan_objmgr_pdev *pdev,
346 				       enum QDF_OPMODE opmode)
347 {
348 	uint32_t id = 0;
349 	struct wlan_objmgr_vdev *vdev = NULL;
350 
351 	if (!ml_dev)
352 		return QDF_STATUS_E_FAILURE;
353 
354 	if (!pdev)
355 		return QDF_STATUS_E_FAILURE;
356 
357 	mlo_dev_lock_acquire(ml_dev);
358 	while (id < WLAN_UMAC_MLO_MAX_VDEVS) {
359 		vdev = ml_dev->wlan_vdev_list[id];
360 		if (vdev) {
361 			if (wlan_mlo_pdev_check(pdev, vdev)) {
362 				mlo_dev_lock_release(ml_dev);
363 				return QDF_STATUS_E_FAILURE;
364 			}
365 
366 			if (wlan_vdev_mlme_get_opmode(vdev) != opmode) {
367 				mlo_err("Invalid opmode %d type found expected %d, investigate config",
368 					wlan_vdev_mlme_get_opmode(vdev),
369 					opmode);
370 				mlo_dev_lock_release(ml_dev);
371 				return QDF_STATUS_E_FAILURE;
372 			}
373 		}
374 		id++;
375 	}
376 
377 	mlo_dev_lock_release(ml_dev);
378 	return QDF_STATUS_SUCCESS;
379 }
380 
381 static QDF_STATUS mlo_dev_ctx_init(struct wlan_objmgr_vdev *vdev)
382 {
383 	struct wlan_mlo_dev_context *ml_dev;
384 	QDF_STATUS status = QDF_STATUS_SUCCESS;
385 	struct qdf_mac_addr *mld_addr;
386 	struct mlo_mgr_context *g_mlo_ctx = wlan_objmgr_get_mlo_ctx();
387 	uint8_t id = 0;
388 
389 	mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
390 	ml_dev = wlan_mlo_get_mld_ctx_by_mldaddr(mld_addr);
391 
392 	if (ml_dev) {
393 		if (mlo_dev_config_check(ml_dev, vdev) != QDF_STATUS_SUCCESS)
394 			return QDF_STATUS_E_FAILURE;
395 
396 		mlo_dev_lock_acquire(ml_dev);
397 		while (id < WLAN_UMAC_MLO_MAX_VDEVS) {
398 			if (ml_dev->wlan_vdev_list[id]) {
399 				id++;
400 				continue;
401 			}
402 
403 			ml_dev->wlan_vdev_list[id] = vdev;
404 			ml_dev->wlan_vdev_count++;
405 			vdev->mlo_dev_ctx = ml_dev;
406 
407 			if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE)
408 				wlan_mlo_vdev_alloc_aid_mgr(ml_dev, vdev);
409 
410 			break;
411 		}
412 		mlo_dev_lock_release(ml_dev);
413 		return QDF_STATUS_SUCCESS;
414 	}
415 
416 	/* Create a new ML dev context */
417 	ml_dev = qdf_mem_malloc(sizeof(*ml_dev));
418 	if (!ml_dev) {
419 		mlo_err("Failed to allocate memory for ML dev");
420 		return QDF_STATUS_E_NOMEM;
421 	}
422 
423 	qdf_copy_macaddr(&ml_dev->mld_addr, mld_addr);
424 	ml_dev->wlan_vdev_list[0] = vdev;
425 	ml_dev->wlan_vdev_count++;
426 	vdev->mlo_dev_ctx = ml_dev;
427 
428 	mlo_dev_lock_create(ml_dev);
429 	tsf_recalculation_lock_create(ml_dev);
430 	if (wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE) {
431 		ml_dev->sta_ctx = qdf_mem_malloc(sizeof(struct wlan_mlo_sta));
432 		if (!ml_dev->sta_ctx) {
433 			tsf_recalculation_lock_destroy(ml_dev);
434 			mlo_dev_lock_destroy(ml_dev);
435 			qdf_mem_free(ml_dev);
436 			return QDF_STATUS_E_NOMEM;
437 		}
438 		copied_conn_req_lock_create(ml_dev->sta_ctx);
439 	} else if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE) {
440 		if (mlo_ap_ctx_init(ml_dev) != QDF_STATUS_SUCCESS) {
441 			tsf_recalculation_lock_destroy(ml_dev);
442 			mlo_dev_lock_destroy(ml_dev);
443 			qdf_mem_free(ml_dev);
444 			mlo_err("Failed to allocate memory for ap ctx");
445 			return QDF_STATUS_E_NOMEM;
446 		}
447 	}
448 
449 	mlo_dev_mlpeer_list_init(ml_dev);
450 
451 	ml_link_lock_acquire(g_mlo_ctx);
452 	if (qdf_list_size(&g_mlo_ctx->ml_dev_list) < WLAN_UMAC_MLO_MAX_DEV)
453 		qdf_list_insert_back(&g_mlo_ctx->ml_dev_list, &ml_dev->node);
454 	ml_link_lock_release(g_mlo_ctx);
455 
456 	return status;
457 }
458 
459 static QDF_STATUS mlo_dev_ctx_deinit(struct wlan_objmgr_vdev *vdev)
460 {
461 	struct wlan_mlo_dev_context *ml_dev;
462 	QDF_STATUS status = QDF_STATUS_SUCCESS;
463 	struct qdf_mac_addr *mld_addr;
464 	struct mlo_mgr_context *g_mlo_ctx = wlan_objmgr_get_mlo_ctx();
465 	uint8_t id = 0;
466 	struct wlan_cm_connect_req *connect_req;
467 
468 	mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
469 	ml_dev = wlan_mlo_get_mld_ctx_by_mldaddr(mld_addr);
470 	if (!ml_dev) {
471 		mlo_err("Failed to get MLD dev context");
472 		return QDF_STATUS_SUCCESS;
473 	} else {
474 		mlo_debug("deleting vdev from MLD device ctx");
475 		mlo_dev_lock_acquire(ml_dev);
476 		while (id < WLAN_UMAC_MLO_MAX_VDEVS) {
477 			if (ml_dev->wlan_vdev_list[id] == vdev) {
478 				if (wlan_vdev_mlme_get_opmode(vdev) ==
479 								QDF_SAP_MODE)
480 					wlan_mlo_vdev_free_aid_mgr(ml_dev,
481 								   vdev);
482 				ml_dev->wlan_vdev_list[id] = NULL;
483 				ml_dev->wlan_vdev_count--;
484 				vdev->mlo_dev_ctx = NULL;
485 				break;
486 			}
487 			id++;
488 		}
489 		mlo_dev_lock_release(ml_dev);
490 	}
491 
492 	ml_link_lock_acquire(g_mlo_ctx);
493 	if (!ml_dev->wlan_vdev_count) {
494 		if (ml_dev->ap_ctx)
495 			mlo_ap_ctx_deinit(ml_dev);
496 
497 		mlo_dev_mlpeer_list_deinit(ml_dev);
498 		qdf_list_remove_node(&g_mlo_ctx->ml_dev_list,
499 				     &ml_dev->node);
500 		if (wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE) {
501 			connect_req = ml_dev->sta_ctx->connect_req;
502 			if (connect_req) {
503 				if (connect_req->scan_ie.ptr) {
504 					qdf_mem_free(connect_req->scan_ie.ptr);
505 					connect_req->scan_ie.ptr = NULL;
506 				}
507 
508 				if (connect_req->assoc_ie.ptr) {
509 					qdf_mem_free(connect_req->assoc_ie.ptr);
510 					connect_req->assoc_ie.ptr = NULL;
511 				}
512 				qdf_mem_free(ml_dev->sta_ctx->connect_req);
513 			}
514 
515 			if (ml_dev->sta_ctx->disconn_req)
516 				qdf_mem_free(ml_dev->sta_ctx->disconn_req);
517 
518 			if (ml_dev->sta_ctx->assoc_rsp.ptr)
519 				qdf_mem_free(ml_dev->sta_ctx->assoc_rsp.ptr);
520 
521 			copied_conn_req_lock_destroy(ml_dev->sta_ctx);
522 
523 			qdf_mem_free(ml_dev->sta_ctx);
524 		}
525 		else if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE)
526 			qdf_mem_free(ml_dev->ap_ctx);
527 
528 		tsf_recalculation_lock_destroy(ml_dev);
529 		mlo_dev_lock_destroy(ml_dev);
530 		qdf_mem_free(ml_dev);
531 	}
532 	ml_link_lock_release(g_mlo_ctx);
533 	return status;
534 }
535 
536 QDF_STATUS wlan_mlo_mgr_vdev_created_notification(struct wlan_objmgr_vdev *vdev,
537 						  void *arg_list)
538 {
539 	QDF_STATUS status = QDF_STATUS_SUCCESS;
540 	struct qdf_mac_addr *mld_addr;
541 
542 	mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
543 	if (qdf_is_macaddr_zero(mld_addr)) {
544 		/* It's not a ML interface*/
545 		return QDF_STATUS_SUCCESS;
546 	}
547 	mlo_debug("MLD addr" QDF_MAC_ADDR_FMT,
548 		  QDF_MAC_ADDR_REF(mld_addr->bytes));
549 	status = mlo_dev_ctx_init(vdev);
550 
551 	return status;
552 }
553 
554 QDF_STATUS wlan_mlo_mgr_vdev_destroyed_notification(struct wlan_objmgr_vdev *vdev,
555 						    void *arg_list)
556 {
557 	QDF_STATUS status = QDF_STATUS_SUCCESS;
558 	struct qdf_mac_addr *mld_addr;
559 
560 	mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
561 	if (qdf_is_macaddr_zero(mld_addr)) {
562 		/* It's not a ML interface*/
563 		return QDF_STATUS_SUCCESS;
564 	}
565 	mlo_debug("MLD addr" QDF_MAC_ADDR_FMT,
566 		  QDF_MAC_ADDR_REF(mld_addr->bytes));
567 
568 	status = mlo_dev_ctx_deinit(vdev);
569 
570 	return status;
571 }
572 
573 QDF_STATUS wlan_mlo_mgr_update_mld_addr(struct qdf_mac_addr *old_mac,
574 					struct qdf_mac_addr *new_mac)
575 {
576 	struct wlan_mlo_dev_context *ml_dev;
577 
578 	ml_dev = wlan_mlo_get_mld_ctx_by_mldaddr(old_mac);
579 	if (!ml_dev) {
580 		mlo_err("ML dev context not found for MLD:" QDF_MAC_ADDR_FMT,
581 			QDF_MAC_ADDR_REF(old_mac->bytes));
582 		return QDF_STATUS_E_INVAL;
583 	}
584 	mlo_dev_lock_acquire(ml_dev);
585 	qdf_copy_macaddr(&ml_dev->mld_addr, new_mac);
586 	mlo_dev_lock_release(ml_dev);
587 
588 	return QDF_STATUS_SUCCESS;
589 }
590