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