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 STA related api's 20 */ 21 22 #include <wlan_cmn.h> 23 #include <wlan_mlo_mgr_sta.h> 24 #include <wlan_cm_public_struct.h> 25 #include <wlan_mlo_mgr_main.h> 26 #include <wlan_cm_api.h> 27 #include <wlan_mlo_mgr_cmn.h> 28 #include <wlan_scan_api.h> 29 #include <scheduler_api.h> 30 31 #ifdef WLAN_FEATURE_11BE_MLO 32 static inline void 33 mlo_allocate_and_copy_ies(struct wlan_cm_connect_req *target, 34 struct wlan_cm_connect_req *source) 35 { 36 target->assoc_ie.ptr = NULL; 37 target->scan_ie.ptr = NULL; 38 39 if (source->scan_ie.ptr) { 40 target->scan_ie.ptr = qdf_mem_malloc(source->scan_ie.len); 41 if (!target->scan_ie.ptr) 42 target->scan_ie.len = 0; 43 else 44 qdf_mem_copy(target->scan_ie.ptr, 45 source->scan_ie.ptr, source->scan_ie.len); 46 } 47 48 if (source->assoc_ie.ptr) { 49 target->assoc_ie.ptr = qdf_mem_malloc(source->assoc_ie.len); 50 if (!target->assoc_ie.ptr) 51 target->assoc_ie.len = 0; 52 else 53 qdf_mem_copy(target->assoc_ie.ptr, source->assoc_ie.ptr, 54 source->assoc_ie.len); 55 } 56 } 57 58 static inline void 59 mlo_free_connect_ies(struct wlan_cm_connect_req *connect_req) 60 { 61 if (connect_req->scan_ie.ptr) { 62 qdf_mem_free(connect_req->scan_ie.ptr); 63 connect_req->scan_ie.ptr = NULL; 64 } 65 66 if (connect_req->assoc_ie.ptr) { 67 qdf_mem_free(connect_req->assoc_ie.ptr); 68 connect_req->assoc_ie.ptr = NULL; 69 } 70 } 71 72 /* 73 * mlo_get_assoc_link_vdev - API to get assoc link vdev 74 * 75 * @mlo_dev_ctx: pointer to mlo dev context 76 * 77 * Return: MLD assoc link vdev 78 */ 79 static inline struct wlan_objmgr_vdev * 80 mlo_get_assoc_link_vdev(struct wlan_mlo_dev_context *mlo_dev_ctx) 81 { 82 uint8_t i = 0; 83 84 if (!mlo_dev_ctx) 85 return NULL; 86 87 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 88 if (!mlo_dev_ctx->wlan_vdev_list[i]) 89 continue; 90 91 if (wlan_vdev_mlme_is_mlo_vdev(mlo_dev_ctx->wlan_vdev_list[i]) && 92 !wlan_vdev_mlme_is_mlo_link_vdev(mlo_dev_ctx->wlan_vdev_list[i])) 93 return mlo_dev_ctx->wlan_vdev_list[i]; 94 } 95 return NULL; 96 } 97 98 struct wlan_objmgr_vdev * 99 wlan_mlo_get_assoc_link_vdev(struct wlan_objmgr_vdev *vdev) 100 { 101 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 102 103 if (!mlo_dev_ctx || !wlan_vdev_mlme_is_mlo_vdev(vdev)) 104 return NULL; 105 106 return mlo_get_assoc_link_vdev(mlo_dev_ctx); 107 } 108 109 struct wlan_objmgr_vdev * 110 ucfg_mlo_get_assoc_link_vdev(struct wlan_objmgr_vdev *vdev) 111 { 112 return wlan_mlo_get_assoc_link_vdev(vdev); 113 } 114 115 /** 116 * mlo_is_mld_disconnected - Check whether MLD is disconnected 117 * 118 * @vdev: pointer to vdev 119 * 120 * Return: true if mld is disconnected, false otherwise 121 */ 122 static inline 123 bool mlo_is_mld_disconnected(struct wlan_objmgr_vdev *vdev) 124 { 125 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 126 uint8_t i = 0; 127 128 if (!mlo_dev_ctx || !wlan_vdev_mlme_is_mlo_vdev(vdev)) 129 return true; 130 131 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 132 if (!mlo_dev_ctx->wlan_vdev_list[i]) 133 continue; 134 135 if (!wlan_cm_is_vdev_disconnected(mlo_dev_ctx->wlan_vdev_list[i])) 136 return false; 137 } 138 return true; 139 } 140 141 bool ucfg_mlo_is_mld_disconnected(struct wlan_objmgr_vdev *vdev) 142 { 143 return mlo_is_mld_disconnected(vdev); 144 } 145 146 /** 147 * mlo_send_link_disconnect- Issue the disconnect request on MLD links 148 * 149 * @mlo_dev_ctx: pointer to mlo dev context 150 * @source: disconnect source 151 * @reason_code: disconnect reason 152 * @bssid: bssid of AP to disconnect, can be null if not known 153 * 154 * Return: QDF_STATUS 155 */ 156 static QDF_STATUS 157 mlo_send_link_disconnect(struct wlan_mlo_dev_context *mlo_dev_ctx, 158 enum wlan_cm_source source, 159 enum wlan_reason_code reason_code, 160 struct qdf_mac_addr *bssid) 161 { 162 uint8_t i = 0; 163 enum wlan_cm_source link_source = source; 164 struct wlan_objmgr_vdev *assoc_vdev = 165 mlo_get_assoc_link_vdev(mlo_dev_ctx); 166 167 if (!assoc_vdev) 168 return QDF_STATUS_E_FAILURE; 169 170 /* 171 * Change the source for the link vdev to make sure it's handled as a 172 * Northbound disconnect in VDEV/PEER state machine. 173 */ 174 if (source != CM_OSIF_DISCONNECT) 175 link_source = CM_MLO_LINK_VDEV_DISCONNECT; 176 177 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 178 if (!mlo_dev_ctx->wlan_vdev_list[i]) 179 continue; 180 181 if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links) && 182 mlo_dev_ctx->wlan_vdev_list[i] != mlo_get_assoc_link_vdev(mlo_dev_ctx)) 183 wlan_cm_disconnect(mlo_dev_ctx->wlan_vdev_list[i], 184 link_source, reason_code, 185 NULL); 186 } 187 188 wlan_cm_disconnect(assoc_vdev, 189 source, reason_code, NULL); 190 return QDF_STATUS_SUCCESS; 191 } 192 193 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 194 static QDF_STATUS 195 mlo_validate_connect_req(struct wlan_objmgr_vdev *vdev, 196 struct wlan_mlo_dev_context *mlo_dev_ctx, 197 struct wlan_cm_connect_req *req) 198 { 199 /* check back to back connect handling */ 200 return QDF_STATUS_SUCCESS; 201 } 202 203 static QDF_STATUS 204 mlo_validate_disconn_req(struct wlan_objmgr_vdev *vdev, 205 enum wlan_cm_source source, 206 enum wlan_reason_code reason_code, 207 struct qdf_mac_addr *bssid) 208 { 209 return QDF_STATUS_SUCCESS; 210 } 211 #else 212 /** 213 * mlo_is_mld_connected - Check whether MLD is connected 214 * 215 * @vdev: pointer to vdev 216 * 217 * Return: true if mld is connected, false otherwise 218 */ 219 static inline 220 bool mlo_is_mld_connected(struct wlan_objmgr_vdev *vdev) 221 { 222 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 223 uint8_t i = 0; 224 225 if (!mlo_dev_ctx || !wlan_vdev_mlme_is_mlo_vdev(vdev)) 226 return true; 227 228 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 229 if (!mlo_dev_ctx->wlan_vdev_list[i]) 230 continue; 231 232 if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links)) { 233 if (!wlan_cm_is_vdev_connected(mlo_dev_ctx->wlan_vdev_list[i])) 234 return false; 235 } 236 } 237 return true; 238 } 239 240 bool ucfg_mlo_is_mld_connected(struct wlan_objmgr_vdev *vdev) 241 { 242 return mlo_is_mld_connected(vdev); 243 } 244 245 static inline 246 void mlo_mld_clear_mlo_cap(struct wlan_objmgr_vdev *vdev) 247 { 248 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 249 uint8_t i = 0; 250 251 if (!mlo_dev_ctx || !wlan_vdev_mlme_is_mlo_vdev(vdev)) 252 return; 253 254 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 255 if (!mlo_dev_ctx->wlan_vdev_list[i]) 256 continue; 257 wlan_vdev_mlme_clear_mlo_vdev(mlo_dev_ctx->wlan_vdev_list[i]); 258 wlan_vdev_mlme_feat_ext2_cap_clear( 259 mlo_dev_ctx->wlan_vdev_list[i], 260 WLAN_VDEV_FEXT2_MLO_STA_LINK); 261 } 262 } 263 264 void ucfg_mlo_mld_clear_mlo_cap(struct wlan_objmgr_vdev *vdev) 265 { 266 mlo_mld_clear_mlo_cap(vdev); 267 } 268 269 static void 270 mlo_cm_handle_connect_in_disconnection_state(struct wlan_objmgr_vdev *vdev, 271 struct wlan_cm_connect_req *req) 272 { 273 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 274 struct wlan_mlo_sta *sta_ctx; 275 276 if (!mlo_dev_ctx) { 277 mlo_err("ML dev ctx is NULL"); 278 return; 279 } 280 281 sta_ctx = mlo_dev_ctx->sta_ctx; 282 if (!sta_ctx->connect_req) 283 sta_ctx->connect_req = qdf_mem_malloc( 284 sizeof(struct wlan_cm_connect_req)); 285 286 if (sta_ctx->connect_req) { 287 qdf_mem_copy(sta_ctx->connect_req, req, 288 sizeof(struct wlan_cm_connect_req)); 289 mlo_allocate_and_copy_ies(sta_ctx->connect_req, req); 290 } else { 291 mlo_err("Failed to allocate connect req"); 292 } 293 } 294 295 static QDF_STATUS mlo_disconnect_no_lock(struct wlan_objmgr_vdev *vdev, 296 enum wlan_cm_source source, 297 enum wlan_reason_code reason_code, 298 struct qdf_mac_addr *bssid) 299 { 300 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 301 struct wlan_mlo_sta *sta_ctx = NULL; 302 QDF_STATUS status = QDF_STATUS_SUCCESS; 303 304 if (mlo_dev_ctx) 305 sta_ctx = mlo_dev_ctx->sta_ctx; 306 if (sta_ctx) { 307 copied_conn_req_lock_acquire(sta_ctx); 308 if (sta_ctx->copied_conn_req) { 309 mlo_free_connect_ies(sta_ctx->copied_conn_req); 310 qdf_mem_free(sta_ctx->copied_conn_req); 311 sta_ctx->copied_conn_req = NULL; 312 } 313 copied_conn_req_lock_release(sta_ctx); 314 } else { 315 return QDF_STATUS_E_FAILURE; 316 } 317 318 if (wlan_vdev_mlme_is_mlo_vdev(vdev)) { 319 sta_ctx = mlo_dev_ctx->sta_ctx; 320 if (!sta_ctx) 321 return QDF_STATUS_E_FAILURE; 322 323 if (sta_ctx->connect_req) { 324 mlo_free_connect_ies(sta_ctx->connect_req); 325 qdf_mem_free(sta_ctx->connect_req); 326 sta_ctx->connect_req = NULL; 327 } 328 329 status = mlo_send_link_disconnect(mlo_dev_ctx, source, 330 reason_code, bssid); 331 } 332 333 return status; 334 } 335 336 static void 337 mlo_cm_handle_connect_in_connection_state(struct wlan_objmgr_vdev *vdev, 338 struct wlan_cm_connect_req *req) 339 { 340 mlo_disconnect_no_lock(vdev, CM_OSIF_CFG_DISCONNECT, 341 REASON_UNSPEC_FAILURE, NULL); 342 mlo_cm_handle_connect_in_disconnection_state(vdev, req); 343 } 344 345 static QDF_STATUS 346 mlo_validate_connect_req(struct wlan_objmgr_vdev *vdev, 347 struct wlan_mlo_dev_context *mlo_dev_ctx, 348 struct wlan_cm_connect_req *req) 349 { 350 uint8_t i = 0; 351 QDF_STATUS status = QDF_STATUS_SUCCESS; 352 353 if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) 354 return QDF_STATUS_SUCCESS; 355 356 // Handle connect in various states 357 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 358 if (!mlo_dev_ctx->wlan_vdev_list[i]) 359 continue; 360 361 if ((wlan_cm_is_vdev_connected(mlo_dev_ctx->wlan_vdev_list[i])) || 362 (wlan_cm_is_vdev_connecting(mlo_dev_ctx->wlan_vdev_list[i])) || 363 (wlan_cm_is_vdev_roaming(mlo_dev_ctx->wlan_vdev_list[i]))) { 364 mlo_cm_handle_connect_in_connection_state(mlo_dev_ctx->wlan_vdev_list[i], req); 365 return QDF_STATUS_E_BUSY; 366 } else if (wlan_cm_is_vdev_disconnecting(mlo_dev_ctx->wlan_vdev_list[i])) { 367 mlo_cm_handle_connect_in_disconnection_state(mlo_dev_ctx->wlan_vdev_list[i], req); 368 return QDF_STATUS_E_BUSY; 369 } 370 371 /* 372 * mlo_connect: update wlan_connect_req_links in 373 * wlan_cfg80211_conect on osif_cm_connect, 374 * Validate pre checks for connection 375 */ 376 if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connect_req_links)) { 377 status = mlo_mlme_validate_conn_req( 378 mlo_dev_ctx->wlan_vdev_list[i], NULL); 379 if (status != QDF_STATUS_SUCCESS) 380 return status; 381 /* 382 * clone security params in all partner sta vaps 383 */ 384 mlo_mlme_clone_sta_security( 385 mlo_dev_ctx->wlan_vdev_list[i], req); 386 } 387 } 388 return status; 389 } 390 391 static QDF_STATUS 392 mlo_validate_disconn_req(struct wlan_objmgr_vdev *vdev, 393 enum wlan_cm_source source, 394 enum wlan_reason_code reason_code, 395 struct qdf_mac_addr *bssid) 396 { 397 struct wlan_mlo_dev_context *mlo_dev = vdev->mlo_dev_ctx; 398 struct wlan_mlo_sta *sta_ctx = mlo_dev->sta_ctx; 399 uint8_t i = 0; 400 401 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 402 if (!mlo_dev->wlan_vdev_list[i]) 403 continue; 404 405 if (wlan_cm_is_vdev_connecting(mlo_dev->wlan_vdev_list[i])) { 406 if (!wlan_vdev_mlme_is_mlo_link_vdev( 407 mlo_dev->wlan_vdev_list[i])) 408 return QDF_STATUS_SUCCESS; 409 410 if (!sta_ctx->disconn_req) 411 sta_ctx->disconn_req = 412 qdf_mem_malloc( 413 sizeof(struct wlan_cm_disconnect_req)); 414 415 if (!sta_ctx->disconn_req) 416 return QDF_STATUS_SUCCESS; 417 418 sta_ctx->disconn_req->vdev_id = 419 wlan_vdev_get_id(vdev); 420 sta_ctx->disconn_req->source = source; 421 sta_ctx->disconn_req->reason_code = reason_code; 422 if (bssid) 423 qdf_copy_macaddr(&sta_ctx->disconn_req->bssid, 424 bssid); 425 return QDF_STATUS_E_BUSY; 426 } else if (wlan_cm_is_vdev_connected(mlo_dev->wlan_vdev_list[i]) && 427 !wlan_vdev_mlme_is_mlo_link_vdev( 428 mlo_dev->wlan_vdev_list[i])) { 429 /* If the vdev is moved to connected state but 430 * MLO mgr is not yet notified, defer disconnect 431 * as it can cause race between connect complete 432 * and disconnect initiation 433 */ 434 if (!qdf_test_bit(i, sta_ctx->wlan_connected_links)) 435 return QDF_STATUS_E_BUSY; 436 } 437 } 438 return QDF_STATUS_SUCCESS; 439 } 440 #endif 441 442 QDF_STATUS mlo_connect(struct wlan_objmgr_vdev *vdev, 443 struct wlan_cm_connect_req *req) 444 { 445 struct wlan_mlo_dev_context *mlo_dev_ctx; 446 struct wlan_mlo_sta *sta_ctx = NULL; 447 QDF_STATUS status = QDF_STATUS_SUCCESS; 448 449 mlo_dev_ctx = vdev->mlo_dev_ctx; 450 if (mlo_dev_ctx) 451 sta_ctx = mlo_dev_ctx->sta_ctx; 452 if (sta_ctx) { 453 mlo_dev_lock_acquire(mlo_dev_ctx); 454 status = mlo_validate_connect_req(vdev, mlo_dev_ctx, req); 455 456 copied_conn_req_lock_acquire(sta_ctx); 457 if (!sta_ctx->copied_conn_req) 458 sta_ctx->copied_conn_req = qdf_mem_malloc( 459 sizeof(struct wlan_cm_connect_req)); 460 else 461 mlo_free_connect_ies(sta_ctx->copied_conn_req); 462 463 mlo_debug("storing orig connect req"); 464 if (sta_ctx->copied_conn_req) { 465 qdf_mem_copy(sta_ctx->copied_conn_req, req, 466 sizeof(struct wlan_cm_connect_req)); 467 mlo_allocate_and_copy_ies(sta_ctx->copied_conn_req, 468 req); 469 copied_conn_req_lock_release(sta_ctx); 470 } else { 471 mlo_err("Failed to allocate orig connect req"); 472 copied_conn_req_lock_release(sta_ctx); 473 mlo_dev_lock_release(mlo_dev_ctx); 474 return QDF_STATUS_E_NOMEM; 475 } 476 477 if (QDF_IS_STATUS_SUCCESS(status)) { 478 mlo_clear_connected_links_bmap(vdev); 479 status = wlan_cm_start_connect(vdev, req); 480 } 481 482 mlo_dev_lock_release(mlo_dev_ctx); 483 return status; 484 } 485 486 return wlan_cm_start_connect(vdev, req); 487 } 488 489 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 490 static inline void 491 mlo_update_connect_req_chan_info(struct wlan_cm_connect_req *req) 492 { } 493 #else 494 static inline void 495 mlo_update_connect_req_chan_info(struct wlan_cm_connect_req *req) 496 { 497 req->chan_freq = 0; 498 req->chan_freq_hint = 0; 499 } 500 #endif 501 502 /** 503 * mlo_prepare_and_send_connect- Prepare and send the connect req 504 * 505 * @vdev: vdev pointer 506 * @ml_parnter_info: ml partner link info 507 * @link_info: link info on which connect req will be sent 508 * @ssid: ssid to connect 509 * 510 * Return: none 511 */ 512 513 static void 514 mlo_prepare_and_send_connect(struct wlan_objmgr_vdev *vdev, 515 struct mlo_partner_info ml_parnter_info, 516 struct mlo_link_info link_info, 517 struct wlan_ssid ssid) 518 { 519 struct wlan_cm_connect_req req = {0}; 520 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 521 struct wlan_mlo_sta *sta_ctx; 522 523 if (!mlo_dev_ctx) { 524 mlo_err("ML dev ctx is NULL"); 525 return; 526 } 527 528 sta_ctx = mlo_dev_ctx->sta_ctx; 529 530 mlo_debug("Partner link connect mac:" QDF_MAC_ADDR_FMT 531 " bssid:" QDF_MAC_ADDR_FMT " vdev_id:%d", 532 QDF_MAC_ADDR_REF(wlan_vdev_mlme_get_macaddr(vdev)), 533 QDF_MAC_ADDR_REF(link_info.link_addr.bytes), 534 wlan_vdev_get_id(vdev)); 535 536 qdf_mem_copy(&req, sta_ctx->copied_conn_req, 537 sizeof(struct wlan_cm_connect_req)); 538 539 mlo_update_connect_req_chan_info(&req); 540 541 qdf_mem_copy(req.bssid.bytes, 542 link_info.link_addr.bytes, 543 QDF_MAC_ADDR_SIZE); 544 545 qdf_mem_copy(&req.ml_parnter_info, 546 &ml_parnter_info, 547 sizeof(struct mlo_partner_info)); 548 549 req.ssid.length = ssid.length; 550 qdf_mem_copy(&req.ssid.ssid, &ssid.ssid, ssid.length); 551 552 mlo_allocate_and_copy_ies(&req, sta_ctx->copied_conn_req); 553 if (!req.assoc_ie.ptr) 554 mlo_err("Failed to allocate assoc IEs"); 555 556 if (!req.scan_ie.ptr) 557 mlo_err("Failed to allocate scan IEs"); 558 559 /* Reset crypto auth type for partner link. 560 * It will be set based on partner scan cache entry 561 */ 562 req.crypto.auth_type = 0; 563 564 wlan_cm_start_connect(vdev, &req); 565 mlo_free_connect_ies(&req); 566 } 567 568 /** 569 * mlo_send_link_connect- Create/Issue the connection on secondary link 570 * 571 * @vdev: vdev pointer 572 * @mlo_dev_ctx: ml dev context 573 * @assoc_rsp: assoc response 574 * @ml_parnter_info: ml partner link info 575 * 576 * Return: none 577 */ 578 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 579 static void 580 mlo_send_link_connect(struct wlan_objmgr_vdev *vdev, 581 struct wlan_mlo_dev_context *mlo_dev_ctx, 582 struct element_info *assoc_rsp, 583 struct mlo_partner_info *ml_parnter_info) 584 { 585 /* Create the secondary interface, Send keys if the last link */ 586 uint8_t i, partner_idx = 0; 587 struct wlan_ssid ssid = {0}; 588 589 mlo_debug("Sending link connect on partner interface"); 590 wlan_vdev_mlme_get_ssid( 591 vdev, ssid.ssid, 592 &ssid.length); 593 594 if (!ml_parnter_info->num_partner_links) { 595 mlo_err("No partner info in connect resp"); 596 return; 597 } 598 599 if(wlan_vdev_mlme_is_mlo_link_vdev(vdev)) 600 return; 601 602 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 603 if (!mlo_dev_ctx->wlan_vdev_list[i] || 604 (mlo_dev_ctx->wlan_vdev_list[i] == vdev)) 605 continue; 606 wlan_vdev_mlme_set_mlo_vdev(mlo_dev_ctx->wlan_vdev_list[i]); 607 wlan_vdev_mlme_feat_ext2_cap_set(mlo_dev_ctx->wlan_vdev_list[i], 608 WLAN_VDEV_FEXT2_MLO_STA_LINK); 609 wlan_vdev_set_link_id( 610 mlo_dev_ctx->wlan_vdev_list[i], 611 ml_parnter_info->partner_link_info[partner_idx].link_id); 612 ml_parnter_info->partner_link_info[partner_idx].vdev_id = 613 wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i]); 614 mlo_prepare_and_send_connect( 615 mlo_dev_ctx->wlan_vdev_list[i], 616 *ml_parnter_info, 617 ml_parnter_info->partner_link_info[partner_idx], 618 ssid); 619 mlo_update_connected_links(mlo_dev_ctx->wlan_vdev_list[i], 1); 620 partner_idx++; 621 } 622 } 623 #else 624 static void 625 mlo_send_link_connect(struct wlan_objmgr_vdev *vdev, 626 struct wlan_mlo_dev_context *mlo_dev_ctx, 627 struct element_info *assoc_rsp, 628 struct mlo_partner_info *ml_parnter_info) 629 { 630 struct wlan_ssid ssid = {0}; 631 uint8_t i = 0; 632 uint8_t j = 0; 633 634 if (!ml_parnter_info->num_partner_links) { 635 mlo_err("No partner info in connect resp"); 636 return; 637 } 638 639 mlo_dev_lock_acquire(mlo_dev_ctx); 640 if (wlan_cm_is_vdev_connected(vdev)) { 641 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 642 if (!mlo_dev_ctx->wlan_vdev_list[i]) 643 continue; 644 /* 645 * mlo_connect: update wlan_connected_links bitmap from 646 * assoc resp parsing 647 */ 648 if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links)) { 649 if (wlan_cm_is_vdev_disconnected( 650 mlo_dev_ctx->wlan_vdev_list[i])) { 651 for (j = 0; j < ml_parnter_info->num_partner_links; j++) { 652 if (mlo_dev_ctx->wlan_vdev_list[i]->vdev_mlme.mlo_link_id == 653 ml_parnter_info->partner_link_info[j].link_id) 654 break; 655 } 656 if (j < ml_parnter_info->num_partner_links) { 657 wlan_vdev_mlme_get_ssid( 658 vdev, ssid.ssid, 659 &ssid.length); 660 mlo_prepare_and_send_connect( 661 mlo_dev_ctx->wlan_vdev_list[i], 662 *ml_parnter_info, 663 ml_parnter_info->partner_link_info[j], 664 ssid); 665 } 666 mlo_dev_lock_release(mlo_dev_ctx); 667 return; 668 } 669 } 670 } 671 } 672 mlo_dev_lock_release(mlo_dev_ctx); 673 } 674 #endif 675 676 void 677 mlo_update_connected_links_bmap(struct wlan_mlo_dev_context *mlo_dev_ctx, 678 struct mlo_partner_info ml_parnter_info) 679 { 680 uint8_t i = 0; 681 uint8_t j = 0; 682 683 if (!mlo_dev_ctx) { 684 mlo_err("ML dev ctx is NULL"); 685 return; 686 } 687 688 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 689 if (!mlo_dev_ctx->wlan_vdev_list[i]) 690 continue; 691 692 for (j = 0; j < ml_parnter_info.num_partner_links; j++) { 693 if (wlan_vdev_get_link_id(mlo_dev_ctx->wlan_vdev_list[i]) == 694 ml_parnter_info.partner_link_info[j].link_id) 695 mlo_update_connected_links( 696 mlo_dev_ctx->wlan_vdev_list[i], 1); 697 } 698 } 699 } 700 701 static QDF_STATUS ml_activate_disconnect_req_sched_cb(struct scheduler_msg *msg) 702 { 703 struct wlan_objmgr_vdev *vdev = msg->bodyptr; 704 705 if (!vdev) { 706 mlme_err("Null input vdev"); 707 return QDF_STATUS_E_INVAL; 708 } 709 710 mlo_disconnect(vdev, CM_OSIF_DISCONNECT, 711 REASON_UNSPEC_FAILURE, NULL); 712 713 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 714 return QDF_STATUS_SUCCESS; 715 } 716 717 static QDF_STATUS ml_activate_disconnect_req_flush_cb(struct scheduler_msg *msg) 718 { 719 struct wlan_objmgr_vdev *vdev = msg->bodyptr; 720 721 if (!vdev) { 722 mlme_err("Null input vdev"); 723 return QDF_STATUS_E_INVAL; 724 } 725 726 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 727 return QDF_STATUS_SUCCESS; 728 } 729 730 static QDF_STATUS ml_activate_pend_disconn_req_cb(struct scheduler_msg *msg) 731 { 732 struct wlan_objmgr_vdev *vdev = msg->bodyptr; 733 struct wlan_mlo_dev_context *mlo_dev_ctx = NULL; 734 struct wlan_mlo_sta *sta_ctx = NULL; 735 736 if (!vdev) { 737 mlme_err("Null input vdev"); 738 return QDF_STATUS_E_INVAL; 739 } 740 741 mlo_dev_ctx = vdev->mlo_dev_ctx; 742 sta_ctx = mlo_dev_ctx->sta_ctx; 743 mlo_disconnect(vdev, sta_ctx->disconn_req->source, 744 sta_ctx->disconn_req->reason_code, 745 &sta_ctx->disconn_req->bssid); 746 747 qdf_mem_free(sta_ctx->disconn_req); 748 sta_ctx->disconn_req = NULL; 749 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 750 return QDF_STATUS_SUCCESS; 751 } 752 753 static QDF_STATUS ml_activate_pend_disconn_req_flush_cb( 754 struct scheduler_msg *msg) 755 { 756 struct wlan_objmgr_vdev *vdev = msg->bodyptr; 757 758 if (!vdev) { 759 mlme_err("Null input vdev"); 760 return QDF_STATUS_E_INVAL; 761 } 762 763 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 764 return QDF_STATUS_SUCCESS; 765 } 766 767 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 768 static inline 769 QDF_STATUS mlo_post_disconnect_msg(struct scheduler_msg *msg) 770 { 771 return scheduler_post_message( 772 QDF_MODULE_ID_OS_IF, 773 QDF_MODULE_ID_SCAN, 774 QDF_MODULE_ID_OS_IF, 775 msg); 776 } 777 #else 778 static inline 779 QDF_STATUS mlo_post_disconnect_msg(struct scheduler_msg *msg) 780 { 781 return scheduler_post_message( 782 QDF_MODULE_ID_MLME, 783 QDF_MODULE_ID_MLME, 784 QDF_MODULE_ID_MLME, 785 msg); 786 } 787 #endif 788 789 static inline 790 void mlo_handle_sta_link_connect_failure(struct wlan_objmgr_vdev *vdev, 791 struct wlan_cm_connect_resp *rsp) 792 { 793 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 794 struct scheduler_msg msg = {0}; 795 QDF_STATUS ret; 796 struct wlan_objmgr_vdev *assoc_vdev; 797 798 if (!mlo_dev_ctx) { 799 mlo_err("ML dev ctx is NULL"); 800 return; 801 } 802 803 assoc_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx); 804 if (!assoc_vdev) { 805 mlo_err("Assoc Vdev is NULL"); 806 return; 807 } 808 809 if (vdev != assoc_vdev) { 810 mlo_update_connected_links(vdev, 0); 811 if (rsp->reason == CM_NO_CANDIDATE_FOUND || 812 rsp->reason == CM_HW_MODE_FAILURE || 813 rsp->reason == CM_SER_FAILURE) { 814 ret = wlan_objmgr_vdev_try_get_ref( 815 assoc_vdev, WLAN_MLO_MGR_ID); 816 if (QDF_IS_STATUS_ERROR(ret)) { 817 mlo_err("Failed to get ref vdev_id %d", 818 wlan_vdev_get_id(assoc_vdev)); 819 return; 820 } 821 /* Since these failures happen in same context. use 822 * scheduler to avoid deadlock by deferring context 823 */ 824 msg.bodyptr = assoc_vdev; 825 msg.callback = ml_activate_disconnect_req_sched_cb; 826 msg.flush_callback = 827 ml_activate_disconnect_req_flush_cb; 828 mlo_post_disconnect_msg(&msg); 829 if (QDF_IS_STATUS_ERROR(ret)) { 830 wlan_objmgr_vdev_release_ref( 831 assoc_vdev, 832 WLAN_MLO_MGR_ID); 833 return; 834 } 835 } else { 836 mlo_disconnect(vdev, CM_OSIF_DISCONNECT, 837 REASON_UNSPEC_FAILURE, NULL); 838 } 839 } 840 } 841 842 static inline 843 void mlo_handle_pending_disconnect(struct wlan_objmgr_vdev *vdev) 844 { 845 struct scheduler_msg msg = {0}; 846 QDF_STATUS ret; 847 848 ret = wlan_objmgr_vdev_try_get_ref( 849 vdev, WLAN_MLO_MGR_ID); 850 if (QDF_IS_STATUS_ERROR(ret)) { 851 mlo_err("Failed to get ref vdev_id %d", 852 wlan_vdev_get_id(vdev)); 853 return; 854 } 855 856 msg.bodyptr = vdev; 857 msg.callback = ml_activate_pend_disconn_req_cb; 858 msg.flush_callback = 859 ml_activate_pend_disconn_req_flush_cb; 860 ret = mlo_post_disconnect_msg(&msg); 861 if (QDF_IS_STATUS_ERROR(ret)) { 862 mlo_err("Failed to post scheduler msg"); 863 wlan_objmgr_vdev_release_ref( 864 vdev, 865 WLAN_MLO_MGR_ID); 866 QDF_BUG(0); 867 return; 868 } 869 } 870 871 void mlo_sta_link_connect_notify(struct wlan_objmgr_vdev *vdev, 872 struct wlan_cm_connect_resp *rsp) 873 { 874 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 875 struct wlan_mlo_sta *sta_ctx = NULL; 876 877 if (mlo_dev_ctx) { 878 sta_ctx = mlo_dev_ctx->sta_ctx; 879 } else { 880 mlo_debug_rl("mlo_dev_ctx is NULL"); 881 return; 882 } 883 884 if (sta_ctx && sta_ctx->disconn_req) { 885 mlo_debug("Handle pending disocnnect for vdev %d", 886 wlan_vdev_get_id(vdev)); 887 mlo_handle_pending_disconnect(vdev); 888 return; 889 } 890 891 if (wlan_cm_is_vdev_disconnected(vdev)) { 892 if (sta_ctx) { 893 copied_conn_req_lock_acquire(sta_ctx); 894 if (sta_ctx->copied_conn_req) { 895 mlo_free_connect_ies(sta_ctx->copied_conn_req); 896 qdf_mem_free(sta_ctx->copied_conn_req); 897 sta_ctx->copied_conn_req = NULL; 898 } 899 copied_conn_req_lock_release(sta_ctx); 900 } 901 } 902 903 if (wlan_vdev_mlme_is_mlo_vdev(vdev)) { 904 mlo_debug("Vdev: %d", wlan_vdev_get_id(vdev)); 905 if (wlan_cm_is_vdev_disconnected(vdev)) { 906 mlo_handle_sta_link_connect_failure(vdev, rsp); 907 return; 908 } else if (!wlan_cm_is_vdev_connected(vdev)) { 909 /* If vdev is not in disconnected or connected state, 910 * then the event is received due to connect req being 911 * flushed. Hence, ignore this event 912 */ 913 return; 914 } 915 916 if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev) && sta_ctx) { 917 if (sta_ctx->assoc_rsp.ptr) { 918 qdf_mem_free(sta_ctx->assoc_rsp.ptr); 919 sta_ctx->assoc_rsp.ptr = NULL; 920 } 921 sta_ctx->assoc_rsp.len = rsp->connect_ies.assoc_rsp.len; 922 sta_ctx->assoc_rsp.ptr = 923 qdf_mem_malloc(rsp->connect_ies.assoc_rsp.len); 924 if (!sta_ctx->assoc_rsp.ptr) { 925 QDF_ASSERT(0); 926 return; 927 } 928 if (rsp->connect_ies.assoc_rsp.ptr) 929 qdf_mem_copy(sta_ctx->assoc_rsp.ptr, 930 rsp->connect_ies.assoc_rsp.ptr, 931 rsp->connect_ies.assoc_rsp.len); 932 /* Update connected_links_bmap for all vdev taking 933 * part in association 934 */ 935 mlo_update_connected_links(vdev, 1); 936 mlo_update_connected_links_bmap(mlo_dev_ctx, 937 rsp->ml_parnter_info); 938 } 939 mlo_send_link_connect(vdev, mlo_dev_ctx, 940 &rsp->connect_ies.assoc_rsp, 941 &rsp->ml_parnter_info); 942 } 943 } 944 945 /** 946 * mlo_send_link_disconnect_sync- Issue sync the disconnect request on MLD links 947 * 948 * @mlo_dev_ctx: pointer to mlo dev context 949 * @source: disconnect source 950 * @reason_code: disconnect reason 951 * @bssid: bssid of AP to disconnect, can be null if not known 952 * 953 * Return: QDF_STATUS 954 */ 955 static QDF_STATUS 956 mlo_send_link_disconnect_sync(struct wlan_mlo_dev_context *mlo_dev_ctx, 957 enum wlan_cm_source source, 958 enum wlan_reason_code reason_code, 959 struct qdf_mac_addr *bssid) 960 { 961 uint8_t i = 0; 962 struct wlan_objmgr_vdev *assoc_vdev = 963 mlo_get_assoc_link_vdev(mlo_dev_ctx); 964 965 if (!assoc_vdev) 966 return QDF_STATUS_E_FAILURE; 967 968 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 969 if (!mlo_dev_ctx->wlan_vdev_list[i]) 970 continue; 971 972 if (mlo_dev_ctx->wlan_vdev_list[i] != 973 mlo_get_assoc_link_vdev(mlo_dev_ctx)) 974 wlan_cm_disconnect_sync(mlo_dev_ctx->wlan_vdev_list[i], 975 source, reason_code); 976 } 977 978 wlan_cm_disconnect_sync(assoc_vdev, 979 source, reason_code); 980 return QDF_STATUS_SUCCESS; 981 } 982 983 QDF_STATUS mlo_disconnect(struct wlan_objmgr_vdev *vdev, 984 enum wlan_cm_source source, 985 enum wlan_reason_code reason_code, 986 struct qdf_mac_addr *bssid) 987 { 988 struct wlan_mlo_dev_context *mlo_dev_ctx = NULL; 989 struct wlan_mlo_sta *sta_ctx = NULL; 990 QDF_STATUS status = QDF_STATUS_SUCCESS; 991 992 if (!vdev) 993 return QDF_STATUS_E_FAILURE; 994 995 mlo_dev_ctx = vdev->mlo_dev_ctx; 996 if (mlo_dev_ctx) 997 sta_ctx = mlo_dev_ctx->sta_ctx; 998 if (sta_ctx) { 999 copied_conn_req_lock_acquire(sta_ctx); 1000 if (sta_ctx->copied_conn_req) { 1001 mlo_free_connect_ies(sta_ctx->copied_conn_req); 1002 qdf_mem_free(sta_ctx->copied_conn_req); 1003 sta_ctx->copied_conn_req = NULL; 1004 } 1005 copied_conn_req_lock_release(sta_ctx); 1006 } 1007 1008 if (mlo_dev_ctx && wlan_vdev_mlme_is_mlo_vdev(vdev)) { 1009 mlo_dev_lock_acquire(mlo_dev_ctx); 1010 if (sta_ctx && sta_ctx->connect_req) { 1011 mlo_free_connect_ies(sta_ctx->connect_req); 1012 qdf_mem_free(sta_ctx->connect_req); 1013 sta_ctx->connect_req = NULL; 1014 } 1015 1016 status = mlo_validate_disconn_req(vdev, source, 1017 reason_code, bssid); 1018 if (QDF_IS_STATUS_ERROR(status)) { 1019 mlo_debug("Connect in progress, deferring disconnect"); 1020 mlo_dev_lock_release(mlo_dev_ctx); 1021 return status; 1022 } 1023 1024 status = mlo_send_link_disconnect(mlo_dev_ctx, source, 1025 reason_code, bssid); 1026 mlo_dev_lock_release(mlo_dev_ctx); 1027 return status; 1028 } 1029 return wlan_cm_disconnect(vdev, source, 1030 reason_code, NULL); 1031 } 1032 1033 QDF_STATUS mlo_sync_disconnect(struct wlan_objmgr_vdev *vdev, 1034 enum wlan_cm_source source, 1035 enum wlan_reason_code reason_code, 1036 struct qdf_mac_addr *bssid) 1037 { 1038 struct wlan_mlo_dev_context *mlo_dev_ctx = NULL; 1039 struct wlan_mlo_sta *sta_ctx = NULL; 1040 QDF_STATUS status = QDF_STATUS_SUCCESS; 1041 1042 if (!vdev) 1043 return QDF_STATUS_E_FAILURE; 1044 1045 mlo_dev_ctx = vdev->mlo_dev_ctx; 1046 if (mlo_dev_ctx) 1047 sta_ctx = mlo_dev_ctx->sta_ctx; 1048 if (sta_ctx) { 1049 copied_conn_req_lock_acquire(sta_ctx); 1050 if (sta_ctx->copied_conn_req) { 1051 mlo_free_connect_ies(sta_ctx->copied_conn_req); 1052 qdf_mem_free(sta_ctx->copied_conn_req); 1053 sta_ctx->copied_conn_req = NULL; 1054 } 1055 copied_conn_req_lock_release(sta_ctx); 1056 } 1057 1058 if (mlo_dev_ctx && wlan_vdev_mlme_is_mlo_vdev(vdev)) { 1059 if (sta_ctx && sta_ctx->connect_req) { 1060 mlo_free_connect_ies(sta_ctx->connect_req); 1061 qdf_mem_free(sta_ctx->connect_req); 1062 sta_ctx->connect_req = NULL; 1063 } 1064 1065 status = mlo_send_link_disconnect_sync(mlo_dev_ctx, source, 1066 reason_code, bssid); 1067 1068 return status; 1069 } 1070 return wlan_cm_disconnect_sync(vdev, source, 1071 reason_code); 1072 } 1073 1074 /** 1075 * mlo_handle_disconnect_resp- Issue desired actions on partner link vdev 1076 * 1077 * @mlo_dev_ctx: pointer to mlo dev context 1078 * @resp: disconnect resp 1079 * 1080 * Return: none 1081 */ 1082 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 1083 static 1084 void mlo_handle_disconnect_resp(struct wlan_mlo_dev_context *mlo_dev_ctx, 1085 struct wlan_cm_discon_rsp *resp) 1086 { 1087 /* If it is secondary link then delete vdev object from mlo device. */ 1088 enum wlan_cm_source source; 1089 enum wlan_reason_code reason_code; 1090 uint8_t i = 0; 1091 1092 mlo_dev_lock_acquire(mlo_dev_ctx); 1093 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 1094 if (!mlo_dev_ctx->wlan_vdev_list[i]) 1095 continue; 1096 1097 if (wlan_cm_is_vdev_connected(mlo_dev_ctx->wlan_vdev_list[i])) { 1098 if (wlan_vdev_mlme_is_mlo_link_vdev( 1099 mlo_dev_ctx->wlan_vdev_list[i])) { 1100 source = resp->req.req.source; 1101 reason_code = resp->req.req.reason_code; 1102 wlan_cm_disconnect( 1103 mlo_dev_ctx->wlan_vdev_list[i], 1104 source, reason_code, NULL); 1105 mlo_dev_lock_release(mlo_dev_ctx); 1106 return; 1107 } 1108 } 1109 } 1110 mlo_dev_lock_release(mlo_dev_ctx); 1111 } 1112 #else 1113 static 1114 void mlo_handle_disconnect_resp(struct wlan_mlo_dev_context *mlo_dev_ctx, 1115 struct wlan_cm_discon_rsp *resp) 1116 { } 1117 1118 static QDF_STATUS ml_activate_connect_req_sched_cb(struct scheduler_msg *msg) 1119 { 1120 struct wlan_objmgr_vdev *vdev = msg->bodyptr; 1121 struct wlan_mlo_dev_context *mlo_dev_ctx = NULL; 1122 struct wlan_mlo_sta *sta_ctx = NULL; 1123 1124 if (!vdev) { 1125 mlme_err("Null input vdev"); 1126 return QDF_STATUS_E_INVAL; 1127 } 1128 1129 mlo_dev_ctx = vdev->mlo_dev_ctx; 1130 if (!mlo_dev_ctx) { 1131 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 1132 return QDF_STATUS_E_INVAL; 1133 } 1134 1135 sta_ctx = mlo_dev_ctx->sta_ctx; 1136 if (!sta_ctx) { 1137 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 1138 return QDF_STATUS_E_INVAL; 1139 } 1140 1141 mlo_connect(vdev, sta_ctx->connect_req); 1142 mlo_free_connect_ies(sta_ctx->connect_req); 1143 qdf_mem_free(sta_ctx->connect_req); 1144 sta_ctx->connect_req = NULL; 1145 1146 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 1147 return QDF_STATUS_SUCCESS; 1148 } 1149 1150 static QDF_STATUS ml_activate_connect_req_flush_cb(struct scheduler_msg *msg) 1151 { 1152 struct wlan_objmgr_vdev *vdev = msg->bodyptr; 1153 1154 if (!vdev) { 1155 mlme_err("Null input vdev"); 1156 return QDF_STATUS_E_INVAL; 1157 } 1158 1159 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 1160 return QDF_STATUS_SUCCESS; 1161 } 1162 #endif 1163 1164 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 1165 static inline 1166 void mlo_sta_link_handle_pending_connect(struct wlan_objmgr_vdev *vdev) 1167 { } 1168 #else 1169 static inline 1170 void mlo_sta_link_handle_pending_connect(struct wlan_objmgr_vdev *vdev) 1171 { 1172 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 1173 struct wlan_objmgr_vdev *tmp_vdev; 1174 struct scheduler_msg msg = {0}; 1175 QDF_STATUS ret; 1176 struct wlan_mlo_sta *sta_ctx = NULL; 1177 uint8_t i = 0; 1178 struct mlo_partner_info partner_info; 1179 struct mlo_link_info partner_link_info; 1180 1181 if (!mlo_dev_ctx) { 1182 mlo_err("ML dev ctx is null"); 1183 return; 1184 } 1185 sta_ctx = mlo_dev_ctx->sta_ctx; 1186 ret = wlan_objmgr_vdev_try_get_ref( 1187 vdev, 1188 WLAN_MLO_MGR_ID); 1189 if (QDF_IS_STATUS_ERROR(ret)) { 1190 mlo_free_connect_ies(sta_ctx->connect_req); 1191 qdf_mem_free(sta_ctx->connect_req); 1192 sta_ctx->connect_req = NULL; 1193 return; 1194 } 1195 msg.bodyptr = vdev; 1196 msg.callback = ml_activate_connect_req_sched_cb; 1197 msg.flush_callback = ml_activate_connect_req_flush_cb; 1198 1199 ret = scheduler_post_message(QDF_MODULE_ID_MLME, 1200 QDF_MODULE_ID_MLME, 1201 QDF_MODULE_ID_MLME, &msg); 1202 if (QDF_IS_STATUS_ERROR(ret)) { 1203 mlo_free_connect_ies(sta_ctx->connect_req); 1204 qdf_mem_free(sta_ctx->connect_req); 1205 sta_ctx->connect_req = NULL; 1206 wlan_objmgr_vdev_release_ref(vdev, 1207 WLAN_MLO_MGR_ID); 1208 return; 1209 } 1210 1211 if (sta_ctx->connect_req->ml_parnter_info.num_partner_links) { 1212 partner_info = sta_ctx->connect_req->ml_parnter_info; 1213 wlan_vdev_mlme_set_mlo_vdev(vdev); 1214 wlan_vdev_mlme_feat_ext2_cap_clear( 1215 vdev, WLAN_VDEV_FEXT2_MLO_STA_LINK); 1216 mlo_clear_connect_req_links_bmap(vdev); 1217 mlo_update_connect_req_links(vdev, 1); 1218 for (i = 0; i < partner_info.num_partner_links; i++) { 1219 partner_link_info = partner_info.partner_link_info[i]; 1220 tmp_vdev = mlo_get_ml_vdev_by_mac( 1221 vdev, 1222 &partner_link_info.link_addr); 1223 if (tmp_vdev) { 1224 mlo_update_connect_req_links(tmp_vdev, 1); 1225 wlan_vdev_mlme_set_mlo_vdev(tmp_vdev); 1226 wlan_vdev_mlme_feat_ext2_cap_set( 1227 tmp_vdev, 1228 WLAN_VDEV_FEXT2_MLO_STA_LINK); 1229 wlan_vdev_set_link_id( 1230 tmp_vdev, 1231 partner_link_info.link_id); 1232 } 1233 } 1234 } 1235 } 1236 #endif 1237 1238 void mlo_sta_link_disconn_notify(struct wlan_objmgr_vdev *vdev, 1239 struct wlan_cm_discon_rsp *resp) 1240 { 1241 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 1242 struct wlan_mlo_sta *sta_ctx = NULL; 1243 struct wlan_objmgr_vdev *assoc_vdev = NULL; 1244 1245 if (!mlo_dev_ctx || !(wlan_vdev_mlme_is_mlo_vdev(vdev))) 1246 return; 1247 1248 sta_ctx = mlo_dev_ctx->sta_ctx; 1249 if (!sta_ctx) 1250 return; 1251 1252 if (!wlan_cm_is_vdev_disconnected(vdev)) 1253 return; 1254 1255 mlo_update_connected_links(vdev, 0); 1256 if (mlo_is_mld_disconnected(vdev)) { 1257 if (sta_ctx->connect_req) { 1258 assoc_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx); 1259 if (!assoc_vdev) 1260 return; 1261 mlo_sta_link_handle_pending_connect(assoc_vdev); 1262 } 1263 } 1264 1265 mlo_handle_disconnect_resp(mlo_dev_ctx, resp); 1266 } 1267 1268 bool mlo_is_mld_sta(struct wlan_objmgr_vdev *vdev) 1269 { 1270 if ((wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE) && 1271 wlan_vdev_mlme_is_mlo_vdev(vdev)) 1272 return true; 1273 1274 return false; 1275 } 1276 1277 #ifndef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 1278 struct wlan_objmgr_vdev * 1279 mlo_get_ml_vdev_by_mac(struct wlan_objmgr_vdev *vdev, 1280 struct qdf_mac_addr *macaddr) 1281 { 1282 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 1283 uint8_t i = 0; 1284 1285 if (!mlo_dev_ctx) 1286 return NULL; 1287 1288 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 1289 if (!mlo_dev_ctx->wlan_vdev_list[i]) 1290 continue; 1291 1292 if(qdf_mem_cmp(macaddr, 1293 wlan_vdev_mlme_get_macaddr(mlo_dev_ctx->wlan_vdev_list[i]), 1294 QDF_MAC_ADDR_SIZE) == 0) { 1295 return mlo_dev_ctx->wlan_vdev_list[i]; 1296 } 1297 } 1298 return NULL; 1299 } 1300 #endif 1301 1302 qdf_freq_t 1303 mlo_get_chan_freq_by_bssid(struct wlan_objmgr_pdev *pdev, 1304 struct qdf_mac_addr *bssid) 1305 { 1306 struct scan_filter *scan_filter; 1307 int8_t ch_freq = 0; 1308 qdf_list_t *list = NULL; 1309 struct scan_cache_node *first_node = NULL; 1310 qdf_list_node_t *cur_node = NULL; 1311 1312 scan_filter = qdf_mem_malloc(sizeof(*scan_filter)); 1313 if (!scan_filter) 1314 return ch_freq; 1315 1316 scan_filter->num_of_bssid = 1; 1317 qdf_mem_copy(scan_filter->bssid_list[0].bytes, 1318 bssid, sizeof(struct qdf_mac_addr)); 1319 list = wlan_scan_get_result(pdev, scan_filter); 1320 qdf_mem_free(scan_filter); 1321 1322 if (!list || (list && !qdf_list_size(list))) { 1323 mlo_debug("scan list empty"); 1324 goto error; 1325 } 1326 1327 qdf_list_peek_front(list, &cur_node); 1328 first_node = qdf_container_of(cur_node, 1329 struct scan_cache_node, 1330 node); 1331 if (first_node && first_node->entry) 1332 ch_freq = first_node->entry->channel.chan_freq; 1333 error: 1334 if (list) 1335 wlan_scan_purge_results(list); 1336 1337 return ch_freq; 1338 } 1339 1340 void mlo_get_assoc_rsp(struct wlan_objmgr_vdev *vdev, 1341 struct element_info *assoc_rsp_frame) 1342 { 1343 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 1344 struct wlan_mlo_sta *sta_ctx = NULL; 1345 1346 if (!mlo_dev_ctx || !mlo_dev_ctx->sta_ctx) 1347 return; 1348 1349 sta_ctx = mlo_dev_ctx->sta_ctx; 1350 1351 if (!sta_ctx->assoc_rsp.len || !sta_ctx->assoc_rsp.ptr) { 1352 mlo_err("Assoc Resp info is empty"); 1353 return; 1354 } 1355 1356 *assoc_rsp_frame = sta_ctx->assoc_rsp; 1357 } 1358 1359 QDF_STATUS mlo_sta_save_quiet_status(struct wlan_mlo_dev_context *mlo_dev_ctx, 1360 uint8_t link_id, 1361 bool quiet_status) 1362 { 1363 struct wlan_mlo_sta *sta_ctx; 1364 int i; 1365 bool find_free_buffer = false; 1366 int free_idx; 1367 1368 if (!mlo_dev_ctx) { 1369 mlo_err("invalid mlo_dev_ctx"); 1370 return QDF_STATUS_E_INVAL; 1371 } 1372 1373 mlo_dev_lock_acquire(mlo_dev_ctx); 1374 sta_ctx = mlo_dev_ctx->sta_ctx; 1375 if (!sta_ctx) { 1376 mlo_err("invalid sta_ctx"); 1377 mlo_dev_lock_release(mlo_dev_ctx); 1378 return QDF_STATUS_E_INVAL; 1379 } 1380 for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_quiet_status); i++) { 1381 if (!sta_ctx->mlo_quiet_status[i].valid_status) { 1382 if (!find_free_buffer) { 1383 free_idx = i; 1384 find_free_buffer = true; 1385 } 1386 } else if (link_id == sta_ctx->mlo_quiet_status[i].link_id) { 1387 sta_ctx->mlo_quiet_status[i].quiet_status = 1388 quiet_status; 1389 mlo_debug("mld mac " QDF_MAC_ADDR_FMT " link id %d quiet status update %d", 1390 QDF_MAC_ADDR_REF(mlo_dev_ctx->mld_addr.bytes), 1391 link_id, quiet_status); 1392 mlo_dev_lock_release(mlo_dev_ctx); 1393 return QDF_STATUS_SUCCESS; 1394 } 1395 } 1396 if (!find_free_buffer) { 1397 mlo_err("no free buffer for link id %d to save quiet_status", 1398 link_id); 1399 mlo_dev_lock_release(mlo_dev_ctx); 1400 return QDF_STATUS_E_INVAL; 1401 } 1402 sta_ctx->mlo_quiet_status[free_idx].quiet_status = quiet_status; 1403 sta_ctx->mlo_quiet_status[free_idx].link_id = link_id; 1404 sta_ctx->mlo_quiet_status[free_idx].valid_status = true; 1405 1406 mlo_debug("mld mac " QDF_MAC_ADDR_FMT " link id %d in quiet status %d", 1407 QDF_MAC_ADDR_REF(mlo_dev_ctx->mld_addr.bytes), 1408 link_id, quiet_status); 1409 mlo_dev_lock_release(mlo_dev_ctx); 1410 1411 return QDF_STATUS_SUCCESS; 1412 } 1413 1414 bool mlo_is_sta_in_quiet_status(struct wlan_mlo_dev_context *mlo_dev_ctx, 1415 uint8_t link_id) 1416 { 1417 struct wlan_mlo_sta *sta_ctx; 1418 int i; 1419 bool quiet_status = false; 1420 1421 if (!mlo_dev_ctx) { 1422 mlo_err("invalid mlo_dev_ctx"); 1423 return quiet_status; 1424 } 1425 1426 mlo_dev_lock_acquire(mlo_dev_ctx); 1427 sta_ctx = mlo_dev_ctx->sta_ctx; 1428 if (!sta_ctx) { 1429 mlo_err("invalid sta_ctx"); 1430 mlo_dev_lock_release(mlo_dev_ctx); 1431 return quiet_status; 1432 } 1433 for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_quiet_status); i++) { 1434 if (sta_ctx->mlo_quiet_status[i].valid_status && 1435 link_id == sta_ctx->mlo_quiet_status[i].link_id) { 1436 quiet_status = 1437 sta_ctx->mlo_quiet_status[i].quiet_status; 1438 break; 1439 } 1440 } 1441 mlo_dev_lock_release(mlo_dev_ctx); 1442 1443 return quiet_status; 1444 } 1445 1446 bool mlo_is_sta_inactivity_allowed_with_quiet(struct wlan_objmgr_psoc *psoc, 1447 uint8_t *vdev_id_list, 1448 uint8_t num_mlo, uint8_t *mlo_idx, 1449 uint8_t affected_links, 1450 uint8_t *affected_list) 1451 { 1452 uint8_t i, j; 1453 struct wlan_objmgr_vdev *vdev; 1454 bool allowed = false; 1455 1456 for (i = 0; i < num_mlo; i++) { 1457 for (j = 0; j < affected_links; j++) { 1458 if (vdev_id_list[mlo_idx[i]] == affected_list[j]) 1459 break; 1460 } 1461 if (j != affected_links) 1462 continue; 1463 /* find vdev not in affected_list */ 1464 vdev = wlan_objmgr_get_vdev_by_id_from_psoc( 1465 psoc, vdev_id_list[mlo_idx[i]], 1466 WLAN_IF_MGR_ID); 1467 if (!vdev) { 1468 mlo_err("invalid vdev for id %d", 1469 vdev_id_list[mlo_idx[i]]); 1470 continue; 1471 } 1472 1473 /* for not affected vdev, check the vdev is in quiet or not*/ 1474 allowed = !mlo_is_sta_in_quiet_status( 1475 vdev->mlo_dev_ctx, wlan_vdev_get_link_id(vdev)); 1476 wlan_objmgr_vdev_release_ref(vdev, WLAN_IF_MGR_ID); 1477 if (allowed) { 1478 mlo_debug("vdev id %d link id %d is not in quiet, allow partner link to trigger inactivity", 1479 wlan_vdev_get_id(vdev), 1480 wlan_vdev_get_link_id(vdev)); 1481 break; 1482 } 1483 } 1484 1485 return allowed; 1486 } 1487 1488 bool mlo_is_sta_csa_synced(struct wlan_mlo_dev_context *mlo_dev_ctx, 1489 uint8_t link_id) 1490 { 1491 struct wlan_mlo_sta *sta_ctx; 1492 int i; 1493 bool sta_csa_synced = false; 1494 1495 if (!mlo_dev_ctx) { 1496 mlo_err("invalid mlo_dev_ctx"); 1497 return sta_csa_synced; 1498 } 1499 1500 mlo_dev_lock_acquire(mlo_dev_ctx); 1501 sta_ctx = mlo_dev_ctx->sta_ctx; 1502 if (!sta_ctx) { 1503 mlo_err("invalid sta_ctx"); 1504 mlo_dev_lock_release(mlo_dev_ctx); 1505 return sta_csa_synced; 1506 } 1507 for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_csa_param); i++) { 1508 if (link_id == sta_ctx->mlo_csa_param[i].link_id && 1509 (sta_ctx->mlo_csa_param[i].valid_csa_param || 1510 sta_ctx->mlo_csa_param[i].mlo_csa_synced)) { 1511 mlo_dev_lock_release(mlo_dev_ctx); 1512 sta_csa_synced = 1513 sta_ctx->mlo_csa_param[i].mlo_csa_synced; 1514 break; 1515 } 1516 } 1517 mlo_dev_lock_release(mlo_dev_ctx); 1518 1519 return sta_csa_synced; 1520 } 1521 1522 QDF_STATUS mlo_sta_csa_save_params(struct wlan_mlo_dev_context *mlo_dev_ctx, 1523 uint8_t link_id, 1524 struct csa_offload_params *csa_param) 1525 { 1526 struct wlan_mlo_sta *sta_ctx; 1527 int i; 1528 bool find_free_buffer = false; 1529 int free_idx; 1530 QDF_STATUS status = QDF_STATUS_SUCCESS; 1531 1532 if (!mlo_dev_ctx) { 1533 mlo_err("invalid mlo_dev_ctx"); 1534 status = QDF_STATUS_E_INVAL; 1535 goto done; 1536 } 1537 1538 mlo_dev_lock_acquire(mlo_dev_ctx); 1539 sta_ctx = mlo_dev_ctx->sta_ctx; 1540 if (!sta_ctx) { 1541 mlo_err("invalid sta_ctx"); 1542 status = QDF_STATUS_E_INVAL; 1543 goto rel_lock; 1544 } 1545 for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_csa_param); i++) { 1546 if (!sta_ctx->mlo_csa_param[i].valid_csa_param && 1547 !sta_ctx->mlo_csa_param[i].mlo_csa_synced) { 1548 if (!find_free_buffer) { 1549 free_idx = i; 1550 find_free_buffer = true; 1551 } 1552 } else if (link_id == sta_ctx->mlo_csa_param[i].link_id) { 1553 qdf_mem_copy(&sta_ctx->mlo_csa_param[i].csa_param, 1554 csa_param, sizeof(*csa_param)); 1555 mlo_debug("mld mac " QDF_MAC_ADDR_FMT " link id %d update csa", 1556 QDF_MAC_ADDR_REF(mlo_dev_ctx->mld_addr.bytes), 1557 link_id); 1558 goto rel_lock; 1559 } 1560 } 1561 if (!find_free_buffer) { 1562 mlo_err("no free buffer of csa param for link %d in sta_ctx", 1563 link_id); 1564 status = QDF_STATUS_E_INVAL; 1565 goto rel_lock; 1566 } 1567 qdf_mem_copy(&sta_ctx->mlo_csa_param[free_idx].csa_param, 1568 csa_param, sizeof(*csa_param)); 1569 sta_ctx->mlo_csa_param[free_idx].link_id = link_id; 1570 sta_ctx->mlo_csa_param[free_idx].valid_csa_param = true; 1571 mlo_debug("mld mac " QDF_MAC_ADDR_FMT " link id %d RX csa", 1572 QDF_MAC_ADDR_REF(mlo_dev_ctx->mld_addr.bytes), 1573 link_id); 1574 1575 rel_lock: 1576 mlo_dev_lock_release(mlo_dev_ctx); 1577 1578 done: 1579 1580 return status; 1581 } 1582 1583 QDF_STATUS mlo_sta_up_active_notify(struct wlan_objmgr_vdev *vdev) 1584 { 1585 struct wlan_mlo_sta *sta_ctx; 1586 struct wlan_mlo_dev_context *mlo_dev_ctx; 1587 uint8_t link_id; 1588 int i; 1589 bool find_free_buffer = false; 1590 int free_idx; 1591 struct csa_offload_params csa_param; 1592 struct wlan_channel *chan; 1593 QDF_STATUS status = QDF_STATUS_SUCCESS; 1594 1595 if (!vdev) { 1596 mlo_err("invalid vdev"); 1597 status = QDF_STATUS_E_INVAL; 1598 goto done; 1599 } 1600 link_id = wlan_vdev_get_link_id(vdev); 1601 mlo_dev_ctx = vdev->mlo_dev_ctx; 1602 if (!mlo_dev_ctx) { 1603 mlo_err("invalid mlo_dev_ctx"); 1604 status = QDF_STATUS_E_INVAL; 1605 goto done; 1606 } 1607 mlo_dev_lock_acquire(mlo_dev_ctx); 1608 sta_ctx = mlo_dev_ctx->sta_ctx; 1609 if (!sta_ctx) { 1610 mlo_err("invalid sta_ctx"); 1611 status = QDF_STATUS_E_INVAL; 1612 goto rel_lock; 1613 } 1614 1615 for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_csa_param); i++) { 1616 if (!sta_ctx->mlo_csa_param[i].valid_csa_param && 1617 !sta_ctx->mlo_csa_param[i].mlo_csa_synced) { 1618 if (!find_free_buffer) { 1619 free_idx = i; 1620 find_free_buffer = true; 1621 } 1622 } else if (link_id == sta_ctx->mlo_csa_param[i].link_id) { 1623 if (sta_ctx->mlo_csa_param[i].valid_csa_param && 1624 !sta_ctx->mlo_csa_param[i].mlo_csa_synced) { 1625 mlo_debug("mld mac " QDF_MAC_ADDR_FMT " vdev id %d link id %d handle csa", 1626 QDF_MAC_ADDR_REF( 1627 mlo_dev_ctx->mld_addr.bytes), 1628 wlan_vdev_get_id(vdev), link_id); 1629 csa_param = sta_ctx->mlo_csa_param[i].csa_param; 1630 sta_ctx->mlo_csa_param[i].mlo_csa_synced = true; 1631 mlo_dev_lock_release(mlo_dev_ctx); 1632 chan = wlan_vdev_mlme_get_bss_chan(vdev); 1633 if (csa_param.csa_chan_freq && chan && 1634 csa_param.csa_chan_freq != chan->ch_freq) 1635 mlo_mlme_handle_sta_csa_param( 1636 vdev, &csa_param); 1637 goto done; 1638 } 1639 sta_ctx->mlo_csa_param[i].mlo_csa_synced = true; 1640 goto rel_lock; 1641 } 1642 } 1643 if (!find_free_buffer) { 1644 mlo_err("no free buffer of csa param for link %d in sta_ctx", 1645 link_id); 1646 goto rel_lock; 1647 } 1648 sta_ctx->mlo_csa_param[free_idx].mlo_csa_synced = true; 1649 sta_ctx->mlo_csa_param[free_idx].link_id = link_id; 1650 mlo_debug("mld mac " QDF_MAC_ADDR_FMT " link id %d UP Active", 1651 QDF_MAC_ADDR_REF(mlo_dev_ctx->mld_addr.bytes), 1652 link_id); 1653 1654 rel_lock: 1655 mlo_dev_lock_release(mlo_dev_ctx); 1656 1657 done: 1658 1659 return status; 1660 } 1661 1662 bool mlo_is_sta_csa_param_handled(struct wlan_objmgr_vdev *vdev, 1663 struct csa_offload_params *csa_param) 1664 { 1665 struct wlan_mlo_sta *sta_ctx; 1666 struct wlan_mlo_dev_context *mlo_dev_ctx; 1667 uint8_t link_id; 1668 int i; 1669 bool handled = false; 1670 1671 if (!vdev) { 1672 mlo_err("invalid vdev"); 1673 goto done; 1674 } 1675 link_id = wlan_vdev_get_link_id(vdev); 1676 mlo_dev_ctx = vdev->mlo_dev_ctx; 1677 if (!mlo_dev_ctx) { 1678 mlo_err("invalid mlo_dev_ctx"); 1679 goto done; 1680 } 1681 mlo_dev_lock_acquire(mlo_dev_ctx); 1682 sta_ctx = mlo_dev_ctx->sta_ctx; 1683 if (!sta_ctx) { 1684 mlo_err("invalid sta_ctx"); 1685 goto rel_lock; 1686 } 1687 1688 for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_csa_param); i++) { 1689 if (link_id == sta_ctx->mlo_csa_param[i].link_id && 1690 (sta_ctx->mlo_csa_param[i].valid_csa_param || 1691 sta_ctx->mlo_csa_param[i].mlo_csa_synced)) 1692 break; 1693 } 1694 1695 if (i >= QDF_ARRAY_SIZE(sta_ctx->mlo_csa_param)) { 1696 mlo_debug("mlo csa synced does not happen before csa FW event"); 1697 goto rel_lock; 1698 } 1699 if (!sta_ctx->mlo_csa_param[i].csa_offload_event_recvd) { 1700 sta_ctx->mlo_csa_param[i].csa_offload_event_recvd = true; 1701 if (sta_ctx->mlo_csa_param[i].valid_csa_param && 1702 !qdf_mem_cmp(&sta_ctx->mlo_csa_param[i].csa_param, 1703 csa_param, sizeof(*csa_param))) 1704 handled = true; 1705 } 1706 1707 rel_lock: 1708 mlo_dev_lock_release(mlo_dev_ctx); 1709 1710 done: 1711 1712 return handled; 1713 } 1714 1715 void mlo_internal_disconnect_links(struct wlan_objmgr_vdev *vdev) 1716 { 1717 struct wlan_mlo_dev_context *mlo_dev_ctx = NULL; 1718 struct wlan_mlo_sta *sta_ctx = NULL; 1719 uint8_t i; 1720 1721 if (!vdev) 1722 return; 1723 1724 if (!wlan_vdev_mlme_is_assoc_sta_vdev(vdev)) { 1725 mlo_debug("Not an assoc vdev, so ignore disconnect req"); 1726 return; 1727 } 1728 1729 mlo_dev_ctx = vdev->mlo_dev_ctx; 1730 if (mlo_dev_ctx) { 1731 sta_ctx = mlo_dev_ctx->sta_ctx; 1732 } else { 1733 mlo_err("Invalid mlo_dev_ctx"); 1734 return; 1735 } 1736 1737 if (sta_ctx) { 1738 copied_conn_req_lock_acquire(sta_ctx); 1739 if (sta_ctx->copied_conn_req) { 1740 mlo_free_connect_ies(sta_ctx->copied_conn_req); 1741 qdf_mem_free(sta_ctx->copied_conn_req); 1742 sta_ctx->copied_conn_req = NULL; 1743 } 1744 copied_conn_req_lock_release(sta_ctx); 1745 } else { 1746 mlo_err("Invalid sta_ctx"); 1747 return; 1748 } 1749 1750 mlo_dev_lock_acquire(mlo_dev_ctx); 1751 if (sta_ctx->connect_req) { 1752 mlo_free_connect_ies(sta_ctx->connect_req); 1753 qdf_mem_free(sta_ctx->connect_req); 1754 sta_ctx->connect_req = NULL; 1755 } 1756 1757 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 1758 if (!mlo_dev_ctx->wlan_vdev_list[i]) 1759 continue; 1760 1761 if (qdf_test_bit(i, 1762 mlo_dev_ctx->sta_ctx->wlan_connected_links) && 1763 mlo_dev_ctx->wlan_vdev_list[i] != 1764 mlo_get_assoc_link_vdev(mlo_dev_ctx)) 1765 wlan_cm_disconnect(mlo_dev_ctx->wlan_vdev_list[i], 1766 CM_INTERNAL_DISCONNECT, 1767 REASON_UNSPEC_FAILURE, 1768 NULL); 1769 } 1770 1771 mlo_dev_lock_release(mlo_dev_ctx); 1772 } 1773 1774 void mlo_sta_get_vdev_list(struct wlan_objmgr_vdev *vdev, uint16_t *vdev_count, 1775 struct wlan_objmgr_vdev **wlan_vdev_list) 1776 { 1777 struct wlan_mlo_dev_context *dev_ctx; 1778 int i; 1779 QDF_STATUS status; 1780 1781 *vdev_count = 0; 1782 1783 if (!vdev || !vdev->mlo_dev_ctx) { 1784 mlo_err("Invalid input"); 1785 return; 1786 } 1787 1788 dev_ctx = vdev->mlo_dev_ctx; 1789 1790 mlo_dev_lock_acquire(dev_ctx); 1791 *vdev_count = 0; 1792 for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) { 1793 if (dev_ctx->wlan_vdev_list[i]) { 1794 status = 1795 wlan_objmgr_vdev_try_get_ref(dev_ctx->wlan_vdev_list[i], 1796 WLAN_MLO_MGR_ID); 1797 if (QDF_IS_STATUS_ERROR(status)) 1798 break; 1799 wlan_vdev_list[*vdev_count] = 1800 dev_ctx->wlan_vdev_list[i]; 1801 (*vdev_count) += 1; 1802 } 1803 } 1804 mlo_dev_lock_release(dev_ctx); 1805 } 1806 1807 #endif 1808