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