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