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 by mld addr "QDF_MAC_ADDR_FMT, 472 QDF_MAC_ADDR_REF(mld_addr->bytes)); 473 if (!vdev->mlo_dev_ctx) { 474 mlo_err("Failed to get MLD dev context from vdev"); 475 return QDF_STATUS_SUCCESS; 476 } 477 ml_dev = vdev->mlo_dev_ctx; 478 } 479 480 mlo_debug("deleting vdev from MLD device ctx "QDF_MAC_ADDR_FMT, 481 QDF_MAC_ADDR_REF(mld_addr->bytes)); 482 mlo_dev_lock_acquire(ml_dev); 483 while (id < WLAN_UMAC_MLO_MAX_VDEVS) { 484 if (ml_dev->wlan_vdev_list[id] == vdev) { 485 if (wlan_vdev_mlme_get_opmode(vdev) == 486 QDF_SAP_MODE) 487 wlan_mlo_vdev_free_aid_mgr(ml_dev, 488 vdev); 489 ml_dev->wlan_vdev_list[id] = NULL; 490 ml_dev->wlan_vdev_count--; 491 vdev->mlo_dev_ctx = NULL; 492 break; 493 } 494 id++; 495 } 496 mlo_dev_lock_release(ml_dev); 497 498 ml_link_lock_acquire(g_mlo_ctx); 499 if (!ml_dev->wlan_vdev_count) { 500 if (ml_dev->ap_ctx) 501 mlo_ap_ctx_deinit(ml_dev); 502 503 mlo_dev_mlpeer_list_deinit(ml_dev); 504 qdf_list_remove_node(&g_mlo_ctx->ml_dev_list, 505 &ml_dev->node); 506 if (wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE) { 507 connect_req = ml_dev->sta_ctx->connect_req; 508 if (connect_req) { 509 if (connect_req->scan_ie.ptr) { 510 qdf_mem_free(connect_req->scan_ie.ptr); 511 connect_req->scan_ie.ptr = NULL; 512 } 513 514 if (connect_req->assoc_ie.ptr) { 515 qdf_mem_free(connect_req->assoc_ie.ptr); 516 connect_req->assoc_ie.ptr = NULL; 517 } 518 qdf_mem_free(ml_dev->sta_ctx->connect_req); 519 } 520 521 if (ml_dev->sta_ctx->disconn_req) 522 qdf_mem_free(ml_dev->sta_ctx->disconn_req); 523 524 if (ml_dev->sta_ctx->assoc_rsp.ptr) 525 qdf_mem_free(ml_dev->sta_ctx->assoc_rsp.ptr); 526 527 copied_conn_req_lock_destroy(ml_dev->sta_ctx); 528 529 qdf_mem_free(ml_dev->sta_ctx); 530 } 531 else if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE) 532 qdf_mem_free(ml_dev->ap_ctx); 533 534 tsf_recalculation_lock_destroy(ml_dev); 535 mlo_dev_lock_destroy(ml_dev); 536 qdf_mem_free(ml_dev); 537 } 538 ml_link_lock_release(g_mlo_ctx); 539 return status; 540 } 541 542 QDF_STATUS wlan_mlo_mgr_vdev_created_notification(struct wlan_objmgr_vdev *vdev, 543 void *arg_list) 544 { 545 QDF_STATUS status = QDF_STATUS_SUCCESS; 546 struct qdf_mac_addr *mld_addr; 547 548 mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev); 549 if (qdf_is_macaddr_zero(mld_addr)) { 550 /* It's not a ML interface*/ 551 return QDF_STATUS_SUCCESS; 552 } 553 mlo_debug("MLD addr" QDF_MAC_ADDR_FMT, 554 QDF_MAC_ADDR_REF(mld_addr->bytes)); 555 status = mlo_dev_ctx_init(vdev); 556 557 return status; 558 } 559 560 QDF_STATUS wlan_mlo_mgr_vdev_destroyed_notification(struct wlan_objmgr_vdev *vdev, 561 void *arg_list) 562 { 563 QDF_STATUS status = QDF_STATUS_SUCCESS; 564 struct qdf_mac_addr *mld_addr; 565 566 mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev); 567 if (qdf_is_macaddr_zero(mld_addr)) { 568 /* It's not a ML interface*/ 569 return QDF_STATUS_SUCCESS; 570 } 571 mlo_debug("MLD addr" QDF_MAC_ADDR_FMT, 572 QDF_MAC_ADDR_REF(mld_addr->bytes)); 573 574 status = mlo_dev_ctx_deinit(vdev); 575 576 return status; 577 } 578 579 QDF_STATUS wlan_mlo_mgr_update_mld_addr(struct qdf_mac_addr *old_mac, 580 struct qdf_mac_addr *new_mac) 581 { 582 struct wlan_mlo_dev_context *ml_dev; 583 584 ml_dev = wlan_mlo_get_mld_ctx_by_mldaddr(old_mac); 585 if (!ml_dev) { 586 mlo_err("ML dev context not found for MLD:" QDF_MAC_ADDR_FMT, 587 QDF_MAC_ADDR_REF(old_mac->bytes)); 588 return QDF_STATUS_E_INVAL; 589 } 590 mlo_dev_lock_acquire(ml_dev); 591 qdf_copy_macaddr(&ml_dev->mld_addr, new_mac); 592 mlo_dev_lock_release(ml_dev); 593 594 return QDF_STATUS_SUCCESS; 595 } 596