1 /* 2 * Copyright (c) 2021-2024 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 struct roam_offload_synch_ind *sync_ind, 216 uint8_t vdev_id, 217 bool is_non_ml_connection) 218 { 219 struct wlan_objmgr_vdev *vdev; 220 struct qdf_mac_addr *mld_mac; 221 222 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, 223 vdev_id, 224 WLAN_MLO_MGR_ID); 225 if (!vdev) { 226 mlo_err("VDEV is null"); 227 return; 228 } 229 230 if (is_non_ml_connection) { 231 mld_mac = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev); 232 if (!qdf_is_macaddr_zero(mld_mac)) 233 wlan_vdev_mlme_set_macaddr(vdev, mld_mac->bytes); 234 } else { 235 struct qdf_mac_addr *vdev_link_addr; 236 uint8_t i; 237 238 wlan_vdev_mlme_set_macaddr(vdev, 239 wlan_vdev_mlme_get_linkaddr(vdev)); 240 /* Update the link address received from fw to assoc vdev */ 241 for (i = 0; i < sync_ind->num_setup_links; i++) { 242 if (vdev_id != sync_ind->ml_link[i].vdev_id) 243 continue; 244 245 vdev_link_addr = &sync_ind->ml_link[i].self_link_addr; 246 if (qdf_is_macaddr_zero(vdev_link_addr) || 247 qdf_is_macaddr_broadcast(vdev_link_addr)) 248 continue; 249 250 wlan_vdev_mlme_set_macaddr(vdev, vdev_link_addr->bytes); 251 wlan_vdev_mlme_set_linkaddr(vdev, 252 vdev_link_addr->bytes); 253 } 254 } 255 256 mlme_debug("vdev_id %d self mac " QDF_MAC_ADDR_FMT, 257 vdev_id, 258 QDF_MAC_ADDR_REF(wlan_vdev_mlme_get_macaddr(vdev))); 259 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 260 } 261 262 QDF_STATUS mlo_fw_roam_sync_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, 263 void *event, uint32_t event_data_len) 264 { 265 struct roam_offload_synch_ind *sync_ind; 266 QDF_STATUS status; 267 uint8_t i; 268 bool is_non_mlo_ap = false; 269 270 sync_ind = (struct roam_offload_synch_ind *)event; 271 if (!sync_ind) 272 return QDF_STATUS_E_FAILURE; 273 274 for (i = 0; i < sync_ind->num_setup_links; i++) 275 mlo_update_for_multi_link_roam(psoc, vdev_id, 276 sync_ind->ml_link[i].vdev_id); 277 278 if (!sync_ind->num_setup_links) { 279 mlo_debug("MLO_ROAM: Roamed to Legacy"); 280 is_non_mlo_ap = true; 281 mlo_set_single_link_ml_roaming(psoc, vdev_id, false); 282 } else if (sync_ind->num_setup_links == 1 || 283 sync_ind->auth_status == ROAM_AUTH_STATUS_CONNECTED) { 284 mlo_debug("MLO_ROAM: Roamed to single link MLO"); 285 mlo_set_single_link_ml_roaming(psoc, vdev_id, true); 286 } else { 287 mlo_debug("MLO_ROAM: Roamed to MLO with %d links", 288 sync_ind->num_setup_links); 289 mlo_set_single_link_ml_roaming(psoc, vdev_id, false); 290 } 291 292 mlo_roam_update_vdev_macaddr(psoc, sync_ind, vdev_id, is_non_mlo_ap); 293 ml_nlink_conn_change_notify( 294 psoc, vdev_id, ml_nlink_roam_sync_start_evt, NULL); 295 296 status = cm_fw_roam_sync_req(psoc, vdev_id, event, event_data_len); 297 298 if (QDF_IS_STATUS_ERROR(status)) 299 mlo_clear_link_bmap(psoc, vdev_id); 300 301 return status; 302 } 303 304 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 305 static struct mlo_link_info * 306 mlo_mgr_get_link_info_by_self_addr(struct wlan_objmgr_vdev *vdev, 307 struct qdf_mac_addr *self_addr) 308 { 309 uint8_t iter; 310 struct mlo_link_info *mlo_link; 311 312 if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->link_ctx || 313 !self_addr || qdf_is_macaddr_zero(self_addr)) 314 return NULL; 315 316 for (iter = 0; iter < WLAN_MAX_ML_BSS_LINKS; iter++) { 317 mlo_link = &vdev->mlo_dev_ctx->link_ctx->links_info[iter]; 318 319 if (qdf_is_macaddr_equal(&mlo_link->link_addr, self_addr)) 320 return mlo_link; 321 } 322 323 return NULL; 324 } 325 326 #ifdef WLAN_FEATURE_ROAM_OFFLOAD 327 uint8_t mlo_mgr_num_roam_links(struct wlan_objmgr_vdev *vdev) 328 { 329 struct wlan_cm_connect_resp *reassoc_rsp; 330 331 if (!vdev->mlo_dev_ctx) 332 return 1; 333 334 if (!vdev->mlo_dev_ctx->sta_ctx) 335 return 0; 336 337 reassoc_rsp = vdev->mlo_dev_ctx->sta_ctx->copied_reassoc_rsp; 338 if (!reassoc_rsp || !reassoc_rsp->roaming_info) 339 return 0; 340 341 return reassoc_rsp->roaming_info->num_setup_links; 342 } 343 #endif 344 345 void mlo_mgr_roam_update_ap_link_info(struct wlan_objmgr_vdev *vdev, 346 struct ml_setup_link_param *src_link_info, 347 struct wlan_channel *channel) 348 { 349 struct mlo_link_info *link_info; 350 351 if (!src_link_info) 352 return; 353 354 link_info = mlo_mgr_get_link_info_by_self_addr(vdev, 355 &src_link_info->self_link_addr); 356 if (!link_info) { 357 mlo_err("No link info found for vdev %d with " QDF_MAC_ADDR_FMT, 358 src_link_info->vdev_id, 359 QDF_MAC_ADDR_REF(src_link_info->self_link_addr.bytes)); 360 QDF_BUG(0); 361 return; 362 } 363 364 if (link_info->vdev_id != src_link_info->vdev_id) { 365 mlo_err("Host(%d)-FW(%d) VDEV-MAC addr mismatch", 366 link_info->vdev_id, src_link_info->vdev_id); 367 QDF_BUG(0); 368 return; 369 } 370 371 link_info->link_id = src_link_info->link_id; 372 qdf_copy_macaddr(&link_info->ap_link_addr, &src_link_info->link_addr); 373 qdf_mem_copy(link_info->link_chan_info, channel, sizeof(*channel)); 374 375 mlo_debug("link_id: %d, vdev_id:%d freq:%d ap_link_addr: "QDF_MAC_ADDR_FMT", self_link_addr: "QDF_MAC_ADDR_FMT, 376 link_info->link_id, link_info->vdev_id, 377 link_info->link_chan_info->ch_freq, 378 QDF_MAC_ADDR_REF(link_info->ap_link_addr.bytes), 379 QDF_MAC_ADDR_REF(link_info->link_addr.bytes)); 380 } 381 382 QDF_STATUS mlo_cm_roam_sync_cb(struct wlan_objmgr_vdev *vdev, 383 void *event, uint32_t event_data_len) 384 { 385 QDF_STATUS status; 386 struct roam_offload_synch_ind *sync_ind; 387 struct wlan_objmgr_psoc *psoc; 388 struct wlan_objmgr_vdev *link_vdev = NULL; 389 uint8_t i; 390 uint8_t vdev_id; 391 392 sync_ind = (struct roam_offload_synch_ind *)event; 393 vdev_id = wlan_vdev_get_id(vdev); 394 psoc = wlan_vdev_get_psoc(vdev); 395 396 /* Clean up link vdev in following cases 397 * 1. When roamed to legacy, num_setup_links = 0 398 * 2. When roamed to single link, num_setup_links = 1 399 * 3. Roamed to AP with auth_status = ROAMED_AUTH_STATUS_CONNECTED 400 */ 401 if (sync_ind->num_setup_links < 2 || 402 sync_ind->auth_status == ROAM_AUTH_STATUS_CONNECTED) { 403 mlme_debug("Roam auth status %d", sync_ind->auth_status); 404 mlo_update_vdev_after_roam(psoc, vdev_id, 405 sync_ind->num_setup_links); 406 } 407 408 /* If EAPOL is offloaded to supplicant, link vdev/s are not up 409 * at FW, in that case complete roam sync on assoc vdev 410 * link vdev will be initialized after set key is complete. 411 */ 412 if (sync_ind->auth_status == ROAM_AUTH_STATUS_CONNECTED) 413 return QDF_STATUS_SUCCESS; 414 415 for (i = 0; i < sync_ind->num_setup_links; i++) { 416 if (vdev_id == sync_ind->ml_link[i].vdev_id) 417 continue; 418 419 /* Standby Link */ 420 if (sync_ind->ml_link[i].vdev_id == WLAN_INVALID_VDEV_ID) 421 continue; 422 423 link_vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, 424 sync_ind->ml_link[i].vdev_id, 425 WLAN_MLME_SB_ID); 426 if (!link_vdev) { 427 mlo_err("Link vdev:%d is null", 428 sync_ind->ml_link[i].vdev_id); 429 return QDF_STATUS_E_FAILURE; 430 } 431 432 if (mlo_check_connect_req_bmap(link_vdev)) { 433 struct qdf_mac_addr *vdev_link_addr; 434 435 mlo_update_connect_req_links(link_vdev, false); 436 437 vdev_link_addr = &sync_ind->ml_link[i].self_link_addr; 438 if (!qdf_is_macaddr_zero(vdev_link_addr) && 439 !qdf_is_macaddr_broadcast(vdev_link_addr)) { 440 wlan_vdev_mlme_set_macaddr(link_vdev, 441 vdev_link_addr->bytes); 442 wlan_vdev_mlme_set_linkaddr(link_vdev, 443 vdev_link_addr->bytes); 444 } 445 446 status = cm_fw_roam_sync_req(psoc, 447 sync_ind->ml_link[i].vdev_id, 448 event, event_data_len); 449 if (QDF_IS_STATUS_ERROR(status)) { 450 mlo_clear_connect_req_links_bmap(link_vdev); 451 mlo_roam_abort_req(psoc, event, 452 sync_ind->ml_link[i].vdev_id); 453 wlan_objmgr_vdev_release_ref(link_vdev, 454 WLAN_MLME_SB_ID); 455 return QDF_STATUS_E_FAILURE; 456 } 457 } 458 wlan_objmgr_vdev_release_ref(link_vdev, 459 WLAN_MLME_SB_ID); 460 } 461 462 return QDF_STATUS_SUCCESS; 463 } 464 #endif 465 466 void 467 mlo_fw_ho_fail_req(struct wlan_objmgr_psoc *psoc, 468 uint8_t vdev_id, struct qdf_mac_addr bssid) 469 { 470 struct wlan_objmgr_vdev *vdev; 471 struct wlan_mlo_dev_context *mlo_dev_ctx; 472 uint8_t i; 473 474 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, 475 vdev_id, 476 WLAN_MLME_SB_ID); 477 478 if (!vdev) { 479 mlo_err("vdev is null"); 480 return; 481 } 482 483 if (!vdev->mlo_dev_ctx) 484 goto end; 485 486 mlo_dev_ctx = vdev->mlo_dev_ctx; 487 488 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 489 if (!mlo_dev_ctx->wlan_vdev_list[i] || 490 mlo_dev_ctx->wlan_vdev_list[i] == vdev) 491 continue; 492 cm_fw_ho_fail_req(psoc, 493 wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i]), 494 bssid); 495 } 496 497 end: 498 cm_fw_ho_fail_req(psoc, vdev_id, bssid); 499 wlan_objmgr_vdev_release_ref(vdev, 500 WLAN_MLME_SB_ID); 501 } 502 503 QDF_STATUS 504 mlo_get_sta_link_mac_addr(uint8_t vdev_id, 505 struct roam_offload_synch_ind *sync_ind, 506 struct qdf_mac_addr *link_mac_addr) 507 { 508 QDF_STATUS status = QDF_STATUS_SUCCESS; 509 uint8_t i; 510 511 if (!sync_ind || !sync_ind->num_setup_links) 512 return QDF_STATUS_E_FAILURE; 513 514 for (i = 0; i < sync_ind->num_setup_links; i++) { 515 if (sync_ind->ml_link[i].vdev_id == vdev_id) { 516 qdf_copy_macaddr(link_mac_addr, 517 &sync_ind->ml_link[i].link_addr); 518 return status; 519 } 520 } 521 522 if (i == sync_ind->num_setup_links) { 523 mlo_err("Link mac addr not found"); 524 status = QDF_STATUS_E_FAILURE; 525 } 526 527 return status; 528 } 529 530 uint32_t 531 mlo_roam_get_chan_freq(uint8_t vdev_id, 532 struct roam_offload_synch_ind *sync_ind) 533 { 534 uint8_t i; 535 536 if (!sync_ind || !sync_ind->num_setup_links) 537 return 0; 538 539 for (i = 0; i < sync_ind->num_setup_links; i++) { 540 if (sync_ind->ml_link[i].vdev_id == vdev_id) 541 return sync_ind->ml_link[i].channel.mhz; 542 } 543 544 return 0; 545 } 546 547 uint32_t 548 mlo_roam_get_link_id(uint8_t vdev_id, 549 struct roam_offload_synch_ind *sync_ind) 550 { 551 uint8_t i; 552 553 if (!sync_ind || !sync_ind->num_setup_links) 554 return 0; 555 556 for (i = 0; i < sync_ind->num_setup_links; i++) { 557 if (sync_ind->ml_link[i].vdev_id == vdev_id) 558 return sync_ind->ml_link[i].link_id; 559 } 560 561 return 0; 562 } 563 564 bool is_multi_link_roam(struct roam_offload_synch_ind *sync_ind) 565 { 566 if (!sync_ind) 567 return false; 568 569 if (sync_ind->num_setup_links) 570 return true; 571 572 return false; 573 } 574 575 uint8_t 576 mlo_roam_get_num_of_setup_links(struct roam_offload_synch_ind *sync_ind) 577 { 578 if (!sync_ind) { 579 mlo_err("Roam Sync ind is null"); 580 return WLAN_INVALID_VDEV_ID; 581 } 582 583 return sync_ind->num_setup_links; 584 } 585 586 uint32_t 587 mlo_roam_get_link_freq_from_mac_addr(struct roam_offload_synch_ind *sync_ind, 588 uint8_t *link_mac_addr) 589 { 590 uint8_t i; 591 592 if (!sync_ind) 593 return 0; 594 595 /* Non-MLO roaming */ 596 if (!sync_ind->num_setup_links) 597 return sync_ind->chan_freq; 598 599 if (!link_mac_addr) { 600 mlo_debug("link_mac_addr is NULL"); 601 return 0; 602 } 603 604 for (i = 0; i < sync_ind->num_setup_links; i++) 605 if (!qdf_mem_cmp(sync_ind->ml_link[i].link_addr.bytes, 606 link_mac_addr, 607 QDF_MAC_ADDR_SIZE)) 608 return sync_ind->ml_link[i].channel.mhz; 609 610 mlo_debug("Mac address not found in ml_link info" QDF_MAC_ADDR_FMT, 611 QDF_MAC_ADDR_REF(link_mac_addr)); 612 613 return 0; 614 } 615 616 QDF_STATUS 617 mlo_roam_get_link_id_from_mac_addr(struct roam_offload_synch_ind *sync_ind, 618 uint8_t *link_mac_addr, uint32_t *link_id) 619 { 620 uint8_t i; 621 622 if (!sync_ind || !sync_ind->num_setup_links || !link_mac_addr) 623 return QDF_STATUS_E_INVAL; 624 625 for (i = 0; i < sync_ind->num_setup_links; i++) 626 if (!qdf_mem_cmp(sync_ind->ml_link[i].link_addr.bytes, 627 link_mac_addr, 628 QDF_MAC_ADDR_SIZE)) { 629 *link_id = sync_ind->ml_link[i].link_id; 630 return QDF_STATUS_SUCCESS; 631 } 632 633 return QDF_STATUS_E_INVAL; 634 } 635 636 QDF_STATUS mlo_enable_rso(struct wlan_objmgr_pdev *pdev, 637 struct wlan_objmgr_vdev *vdev, 638 struct wlan_cm_connect_resp *rsp) 639 { 640 struct wlan_objmgr_vdev *assoc_vdev; 641 uint8_t num_partner_links; 642 643 if (!rsp) { 644 mlo_err("Connect resp is null"); 645 return QDF_STATUS_E_NULL_VALUE; 646 } 647 648 num_partner_links = rsp->ml_parnter_info.num_partner_links; 649 650 if (num_partner_links && 651 (!wlan_vdev_mlme_is_mlo_link_vdev(vdev) || 652 !mlo_check_if_all_links_up(vdev))) 653 return QDF_STATUS_SUCCESS; 654 655 assoc_vdev = wlan_mlo_get_assoc_link_vdev(vdev); 656 if (!assoc_vdev) { 657 mlo_err("Assoc vdev is null"); 658 return QDF_STATUS_E_NULL_VALUE; 659 } 660 cm_roam_start_init_on_connect(pdev, wlan_vdev_get_id(assoc_vdev)); 661 662 return QDF_STATUS_SUCCESS; 663 } 664 665 void 666 mlo_roam_copy_partner_info(struct mlo_partner_info *partner_info, 667 struct roam_offload_synch_ind *sync_ind, 668 uint8_t skip_vdev_id, bool fill_all_links) 669 { 670 uint8_t i, j; 671 struct mlo_link_info *link; 672 673 if (!sync_ind) 674 return; 675 676 for (i = 0, j = 0; i < sync_ind->num_setup_links; i++) { 677 if (!fill_all_links && 678 sync_ind->ml_link[i].vdev_id == skip_vdev_id) 679 continue; 680 681 link = &partner_info->partner_link_info[j]; 682 link->link_id = sync_ind->ml_link[i].link_id; 683 link->vdev_id = sync_ind->ml_link[i].vdev_id; 684 685 qdf_copy_macaddr(&link->link_addr, 686 &sync_ind->ml_link[i].link_addr); 687 link->chan_freq = sync_ind->ml_link[i].channel.mhz; 688 mlo_debug("vdev_id %d link_id %d freq %d bssid" QDF_MAC_ADDR_FMT, 689 link->vdev_id, link->link_id, link->chan_freq, 690 QDF_MAC_ADDR_REF(link->link_addr.bytes)); 691 j++; 692 } 693 partner_info->num_partner_links = j; 694 mlo_debug("vdev_to_skip:%d num_setup_links %d fill_all_links:%d", 695 skip_vdev_id, partner_info->num_partner_links, 696 fill_all_links); 697 } 698 699 void mlo_roam_init_cu_bpcc(struct wlan_objmgr_vdev *vdev, 700 struct roam_offload_synch_ind *sync_ind) 701 { 702 uint8_t i; 703 struct wlan_mlo_dev_context *mlo_dev_ctx; 704 705 if (!vdev) { 706 mlo_err("vdev is NULL"); 707 return; 708 } 709 710 mlo_dev_ctx = vdev->mlo_dev_ctx; 711 if (!mlo_dev_ctx) { 712 mlo_err("ML dev ctx is NULL"); 713 return; 714 } 715 716 mlo_clear_cu_bpcc(vdev); 717 for (i = 0; i < sync_ind->num_setup_links; i++) 718 mlo_init_cu_bpcc(mlo_dev_ctx, sync_ind->ml_link[i].vdev_id); 719 720 mlo_debug("update cu info from roam sync"); 721 } 722 723 void 724 mlo_roam_update_connected_links(struct wlan_objmgr_vdev *vdev, 725 struct wlan_cm_connect_resp *connect_rsp) 726 { 727 mlo_clear_connected_links_bmap(vdev); 728 if (mlo_get_single_link_ml_roaming(wlan_vdev_get_psoc(vdev), 729 wlan_vdev_get_id(vdev))) 730 mlo_update_connected_links(vdev, 1); 731 else 732 mlo_update_connected_links_bmap(vdev->mlo_dev_ctx, 733 connect_rsp->ml_parnter_info); 734 } 735 736 QDF_STATUS 737 wlan_mlo_roam_abort_on_link(struct wlan_objmgr_psoc *psoc, 738 uint8_t *event, uint8_t vdev_id) 739 { 740 uint8_t i; 741 QDF_STATUS status; 742 struct roam_offload_synch_ind *sync_ind = NULL; 743 744 sync_ind = (struct roam_offload_synch_ind *)event; 745 746 if (!sync_ind) { 747 mlo_err("Roam Sync ind ptr is NULL"); 748 return QDF_STATUS_E_NULL_VALUE; 749 } 750 751 for (i = 0; i < sync_ind->num_setup_links; i++) { 752 if (sync_ind->ml_link[i].vdev_id != vdev_id) { 753 status = cm_fw_roam_abort_req(psoc, 754 sync_ind->ml_link[i].vdev_id); 755 if (QDF_IS_STATUS_ERROR(status)) { 756 mlo_err("LFR3: Fail to abort roam on vdev: %u", 757 sync_ind->ml_link[i].vdev_id); 758 } 759 } 760 } 761 762 return QDF_STATUS_SUCCESS; 763 } 764 765 void 766 mlo_set_single_link_ml_roaming(struct wlan_objmgr_psoc *psoc, 767 uint8_t vdev_id, 768 bool is_single_link_ml_roaming) 769 { 770 struct wlan_objmgr_vdev *vdev; 771 772 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, 773 vdev_id, 774 WLAN_MLME_SB_ID); 775 if (!vdev) { 776 mlo_err("VDEV is null"); 777 return; 778 } 779 780 if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev)) 781 mlme_set_single_link_mlo_roaming(vdev, 782 is_single_link_ml_roaming); 783 784 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); 785 } 786 787 bool 788 mlo_get_single_link_ml_roaming(struct wlan_objmgr_psoc *psoc, 789 uint8_t vdev_id) 790 { 791 bool is_single_link_ml_roaming = false; 792 struct wlan_objmgr_vdev *vdev; 793 794 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, 795 vdev_id, 796 WLAN_MLME_SB_ID); 797 if (!vdev) { 798 mlo_err("VDEV is null"); 799 return is_single_link_ml_roaming; 800 } 801 802 is_single_link_ml_roaming = mlme_get_single_link_mlo_roaming(vdev); 803 mlo_debug("MLO:is_single_link_ml_roaming %d", 804 is_single_link_ml_roaming); 805 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); 806 807 return is_single_link_ml_roaming; 808 } 809 810 QDF_STATUS 811 mlo_roam_get_bssid_chan_for_link(uint8_t vdev_id, 812 struct roam_offload_synch_ind *sync_ind, 813 struct qdf_mac_addr *bssid, 814 wmi_channel *chan) 815 { 816 QDF_STATUS status = QDF_STATUS_SUCCESS; 817 uint8_t i; 818 819 if (!sync_ind || !sync_ind->num_setup_links) 820 return QDF_STATUS_E_FAILURE; 821 822 for (i = 0; i < sync_ind->num_setup_links; i++) { 823 if (vdev_id == sync_ind->ml_link[i].vdev_id) { 824 qdf_mem_copy(chan, &sync_ind->ml_link[i].channel, 825 sizeof(wmi_channel)); 826 qdf_copy_macaddr(bssid, 827 &sync_ind->ml_link[i].link_addr); 828 return status; 829 } 830 } 831 832 if (i == sync_ind->num_setup_links) { 833 mlo_err("roam sync info not found for vdev id %d", vdev_id); 834 status = QDF_STATUS_E_FAILURE; 835 } 836 837 return status; 838 } 839 840 bool 841 mlo_check_if_all_links_up(struct wlan_objmgr_vdev *vdev) 842 { 843 struct wlan_mlo_dev_context *mlo_dev_ctx; 844 struct wlan_mlo_sta *sta_ctx; 845 uint8_t i; 846 847 if (!vdev || !vdev->mlo_dev_ctx) { 848 mlo_err("Vdev is null"); 849 return false; 850 } 851 852 mlo_dev_ctx = vdev->mlo_dev_ctx; 853 if (!mlo_dev_ctx->sta_ctx) { 854 mlo_err("mlo sta ctx is null"); 855 return false; 856 } 857 858 sta_ctx = mlo_dev_ctx->sta_ctx; 859 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 860 if (!mlo_dev_ctx->wlan_vdev_list[i]) 861 continue; 862 863 if (qdf_test_bit(i, sta_ctx->wlan_connected_links) && 864 !wlan_cm_is_vdev_connected(mlo_dev_ctx->wlan_vdev_list[i])) { 865 mlo_debug("Vdev id %d is not in connected state", 866 wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i])); 867 return false; 868 } 869 } 870 871 if (i == WLAN_UMAC_MLO_MAX_VDEVS) { 872 mlo_debug("all links are up"); 873 return true; 874 } 875 876 return false; 877 } 878 879 bool 880 mlo_check_if_all_vdev_up(struct wlan_objmgr_vdev *vdev) 881 { 882 struct wlan_mlo_dev_context *mlo_dev_ctx; 883 struct wlan_mlo_sta *sta_ctx; 884 uint8_t i; 885 886 if (!vdev || !vdev->mlo_dev_ctx) { 887 mlo_err("Vdev is null"); 888 return false; 889 } 890 891 if (QDF_IS_STATUS_ERROR(wlan_vdev_is_up(vdev))) { 892 mlo_debug("Vdev id %d is not in up state", 893 wlan_vdev_get_id(vdev)); 894 return false; 895 } 896 897 mlo_dev_ctx = vdev->mlo_dev_ctx; 898 if (!mlo_dev_ctx->sta_ctx) { 899 mlo_err("mlo sta ctx is null"); 900 return false; 901 } 902 sta_ctx = mlo_dev_ctx->sta_ctx; 903 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 904 if (!mlo_dev_ctx->wlan_vdev_list[i]) 905 continue; 906 907 if ((qdf_test_bit(i, sta_ctx->wlan_connected_links) || 908 qdf_test_bit(i, sta_ctx->wlan_connect_req_links)) && 909 !QDF_IS_STATUS_SUCCESS(wlan_vdev_is_up(mlo_dev_ctx->wlan_vdev_list[i]))) { 910 mlo_debug("Vdev id %d is not in up state", 911 wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i])); 912 return false; 913 } 914 } 915 916 if (i == WLAN_UMAC_MLO_MAX_VDEVS) { 917 mlo_debug("all links are up"); 918 return true; 919 } 920 921 return false; 922 } 923 924 void 925 mlo_roam_set_link_id(struct wlan_objmgr_vdev *vdev, 926 struct roam_offload_synch_ind *sync_ind) 927 { 928 uint8_t i; 929 uint8_t j; 930 struct wlan_mlo_dev_context *mlo_dev_ctx; 931 932 if (!vdev || !sync_ind || !vdev->mlo_dev_ctx) { 933 mlo_debug("Invalid input"); 934 return; 935 } 936 937 mlo_dev_ctx = vdev->mlo_dev_ctx; 938 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 939 vdev = mlo_dev_ctx->wlan_vdev_list[i]; 940 if (!vdev) 941 continue; 942 943 wlan_vdev_set_link_id(vdev, WLAN_LINK_ID_INVALID); 944 for (j = 0; j < sync_ind->num_setup_links; j++) { 945 if (sync_ind->ml_link[j].vdev_id == 946 wlan_vdev_get_id(vdev)) { 947 wlan_vdev_set_link_id( 948 vdev, sync_ind->ml_link[j].link_id); 949 mlme_debug("Set link for vdev id %d link id %d", 950 wlan_vdev_get_id(vdev), 951 sync_ind->ml_link[j].link_id); 952 } 953 } 954 } 955 } 956 957 QDF_STATUS 958 mlo_get_link_mac_addr_from_reassoc_rsp(struct wlan_objmgr_vdev *vdev, 959 struct qdf_mac_addr *link_mac_addr) 960 { 961 uint8_t i; 962 struct wlan_mlo_sta *sta_ctx; 963 struct wlan_cm_connect_resp *rsp; 964 struct mlo_partner_info parnter_info; 965 uint8_t vdev_id; 966 967 if (!vdev) 968 return QDF_STATUS_E_NULL_VALUE; 969 970 vdev_id = wlan_vdev_get_id(vdev); 971 972 if (!vdev->mlo_dev_ctx) { 973 mlo_err("mlo dev ctx is null, vdev id %d", vdev_id); 974 return QDF_STATUS_E_NULL_VALUE; 975 } 976 977 sta_ctx = vdev->mlo_dev_ctx->sta_ctx; 978 if (!sta_ctx || !sta_ctx->copied_reassoc_rsp || 979 !sta_ctx->copied_reassoc_rsp->roaming_info) { 980 mlo_debug("sta ctx or copied reassoc rsp is null for vdev id %d", vdev_id); 981 return QDF_STATUS_E_NULL_VALUE; 982 } 983 984 rsp = sta_ctx->copied_reassoc_rsp; 985 if (rsp->roaming_info->auth_status != ROAM_AUTH_STATUS_CONNECTED) { 986 mlo_debug("Roam auth status is not connected"); 987 return QDF_STATUS_E_FAILURE; 988 } 989 990 parnter_info = rsp->ml_parnter_info; 991 for (i = 0; i < parnter_info.num_partner_links; i++) { 992 if (parnter_info.partner_link_info[i].vdev_id == vdev_id) { 993 qdf_copy_macaddr(link_mac_addr, 994 &parnter_info.partner_link_info[i].link_addr); 995 return QDF_STATUS_SUCCESS; 996 } 997 } 998 999 if (i == parnter_info.num_partner_links) { 1000 mlo_debug("Link mac addr not found"); 1001 return QDF_STATUS_E_FAILURE; 1002 } 1003 1004 return QDF_STATUS_SUCCESS; 1005 } 1006 1007 QDF_STATUS 1008 mlo_roam_copy_reassoc_rsp(struct wlan_objmgr_vdev *vdev, 1009 struct wlan_cm_connect_resp *reassoc_rsp) 1010 { 1011 struct wlan_mlo_dev_context *mlo_dev_ctx; 1012 struct wlan_mlo_sta *sta_ctx; 1013 struct wlan_connect_rsp_ies *connect_ies; 1014 1015 if (!vdev) 1016 return QDF_STATUS_E_NULL_VALUE; 1017 1018 if (!reassoc_rsp) 1019 return QDF_STATUS_E_NULL_VALUE; 1020 1021 /* Store reassoc rsp only if roamed to 2 link AP */ 1022 if (reassoc_rsp->ml_parnter_info.num_partner_links < 2) 1023 return QDF_STATUS_E_INVAL; 1024 1025 mlo_dev_ctx = vdev->mlo_dev_ctx; 1026 if (!mlo_dev_ctx) 1027 return QDF_STATUS_E_NULL_VALUE; 1028 1029 sta_ctx = mlo_dev_ctx->sta_ctx; 1030 if (!sta_ctx) 1031 return QDF_STATUS_E_NULL_VALUE; 1032 1033 wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp); 1034 /* Free assoc rsp, so that reassoc rsp can be used during 1035 * reassociation. 1036 */ 1037 if (sta_ctx->assoc_rsp.ptr) { 1038 qdf_mem_free(sta_ctx->assoc_rsp.ptr); 1039 sta_ctx->assoc_rsp.ptr = NULL; 1040 sta_ctx->assoc_rsp.len = 0; 1041 } 1042 1043 sta_ctx->ml_partner_info = reassoc_rsp->ml_parnter_info; 1044 1045 sta_ctx->copied_reassoc_rsp = qdf_mem_malloc( 1046 sizeof(struct wlan_cm_connect_resp)); 1047 if (!sta_ctx->copied_reassoc_rsp) 1048 return QDF_STATUS_E_NOMEM; 1049 1050 qdf_mem_copy(sta_ctx->copied_reassoc_rsp, reassoc_rsp, 1051 sizeof(struct wlan_cm_connect_resp)); 1052 1053 sta_ctx->copied_reassoc_rsp->roaming_info = qdf_mem_malloc( 1054 sizeof(struct wlan_roam_sync_info)); 1055 1056 if (!sta_ctx->copied_reassoc_rsp->roaming_info) { 1057 qdf_mem_free(sta_ctx->copied_reassoc_rsp); 1058 sta_ctx->copied_reassoc_rsp = NULL; 1059 return QDF_STATUS_E_NOMEM; 1060 } 1061 1062 qdf_mem_copy(sta_ctx->copied_reassoc_rsp->roaming_info, 1063 reassoc_rsp->roaming_info, 1064 sizeof(struct wlan_roam_sync_info)); 1065 1066 connect_ies = &sta_ctx->copied_reassoc_rsp->connect_ies; 1067 1068 connect_ies->assoc_rsp.len = 1069 reassoc_rsp->connect_ies.assoc_rsp.len; 1070 1071 connect_ies->assoc_rsp.ptr = qdf_mem_malloc( 1072 connect_ies->assoc_rsp.len); 1073 1074 if (!connect_ies->assoc_rsp.ptr) { 1075 qdf_mem_free(sta_ctx->copied_reassoc_rsp->roaming_info); 1076 sta_ctx->copied_reassoc_rsp->roaming_info = NULL; 1077 qdf_mem_free(sta_ctx->copied_reassoc_rsp); 1078 sta_ctx->copied_reassoc_rsp = NULL; 1079 return QDF_STATUS_E_NOMEM; 1080 } 1081 1082 qdf_mem_copy(connect_ies->assoc_rsp.ptr, 1083 reassoc_rsp->connect_ies.assoc_rsp.ptr, 1084 reassoc_rsp->connect_ies.assoc_rsp.len); 1085 1086 connect_ies->assoc_req.len = 0; 1087 connect_ies->assoc_req.ptr = NULL; 1088 connect_ies->bcn_probe_rsp.len = 0; 1089 connect_ies->bcn_probe_rsp.ptr = NULL; 1090 connect_ies->link_bcn_probe_rsp.len = 0; 1091 connect_ies->link_bcn_probe_rsp.ptr = NULL; 1092 connect_ies->fils_ie = NULL; 1093 1094 mlo_debug("Copied reassoc response for vdev: %d len: %d", 1095 wlan_vdev_get_id(vdev), connect_ies->assoc_rsp.len); 1096 1097 return QDF_STATUS_SUCCESS; 1098 } 1099 1100 static bool 1101 mlo_roam_is_internal_disconnect(struct wlan_objmgr_vdev *link_vdev) 1102 { 1103 struct wlan_cm_vdev_discon_req *disconn_req; 1104 1105 if (wlan_vdev_mlme_is_mlo_link_vdev(link_vdev) && 1106 wlan_cm_is_vdev_disconnecting(link_vdev)) { 1107 mlo_debug("Disconnect is ongoing on vdev %d", 1108 wlan_vdev_get_id(link_vdev)); 1109 1110 disconn_req = qdf_mem_malloc(sizeof(*disconn_req)); 1111 if (!disconn_req) { 1112 mlme_err("Malloc failed for disconnect req"); 1113 return false; 1114 } 1115 1116 if (!wlan_cm_get_active_disconnect_req(link_vdev, 1117 disconn_req)) { 1118 mlme_err("vdev: %d: Active disconnect not found", 1119 wlan_vdev_get_id(link_vdev)); 1120 qdf_mem_free(disconn_req); 1121 return false; 1122 } 1123 1124 mlo_debug("Disconnect source %d", disconn_req->req.source); 1125 1126 if (disconn_req->req.source == CM_MLO_ROAM_INTERNAL_DISCONNECT) { 1127 qdf_mem_free(disconn_req); 1128 return true; 1129 } 1130 1131 qdf_mem_free(disconn_req); 1132 } 1133 /* Disconnect is not ongoing */ 1134 return true; 1135 } 1136 1137 static QDF_STATUS 1138 mlo_roam_validate_req(struct wlan_objmgr_vdev *vdev, 1139 struct wlan_objmgr_vdev *link_vdev, 1140 struct wlan_cm_connect_resp *rsp) 1141 { 1142 struct wlan_mlo_dev_context *mlo_dev_ctx; 1143 struct wlan_mlo_sta *sta_ctx; 1144 1145 if (!vdev) { 1146 mlo_debug_rl("vdev is NULL"); 1147 return QDF_STATUS_E_NULL_VALUE; 1148 } 1149 1150 mlo_dev_ctx = vdev->mlo_dev_ctx; 1151 if (!mlo_dev_ctx) { 1152 mlo_debug_rl("mlo_dev_ctx is NULL"); 1153 return QDF_STATUS_E_NULL_VALUE; 1154 } 1155 1156 sta_ctx = mlo_dev_ctx->sta_ctx; 1157 if (sta_ctx && sta_ctx->disconn_req) { 1158 mlo_debug("Handle pending disconnect for vdev %d", 1159 wlan_vdev_get_id(vdev)); 1160 mlo_handle_pending_disconnect(vdev); 1161 return QDF_STATUS_E_FAILURE; 1162 } 1163 1164 if (wlan_cm_is_vdev_disconnected(vdev) || 1165 (wlan_vdev_mlme_is_mlo_link_vdev(link_vdev) && 1166 (wlan_cm_is_vdev_connecting(link_vdev) || 1167 !mlo_roam_is_internal_disconnect(link_vdev)))) { 1168 if (sta_ctx) { 1169 if (sta_ctx->copied_reassoc_rsp) { 1170 wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp); 1171 sta_ctx->copied_reassoc_rsp = NULL; 1172 } 1173 copied_conn_req_lock_acquire(sta_ctx); 1174 if (sta_ctx->copied_conn_req) { 1175 wlan_cm_free_connect_req(sta_ctx->copied_conn_req); 1176 sta_ctx->copied_conn_req = NULL; 1177 } 1178 copied_conn_req_lock_release(sta_ctx); 1179 } 1180 } 1181 1182 if (wlan_vdev_mlme_is_mlo_vdev(vdev)) { 1183 mlo_debug("Vdev: %d", wlan_vdev_get_id(vdev)); 1184 if (wlan_cm_is_vdev_disconnected(vdev)) { 1185 mlo_handle_sta_link_connect_failure(vdev, rsp); 1186 return QDF_STATUS_E_FAILURE; 1187 } else if (!wlan_cm_is_vdev_connected(vdev)) { 1188 /* If vdev is not in disconnected or connected state, 1189 * then the event is received due to connect req being 1190 * flushed. Hence, ignore this event 1191 */ 1192 if (sta_ctx && sta_ctx->copied_reassoc_rsp) { 1193 wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp); 1194 sta_ctx->copied_reassoc_rsp = NULL; 1195 } 1196 return QDF_STATUS_E_FAILURE; 1197 } 1198 } 1199 1200 if (wlan_vdev_mlme_is_mlo_link_vdev(link_vdev) && 1201 (wlan_cm_is_vdev_connecting(link_vdev) || 1202 !mlo_roam_is_internal_disconnect(link_vdev))) { 1203 return QDF_STATUS_E_FAILURE; 1204 } 1205 1206 if (sta_ctx && !wlan_vdev_mlme_is_mlo_link_vdev(vdev)) { 1207 if (sta_ctx->assoc_rsp.ptr) { 1208 qdf_mem_free(sta_ctx->assoc_rsp.ptr); 1209 sta_ctx->assoc_rsp.ptr = NULL; 1210 } 1211 sta_ctx->assoc_rsp.len = rsp->connect_ies.assoc_rsp.len; 1212 sta_ctx->assoc_rsp.ptr = 1213 qdf_mem_malloc(rsp->connect_ies.assoc_rsp.len); 1214 if (!sta_ctx->assoc_rsp.ptr) 1215 return QDF_STATUS_E_FAILURE; 1216 if (rsp->connect_ies.assoc_rsp.ptr) 1217 qdf_mem_copy(sta_ctx->assoc_rsp.ptr, 1218 rsp->connect_ies.assoc_rsp.ptr, 1219 rsp->connect_ies.assoc_rsp.len); 1220 /* Update connected_links_bmap for all vdev taking 1221 * part in association 1222 */ 1223 mlo_update_connected_links(vdev, 1); 1224 mlo_update_connected_links_bmap(mlo_dev_ctx, 1225 rsp->ml_parnter_info); 1226 } 1227 1228 return QDF_STATUS_SUCCESS; 1229 } 1230 1231 static QDF_STATUS 1232 mlo_roam_prepare_and_send_link_connect_req(struct wlan_objmgr_vdev *assoc_vdev, 1233 struct wlan_objmgr_vdev *link_vdev, 1234 struct wlan_cm_connect_resp *rsp, 1235 struct qdf_mac_addr *link_addr, 1236 uint16_t chan_freq) 1237 { 1238 struct wlan_mlo_sta *sta_ctx; 1239 struct wlan_cm_connect_req req = {0}; 1240 struct wlan_ssid ssid = {0}; 1241 struct rso_config *rso_cfg; 1242 QDF_STATUS status = QDF_STATUS_SUCCESS; 1243 1244 if (!assoc_vdev->mlo_dev_ctx || !assoc_vdev->mlo_dev_ctx->sta_ctx) 1245 return QDF_STATUS_E_FAILURE; 1246 1247 sta_ctx = assoc_vdev->mlo_dev_ctx->sta_ctx; 1248 1249 wlan_vdev_mlme_get_ssid(assoc_vdev, ssid.ssid, 1250 &ssid.length); 1251 1252 req.vdev_id = wlan_vdev_get_id(link_vdev); 1253 req.source = CM_MLO_LINK_VDEV_CONNECT; 1254 req.chan_freq = chan_freq; 1255 qdf_mem_copy(&req.bssid.bytes, link_addr->bytes, QDF_MAC_ADDR_SIZE); 1256 1257 req.ssid.length = ssid.length; 1258 qdf_mem_copy(&req.ssid.ssid, &ssid.ssid, ssid.length); 1259 qdf_copy_macaddr(&req.mld_addr, &rsp->mld_addr); 1260 1261 req.ml_parnter_info = rsp->ml_parnter_info; 1262 1263 rso_cfg = wlan_cm_get_rso_config(assoc_vdev); 1264 if (rso_cfg) { 1265 req.crypto.rsn_caps = rso_cfg->orig_sec_info.rsn_caps; 1266 req.crypto.auth_type = rso_cfg->orig_sec_info.authmodeset; 1267 req.crypto.ciphers_pairwise = 1268 rso_cfg->orig_sec_info.ucastcipherset; 1269 req.crypto.group_cipher = rso_cfg->orig_sec_info.mcastcipherset; 1270 req.crypto.mgmt_ciphers = rso_cfg->orig_sec_info.mgmtcipherset; 1271 req.crypto.akm_suites = rso_cfg->orig_sec_info.key_mgmt; 1272 req.assoc_ie.len = rso_cfg->assoc_ie.len; 1273 1274 req.assoc_ie.ptr = qdf_mem_malloc(req.assoc_ie.len); 1275 if (!req.assoc_ie.ptr) 1276 return QDF_STATUS_E_NOMEM; 1277 1278 if (rso_cfg->assoc_ie.len) 1279 qdf_mem_copy(req.assoc_ie.ptr, rso_cfg->assoc_ie.ptr, 1280 rso_cfg->assoc_ie.len); 1281 } 1282 1283 mlme_cm_osif_roam_get_scan_params(assoc_vdev, &req.scan_ie, 1284 &req.dot11mode_filter); 1285 1286 mlme_info("vdev:%d Connecting to " QDF_SSID_FMT " link_addr: " QDF_MAC_ADDR_FMT " freq %d rsn_caps:0x%x auth_type:0x%x pairwise:0x%x grp:0x%x mcast:0x%x akms:0x%x assoc_ie_len:%d f_rsne:%d is_wps:%d dot11_filter:%d", 1287 req.vdev_id, QDF_SSID_REF(req.ssid.length, req.ssid.ssid), 1288 QDF_MAC_ADDR_REF(link_addr->bytes), 1289 req.chan_freq, req.crypto.rsn_caps, req.crypto.auth_type, 1290 req.crypto.ciphers_pairwise, req.crypto.group_cipher, 1291 req.crypto.mgmt_ciphers, req.crypto.akm_suites, 1292 req.assoc_ie.len, req.force_rsne_override, 1293 req.is_wps_connection, req.dot11mode_filter); 1294 1295 copied_conn_req_lock_acquire(sta_ctx); 1296 if (!sta_ctx->copied_conn_req) 1297 sta_ctx->copied_conn_req = 1298 qdf_mem_malloc(sizeof(struct wlan_cm_connect_req)); 1299 else 1300 wlan_cm_free_connect_req_param(sta_ctx->copied_conn_req); 1301 1302 if (!sta_ctx->copied_conn_req) { 1303 mlo_err("MLO_ROAM: vdev:%d Failed to allocate connect req", 1304 req.vdev_id); 1305 copied_conn_req_lock_release(sta_ctx); 1306 status = QDF_STATUS_E_NOMEM; 1307 goto err; 1308 } 1309 1310 qdf_mem_copy(sta_ctx->copied_conn_req, &req, 1311 sizeof(struct wlan_cm_connect_req)); 1312 mlo_allocate_and_copy_ies(sta_ctx->copied_conn_req, &req); 1313 copied_conn_req_lock_release(sta_ctx); 1314 1315 status = mlo_roam_validate_req(assoc_vdev, link_vdev, rsp); 1316 if (QDF_IS_STATUS_ERROR(status)) 1317 goto err; 1318 1319 status = wlan_cm_start_connect(link_vdev, &req); 1320 if (QDF_IS_STATUS_ERROR(status)) 1321 goto err; 1322 1323 mlo_update_connected_links(link_vdev, 1); 1324 err: 1325 qdf_mem_free(req.assoc_ie.ptr); 1326 1327 return status; 1328 } 1329 1330 void mlo_roam_free_copied_reassoc_rsp(struct wlan_objmgr_vdev *vdev) 1331 { 1332 struct wlan_mlo_sta *sta_ctx; 1333 1334 if (!vdev) 1335 return; 1336 1337 if (!vdev->mlo_dev_ctx) 1338 return; 1339 1340 sta_ctx = vdev->mlo_dev_ctx->sta_ctx; 1341 if (!sta_ctx || !sta_ctx->copied_reassoc_rsp || 1342 !sta_ctx->copied_reassoc_rsp->roaming_info) 1343 return; 1344 1345 wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp); 1346 sta_ctx->copied_reassoc_rsp = NULL; 1347 } 1348 1349 void mlo_roam_connect_complete(struct wlan_objmgr_vdev *vdev) 1350 { 1351 struct wlan_mlo_sta *sta_ctx; 1352 uint8_t auth_status; 1353 1354 if (!vdev) 1355 return; 1356 1357 if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev)) 1358 return; 1359 1360 if (!vdev->mlo_dev_ctx) 1361 return; 1362 1363 sta_ctx = vdev->mlo_dev_ctx->sta_ctx; 1364 if (!sta_ctx || !sta_ctx->copied_reassoc_rsp || 1365 !sta_ctx->copied_reassoc_rsp->roaming_info) 1366 return; 1367 1368 auth_status = sta_ctx->copied_reassoc_rsp->roaming_info->auth_status; 1369 if (!mlo_check_connect_req_bmap(vdev) && 1370 auth_status == ROAM_AUTH_STATUS_CONNECTED) { 1371 wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp); 1372 sta_ctx->copied_reassoc_rsp = NULL; 1373 } 1374 } 1375 1376 bool 1377 mlo_roam_is_auth_status_connected(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) 1378 { 1379 bool status = false; 1380 struct wlan_mlo_sta *sta_ctx; 1381 struct wlan_cm_connect_resp *rsp; 1382 struct wlan_objmgr_vdev *vdev; 1383 1384 if (!psoc) 1385 return status; 1386 1387 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, 1388 WLAN_MLME_SB_ID); 1389 if (!vdev) 1390 return status; 1391 1392 if (!vdev->mlo_dev_ctx) 1393 goto end; 1394 1395 sta_ctx = vdev->mlo_dev_ctx->sta_ctx; 1396 if (!sta_ctx || !sta_ctx->copied_reassoc_rsp || 1397 !sta_ctx->copied_reassoc_rsp->roaming_info) 1398 goto end; 1399 1400 rsp = sta_ctx->copied_reassoc_rsp; 1401 if (rsp->roaming_info->auth_status == ROAM_AUTH_STATUS_CONNECTED) 1402 status = true; 1403 1404 end: 1405 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); 1406 return status; 1407 } 1408 1409 QDF_STATUS 1410 mlo_roam_link_connect_notify(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) 1411 { 1412 struct wlan_mlo_sta *sta_ctx = NULL; 1413 struct wlan_cm_connect_resp *rsp; 1414 struct wlan_objmgr_vdev *assoc_vdev; 1415 struct wlan_objmgr_vdev *link_vdev = NULL; 1416 struct wlan_objmgr_vdev *vdev; 1417 struct mlo_partner_info partner_info; 1418 QDF_STATUS status = QDF_STATUS_SUCCESS; 1419 uint8_t i; 1420 uint8_t assoc_vdev_id; 1421 uint8_t link_vdev_id; 1422 1423 if (!psoc) 1424 return QDF_STATUS_E_NULL_VALUE; 1425 1426 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, 1427 WLAN_MLME_SB_ID); 1428 if (!vdev) 1429 return QDF_STATUS_E_NULL_VALUE; 1430 1431 if (!vdev->mlo_dev_ctx) { 1432 mlo_err("mlo dev ctx is null"); 1433 status = QDF_STATUS_E_FAILURE; 1434 goto err; 1435 } 1436 1437 sta_ctx = vdev->mlo_dev_ctx->sta_ctx; 1438 if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) { 1439 mlo_debug("MLO_ROAM: Ignore if not mlo vdev"); 1440 status = QDF_STATUS_E_FAILURE; 1441 goto err; 1442 } 1443 1444 assoc_vdev = wlan_mlo_get_assoc_link_vdev(vdev); 1445 if (!assoc_vdev) { 1446 status = QDF_STATUS_E_NULL_VALUE; 1447 goto err; 1448 } 1449 1450 assoc_vdev_id = wlan_vdev_get_id(assoc_vdev); 1451 if (!sta_ctx || !sta_ctx->copied_reassoc_rsp) { 1452 status = QDF_STATUS_E_NULL_VALUE; 1453 goto err; 1454 } 1455 1456 rsp = sta_ctx->copied_reassoc_rsp; 1457 partner_info = rsp->ml_parnter_info; 1458 mlo_debug("partner links %d", partner_info.num_partner_links); 1459 1460 for (i = 0; i < partner_info.num_partner_links; i++) { 1461 link_vdev_id = partner_info.partner_link_info[i].vdev_id; 1462 if (assoc_vdev_id == link_vdev_id) 1463 continue; 1464 link_vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, 1465 link_vdev_id, 1466 WLAN_MLME_SB_ID); 1467 if (!link_vdev) { 1468 mlo_err("Link vdev is null"); 1469 status = QDF_STATUS_E_NULL_VALUE; 1470 goto err; 1471 } 1472 1473 if (mlo_check_connect_req_bmap(link_vdev)) { 1474 status = mlo_roam_prepare_and_send_link_connect_req(assoc_vdev, 1475 link_vdev, 1476 rsp, 1477 &partner_info.partner_link_info[i].link_addr, 1478 partner_info.partner_link_info[i].chan_freq); 1479 if (QDF_IS_STATUS_ERROR(status)) 1480 goto err; 1481 else { 1482 mlo_update_connect_req_links(link_vdev, false); 1483 goto end; 1484 } 1485 } 1486 } 1487 err: 1488 if (link_vdev) 1489 mlo_clear_connect_req_links_bmap(link_vdev); 1490 if (sta_ctx && sta_ctx->copied_reassoc_rsp) { 1491 wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp); 1492 sta_ctx->copied_reassoc_rsp = NULL; 1493 } 1494 end: 1495 if (link_vdev) 1496 wlan_objmgr_vdev_release_ref(link_vdev, WLAN_MLME_SB_ID); 1497 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); 1498 return status; 1499 } 1500 1501 bool 1502 mlo_is_roaming_in_progress(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) 1503 { 1504 struct wlan_objmgr_vdev *vdev; 1505 struct wlan_mlo_dev_context *mlo_dev_ctx; 1506 bool is_roaming_in_progress = false; 1507 uint8_t link_vdev_id; 1508 uint8_t i; 1509 1510 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, 1511 WLAN_MLME_OBJMGR_ID); 1512 if (!vdev) { 1513 mlme_err("vdev object is NULL for vdev %d", vdev_id); 1514 return false; 1515 } 1516 1517 mlo_dev_ctx = vdev->mlo_dev_ctx; 1518 if (!mlo_dev_ctx) { 1519 mlme_err("mlo_dev_ctx object is NULL for vdev %d", vdev_id); 1520 goto end; 1521 } 1522 1523 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 1524 if (!mlo_dev_ctx->wlan_vdev_list[i]) 1525 continue; 1526 1527 link_vdev_id = wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i]); 1528 if (link_vdev_id == WLAN_INVALID_VDEV_ID) { 1529 mlme_err("invalid vdev id"); 1530 goto end; 1531 } 1532 1533 if (wlan_cm_is_roam_sync_in_progress(psoc, link_vdev_id)) { 1534 is_roaming_in_progress = true; 1535 goto end; 1536 } 1537 } 1538 1539 end: 1540 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); 1541 return is_roaming_in_progress; 1542 } 1543 1544 QDF_STATUS 1545 mlo_add_all_link_probe_rsp_to_scan_db(struct wlan_objmgr_psoc *psoc, 1546 struct roam_scan_candidate_frame *rcvd_frame) 1547 { 1548 uint8_t *ml_ie, link_id, idx, ies_offset; 1549 qdf_size_t ml_ie_total_len, gen_frame_len; 1550 QDF_STATUS status; 1551 struct mlo_partner_info ml_partner_info = {0}; 1552 struct element_info rcvd_probe_rsp, gen_probe_rsp = {0, NULL}; 1553 struct roam_scan_candidate_frame entry = {0}; 1554 struct qdf_mac_addr self_link_addr; 1555 struct wlan_objmgr_vdev *vdev; 1556 1557 /* Add the received scan entry as it is */ 1558 wlan_cm_add_frame_to_scan_db(psoc, rcvd_frame); 1559 1560 ies_offset = WLAN_MAC_HDR_LEN_3A + WLAN_PROBE_RESP_IES_OFFSET; 1561 if (rcvd_frame->frame_length < ies_offset) { 1562 mlme_err("No IEs in probe rsp"); 1563 return QDF_STATUS_E_FAILURE; 1564 } 1565 1566 status = util_find_mlie(rcvd_frame->frame + ies_offset, 1567 rcvd_frame->frame_length - ies_offset, 1568 &ml_ie, &ml_ie_total_len); 1569 if (QDF_IS_STATUS_ERROR(status)) 1570 return QDF_STATUS_SUCCESS; 1571 1572 status = util_get_bvmlie_persta_partner_info(ml_ie, 1573 ml_ie_total_len, 1574 &ml_partner_info); 1575 if (QDF_IS_STATUS_ERROR(status)) { 1576 mlme_err("Per STA profile parsing failed"); 1577 return status; 1578 } 1579 1580 gen_frame_len = MAX_MGMT_MPDU_LEN; 1581 1582 gen_probe_rsp.ptr = qdf_mem_malloc(gen_frame_len); 1583 if (!gen_probe_rsp.ptr) 1584 return QDF_STATUS_E_NOMEM; 1585 1586 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, rcvd_frame->vdev_id, 1587 WLAN_MLME_CM_ID); 1588 if (!vdev) { 1589 mlme_err("vdev object is NULL"); 1590 status = QDF_STATUS_E_NULL_VALUE; 1591 goto done; 1592 } 1593 qdf_mem_copy(self_link_addr.bytes, 1594 wlan_vdev_mlme_get_macaddr(vdev), 1595 QDF_MAC_ADDR_SIZE); 1596 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); 1597 1598 rcvd_probe_rsp.ptr = rcvd_frame->frame + WLAN_MAC_HDR_LEN_3A; 1599 rcvd_probe_rsp.len = rcvd_frame->frame_length - WLAN_MAC_HDR_LEN_3A; 1600 1601 for (idx = 0; idx < ml_partner_info.num_partner_links; idx++) { 1602 link_id = ml_partner_info.partner_link_info[idx].link_id; 1603 status = util_gen_link_probe_rsp(rcvd_probe_rsp.ptr, 1604 rcvd_probe_rsp.len, 1605 link_id, 1606 self_link_addr, 1607 gen_probe_rsp.ptr, 1608 gen_frame_len, 1609 (qdf_size_t *)&gen_probe_rsp.len); 1610 if (QDF_IS_STATUS_ERROR(status)) { 1611 mlme_err("MLO: Link %d probe resp gen failed %d", 1612 link_id, status); 1613 status = QDF_STATUS_E_FAILURE; 1614 goto done; 1615 } 1616 1617 mlme_debug("MLO: link probe rsp size:%u orig probe rsp :%u", 1618 gen_probe_rsp.len, rcvd_probe_rsp.len); 1619 1620 entry.vdev_id = rcvd_frame->vdev_id; 1621 entry.frame = gen_probe_rsp.ptr; 1622 entry.frame_length = gen_probe_rsp.len; 1623 entry.rssi = rcvd_frame->rssi; 1624 1625 wlan_cm_add_frame_to_scan_db(psoc, &entry); 1626 } 1627 done: 1628 qdf_mem_free(gen_probe_rsp.ptr); 1629 1630 return status; 1631 } 1632 1633 bool 1634 mlo_is_enable_roaming_on_connected_sta_allowed(struct wlan_objmgr_vdev *vdev) 1635 { 1636 struct mlo_partner_info *partner_info; 1637 1638 if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev)) 1639 return true; 1640 1641 if (!vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->sta_ctx || 1642 !vdev->mlo_dev_ctx->sta_ctx->copied_reassoc_rsp) 1643 return true; 1644 1645 partner_info = 1646 &vdev->mlo_dev_ctx->sta_ctx->copied_reassoc_rsp->ml_parnter_info; 1647 if (partner_info->num_partner_links <= 1) 1648 return true; 1649 1650 /* Roamed to MLO AP, do nothing if link vdev is disconnected */ 1651 return false; 1652 } 1653 1654 bool 1655 mlo_check_is_given_vdevs_on_same_mld(struct wlan_objmgr_psoc *psoc, 1656 uint8_t vdev_id_1, uint8_t vdev_id_2) 1657 { 1658 struct wlan_objmgr_vdev *vdev1; 1659 struct wlan_mlo_dev_context *ml_dev_ctx1; 1660 struct wlan_objmgr_vdev **vdev_list; 1661 bool is_same_mld = false; 1662 uint8_t i; 1663 1664 vdev1 = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id_1, 1665 WLAN_MLME_CM_ID); 1666 if (!vdev1) 1667 return false; 1668 1669 ml_dev_ctx1 = vdev1->mlo_dev_ctx; 1670 if (!ml_dev_ctx1) 1671 goto end; 1672 1673 vdev_list = ml_dev_ctx1->wlan_vdev_list; 1674 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 1675 if (!vdev_list[i]) 1676 continue; 1677 1678 if (wlan_vdev_get_id(vdev_list[i]) == vdev_id_2) { 1679 is_same_mld = true; 1680 goto end; 1681 } 1682 } 1683 1684 end: 1685 if (vdev1) 1686 wlan_objmgr_vdev_release_ref(vdev1, WLAN_MLME_CM_ID); 1687 1688 return is_same_mld; 1689 } 1690