1 /* 2 * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 /* 18 * DOC: contains MLO manager roaming related functionality 19 */ 20 #include <wlan_cmn.h> 21 #include <wlan_cm_public_struct.h> 22 #include <wlan_cm_roam_public_struct.h> 23 #include "wlan_mlo_mgr_cmn.h" 24 #include "wlan_mlo_mgr_main.h" 25 #include "wlan_mlo_mgr_roam.h" 26 #include "wlan_mlo_mgr_public_structs.h" 27 #include "wlan_mlo_mgr_sta.h" 28 #include <../../core/src/wlan_cm_roam_i.h> 29 #include "wlan_cm_roam_api.h" 30 #include "wlan_mlme_vdev_mgr_interface.h" 31 #include <include/wlan_mlme_cmn.h> 32 #include <wlan_cm_api.h> 33 #include <utils_mlo.h> 34 #include <wlan_mlo_mgr_peer.h> 35 #include "wlan_mlo_link_force.h" 36 37 #ifdef WLAN_FEATURE_11BE_MLO 38 static bool 39 mlo_check_connect_req_bmap(struct wlan_objmgr_vdev *vdev) 40 { 41 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 42 struct wlan_mlo_sta *sta_ctx; 43 uint8_t i = 0; 44 45 if (!mlo_dev_ctx) 46 return false; 47 48 sta_ctx = mlo_dev_ctx->sta_ctx; 49 50 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 51 if (!mlo_dev_ctx->wlan_vdev_list[i]) 52 continue; 53 54 if (vdev == mlo_dev_ctx->wlan_vdev_list[i]) 55 return qdf_test_bit(i, sta_ctx->wlan_connect_req_links); 56 } 57 58 mlo_err("vdev:%d not found in ml dev ctx list", wlan_vdev_get_id(vdev)); 59 60 return false; 61 } 62 63 static void 64 mlo_update_for_multi_link_roam(struct wlan_objmgr_psoc *psoc, 65 uint8_t vdev_id, 66 uint8_t ml_link_vdev_id) 67 { 68 struct wlan_objmgr_vdev *vdev; 69 70 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, 71 ml_link_vdev_id, 72 WLAN_MLME_SB_ID); 73 if (!vdev) { 74 mlo_err("VDEV is null"); 75 return; 76 } 77 78 if (vdev_id == ml_link_vdev_id) { 79 wlan_vdev_mlme_set_mlo_vdev(vdev); 80 goto end; 81 } 82 83 wlan_vdev_mlme_set_mlo_vdev(vdev); 84 wlan_vdev_mlme_set_mlo_link_vdev(vdev); 85 86 mlo_update_connect_req_links(vdev, true); 87 88 end: 89 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); 90 } 91 92 static void 93 mlo_cleanup_link(struct wlan_objmgr_vdev *vdev, uint8_t num_setup_links) 94 { 95 /* 96 * Cleanup the non-assoc link link in below cases, 97 * 1. Roamed to single link-MLO AP 98 * 2. Roamed to an MLO AP but 4-way handshake is offloaded to 99 * userspace, i.e.auth_status = ROAM_AUTH_STATUS_CONNECTED 100 * 3. Roamed to non-MLO AP(num_setup_links = 0) 101 * This covers all supported combinations. So cleanup the link always. 102 */ 103 if (wlan_vdev_mlme_is_mlo_link_vdev(vdev)) 104 cm_cleanup_mlo_link(vdev); 105 /* 106 * Clear the MLO vdev flag when roam to a non-MLO AP to prepare the 107 * roam done indication to userspace in non-MLO format 108 * i.e. without MLD/link info 109 */ 110 else if (wlan_vdev_mlme_is_mlo_vdev(vdev) && !num_setup_links) 111 wlan_vdev_mlme_clear_mlo_vdev(vdev); 112 } 113 114 static void 115 mlo_update_vdev_after_roam(struct wlan_objmgr_psoc *psoc, 116 uint8_t vdev_id, uint8_t num_setup_links) 117 { 118 struct wlan_mlo_dev_context *mlo_dev_ctx; 119 uint8_t i; 120 struct wlan_objmgr_vdev *vdev, *tmp_vdev; 121 122 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, 123 vdev_id, 124 WLAN_MLME_SB_ID); 125 if (!vdev) { 126 mlo_err("VDEV:%d is null", vdev_id); 127 return; 128 } 129 130 if (!vdev->mlo_dev_ctx) 131 goto end; 132 133 mlo_dev_ctx = vdev->mlo_dev_ctx; 134 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 135 if (!mlo_dev_ctx->wlan_vdev_list[i]) 136 continue; 137 138 tmp_vdev = mlo_dev_ctx->wlan_vdev_list[i]; 139 mlo_cleanup_link(tmp_vdev, num_setup_links); 140 } 141 142 end: 143 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); 144 } 145 146 static void 147 mlo_clear_link_bmap(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) 148 { 149 struct wlan_objmgr_vdev *vdev; 150 151 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, 152 vdev_id, 153 WLAN_MLME_SB_ID); 154 if (!vdev) { 155 mlo_err("VDEV is null"); 156 return; 157 } 158 159 mlo_clear_connect_req_links_bmap(vdev); 160 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); 161 } 162 163 static QDF_STATUS 164 mlo_roam_abort_req(struct wlan_objmgr_psoc *psoc, 165 uint8_t *event, uint8_t vdev_id) 166 { 167 struct roam_offload_synch_ind *sync_ind = NULL; 168 169 sync_ind = (struct roam_offload_synch_ind *)event; 170 171 if (!sync_ind) { 172 mlme_err("Roam Sync ind ptr is NULL"); 173 return QDF_STATUS_E_NULL_VALUE; 174 } 175 176 wlan_mlo_roam_abort_on_link(psoc, event, sync_ind->roamed_vdev_id); 177 178 return QDF_STATUS_SUCCESS; 179 } 180 #else 181 static inline void 182 mlo_clear_link_bmap(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) 183 {} 184 185 static inline void 186 mlo_update_vdev_after_roam(struct wlan_objmgr_psoc *psoc, 187 uint8_t vdev_id, uint8_t num_setup_links) 188 {} 189 190 static inline void 191 mlo_cleanup_link(struct wlan_objmgr_vdev *vdev, uint8_t num_setup_links) 192 {} 193 194 static inline void 195 mlo_update_for_multi_link_roam(struct wlan_objmgr_psoc *psoc, 196 uint8_t vdev_id, 197 uint8_t ml_link_vdev_id) 198 {} 199 200 static inline bool 201 mlo_check_connect_req_bmap(struct wlan_objmgr_vdev *vdev) 202 { 203 return false; 204 } 205 206 static inline QDF_STATUS 207 mlo_roam_abort_req(struct wlan_objmgr_psoc *psoc, 208 uint8_t *event, uint8_t vdev_id) 209 { 210 return QDF_STATUS_E_NOSUPPORT; 211 } 212 #endif 213 214 static void mlo_roam_update_vdev_macaddr(struct wlan_objmgr_psoc *psoc, 215 uint8_t vdev_id, 216 bool is_non_ml_connection) 217 { 218 struct wlan_objmgr_vdev *vdev; 219 struct qdf_mac_addr *mld_mac; 220 221 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, 222 vdev_id, 223 WLAN_MLO_MGR_ID); 224 if (!vdev) { 225 mlo_err("VDEV is null"); 226 return; 227 } 228 229 if (is_non_ml_connection) { 230 mld_mac = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev); 231 if (!qdf_is_macaddr_zero(mld_mac)) 232 wlan_vdev_mlme_set_macaddr(vdev, mld_mac->bytes); 233 } else { 234 wlan_vdev_mlme_set_macaddr(vdev, 235 wlan_vdev_mlme_get_linkaddr(vdev)); 236 } 237 238 mlme_debug("vdev_id %d self mac " QDF_MAC_ADDR_FMT, 239 vdev_id, 240 QDF_MAC_ADDR_REF(wlan_vdev_mlme_get_macaddr(vdev))); 241 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 242 } 243 244 QDF_STATUS mlo_fw_roam_sync_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, 245 void *event, uint32_t event_data_len) 246 { 247 struct roam_offload_synch_ind *sync_ind; 248 QDF_STATUS status; 249 uint8_t i; 250 bool is_non_mlo_ap = false; 251 252 sync_ind = (struct roam_offload_synch_ind *)event; 253 if (!sync_ind) 254 return QDF_STATUS_E_FAILURE; 255 256 for (i = 0; i < sync_ind->num_setup_links; i++) 257 mlo_update_for_multi_link_roam(psoc, vdev_id, 258 sync_ind->ml_link[i].vdev_id); 259 260 if (!sync_ind->num_setup_links) { 261 mlo_debug("MLO_ROAM: Roamed to Legacy"); 262 is_non_mlo_ap = true; 263 mlo_set_single_link_ml_roaming(psoc, vdev_id, false); 264 } else if (sync_ind->num_setup_links == 1 || 265 sync_ind->auth_status == ROAM_AUTH_STATUS_CONNECTED) { 266 mlo_debug("MLO_ROAM: Roamed to single link MLO"); 267 mlo_set_single_link_ml_roaming(psoc, vdev_id, true); 268 } else { 269 mlo_debug("MLO_ROAM: Roamed to MLO with %d links", 270 sync_ind->num_setup_links); 271 mlo_set_single_link_ml_roaming(psoc, vdev_id, false); 272 } 273 274 mlo_roam_update_vdev_macaddr(psoc, vdev_id, is_non_mlo_ap); 275 ml_nlink_conn_change_notify( 276 psoc, vdev_id, ml_nlink_roam_sync_start_evt, NULL); 277 278 status = cm_fw_roam_sync_req(psoc, vdev_id, event, event_data_len); 279 280 if (QDF_IS_STATUS_ERROR(status)) 281 mlo_clear_link_bmap(psoc, vdev_id); 282 283 return status; 284 } 285 286 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 287 QDF_STATUS mlo_cm_roam_sync_cb(struct wlan_objmgr_vdev *vdev, 288 void *event, uint32_t event_data_len) 289 { 290 QDF_STATUS status; 291 struct roam_offload_synch_ind *sync_ind; 292 struct wlan_objmgr_psoc *psoc; 293 struct wlan_objmgr_vdev *link_vdev = NULL; 294 uint8_t i; 295 uint8_t vdev_id; 296 297 sync_ind = (struct roam_offload_synch_ind *)event; 298 vdev_id = wlan_vdev_get_id(vdev); 299 psoc = wlan_vdev_get_psoc(vdev); 300 301 /* Clean up link vdev in following cases 302 * 1. When roamed to legacy, num_setup_links = 0 303 * 2. When roamed to single link, num_setup_links = 1 304 * 3. Roamed to AP with auth_status = ROAMED_AUTH_STATUS_CONNECTED 305 */ 306 if (sync_ind->num_setup_links < 2 || 307 sync_ind->auth_status == ROAM_AUTH_STATUS_CONNECTED) { 308 mlme_debug("Roam auth status %d", sync_ind->auth_status); 309 mlo_update_vdev_after_roam(psoc, vdev_id, 310 sync_ind->num_setup_links); 311 } 312 313 /* If EAPOL is offloaded to supplicant, link vdev/s are not up 314 * at FW, in that case complete roam sync on assoc vdev 315 * link vdev will be initialized after set key is complete. 316 */ 317 if (sync_ind->auth_status == ROAM_AUTH_STATUS_CONNECTED) 318 return QDF_STATUS_SUCCESS; 319 320 for (i = 0; i < sync_ind->num_setup_links; i++) { 321 if (vdev_id == sync_ind->ml_link[i].vdev_id) 322 continue; 323 324 /* Standby Link */ 325 if (sync_ind->ml_link[i].vdev_id == WLAN_INVALID_VDEV_ID) 326 continue; 327 328 link_vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, 329 sync_ind->ml_link[i].vdev_id, 330 WLAN_MLME_SB_ID); 331 if (!link_vdev) { 332 mlo_err("Link vdev:%d is null", 333 sync_ind->ml_link[i].vdev_id); 334 return QDF_STATUS_E_FAILURE; 335 } 336 337 if (mlo_check_connect_req_bmap(link_vdev)) { 338 mlo_update_connect_req_links(link_vdev, false); 339 340 status = cm_fw_roam_sync_req(psoc, 341 sync_ind->ml_link[i].vdev_id, 342 event, event_data_len); 343 if (QDF_IS_STATUS_ERROR(status)) { 344 mlo_clear_connect_req_links_bmap(link_vdev); 345 mlo_roam_abort_req(psoc, event, 346 sync_ind->ml_link[i].vdev_id); 347 wlan_objmgr_vdev_release_ref(link_vdev, 348 WLAN_MLME_SB_ID); 349 return QDF_STATUS_E_FAILURE; 350 } 351 } 352 wlan_objmgr_vdev_release_ref(link_vdev, 353 WLAN_MLME_SB_ID); 354 } 355 356 return QDF_STATUS_SUCCESS; 357 } 358 #endif 359 360 void 361 mlo_fw_ho_fail_req(struct wlan_objmgr_psoc *psoc, 362 uint8_t vdev_id, struct qdf_mac_addr bssid) 363 { 364 struct wlan_objmgr_vdev *vdev; 365 struct wlan_mlo_dev_context *mlo_dev_ctx; 366 uint8_t i; 367 368 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, 369 vdev_id, 370 WLAN_MLME_SB_ID); 371 372 if (!vdev) { 373 mlo_err("vdev is null"); 374 return; 375 } 376 377 if (!vdev->mlo_dev_ctx) 378 goto end; 379 380 mlo_dev_ctx = vdev->mlo_dev_ctx; 381 382 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 383 if (!mlo_dev_ctx->wlan_vdev_list[i] || 384 mlo_dev_ctx->wlan_vdev_list[i] == vdev) 385 continue; 386 cm_fw_ho_fail_req(psoc, 387 wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i]), 388 bssid); 389 } 390 391 end: 392 cm_fw_ho_fail_req(psoc, vdev_id, bssid); 393 wlan_objmgr_vdev_release_ref(vdev, 394 WLAN_MLME_SB_ID); 395 } 396 397 QDF_STATUS 398 mlo_get_sta_link_mac_addr(uint8_t vdev_id, 399 struct roam_offload_synch_ind *sync_ind, 400 struct qdf_mac_addr *link_mac_addr) 401 { 402 QDF_STATUS status = QDF_STATUS_SUCCESS; 403 uint8_t i; 404 405 if (!sync_ind || !sync_ind->num_setup_links) 406 return QDF_STATUS_E_FAILURE; 407 408 for (i = 0; i < sync_ind->num_setup_links; i++) { 409 if (sync_ind->ml_link[i].vdev_id == vdev_id) { 410 qdf_copy_macaddr(link_mac_addr, 411 &sync_ind->ml_link[i].link_addr); 412 return status; 413 } 414 } 415 416 if (i == sync_ind->num_setup_links) { 417 mlo_err("Link mac addr not found"); 418 status = QDF_STATUS_E_FAILURE; 419 } 420 421 return status; 422 } 423 424 uint32_t 425 mlo_roam_get_chan_freq(uint8_t vdev_id, 426 struct roam_offload_synch_ind *sync_ind) 427 { 428 uint8_t i; 429 430 if (!sync_ind || !sync_ind->num_setup_links) 431 return 0; 432 433 for (i = 0; i < sync_ind->num_setup_links; i++) { 434 if (sync_ind->ml_link[i].vdev_id == vdev_id) 435 return sync_ind->ml_link[i].channel.mhz; 436 } 437 438 return 0; 439 } 440 441 uint32_t 442 mlo_roam_get_link_id(uint8_t vdev_id, 443 struct roam_offload_synch_ind *sync_ind) 444 { 445 uint8_t i; 446 447 if (!sync_ind || !sync_ind->num_setup_links) 448 return 0; 449 450 for (i = 0; i < sync_ind->num_setup_links; i++) { 451 if (sync_ind->ml_link[i].vdev_id == vdev_id) 452 return sync_ind->ml_link[i].link_id; 453 } 454 455 return 0; 456 } 457 458 bool is_multi_link_roam(struct roam_offload_synch_ind *sync_ind) 459 { 460 if (!sync_ind) 461 return false; 462 463 if (sync_ind->num_setup_links) 464 return true; 465 466 return false; 467 } 468 469 uint8_t 470 mlo_roam_get_num_of_setup_links(struct roam_offload_synch_ind *sync_ind) 471 { 472 if (!sync_ind) { 473 mlo_err("Roam Sync ind is null"); 474 return WLAN_INVALID_VDEV_ID; 475 } 476 477 return sync_ind->num_setup_links; 478 } 479 480 uint32_t 481 mlo_roam_get_link_freq_from_mac_addr(struct roam_offload_synch_ind *sync_ind, 482 uint8_t *link_mac_addr) 483 { 484 uint8_t i; 485 486 if (!sync_ind) 487 return 0; 488 489 /* Non-MLO roaming */ 490 if (!sync_ind->num_setup_links) 491 return sync_ind->chan_freq; 492 493 if (!link_mac_addr) { 494 mlo_debug("link_mac_addr is NULL"); 495 return 0; 496 } 497 498 for (i = 0; i < sync_ind->num_setup_links; i++) 499 if (!qdf_mem_cmp(sync_ind->ml_link[i].link_addr.bytes, 500 link_mac_addr, 501 QDF_MAC_ADDR_SIZE)) 502 return sync_ind->ml_link[i].channel.mhz; 503 504 mlo_debug("Mac address not found in ml_link info" QDF_MAC_ADDR_FMT, 505 QDF_MAC_ADDR_REF(link_mac_addr)); 506 507 return 0; 508 } 509 510 QDF_STATUS 511 mlo_roam_get_link_id_from_mac_addr(struct roam_offload_synch_ind *sync_ind, 512 uint8_t *link_mac_addr, uint32_t *link_id) 513 { 514 uint8_t i; 515 516 if (!sync_ind || !sync_ind->num_setup_links || !link_mac_addr) 517 return QDF_STATUS_E_INVAL; 518 519 for (i = 0; i < sync_ind->num_setup_links; i++) 520 if (!qdf_mem_cmp(sync_ind->ml_link[i].link_addr.bytes, 521 link_mac_addr, 522 QDF_MAC_ADDR_SIZE)) { 523 *link_id = sync_ind->ml_link[i].link_id; 524 return QDF_STATUS_SUCCESS; 525 } 526 527 return QDF_STATUS_E_INVAL; 528 } 529 530 QDF_STATUS mlo_enable_rso(struct wlan_objmgr_pdev *pdev, 531 struct wlan_objmgr_vdev *vdev, 532 struct wlan_cm_connect_resp *rsp) 533 { 534 struct wlan_objmgr_vdev *assoc_vdev; 535 uint8_t num_partner_links; 536 537 if (!rsp) { 538 mlo_err("Connect resp is null"); 539 return QDF_STATUS_E_NULL_VALUE; 540 } 541 542 num_partner_links = rsp->ml_parnter_info.num_partner_links; 543 544 if (num_partner_links && 545 (!wlan_vdev_mlme_is_mlo_link_vdev(vdev) || 546 !mlo_check_if_all_links_up(vdev))) 547 return QDF_STATUS_SUCCESS; 548 549 assoc_vdev = wlan_mlo_get_assoc_link_vdev(vdev); 550 if (!assoc_vdev) { 551 mlo_err("Assoc vdev is null"); 552 return QDF_STATUS_E_NULL_VALUE; 553 } 554 cm_roam_start_init_on_connect(pdev, wlan_vdev_get_id(assoc_vdev)); 555 556 return QDF_STATUS_SUCCESS; 557 } 558 559 void 560 mlo_roam_copy_partner_info(struct mlo_partner_info *partner_info, 561 struct roam_offload_synch_ind *sync_ind, 562 uint8_t skip_vdev_id, bool fill_all_links) 563 { 564 uint8_t i, j; 565 struct mlo_link_info *link; 566 567 if (!sync_ind) 568 return; 569 570 for (i = 0, j = 0; i < sync_ind->num_setup_links; i++) { 571 if (!fill_all_links && 572 sync_ind->ml_link[i].vdev_id == skip_vdev_id) 573 continue; 574 575 link = &partner_info->partner_link_info[j]; 576 link->link_id = sync_ind->ml_link[i].link_id; 577 link->vdev_id = sync_ind->ml_link[i].vdev_id; 578 579 qdf_copy_macaddr(&link->link_addr, 580 &sync_ind->ml_link[i].link_addr); 581 link->chan_freq = sync_ind->ml_link[i].channel.mhz; 582 mlo_debug("vdev_id %d link_id %d freq %d bssid" QDF_MAC_ADDR_FMT, 583 link->vdev_id, link->link_id, link->chan_freq, 584 QDF_MAC_ADDR_REF(link->link_addr.bytes)); 585 j++; 586 } 587 partner_info->num_partner_links = j; 588 mlo_debug("vdev_to_skip:%d num_setup_links %d fill_all_links:%d", 589 skip_vdev_id, partner_info->num_partner_links, 590 fill_all_links); 591 } 592 593 void mlo_roam_init_cu_bpcc(struct wlan_objmgr_vdev *vdev, 594 struct roam_offload_synch_ind *sync_ind) 595 { 596 uint8_t i; 597 struct wlan_mlo_dev_context *mlo_dev_ctx; 598 599 if (!vdev) { 600 mlo_err("vdev is NULL"); 601 return; 602 } 603 604 mlo_dev_ctx = vdev->mlo_dev_ctx; 605 if (!mlo_dev_ctx) { 606 mlo_err("ML dev ctx is NULL"); 607 return; 608 } 609 610 mlo_clear_cu_bpcc(vdev); 611 for (i = 0; i < sync_ind->num_setup_links; i++) 612 mlo_init_cu_bpcc(mlo_dev_ctx, sync_ind->ml_link[i].vdev_id); 613 614 mlo_debug("update cu info from roam sync"); 615 } 616 617 void 618 mlo_roam_update_connected_links(struct wlan_objmgr_vdev *vdev, 619 struct wlan_cm_connect_resp *connect_rsp) 620 { 621 mlo_clear_connected_links_bmap(vdev); 622 if (mlo_get_single_link_ml_roaming(wlan_vdev_get_psoc(vdev), 623 wlan_vdev_get_id(vdev))) 624 mlo_update_connected_links(vdev, 1); 625 else 626 mlo_update_connected_links_bmap(vdev->mlo_dev_ctx, 627 connect_rsp->ml_parnter_info); 628 } 629 630 QDF_STATUS 631 wlan_mlo_roam_abort_on_link(struct wlan_objmgr_psoc *psoc, 632 uint8_t *event, uint8_t vdev_id) 633 { 634 uint8_t i; 635 QDF_STATUS status; 636 struct roam_offload_synch_ind *sync_ind = NULL; 637 638 sync_ind = (struct roam_offload_synch_ind *)event; 639 640 if (!sync_ind) { 641 mlo_err("Roam Sync ind ptr is NULL"); 642 return QDF_STATUS_E_NULL_VALUE; 643 } 644 645 for (i = 0; i < sync_ind->num_setup_links; i++) { 646 if (sync_ind->ml_link[i].vdev_id != vdev_id) { 647 status = cm_fw_roam_abort_req(psoc, 648 sync_ind->ml_link[i].vdev_id); 649 if (QDF_IS_STATUS_ERROR(status)) { 650 mlo_err("LFR3: Fail to abort roam on vdev: %u", 651 sync_ind->ml_link[i].vdev_id); 652 } 653 } 654 } 655 656 return QDF_STATUS_SUCCESS; 657 } 658 659 void 660 mlo_set_single_link_ml_roaming(struct wlan_objmgr_psoc *psoc, 661 uint8_t vdev_id, 662 bool is_single_link_ml_roaming) 663 { 664 struct wlan_objmgr_vdev *vdev; 665 666 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, 667 vdev_id, 668 WLAN_MLME_SB_ID); 669 if (!vdev) { 670 mlo_err("VDEV is null"); 671 return; 672 } 673 674 if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev)) 675 mlme_set_single_link_mlo_roaming(vdev, 676 is_single_link_ml_roaming); 677 678 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); 679 } 680 681 bool 682 mlo_get_single_link_ml_roaming(struct wlan_objmgr_psoc *psoc, 683 uint8_t vdev_id) 684 { 685 bool is_single_link_ml_roaming = false; 686 struct wlan_objmgr_vdev *vdev; 687 688 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, 689 vdev_id, 690 WLAN_MLME_SB_ID); 691 if (!vdev) { 692 mlo_err("VDEV is null"); 693 return is_single_link_ml_roaming; 694 } 695 696 is_single_link_ml_roaming = mlme_get_single_link_mlo_roaming(vdev); 697 mlo_debug("MLO:is_single_link_ml_roaming %d", 698 is_single_link_ml_roaming); 699 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); 700 701 return is_single_link_ml_roaming; 702 } 703 704 QDF_STATUS 705 mlo_roam_get_bssid_chan_for_link(uint8_t vdev_id, 706 struct roam_offload_synch_ind *sync_ind, 707 struct qdf_mac_addr *bssid, 708 wmi_channel *chan) 709 { 710 QDF_STATUS status = QDF_STATUS_SUCCESS; 711 uint8_t i; 712 713 if (!sync_ind || !sync_ind->num_setup_links) 714 return QDF_STATUS_E_FAILURE; 715 716 for (i = 0; i < sync_ind->num_setup_links; i++) { 717 if (vdev_id == sync_ind->ml_link[i].vdev_id) { 718 qdf_mem_copy(chan, &sync_ind->ml_link[i].channel, 719 sizeof(wmi_channel)); 720 qdf_copy_macaddr(bssid, 721 &sync_ind->ml_link[i].link_addr); 722 return status; 723 } 724 } 725 726 if (i == sync_ind->num_setup_links) { 727 mlo_err("roam sync info not found for vdev id %d", vdev_id); 728 status = QDF_STATUS_E_FAILURE; 729 } 730 731 return status; 732 } 733 734 bool 735 mlo_check_if_all_links_up(struct wlan_objmgr_vdev *vdev) 736 { 737 struct wlan_mlo_dev_context *mlo_dev_ctx; 738 struct wlan_mlo_sta *sta_ctx; 739 uint8_t i; 740 741 if (!vdev || !vdev->mlo_dev_ctx) { 742 mlo_err("Vdev is null"); 743 return false; 744 } 745 746 mlo_dev_ctx = vdev->mlo_dev_ctx; 747 sta_ctx = mlo_dev_ctx->sta_ctx; 748 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 749 if (!mlo_dev_ctx->wlan_vdev_list[i]) 750 continue; 751 752 if (qdf_test_bit(i, sta_ctx->wlan_connected_links) && 753 !wlan_cm_is_vdev_connected(mlo_dev_ctx->wlan_vdev_list[i])) { 754 mlo_debug("Vdev id %d is not in connected state", 755 wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i])); 756 return false; 757 } 758 } 759 760 if (i == WLAN_UMAC_MLO_MAX_VDEVS) { 761 mlo_debug("all links are up"); 762 return true; 763 } 764 765 return false; 766 } 767 768 bool 769 mlo_check_if_all_vdev_up(struct wlan_objmgr_vdev *vdev) 770 { 771 struct wlan_mlo_dev_context *mlo_dev_ctx; 772 struct wlan_mlo_sta *sta_ctx; 773 uint8_t i; 774 775 if (!vdev || !vdev->mlo_dev_ctx) { 776 mlo_err("Vdev is null"); 777 return false; 778 } 779 780 if (QDF_IS_STATUS_ERROR(wlan_vdev_is_up(vdev))) { 781 mlo_debug("Vdev id %d is not in up state", 782 wlan_vdev_get_id(vdev)); 783 return false; 784 } 785 786 mlo_dev_ctx = vdev->mlo_dev_ctx; 787 sta_ctx = mlo_dev_ctx->sta_ctx; 788 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 789 if (!mlo_dev_ctx->wlan_vdev_list[i]) 790 continue; 791 792 if (qdf_test_bit(i, sta_ctx->wlan_connected_links) && 793 !QDF_IS_STATUS_SUCCESS(wlan_vdev_is_up(mlo_dev_ctx->wlan_vdev_list[i]))) { 794 mlo_debug("Vdev id %d is not in up state", 795 wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i])); 796 return false; 797 } 798 } 799 800 if (i == WLAN_UMAC_MLO_MAX_VDEVS) { 801 mlo_debug("all links are up"); 802 return true; 803 } 804 805 return false; 806 } 807 808 void 809 mlo_roam_set_link_id(struct wlan_objmgr_vdev *vdev, 810 struct roam_offload_synch_ind *sync_ind) 811 { 812 uint8_t i; 813 uint8_t j; 814 struct wlan_mlo_dev_context *mlo_dev_ctx; 815 816 if (!vdev || !sync_ind || !vdev->mlo_dev_ctx) { 817 mlo_debug("Invalid input"); 818 return; 819 } 820 821 mlo_dev_ctx = vdev->mlo_dev_ctx; 822 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 823 vdev = mlo_dev_ctx->wlan_vdev_list[i]; 824 if (!vdev) 825 continue; 826 827 wlan_vdev_set_link_id(vdev, WLAN_LINK_ID_INVALID); 828 for (j = 0; j < sync_ind->num_setup_links; j++) { 829 if (sync_ind->ml_link[j].vdev_id == 830 wlan_vdev_get_id(vdev)) { 831 wlan_vdev_set_link_id( 832 vdev, sync_ind->ml_link[j].link_id); 833 mlme_debug("Set link for vdev id %d link id %d", 834 wlan_vdev_get_id(vdev), 835 sync_ind->ml_link[j].link_id); 836 } 837 } 838 } 839 } 840 841 QDF_STATUS 842 mlo_get_link_mac_addr_from_reassoc_rsp(struct wlan_objmgr_vdev *vdev, 843 struct qdf_mac_addr *link_mac_addr) 844 { 845 uint8_t i; 846 struct wlan_mlo_sta *sta_ctx; 847 struct wlan_cm_connect_resp *rsp; 848 struct mlo_partner_info parnter_info; 849 uint8_t vdev_id; 850 851 if (!vdev) 852 return QDF_STATUS_E_NULL_VALUE; 853 854 vdev_id = wlan_vdev_get_id(vdev); 855 856 if (!vdev->mlo_dev_ctx) { 857 mlo_err("mlo dev ctx is null, vdev id %d", vdev_id); 858 return QDF_STATUS_E_NULL_VALUE; 859 } 860 861 sta_ctx = vdev->mlo_dev_ctx->sta_ctx; 862 if (!sta_ctx || !sta_ctx->copied_reassoc_rsp || 863 !sta_ctx->copied_reassoc_rsp->roaming_info) { 864 mlo_debug("sta ctx or copied reassoc rsp is null for vdev id %d", vdev_id); 865 return QDF_STATUS_E_NULL_VALUE; 866 } 867 868 rsp = sta_ctx->copied_reassoc_rsp; 869 if (rsp->roaming_info->auth_status != ROAM_AUTH_STATUS_CONNECTED) { 870 mlo_debug("Roam auth status is not connected"); 871 return QDF_STATUS_E_FAILURE; 872 } 873 874 parnter_info = rsp->ml_parnter_info; 875 for (i = 0; i < parnter_info.num_partner_links; i++) { 876 if (parnter_info.partner_link_info[i].vdev_id == vdev_id) { 877 qdf_copy_macaddr(link_mac_addr, 878 &parnter_info.partner_link_info[i].link_addr); 879 return QDF_STATUS_SUCCESS; 880 } 881 } 882 883 if (i == parnter_info.num_partner_links) { 884 mlo_debug("Link mac addr not found"); 885 return QDF_STATUS_E_FAILURE; 886 } 887 888 return QDF_STATUS_SUCCESS; 889 } 890 891 QDF_STATUS 892 mlo_roam_copy_reassoc_rsp(struct wlan_objmgr_vdev *vdev, 893 struct wlan_cm_connect_resp *reassoc_rsp) 894 { 895 struct wlan_mlo_dev_context *mlo_dev_ctx; 896 struct wlan_mlo_sta *sta_ctx; 897 struct wlan_connect_rsp_ies *connect_ies; 898 899 if (!vdev) 900 return QDF_STATUS_E_NULL_VALUE; 901 902 if (!reassoc_rsp) 903 return QDF_STATUS_E_NULL_VALUE; 904 905 /* Store reassoc rsp only if roamed to 2 link AP */ 906 if (reassoc_rsp->ml_parnter_info.num_partner_links < 2) 907 return QDF_STATUS_E_INVAL; 908 909 mlo_dev_ctx = vdev->mlo_dev_ctx; 910 if (!mlo_dev_ctx) 911 return QDF_STATUS_E_NULL_VALUE; 912 913 sta_ctx = mlo_dev_ctx->sta_ctx; 914 if (!sta_ctx) 915 return QDF_STATUS_E_NULL_VALUE; 916 917 if (sta_ctx) { 918 wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp); 919 920 sta_ctx->copied_reassoc_rsp = qdf_mem_malloc( 921 sizeof(struct wlan_cm_connect_resp)); 922 if (!sta_ctx->copied_reassoc_rsp) 923 return QDF_STATUS_E_NOMEM; 924 925 qdf_mem_copy(sta_ctx->copied_reassoc_rsp, reassoc_rsp, 926 sizeof(struct wlan_cm_connect_resp)); 927 928 sta_ctx->copied_reassoc_rsp->roaming_info = qdf_mem_malloc( 929 sizeof(struct wlan_roam_sync_info)); 930 931 if (!sta_ctx->copied_reassoc_rsp->roaming_info) { 932 qdf_mem_free(sta_ctx->copied_reassoc_rsp); 933 return QDF_STATUS_E_NOMEM; 934 } 935 936 qdf_mem_copy(sta_ctx->copied_reassoc_rsp->roaming_info, 937 reassoc_rsp->roaming_info, 938 sizeof(struct wlan_roam_sync_info)); 939 940 connect_ies = &sta_ctx->copied_reassoc_rsp->connect_ies; 941 942 connect_ies->assoc_rsp.len = 943 reassoc_rsp->connect_ies.assoc_rsp.len; 944 945 connect_ies->assoc_rsp.ptr = qdf_mem_malloc( 946 connect_ies->assoc_rsp.len); 947 948 if (!connect_ies->assoc_rsp.ptr) { 949 qdf_mem_free(sta_ctx->copied_reassoc_rsp->roaming_info); 950 qdf_mem_free(sta_ctx->copied_reassoc_rsp); 951 return QDF_STATUS_E_NOMEM; 952 } 953 954 qdf_mem_copy(connect_ies->assoc_rsp.ptr, 955 reassoc_rsp->connect_ies.assoc_rsp.ptr, 956 reassoc_rsp->connect_ies.assoc_rsp.len); 957 958 connect_ies->assoc_req.len = 0; 959 connect_ies->assoc_req.ptr = NULL; 960 connect_ies->bcn_probe_rsp.len = 0; 961 connect_ies->bcn_probe_rsp.ptr = NULL; 962 connect_ies->link_bcn_probe_rsp.len = 0; 963 connect_ies->link_bcn_probe_rsp.ptr = NULL; 964 connect_ies->fils_ie = NULL; 965 966 mlo_debug("Copied reassoc response"); 967 } 968 969 return QDF_STATUS_SUCCESS; 970 } 971 972 static bool 973 mlo_roam_is_internal_disconnect(struct wlan_objmgr_vdev *link_vdev) 974 { 975 struct wlan_cm_vdev_discon_req *disconn_req; 976 977 if (wlan_vdev_mlme_is_mlo_link_vdev(link_vdev) && 978 wlan_cm_is_vdev_disconnecting(link_vdev)) { 979 mlo_debug("Disconnect is ongoing on vdev %d", 980 wlan_vdev_get_id(link_vdev)); 981 982 disconn_req = qdf_mem_malloc(sizeof(*disconn_req)); 983 if (!disconn_req) { 984 mlme_err("Malloc failed for disconnect req"); 985 return false; 986 } 987 988 if (!wlan_cm_get_active_disconnect_req(link_vdev, 989 disconn_req)) { 990 mlme_err("vdev: %d: Active disconnect not found", 991 wlan_vdev_get_id(link_vdev)); 992 qdf_mem_free(disconn_req); 993 return false; 994 } 995 996 mlo_debug("Disconnect source %d", disconn_req->req.source); 997 998 if (disconn_req->req.source == CM_MLO_ROAM_INTERNAL_DISCONNECT) { 999 qdf_mem_free(disconn_req); 1000 return true; 1001 } 1002 1003 qdf_mem_free(disconn_req); 1004 } 1005 /* Disconnect is not ongoing */ 1006 return true; 1007 } 1008 1009 static QDF_STATUS 1010 mlo_roam_validate_req(struct wlan_objmgr_vdev *vdev, 1011 struct wlan_objmgr_vdev *link_vdev, 1012 struct wlan_cm_connect_resp *rsp) 1013 { 1014 struct wlan_mlo_dev_context *mlo_dev_ctx; 1015 struct wlan_mlo_sta *sta_ctx; 1016 1017 if (!vdev) { 1018 mlo_debug_rl("vdev is NULL"); 1019 return QDF_STATUS_E_NULL_VALUE; 1020 } 1021 1022 mlo_dev_ctx = vdev->mlo_dev_ctx; 1023 if (!mlo_dev_ctx) { 1024 mlo_debug_rl("mlo_dev_ctx is NULL"); 1025 return QDF_STATUS_E_NULL_VALUE; 1026 } 1027 1028 sta_ctx = mlo_dev_ctx->sta_ctx; 1029 if (sta_ctx && sta_ctx->disconn_req) { 1030 mlo_debug("Handle pending disconnect for vdev %d", 1031 wlan_vdev_get_id(vdev)); 1032 mlo_handle_pending_disconnect(vdev); 1033 return QDF_STATUS_E_FAILURE; 1034 } 1035 1036 if (wlan_cm_is_vdev_disconnected(vdev) || 1037 (wlan_vdev_mlme_is_mlo_link_vdev(link_vdev) && 1038 (wlan_cm_is_vdev_connecting(link_vdev) || 1039 !mlo_roam_is_internal_disconnect(link_vdev)))) { 1040 if (sta_ctx) { 1041 if (sta_ctx->copied_reassoc_rsp) { 1042 wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp); 1043 sta_ctx->copied_reassoc_rsp = NULL; 1044 } 1045 copied_conn_req_lock_acquire(sta_ctx); 1046 if (sta_ctx->copied_conn_req) { 1047 wlan_cm_free_connect_req(sta_ctx->copied_conn_req); 1048 sta_ctx->copied_conn_req = NULL; 1049 } 1050 copied_conn_req_lock_release(sta_ctx); 1051 } 1052 } 1053 1054 if (wlan_vdev_mlme_is_mlo_vdev(vdev)) { 1055 mlo_debug("Vdev: %d", wlan_vdev_get_id(vdev)); 1056 if (wlan_cm_is_vdev_disconnected(vdev)) { 1057 mlo_handle_sta_link_connect_failure(vdev, rsp); 1058 return QDF_STATUS_E_FAILURE; 1059 } else if (!wlan_cm_is_vdev_connected(vdev)) { 1060 /* If vdev is not in disconnected or connected state, 1061 * then the event is received due to connect req being 1062 * flushed. Hence, ignore this event 1063 */ 1064 if (sta_ctx && sta_ctx->copied_reassoc_rsp) { 1065 wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp); 1066 sta_ctx->copied_reassoc_rsp = NULL; 1067 } 1068 return QDF_STATUS_E_FAILURE; 1069 } 1070 } 1071 1072 if (wlan_vdev_mlme_is_mlo_link_vdev(link_vdev) && 1073 (wlan_cm_is_vdev_connecting(link_vdev) || 1074 !mlo_roam_is_internal_disconnect(link_vdev))) { 1075 return QDF_STATUS_E_FAILURE; 1076 } 1077 1078 if (sta_ctx && !wlan_vdev_mlme_is_mlo_link_vdev(vdev)) { 1079 if (sta_ctx->assoc_rsp.ptr) { 1080 qdf_mem_free(sta_ctx->assoc_rsp.ptr); 1081 sta_ctx->assoc_rsp.ptr = NULL; 1082 } 1083 sta_ctx->assoc_rsp.len = rsp->connect_ies.assoc_rsp.len; 1084 sta_ctx->assoc_rsp.ptr = 1085 qdf_mem_malloc(rsp->connect_ies.assoc_rsp.len); 1086 if (!sta_ctx->assoc_rsp.ptr) 1087 return QDF_STATUS_E_FAILURE; 1088 if (rsp->connect_ies.assoc_rsp.ptr) 1089 qdf_mem_copy(sta_ctx->assoc_rsp.ptr, 1090 rsp->connect_ies.assoc_rsp.ptr, 1091 rsp->connect_ies.assoc_rsp.len); 1092 /* Update connected_links_bmap for all vdev taking 1093 * part in association 1094 */ 1095 mlo_update_connected_links(vdev, 1); 1096 mlo_update_connected_links_bmap(mlo_dev_ctx, 1097 rsp->ml_parnter_info); 1098 } 1099 1100 return QDF_STATUS_SUCCESS; 1101 } 1102 1103 static QDF_STATUS 1104 mlo_roam_prepare_and_send_link_connect_req(struct wlan_objmgr_vdev *assoc_vdev, 1105 struct wlan_objmgr_vdev *link_vdev, 1106 struct wlan_cm_connect_resp *rsp, 1107 struct qdf_mac_addr *link_addr, 1108 uint16_t chan_freq) 1109 { 1110 struct wlan_mlo_sta *sta_ctx; 1111 struct wlan_cm_connect_req req = {0}; 1112 struct wlan_ssid ssid = {0}; 1113 struct rso_config *rso_cfg; 1114 QDF_STATUS status = QDF_STATUS_SUCCESS; 1115 1116 if (!assoc_vdev || !link_vdev || !rsp) 1117 return QDF_STATUS_E_FAILURE; 1118 1119 if (!assoc_vdev->mlo_dev_ctx || !assoc_vdev->mlo_dev_ctx->sta_ctx) 1120 return QDF_STATUS_E_FAILURE; 1121 1122 sta_ctx = assoc_vdev->mlo_dev_ctx->sta_ctx; 1123 1124 wlan_vdev_mlme_get_ssid(assoc_vdev, ssid.ssid, 1125 &ssid.length); 1126 1127 rso_cfg = wlan_cm_get_rso_config(assoc_vdev); 1128 req.vdev_id = wlan_vdev_get_id(link_vdev); 1129 req.source = CM_MLO_LINK_VDEV_CONNECT; 1130 qdf_mem_copy(&req.bssid.bytes, 1131 link_addr->bytes, 1132 QDF_MAC_ADDR_SIZE); 1133 req.ssid.length = ssid.length; 1134 qdf_mem_copy(&req.ssid.ssid, &ssid.ssid, ssid.length); 1135 req.chan_freq = chan_freq; 1136 1137 req.ml_parnter_info = rsp->ml_parnter_info; 1138 if (rso_cfg) { 1139 req.crypto.rsn_caps = rso_cfg->orig_sec_info.rsn_caps; 1140 req.crypto.auth_type = rso_cfg->orig_sec_info.authmodeset; 1141 req.crypto.ciphers_pairwise = rso_cfg->orig_sec_info.ucastcipherset; 1142 req.crypto.group_cipher = rso_cfg->orig_sec_info.mcastcipherset; 1143 req.crypto.akm_suites = rso_cfg->orig_sec_info.key_mgmt; 1144 req.assoc_ie.len = rso_cfg->assoc_ie.len; 1145 if (rso_cfg->assoc_ie.len) 1146 qdf_mem_copy(&req.assoc_ie.ptr, &rso_cfg->assoc_ie.ptr, 1147 rso_cfg->assoc_ie.len); 1148 } 1149 1150 mlo_debug("vdev_id %d, chan_freq %d, mac_addr " QDF_MAC_ADDR_FMT, 1151 req.vdev_id, req.chan_freq, 1152 QDF_MAC_ADDR_REF(link_addr->bytes)); 1153 1154 mlme_cm_osif_roam_get_scan_params(assoc_vdev, &req.scan_ie, 1155 &req.dot11mode_filter); 1156 1157 copied_conn_req_lock_acquire(sta_ctx); 1158 if (!sta_ctx->copied_conn_req) 1159 sta_ctx->copied_conn_req = qdf_mem_malloc( 1160 sizeof(struct wlan_cm_connect_req)); 1161 else 1162 wlan_cm_free_connect_req_param(sta_ctx->copied_conn_req); 1163 1164 mlo_debug("MLO_ROAM: storing from roam connect rsp to connect req"); 1165 if (sta_ctx->copied_conn_req) { 1166 qdf_mem_copy(sta_ctx->copied_conn_req, &req, 1167 sizeof(struct wlan_cm_connect_req)); 1168 mlo_allocate_and_copy_ies(sta_ctx->copied_conn_req, 1169 &req); 1170 copied_conn_req_lock_release(sta_ctx); 1171 } else { 1172 mlo_err("MLO_ROAM: Failed to allocate connect req"); 1173 copied_conn_req_lock_release(sta_ctx); 1174 return QDF_STATUS_E_NOMEM; 1175 } 1176 1177 status = mlo_roam_validate_req(assoc_vdev, link_vdev, rsp); 1178 if (QDF_IS_STATUS_ERROR(status)) 1179 return status; 1180 1181 mlo_debug("MLO_ROAM: Partner link connect mac:" QDF_MAC_ADDR_FMT " vdev_id:%d", 1182 QDF_MAC_ADDR_REF(req.bssid.bytes), 1183 req.vdev_id); 1184 status = wlan_cm_start_connect(link_vdev, &req); 1185 if (QDF_IS_STATUS_ERROR(status)) 1186 return status; 1187 1188 mlo_update_connected_links(link_vdev, 1); 1189 return status; 1190 } 1191 1192 void mlo_roam_free_copied_reassoc_rsp(struct wlan_objmgr_vdev *vdev) 1193 { 1194 struct wlan_mlo_sta *sta_ctx; 1195 1196 if (!vdev) 1197 return; 1198 1199 if (!vdev->mlo_dev_ctx) 1200 return; 1201 1202 sta_ctx = vdev->mlo_dev_ctx->sta_ctx; 1203 if (!sta_ctx || !sta_ctx->copied_reassoc_rsp || 1204 !sta_ctx->copied_reassoc_rsp->roaming_info) 1205 return; 1206 1207 wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp); 1208 sta_ctx->copied_reassoc_rsp = NULL; 1209 } 1210 1211 void mlo_roam_connect_complete(struct wlan_objmgr_vdev *vdev) 1212 { 1213 struct wlan_mlo_sta *sta_ctx; 1214 uint8_t auth_status; 1215 1216 if (!vdev) 1217 return; 1218 1219 if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev)) 1220 return; 1221 1222 if (!vdev->mlo_dev_ctx) 1223 return; 1224 1225 sta_ctx = vdev->mlo_dev_ctx->sta_ctx; 1226 if (!sta_ctx || !sta_ctx->copied_reassoc_rsp || 1227 !sta_ctx->copied_reassoc_rsp->roaming_info) 1228 return; 1229 1230 auth_status = sta_ctx->copied_reassoc_rsp->roaming_info->auth_status; 1231 if (!mlo_check_connect_req_bmap(vdev) && 1232 auth_status == ROAM_AUTH_STATUS_CONNECTED) { 1233 wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp); 1234 sta_ctx->copied_reassoc_rsp = NULL; 1235 } 1236 } 1237 1238 bool 1239 mlo_roam_is_auth_status_connected(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) 1240 { 1241 bool status = false; 1242 struct wlan_mlo_sta *sta_ctx; 1243 struct wlan_cm_connect_resp *rsp; 1244 struct wlan_objmgr_vdev *vdev; 1245 1246 if (!psoc) 1247 return status; 1248 1249 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, 1250 WLAN_MLME_SB_ID); 1251 if (!vdev) 1252 return status; 1253 1254 if (!vdev->mlo_dev_ctx) 1255 goto end; 1256 1257 sta_ctx = vdev->mlo_dev_ctx->sta_ctx; 1258 if (!sta_ctx || !sta_ctx->copied_reassoc_rsp || 1259 !sta_ctx->copied_reassoc_rsp->roaming_info) 1260 goto end; 1261 1262 rsp = sta_ctx->copied_reassoc_rsp; 1263 if (rsp->roaming_info->auth_status == ROAM_AUTH_STATUS_CONNECTED) 1264 status = true; 1265 1266 end: 1267 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); 1268 return status; 1269 } 1270 1271 QDF_STATUS 1272 mlo_roam_link_connect_notify(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) 1273 { 1274 struct wlan_mlo_sta *sta_ctx = NULL; 1275 struct wlan_cm_connect_resp *rsp; 1276 struct wlan_objmgr_vdev *assoc_vdev; 1277 struct wlan_objmgr_vdev *link_vdev = NULL; 1278 struct wlan_objmgr_vdev *vdev; 1279 struct mlo_partner_info partner_info; 1280 QDF_STATUS status = QDF_STATUS_SUCCESS; 1281 uint8_t i; 1282 uint8_t assoc_vdev_id; 1283 uint8_t link_vdev_id; 1284 1285 if (!psoc) 1286 return QDF_STATUS_E_NULL_VALUE; 1287 1288 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, 1289 WLAN_MLME_SB_ID); 1290 if (!vdev) 1291 return QDF_STATUS_E_NULL_VALUE; 1292 1293 if (!vdev->mlo_dev_ctx) { 1294 mlo_err("mlo dev ctx is null"); 1295 status = QDF_STATUS_E_FAILURE; 1296 goto err; 1297 } 1298 1299 sta_ctx = vdev->mlo_dev_ctx->sta_ctx; 1300 if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) { 1301 mlo_debug("MLO_ROAM: Ignore if not mlo vdev"); 1302 status = QDF_STATUS_E_FAILURE; 1303 goto err; 1304 } 1305 1306 assoc_vdev = wlan_mlo_get_assoc_link_vdev(vdev); 1307 if (!assoc_vdev) { 1308 status = QDF_STATUS_E_NULL_VALUE; 1309 goto err; 1310 } 1311 1312 assoc_vdev_id = wlan_vdev_get_id(assoc_vdev); 1313 if (!sta_ctx || !sta_ctx->copied_reassoc_rsp) { 1314 status = QDF_STATUS_E_NULL_VALUE; 1315 goto err; 1316 } 1317 1318 rsp = sta_ctx->copied_reassoc_rsp; 1319 partner_info = rsp->ml_parnter_info; 1320 mlo_debug("partner links %d", partner_info.num_partner_links); 1321 1322 for (i = 0; i < partner_info.num_partner_links; i++) { 1323 link_vdev_id = partner_info.partner_link_info[i].vdev_id; 1324 if (assoc_vdev_id == link_vdev_id) 1325 continue; 1326 link_vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, 1327 link_vdev_id, 1328 WLAN_MLME_SB_ID); 1329 if (!link_vdev) { 1330 mlo_err("Link vdev is null"); 1331 status = QDF_STATUS_E_NULL_VALUE; 1332 goto err; 1333 } 1334 1335 if (mlo_check_connect_req_bmap(link_vdev)) { 1336 mlo_update_connect_req_links(link_vdev, false); 1337 status = mlo_roam_prepare_and_send_link_connect_req(assoc_vdev, 1338 link_vdev, 1339 rsp, 1340 &partner_info.partner_link_info[i].link_addr, 1341 partner_info.partner_link_info[i].chan_freq); 1342 if (QDF_IS_STATUS_ERROR(status)) 1343 goto err; 1344 else 1345 goto end; 1346 } 1347 } 1348 err: 1349 if (link_vdev) 1350 mlo_clear_connect_req_links_bmap(link_vdev); 1351 if (sta_ctx && sta_ctx->copied_reassoc_rsp) { 1352 wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp); 1353 sta_ctx->copied_reassoc_rsp = NULL; 1354 } 1355 end: 1356 if (link_vdev) 1357 wlan_objmgr_vdev_release_ref(link_vdev, WLAN_MLME_SB_ID); 1358 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); 1359 return status; 1360 } 1361 1362 bool 1363 mlo_is_roaming_in_progress(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) 1364 { 1365 struct wlan_objmgr_vdev *vdev; 1366 struct wlan_mlo_dev_context *mlo_dev_ctx; 1367 bool is_roaming_in_progress = false; 1368 uint8_t link_vdev_id; 1369 uint8_t i; 1370 1371 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, 1372 WLAN_MLME_OBJMGR_ID); 1373 if (!vdev) { 1374 mlme_err("vdev object is NULL for vdev %d", vdev_id); 1375 return false; 1376 } 1377 1378 mlo_dev_ctx = vdev->mlo_dev_ctx; 1379 if (!mlo_dev_ctx) { 1380 mlme_err("mlo_dev_ctx object is NULL for vdev %d", vdev_id); 1381 goto end; 1382 } 1383 1384 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 1385 if (!mlo_dev_ctx->wlan_vdev_list[i]) 1386 continue; 1387 1388 link_vdev_id = wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i]); 1389 if (link_vdev_id == WLAN_INVALID_VDEV_ID) { 1390 mlme_err("invalid vdev id"); 1391 goto end; 1392 } 1393 1394 if (wlan_cm_is_roam_sync_in_progress(psoc, link_vdev_id)) { 1395 is_roaming_in_progress = true; 1396 goto end; 1397 } 1398 } 1399 1400 end: 1401 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); 1402 return is_roaming_in_progress; 1403 } 1404 1405 QDF_STATUS 1406 mlo_add_all_link_probe_rsp_to_scan_db(struct wlan_objmgr_psoc *psoc, 1407 struct roam_scan_candidate_frame *rcvd_frame) 1408 { 1409 uint8_t *ml_ie, link_id, idx, ies_offset; 1410 qdf_size_t ml_ie_total_len, gen_frame_len; 1411 QDF_STATUS status; 1412 struct mlo_partner_info ml_partner_info = {0}; 1413 struct element_info rcvd_probe_rsp, gen_probe_rsp = {0, NULL}; 1414 struct roam_scan_candidate_frame entry = {0}; 1415 struct qdf_mac_addr self_link_addr; 1416 struct wlan_objmgr_vdev *vdev; 1417 1418 /* Add the received scan entry as it is */ 1419 wlan_cm_add_frame_to_scan_db(psoc, rcvd_frame); 1420 1421 ies_offset = WLAN_MAC_HDR_LEN_3A + WLAN_PROBE_RESP_IES_OFFSET; 1422 if (rcvd_frame->frame_length < ies_offset) { 1423 mlme_err("No IEs in probe rsp"); 1424 return QDF_STATUS_E_FAILURE; 1425 } 1426 1427 status = util_find_mlie(rcvd_frame->frame + ies_offset, 1428 rcvd_frame->frame_length - ies_offset, 1429 &ml_ie, &ml_ie_total_len); 1430 if (QDF_IS_STATUS_ERROR(status)) 1431 return QDF_STATUS_SUCCESS; 1432 1433 status = util_get_bvmlie_persta_partner_info(ml_ie, 1434 ml_ie_total_len, 1435 &ml_partner_info); 1436 if (QDF_IS_STATUS_ERROR(status)) { 1437 mlme_err("Per STA profile parsing failed"); 1438 return status; 1439 } 1440 1441 gen_frame_len = MAX_MGMT_MPDU_LEN; 1442 1443 gen_probe_rsp.ptr = qdf_mem_malloc(gen_frame_len); 1444 if (!gen_probe_rsp.ptr) 1445 return QDF_STATUS_E_NOMEM; 1446 1447 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, rcvd_frame->vdev_id, 1448 WLAN_MLME_CM_ID); 1449 if (!vdev) { 1450 mlme_err("vdev object is NULL"); 1451 status = QDF_STATUS_E_NULL_VALUE; 1452 goto done; 1453 } 1454 qdf_mem_copy(self_link_addr.bytes, 1455 wlan_vdev_mlme_get_macaddr(vdev), 1456 QDF_MAC_ADDR_SIZE); 1457 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); 1458 1459 rcvd_probe_rsp.ptr = rcvd_frame->frame + WLAN_MAC_HDR_LEN_3A; 1460 rcvd_probe_rsp.len = rcvd_frame->frame_length - WLAN_MAC_HDR_LEN_3A; 1461 1462 for (idx = 0; idx < ml_partner_info.num_partner_links; idx++) { 1463 link_id = ml_partner_info.partner_link_info[idx].link_id; 1464 status = util_gen_link_probe_rsp(rcvd_probe_rsp.ptr, 1465 rcvd_probe_rsp.len, 1466 link_id, 1467 self_link_addr, 1468 gen_probe_rsp.ptr, 1469 gen_frame_len, 1470 (qdf_size_t *)&gen_probe_rsp.len); 1471 if (QDF_IS_STATUS_ERROR(status)) { 1472 mlme_err("MLO: Link %d probe resp gen failed %d", 1473 link_id, status); 1474 status = QDF_STATUS_E_FAILURE; 1475 goto done; 1476 } 1477 1478 mlme_debug("MLO: link probe rsp size:%u orig probe rsp :%u", 1479 gen_probe_rsp.len, rcvd_probe_rsp.len); 1480 1481 entry.vdev_id = rcvd_frame->vdev_id; 1482 entry.frame = gen_probe_rsp.ptr; 1483 entry.frame_length = gen_probe_rsp.len; 1484 entry.rssi = rcvd_frame->rssi; 1485 1486 wlan_cm_add_frame_to_scan_db(psoc, &entry); 1487 } 1488 done: 1489 qdf_mem_free(gen_probe_rsp.ptr); 1490 1491 return status; 1492 } 1493 1494 bool 1495 mlo_is_enable_roaming_on_connected_sta_allowed(struct wlan_objmgr_vdev *vdev) 1496 { 1497 struct mlo_partner_info *partner_info; 1498 1499 if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev)) 1500 return true; 1501 1502 if (!vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->sta_ctx || 1503 !vdev->mlo_dev_ctx->sta_ctx->copied_reassoc_rsp) 1504 return true; 1505 1506 partner_info = 1507 &vdev->mlo_dev_ctx->sta_ctx->copied_reassoc_rsp->ml_parnter_info; 1508 if (partner_info->num_partner_links <= 1) 1509 return true; 1510 1511 /* Roamed to MLO AP, do nothing if link vdev is disconnected */ 1512 return false; 1513 } 1514