1 /* 2 * Copyright (c) 2021, The Linux Foundation. All rights reserved. 3 * Copyright (c) 2021-2024 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 #include <wlan_crypto_global_api.h> 31 #include <utils_mlo.h> 32 #include <wlan_mlme_cmn.h> 33 #include <wlan_scan_utils_api.h> 34 #include <qdf_time.h> 35 #include <wlan_objmgr_peer_obj.h> 36 #include <wlan_scan_api.h> 37 #include <wlan_mlo_mgr_peer.h> 38 #include <qdf_module.h> 39 #include <wlan_mlo_mgr_public_api.h> 40 41 #ifdef WLAN_FEATURE_11BE_MLO 42 static QDF_STATUS mlo_disconnect_req(struct wlan_objmgr_vdev *vdev, 43 enum wlan_cm_source source, 44 enum wlan_reason_code reason_code, 45 struct qdf_mac_addr *bssid, 46 bool validate_req); 47 48 void 49 mlo_allocate_and_copy_ies(struct wlan_cm_connect_req *target, 50 struct wlan_cm_connect_req *source) 51 { 52 target->assoc_ie.ptr = NULL; 53 target->scan_ie.ptr = NULL; 54 target->crypto.wep_keys.key = NULL; 55 target->crypto.wep_keys.seq = NULL; 56 target->crypto.wep_keys.key_len = 0; 57 target->crypto.wep_keys.seq_len = 0; 58 59 if (source->scan_ie.ptr) { 60 target->scan_ie.ptr = qdf_mem_malloc(source->scan_ie.len); 61 if (!target->scan_ie.ptr) 62 target->scan_ie.len = 0; 63 else 64 qdf_mem_copy(target->scan_ie.ptr, 65 source->scan_ie.ptr, source->scan_ie.len); 66 } 67 68 if (source->assoc_ie.ptr) { 69 target->assoc_ie.ptr = qdf_mem_malloc(source->assoc_ie.len); 70 if (!target->assoc_ie.ptr) 71 target->assoc_ie.len = 0; 72 else 73 qdf_mem_copy(target->assoc_ie.ptr, source->assoc_ie.ptr, 74 source->assoc_ie.len); 75 } 76 } 77 78 /* 79 * mlo_get_tdls_link_vdev() - API to get tdls link vdev 80 * @mlo_dev_ctx: pointer to mlo dev context 81 * 82 * Return: MLD tdls link vdev 83 */ 84 static inline struct wlan_objmgr_vdev * 85 mlo_get_tdls_link_vdev(struct wlan_mlo_dev_context *mlo_dev_ctx) 86 { 87 uint8_t i = 0; 88 89 if (!mlo_dev_ctx) 90 return NULL; 91 92 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 93 if (!mlo_dev_ctx->wlan_vdev_list[i]) 94 continue; 95 96 if (wlan_vdev_mlme_is_tdls_vdev(mlo_dev_ctx->wlan_vdev_list[i])) 97 return mlo_dev_ctx->wlan_vdev_list[i]; 98 } 99 return NULL; 100 } 101 102 struct wlan_objmgr_vdev * 103 wlan_mlo_get_tdls_link_vdev(struct wlan_objmgr_vdev *vdev) 104 { 105 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 106 107 if (!mlo_dev_ctx || !wlan_vdev_mlme_is_mlo_vdev(vdev)) 108 return NULL; 109 110 return mlo_get_tdls_link_vdev(mlo_dev_ctx); 111 } 112 113 /* 114 * mlo_get_assoc_link_vdev - API to get assoc link vdev 115 * 116 * @mlo_dev_ctx: pointer to mlo dev context 117 * 118 * Return: MLD assoc link vdev 119 */ 120 static inline struct wlan_objmgr_vdev * 121 mlo_get_assoc_link_vdev(struct wlan_mlo_dev_context *mlo_dev_ctx) 122 { 123 uint8_t i = 0; 124 125 if (!mlo_dev_ctx) 126 return NULL; 127 128 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 129 if (!mlo_dev_ctx->wlan_vdev_list[i]) 130 continue; 131 132 if (wlan_vdev_mlme_is_mlo_vdev(mlo_dev_ctx->wlan_vdev_list[i]) && 133 !wlan_vdev_mlme_is_mlo_link_vdev(mlo_dev_ctx->wlan_vdev_list[i])) 134 return mlo_dev_ctx->wlan_vdev_list[i]; 135 } 136 return NULL; 137 } 138 139 struct wlan_objmgr_vdev * 140 wlan_mlo_get_assoc_link_vdev(struct wlan_objmgr_vdev *vdev) 141 { 142 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 143 144 if (!mlo_dev_ctx || !wlan_vdev_mlme_is_mlo_vdev(vdev)) 145 return NULL; 146 147 return mlo_get_assoc_link_vdev(mlo_dev_ctx); 148 } 149 150 struct wlan_objmgr_vdev * 151 ucfg_mlo_get_assoc_link_vdev(struct wlan_objmgr_vdev *vdev) 152 { 153 return wlan_mlo_get_assoc_link_vdev(vdev); 154 } 155 156 /** 157 * mlo_is_mld_disconnected - Check whether MLD is disconnected 158 * 159 * @vdev: pointer to vdev 160 * 161 * Return: true if mld is disconnected, false otherwise 162 */ 163 static inline 164 bool mlo_is_mld_disconnected(struct wlan_objmgr_vdev *vdev) 165 { 166 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 167 uint8_t i = 0; 168 169 if (!mlo_dev_ctx || !wlan_vdev_mlme_is_mlo_vdev(vdev)) 170 return true; 171 172 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 173 if (!mlo_dev_ctx->wlan_vdev_list[i]) 174 continue; 175 176 if (!wlan_cm_is_vdev_disconnected(mlo_dev_ctx->wlan_vdev_list[i])) 177 return false; 178 } 179 return true; 180 } 181 182 bool mlo_is_mld_disconnecting_connecting(struct wlan_objmgr_vdev *vdev) 183 { 184 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 185 uint8_t i = 0; 186 187 if (!mlo_dev_ctx || !wlan_vdev_mlme_is_mlo_vdev(vdev)) 188 return false; 189 190 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 191 if (!mlo_dev_ctx->wlan_vdev_list[i]) 192 continue; 193 if (wlan_cm_is_vdev_disconnecting(mlo_dev_ctx->wlan_vdev_list[i]) || 194 wlan_cm_is_vdev_connecting(mlo_dev_ctx->wlan_vdev_list[i])) 195 return true; 196 } 197 return false; 198 } 199 200 bool mlo_is_ml_connection_in_progress(struct wlan_objmgr_psoc *psoc, 201 uint8_t vdev_id) 202 { 203 struct wlan_objmgr_vdev *vdev; 204 struct wlan_mlo_dev_context *mlo_dev_ctx; 205 uint8_t i = 0; 206 bool val = false; 207 208 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, 209 WLAN_MLO_MGR_ID); 210 211 if (!vdev) { 212 mlo_err("Invalid vdev"); 213 return false; 214 } 215 216 mlo_dev_ctx = vdev->mlo_dev_ctx; 217 if (!mlo_dev_ctx || !wlan_vdev_mlme_is_mlo_vdev(vdev)) 218 goto end; 219 220 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 221 if (!mlo_dev_ctx->wlan_vdev_list[i]) 222 continue; 223 if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links)) { 224 if (!wlan_cm_is_vdev_connected(mlo_dev_ctx->wlan_vdev_list[i])) { 225 val = true; 226 goto end; 227 } 228 } 229 } 230 231 end: 232 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 233 return val; 234 } 235 236 bool ucfg_mlo_is_mld_disconnected(struct wlan_objmgr_vdev *vdev) 237 { 238 return mlo_is_mld_disconnected(vdev); 239 } 240 241 /** 242 * mlo_send_link_disconnect- Issue the disconnect request on MLD links 243 * 244 * @vdev: pointer to vdev 245 * @source: disconnect source 246 * @reason_code: disconnect reason 247 * @bssid: bssid of AP to disconnect, can be null if not known 248 * 249 * Return: QDF_STATUS 250 */ 251 static QDF_STATUS 252 mlo_send_link_disconnect(struct wlan_objmgr_vdev *vdev, 253 enum wlan_cm_source source, 254 enum wlan_reason_code reason_code, 255 struct qdf_mac_addr *bssid) 256 { 257 uint8_t i = 0; 258 enum wlan_cm_source link_source = source; 259 struct wlan_objmgr_vdev *assoc_vdev = 260 mlo_get_assoc_link_vdev(vdev->mlo_dev_ctx); 261 struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS]; 262 uint16_t vdev_count = 0; 263 struct wlan_mlo_sta *sta_ctx = NULL; 264 265 sta_ctx = vdev->mlo_dev_ctx->sta_ctx; 266 if (!sta_ctx) { 267 mlo_err("Invalid sta_ctx"); 268 return QDF_STATUS_E_FAILURE; 269 } 270 271 if (!assoc_vdev && mlo_mgr_is_link_switch_supported(vdev)) { 272 if (!wlan_mlo_mgr_is_link_switch_on_assoc_vdev(vdev)) 273 return QDF_STATUS_E_FAILURE; 274 275 assoc_vdev = wlan_mlo_mgr_link_switch_get_assoc_vdev(vdev); 276 mlo_release_vdev_ref(assoc_vdev); 277 } 278 279 /* 280 * Change the source for the link vdev to make sure it's handled as a 281 * Northbound disconnect in VDEV/PEER state machine. 282 */ 283 if (source != CM_OSIF_DISCONNECT) 284 link_source = CM_MLO_LINK_VDEV_DISCONNECT; 285 286 mlo_sta_get_vdev_list(vdev, &vdev_count, wlan_vdev_list); 287 for (i = 0; i < vdev_count; i++) { 288 if ((wlan_vdev_list[i] != assoc_vdev) && 289 (qdf_test_bit(i, sta_ctx->wlan_connected_links) || 290 (wlan_cm_is_vdev_connected(wlan_vdev_list[i]) && 291 !wlan_peer_is_mlo(wlan_vdev_get_bsspeer(wlan_vdev_list[i]))) || 292 wlan_cm_is_vdev_idle_due_to_link_switch(wlan_vdev_list[i]))) 293 wlan_cm_disconnect(wlan_vdev_list[i], 294 link_source, reason_code, 295 NULL); 296 mlo_release_vdev_ref(wlan_vdev_list[i]); 297 } 298 299 if (assoc_vdev) 300 wlan_cm_disconnect(assoc_vdev, source, reason_code, NULL); 301 302 return QDF_STATUS_SUCCESS; 303 } 304 305 static void mlo_free_copied_conn_req(struct wlan_mlo_sta *sta_ctx) 306 { 307 if (sta_ctx) { 308 mlo_debug("enter"); 309 copied_conn_req_lock_acquire(sta_ctx); 310 if (sta_ctx->copied_conn_req) { 311 wlan_cm_free_connect_req(sta_ctx->copied_conn_req); 312 sta_ctx->copied_conn_req = NULL; 313 } 314 copied_conn_req_lock_release(sta_ctx); 315 } 316 } 317 318 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 319 int mlo_mgr_get_per_link_chan_info(struct wlan_objmgr_vdev *vdev, int link_id, 320 struct wlan_channel *chan_info) 321 { 322 struct mlo_link_info *ml_link_info; 323 324 ml_link_info = mlo_mgr_get_ap_link_by_link_id(vdev->mlo_dev_ctx, 325 link_id); 326 if (!ml_link_info) { 327 mlo_debug("ml_link_info null for link_id: %d", link_id); 328 return -EINVAL; 329 } 330 331 qdf_mem_copy(chan_info, ml_link_info->link_chan_info, 332 sizeof(*chan_info)); 333 334 return 0; 335 } 336 337 static QDF_STATUS 338 mlo_validate_connect_req(struct wlan_objmgr_vdev *vdev, 339 struct wlan_mlo_dev_context *mlo_dev_ctx, 340 struct wlan_cm_connect_req *req) 341 { 342 /* check back to back connect handling */ 343 return QDF_STATUS_SUCCESS; 344 } 345 346 static QDF_STATUS 347 mlo_validate_disconn_req(struct wlan_objmgr_vdev *vdev, 348 enum wlan_cm_source source, 349 enum wlan_reason_code reason_code, 350 struct qdf_mac_addr *bssid) 351 { 352 return QDF_STATUS_SUCCESS; 353 } 354 355 static QDF_STATUS mlo_validate_mlo_cap(struct wlan_objmgr_vdev *vdev) 356 { 357 return QDF_STATUS_SUCCESS; 358 } 359 360 static inline 361 void mlo_mld_clear_mlo_cap(struct wlan_objmgr_vdev *vdev) 362 { } 363 #else 364 /** 365 * mlo_is_mld_connected - Check whether MLD is connected 366 * 367 * @vdev: pointer to vdev 368 * 369 * Return: true if mld is connected, false otherwise 370 */ 371 static inline 372 bool mlo_is_mld_connected(struct wlan_objmgr_vdev *vdev) 373 { 374 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 375 uint8_t i = 0; 376 377 if (!mlo_dev_ctx || !wlan_vdev_mlme_is_mlo_vdev(vdev)) 378 return true; 379 380 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 381 if (!mlo_dev_ctx->wlan_vdev_list[i]) 382 continue; 383 384 if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links)) { 385 if (!wlan_cm_is_vdev_connected(mlo_dev_ctx->wlan_vdev_list[i])) 386 return false; 387 } 388 } 389 return true; 390 } 391 392 bool ucfg_mlo_is_mld_connected(struct wlan_objmgr_vdev *vdev) 393 { 394 return mlo_is_mld_connected(vdev); 395 } 396 397 static inline 398 void mlo_mld_clear_mlo_cap(struct wlan_objmgr_vdev *vdev) 399 { 400 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 401 uint8_t i = 0; 402 403 if (!mlo_dev_ctx || !wlan_vdev_mlme_is_mlo_vdev(vdev)) 404 return; 405 406 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 407 if (!mlo_dev_ctx->wlan_vdev_list[i]) 408 continue; 409 wlan_vdev_mlme_clear_mlo_vdev(mlo_dev_ctx->wlan_vdev_list[i]); 410 wlan_vdev_mlme_clear_mlo_link_vdev(mlo_dev_ctx->wlan_vdev_list[i]); 411 } 412 mlo_clear_bridge_sta_ctx(vdev); 413 } 414 415 void ucfg_mlo_mld_clear_mlo_cap(struct wlan_objmgr_vdev *vdev) 416 { 417 mlo_mld_clear_mlo_cap(vdev); 418 } 419 420 static void 421 mlo_cm_handle_connect_in_disconnection_state(struct wlan_objmgr_vdev *vdev, 422 struct wlan_cm_connect_req *req) 423 { 424 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 425 struct wlan_mlo_sta *sta_ctx; 426 427 if (!mlo_dev_ctx) { 428 mlo_err("ML dev ctx is NULL"); 429 return; 430 } 431 432 sta_ctx = mlo_dev_ctx->sta_ctx; 433 if (!sta_ctx->connect_req) 434 sta_ctx->connect_req = qdf_mem_malloc( 435 sizeof(struct wlan_cm_connect_req)); 436 437 if (sta_ctx->connect_req) { 438 qdf_mem_copy(sta_ctx->connect_req, req, 439 sizeof(struct wlan_cm_connect_req)); 440 mlo_allocate_and_copy_ies(sta_ctx->connect_req, req); 441 } else { 442 mlo_err("Failed to allocate connect req"); 443 } 444 } 445 446 static QDF_STATUS 447 mlo_validate_disconn_req(struct wlan_objmgr_vdev *vdev, 448 enum wlan_cm_source source, 449 enum wlan_reason_code reason_code, 450 struct qdf_mac_addr *bssid) 451 { 452 struct wlan_mlo_dev_context *mlo_dev = vdev->mlo_dev_ctx; 453 struct wlan_mlo_sta *sta_ctx = mlo_dev->sta_ctx; 454 uint8_t i = 0; 455 456 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 457 if (!mlo_dev->wlan_vdev_list[i]) 458 continue; 459 460 if (wlan_cm_is_vdev_connecting(mlo_dev->wlan_vdev_list[i])) { 461 if (!wlan_vdev_mlme_is_mlo_link_vdev( 462 mlo_dev->wlan_vdev_list[i])) 463 return QDF_STATUS_SUCCESS; 464 465 if (!sta_ctx->disconn_req) 466 sta_ctx->disconn_req = 467 qdf_mem_malloc( 468 sizeof(struct wlan_cm_disconnect_req)); 469 470 if (!sta_ctx->disconn_req) 471 return QDF_STATUS_SUCCESS; 472 473 sta_ctx->disconn_req->vdev_id = 474 wlan_vdev_get_id(vdev); 475 sta_ctx->disconn_req->source = source; 476 sta_ctx->disconn_req->reason_code = reason_code; 477 if (bssid) 478 qdf_copy_macaddr(&sta_ctx->disconn_req->bssid, 479 bssid); 480 return QDF_STATUS_E_BUSY; 481 } else if (wlan_cm_is_vdev_connected(mlo_dev->wlan_vdev_list[i]) && 482 !wlan_vdev_mlme_is_mlo_link_vdev( 483 mlo_dev->wlan_vdev_list[i]) && 484 wlan_peer_is_mlo(wlan_vdev_get_bsspeer( 485 mlo_dev->wlan_vdev_list[i]))) { 486 /* If the vdev is moved to connected state but 487 * MLO mgr is not yet notified, defer disconnect 488 * as it can cause race between connect complete 489 * and disconnect initiation 490 */ 491 if (!qdf_test_bit(i, sta_ctx->wlan_connected_links)) { 492 if (!sta_ctx->disconn_req) 493 sta_ctx->disconn_req = 494 qdf_mem_malloc( 495 sizeof(struct wlan_cm_disconnect_req)); 496 497 if (!sta_ctx->disconn_req) 498 return QDF_STATUS_SUCCESS; 499 500 sta_ctx->disconn_req->vdev_id = 501 wlan_vdev_get_id(vdev); 502 sta_ctx->disconn_req->source = source; 503 sta_ctx->disconn_req->reason_code = reason_code; 504 if (bssid) 505 qdf_copy_macaddr(&sta_ctx->disconn_req->bssid, 506 bssid); 507 508 return QDF_STATUS_E_BUSY; 509 } 510 } 511 } 512 return QDF_STATUS_SUCCESS; 513 } 514 515 static QDF_STATUS mlo_disconnect_no_lock(struct wlan_objmgr_vdev *vdev, 516 enum wlan_cm_source source, 517 enum wlan_reason_code reason_code, 518 struct qdf_mac_addr *bssid) 519 { 520 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 521 struct wlan_mlo_sta *sta_ctx = NULL; 522 QDF_STATUS status = QDF_STATUS_SUCCESS; 523 struct wlan_objmgr_vdev *assoc_vdev = NULL; 524 uint8_t i = 0; 525 526 if (mlo_dev_ctx) 527 sta_ctx = mlo_dev_ctx->sta_ctx; 528 if (sta_ctx) { 529 mlo_free_copied_conn_req(sta_ctx); 530 } else { 531 return QDF_STATUS_E_FAILURE; 532 } 533 534 if (wlan_vdev_mlme_is_mlo_vdev(vdev)) { 535 sta_ctx = mlo_dev_ctx->sta_ctx; 536 if (!sta_ctx) 537 return QDF_STATUS_E_FAILURE; 538 539 assoc_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx); 540 541 if (sta_ctx->connect_req) { 542 wlan_cm_free_connect_req(sta_ctx->connect_req); 543 sta_ctx->connect_req = NULL; 544 } 545 546 status = mlo_validate_disconn_req(vdev, source, 547 reason_code, bssid); 548 if (QDF_IS_STATUS_ERROR(status)) { 549 mlo_err("Connect in progress, deferring disconnect"); 550 return status; 551 } 552 553 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 554 if (!mlo_dev_ctx->wlan_vdev_list[i]) 555 continue; 556 557 if ((mlo_dev_ctx->wlan_vdev_list[i] != assoc_vdev) && 558 (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links) || 559 (wlan_cm_is_vdev_connected(mlo_dev_ctx->wlan_vdev_list[i]) && 560 !wlan_peer_is_mlo(wlan_vdev_get_bsspeer(mlo_dev_ctx->wlan_vdev_list[i]))))) 561 wlan_cm_disconnect(mlo_dev_ctx->wlan_vdev_list[i], 562 source, reason_code, 563 NULL); 564 } 565 566 if (assoc_vdev) 567 wlan_cm_disconnect(assoc_vdev, source, 568 reason_code, NULL); 569 } 570 571 return status; 572 } 573 574 static void 575 mlo_cm_handle_connect_in_connection_state(struct wlan_objmgr_vdev *vdev, 576 struct wlan_cm_connect_req *req) 577 { 578 mlo_disconnect_no_lock(vdev, CM_INTERNAL_DISCONNECT, 579 REASON_UNSPEC_FAILURE, NULL); 580 mlo_cm_handle_connect_in_disconnection_state(vdev, req); 581 } 582 583 static QDF_STATUS 584 mlo_validate_connect_req(struct wlan_objmgr_vdev *vdev, 585 struct wlan_mlo_dev_context *mlo_dev_ctx, 586 struct wlan_cm_connect_req *req) 587 { 588 uint8_t i = 0; 589 QDF_STATUS status = QDF_STATUS_SUCCESS; 590 591 if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) 592 return QDF_STATUS_SUCCESS; 593 594 // Handle connect in various states 595 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 596 if (!mlo_dev_ctx->wlan_vdev_list[i]) 597 continue; 598 599 if ((wlan_cm_is_vdev_connected(mlo_dev_ctx->wlan_vdev_list[i])) || 600 (wlan_cm_is_vdev_connecting(mlo_dev_ctx->wlan_vdev_list[i])) || 601 (wlan_cm_is_vdev_roaming(mlo_dev_ctx->wlan_vdev_list[i]))) { 602 mlo_cm_handle_connect_in_connection_state(mlo_dev_ctx->wlan_vdev_list[i], req); 603 return QDF_STATUS_E_BUSY; 604 } else if (wlan_cm_is_vdev_disconnecting(mlo_dev_ctx->wlan_vdev_list[i])) { 605 mlo_cm_handle_connect_in_disconnection_state(mlo_dev_ctx->wlan_vdev_list[i], req); 606 return QDF_STATUS_E_BUSY; 607 } 608 609 /* 610 * mlo_connect: update wlan_connect_req_links in 611 * wlan_cfg80211_conect on osif_cm_connect, 612 * Validate pre checks for connection 613 */ 614 if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connect_req_links)) { 615 status = mlo_mlme_validate_conn_req( 616 mlo_dev_ctx->wlan_vdev_list[i], NULL); 617 if (status != QDF_STATUS_SUCCESS) 618 return status; 619 /* 620 * clone security params in all partner sta vaps 621 */ 622 mlo_mlme_clone_sta_security( 623 mlo_dev_ctx->wlan_vdev_list[i], req); 624 } 625 } 626 return status; 627 } 628 629 static QDF_STATUS mlo_validate_mlo_cap(struct wlan_objmgr_vdev *vdev) 630 { 631 if (wlan_vdev_mlme_is_mlo_vdev(vdev)) 632 return QDF_STATUS_SUCCESS; 633 634 return QDF_STATUS_E_FAILURE; 635 } 636 #endif 637 638 QDF_STATUS mlo_set_cu_bpcc(struct wlan_objmgr_vdev *vdev, 639 uint8_t vdev_id, uint8_t bpcc) 640 { 641 struct wlan_mlo_dev_context *mlo_dev_ctx; 642 struct mlo_sta_cu_params *cu_param; 643 uint8_t i; 644 645 mlo_dev_ctx = vdev->mlo_dev_ctx; 646 if (!mlo_dev_ctx) { 647 mlo_err("ML dev ctx is NULL"); 648 return QDF_STATUS_E_INVAL; 649 } 650 651 cu_param = &mlo_dev_ctx->sta_ctx->mlo_cu_param[0]; 652 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 653 if (cu_param[i].initialized && cu_param[i].vdev_id == vdev_id) { 654 cu_param[i].bpcc = bpcc; 655 return QDF_STATUS_SUCCESS; 656 } 657 } 658 659 return QDF_STATUS_E_INVAL; 660 } 661 662 QDF_STATUS mlo_get_cu_bpcc(struct wlan_objmgr_vdev *vdev, 663 uint8_t vdev_id, uint8_t *bpcc) 664 { 665 struct wlan_mlo_dev_context *mlo_dev_ctx; 666 struct mlo_sta_cu_params *cu_param; 667 uint8_t i; 668 669 mlo_dev_ctx = vdev->mlo_dev_ctx; 670 if (!mlo_dev_ctx) { 671 mlo_err("ML dev ctx is NULL"); 672 return QDF_STATUS_E_INVAL; 673 } 674 675 cu_param = &mlo_dev_ctx->sta_ctx->mlo_cu_param[0]; 676 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 677 if (cu_param[i].initialized && 678 cu_param[i].vdev_id == vdev_id) { 679 *bpcc = cu_param[i].bpcc; 680 return QDF_STATUS_SUCCESS; 681 } 682 } 683 684 return QDF_STATUS_E_INVAL; 685 } 686 687 void mlo_init_cu_bpcc(struct wlan_mlo_dev_context *mlo_dev_ctx, 688 uint8_t vdev_id) 689 { 690 uint8_t i; 691 struct mlo_sta_cu_params *cu_param; 692 uint8_t empty_slot = 0xff; 693 694 cu_param = &mlo_dev_ctx->sta_ctx->mlo_cu_param[0]; 695 696 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 697 if (cu_param[i].initialized && 698 cu_param[i].vdev_id == vdev_id) { 699 cu_param[i].bpcc = 0; 700 return; 701 } 702 703 if (!cu_param[i].initialized && empty_slot == 0xff) 704 empty_slot = i; 705 } 706 707 if (empty_slot != 0xff) { 708 cu_param[empty_slot].bpcc = 0; 709 cu_param[empty_slot].vdev_id = vdev_id; 710 cu_param[empty_slot].initialized = true; 711 mlo_debug("init cu bpcc idx %d, vdev_id %d", 712 empty_slot, vdev_id); 713 } else { 714 mlo_debug("No bpcc idx for vdev_id %d", vdev_id); 715 } 716 } 717 718 void mlo_clear_cu_bpcc(struct wlan_objmgr_vdev *vdev) 719 { 720 struct wlan_mlo_dev_context *mlo_dev_ctx = NULL; 721 struct wlan_mlo_sta *sta_ctx = NULL; 722 uint32_t size; 723 724 if (!vdev) 725 return; 726 727 mlo_dev_ctx = vdev->mlo_dev_ctx; 728 if (!mlo_dev_ctx) 729 return; 730 731 sta_ctx = mlo_dev_ctx->sta_ctx; 732 if (!sta_ctx) 733 return; 734 735 size = sizeof(sta_ctx->mlo_cu_param); 736 qdf_mem_zero(sta_ctx->mlo_cu_param, size); 737 } 738 739 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 740 static void mlo_clear_sta_key_mgmt(struct wlan_objmgr_vdev *vdev) 741 { 742 struct wlan_mlo_dev_context *mlo_dev_ctx = NULL; 743 struct wlan_mlo_sta *sta_ctx = NULL; 744 745 if (!vdev) 746 return; 747 748 mlo_dev_ctx = vdev->mlo_dev_ctx; 749 if (!mlo_dev_ctx) 750 return; 751 752 sta_ctx = mlo_dev_ctx->sta_ctx; 753 if (!sta_ctx) 754 return; 755 756 qdf_mem_zero(sta_ctx->key_mgmt, sizeof(sta_ctx->key_mgmt)); 757 758 mlo_debug("clear sta_key_mgmt"); 759 } 760 761 #else 762 static void mlo_clear_sta_key_mgmt(struct wlan_objmgr_vdev *vdev) 763 { 764 } 765 #endif 766 767 QDF_STATUS mlo_connect(struct wlan_objmgr_vdev *vdev, 768 struct wlan_cm_connect_req *req) 769 { 770 struct wlan_mlo_dev_context *mlo_dev_ctx; 771 struct wlan_mlo_sta *sta_ctx = NULL; 772 QDF_STATUS status = QDF_STATUS_SUCCESS; 773 774 mlo_dev_ctx = vdev->mlo_dev_ctx; 775 if (mlo_dev_ctx) 776 sta_ctx = mlo_dev_ctx->sta_ctx; 777 if (sta_ctx) { 778 status = mlo_validate_mlo_cap(vdev); 779 if (QDF_IS_STATUS_ERROR(status)) 780 return wlan_cm_start_connect(vdev, req); 781 782 mlo_dev_lock_acquire(mlo_dev_ctx); 783 status = mlo_validate_connect_req(vdev, mlo_dev_ctx, req); 784 copied_conn_req_lock_acquire(sta_ctx); 785 if (!sta_ctx->copied_conn_req) 786 sta_ctx->copied_conn_req = qdf_mem_malloc( 787 sizeof(struct wlan_cm_connect_req)); 788 else 789 wlan_cm_free_connect_req_param(sta_ctx->copied_conn_req); 790 791 if (sta_ctx->copied_conn_req) { 792 qdf_mem_copy(sta_ctx->copied_conn_req, req, 793 sizeof(struct wlan_cm_connect_req)); 794 mlo_allocate_and_copy_ies(sta_ctx->copied_conn_req, 795 req); 796 copied_conn_req_lock_release(sta_ctx); 797 } else { 798 mlo_err("Failed to allocate orig connect req"); 799 copied_conn_req_lock_release(sta_ctx); 800 mlo_dev_lock_release(mlo_dev_ctx); 801 802 return QDF_STATUS_E_NOMEM; 803 } 804 805 if (QDF_IS_STATUS_SUCCESS(status)) { 806 mlo_clear_cu_bpcc(vdev); 807 mlo_clear_connected_links_bmap(vdev); 808 mlo_clear_sta_key_mgmt(vdev); 809 mlo_dev_lock_release(mlo_dev_ctx); 810 811 status = wlan_cm_start_connect(vdev, req); 812 if (QDF_IS_STATUS_ERROR(status)) 813 mlo_mld_clear_mlo_cap(vdev); 814 return status; 815 } 816 817 mlo_dev_lock_release(mlo_dev_ctx); 818 819 return status; 820 } 821 822 return wlan_cm_start_connect(vdev, req); 823 } 824 825 static inline void 826 mlo_update_connect_req_chan_info(struct wlan_cm_connect_req *req) 827 { 828 req->chan_freq = 0; 829 req->chan_freq_hint = 0; 830 } 831 832 /** 833 * mlo_prepare_and_send_connect- Prepare and send the connect req 834 * 835 * @vdev: vdev pointer 836 * @ml_parnter_info: ml partner link info 837 * @link_info: link info on which connect req will be sent 838 * @ssid: ssid to connect 839 * @mld_addr: MLD address for connect request. 840 * 841 * Return: none 842 */ 843 844 static void 845 mlo_prepare_and_send_connect(struct wlan_objmgr_vdev *vdev, 846 struct mlo_partner_info ml_parnter_info, 847 struct mlo_link_info link_info, 848 struct wlan_ssid ssid, 849 struct qdf_mac_addr *mld_addr) 850 { 851 struct wlan_cm_connect_req req = {0}; 852 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 853 struct wlan_mlo_sta *sta_ctx; 854 855 if (!mlo_dev_ctx) { 856 mlo_err("ML dev ctx is NULL"); 857 return; 858 } 859 860 sta_ctx = mlo_dev_ctx->sta_ctx; 861 862 mlo_debug("Partner link connect mac:" QDF_MAC_ADDR_FMT 863 " bssid:" QDF_MAC_ADDR_FMT " vdev_id:%d", 864 QDF_MAC_ADDR_REF(wlan_vdev_mlme_get_macaddr(vdev)), 865 QDF_MAC_ADDR_REF(link_info.link_addr.bytes), 866 wlan_vdev_get_id(vdev)); 867 868 if (sta_ctx->copied_conn_req) 869 qdf_mem_copy(&req, sta_ctx->copied_conn_req, 870 sizeof(struct wlan_cm_connect_req)); 871 else 872 mlo_err("Invalid copied_conn_req"); 873 874 mlo_update_connect_req_chan_info(&req); 875 876 qdf_mem_copy(req.bssid.bytes, 877 link_info.link_addr.bytes, 878 QDF_MAC_ADDR_SIZE); 879 880 qdf_mem_copy(&req.ml_parnter_info, 881 &ml_parnter_info, 882 sizeof(struct mlo_partner_info)); 883 884 req.vdev_id = wlan_vdev_get_id(vdev); 885 req.ssid.length = ssid.length; 886 qdf_mem_copy(&req.ssid.ssid, &ssid.ssid, ssid.length); 887 if (mld_addr) 888 qdf_copy_macaddr(&req.mld_addr, mld_addr); 889 890 if (sta_ctx->copied_conn_req) 891 mlo_allocate_and_copy_ies(&req, sta_ctx->copied_conn_req); 892 893 if (!req.assoc_ie.ptr) 894 mlo_err("Failed to allocate assoc IEs"); 895 896 if (!req.scan_ie.ptr) 897 mlo_err("Failed to allocate scan IEs"); 898 899 /* Reset crypto auth type for partner link. 900 * It will be set based on partner scan cache entry 901 */ 902 req.crypto.auth_type = 0; 903 904 wlan_cm_start_connect(vdev, &req); 905 wlan_cm_free_connect_req_param(&req); 906 } 907 908 /** 909 * mlo_send_link_connect- Create/Issue the connection on secondary link 910 * 911 * @vdev: vdev pointer 912 * @resp: Connection resp of assoc VDEV 913 * 914 * Return: none 915 */ 916 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 917 static void mlo_send_link_connect(struct wlan_objmgr_vdev *vdev, 918 struct wlan_cm_connect_resp *resp) 919 { 920 /* Create the secondary interface, Send keys if the last link */ 921 uint8_t i, partner_idx = 0; 922 struct wlan_ssid ssid = {0}; 923 struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS]; 924 uint16_t vdev_count = 0; 925 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 926 struct mlo_partner_info *ml_parnter_info = &resp->ml_parnter_info; 927 928 mlo_debug("Sending link connect on partner interface"); 929 wlan_vdev_mlme_get_ssid( 930 vdev, ssid.ssid, 931 &ssid.length); 932 933 if (!ml_parnter_info->num_partner_links) { 934 mlo_err("No partner info in connect resp"); 935 return; 936 } 937 938 if(wlan_vdev_mlme_is_mlo_link_vdev(vdev)) 939 return; 940 941 copied_conn_req_lock_acquire(mlo_dev_ctx->sta_ctx); 942 if (!mlo_dev_ctx->sta_ctx->copied_conn_req) { 943 mlo_dev_ctx->sta_ctx->copied_conn_req = 944 qdf_mem_malloc(sizeof(struct wlan_cm_connect_req)); 945 if (mlo_dev_ctx->sta_ctx->copied_conn_req) { 946 wlan_cm_get_active_connect_req_param(vdev, 947 mlo_dev_ctx->sta_ctx->copied_conn_req); 948 } 949 } 950 copied_conn_req_lock_release(mlo_dev_ctx->sta_ctx); 951 952 mlo_sta_get_vdev_list(vdev, &vdev_count, wlan_vdev_list); 953 for (i = 0; i < vdev_count; i++) { 954 if (wlan_vdev_list[i] == vdev) { 955 mlo_release_vdev_ref(wlan_vdev_list[i]); 956 continue; 957 } 958 wlan_vdev_mlme_set_mlo_vdev(mlo_dev_ctx->wlan_vdev_list[i]); 959 wlan_vdev_mlme_set_mlo_link_vdev(mlo_dev_ctx->wlan_vdev_list[i]); 960 wlan_vdev_set_link_id( 961 wlan_vdev_list[i], 962 ml_parnter_info->partner_link_info[partner_idx].link_id); 963 ml_parnter_info->partner_link_info[partner_idx].vdev_id = 964 wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i]); 965 wlan_crypto_free_vdev_key(wlan_vdev_list[i]); 966 mlo_prepare_and_send_connect( 967 wlan_vdev_list[i], 968 *ml_parnter_info, 969 ml_parnter_info->partner_link_info[partner_idx], 970 ssid, &resp->mld_addr); 971 mlo_update_connected_links(wlan_vdev_list[i], 1); 972 partner_idx++; 973 mlo_release_vdev_ref(wlan_vdev_list[i]); 974 } 975 } 976 #else 977 static void mlo_send_link_connect(struct wlan_objmgr_vdev *vdev, 978 struct wlan_cm_connect_resp *resp) 979 { 980 struct wlan_ssid ssid = {0}; 981 uint8_t i = 0; 982 uint8_t j = 0; 983 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 984 struct mlo_partner_info *ml_parnter_info = &resp->ml_parnter_info; 985 986 if (!ml_parnter_info->num_partner_links) { 987 mlo_err("No partner info in connect resp"); 988 return; 989 } 990 991 mlo_dev_lock_acquire(mlo_dev_ctx); 992 if (!wlan_cm_is_vdev_connected(vdev)) { 993 mlo_dev_lock_release(mlo_dev_ctx); 994 return; 995 } 996 997 for (j = 0; j < ml_parnter_info->num_partner_links; j++) { 998 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 999 if (!mlo_dev_ctx->wlan_vdev_list[i]) 1000 continue; 1001 /* 1002 * mlo_connect: update wlan_connected_links bitmap from 1003 * assoc resp parsing 1004 */ 1005 if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links)) { 1006 if (wlan_cm_is_vdev_disconnected( 1007 mlo_dev_ctx->wlan_vdev_list[i])) { 1008 if (mlo_dev_ctx->wlan_vdev_list[i]->vdev_mlme.mlo_link_id 1009 == ml_parnter_info->partner_link_info[j].link_id) { 1010 wlan_vdev_mlme_get_ssid( 1011 vdev, ssid.ssid, 1012 &ssid.length); 1013 mlo_prepare_and_send_connect( 1014 mlo_dev_ctx->wlan_vdev_list[i], 1015 *ml_parnter_info, 1016 ml_parnter_info->partner_link_info[j], 1017 ssid, NULL); 1018 mlo_dev_lock_release(mlo_dev_ctx); 1019 return; 1020 } 1021 } 1022 } 1023 } 1024 } 1025 mlo_dev_lock_release(mlo_dev_ctx); 1026 } 1027 #endif 1028 1029 void 1030 mlo_update_connected_links_bmap(struct wlan_mlo_dev_context *mlo_dev_ctx, 1031 struct mlo_partner_info ml_parnter_info) 1032 { 1033 uint8_t i = 0; 1034 uint8_t j = 0; 1035 1036 if (!mlo_dev_ctx) { 1037 mlo_err("ML dev ctx is NULL"); 1038 return; 1039 } 1040 1041 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 1042 if (!mlo_dev_ctx->wlan_vdev_list[i]) 1043 continue; 1044 1045 for (j = 0; j < ml_parnter_info.num_partner_links; j++) { 1046 if (wlan_vdev_get_link_id(mlo_dev_ctx->wlan_vdev_list[i]) == 1047 ml_parnter_info.partner_link_info[j].link_id) 1048 mlo_update_connected_links( 1049 mlo_dev_ctx->wlan_vdev_list[i], 1); 1050 } 1051 } 1052 } 1053 1054 void mlo_clear_connected_links_bmap(struct wlan_objmgr_vdev *vdev) 1055 { 1056 struct wlan_mlo_dev_context *mlo_dev_ctx = NULL; 1057 struct wlan_mlo_sta *sta_ctx = NULL; 1058 1059 if (!vdev) 1060 return; 1061 1062 mlo_dev_ctx = vdev->mlo_dev_ctx; 1063 if (!mlo_dev_ctx) 1064 return; 1065 1066 sta_ctx = mlo_dev_ctx->sta_ctx; 1067 if (!sta_ctx) 1068 return; 1069 1070 qdf_mem_zero(sta_ctx->wlan_connected_links, 1071 sizeof(sta_ctx->wlan_connected_links)); 1072 } 1073 1074 static QDF_STATUS ml_activate_disconnect_req_sched_cb(struct scheduler_msg *msg) 1075 { 1076 struct wlan_objmgr_vdev *vdev = msg->bodyptr; 1077 1078 if (!vdev) { 1079 mlme_err("Null input vdev"); 1080 return QDF_STATUS_E_INVAL; 1081 } 1082 1083 mlo_disconnect(vdev, CM_OSIF_DISCONNECT, 1084 REASON_UNSPEC_FAILURE, NULL); 1085 1086 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 1087 return QDF_STATUS_SUCCESS; 1088 } 1089 1090 static QDF_STATUS ml_activate_disconnect_req_flush_cb(struct scheduler_msg *msg) 1091 { 1092 struct wlan_objmgr_vdev *vdev = msg->bodyptr; 1093 1094 if (!vdev) { 1095 mlme_err("Null input vdev"); 1096 return QDF_STATUS_E_INVAL; 1097 } 1098 1099 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 1100 return QDF_STATUS_SUCCESS; 1101 } 1102 1103 static QDF_STATUS ml_activate_pend_disconn_req_cb(struct scheduler_msg *msg) 1104 { 1105 struct wlan_objmgr_vdev *vdev = msg->bodyptr; 1106 struct wlan_mlo_dev_context *mlo_dev_ctx = NULL; 1107 struct wlan_mlo_sta *sta_ctx = NULL; 1108 1109 if (!vdev) { 1110 mlme_err("Null input vdev"); 1111 return QDF_STATUS_E_INVAL; 1112 } 1113 1114 mlo_dev_ctx = vdev->mlo_dev_ctx; 1115 sta_ctx = mlo_dev_ctx->sta_ctx; 1116 if (!sta_ctx || !sta_ctx->disconn_req) 1117 goto release_ref; 1118 1119 mlo_disconnect_req(vdev, sta_ctx->disconn_req->source, 1120 sta_ctx->disconn_req->reason_code, 1121 &sta_ctx->disconn_req->bssid, false); 1122 1123 qdf_mem_free(sta_ctx->disconn_req); 1124 sta_ctx->disconn_req = NULL; 1125 1126 release_ref: 1127 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 1128 1129 return QDF_STATUS_SUCCESS; 1130 } 1131 1132 static QDF_STATUS ml_activate_pend_disconn_req_flush_cb( 1133 struct scheduler_msg *msg) 1134 { 1135 struct wlan_objmgr_vdev *vdev = msg->bodyptr; 1136 1137 if (!vdev) { 1138 mlme_err("Null input vdev"); 1139 return QDF_STATUS_E_INVAL; 1140 } 1141 1142 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 1143 return QDF_STATUS_SUCCESS; 1144 } 1145 1146 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 1147 static inline 1148 QDF_STATUS mlo_post_disconnect_msg(struct scheduler_msg *msg) 1149 { 1150 return scheduler_post_message( 1151 QDF_MODULE_ID_OS_IF, 1152 QDF_MODULE_ID_SCAN, 1153 QDF_MODULE_ID_OS_IF, 1154 msg); 1155 } 1156 #else 1157 static inline 1158 QDF_STATUS mlo_post_disconnect_msg(struct scheduler_msg *msg) 1159 { 1160 return scheduler_post_message( 1161 QDF_MODULE_ID_MLME, 1162 QDF_MODULE_ID_MLME, 1163 QDF_MODULE_ID_MLME, 1164 msg); 1165 } 1166 #endif 1167 1168 void mlo_handle_sta_link_connect_failure(struct wlan_objmgr_vdev *vdev, 1169 struct wlan_cm_connect_resp *rsp) 1170 { 1171 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 1172 struct scheduler_msg msg = {0}; 1173 QDF_STATUS ret; 1174 struct wlan_objmgr_vdev *assoc_vdev; 1175 1176 if (!mlo_dev_ctx) { 1177 mlo_err("ML dev ctx is NULL"); 1178 return; 1179 } 1180 1181 assoc_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx); 1182 if (!assoc_vdev) { 1183 mlo_err("Assoc Vdev is NULL"); 1184 return; 1185 } 1186 1187 if (vdev != assoc_vdev) { 1188 mlo_update_connected_links(vdev, 0); 1189 if (rsp->reason == CM_NO_CANDIDATE_FOUND || 1190 rsp->reason == CM_HW_MODE_FAILURE || 1191 rsp->reason == CM_SER_FAILURE) { 1192 ret = wlan_objmgr_vdev_try_get_ref( 1193 assoc_vdev, WLAN_MLO_MGR_ID); 1194 if (QDF_IS_STATUS_ERROR(ret)) { 1195 mlo_err("Failed to get ref vdev_id %d", 1196 wlan_vdev_get_id(assoc_vdev)); 1197 return; 1198 } 1199 /* Since these failures happen in same context. use 1200 * scheduler to avoid deadlock by deferring context 1201 */ 1202 msg.bodyptr = assoc_vdev; 1203 msg.callback = ml_activate_disconnect_req_sched_cb; 1204 msg.flush_callback = 1205 ml_activate_disconnect_req_flush_cb; 1206 ret = mlo_post_disconnect_msg(&msg); 1207 if (QDF_IS_STATUS_ERROR(ret)) { 1208 wlan_objmgr_vdev_release_ref( 1209 assoc_vdev, 1210 WLAN_MLO_MGR_ID); 1211 return; 1212 } 1213 } else { 1214 mlo_disconnect(vdev, CM_OSIF_DISCONNECT, 1215 REASON_UNSPEC_FAILURE, NULL); 1216 } 1217 } 1218 } 1219 1220 void mlo_handle_pending_disconnect(struct wlan_objmgr_vdev *vdev) 1221 { 1222 struct scheduler_msg msg = {0}; 1223 QDF_STATUS ret; 1224 1225 ret = wlan_objmgr_vdev_try_get_ref( 1226 vdev, WLAN_MLO_MGR_ID); 1227 if (QDF_IS_STATUS_ERROR(ret)) { 1228 mlo_err("Failed to get ref vdev_id %d", 1229 wlan_vdev_get_id(vdev)); 1230 return; 1231 } 1232 1233 msg.bodyptr = vdev; 1234 msg.callback = ml_activate_pend_disconn_req_cb; 1235 msg.flush_callback = 1236 ml_activate_pend_disconn_req_flush_cb; 1237 ret = mlo_post_disconnect_msg(&msg); 1238 if (QDF_IS_STATUS_ERROR(ret)) { 1239 mlo_err("Failed to post scheduler msg"); 1240 wlan_objmgr_vdev_release_ref( 1241 vdev, 1242 WLAN_MLO_MGR_ID); 1243 QDF_BUG(0); 1244 return; 1245 } 1246 } 1247 1248 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 1249 static bool 1250 mlo_sta_ignore_link_connect_fail(struct wlan_objmgr_vdev *vdev) 1251 { 1252 if (wlan_cm_is_vdev_disconnected(vdev)) { 1253 if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev)) 1254 return false; 1255 else 1256 return true; 1257 } 1258 1259 return false; 1260 } 1261 #else 1262 static inline bool 1263 mlo_sta_ignore_link_connect_fail(struct wlan_objmgr_vdev *vdev) 1264 { 1265 return false; 1266 } 1267 #endif 1268 1269 void mlo_sta_link_connect_notify(struct wlan_objmgr_vdev *vdev, 1270 struct wlan_cm_connect_resp *rsp) 1271 { 1272 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 1273 struct wlan_mlo_sta *sta_ctx = NULL; 1274 1275 if (mlo_dev_ctx) { 1276 sta_ctx = mlo_dev_ctx->sta_ctx; 1277 } else { 1278 mlo_debug_rl("mlo_dev_ctx is NULL"); 1279 return; 1280 } 1281 1282 if (sta_ctx && sta_ctx->disconn_req) { 1283 mlo_debug("Handle pending disocnnect for vdev %d", 1284 wlan_vdev_get_id(vdev)); 1285 mlo_handle_pending_disconnect(vdev); 1286 return; 1287 } 1288 1289 if (wlan_cm_is_link_switch_connect_resp(rsp)) { 1290 mlo_info("Skip for link switch connect request"); 1291 return; 1292 } 1293 1294 if (mlo_sta_ignore_link_connect_fail(vdev)) 1295 return; 1296 1297 if (wlan_cm_is_vdev_disconnected(vdev)) 1298 mlo_free_copied_conn_req(sta_ctx); 1299 1300 if (wlan_vdev_mlme_is_mlo_vdev(vdev)) { 1301 mlo_debug("Vdev: %d", wlan_vdev_get_id(vdev)); 1302 if (wlan_cm_is_vdev_disconnected(vdev)) { 1303 mlo_handle_sta_link_connect_failure(vdev, rsp); 1304 return; 1305 } else if (!wlan_cm_is_vdev_connected(vdev)) { 1306 /* If vdev is not in disconnected or connected state, 1307 * then the event is received due to connect req being 1308 * flushed. Hence, ignore this event 1309 */ 1310 return; 1311 } 1312 1313 if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev) && sta_ctx) { 1314 if (sta_ctx->assoc_rsp.ptr) { 1315 qdf_mem_free(sta_ctx->assoc_rsp.ptr); 1316 sta_ctx->assoc_rsp.ptr = NULL; 1317 } 1318 sta_ctx->assoc_rsp.len = rsp->connect_ies.assoc_rsp.len; 1319 sta_ctx->assoc_rsp.ptr = 1320 qdf_mem_malloc(rsp->connect_ies.assoc_rsp.len); 1321 if (!sta_ctx->assoc_rsp.ptr) { 1322 QDF_ASSERT(0); 1323 return; 1324 } 1325 if (rsp->connect_ies.assoc_rsp.ptr) 1326 qdf_mem_copy(sta_ctx->assoc_rsp.ptr, 1327 rsp->connect_ies.assoc_rsp.ptr, 1328 rsp->connect_ies.assoc_rsp.len); 1329 sta_ctx->ml_partner_info = rsp->ml_parnter_info; 1330 /* Update connected_links_bmap for all vdev taking 1331 * part in association 1332 */ 1333 mlo_update_connected_links(vdev, 1); 1334 mlo_update_connected_links_bmap(mlo_dev_ctx, 1335 rsp->ml_parnter_info); 1336 } 1337 mlo_send_link_connect(vdev, rsp); 1338 } 1339 } 1340 1341 /** 1342 * mlo_send_link_disconnect_sync- Issue sync the disconnect request on MLD links 1343 * 1344 * @mlo_dev_ctx: pointer to mlo dev context 1345 * @source: disconnect source 1346 * @reason_code: disconnect reason 1347 * @bssid: bssid of AP to disconnect, can be null if not known 1348 * 1349 * Return: QDF_STATUS 1350 */ 1351 static QDF_STATUS 1352 mlo_send_link_disconnect_sync(struct wlan_mlo_dev_context *mlo_dev_ctx, 1353 enum wlan_cm_source source, 1354 enum wlan_reason_code reason_code, 1355 struct qdf_mac_addr *bssid) 1356 { 1357 uint8_t i; 1358 struct wlan_objmgr_vdev *sync_vdev = 1359 mlo_get_assoc_link_vdev(mlo_dev_ctx); 1360 1361 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 1362 if (!mlo_dev_ctx->wlan_vdev_list[i] || 1363 mlo_dev_ctx->wlan_vdev_list[i] == sync_vdev) { 1364 continue; 1365 } 1366 1367 /** 1368 * If the assoc vdev isn't present, use the first link dev as 1369 * sync candidate. 1370 */ 1371 if (!sync_vdev) { 1372 sync_vdev = mlo_dev_ctx->wlan_vdev_list[i]; 1373 continue; 1374 } 1375 1376 /** 1377 * To initiate disconnect on all links at once, no need to use 1378 * sync API for all link vdevs. 1379 */ 1380 wlan_cm_disconnect(mlo_dev_ctx->wlan_vdev_list[i], 1381 source, reason_code, NULL); 1382 } 1383 1384 if (sync_vdev) 1385 wlan_cm_disconnect_sync(sync_vdev, source, reason_code); 1386 1387 return QDF_STATUS_SUCCESS; 1388 } 1389 1390 static QDF_STATUS mlo_disconnect_req(struct wlan_objmgr_vdev *vdev, 1391 enum wlan_cm_source source, 1392 enum wlan_reason_code reason_code, 1393 struct qdf_mac_addr *bssid, 1394 bool validate_req) 1395 { 1396 struct wlan_mlo_dev_context *mlo_dev_ctx = NULL; 1397 struct wlan_mlo_sta *sta_ctx = NULL; 1398 QDF_STATUS status = QDF_STATUS_SUCCESS; 1399 1400 if (!vdev) 1401 return QDF_STATUS_E_FAILURE; 1402 1403 mlo_dev_ctx = vdev->mlo_dev_ctx; 1404 if (mlo_dev_ctx) 1405 sta_ctx = mlo_dev_ctx->sta_ctx; 1406 if (mlo_dev_ctx && wlan_vdev_mlme_is_mlo_vdev(vdev)) { 1407 mlo_dev_lock_acquire(mlo_dev_ctx); 1408 if (sta_ctx && sta_ctx->connect_req && 1409 source != CM_INTERNAL_DISCONNECT) { 1410 wlan_cm_free_connect_req(sta_ctx->connect_req); 1411 sta_ctx->connect_req = NULL; 1412 } 1413 1414 if (validate_req) { 1415 status = mlo_validate_disconn_req(vdev, source, 1416 reason_code, bssid); 1417 if (QDF_IS_STATUS_ERROR(status)) { 1418 mlo_err("Connect in progress, deferring disconnect"); 1419 mlo_dev_lock_release(mlo_dev_ctx); 1420 return status; 1421 } 1422 } 1423 1424 mlo_dev_lock_release(mlo_dev_ctx); 1425 1426 status = mlo_send_link_disconnect(vdev, source, 1427 reason_code, bssid); 1428 if (QDF_IS_STATUS_SUCCESS(status)) 1429 mlo_free_copied_conn_req(sta_ctx); 1430 1431 return status; 1432 } 1433 status = wlan_cm_disconnect(vdev, source, 1434 reason_code, NULL); 1435 if (QDF_IS_STATUS_SUCCESS(status)) 1436 mlo_free_copied_conn_req(sta_ctx); 1437 1438 return status; 1439 } 1440 1441 QDF_STATUS mlo_disconnect(struct wlan_objmgr_vdev *vdev, 1442 enum wlan_cm_source source, 1443 enum wlan_reason_code reason_code, 1444 struct qdf_mac_addr *bssid) 1445 { 1446 return mlo_disconnect_req(vdev, source, reason_code, bssid, true); 1447 } 1448 1449 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 1450 /** 1451 * mlo_wait_for_mld_disconnection - API to wait for sync mld disconnection 1452 * @vdev: pointer to vdev 1453 * 1454 * Return: none 1455 */ 1456 static inline 1457 void mlo_wait_for_mld_disconnection(struct wlan_objmgr_vdev *vdev) 1458 { } 1459 #else 1460 #define ML_DISCONNECT_CMD_TIMEOUT 1000 1461 #define ML_DISCONNECT_CMD_TIMEOUT_CNT 30 /* 30*1000 ms */ 1462 1463 static void mlo_wait_for_mld_disconnection(struct wlan_objmgr_vdev *vdev) 1464 { 1465 int waitcnt = 0; 1466 qdf_event_t wait_event; 1467 1468 qdf_mem_zero(&wait_event, sizeof(wait_event)); 1469 qdf_event_create(&wait_event); 1470 qdf_event_reset(&wait_event); 1471 1472 while (!mlo_is_mld_disconnected(vdev) && 1473 waitcnt < ML_DISCONNECT_CMD_TIMEOUT_CNT) { 1474 qdf_wait_single_event(&wait_event, ML_DISCONNECT_CMD_TIMEOUT); 1475 waitcnt++; 1476 } 1477 qdf_event_destroy(&wait_event); 1478 } 1479 #endif 1480 QDF_STATUS mlo_sync_disconnect(struct wlan_objmgr_vdev *vdev, 1481 enum wlan_cm_source source, 1482 enum wlan_reason_code reason_code, 1483 struct qdf_mac_addr *bssid) 1484 { 1485 struct wlan_mlo_dev_context *mlo_dev_ctx = NULL; 1486 struct wlan_mlo_sta *sta_ctx = NULL; 1487 QDF_STATUS status = QDF_STATUS_SUCCESS; 1488 1489 if (!vdev) 1490 return QDF_STATUS_E_FAILURE; 1491 1492 mlo_dev_ctx = vdev->mlo_dev_ctx; 1493 if (mlo_dev_ctx) 1494 sta_ctx = mlo_dev_ctx->sta_ctx; 1495 if (mlo_dev_ctx && wlan_vdev_mlme_is_mlo_vdev(vdev)) { 1496 if (sta_ctx && sta_ctx->connect_req) { 1497 wlan_cm_free_connect_req(sta_ctx->connect_req); 1498 sta_ctx->connect_req = NULL; 1499 } 1500 1501 status = mlo_validate_disconn_req(vdev, source, 1502 reason_code, bssid); 1503 if (QDF_IS_STATUS_ERROR(status)) { 1504 mlo_err("Connect in progress, deferring disconnect"); 1505 return status; 1506 } 1507 1508 status = mlo_send_link_disconnect_sync(mlo_dev_ctx, source, 1509 reason_code, bssid); 1510 if (QDF_IS_STATUS_SUCCESS(status)) { 1511 mlo_free_copied_conn_req(sta_ctx); 1512 mlo_wait_for_mld_disconnection(vdev); 1513 } 1514 1515 return status; 1516 } 1517 status = wlan_cm_disconnect_sync(vdev, source, 1518 reason_code); 1519 if (QDF_IS_STATUS_SUCCESS(status)) 1520 mlo_free_copied_conn_req(sta_ctx); 1521 1522 return status; 1523 } 1524 1525 /** 1526 * mlo_handle_disconnect_resp- Issue desired actions on partner link vdev 1527 * 1528 * @vdev: pointer to vdev 1529 * @resp: disconnect resp 1530 * 1531 * Return: none 1532 */ 1533 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 1534 static 1535 void mlo_handle_disconnect_resp(struct wlan_objmgr_vdev *vdev, 1536 struct wlan_cm_discon_rsp *resp) 1537 { 1538 /* If it is secondary link then delete vdev object from mlo device. */ 1539 enum wlan_cm_source source; 1540 enum wlan_reason_code reason_code; 1541 uint8_t i = 0; 1542 struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS]; 1543 uint16_t vdev_count = 0; 1544 1545 mlo_sta_get_vdev_list(vdev, &vdev_count, wlan_vdev_list); 1546 for (i = 0; i < vdev_count; i++) { 1547 if (wlan_cm_is_vdev_connected(wlan_vdev_list[i])) { 1548 if (wlan_vdev_mlme_is_mlo_link_vdev( 1549 wlan_vdev_list[i])) { 1550 source = resp->req.req.source; 1551 reason_code = resp->req.req.reason_code; 1552 wlan_cm_disconnect( 1553 wlan_vdev_list[i], 1554 source, reason_code, NULL); 1555 } 1556 } 1557 mlo_release_vdev_ref(wlan_vdev_list[i]); 1558 } 1559 } 1560 #else 1561 static 1562 void mlo_handle_disconnect_resp(struct wlan_objmgr_vdev *vdev, 1563 struct wlan_cm_discon_rsp *resp) 1564 { } 1565 1566 static QDF_STATUS ml_activate_connect_req_sched_cb(struct scheduler_msg *msg) 1567 { 1568 struct wlan_objmgr_vdev *vdev = msg->bodyptr; 1569 struct wlan_mlo_dev_context *mlo_dev_ctx = NULL; 1570 struct wlan_mlo_sta *sta_ctx = NULL; 1571 uint8_t i = 0; 1572 struct mlo_partner_info partner_info; 1573 struct mlo_link_info partner_link_info; 1574 struct wlan_objmgr_vdev *tmp_vdev; 1575 1576 if (!vdev) { 1577 mlme_err("Null input vdev"); 1578 return QDF_STATUS_E_INVAL; 1579 } 1580 1581 mlo_dev_ctx = vdev->mlo_dev_ctx; 1582 if (!mlo_dev_ctx) { 1583 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 1584 return QDF_STATUS_E_INVAL; 1585 } 1586 1587 sta_ctx = mlo_dev_ctx->sta_ctx; 1588 if (!sta_ctx || !sta_ctx->connect_req) { 1589 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 1590 return QDF_STATUS_E_INVAL; 1591 } 1592 1593 if (sta_ctx->connect_req->ml_parnter_info.num_partner_links) { 1594 partner_info = sta_ctx->connect_req->ml_parnter_info; 1595 wlan_vdev_mlme_set_mlo_vdev(vdev); 1596 wlan_vdev_mlme_clear_mlo_link_vdev(vdev); 1597 mlo_clear_connect_req_links_bmap(vdev); 1598 mlo_update_connect_req_links(vdev, 1); 1599 for (i = 0; i < partner_info.num_partner_links; i++) { 1600 partner_link_info = partner_info.partner_link_info[i]; 1601 tmp_vdev = mlo_get_ml_vdev_by_mac( 1602 vdev, 1603 &partner_link_info.link_addr); 1604 if (tmp_vdev) { 1605 mlo_update_connect_req_links(tmp_vdev, 1); 1606 wlan_vdev_mlme_set_mlo_vdev(tmp_vdev); 1607 wlan_vdev_mlme_set_mlo_link_vdev(tmp_vdev); 1608 wlan_vdev_set_link_id( 1609 tmp_vdev, 1610 partner_link_info.link_id); 1611 } 1612 } 1613 } 1614 1615 mlo_connect(vdev, sta_ctx->connect_req); 1616 wlan_cm_free_connect_req(sta_ctx->connect_req); 1617 sta_ctx->connect_req = NULL; 1618 1619 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 1620 return QDF_STATUS_SUCCESS; 1621 } 1622 1623 static QDF_STATUS ml_activate_connect_req_flush_cb(struct scheduler_msg *msg) 1624 { 1625 struct wlan_objmgr_vdev *vdev = msg->bodyptr; 1626 1627 if (!vdev) { 1628 mlme_err("Null input vdev"); 1629 return QDF_STATUS_E_INVAL; 1630 } 1631 1632 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 1633 return QDF_STATUS_SUCCESS; 1634 } 1635 #endif 1636 1637 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 1638 static inline 1639 void mlo_sta_link_handle_pending_connect(struct wlan_objmgr_vdev *vdev) 1640 { } 1641 #else 1642 static inline 1643 void mlo_sta_link_handle_pending_connect(struct wlan_objmgr_vdev *vdev) 1644 { 1645 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 1646 struct scheduler_msg msg = {0}; 1647 QDF_STATUS ret; 1648 struct wlan_mlo_sta *sta_ctx = NULL; 1649 1650 if (!mlo_dev_ctx) { 1651 mlo_err("ML dev ctx is null"); 1652 return; 1653 } 1654 sta_ctx = mlo_dev_ctx->sta_ctx; 1655 ret = wlan_objmgr_vdev_try_get_ref( 1656 vdev, 1657 WLAN_MLO_MGR_ID); 1658 if (QDF_IS_STATUS_ERROR(ret)) { 1659 wlan_cm_free_connect_req(sta_ctx->connect_req); 1660 sta_ctx->connect_req = NULL; 1661 return; 1662 } 1663 msg.bodyptr = vdev; 1664 msg.callback = ml_activate_connect_req_sched_cb; 1665 msg.flush_callback = ml_activate_connect_req_flush_cb; 1666 1667 ret = scheduler_post_message(QDF_MODULE_ID_MLME, 1668 QDF_MODULE_ID_MLME, 1669 QDF_MODULE_ID_MLME, &msg); 1670 if (QDF_IS_STATUS_ERROR(ret)) { 1671 wlan_cm_free_connect_req(sta_ctx->connect_req); 1672 sta_ctx->connect_req = NULL; 1673 wlan_objmgr_vdev_release_ref(vdev, 1674 WLAN_MLO_MGR_ID); 1675 return; 1676 } 1677 } 1678 #endif 1679 1680 void mlo_sta_link_disconn_notify(struct wlan_objmgr_vdev *vdev, 1681 struct wlan_cm_discon_rsp *resp) 1682 { 1683 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 1684 struct wlan_mlo_sta *sta_ctx = NULL; 1685 struct wlan_objmgr_vdev *assoc_vdev = NULL; 1686 1687 if (!mlo_dev_ctx || !(wlan_vdev_mlme_is_mlo_vdev(vdev))) 1688 return; 1689 1690 sta_ctx = mlo_dev_ctx->sta_ctx; 1691 if (!sta_ctx) 1692 return; 1693 1694 if (!wlan_cm_is_vdev_disconnected(vdev)) 1695 return; 1696 1697 mlo_update_connected_links(vdev, 0); 1698 if (mlo_is_mld_disconnected(vdev)) { 1699 if (sta_ctx->connect_req) { 1700 assoc_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx); 1701 if (!assoc_vdev) 1702 return; 1703 mlo_sta_link_handle_pending_connect(assoc_vdev); 1704 } 1705 } 1706 1707 if (!wlan_cm_is_link_switch_disconnect_resp(resp)) 1708 mlo_handle_disconnect_resp(vdev, resp); 1709 } 1710 1711 bool mlo_is_mld_sta(struct wlan_objmgr_vdev *vdev) 1712 { 1713 if ((wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE) && 1714 wlan_vdev_mlme_is_mlo_vdev(vdev)) 1715 return true; 1716 1717 return false; 1718 } 1719 1720 qdf_export_symbol(mlo_is_mld_sta); 1721 #ifndef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 1722 struct wlan_objmgr_vdev * 1723 mlo_get_ml_vdev_by_mac(struct wlan_objmgr_vdev *vdev, 1724 struct qdf_mac_addr *macaddr) 1725 { 1726 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 1727 uint8_t i = 0; 1728 1729 if (!mlo_dev_ctx) 1730 return NULL; 1731 1732 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 1733 if (!mlo_dev_ctx->wlan_vdev_list[i]) 1734 continue; 1735 1736 if(qdf_mem_cmp(macaddr, 1737 wlan_vdev_mlme_get_macaddr(mlo_dev_ctx->wlan_vdev_list[i]), 1738 QDF_MAC_ADDR_SIZE) == 0) { 1739 return mlo_dev_ctx->wlan_vdev_list[i]; 1740 } 1741 } 1742 return NULL; 1743 } 1744 #endif 1745 1746 qdf_freq_t 1747 mlo_get_chan_freq_by_bssid(struct wlan_objmgr_pdev *pdev, 1748 struct qdf_mac_addr *bssid) 1749 { 1750 struct scan_filter *scan_filter; 1751 int8_t ch_freq = 0; 1752 qdf_list_t *list = NULL; 1753 struct scan_cache_node *first_node = NULL; 1754 qdf_list_node_t *cur_node = NULL; 1755 1756 scan_filter = qdf_mem_malloc(sizeof(*scan_filter)); 1757 if (!scan_filter) 1758 return ch_freq; 1759 1760 scan_filter->num_of_bssid = 1; 1761 qdf_mem_copy(scan_filter->bssid_list[0].bytes, 1762 bssid, sizeof(struct qdf_mac_addr)); 1763 list = wlan_scan_get_result(pdev, scan_filter); 1764 qdf_mem_free(scan_filter); 1765 1766 if (!list || (list && !qdf_list_size(list))) { 1767 mlo_debug("scan list empty"); 1768 goto error; 1769 } 1770 1771 qdf_list_peek_front(list, &cur_node); 1772 first_node = qdf_container_of(cur_node, 1773 struct scan_cache_node, 1774 node); 1775 if (first_node && first_node->entry) 1776 ch_freq = first_node->entry->channel.chan_freq; 1777 error: 1778 if (list) 1779 wlan_scan_purge_results(list); 1780 1781 return ch_freq; 1782 } 1783 1784 #ifdef WLAN_FEATURE_ROAM_OFFLOAD 1785 /** 1786 * mlo_get_reassoc_rsp() - To get reassoc response 1787 * @vdev: objmgr vdev 1788 * @reassoc_rsp_frame: reassoc rsp 1789 * 1790 * Return: NA 1791 */ 1792 static 1793 void mlo_get_reassoc_rsp(struct wlan_objmgr_vdev *vdev, 1794 struct element_info **reassoc_rsp_frame) 1795 { 1796 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 1797 struct wlan_mlo_sta *sta_ctx = NULL; 1798 1799 if (!mlo_dev_ctx || !mlo_dev_ctx->sta_ctx) 1800 return; 1801 1802 sta_ctx = mlo_dev_ctx->sta_ctx; 1803 if (!sta_ctx->copied_reassoc_rsp) { 1804 mlo_err("Reassoc rsp not present for vdev_id %d", 1805 wlan_vdev_get_id(vdev)); 1806 *reassoc_rsp_frame = NULL; 1807 return; 1808 } 1809 1810 if (!sta_ctx->copied_reassoc_rsp->connect_ies.assoc_rsp.len || 1811 !sta_ctx->copied_reassoc_rsp->connect_ies.assoc_rsp.ptr) { 1812 mlo_err("Reassoc Resp info empty vdev_id %d assoc len %d", 1813 wlan_vdev_get_id(vdev), 1814 sta_ctx->copied_reassoc_rsp->connect_ies.assoc_rsp.len); 1815 *reassoc_rsp_frame = NULL; 1816 return; 1817 } 1818 1819 *reassoc_rsp_frame = 1820 &sta_ctx->copied_reassoc_rsp->connect_ies.assoc_rsp; 1821 } 1822 #else 1823 static inline 1824 void mlo_get_reassoc_rsp(struct wlan_objmgr_vdev *vdev, 1825 struct element_info **reassoc_rsp_frame) 1826 { 1827 *reassoc_rsp_frame = NULL; 1828 } 1829 #endif 1830 1831 void mlo_get_assoc_rsp(struct wlan_objmgr_vdev *vdev, 1832 struct element_info *assoc_rsp_frame) 1833 { 1834 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 1835 struct wlan_mlo_sta *sta_ctx = NULL; 1836 struct element_info *mlo_reassoc_rsp = NULL; 1837 1838 if (!mlo_dev_ctx || !mlo_dev_ctx->sta_ctx) 1839 return; 1840 1841 sta_ctx = mlo_dev_ctx->sta_ctx; 1842 if (sta_ctx->assoc_rsp.len && sta_ctx->assoc_rsp.ptr) { 1843 *assoc_rsp_frame = sta_ctx->assoc_rsp; 1844 return; 1845 } 1846 mlo_get_reassoc_rsp(vdev, &mlo_reassoc_rsp); 1847 if (mlo_reassoc_rsp) 1848 *assoc_rsp_frame = *mlo_reassoc_rsp; 1849 } 1850 1851 QDF_STATUS mlo_sta_save_quiet_status(struct wlan_mlo_dev_context *mlo_dev_ctx, 1852 uint8_t link_id, 1853 bool quiet_status) 1854 { 1855 struct wlan_mlo_sta *sta_ctx; 1856 int i; 1857 bool find_free_buffer = false; 1858 int free_idx; 1859 1860 if (!mlo_dev_ctx) { 1861 mlo_err("invalid mlo_dev_ctx"); 1862 return QDF_STATUS_E_INVAL; 1863 } 1864 1865 mlo_dev_lock_acquire(mlo_dev_ctx); 1866 sta_ctx = mlo_dev_ctx->sta_ctx; 1867 if (!sta_ctx) { 1868 mlo_err("invalid sta_ctx"); 1869 mlo_dev_lock_release(mlo_dev_ctx); 1870 return QDF_STATUS_E_INVAL; 1871 } 1872 for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_quiet_status); i++) { 1873 if (!sta_ctx->mlo_quiet_status[i].valid_status) { 1874 if (!find_free_buffer) { 1875 free_idx = i; 1876 find_free_buffer = true; 1877 } 1878 } else if (link_id == sta_ctx->mlo_quiet_status[i].link_id) { 1879 sta_ctx->mlo_quiet_status[i].quiet_status = 1880 quiet_status; 1881 mlo_debug("mld mac " QDF_MAC_ADDR_FMT " link id %d quiet status update %d", 1882 QDF_MAC_ADDR_REF(mlo_dev_ctx->mld_addr.bytes), 1883 link_id, quiet_status); 1884 mlo_dev_lock_release(mlo_dev_ctx); 1885 return QDF_STATUS_SUCCESS; 1886 } 1887 } 1888 if (!find_free_buffer) { 1889 mlo_err("no free buffer for link id %d to save quiet_status", 1890 link_id); 1891 mlo_dev_lock_release(mlo_dev_ctx); 1892 return QDF_STATUS_E_INVAL; 1893 } 1894 sta_ctx->mlo_quiet_status[free_idx].quiet_status = quiet_status; 1895 sta_ctx->mlo_quiet_status[free_idx].link_id = link_id; 1896 sta_ctx->mlo_quiet_status[free_idx].valid_status = true; 1897 1898 mlo_debug("mld mac " QDF_MAC_ADDR_FMT " link id %d in quiet status %d", 1899 QDF_MAC_ADDR_REF(mlo_dev_ctx->mld_addr.bytes), 1900 link_id, quiet_status); 1901 mlo_dev_lock_release(mlo_dev_ctx); 1902 1903 return QDF_STATUS_SUCCESS; 1904 } 1905 1906 bool mlo_is_sta_in_quiet_status(struct wlan_mlo_dev_context *mlo_dev_ctx, 1907 uint8_t link_id) 1908 { 1909 struct wlan_mlo_sta *sta_ctx; 1910 int i; 1911 bool quiet_status = false; 1912 1913 if (!mlo_dev_ctx) { 1914 mlo_err("invalid mlo_dev_ctx"); 1915 return quiet_status; 1916 } 1917 1918 mlo_dev_lock_acquire(mlo_dev_ctx); 1919 sta_ctx = mlo_dev_ctx->sta_ctx; 1920 if (!sta_ctx) { 1921 mlo_err("invalid sta_ctx"); 1922 mlo_dev_lock_release(mlo_dev_ctx); 1923 return quiet_status; 1924 } 1925 for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_quiet_status); i++) { 1926 if (sta_ctx->mlo_quiet_status[i].valid_status && 1927 link_id == sta_ctx->mlo_quiet_status[i].link_id) { 1928 quiet_status = 1929 sta_ctx->mlo_quiet_status[i].quiet_status; 1930 break; 1931 } 1932 } 1933 mlo_dev_lock_release(mlo_dev_ctx); 1934 1935 return quiet_status; 1936 } 1937 1938 bool mlo_is_sta_inactivity_allowed_with_quiet(struct wlan_objmgr_psoc *psoc, 1939 uint8_t *vdev_id_list, 1940 uint8_t num_mlo, uint8_t *mlo_idx, 1941 uint8_t affected_links, 1942 uint8_t *affected_list) 1943 { 1944 uint8_t i, j; 1945 struct wlan_objmgr_vdev *vdev; 1946 bool allowed = false; 1947 1948 for (i = 0; i < num_mlo; i++) { 1949 for (j = 0; j < affected_links; j++) { 1950 if (vdev_id_list[mlo_idx[i]] == affected_list[j]) 1951 break; 1952 } 1953 if (j != affected_links) 1954 continue; 1955 /* find vdev not in affected_list */ 1956 vdev = wlan_objmgr_get_vdev_by_id_from_psoc( 1957 psoc, vdev_id_list[mlo_idx[i]], 1958 WLAN_IF_MGR_ID); 1959 if (!vdev) { 1960 mlo_err("invalid vdev for id %d", 1961 vdev_id_list[mlo_idx[i]]); 1962 continue; 1963 } 1964 1965 /* for not affected vdev, check the vdev is in quiet or not*/ 1966 allowed = !mlo_is_sta_in_quiet_status( 1967 vdev->mlo_dev_ctx, wlan_vdev_get_link_id(vdev)); 1968 wlan_objmgr_vdev_release_ref(vdev, WLAN_IF_MGR_ID); 1969 if (allowed) { 1970 mlo_debug("vdev id %d link id %d is not in quiet, allow partner link to trigger inactivity", 1971 wlan_vdev_get_id(vdev), 1972 wlan_vdev_get_link_id(vdev)); 1973 break; 1974 } 1975 } 1976 1977 return allowed; 1978 } 1979 1980 bool mlo_is_sta_csa_synced(struct wlan_mlo_dev_context *mlo_dev_ctx, 1981 uint8_t link_id) 1982 { 1983 struct wlan_mlo_sta *sta_ctx; 1984 int i; 1985 bool sta_csa_synced = false; 1986 1987 if (!mlo_dev_ctx) { 1988 mlo_err("invalid mlo_dev_ctx"); 1989 return sta_csa_synced; 1990 } 1991 1992 mlo_dev_lock_acquire(mlo_dev_ctx); 1993 sta_ctx = mlo_dev_ctx->sta_ctx; 1994 if (!sta_ctx) { 1995 mlo_err("invalid sta_ctx"); 1996 mlo_dev_lock_release(mlo_dev_ctx); 1997 return sta_csa_synced; 1998 } 1999 for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_csa_param); i++) { 2000 if (link_id == sta_ctx->mlo_csa_param[i].link_id && 2001 (sta_ctx->mlo_csa_param[i].valid_csa_param || 2002 sta_ctx->mlo_csa_param[i].mlo_csa_synced)) { 2003 sta_csa_synced = 2004 sta_ctx->mlo_csa_param[i].mlo_csa_synced; 2005 break; 2006 } 2007 } 2008 mlo_dev_lock_release(mlo_dev_ctx); 2009 2010 return sta_csa_synced; 2011 } 2012 2013 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 2014 QDF_STATUS mlo_sta_handle_csa_standby_link( 2015 struct wlan_mlo_dev_context *mlo_dev_ctx, 2016 uint8_t link_id, 2017 struct csa_offload_params *csa_param, 2018 struct wlan_objmgr_vdev *vdev) 2019 { 2020 QDF_STATUS status = QDF_STATUS_SUCCESS; 2021 struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops; 2022 struct mlo_link_info *link_info; 2023 struct mlo_link_bss_params params = {0}; 2024 struct wlan_objmgr_psoc *psoc; 2025 struct wlan_objmgr_pdev *pdev; 2026 2027 if (!mlo_dev_ctx) { 2028 mlo_err("invalid mlo_dev_ctx"); 2029 return QDF_STATUS_E_NULL_VALUE; 2030 } 2031 2032 pdev = wlan_vdev_get_pdev(vdev); 2033 if (!pdev) { 2034 mlo_err("null pdev"); 2035 return QDF_STATUS_E_NULL_VALUE; 2036 } 2037 2038 psoc = wlan_vdev_get_psoc(vdev); 2039 if (!psoc) { 2040 mlo_err("null psoc"); 2041 return QDF_STATUS_E_NULL_VALUE; 2042 } 2043 2044 mlo_tx_ops = &psoc->soc_cb.tx_ops->mlo_ops; 2045 2046 link_info = mlo_mgr_get_ap_link_by_link_id(mlo_dev_ctx, link_id); 2047 if (!link_info) { 2048 mlo_err("link info null"); 2049 return QDF_STATUS_E_NULL_VALUE; 2050 } 2051 2052 if (link_info->vdev_id != WLAN_INVALID_VDEV_ID) { 2053 mlo_debug("vdev id %d link id %d ", link_info->vdev_id, 2054 link_id); 2055 return QDF_STATUS_E_NULL_VALUE; 2056 } 2057 2058 mlo_mgr_update_csa_link_info(pdev, mlo_dev_ctx, csa_param, link_id); 2059 2060 params.link_id = link_info->link_id; 2061 params.chan = qdf_mem_malloc(sizeof(struct wlan_channel)); 2062 if (!params.chan) { 2063 mlo_err("no mem allocated"); 2064 return QDF_STATUS_E_NOMEM; 2065 } 2066 2067 wlan_vdev_get_bss_peer_mld_mac( 2068 vdev, 2069 (struct qdf_mac_addr *)¶ms.ap_mld_mac[0]); 2070 2071 params.chan->ch_freq = link_info->link_chan_info->ch_freq; 2072 params.chan->ch_cfreq1 = link_info->link_chan_info->ch_cfreq1; 2073 params.chan->ch_cfreq2 = link_info->link_chan_info->ch_cfreq2; 2074 params.chan->ch_phymode = link_info->link_chan_info->ch_phymode; 2075 2076 mlo_debug("link id %d chan freq %d cfreq1 %d cfreq2 %d host phymode %d ap mld mac " QDF_MAC_ADDR_FMT, 2077 link_info->link_id, link_info->link_chan_info->ch_freq, 2078 link_info->link_chan_info->ch_cfreq1, 2079 link_info->link_chan_info->ch_cfreq2, 2080 link_info->link_chan_info->ch_phymode, 2081 QDF_MAC_ADDR_REF(¶ms.ap_mld_mac[0])); 2082 2083 if (!mlo_tx_ops->send_link_set_bss_params_cmd) { 2084 mlo_err("handler is not registered"); 2085 qdf_mem_free(params.chan); 2086 return QDF_STATUS_E_NULL_VALUE; 2087 } 2088 2089 status = mlo_tx_ops->send_link_set_bss_params_cmd(psoc, ¶ms); 2090 2091 if (QDF_IS_STATUS_ERROR(status)) { 2092 mlo_err("failed to send link set bss request command to FW"); 2093 qdf_mem_free(params.chan); 2094 return QDF_STATUS_E_NULL_VALUE; 2095 } 2096 qdf_mem_free(params.chan); 2097 return status; 2098 } 2099 2100 static void mlo_sta_handle_link_reconfig_standby_link( 2101 struct wlan_objmgr_vdev *vdev, 2102 struct ml_rv_info *reconfig_info) 2103 { 2104 struct vdev_mlme_obj *vdev_mlme; 2105 2106 vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); 2107 if (!vdev_mlme) 2108 return; 2109 if (vdev_mlme->ops && 2110 vdev_mlme->ops->mlme_vdev_reconfig_notify_standby) { 2111 vdev_mlme->ops->mlme_vdev_reconfig_notify_standby( 2112 vdev_mlme, 2113 reconfig_info); 2114 } 2115 } 2116 #else 2117 static void mlo_sta_handle_link_reconfig_standby_link( 2118 struct wlan_objmgr_vdev *vdev, 2119 struct ml_rv_info *reconfig_info) 2120 { 2121 } 2122 #endif 2123 2124 QDF_STATUS mlo_sta_csa_save_params(struct wlan_mlo_dev_context *mlo_dev_ctx, 2125 uint8_t link_id, 2126 struct csa_offload_params *csa_param) 2127 { 2128 struct wlan_mlo_sta *sta_ctx; 2129 int i; 2130 bool find_free_buffer = false; 2131 int free_idx; 2132 QDF_STATUS status = QDF_STATUS_SUCCESS; 2133 2134 if (!mlo_dev_ctx) { 2135 mlo_err("invalid mlo_dev_ctx"); 2136 status = QDF_STATUS_E_INVAL; 2137 goto done; 2138 } 2139 2140 mlo_dev_lock_acquire(mlo_dev_ctx); 2141 sta_ctx = mlo_dev_ctx->sta_ctx; 2142 if (!sta_ctx) { 2143 mlo_err("invalid sta_ctx"); 2144 status = QDF_STATUS_E_INVAL; 2145 goto rel_lock; 2146 } 2147 for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_csa_param); i++) { 2148 if (!sta_ctx->mlo_csa_param[i].valid_csa_param && 2149 !sta_ctx->mlo_csa_param[i].mlo_csa_synced) { 2150 if (!find_free_buffer) { 2151 free_idx = i; 2152 find_free_buffer = true; 2153 } 2154 } else if (link_id == sta_ctx->mlo_csa_param[i].link_id) { 2155 qdf_mem_copy(&sta_ctx->mlo_csa_param[i].csa_param, 2156 csa_param, sizeof(*csa_param)); 2157 mlo_debug("mld mac " QDF_MAC_ADDR_FMT " link id %d update csa", 2158 QDF_MAC_ADDR_REF(mlo_dev_ctx->mld_addr.bytes), 2159 link_id); 2160 goto rel_lock; 2161 } 2162 } 2163 if (!find_free_buffer) { 2164 mlo_err("no free buffer of csa param for link %d in sta_ctx", 2165 link_id); 2166 status = QDF_STATUS_E_INVAL; 2167 goto rel_lock; 2168 } 2169 qdf_mem_copy(&sta_ctx->mlo_csa_param[free_idx].csa_param, 2170 csa_param, sizeof(*csa_param)); 2171 sta_ctx->mlo_csa_param[free_idx].link_id = link_id; 2172 sta_ctx->mlo_csa_param[free_idx].valid_csa_param = true; 2173 mlo_debug("mld mac " QDF_MAC_ADDR_FMT " link id %d RX csa", 2174 QDF_MAC_ADDR_REF(mlo_dev_ctx->mld_addr.bytes), 2175 link_id); 2176 2177 rel_lock: 2178 mlo_dev_lock_release(mlo_dev_ctx); 2179 2180 done: 2181 2182 return status; 2183 } 2184 2185 QDF_STATUS mlo_sta_up_active_notify(struct wlan_objmgr_vdev *vdev) 2186 { 2187 struct wlan_mlo_sta *sta_ctx; 2188 struct wlan_mlo_dev_context *mlo_dev_ctx; 2189 uint8_t link_id; 2190 int i; 2191 bool find_free_buffer = false; 2192 int free_idx; 2193 struct csa_offload_params csa_param; 2194 struct wlan_channel *chan; 2195 QDF_STATUS status = QDF_STATUS_SUCCESS; 2196 2197 if (!vdev) { 2198 mlo_err("invalid vdev"); 2199 status = QDF_STATUS_E_INVAL; 2200 goto done; 2201 } 2202 link_id = wlan_vdev_get_link_id(vdev); 2203 mlo_dev_ctx = vdev->mlo_dev_ctx; 2204 if (!mlo_dev_ctx) { 2205 mlo_err("invalid mlo_dev_ctx"); 2206 status = QDF_STATUS_E_INVAL; 2207 goto done; 2208 } 2209 mlo_dev_lock_acquire(mlo_dev_ctx); 2210 sta_ctx = mlo_dev_ctx->sta_ctx; 2211 if (!sta_ctx) { 2212 mlo_err("invalid sta_ctx"); 2213 status = QDF_STATUS_E_INVAL; 2214 goto rel_lock; 2215 } 2216 2217 for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_csa_param); i++) { 2218 if (!sta_ctx->mlo_csa_param[i].valid_csa_param && 2219 !sta_ctx->mlo_csa_param[i].mlo_csa_synced) { 2220 if (!find_free_buffer) { 2221 free_idx = i; 2222 find_free_buffer = true; 2223 } 2224 } else if (link_id == sta_ctx->mlo_csa_param[i].link_id) { 2225 if (sta_ctx->mlo_csa_param[i].valid_csa_param && 2226 !sta_ctx->mlo_csa_param[i].mlo_csa_synced) { 2227 mlo_debug("mld mac " QDF_MAC_ADDR_FMT " vdev id %d link id %d handle csa", 2228 QDF_MAC_ADDR_REF( 2229 mlo_dev_ctx->mld_addr.bytes), 2230 wlan_vdev_get_id(vdev), link_id); 2231 csa_param = sta_ctx->mlo_csa_param[i].csa_param; 2232 sta_ctx->mlo_csa_param[i].mlo_csa_synced = true; 2233 mlo_dev_lock_release(mlo_dev_ctx); 2234 chan = wlan_vdev_mlme_get_bss_chan(vdev); 2235 if (csa_param.csa_chan_freq && chan && 2236 csa_param.csa_chan_freq != chan->ch_freq) 2237 mlo_mlme_handle_sta_csa_param( 2238 vdev, &csa_param); 2239 goto done; 2240 } 2241 sta_ctx->mlo_csa_param[i].mlo_csa_synced = true; 2242 goto rel_lock; 2243 } 2244 } 2245 if (!find_free_buffer) { 2246 mlo_err("no free buffer of csa param for link %d in sta_ctx", 2247 link_id); 2248 goto rel_lock; 2249 } 2250 sta_ctx->mlo_csa_param[free_idx].mlo_csa_synced = true; 2251 sta_ctx->mlo_csa_param[free_idx].link_id = link_id; 2252 mlo_debug("mld mac " QDF_MAC_ADDR_FMT " link id %d UP Active", 2253 QDF_MAC_ADDR_REF(mlo_dev_ctx->mld_addr.bytes), 2254 link_id); 2255 2256 rel_lock: 2257 mlo_dev_lock_release(mlo_dev_ctx); 2258 2259 done: 2260 2261 return status; 2262 } 2263 2264 bool mlo_is_sta_csa_param_handled(struct wlan_objmgr_vdev *vdev, 2265 struct csa_offload_params *csa_param) 2266 { 2267 struct wlan_mlo_sta *sta_ctx; 2268 struct wlan_mlo_dev_context *mlo_dev_ctx; 2269 uint8_t link_id; 2270 int i; 2271 bool handled = false; 2272 2273 if (!vdev) { 2274 mlo_err("invalid vdev"); 2275 goto done; 2276 } 2277 link_id = wlan_vdev_get_link_id(vdev); 2278 mlo_dev_ctx = vdev->mlo_dev_ctx; 2279 if (!mlo_dev_ctx) { 2280 mlo_err("invalid mlo_dev_ctx"); 2281 goto done; 2282 } 2283 mlo_dev_lock_acquire(mlo_dev_ctx); 2284 sta_ctx = mlo_dev_ctx->sta_ctx; 2285 if (!sta_ctx) { 2286 mlo_err("invalid sta_ctx"); 2287 goto rel_lock; 2288 } 2289 2290 for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_csa_param); i++) { 2291 if (link_id == sta_ctx->mlo_csa_param[i].link_id && 2292 (sta_ctx->mlo_csa_param[i].valid_csa_param || 2293 sta_ctx->mlo_csa_param[i].mlo_csa_synced)) 2294 break; 2295 } 2296 2297 if (i >= QDF_ARRAY_SIZE(sta_ctx->mlo_csa_param)) { 2298 mlo_debug("mlo csa synced does not happen before csa FW event"); 2299 goto rel_lock; 2300 } 2301 if (!sta_ctx->mlo_csa_param[i].csa_offload_event_recvd) { 2302 sta_ctx->mlo_csa_param[i].csa_offload_event_recvd = true; 2303 if (sta_ctx->mlo_csa_param[i].valid_csa_param && 2304 !qdf_mem_cmp(&sta_ctx->mlo_csa_param[i].csa_param, 2305 csa_param, sizeof(*csa_param))) 2306 handled = true; 2307 } 2308 2309 rel_lock: 2310 mlo_dev_lock_release(mlo_dev_ctx); 2311 2312 done: 2313 2314 return handled; 2315 } 2316 2317 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 2318 void mlo_internal_disconnect_links(struct wlan_objmgr_vdev *vdev) 2319 { 2320 struct wlan_mlo_dev_context *mlo_dev_ctx = NULL; 2321 struct wlan_mlo_sta *sta_ctx = NULL; 2322 uint8_t i; 2323 struct wlan_objmgr_vdev *assoc_vdev; 2324 struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS]; 2325 uint16_t vdev_count = 0; 2326 2327 if (!vdev) 2328 return; 2329 2330 if (!wlan_vdev_mlme_is_assoc_sta_vdev(vdev) && 2331 !wlan_mlo_mgr_is_link_switch_on_assoc_vdev(vdev)) { 2332 mlo_debug("Not an assoc vdev, so ignore disconnect req"); 2333 return; 2334 } 2335 2336 mlo_dev_ctx = vdev->mlo_dev_ctx; 2337 if (mlo_dev_ctx) { 2338 sta_ctx = mlo_dev_ctx->sta_ctx; 2339 } else { 2340 mlo_err("Invalid mlo_dev_ctx"); 2341 return; 2342 } 2343 2344 if (sta_ctx) { 2345 mlo_free_copied_conn_req(sta_ctx); 2346 } else { 2347 mlo_err("Invalid sta_ctx"); 2348 return; 2349 } 2350 2351 if (sta_ctx->connect_req) { 2352 wlan_cm_free_connect_req(sta_ctx->connect_req); 2353 sta_ctx->connect_req = NULL; 2354 } 2355 2356 assoc_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx); 2357 if (!assoc_vdev) { 2358 assoc_vdev = wlan_mlo_mgr_link_switch_get_assoc_vdev(vdev); 2359 if (!assoc_vdev) { 2360 mlo_debug("Couldn't get assoc vdev"); 2361 return; 2362 } 2363 mlo_release_vdev_ref(assoc_vdev); 2364 } 2365 2366 mlo_sta_get_vdev_list(vdev, &vdev_count, wlan_vdev_list); 2367 for (i = 0; i < vdev_count; i++) { 2368 if (wlan_vdev_list[i] != assoc_vdev && 2369 (wlan_cm_is_vdev_connected(wlan_vdev_list[i]) || 2370 wlan_cm_is_vdev_connecting(wlan_vdev_list[i]) || 2371 wlan_cm_is_vdev_idle_due_to_link_switch(wlan_vdev_list[i]))) 2372 wlan_cm_disconnect(wlan_vdev_list[i], 2373 CM_MLO_LINK_VDEV_DISCONNECT, 2374 REASON_UNSPEC_FAILURE, 2375 NULL); 2376 mlo_release_vdev_ref(wlan_vdev_list[i]); 2377 } 2378 } 2379 #else 2380 void mlo_internal_disconnect_links(struct wlan_objmgr_vdev *vdev) 2381 { 2382 } 2383 #endif /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */ 2384 2385 void mlo_sta_get_vdev_list(struct wlan_objmgr_vdev *vdev, uint16_t *vdev_count, 2386 struct wlan_objmgr_vdev **wlan_vdev_list) 2387 { 2388 struct wlan_mlo_dev_context *dev_ctx; 2389 int i; 2390 QDF_STATUS status; 2391 2392 *vdev_count = 0; 2393 2394 if (!vdev || !vdev->mlo_dev_ctx) { 2395 mlo_err("Invalid input"); 2396 return; 2397 } 2398 2399 dev_ctx = vdev->mlo_dev_ctx; 2400 2401 mlo_dev_lock_acquire(dev_ctx); 2402 *vdev_count = 0; 2403 for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) { 2404 if (dev_ctx->wlan_vdev_list[i]) { 2405 status = 2406 wlan_objmgr_vdev_try_get_ref(dev_ctx->wlan_vdev_list[i], 2407 WLAN_MLO_MGR_ID); 2408 if (QDF_IS_STATUS_ERROR(status)) 2409 break; 2410 wlan_vdev_list[*vdev_count] = 2411 dev_ctx->wlan_vdev_list[i]; 2412 (*vdev_count) += 1; 2413 } 2414 } 2415 mlo_dev_lock_release(dev_ctx); 2416 } 2417 2418 bool mlo_sta_vdev_get_reconfig_timer_state(struct wlan_objmgr_vdev *vdev) 2419 { 2420 struct vdev_mlme_obj *vdev_mlme; 2421 2422 if (!vdev || !mlo_is_mld_sta(vdev)) 2423 return false; 2424 2425 vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); 2426 if (!vdev_mlme) { 2427 mlo_err("vdev mlme is null"); 2428 return false; 2429 } 2430 2431 return vdev_mlme->ml_reconfig_started; 2432 } 2433 2434 void mlo_sta_stop_reconfig_timer_by_vdev(struct wlan_objmgr_vdev *vdev) 2435 { 2436 struct vdev_mlme_obj *vdev_mlme; 2437 2438 if (!vdev || !mlo_is_mld_sta(vdev)) 2439 return; 2440 2441 vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); 2442 if (!vdev_mlme) { 2443 mlo_err("vdev mlme is null"); 2444 return; 2445 } 2446 2447 if (!vdev_mlme->ml_reconfig_started) 2448 return; 2449 2450 qdf_timer_stop(&vdev_mlme->ml_reconfig_timer); 2451 2452 mlo_debug("vdev %d reconfig timer active to stop", 2453 wlan_vdev_get_id(vdev)); 2454 vdev_mlme->ml_reconfig_started = false; 2455 } 2456 2457 void mlo_sta_stop_reconfig_timer(struct wlan_objmgr_vdev *vdev) 2458 { 2459 struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS] = {0}; 2460 uint16_t vdev_count = 0; 2461 uint8_t i; 2462 2463 if (!vdev || !mlo_is_mld_sta(vdev)) 2464 return; 2465 2466 mlo_get_ml_vdev_list(vdev, &vdev_count, wlan_vdev_list); 2467 if (!vdev_count) { 2468 mlo_err("vdev num 0 in mld dev"); 2469 return; 2470 } 2471 2472 for (i = 0; i < vdev_count; i++) { 2473 if (!wlan_vdev_list[i]) { 2474 mlo_err("vdev is null in mld"); 2475 goto release_ref; 2476 } 2477 mlo_sta_stop_reconfig_timer_by_vdev(wlan_vdev_list[i]); 2478 } 2479 2480 release_ref: 2481 for (i = 0; i < vdev_count; i++) 2482 mlo_release_vdev_ref(wlan_vdev_list[i]); 2483 } 2484 2485 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 2486 void mlo_defer_set_keys(struct wlan_objmgr_vdev *vdev, 2487 uint8_t link_id, bool value) 2488 { 2489 struct wlan_mlo_sta *sta_ctx; 2490 uint8_t link_iter; 2491 2492 if (!vdev || !vdev->mlo_dev_ctx) 2493 return; 2494 2495 sta_ctx = vdev->mlo_dev_ctx->sta_ctx; 2496 if (!sta_ctx) 2497 return; 2498 if (value) { 2499 for (link_iter = 0; link_iter < WLAN_MAX_ML_BSS_LINKS; 2500 link_iter++) { 2501 if (sta_ctx->key_mgmt[link_iter].keys_saved && 2502 sta_ctx->key_mgmt[link_iter].link_id == link_id) 2503 return; 2504 } 2505 2506 for (link_iter = 0; link_iter < WLAN_MAX_ML_BSS_LINKS; 2507 link_iter++) { 2508 if (!sta_ctx->key_mgmt[link_iter].keys_saved) { 2509 sta_ctx->key_mgmt[link_iter].link_id = link_id; 2510 sta_ctx->key_mgmt[link_iter].keys_saved = true; 2511 mlo_debug("set key link id %d value %d iter %d", 2512 link_id, value, link_iter); 2513 return; 2514 } 2515 } 2516 } else { 2517 for (link_iter = 0; link_iter < WLAN_MAX_ML_BSS_LINKS; 2518 link_iter++) { 2519 if (sta_ctx->key_mgmt[link_iter].link_id == link_id) { 2520 sta_ctx->key_mgmt[link_iter].keys_saved = false; 2521 mlo_debug("set key link id %d value %d iter %d", 2522 link_id, value, link_iter); 2523 return; 2524 } 2525 } 2526 } 2527 } 2528 2529 bool mlo_is_set_key_defered(struct wlan_objmgr_vdev *vdev, 2530 uint8_t link_id) 2531 { 2532 struct wlan_mlo_sta *sta_ctx; 2533 uint8_t link_iter; 2534 2535 if (!vdev || !vdev->mlo_dev_ctx) 2536 return false; 2537 2538 sta_ctx = vdev->mlo_dev_ctx->sta_ctx; 2539 if (!sta_ctx) 2540 return false; 2541 2542 for (link_iter = 0; link_iter < WLAN_MAX_ML_BSS_LINKS; 2543 link_iter++) { 2544 if (sta_ctx->key_mgmt[link_iter].link_id == link_id) 2545 return sta_ctx->key_mgmt[link_iter].keys_saved; 2546 } 2547 return false; 2548 } 2549 #endif 2550 2551 static uint16_t 2552 mlo_get_bcn_interval_by_bssid(struct wlan_objmgr_pdev *pdev, 2553 uint8_t *bssid) 2554 { 2555 struct scan_filter *scan_filter; 2556 uint16_t bcn_int = 0; 2557 qdf_list_t *list = NULL; 2558 struct scan_cache_node *first_node = NULL; 2559 qdf_list_node_t *cur_node = NULL; 2560 2561 scan_filter = qdf_mem_malloc(sizeof(*scan_filter)); 2562 if (!scan_filter) 2563 return bcn_int; 2564 2565 scan_filter->num_of_bssid = 1; 2566 qdf_mem_copy(scan_filter->bssid_list[0].bytes, 2567 bssid, sizeof(struct qdf_mac_addr)); 2568 list = wlan_scan_get_result(pdev, scan_filter); 2569 qdf_mem_free(scan_filter); 2570 2571 if (!list || (list && !qdf_list_size(list))) { 2572 mlo_debug("scan list empty"); 2573 goto error; 2574 } 2575 2576 qdf_list_peek_front(list, &cur_node); 2577 first_node = qdf_container_of(cur_node, 2578 struct scan_cache_node, 2579 node); 2580 if (first_node && first_node->entry) 2581 bcn_int = first_node->entry->bcn_int; 2582 error: 2583 if (list) 2584 wlan_scan_purge_results(list); 2585 2586 return bcn_int; 2587 } 2588 2589 #ifdef QCA_SUPPORT_PRIMARY_LINK_MIGRATE 2590 static QDF_STATUS 2591 mlo_sta_handle_ptqm_migration(struct wlan_objmgr_vdev *removal_vdev) 2592 { 2593 struct wlan_objmgr_peer *bss_peer; 2594 2595 if (!wlan_cm_is_vdev_connected(removal_vdev)) 2596 return QDF_STATUS_E_INVAL; 2597 2598 bss_peer = wlan_vdev_get_bsspeer(removal_vdev); 2599 if (!bss_peer) 2600 return QDF_STATUS_E_INVAL; 2601 2602 /* Invoke migration only if the link being removed is the primary */ 2603 if (wlan_mlo_peer_get_primary_peer_link_id(bss_peer) 2604 != wlan_vdev_get_link_id(removal_vdev)) 2605 return QDF_STATUS_SUCCESS; 2606 2607 return wlan_mlo_set_ptqm_migration(removal_vdev, bss_peer->mlo_peer_ctx, 2608 false, WLAN_LINK_ID_INVALID, true); 2609 } 2610 #else 2611 static QDF_STATUS 2612 mlo_sta_handle_ptqm_migration(struct wlan_objmgr_vdev *removal_vdev) 2613 { 2614 return QDF_STATUS_SUCCESS; 2615 } 2616 #endif 2617 2618 static void mlo_process_link_remove(struct wlan_objmgr_vdev *vdev, 2619 struct ml_rv_partner_link_info *link_info) 2620 { 2621 struct vdev_mlme_obj *vdev_mlme = NULL; 2622 struct wlan_objmgr_peer *bss_peer = NULL; 2623 uint16_t bcn_int = 0; 2624 uint16_t tbtt_count = 0; 2625 QDF_STATUS status; 2626 2627 vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); 2628 if (!vdev_mlme) 2629 return; 2630 2631 bss_peer = wlan_vdev_get_bsspeer(vdev); 2632 if (!bss_peer) 2633 return; 2634 2635 /* Link delete triggered from AP, 2636 * start timer with tbtt count * beacon interval 2637 */ 2638 tbtt_count = link_info->ap_removal_timer; 2639 bcn_int = mlo_get_bcn_interval_by_bssid( 2640 wlan_vdev_get_pdev(vdev), 2641 wlan_peer_get_macaddr(bss_peer)); 2642 if (!bcn_int) 2643 return; 2644 2645 if (vdev_mlme->ops && 2646 vdev_mlme->ops->mlme_vdev_reconfig_notify) { 2647 status = vdev_mlme->ops->mlme_vdev_reconfig_notify( 2648 vdev_mlme, &tbtt_count, bcn_int); 2649 if (QDF_IS_STATUS_ERROR(status)) 2650 return; 2651 } 2652 2653 /* Handle PTQM migration upon seeing AP removal for the first time */ 2654 if (!vdev_mlme->ml_reconfig_started) 2655 mlo_sta_handle_ptqm_migration(vdev); 2656 2657 vdev_mlme->ml_reconfig_started = true; 2658 qdf_timer_mod(&vdev_mlme->ml_reconfig_timer, 2659 qdf_time_uint_to_ms(tbtt_count * bcn_int)); 2660 } 2661 2662 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 2663 static inline 2664 QDF_STATUS mlo_process_link_add(struct wlan_objmgr_psoc *psoc, 2665 struct wlan_objmgr_vdev *vdev, 2666 struct mlo_partner_info *cache_partner_info, 2667 struct mlo_partner_info *partner_info, 2668 uint16_t vdev_count) 2669 { 2670 return QDF_STATUS_E_INVAL; 2671 } 2672 #else 2673 static 2674 QDF_STATUS mlo_process_link_add(struct wlan_objmgr_psoc *psoc, 2675 struct wlan_objmgr_vdev *vdev, 2676 struct mlo_partner_info *cache_partner_info, 2677 struct mlo_partner_info *partner_info, 2678 uint16_t vdev_count) 2679 { 2680 struct wlan_mlo_dev_context *ml_ctx = vdev->mlo_dev_ctx; 2681 2682 /* Check if ini to support dynamic link add is enable 2683 * or not 2684 */ 2685 if (!mlme_mlo_is_reconfig_reassoc_enable(psoc)) { 2686 mlo_debug("ML Reconfig link add support disabled"); 2687 return QDF_STATUS_E_INVAL; 2688 } 2689 2690 if (vdev_count == ml_ctx->wlan_vdev_count) { 2691 /* All links are participating in current ML connection */ 2692 return QDF_STATUS_E_INVAL; 2693 } 2694 2695 /* check if any new link in scan entry */ 2696 if (partner_info->num_partner_links == 2697 cache_partner_info->num_partner_links) { 2698 if (!qdf_mem_cmp(cache_partner_info, partner_info, 2699 sizeof(struct mlo_partner_info))) { 2700 mlo_debug("No new link found"); 2701 return QDF_STATUS_E_INVAL; 2702 } 2703 } 2704 2705 /* mlo connected on all links already */ 2706 if (partner_info->num_partner_links <= (vdev_count - 1)) 2707 return QDF_STATUS_E_INVAL; 2708 2709 /* Partner info changed compared to the cached scan entry. 2710 * Process link add 2711 */ 2712 mlo_err("Link addition detected, issue disconnect"); 2713 mlo_disconnect(vdev, CM_SB_DISCONNECT, 2714 REASON_UNSPEC_FAILURE, NULL); 2715 return QDF_STATUS_SUCCESS; 2716 } 2717 #endif 2718 2719 void mlo_process_ml_reconfig_ie(struct wlan_objmgr_vdev *vdev, 2720 struct scan_cache_entry *scan_entry, 2721 uint8_t *ml_ie, qdf_size_t ml_ie_len, 2722 struct mlo_partner_info *partner_info) 2723 { 2724 struct wlan_objmgr_psoc *psoc = NULL; 2725 struct wlan_objmgr_pdev *pdev = NULL; 2726 struct wlan_objmgr_vdev *co_mld_vdev = NULL; 2727 struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS] = {NULL}; 2728 uint16_t vdev_count = 0; 2729 uint8_t idx = 0; 2730 uint8_t i = 0; 2731 uint8_t link_ix = 0; 2732 struct ml_rv_info reconfig_info = {0}; 2733 struct mlo_partner_info ml_partner_info = {0}; 2734 uint8_t *ml_rv_ie = NULL; 2735 qdf_size_t ml_rv_ie_len = 0; 2736 QDF_STATUS status = QDF_STATUS_SUCCESS; 2737 2738 if (!vdev || !mlo_is_mld_sta(vdev)) 2739 return; 2740 2741 pdev = wlan_vdev_get_pdev(vdev); 2742 if (!pdev) 2743 return; 2744 2745 psoc = wlan_pdev_get_psoc(pdev); 2746 if (!psoc) 2747 return; 2748 2749 mlo_get_ml_vdev_list(vdev, &vdev_count, wlan_vdev_list); 2750 if (!vdev_count) { 2751 mlo_debug("Number of VDEVs under MLD is reported as 0"); 2752 return; 2753 } 2754 2755 if (!scan_entry || 2756 QDF_IS_STATUS_ERROR(util_scan_get_ml_partner_info(scan_entry, 2757 &ml_partner_info))) { 2758 mlo_debug("Unable to fetch the partner info in scan db"); 2759 goto check_ml_rv; 2760 } 2761 2762 /* Processing for link add */ 2763 if (QDF_IS_STATUS_SUCCESS(mlo_process_link_add(psoc, vdev, 2764 partner_info, 2765 &ml_partner_info, 2766 vdev_count))) { 2767 mlo_err("Issued MLD disconnect for link add"); 2768 goto err_release_refs; 2769 } 2770 2771 check_ml_rv: 2772 /* Processing for ML Reconfig IE */ 2773 if (vdev_count == 1) { 2774 /* Single link MLO, no need to process link delete */ 2775 goto err_release_refs; 2776 } 2777 2778 status = util_find_mlie_by_variant(ml_ie, 2779 ml_ie_len, 2780 &ml_rv_ie, 2781 &ml_rv_ie_len, 2782 WLAN_ML_VARIANT_RECONFIG); 2783 if (QDF_IS_STATUS_ERROR(status) || !ml_rv_ie) { 2784 mlo_debug("ML IE for reconfig variant not found"); 2785 goto err_release_refs; 2786 } 2787 2788 status = util_get_rvmlie_persta_link_info(ml_rv_ie, ml_rv_ie_len, 2789 &reconfig_info); 2790 if (QDF_IS_STATUS_ERROR(status)) { 2791 mlo_err("Unable to get persta link info from ML RV IE"); 2792 goto err_release_refs; 2793 } 2794 2795 if (!reconfig_info.num_links) { 2796 mlo_err("No. of links is 0 in ML reconfig IE"); 2797 goto err_release_refs; 2798 } 2799 2800 for (idx = 0; idx < vdev_count; idx++) { 2801 co_mld_vdev = wlan_vdev_list[idx]; 2802 if (!co_mld_vdev) { 2803 mlo_debug("VDEV in MLD VDEV list is NULL"); 2804 goto err_release_refs; 2805 } 2806 2807 link_ix = wlan_vdev_get_link_id(co_mld_vdev); 2808 for (i = 0; i < reconfig_info.num_links; i++) { 2809 if (link_ix == reconfig_info.link_info[i].link_id) 2810 mlo_process_link_remove(co_mld_vdev, 2811 &reconfig_info.link_info[i]); 2812 } 2813 } 2814 2815 mlo_sta_handle_link_reconfig_standby_link(vdev, &reconfig_info); 2816 2817 err_release_refs: 2818 2819 for (i = 0; i < vdev_count; i++) 2820 mlo_release_vdev_ref(wlan_vdev_list[i]); 2821 } 2822 2823 QDF_STATUS 2824 mlo_get_link_state_context(struct wlan_objmgr_psoc *psoc, 2825 get_ml_link_state_cb *resp_cb, 2826 void **context, uint8_t vdev_id) 2827 { 2828 struct wlan_mlo_dev_context *mlo_ctx; 2829 struct wlan_mlo_sta *sta_ctx = NULL; 2830 struct wlan_objmgr_vdev *vdev; 2831 2832 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, 2833 WLAN_MLO_MGR_ID); 2834 if (!vdev) 2835 return QDF_STATUS_E_NULL_VALUE; 2836 2837 if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) { 2838 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 2839 return QDF_STATUS_E_NULL_VALUE; 2840 } 2841 2842 mlo_ctx = vdev->mlo_dev_ctx; 2843 2844 if (!mlo_ctx) { 2845 mlo_err("null mlo_dev_ctx"); 2846 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 2847 return QDF_STATUS_E_NULL_VALUE; 2848 } 2849 2850 sta_ctx = mlo_ctx->sta_ctx; 2851 2852 if (!sta_ctx) { 2853 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 2854 return QDF_STATUS_E_INVAL; 2855 } 2856 2857 mlo_dev_lock_acquire(mlo_ctx); 2858 *resp_cb = sta_ctx->ml_link_state.ml_link_state_resp_cb; 2859 *context = sta_ctx->ml_link_state.ml_link_state_req_context; 2860 2861 mlo_dev_lock_release(mlo_ctx); 2862 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 2863 return QDF_STATUS_SUCCESS; 2864 } 2865 2866 void 2867 wlan_mlo_send_vdev_pause(struct wlan_objmgr_psoc *psoc, 2868 struct wlan_objmgr_vdev *vdev, 2869 uint16_t session_id, 2870 uint16_t vdev_pause_dur) 2871 { 2872 struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops; 2873 struct mlo_vdev_pause vdev_pause_info; 2874 QDF_STATUS status = QDF_STATUS_E_FAILURE; 2875 2876 mlo_tx_ops = &psoc->soc_cb.tx_ops->mlo_ops; 2877 if (!mlo_tx_ops) { 2878 mlo_err("tx_ops is null!"); 2879 return; 2880 } 2881 2882 if (!mlo_tx_ops->send_vdev_pause) { 2883 mlo_err("send_vdev_pause is null"); 2884 return; 2885 } 2886 2887 vdev_pause_info.vdev_id = session_id; 2888 vdev_pause_info.vdev_pause_duration = vdev_pause_dur; 2889 status = mlo_tx_ops->send_vdev_pause(psoc, &vdev_pause_info); 2890 if (QDF_IS_STATUS_ERROR(status)) 2891 mlo_err("Failed to send vdev pause to FW"); 2892 } 2893 2894 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 2895 bool mlo_is_any_link_disconnecting(struct wlan_objmgr_vdev *vdev) 2896 { 2897 struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS]; 2898 uint16_t vdev_count = 0, i; 2899 bool status = false; 2900 2901 if (!vdev) 2902 return status; 2903 2904 mlo_sta_get_vdev_list(vdev, &vdev_count, wlan_vdev_list); 2905 for (i = 0; i < vdev_count; i++) { 2906 if (!status && wlan_cm_is_vdev_disconnecting(wlan_vdev_list[i])) 2907 status = true; 2908 mlo_release_vdev_ref(wlan_vdev_list[i]); 2909 } 2910 2911 return status; 2912 } 2913 2914 QDF_STATUS 2915 mlo_set_chan_switch_in_progress(struct wlan_objmgr_vdev *vdev, bool val) 2916 { 2917 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 2918 2919 if (!mlo_dev_ctx || !mlo_dev_ctx->sta_ctx) 2920 return QDF_STATUS_E_INVAL; 2921 2922 mlo_dev_ctx->sta_ctx->ml_chan_switch_in_progress = val; 2923 mlo_debug("Set ml_chan_switch_in_progress: %d vdev %d", 2924 val, wlan_vdev_get_id(vdev)); 2925 2926 return QDF_STATUS_SUCCESS; 2927 } 2928 2929 bool mlo_is_chan_switch_in_progress(struct wlan_objmgr_vdev *vdev) 2930 { 2931 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 2932 2933 if (!mlo_dev_ctx || !mlo_dev_ctx->sta_ctx) 2934 return false; 2935 2936 return mlo_dev_ctx->sta_ctx->ml_chan_switch_in_progress; 2937 } 2938 #endif 2939 #endif 2940