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