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 " vdev_id:%d", 531 QDF_MAC_ADDR_REF(wlan_vdev_mlme_get_macaddr(vdev)), 532 wlan_vdev_get_id(vdev)); 533 534 qdf_mem_copy(&req, sta_ctx->copied_conn_req, 535 sizeof(struct wlan_cm_connect_req)); 536 537 mlo_update_connect_req_chan_info(&req); 538 539 qdf_mem_copy(req.bssid.bytes, 540 link_info.link_addr.bytes, 541 QDF_MAC_ADDR_SIZE); 542 543 qdf_mem_copy(&req.ml_parnter_info, 544 &ml_parnter_info, 545 sizeof(struct mlo_partner_info)); 546 547 req.ssid.length = ssid.length; 548 qdf_mem_copy(&req.ssid.ssid, &ssid.ssid, ssid.length); 549 550 mlo_allocate_and_copy_ies(&req, sta_ctx->copied_conn_req); 551 if (!req.assoc_ie.ptr) 552 mlo_err("Failed to allocate assoc IEs"); 553 554 if (!req.scan_ie.ptr) 555 mlo_err("Failed to allocate scan IEs"); 556 557 /* Reset crypto auth type for partner link. 558 * It will be set based on partner scan cache entry 559 */ 560 req.crypto.auth_type = 0; 561 562 wlan_cm_start_connect(vdev, &req); 563 mlo_free_connect_ies(&req); 564 } 565 566 /** 567 * mlo_send_link_connect- Create/Issue the connection on secondary link 568 * 569 * @vdev: vdev pointer 570 * @mlo_dev_ctx: ml dev context 571 * @assoc_rsp: assoc response 572 * @ml_parnter_info: ml partner link info 573 * 574 * Return: none 575 */ 576 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 577 static void 578 mlo_send_link_connect(struct wlan_objmgr_vdev *vdev, 579 struct wlan_mlo_dev_context *mlo_dev_ctx, 580 struct element_info *assoc_rsp, 581 struct mlo_partner_info *ml_parnter_info) 582 { 583 /* Create the secondary interface, Send keys if the last link */ 584 uint8_t i, partner_idx = 0; 585 struct wlan_ssid ssid = {0}; 586 587 mlo_debug("Sending link connect on partner interface"); 588 wlan_vdev_mlme_get_ssid( 589 vdev, ssid.ssid, 590 &ssid.length); 591 592 if (!ml_parnter_info->num_partner_links) { 593 mlo_err("No partner info in connect resp"); 594 return; 595 } 596 597 if(wlan_vdev_mlme_is_mlo_link_vdev(vdev)) 598 return; 599 600 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 601 if (!mlo_dev_ctx->wlan_vdev_list[i] || 602 (mlo_dev_ctx->wlan_vdev_list[i] == vdev)) 603 continue; 604 wlan_vdev_mlme_set_mlo_vdev(mlo_dev_ctx->wlan_vdev_list[i]); 605 wlan_vdev_mlme_feat_ext2_cap_set(mlo_dev_ctx->wlan_vdev_list[i], 606 WLAN_VDEV_FEXT2_MLO_STA_LINK); 607 wlan_vdev_set_link_id( 608 mlo_dev_ctx->wlan_vdev_list[i], 609 ml_parnter_info->partner_link_info[partner_idx].link_id); 610 ml_parnter_info->partner_link_info[partner_idx].vdev_id = 611 wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i]); 612 mlo_prepare_and_send_connect( 613 mlo_dev_ctx->wlan_vdev_list[i], 614 *ml_parnter_info, 615 ml_parnter_info->partner_link_info[partner_idx], 616 ssid); 617 mlo_update_connected_links(mlo_dev_ctx->wlan_vdev_list[i], 1); 618 partner_idx++; 619 } 620 } 621 #else 622 static void 623 mlo_send_link_connect(struct wlan_objmgr_vdev *vdev, 624 struct wlan_mlo_dev_context *mlo_dev_ctx, 625 struct element_info *assoc_rsp, 626 struct mlo_partner_info *ml_parnter_info) 627 { 628 struct wlan_ssid ssid = {0}; 629 uint8_t i = 0; 630 uint8_t j = 0; 631 632 if (!ml_parnter_info->num_partner_links) { 633 mlo_err("No partner info in connect resp"); 634 return; 635 } 636 637 mlo_dev_lock_acquire(mlo_dev_ctx); 638 if (wlan_cm_is_vdev_connected(vdev)) { 639 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 640 if (!mlo_dev_ctx->wlan_vdev_list[i]) 641 continue; 642 /* 643 * mlo_connect: update wlan_connected_links bitmap from 644 * assoc resp parsing 645 */ 646 if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links)) { 647 if (wlan_cm_is_vdev_disconnected( 648 mlo_dev_ctx->wlan_vdev_list[i])) { 649 for (j = 0; j < ml_parnter_info->num_partner_links; j++) { 650 if (mlo_dev_ctx->wlan_vdev_list[i]->vdev_mlme.mlo_link_id == 651 ml_parnter_info->partner_link_info[j].link_id) 652 break; 653 } 654 if (j < ml_parnter_info->num_partner_links) { 655 wlan_vdev_mlme_get_ssid( 656 vdev, ssid.ssid, 657 &ssid.length); 658 mlo_prepare_and_send_connect( 659 mlo_dev_ctx->wlan_vdev_list[i], 660 *ml_parnter_info, 661 ml_parnter_info->partner_link_info[j], 662 ssid); 663 } 664 mlo_dev_lock_release(mlo_dev_ctx); 665 return; 666 } 667 } 668 } 669 } 670 mlo_dev_lock_release(mlo_dev_ctx); 671 } 672 #endif 673 674 void 675 mlo_update_connected_links_bmap(struct wlan_mlo_dev_context *mlo_dev_ctx, 676 struct mlo_partner_info ml_parnter_info) 677 { 678 uint8_t i = 0; 679 uint8_t j = 0; 680 681 if (!mlo_dev_ctx) { 682 mlo_err("ML dev ctx is NULL"); 683 return; 684 } 685 686 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 687 if (!mlo_dev_ctx->wlan_vdev_list[i]) 688 continue; 689 690 for (j = 0; j < ml_parnter_info.num_partner_links; j++) { 691 if (wlan_vdev_get_link_id(mlo_dev_ctx->wlan_vdev_list[i]) == 692 ml_parnter_info.partner_link_info[j].link_id) 693 mlo_update_connected_links( 694 mlo_dev_ctx->wlan_vdev_list[i], 1); 695 } 696 } 697 } 698 699 static QDF_STATUS ml_activate_disconnect_req_sched_cb(struct scheduler_msg *msg) 700 { 701 struct wlan_objmgr_vdev *vdev = msg->bodyptr; 702 703 if (!vdev) { 704 mlme_err("Null input vdev"); 705 return QDF_STATUS_E_INVAL; 706 } 707 708 mlo_disconnect(vdev, CM_OSIF_DISCONNECT, 709 REASON_UNSPEC_FAILURE, NULL); 710 711 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 712 return QDF_STATUS_SUCCESS; 713 } 714 715 static QDF_STATUS ml_activate_disconnect_req_flush_cb(struct scheduler_msg *msg) 716 { 717 struct wlan_objmgr_vdev *vdev = msg->bodyptr; 718 719 if (!vdev) { 720 mlme_err("Null input vdev"); 721 return QDF_STATUS_E_INVAL; 722 } 723 724 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 725 return QDF_STATUS_SUCCESS; 726 } 727 728 static QDF_STATUS ml_activate_pend_disconn_req_cb(struct scheduler_msg *msg) 729 { 730 struct wlan_objmgr_vdev *vdev = msg->bodyptr; 731 struct wlan_mlo_dev_context *mlo_dev_ctx = NULL; 732 struct wlan_mlo_sta *sta_ctx = NULL; 733 734 if (!vdev) { 735 mlme_err("Null input vdev"); 736 return QDF_STATUS_E_INVAL; 737 } 738 739 mlo_dev_ctx = vdev->mlo_dev_ctx; 740 sta_ctx = mlo_dev_ctx->sta_ctx; 741 mlo_disconnect(vdev, sta_ctx->disconn_req->source, 742 sta_ctx->disconn_req->reason_code, 743 &sta_ctx->disconn_req->bssid); 744 745 qdf_mem_free(sta_ctx->disconn_req); 746 sta_ctx->disconn_req = NULL; 747 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 748 return QDF_STATUS_SUCCESS; 749 } 750 751 static QDF_STATUS ml_activate_pend_disconn_req_flush_cb( 752 struct scheduler_msg *msg) 753 { 754 struct wlan_objmgr_vdev *vdev = msg->bodyptr; 755 756 if (!vdev) { 757 mlme_err("Null input vdev"); 758 return QDF_STATUS_E_INVAL; 759 } 760 761 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 762 return QDF_STATUS_SUCCESS; 763 } 764 765 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 766 static inline 767 QDF_STATUS mlo_post_disconnect_msg(struct scheduler_msg *msg) 768 { 769 return scheduler_post_message( 770 QDF_MODULE_ID_OS_IF, 771 QDF_MODULE_ID_SCAN, 772 QDF_MODULE_ID_OS_IF, 773 msg); 774 } 775 #else 776 static inline 777 QDF_STATUS mlo_post_disconnect_msg(struct scheduler_msg *msg) 778 { 779 return scheduler_post_message( 780 QDF_MODULE_ID_MLME, 781 QDF_MODULE_ID_MLME, 782 QDF_MODULE_ID_MLME, 783 msg); 784 } 785 #endif 786 787 static inline 788 void mlo_handle_sta_link_connect_failure(struct wlan_objmgr_vdev *vdev, 789 struct wlan_cm_connect_resp *rsp) 790 { 791 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 792 struct scheduler_msg msg = {0}; 793 QDF_STATUS ret; 794 struct wlan_objmgr_vdev *assoc_vdev; 795 796 if (!mlo_dev_ctx) { 797 mlo_err("ML dev ctx is NULL"); 798 return; 799 } 800 801 assoc_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx); 802 if (!assoc_vdev) { 803 mlo_err("Assoc Vdev is NULL"); 804 return; 805 } 806 807 if (vdev != assoc_vdev) { 808 mlo_update_connected_links(vdev, 0); 809 if (rsp->reason == CM_NO_CANDIDATE_FOUND || 810 rsp->reason == CM_HW_MODE_FAILURE || 811 rsp->reason == CM_SER_FAILURE) { 812 ret = wlan_objmgr_vdev_try_get_ref( 813 assoc_vdev, WLAN_MLO_MGR_ID); 814 if (QDF_IS_STATUS_ERROR(ret)) { 815 mlo_err("Failed to get ref vdev_id %d", 816 wlan_vdev_get_id(assoc_vdev)); 817 return; 818 } 819 /* Since these failures happen in same context. use 820 * scheduler to avoid deadlock by deferring context 821 */ 822 msg.bodyptr = assoc_vdev; 823 msg.callback = ml_activate_disconnect_req_sched_cb; 824 msg.flush_callback = 825 ml_activate_disconnect_req_flush_cb; 826 mlo_post_disconnect_msg(&msg); 827 if (QDF_IS_STATUS_ERROR(ret)) { 828 wlan_objmgr_vdev_release_ref( 829 assoc_vdev, 830 WLAN_MLO_MGR_ID); 831 return; 832 } 833 } else { 834 mlo_disconnect(vdev, CM_OSIF_DISCONNECT, 835 REASON_UNSPEC_FAILURE, NULL); 836 } 837 } 838 } 839 840 static inline 841 void mlo_handle_pending_disconnect(struct wlan_objmgr_vdev *vdev) 842 { 843 struct scheduler_msg msg = {0}; 844 QDF_STATUS ret; 845 846 ret = wlan_objmgr_vdev_try_get_ref( 847 vdev, WLAN_MLO_MGR_ID); 848 if (QDF_IS_STATUS_ERROR(ret)) { 849 mlo_err("Failed to get ref vdev_id %d", 850 wlan_vdev_get_id(vdev)); 851 return; 852 } 853 854 msg.bodyptr = vdev; 855 msg.callback = ml_activate_pend_disconn_req_cb; 856 msg.flush_callback = 857 ml_activate_pend_disconn_req_flush_cb; 858 ret = mlo_post_disconnect_msg(&msg); 859 if (QDF_IS_STATUS_ERROR(ret)) { 860 mlo_err("Failed to post scheduler msg"); 861 wlan_objmgr_vdev_release_ref( 862 vdev, 863 WLAN_MLO_MGR_ID); 864 QDF_BUG(0); 865 return; 866 } 867 } 868 869 void mlo_sta_link_connect_notify(struct wlan_objmgr_vdev *vdev, 870 struct wlan_cm_connect_resp *rsp) 871 { 872 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 873 struct wlan_mlo_sta *sta_ctx = NULL; 874 875 if (mlo_dev_ctx) { 876 sta_ctx = mlo_dev_ctx->sta_ctx; 877 } else { 878 mlo_debug_rl("mlo_dev_ctx is NULL"); 879 return; 880 } 881 882 if (sta_ctx && sta_ctx->disconn_req) { 883 mlo_debug("Handle pending disocnnect for vdev %d", 884 wlan_vdev_get_id(vdev)); 885 mlo_handle_pending_disconnect(vdev); 886 return; 887 } 888 889 if (wlan_cm_is_vdev_disconnected(vdev)) { 890 if (sta_ctx) { 891 copied_conn_req_lock_acquire(sta_ctx); 892 if (sta_ctx->copied_conn_req) { 893 mlo_free_connect_ies(sta_ctx->copied_conn_req); 894 qdf_mem_free(sta_ctx->copied_conn_req); 895 sta_ctx->copied_conn_req = NULL; 896 } 897 copied_conn_req_lock_release(sta_ctx); 898 } 899 } 900 901 if (wlan_vdev_mlme_is_mlo_vdev(vdev)) { 902 mlo_debug("Vdev: %d", wlan_vdev_get_id(vdev)); 903 if (wlan_cm_is_vdev_disconnected(vdev)) { 904 mlo_handle_sta_link_connect_failure(vdev, rsp); 905 return; 906 } else if (!wlan_cm_is_vdev_connected(vdev)) { 907 /* If vdev is not in disconnected or connected state, 908 * then the event is received due to connect req being 909 * flushed. Hence, ignore this event 910 */ 911 return; 912 } 913 914 if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev) && sta_ctx) { 915 if (sta_ctx->assoc_rsp.ptr) { 916 qdf_mem_free(sta_ctx->assoc_rsp.ptr); 917 sta_ctx->assoc_rsp.ptr = NULL; 918 } 919 sta_ctx->assoc_rsp.len = rsp->connect_ies.assoc_rsp.len; 920 sta_ctx->assoc_rsp.ptr = 921 qdf_mem_malloc(rsp->connect_ies.assoc_rsp.len); 922 if (!sta_ctx->assoc_rsp.ptr) { 923 QDF_ASSERT(0); 924 return; 925 } 926 if (rsp->connect_ies.assoc_rsp.ptr) 927 qdf_mem_copy(sta_ctx->assoc_rsp.ptr, 928 rsp->connect_ies.assoc_rsp.ptr, 929 rsp->connect_ies.assoc_rsp.len); 930 /* Update connected_links_bmap for all vdev taking 931 * part in association 932 */ 933 mlo_update_connected_links(vdev, 1); 934 mlo_update_connected_links_bmap(mlo_dev_ctx, 935 rsp->ml_parnter_info); 936 } 937 mlo_send_link_connect(vdev, mlo_dev_ctx, 938 &rsp->connect_ies.assoc_rsp, 939 &rsp->ml_parnter_info); 940 } 941 } 942 943 /** 944 * mlo_send_link_disconnect_sync- Issue sync the disconnect request on MLD links 945 * 946 * @mlo_dev_ctx: pointer to mlo dev context 947 * @source: disconnect source 948 * @reason_code: disconnect reason 949 * @bssid: bssid of AP to disconnect, can be null if not known 950 * 951 * Return: QDF_STATUS 952 */ 953 static QDF_STATUS 954 mlo_send_link_disconnect_sync(struct wlan_mlo_dev_context *mlo_dev_ctx, 955 enum wlan_cm_source source, 956 enum wlan_reason_code reason_code, 957 struct qdf_mac_addr *bssid) 958 { 959 uint8_t i = 0; 960 struct wlan_objmgr_vdev *assoc_vdev = 961 mlo_get_assoc_link_vdev(mlo_dev_ctx); 962 963 if (!assoc_vdev) 964 return QDF_STATUS_E_FAILURE; 965 966 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 967 if (!mlo_dev_ctx->wlan_vdev_list[i]) 968 continue; 969 970 if (mlo_dev_ctx->wlan_vdev_list[i] != 971 mlo_get_assoc_link_vdev(mlo_dev_ctx)) 972 wlan_cm_disconnect_sync(mlo_dev_ctx->wlan_vdev_list[i], 973 source, reason_code); 974 } 975 976 wlan_cm_disconnect_sync(assoc_vdev, 977 source, reason_code); 978 return QDF_STATUS_SUCCESS; 979 } 980 981 QDF_STATUS mlo_disconnect(struct wlan_objmgr_vdev *vdev, 982 enum wlan_cm_source source, 983 enum wlan_reason_code reason_code, 984 struct qdf_mac_addr *bssid) 985 { 986 struct wlan_mlo_dev_context *mlo_dev_ctx = NULL; 987 struct wlan_mlo_sta *sta_ctx = NULL; 988 QDF_STATUS status = QDF_STATUS_SUCCESS; 989 990 if (!vdev) 991 return QDF_STATUS_E_FAILURE; 992 993 mlo_dev_ctx = vdev->mlo_dev_ctx; 994 if (mlo_dev_ctx) 995 sta_ctx = mlo_dev_ctx->sta_ctx; 996 if (sta_ctx) { 997 copied_conn_req_lock_acquire(sta_ctx); 998 if (sta_ctx->copied_conn_req) { 999 mlo_free_connect_ies(sta_ctx->copied_conn_req); 1000 qdf_mem_free(sta_ctx->copied_conn_req); 1001 sta_ctx->copied_conn_req = NULL; 1002 } 1003 copied_conn_req_lock_release(sta_ctx); 1004 } 1005 1006 if (mlo_dev_ctx && wlan_vdev_mlme_is_mlo_vdev(vdev)) { 1007 mlo_dev_lock_acquire(mlo_dev_ctx); 1008 if (sta_ctx && sta_ctx->connect_req) { 1009 mlo_free_connect_ies(sta_ctx->connect_req); 1010 qdf_mem_free(sta_ctx->connect_req); 1011 sta_ctx->connect_req = NULL; 1012 } 1013 1014 status = mlo_validate_disconn_req(vdev, source, 1015 reason_code, bssid); 1016 if (QDF_IS_STATUS_ERROR(status)) { 1017 mlo_debug("Connect in progress, deferring disconnect"); 1018 mlo_dev_lock_release(mlo_dev_ctx); 1019 return status; 1020 } 1021 1022 status = mlo_send_link_disconnect(mlo_dev_ctx, source, 1023 reason_code, bssid); 1024 mlo_dev_lock_release(mlo_dev_ctx); 1025 return status; 1026 } 1027 return wlan_cm_disconnect(vdev, source, 1028 reason_code, NULL); 1029 } 1030 1031 QDF_STATUS mlo_sync_disconnect(struct wlan_objmgr_vdev *vdev, 1032 enum wlan_cm_source source, 1033 enum wlan_reason_code reason_code, 1034 struct qdf_mac_addr *bssid) 1035 { 1036 struct wlan_mlo_dev_context *mlo_dev_ctx = NULL; 1037 struct wlan_mlo_sta *sta_ctx = NULL; 1038 QDF_STATUS status = QDF_STATUS_SUCCESS; 1039 1040 if (!vdev) 1041 return QDF_STATUS_E_FAILURE; 1042 1043 mlo_dev_ctx = vdev->mlo_dev_ctx; 1044 if (mlo_dev_ctx) 1045 sta_ctx = mlo_dev_ctx->sta_ctx; 1046 if (sta_ctx) { 1047 copied_conn_req_lock_acquire(sta_ctx); 1048 if (sta_ctx->copied_conn_req) { 1049 mlo_free_connect_ies(sta_ctx->copied_conn_req); 1050 qdf_mem_free(sta_ctx->copied_conn_req); 1051 sta_ctx->copied_conn_req = NULL; 1052 } 1053 copied_conn_req_lock_release(sta_ctx); 1054 } 1055 1056 if (mlo_dev_ctx && wlan_vdev_mlme_is_mlo_vdev(vdev)) { 1057 if (sta_ctx && sta_ctx->connect_req) { 1058 mlo_free_connect_ies(sta_ctx->connect_req); 1059 qdf_mem_free(sta_ctx->connect_req); 1060 sta_ctx->connect_req = NULL; 1061 } 1062 1063 status = mlo_send_link_disconnect_sync(mlo_dev_ctx, source, 1064 reason_code, bssid); 1065 1066 return status; 1067 } 1068 return wlan_cm_disconnect_sync(vdev, source, 1069 reason_code); 1070 } 1071 1072 /** 1073 * mlo_handle_disconnect_resp- Issue desired actions on partner link vdev 1074 * 1075 * @mlo_dev_ctx: pointer to mlo dev context 1076 * @resp: disconnect resp 1077 * 1078 * Return: none 1079 */ 1080 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 1081 static 1082 void mlo_handle_disconnect_resp(struct wlan_mlo_dev_context *mlo_dev_ctx, 1083 struct wlan_cm_discon_rsp *resp) 1084 { 1085 /* If it is secondary link then delete vdev object from mlo device. */ 1086 enum wlan_cm_source source; 1087 enum wlan_reason_code reason_code; 1088 uint8_t i = 0; 1089 1090 mlo_dev_lock_acquire(mlo_dev_ctx); 1091 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 1092 if (!mlo_dev_ctx->wlan_vdev_list[i]) 1093 continue; 1094 1095 if (wlan_cm_is_vdev_connected(mlo_dev_ctx->wlan_vdev_list[i])) { 1096 if (wlan_vdev_mlme_is_mlo_link_vdev( 1097 mlo_dev_ctx->wlan_vdev_list[i])) { 1098 source = resp->req.req.source; 1099 reason_code = resp->req.req.reason_code; 1100 wlan_cm_disconnect( 1101 mlo_dev_ctx->wlan_vdev_list[i], 1102 source, reason_code, NULL); 1103 mlo_dev_lock_release(mlo_dev_ctx); 1104 return; 1105 } 1106 } 1107 } 1108 mlo_dev_lock_release(mlo_dev_ctx); 1109 } 1110 #else 1111 static 1112 void mlo_handle_disconnect_resp(struct wlan_mlo_dev_context *mlo_dev_ctx, 1113 struct wlan_cm_discon_rsp *resp) 1114 { } 1115 1116 static QDF_STATUS ml_activate_connect_req_sched_cb(struct scheduler_msg *msg) 1117 { 1118 struct wlan_objmgr_vdev *vdev = msg->bodyptr; 1119 struct wlan_mlo_dev_context *mlo_dev_ctx = NULL; 1120 struct wlan_mlo_sta *sta_ctx = NULL; 1121 1122 if (!vdev) { 1123 mlme_err("Null input vdev"); 1124 return QDF_STATUS_E_INVAL; 1125 } 1126 1127 mlo_dev_ctx = vdev->mlo_dev_ctx; 1128 if (!mlo_dev_ctx) { 1129 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 1130 return QDF_STATUS_E_INVAL; 1131 } 1132 1133 sta_ctx = mlo_dev_ctx->sta_ctx; 1134 if (!sta_ctx) { 1135 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 1136 return QDF_STATUS_E_INVAL; 1137 } 1138 1139 mlo_connect(vdev, sta_ctx->connect_req); 1140 mlo_free_connect_ies(sta_ctx->connect_req); 1141 qdf_mem_free(sta_ctx->connect_req); 1142 sta_ctx->connect_req = NULL; 1143 1144 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 1145 return QDF_STATUS_SUCCESS; 1146 } 1147 1148 static QDF_STATUS ml_activate_connect_req_flush_cb(struct scheduler_msg *msg) 1149 { 1150 struct wlan_objmgr_vdev *vdev = msg->bodyptr; 1151 1152 if (!vdev) { 1153 mlme_err("Null input vdev"); 1154 return QDF_STATUS_E_INVAL; 1155 } 1156 1157 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 1158 return QDF_STATUS_SUCCESS; 1159 } 1160 #endif 1161 1162 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 1163 static inline 1164 void mlo_sta_link_handle_pending_connect(struct wlan_objmgr_vdev *vdev) 1165 { } 1166 #else 1167 static inline 1168 void mlo_sta_link_handle_pending_connect(struct wlan_objmgr_vdev *vdev) 1169 { 1170 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 1171 struct wlan_objmgr_vdev *tmp_vdev; 1172 struct scheduler_msg msg = {0}; 1173 QDF_STATUS ret; 1174 struct wlan_mlo_sta *sta_ctx = NULL; 1175 uint8_t i = 0; 1176 struct mlo_partner_info partner_info; 1177 struct mlo_link_info partner_link_info; 1178 1179 if (!mlo_dev_ctx) { 1180 mlo_err("ML dev ctx is null"); 1181 return; 1182 } 1183 sta_ctx = mlo_dev_ctx->sta_ctx; 1184 ret = wlan_objmgr_vdev_try_get_ref( 1185 vdev, 1186 WLAN_MLO_MGR_ID); 1187 if (QDF_IS_STATUS_ERROR(ret)) { 1188 mlo_free_connect_ies(sta_ctx->connect_req); 1189 qdf_mem_free(sta_ctx->connect_req); 1190 sta_ctx->connect_req = NULL; 1191 return; 1192 } 1193 msg.bodyptr = vdev; 1194 msg.callback = ml_activate_connect_req_sched_cb; 1195 msg.flush_callback = ml_activate_connect_req_flush_cb; 1196 1197 ret = scheduler_post_message(QDF_MODULE_ID_MLME, 1198 QDF_MODULE_ID_MLME, 1199 QDF_MODULE_ID_MLME, &msg); 1200 if (QDF_IS_STATUS_ERROR(ret)) { 1201 mlo_free_connect_ies(sta_ctx->connect_req); 1202 qdf_mem_free(sta_ctx->connect_req); 1203 sta_ctx->connect_req = NULL; 1204 wlan_objmgr_vdev_release_ref(vdev, 1205 WLAN_MLO_MGR_ID); 1206 return; 1207 } 1208 1209 if (sta_ctx->connect_req->ml_parnter_info.num_partner_links) { 1210 partner_info = sta_ctx->connect_req->ml_parnter_info; 1211 wlan_vdev_mlme_set_mlo_vdev(vdev); 1212 wlan_vdev_mlme_feat_ext2_cap_clear( 1213 vdev, WLAN_VDEV_FEXT2_MLO_STA_LINK); 1214 mlo_clear_connect_req_links_bmap(vdev); 1215 mlo_update_connect_req_links(vdev, 1); 1216 for (i = 0; i < partner_info.num_partner_links; i++) { 1217 partner_link_info = partner_info.partner_link_info[i]; 1218 tmp_vdev = mlo_get_ml_vdev_by_mac( 1219 vdev, 1220 &partner_link_info.link_addr); 1221 if (tmp_vdev) { 1222 mlo_update_connect_req_links(tmp_vdev, 1); 1223 wlan_vdev_mlme_set_mlo_vdev(tmp_vdev); 1224 wlan_vdev_mlme_feat_ext2_cap_set( 1225 tmp_vdev, 1226 WLAN_VDEV_FEXT2_MLO_STA_LINK); 1227 wlan_vdev_set_link_id( 1228 tmp_vdev, 1229 partner_link_info.link_id); 1230 } 1231 } 1232 } 1233 } 1234 #endif 1235 1236 void mlo_sta_link_disconn_notify(struct wlan_objmgr_vdev *vdev, 1237 struct wlan_cm_discon_rsp *resp) 1238 { 1239 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 1240 struct wlan_mlo_sta *sta_ctx = NULL; 1241 struct wlan_objmgr_vdev *assoc_vdev = NULL; 1242 1243 if (!mlo_dev_ctx || !(wlan_vdev_mlme_is_mlo_vdev(vdev))) 1244 return; 1245 1246 sta_ctx = mlo_dev_ctx->sta_ctx; 1247 if (!sta_ctx) 1248 return; 1249 1250 if (!wlan_cm_is_vdev_disconnected(vdev)) 1251 return; 1252 1253 mlo_update_connected_links(vdev, 0); 1254 if (mlo_is_mld_disconnected(vdev)) { 1255 if (sta_ctx->connect_req) { 1256 assoc_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx); 1257 if (!assoc_vdev) 1258 return; 1259 mlo_sta_link_handle_pending_connect(assoc_vdev); 1260 } 1261 } 1262 1263 mlo_handle_disconnect_resp(mlo_dev_ctx, resp); 1264 } 1265 1266 bool mlo_is_mld_sta(struct wlan_objmgr_vdev *vdev) 1267 { 1268 if ((wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE) && 1269 wlan_vdev_mlme_is_mlo_vdev(vdev)) 1270 return true; 1271 1272 return false; 1273 } 1274 1275 #ifndef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 1276 struct wlan_objmgr_vdev * 1277 mlo_get_ml_vdev_by_mac(struct wlan_objmgr_vdev *vdev, 1278 struct qdf_mac_addr *macaddr) 1279 { 1280 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 1281 uint8_t i = 0; 1282 1283 if (!mlo_dev_ctx) 1284 return NULL; 1285 1286 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 1287 if (!mlo_dev_ctx->wlan_vdev_list[i]) 1288 continue; 1289 1290 if(qdf_mem_cmp(macaddr, 1291 wlan_vdev_mlme_get_macaddr(mlo_dev_ctx->wlan_vdev_list[i]), 1292 QDF_MAC_ADDR_SIZE) == 0) { 1293 return mlo_dev_ctx->wlan_vdev_list[i]; 1294 } 1295 } 1296 return NULL; 1297 } 1298 #endif 1299 1300 qdf_freq_t 1301 mlo_get_chan_freq_by_bssid(struct wlan_objmgr_pdev *pdev, 1302 struct qdf_mac_addr *bssid) 1303 { 1304 struct scan_filter *scan_filter; 1305 int8_t ch_freq = 0; 1306 qdf_list_t *list = NULL; 1307 struct scan_cache_node *first_node = NULL; 1308 qdf_list_node_t *cur_node = NULL; 1309 1310 scan_filter = qdf_mem_malloc(sizeof(*scan_filter)); 1311 if (!scan_filter) 1312 return ch_freq; 1313 1314 scan_filter->num_of_bssid = 1; 1315 qdf_mem_copy(scan_filter->bssid_list[0].bytes, 1316 bssid, sizeof(struct qdf_mac_addr)); 1317 list = wlan_scan_get_result(pdev, scan_filter); 1318 qdf_mem_free(scan_filter); 1319 1320 if (!list || (list && !qdf_list_size(list))) { 1321 mlo_debug("scan list empty"); 1322 goto error; 1323 } 1324 1325 qdf_list_peek_front(list, &cur_node); 1326 first_node = qdf_container_of(cur_node, 1327 struct scan_cache_node, 1328 node); 1329 if (first_node && first_node->entry) 1330 ch_freq = first_node->entry->channel.chan_freq; 1331 error: 1332 if (list) 1333 wlan_scan_purge_results(list); 1334 1335 return ch_freq; 1336 } 1337 1338 void mlo_get_assoc_rsp(struct wlan_objmgr_vdev *vdev, 1339 struct element_info *assoc_rsp_frame) 1340 { 1341 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 1342 struct wlan_mlo_sta *sta_ctx = NULL; 1343 1344 if (!mlo_dev_ctx || !mlo_dev_ctx->sta_ctx) 1345 return; 1346 1347 sta_ctx = mlo_dev_ctx->sta_ctx; 1348 1349 if (!sta_ctx->assoc_rsp.len || !sta_ctx->assoc_rsp.ptr) { 1350 mlo_err("Assoc Resp info is empty"); 1351 return; 1352 } 1353 1354 *assoc_rsp_frame = sta_ctx->assoc_rsp; 1355 } 1356 1357 QDF_STATUS mlo_sta_save_quiet_status(struct wlan_mlo_dev_context *mlo_dev_ctx, 1358 uint8_t link_id, 1359 bool quiet_status) 1360 { 1361 struct wlan_mlo_sta *sta_ctx; 1362 int i; 1363 bool find_free_buffer = false; 1364 int free_idx; 1365 1366 if (!mlo_dev_ctx) { 1367 mlo_err("invalid mlo_dev_ctx"); 1368 return QDF_STATUS_E_INVAL; 1369 } 1370 1371 mlo_dev_lock_acquire(mlo_dev_ctx); 1372 sta_ctx = mlo_dev_ctx->sta_ctx; 1373 if (!sta_ctx) { 1374 mlo_err("invalid sta_ctx"); 1375 mlo_dev_lock_release(mlo_dev_ctx); 1376 return QDF_STATUS_E_INVAL; 1377 } 1378 for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_quiet_status); i++) { 1379 if (!sta_ctx->mlo_quiet_status[i].valid_status) { 1380 if (!find_free_buffer) { 1381 free_idx = i; 1382 find_free_buffer = true; 1383 } 1384 } else if (link_id == sta_ctx->mlo_quiet_status[i].link_id) { 1385 sta_ctx->mlo_quiet_status[i].quiet_status = 1386 quiet_status; 1387 mlo_debug("mld mac " QDF_MAC_ADDR_FMT " link id %d quiet status update %d", 1388 QDF_MAC_ADDR_REF(mlo_dev_ctx->mld_addr.bytes), 1389 link_id, quiet_status); 1390 mlo_dev_lock_release(mlo_dev_ctx); 1391 return QDF_STATUS_SUCCESS; 1392 } 1393 } 1394 if (!find_free_buffer) { 1395 mlo_err("no free buffer for link id %d to save quiet_status", 1396 link_id); 1397 mlo_dev_lock_release(mlo_dev_ctx); 1398 return QDF_STATUS_E_INVAL; 1399 } 1400 sta_ctx->mlo_quiet_status[free_idx].quiet_status = quiet_status; 1401 sta_ctx->mlo_quiet_status[free_idx].link_id = link_id; 1402 sta_ctx->mlo_quiet_status[free_idx].valid_status = true; 1403 1404 mlo_debug("mld mac " QDF_MAC_ADDR_FMT " link id %d in quiet status %d", 1405 QDF_MAC_ADDR_REF(mlo_dev_ctx->mld_addr.bytes), 1406 link_id, quiet_status); 1407 mlo_dev_lock_release(mlo_dev_ctx); 1408 1409 return QDF_STATUS_SUCCESS; 1410 } 1411 1412 bool mlo_is_sta_in_quiet_status(struct wlan_mlo_dev_context *mlo_dev_ctx, 1413 uint8_t link_id) 1414 { 1415 struct wlan_mlo_sta *sta_ctx; 1416 int i; 1417 bool quiet_status = false; 1418 1419 if (!mlo_dev_ctx) { 1420 mlo_err("invalid mlo_dev_ctx"); 1421 return quiet_status; 1422 } 1423 1424 mlo_dev_lock_acquire(mlo_dev_ctx); 1425 sta_ctx = mlo_dev_ctx->sta_ctx; 1426 if (!sta_ctx) { 1427 mlo_err("invalid sta_ctx"); 1428 mlo_dev_lock_release(mlo_dev_ctx); 1429 return quiet_status; 1430 } 1431 for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_quiet_status); i++) { 1432 if (sta_ctx->mlo_quiet_status[i].valid_status && 1433 link_id == sta_ctx->mlo_quiet_status[i].link_id) { 1434 quiet_status = 1435 sta_ctx->mlo_quiet_status[i].quiet_status; 1436 break; 1437 } 1438 } 1439 mlo_dev_lock_release(mlo_dev_ctx); 1440 1441 return quiet_status; 1442 } 1443 1444 bool mlo_is_sta_inactivity_allowed_with_quiet(struct wlan_objmgr_psoc *psoc, 1445 uint8_t *vdev_id_list, 1446 uint8_t num_mlo, uint8_t *mlo_idx, 1447 uint8_t affected_links, 1448 uint8_t *affected_list) 1449 { 1450 uint8_t i, j; 1451 struct wlan_objmgr_vdev *vdev; 1452 bool allowed = false; 1453 1454 for (i = 0; i < num_mlo; i++) { 1455 for (j = 0; j < affected_links; j++) { 1456 if (vdev_id_list[mlo_idx[i]] == affected_list[j]) 1457 break; 1458 } 1459 if (j != affected_links) 1460 continue; 1461 /* find vdev not in affected_list */ 1462 vdev = wlan_objmgr_get_vdev_by_id_from_psoc( 1463 psoc, vdev_id_list[mlo_idx[i]], 1464 WLAN_IF_MGR_ID); 1465 if (!vdev) { 1466 mlo_err("invalid vdev for id %d", 1467 vdev_id_list[mlo_idx[i]]); 1468 continue; 1469 } 1470 1471 /* for not affected vdev, check the vdev is in quiet or not*/ 1472 allowed = !mlo_is_sta_in_quiet_status( 1473 vdev->mlo_dev_ctx, wlan_vdev_get_link_id(vdev)); 1474 wlan_objmgr_vdev_release_ref(vdev, WLAN_IF_MGR_ID); 1475 if (allowed) { 1476 mlo_debug("vdev id %d link id %d is not in quiet, allow partner link to trigger inactivity", 1477 wlan_vdev_get_id(vdev), 1478 wlan_vdev_get_link_id(vdev)); 1479 break; 1480 } 1481 } 1482 1483 return allowed; 1484 } 1485 1486 bool mlo_is_sta_csa_synced(struct wlan_mlo_dev_context *mlo_dev_ctx, 1487 uint8_t link_id) 1488 { 1489 struct wlan_mlo_sta *sta_ctx; 1490 int i; 1491 bool sta_csa_synced = false; 1492 1493 if (!mlo_dev_ctx) { 1494 mlo_err("invalid mlo_dev_ctx"); 1495 return sta_csa_synced; 1496 } 1497 1498 mlo_dev_lock_acquire(mlo_dev_ctx); 1499 sta_ctx = mlo_dev_ctx->sta_ctx; 1500 if (!sta_ctx) { 1501 mlo_err("invalid sta_ctx"); 1502 mlo_dev_lock_release(mlo_dev_ctx); 1503 return sta_csa_synced; 1504 } 1505 for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_csa_param); i++) { 1506 if (link_id == sta_ctx->mlo_csa_param[i].link_id && 1507 (sta_ctx->mlo_csa_param[i].valid_csa_param || 1508 sta_ctx->mlo_csa_param[i].mlo_csa_synced)) { 1509 mlo_dev_lock_release(mlo_dev_ctx); 1510 sta_csa_synced = 1511 sta_ctx->mlo_csa_param[i].mlo_csa_synced; 1512 break; 1513 } 1514 } 1515 mlo_dev_lock_release(mlo_dev_ctx); 1516 1517 return sta_csa_synced; 1518 } 1519 1520 QDF_STATUS mlo_sta_csa_save_params(struct wlan_mlo_dev_context *mlo_dev_ctx, 1521 uint8_t link_id, 1522 struct csa_offload_params *csa_param) 1523 { 1524 struct wlan_mlo_sta *sta_ctx; 1525 int i; 1526 bool find_free_buffer = false; 1527 int free_idx; 1528 QDF_STATUS status = QDF_STATUS_SUCCESS; 1529 1530 if (!mlo_dev_ctx) { 1531 mlo_err("invalid mlo_dev_ctx"); 1532 status = QDF_STATUS_E_INVAL; 1533 goto done; 1534 } 1535 1536 mlo_dev_lock_acquire(mlo_dev_ctx); 1537 sta_ctx = mlo_dev_ctx->sta_ctx; 1538 if (!sta_ctx) { 1539 mlo_err("invalid sta_ctx"); 1540 status = QDF_STATUS_E_INVAL; 1541 goto rel_lock; 1542 } 1543 for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_csa_param); i++) { 1544 if (!sta_ctx->mlo_csa_param[i].valid_csa_param && 1545 !sta_ctx->mlo_csa_param[i].mlo_csa_synced) { 1546 if (!find_free_buffer) { 1547 free_idx = i; 1548 find_free_buffer = true; 1549 } 1550 } else if (link_id == sta_ctx->mlo_csa_param[i].link_id) { 1551 qdf_mem_copy(&sta_ctx->mlo_csa_param[i].csa_param, 1552 csa_param, sizeof(*csa_param)); 1553 mlo_debug("mld mac " QDF_MAC_ADDR_FMT " link id %d update csa", 1554 QDF_MAC_ADDR_REF(mlo_dev_ctx->mld_addr.bytes), 1555 link_id); 1556 goto rel_lock; 1557 } 1558 } 1559 if (!find_free_buffer) { 1560 mlo_err("no free buffer of csa param for link %d in sta_ctx", 1561 link_id); 1562 status = QDF_STATUS_E_INVAL; 1563 goto rel_lock; 1564 } 1565 qdf_mem_copy(&sta_ctx->mlo_csa_param[free_idx].csa_param, 1566 csa_param, sizeof(*csa_param)); 1567 sta_ctx->mlo_csa_param[free_idx].link_id = link_id; 1568 sta_ctx->mlo_csa_param[free_idx].valid_csa_param = true; 1569 mlo_debug("mld mac " QDF_MAC_ADDR_FMT " link id %d RX csa", 1570 QDF_MAC_ADDR_REF(mlo_dev_ctx->mld_addr.bytes), 1571 link_id); 1572 1573 rel_lock: 1574 mlo_dev_lock_release(mlo_dev_ctx); 1575 1576 done: 1577 1578 return status; 1579 } 1580 1581 QDF_STATUS mlo_sta_up_active_notify(struct wlan_objmgr_vdev *vdev) 1582 { 1583 struct wlan_mlo_sta *sta_ctx; 1584 struct wlan_mlo_dev_context *mlo_dev_ctx; 1585 uint8_t link_id; 1586 int i; 1587 bool find_free_buffer = false; 1588 int free_idx; 1589 struct csa_offload_params csa_param; 1590 struct wlan_channel *chan; 1591 QDF_STATUS status = QDF_STATUS_SUCCESS; 1592 1593 if (!vdev) { 1594 mlo_err("invalid vdev"); 1595 status = QDF_STATUS_E_INVAL; 1596 goto done; 1597 } 1598 link_id = wlan_vdev_get_link_id(vdev); 1599 mlo_dev_ctx = vdev->mlo_dev_ctx; 1600 if (!mlo_dev_ctx) { 1601 mlo_err("invalid mlo_dev_ctx"); 1602 status = QDF_STATUS_E_INVAL; 1603 goto done; 1604 } 1605 mlo_dev_lock_acquire(mlo_dev_ctx); 1606 sta_ctx = mlo_dev_ctx->sta_ctx; 1607 if (!sta_ctx) { 1608 mlo_err("invalid sta_ctx"); 1609 status = QDF_STATUS_E_INVAL; 1610 goto rel_lock; 1611 } 1612 1613 for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_csa_param); i++) { 1614 if (!sta_ctx->mlo_csa_param[i].valid_csa_param && 1615 !sta_ctx->mlo_csa_param[i].mlo_csa_synced) { 1616 if (!find_free_buffer) { 1617 free_idx = i; 1618 find_free_buffer = true; 1619 } 1620 } else if (link_id == sta_ctx->mlo_csa_param[i].link_id) { 1621 if (sta_ctx->mlo_csa_param[i].valid_csa_param && 1622 !sta_ctx->mlo_csa_param[i].mlo_csa_synced) { 1623 mlo_debug("mld mac " QDF_MAC_ADDR_FMT " vdev id %d link id %d handle csa", 1624 QDF_MAC_ADDR_REF( 1625 mlo_dev_ctx->mld_addr.bytes), 1626 wlan_vdev_get_id(vdev), link_id); 1627 csa_param = sta_ctx->mlo_csa_param[i].csa_param; 1628 sta_ctx->mlo_csa_param[i].mlo_csa_synced = true; 1629 mlo_dev_lock_release(mlo_dev_ctx); 1630 chan = wlan_vdev_mlme_get_bss_chan(vdev); 1631 if (csa_param.csa_chan_freq && chan && 1632 csa_param.csa_chan_freq != chan->ch_freq) 1633 mlo_mlme_handle_sta_csa_param( 1634 vdev, &csa_param); 1635 goto done; 1636 } 1637 sta_ctx->mlo_csa_param[i].mlo_csa_synced = true; 1638 goto rel_lock; 1639 } 1640 } 1641 if (!find_free_buffer) { 1642 mlo_err("no free buffer of csa param for link %d in sta_ctx", 1643 link_id); 1644 goto rel_lock; 1645 } 1646 sta_ctx->mlo_csa_param[free_idx].mlo_csa_synced = true; 1647 sta_ctx->mlo_csa_param[free_idx].link_id = link_id; 1648 mlo_debug("mld mac " QDF_MAC_ADDR_FMT " link id %d UP Active", 1649 QDF_MAC_ADDR_REF(mlo_dev_ctx->mld_addr.bytes), 1650 link_id); 1651 1652 rel_lock: 1653 mlo_dev_lock_release(mlo_dev_ctx); 1654 1655 done: 1656 1657 return status; 1658 } 1659 1660 bool mlo_is_sta_csa_param_handled(struct wlan_objmgr_vdev *vdev, 1661 struct csa_offload_params *csa_param) 1662 { 1663 struct wlan_mlo_sta *sta_ctx; 1664 struct wlan_mlo_dev_context *mlo_dev_ctx; 1665 uint8_t link_id; 1666 int i; 1667 bool handled = false; 1668 1669 if (!vdev) { 1670 mlo_err("invalid vdev"); 1671 goto done; 1672 } 1673 link_id = wlan_vdev_get_link_id(vdev); 1674 mlo_dev_ctx = vdev->mlo_dev_ctx; 1675 if (!mlo_dev_ctx) { 1676 mlo_err("invalid mlo_dev_ctx"); 1677 goto done; 1678 } 1679 mlo_dev_lock_acquire(mlo_dev_ctx); 1680 sta_ctx = mlo_dev_ctx->sta_ctx; 1681 if (!sta_ctx) { 1682 mlo_err("invalid sta_ctx"); 1683 goto rel_lock; 1684 } 1685 1686 for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_csa_param); i++) { 1687 if (link_id == sta_ctx->mlo_csa_param[i].link_id && 1688 (sta_ctx->mlo_csa_param[i].valid_csa_param || 1689 sta_ctx->mlo_csa_param[i].mlo_csa_synced)) 1690 break; 1691 } 1692 1693 if (i >= QDF_ARRAY_SIZE(sta_ctx->mlo_csa_param)) { 1694 mlo_debug("mlo csa synced does not happen before csa FW event"); 1695 goto rel_lock; 1696 } 1697 if (!sta_ctx->mlo_csa_param[i].csa_offload_event_recvd) { 1698 sta_ctx->mlo_csa_param[i].csa_offload_event_recvd = true; 1699 if (sta_ctx->mlo_csa_param[i].valid_csa_param && 1700 !qdf_mem_cmp(&sta_ctx->mlo_csa_param[i].csa_param, 1701 csa_param, sizeof(*csa_param))) 1702 handled = true; 1703 } 1704 1705 rel_lock: 1706 mlo_dev_lock_release(mlo_dev_ctx); 1707 1708 done: 1709 1710 return handled; 1711 } 1712 1713 void mlo_internal_disconnect_links(struct wlan_objmgr_vdev *vdev) 1714 { 1715 struct wlan_mlo_dev_context *mlo_dev_ctx = NULL; 1716 struct wlan_mlo_sta *sta_ctx = NULL; 1717 uint8_t i; 1718 1719 if (!vdev) 1720 return; 1721 1722 if (!wlan_vdev_mlme_is_assoc_sta_vdev(vdev)) { 1723 mlo_debug("Not an assoc vdev, so ignore disconnect req"); 1724 return; 1725 } 1726 1727 mlo_dev_ctx = vdev->mlo_dev_ctx; 1728 if (mlo_dev_ctx) { 1729 sta_ctx = mlo_dev_ctx->sta_ctx; 1730 } else { 1731 mlo_err("Invalid mlo_dev_ctx"); 1732 return; 1733 } 1734 1735 if (sta_ctx) { 1736 copied_conn_req_lock_acquire(sta_ctx); 1737 if (sta_ctx->copied_conn_req) { 1738 mlo_free_connect_ies(sta_ctx->copied_conn_req); 1739 qdf_mem_free(sta_ctx->copied_conn_req); 1740 sta_ctx->copied_conn_req = NULL; 1741 } 1742 copied_conn_req_lock_release(sta_ctx); 1743 } else { 1744 mlo_err("Invalid sta_ctx"); 1745 return; 1746 } 1747 1748 mlo_dev_lock_acquire(mlo_dev_ctx); 1749 if (sta_ctx->connect_req) { 1750 mlo_free_connect_ies(sta_ctx->connect_req); 1751 qdf_mem_free(sta_ctx->connect_req); 1752 sta_ctx->connect_req = NULL; 1753 } 1754 1755 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 1756 if (!mlo_dev_ctx->wlan_vdev_list[i]) 1757 continue; 1758 1759 if (qdf_test_bit(i, 1760 mlo_dev_ctx->sta_ctx->wlan_connected_links) && 1761 mlo_dev_ctx->wlan_vdev_list[i] != 1762 mlo_get_assoc_link_vdev(mlo_dev_ctx)) 1763 wlan_cm_disconnect(mlo_dev_ctx->wlan_vdev_list[i], 1764 CM_INTERNAL_DISCONNECT, 1765 REASON_UNSPEC_FAILURE, 1766 NULL); 1767 } 1768 1769 mlo_dev_lock_release(mlo_dev_ctx); 1770 } 1771 1772 void mlo_sta_get_vdev_list(struct wlan_objmgr_vdev *vdev, uint16_t *vdev_count, 1773 struct wlan_objmgr_vdev **wlan_vdev_list) 1774 { 1775 struct wlan_mlo_dev_context *dev_ctx; 1776 int i; 1777 QDF_STATUS status; 1778 1779 *vdev_count = 0; 1780 1781 if (!vdev || !vdev->mlo_dev_ctx) { 1782 mlo_err("Invalid input"); 1783 return; 1784 } 1785 1786 dev_ctx = vdev->mlo_dev_ctx; 1787 1788 mlo_dev_lock_acquire(dev_ctx); 1789 *vdev_count = 0; 1790 for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) { 1791 if (dev_ctx->wlan_vdev_list[i]) { 1792 status = 1793 wlan_objmgr_vdev_try_get_ref(dev_ctx->wlan_vdev_list[i], 1794 WLAN_MLO_MGR_ID); 1795 if (QDF_IS_STATUS_ERROR(status)) 1796 break; 1797 wlan_vdev_list[*vdev_count] = 1798 dev_ctx->wlan_vdev_list[i]; 1799 (*vdev_count) += 1; 1800 } 1801 } 1802 mlo_dev_lock_release(dev_ctx); 1803 } 1804 1805 #endif 1806