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