1 /* 2 * Copyright (c) 2023-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 Link Switch related functionality 19 */ 20 #include <wlan_mlo_mgr_link_switch.h> 21 #include <wlan_mlo_mgr_main.h> 22 #include <wlan_mlo_mgr_sta.h> 23 #include <wlan_serialization_api.h> 24 #include <wlan_cm_api.h> 25 #include <wlan_crypto_def_i.h> 26 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 27 #include "wlan_cm_roam_api.h" 28 #include <wlan_mlo_mgr_roam.h> 29 #endif 30 #include "host_diag_core_event.h" 31 32 void mlo_mgr_update_link_info_mac_addr(struct wlan_objmgr_vdev *vdev, 33 struct wlan_mlo_link_mac_update *ml_mac_update) 34 { 35 struct mlo_link_info *link_info; 36 uint8_t link_info_iter; 37 struct mlo_vdev_link_mac_info *link_mac_info; 38 39 if (!vdev || !vdev->mlo_dev_ctx || !ml_mac_update) 40 return; 41 42 link_mac_info = &ml_mac_update->link_mac_info[0]; 43 link_info = &vdev->mlo_dev_ctx->link_ctx->links_info[0]; 44 45 for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS; 46 link_info_iter++) { 47 qdf_mem_copy(&link_info->link_addr, 48 &link_mac_info->link_mac_addr, 49 QDF_MAC_ADDR_SIZE); 50 51 link_info->vdev_id = link_mac_info->vdev_id; 52 mlo_debug("Update STA Link info for vdev_id %d, link_addr:" QDF_MAC_ADDR_FMT, 53 link_info->vdev_id, 54 QDF_MAC_ADDR_REF(link_info->link_addr.bytes)); 55 link_mac_info++; 56 link_info++; 57 } 58 } 59 60 void mlo_mgr_update_ap_link_info(struct wlan_objmgr_vdev *vdev, uint8_t link_id, 61 uint8_t *ap_link_addr, 62 struct wlan_channel channel) 63 { 64 struct mlo_link_info *link_info; 65 uint8_t link_info_iter; 66 67 if (!vdev || !vdev->mlo_dev_ctx || !ap_link_addr) 68 return; 69 70 link_info = &vdev->mlo_dev_ctx->link_ctx->links_info[0]; 71 for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS; 72 link_info_iter++) { 73 if (qdf_is_macaddr_zero(&link_info->ap_link_addr)) 74 break; 75 76 link_info++; 77 } 78 79 if (link_info_iter == WLAN_MAX_ML_BSS_LINKS) 80 return; 81 82 qdf_mem_copy(&link_info->ap_link_addr, ap_link_addr, QDF_MAC_ADDR_SIZE); 83 84 qdf_mem_copy(link_info->link_chan_info, &channel, sizeof(channel)); 85 link_info->link_status_flags = 0; 86 link_info->link_id = link_id; 87 link_info->is_link_active = false; 88 89 mlo_debug("Update AP Link info for link_id: %d, vdev_id:%d, link_addr:" QDF_MAC_ADDR_FMT, 90 link_info->link_id, link_info->vdev_id, 91 QDF_MAC_ADDR_REF(link_info->ap_link_addr.bytes)); 92 } 93 94 void mlo_mgr_clear_ap_link_info(struct wlan_objmgr_vdev *vdev, 95 uint8_t *ap_link_addr) 96 { 97 struct mlo_link_info *link_info; 98 uint8_t link_info_iter; 99 100 if (!vdev || !vdev->mlo_dev_ctx || !ap_link_addr) 101 return; 102 103 link_info = &vdev->mlo_dev_ctx->link_ctx->links_info[0]; 104 for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS; 105 link_info_iter++) { 106 if (qdf_is_macaddr_equal(&link_info->ap_link_addr, 107 (struct qdf_mac_addr *)ap_link_addr)) { 108 mlo_debug("Clear AP link info for link_id: %d, vdev_id:%d, link_addr:" QDF_MAC_ADDR_FMT, 109 link_info->link_id, link_info->vdev_id, 110 QDF_MAC_ADDR_REF(link_info->ap_link_addr.bytes)); 111 112 qdf_mem_zero(&link_info->ap_link_addr, 113 QDF_MAC_ADDR_SIZE); 114 qdf_mem_zero(link_info->link_chan_info, 115 sizeof(*link_info->link_chan_info)); 116 link_info->link_id = WLAN_INVALID_LINK_ID; 117 link_info->link_status_flags = 0; 118 119 return; 120 } 121 122 link_info++; 123 } 124 } 125 126 void mlo_mgr_update_ap_channel_info(struct wlan_objmgr_vdev *vdev, uint8_t link_id, 127 uint8_t *ap_link_addr, 128 struct wlan_channel channel) 129 { 130 struct mlo_link_info *link_info; 131 132 if (!vdev || !vdev->mlo_dev_ctx || !ap_link_addr) 133 return; 134 135 link_info = mlo_mgr_get_ap_link_by_link_id(vdev->mlo_dev_ctx, link_id); 136 if (!link_info) 137 return; 138 139 qdf_mem_copy(link_info->link_chan_info, &channel, 140 sizeof(*link_info->link_chan_info)); 141 142 mlo_debug("update AP channel info link_id: %d, vdev_id:%d, link_addr:" QDF_MAC_ADDR_FMT, 143 link_info->link_id, link_info->vdev_id, 144 QDF_MAC_ADDR_REF(link_info->ap_link_addr.bytes)); 145 mlo_debug("ch_freq: %d, freq1: %d, freq2: %d, phy_mode: %d", 146 link_info->link_chan_info->ch_freq, 147 link_info->link_chan_info->ch_cfreq1, 148 link_info->link_chan_info->ch_cfreq2, 149 link_info->link_chan_info->ch_phymode); 150 } 151 152 void mlo_mgr_update_link_info_reset(struct wlan_objmgr_psoc *psoc, 153 struct wlan_mlo_dev_context *ml_dev) 154 { 155 struct mlo_link_info *link_info; 156 uint8_t link_info_iter; 157 158 if (!ml_dev) 159 return; 160 161 link_info = &ml_dev->link_ctx->links_info[0]; 162 163 for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS; 164 link_info_iter++) { 165 if (!qdf_is_macaddr_zero(&link_info->ap_link_addr) && 166 !qdf_is_macaddr_zero(&link_info->link_addr)) 167 wlan_crypto_free_key_by_link_id( 168 psoc, 169 &link_info->link_addr, 170 link_info->link_id); 171 qdf_mem_zero(&link_info->link_addr, QDF_MAC_ADDR_SIZE); 172 qdf_mem_zero(&link_info->ap_link_addr, QDF_MAC_ADDR_SIZE); 173 qdf_mem_zero(link_info->link_chan_info, 174 sizeof(*link_info->link_chan_info)); 175 link_info->vdev_id = WLAN_INVALID_VDEV_ID; 176 link_info->link_id = WLAN_INVALID_LINK_ID; 177 link_info->link_status_flags = 0; 178 link_info++; 179 } 180 } 181 182 void mlo_mgr_reset_ap_link_info(struct wlan_objmgr_vdev *vdev) 183 { 184 struct mlo_link_info *link_info; 185 uint8_t link_info_iter; 186 struct wlan_objmgr_psoc *psoc; 187 188 if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->link_ctx) 189 return; 190 191 psoc = wlan_vdev_get_psoc(vdev); 192 if (!psoc) { 193 mlo_err("psoc NULL"); 194 return; 195 } 196 197 link_info = &vdev->mlo_dev_ctx->link_ctx->links_info[0]; 198 199 for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS; 200 link_info_iter++) { 201 if (!qdf_is_macaddr_zero(&link_info->ap_link_addr) && 202 !qdf_is_macaddr_zero(&link_info->link_addr)) 203 wlan_crypto_free_key_by_link_id( 204 psoc, 205 &link_info->link_addr, 206 link_info->link_id); 207 qdf_mem_zero(&link_info->ap_link_addr, QDF_MAC_ADDR_SIZE); 208 qdf_mem_zero(link_info->link_chan_info, 209 sizeof(*link_info->link_chan_info)); 210 link_info->link_id = WLAN_INVALID_LINK_ID; 211 link_info->link_status_flags = 0; 212 link_info++; 213 } 214 } 215 216 struct mlo_link_info 217 *mlo_mgr_get_ap_link(struct wlan_objmgr_vdev *vdev) 218 { 219 if (!vdev || !vdev->mlo_dev_ctx) 220 return NULL; 221 222 return &vdev->mlo_dev_ctx->link_ctx->links_info[0]; 223 } 224 225 static 226 void mlo_mgr_alloc_link_info_wmi_chan(struct wlan_mlo_dev_context *ml_dev) 227 { 228 struct mlo_link_info *link_info; 229 uint8_t link_info_iter; 230 231 if (!ml_dev) 232 return; 233 234 link_info = &ml_dev->link_ctx->links_info[0]; 235 for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS; 236 link_info_iter++) { 237 link_info->link_chan_info = 238 qdf_mem_malloc(sizeof(*link_info->link_chan_info)); 239 if (!link_info->link_chan_info) 240 return; 241 link_info++; 242 } 243 } 244 245 static 246 void mlo_mgr_free_link_info_wmi_chan(struct wlan_mlo_dev_context *ml_dev) 247 { 248 struct mlo_link_info *link_info; 249 uint8_t link_info_iter; 250 251 if (!ml_dev) 252 return; 253 254 link_info = &ml_dev->link_ctx->links_info[0]; 255 for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS; 256 link_info_iter++) { 257 if (link_info->link_chan_info) 258 qdf_mem_free(link_info->link_chan_info); 259 link_info++; 260 } 261 } 262 263 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 264 struct mlo_link_info 265 *mlo_mgr_get_ap_link_by_link_id(struct wlan_mlo_dev_context *mlo_dev_ctx, 266 int link_id) 267 { 268 struct mlo_link_info *link_info; 269 uint8_t link_info_iter; 270 271 if (!mlo_dev_ctx || link_id < 0 || link_id > 15) 272 return NULL; 273 274 link_info = &mlo_dev_ctx->link_ctx->links_info[0]; 275 for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS; 276 link_info_iter++) { 277 if (link_info->link_id == link_id) 278 return link_info; 279 link_info++; 280 } 281 282 return NULL; 283 } 284 285 bool mlo_mgr_update_csa_link_info(struct wlan_objmgr_pdev *pdev, 286 struct wlan_mlo_dev_context *mlo_dev_ctx, 287 struct csa_offload_params *csa_param, 288 uint8_t link_id) 289 { 290 struct mlo_link_info *link_info; 291 uint16_t bw_val; 292 uint32_t ch_cfreq1, ch_cfreq2; 293 294 if (!mlo_dev_ctx) { 295 mlo_err("invalid mlo dev ctx"); 296 goto done; 297 } 298 299 bw_val = wlan_reg_get_bw_value(csa_param->new_ch_width); 300 301 link_info = mlo_mgr_get_ap_link_by_link_id(mlo_dev_ctx, link_id); 302 if (!link_info) { 303 mlo_err("invalid link_info"); 304 goto done; 305 } 306 307 link_info->link_chan_info->ch_freq = csa_param->csa_chan_freq; 308 309 if (wlan_reg_is_6ghz_chan_freq(csa_param->csa_chan_freq)) { 310 ch_cfreq1 = wlan_reg_compute_6g_center_freq_from_cfi( 311 csa_param->new_ch_freq_seg1); 312 ch_cfreq2 = wlan_reg_compute_6g_center_freq_from_cfi( 313 csa_param->new_ch_freq_seg2); 314 } else { 315 ch_cfreq1 = wlan_reg_legacy_chan_to_freq(pdev, 316 csa_param->new_ch_freq_seg1); 317 ch_cfreq2 = wlan_reg_legacy_chan_to_freq(pdev, 318 csa_param->new_ch_freq_seg2); 319 } 320 321 link_info->link_chan_info->ch_cfreq1 = ch_cfreq1; 322 link_info->link_chan_info->ch_cfreq2 = ch_cfreq2; 323 324 link_info->link_chan_info->ch_phymode = wlan_eht_chan_phy_mode( 325 csa_param->csa_chan_freq, 326 bw_val, csa_param->new_ch_width); 327 328 mlo_debug("CSA: freq: %d, cfreq1: %d, cfreq2: %d, bw: %d, phymode:%d", 329 link_info->link_chan_info->ch_freq, ch_cfreq1, ch_cfreq2, 330 bw_val, link_info->link_chan_info->ch_phymode); 331 332 return true; 333 done: 334 return false; 335 } 336 337 struct wlan_objmgr_vdev * 338 mlo_mgr_link_switch_get_assoc_vdev(struct wlan_objmgr_vdev *vdev) 339 { 340 uint8_t vdev_id; 341 struct wlan_objmgr_psoc *psoc; 342 struct wlan_objmgr_vdev *assoc_vdev; 343 344 if (!vdev) 345 return NULL; 346 347 if (!mlo_mgr_is_link_switch_on_assoc_vdev(vdev)) 348 return NULL; 349 350 vdev_id = vdev->mlo_dev_ctx->link_ctx->last_req.vdev_id; 351 psoc = wlan_vdev_get_psoc(vdev); 352 if (!psoc) { 353 mlo_err("PSOC NULL"); 354 return NULL; 355 } 356 357 assoc_vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, 358 WLAN_MLO_MGR_ID); 359 360 return assoc_vdev; 361 } 362 363 bool mlo_mgr_is_link_switch_in_progress(struct wlan_objmgr_vdev *vdev) 364 { 365 enum mlo_link_switch_req_state state; 366 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 367 368 if (!mlo_dev_ctx) 369 return false; 370 371 state = mlo_mgr_link_switch_get_curr_state(mlo_dev_ctx); 372 return (state > MLO_LINK_SWITCH_STATE_INIT); 373 } 374 375 bool mlo_mgr_is_link_switch_on_assoc_vdev(struct wlan_objmgr_vdev *vdev) 376 { 377 if (!mlo_mgr_is_link_switch_in_progress(vdev)) 378 return false; 379 380 return vdev->mlo_dev_ctx->link_ctx->last_req.restore_vdev_flag; 381 } 382 383 void mlo_mgr_link_switch_init_state(struct wlan_mlo_dev_context *mlo_dev_ctx) 384 { 385 mlo_dev_lock_acquire(mlo_dev_ctx); 386 mlo_dev_ctx->link_ctx->last_req.state = MLO_LINK_SWITCH_STATE_IDLE; 387 mlo_dev_lock_release(mlo_dev_ctx); 388 } 389 390 QDF_STATUS 391 mlo_mgr_link_switch_trans_next_state(struct wlan_mlo_dev_context *mlo_dev_ctx) 392 { 393 QDF_STATUS status = QDF_STATUS_SUCCESS; 394 enum mlo_link_switch_req_state cur_state, next_state; 395 396 mlo_dev_lock_acquire(mlo_dev_ctx); 397 cur_state = mlo_dev_ctx->link_ctx->last_req.state; 398 switch (cur_state) { 399 case MLO_LINK_SWITCH_STATE_IDLE: 400 next_state = MLO_LINK_SWITCH_STATE_INIT; 401 break; 402 case MLO_LINK_SWITCH_STATE_INIT: 403 next_state = MLO_LINK_SWITCH_STATE_DISCONNECT_CURR_LINK; 404 break; 405 case MLO_LINK_SWITCH_STATE_DISCONNECT_CURR_LINK: 406 next_state = MLO_LINK_SWITCH_STATE_SET_MAC_ADDR; 407 break; 408 case MLO_LINK_SWITCH_STATE_SET_MAC_ADDR: 409 next_state = MLO_LINK_SWITCH_STATE_CONNECT_NEW_LINK; 410 break; 411 case MLO_LINK_SWITCH_STATE_CONNECT_NEW_LINK: 412 next_state = MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS; 413 break; 414 case MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS: 415 next_state = MLO_LINK_SWITCH_STATE_IDLE; 416 break; 417 case MLO_LINK_SWITCH_STATE_ABORT_TRANS: 418 next_state = cur_state; 419 status = QDF_STATUS_E_PERM; 420 mlo_debug("State transition not allowed"); 421 break; 422 default: 423 QDF_ASSERT(0); 424 break; 425 } 426 mlo_dev_ctx->link_ctx->last_req.state = next_state; 427 mlo_dev_lock_release(mlo_dev_ctx); 428 429 return status; 430 } 431 432 void 433 mlo_mgr_link_switch_trans_abort_state(struct wlan_mlo_dev_context *mlo_dev_ctx) 434 { 435 enum mlo_link_switch_req_state next_state = 436 MLO_LINK_SWITCH_STATE_ABORT_TRANS; 437 438 mlo_dev_lock_acquire(mlo_dev_ctx); 439 mlo_dev_ctx->link_ctx->last_req.state = next_state; 440 mlo_dev_lock_release(mlo_dev_ctx); 441 } 442 443 enum mlo_link_switch_req_state 444 mlo_mgr_link_switch_get_curr_state(struct wlan_mlo_dev_context *mlo_dev_ctx) 445 { 446 enum mlo_link_switch_req_state state; 447 448 mlo_dev_lock_acquire(mlo_dev_ctx); 449 state = mlo_dev_ctx->link_ctx->last_req.state; 450 mlo_dev_lock_release(mlo_dev_ctx); 451 452 return state; 453 } 454 455 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 456 static void 457 mlo_mgr_reset_roam_state_for_link_vdev(struct wlan_objmgr_vdev *vdev, 458 struct wlan_objmgr_vdev *assoc_vdev) 459 { 460 QDF_STATUS status; 461 462 status = wlan_cm_roam_state_change(wlan_vdev_get_pdev(vdev), 463 wlan_vdev_get_id(assoc_vdev), 464 WLAN_ROAM_DEINIT, 465 REASON_ROAM_LINK_SWITCH_ASSOC_VDEV_CHANGE); 466 if (QDF_IS_STATUS_ERROR(status)) 467 mlo_err("vdev:%d failed to change RSO state to deinit", 468 wlan_vdev_get_id(assoc_vdev)); 469 } 470 471 static void 472 mlo_mgr_restore_rso_upon_link_switch_failure(struct wlan_objmgr_vdev *vdev) 473 { 474 wlan_cm_roam_state_change(wlan_vdev_get_pdev(vdev), 475 wlan_vdev_get_id(vdev), 476 WLAN_ROAM_RSO_ENABLED, 477 REASON_CONNECT); 478 } 479 #else 480 static inline void 481 mlo_mgr_reset_roam_state_for_link_vdev(struct wlan_objmgr_vdev *vdev, 482 struct wlan_objmgr_vdev *assoc_vdev) 483 {} 484 485 static inline void 486 mlo_mgr_restore_rso_upon_link_switch_failure(struct wlan_objmgr_vdev *vdev) 487 {} 488 #endif 489 490 static QDF_STATUS 491 mlo_mgr_link_switch_osif_notification(struct wlan_objmgr_vdev *vdev, 492 struct wlan_mlo_link_switch_req *lswitch_req) 493 { 494 uint8_t idx; 495 uint16_t vdev_count; 496 struct wlan_objmgr_vdev *assoc_vdev; 497 struct wlan_mlo_sta *sta_ctx; 498 struct wlan_objmgr_vdev *vdev_list[WLAN_UMAC_MLO_MAX_VDEVS]; 499 QDF_STATUS status = QDF_STATUS_E_INVAL; 500 struct mlo_mgr_context *g_mlo_ctx = wlan_objmgr_get_mlo_ctx(); 501 QDF_STATUS(*cb)(struct wlan_objmgr_vdev *vdev, 502 uint8_t non_trans_vdev_id); 503 504 if (!vdev->mlo_dev_ctx) 505 return status; 506 507 sta_ctx = vdev->mlo_dev_ctx->sta_ctx; 508 if (!sta_ctx) 509 return status; 510 511 assoc_vdev = wlan_mlo_get_assoc_link_vdev(vdev); 512 if (!assoc_vdev) 513 return status; 514 515 cb = g_mlo_ctx->osif_ops->mlo_mgr_osif_link_switch_notification; 516 517 if (lswitch_req->restore_vdev_flag) { 518 wlan_vdev_mlme_clear_mlo_link_vdev(vdev); 519 wlan_vdev_mlme_set_mlo_link_vdev(assoc_vdev); 520 mlo_mgr_reset_roam_state_for_link_vdev(vdev, assoc_vdev); 521 522 lswitch_req->restore_vdev_flag = false; 523 524 status = cb(assoc_vdev, wlan_vdev_get_id(vdev)); 525 if (QDF_IS_STATUS_ERROR(status)) 526 mlo_debug("OSIF deflink restore failed"); 527 528 return status; 529 } 530 531 if (wlan_vdev_get_id(assoc_vdev) != lswitch_req->vdev_id) { 532 mlo_debug("Not on assoc VDEV no need to swap"); 533 return QDF_STATUS_SUCCESS; 534 } 535 536 mlo_sta_get_vdev_list(vdev, &vdev_count, vdev_list); 537 for (idx = 0; idx < vdev_count; idx++) { 538 if (wlan_vdev_get_id(vdev_list[idx]) != lswitch_req->vdev_id && 539 qdf_test_bit(idx, sta_ctx->wlan_connected_links)) { 540 wlan_vdev_mlme_clear_mlo_link_vdev(vdev_list[idx]); 541 wlan_vdev_mlme_set_mlo_link_vdev(assoc_vdev); 542 lswitch_req->restore_vdev_flag = true; 543 544 status = cb(assoc_vdev, 545 wlan_vdev_get_id(vdev_list[idx])); 546 break; 547 } 548 549 mlo_release_vdev_ref(vdev_list[idx]); 550 } 551 552 for (; idx < vdev_count; idx++) 553 mlo_release_vdev_ref(vdev_list[idx]); 554 555 return status; 556 } 557 558 QDF_STATUS 559 mlo_mgr_link_switch_notification(struct wlan_objmgr_vdev *vdev, 560 struct wlan_mlo_link_switch_req *lswitch_req, 561 enum wlan_mlo_link_switch_notify_reason notify_reason) 562 { 563 QDF_STATUS status; 564 565 switch (notify_reason) { 566 case MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_PRE_SER: 567 case MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_POST_SER: 568 if (!mlo_check_if_all_vdev_up(vdev)) { 569 mlo_debug("Not all VDEVs up"); 570 return QDF_STATUS_E_AGAIN; 571 } 572 573 if (mlo_is_chan_switch_in_progress(vdev)) { 574 mlo_debug("CSA is in progress on one of ML vdevs, abort link switch"); 575 return QDF_STATUS_E_AGAIN; 576 } 577 578 if (notify_reason == 579 MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_PRE_SER) { 580 return QDF_STATUS_SUCCESS; 581 } 582 583 break; 584 default: 585 break; 586 } 587 588 status = mlo_mgr_link_switch_osif_notification(vdev, lswitch_req); 589 590 return status; 591 } 592 593 QDF_STATUS mlo_mgr_link_switch_init(struct wlan_objmgr_psoc *psoc, 594 struct wlan_mlo_dev_context *ml_dev) 595 { 596 ml_dev->link_ctx = 597 qdf_mem_malloc(sizeof(struct mlo_link_switch_context)); 598 599 if (!ml_dev->link_ctx) 600 return QDF_STATUS_E_NOMEM; 601 602 mlo_mgr_link_switch_init_state(ml_dev); 603 mlo_mgr_alloc_link_info_wmi_chan(ml_dev); 604 mlo_mgr_update_link_info_reset(psoc, ml_dev); 605 606 return QDF_STATUS_SUCCESS; 607 } 608 609 QDF_STATUS mlo_mgr_link_switch_deinit(struct wlan_mlo_dev_context *ml_dev) 610 { 611 mlo_mgr_free_link_info_wmi_chan(ml_dev); 612 qdf_mem_free(ml_dev->link_ctx); 613 ml_dev->link_ctx = NULL; 614 return QDF_STATUS_SUCCESS; 615 } 616 617 void 618 mlo_mgr_osif_update_connect_info(struct wlan_objmgr_vdev *vdev, int32_t link_id) 619 { 620 struct mlo_mgr_context *g_mlo_ctx = wlan_objmgr_get_mlo_ctx(); 621 struct mlo_link_info *link_info; 622 QDF_STATUS(*osif_bss_update_cb)(struct qdf_mac_addr *self_mac, 623 struct qdf_mac_addr *bssid, 624 int32_t link_id); 625 626 if (!g_mlo_ctx || !vdev->mlo_dev_ctx || !g_mlo_ctx->osif_ops || 627 !g_mlo_ctx->osif_ops->mlo_mgr_osif_update_bss_info) 628 return; 629 630 link_info = mlo_mgr_get_ap_link_by_link_id(vdev->mlo_dev_ctx, link_id); 631 if (!link_info) 632 return; 633 634 mlo_debug("VDEV ID %d, Link ID %d, STA MAC " QDF_MAC_ADDR_FMT ", BSSID " QDF_MAC_ADDR_FMT, 635 link_info->vdev_id, link_id, 636 QDF_MAC_ADDR_REF(link_info->link_addr.bytes), 637 QDF_MAC_ADDR_REF(link_info->ap_link_addr.bytes)); 638 osif_bss_update_cb = g_mlo_ctx->osif_ops->mlo_mgr_osif_update_bss_info; 639 640 osif_bss_update_cb(&link_info->link_addr, &link_info->ap_link_addr, 641 link_id); 642 } 643 644 QDF_STATUS mlo_mgr_link_switch_disconnect_done(struct wlan_objmgr_vdev *vdev, 645 QDF_STATUS discon_status, 646 bool is_link_switch_resp) 647 { 648 QDF_STATUS status; 649 enum mlo_link_switch_req_state cur_state; 650 struct mlo_link_info *new_link_info; 651 struct qdf_mac_addr mac_addr, mld_addr; 652 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 653 struct wlan_mlo_link_switch_req *req = &mlo_dev_ctx->link_ctx->last_req; 654 655 if (!is_link_switch_resp) { 656 mlo_mgr_link_switch_trans_abort_state(mlo_dev_ctx); 657 return QDF_STATUS_SUCCESS; 658 } 659 660 cur_state = mlo_mgr_link_switch_get_curr_state(mlo_dev_ctx); 661 if (QDF_IS_STATUS_ERROR(discon_status) || 662 cur_state != MLO_LINK_SWITCH_STATE_DISCONNECT_CURR_LINK) { 663 mlo_err("VDEV %d link switch disconnect req failed", 664 req->vdev_id); 665 mlo_mgr_remove_link_switch_cmd(vdev); 666 return QDF_STATUS_SUCCESS; 667 } 668 669 mlo_debug("VDEV %d link switch disconnect complete", 670 wlan_vdev_get_id(vdev)); 671 672 new_link_info = 673 mlo_mgr_get_ap_link_by_link_id(vdev->mlo_dev_ctx, 674 req->new_ieee_link_id); 675 if (!new_link_info) { 676 mlo_err("New link not found in mlo dev ctx"); 677 mlo_mgr_remove_link_switch_cmd(vdev); 678 return QDF_STATUS_E_INVAL; 679 } 680 681 qdf_copy_macaddr(&mld_addr, &mlo_dev_ctx->mld_addr); 682 qdf_copy_macaddr(&mac_addr, &new_link_info->link_addr); 683 684 status = mlo_mgr_link_switch_trans_next_state(mlo_dev_ctx); 685 if (QDF_IS_STATUS_ERROR(status)) { 686 mlo_mgr_remove_link_switch_cmd(vdev); 687 return status; 688 } 689 690 status = wlan_vdev_mlme_send_set_mac_addr(mac_addr, mld_addr, vdev); 691 if (QDF_IS_STATUS_ERROR(status)) { 692 mlo_debug("VDEV %d set MAC addr FW request failed", 693 req->vdev_id); 694 mlo_mgr_remove_link_switch_cmd(vdev); 695 } 696 697 return status; 698 } 699 700 QDF_STATUS mlo_mgr_link_switch_set_mac_addr_resp(struct wlan_objmgr_vdev *vdev, 701 uint8_t resp_status) 702 { 703 QDF_STATUS status = QDF_STATUS_E_INVAL; 704 enum mlo_link_switch_req_state cur_state; 705 struct mlo_mgr_context *g_mlo_ctx = wlan_objmgr_get_mlo_ctx(); 706 struct wlan_mlo_link_switch_req *req; 707 struct mlo_link_info *new_link_info; 708 709 if (resp_status) { 710 mlo_err("VDEV %d set MAC address response %d", 711 wlan_vdev_get_id(vdev), resp_status); 712 mlo_mgr_remove_link_switch_cmd(vdev); 713 return status; 714 } 715 716 if (!g_mlo_ctx) { 717 mlo_err("global mlo ctx NULL"); 718 mlo_mgr_remove_link_switch_cmd(vdev); 719 return status; 720 } 721 722 req = &vdev->mlo_dev_ctx->link_ctx->last_req; 723 cur_state = mlo_mgr_link_switch_get_curr_state(vdev->mlo_dev_ctx); 724 if (cur_state != MLO_LINK_SWITCH_STATE_SET_MAC_ADDR) { 725 mlo_err("Link switch cmd flushed, there can be MAC addr mismatch with FW"); 726 mlo_mgr_remove_link_switch_cmd(vdev); 727 return status; 728 } 729 730 new_link_info = 731 mlo_mgr_get_ap_link_by_link_id(vdev->mlo_dev_ctx, 732 req->new_ieee_link_id); 733 if (!new_link_info) { 734 mlo_mgr_remove_link_switch_cmd(vdev); 735 return status; 736 } 737 738 wlan_vdev_mlme_set_macaddr(vdev, new_link_info->link_addr.bytes); 739 wlan_vdev_mlme_set_linkaddr(vdev, new_link_info->link_addr.bytes); 740 741 status = g_mlo_ctx->osif_ops->mlo_mgr_osif_update_mac_addr( 742 req->curr_ieee_link_id, 743 req->new_ieee_link_id, 744 req->vdev_id); 745 if (QDF_IS_STATUS_ERROR(status)) { 746 mlo_debug("VDEV %d OSIF MAC addr update failed %d", 747 req->vdev_id, status); 748 mlo_mgr_remove_link_switch_cmd(vdev); 749 return status; 750 } 751 752 status = mlo_mgr_link_switch_trans_next_state(vdev->mlo_dev_ctx); 753 if (QDF_IS_STATUS_ERROR(status)) { 754 mlo_mgr_remove_link_switch_cmd(vdev); 755 return status; 756 } 757 758 status = mlo_mgr_link_switch_start_connect(vdev); 759 760 return status; 761 } 762 763 QDF_STATUS mlo_mgr_link_switch_start_connect(struct wlan_objmgr_vdev *vdev) 764 { 765 QDF_STATUS status = QDF_STATUS_E_INVAL; 766 struct wlan_cm_connect_req conn_req = {0}; 767 struct mlo_link_info *mlo_link_info; 768 uint8_t *vdev_mac; 769 struct wlan_mlo_sta *sta_ctx; 770 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 771 struct wlan_mlo_link_switch_req *req = &mlo_dev_ctx->link_ctx->last_req; 772 struct wlan_objmgr_vdev *assoc_vdev = wlan_mlo_get_assoc_link_vdev(vdev); 773 774 if (!assoc_vdev) { 775 mlo_err("Assoc VDEV not found"); 776 goto out; 777 } 778 779 mlo_link_info = mlo_mgr_get_ap_link_by_link_id(mlo_dev_ctx, 780 req->new_ieee_link_id); 781 782 if (!mlo_link_info) { 783 mlo_err("New link ID not found"); 784 goto out; 785 } 786 787 vdev_mac = wlan_vdev_mlme_get_linkaddr(vdev); 788 if (!qdf_is_macaddr_equal(&mlo_link_info->link_addr, 789 (struct qdf_mac_addr *)vdev_mac)) { 790 mlo_err("MAC address not equal for the new Link ID VDEV: " QDF_MAC_ADDR_FMT ", MLO_LINK: " QDF_MAC_ADDR_FMT, 791 QDF_MAC_ADDR_REF(vdev_mac), 792 QDF_MAC_ADDR_REF(mlo_link_info->link_addr.bytes)); 793 goto out; 794 } 795 796 sta_ctx = mlo_dev_ctx->sta_ctx; 797 copied_conn_req_lock_acquire(sta_ctx); 798 if (sta_ctx->copied_conn_req) { 799 qdf_mem_copy(&conn_req, sta_ctx->copied_conn_req, 800 sizeof(struct wlan_cm_connect_req)); 801 } else { 802 copied_conn_req_lock_release(sta_ctx); 803 goto out; 804 } 805 copied_conn_req_lock_release(sta_ctx); 806 807 conn_req.vdev_id = wlan_vdev_get_id(vdev); 808 conn_req.source = CM_MLO_LINK_SWITCH_CONNECT; 809 wlan_vdev_set_link_id(vdev, req->new_ieee_link_id); 810 811 qdf_copy_macaddr(&conn_req.bssid, &mlo_link_info->ap_link_addr); 812 wlan_vdev_mlme_get_ssid(assoc_vdev, conn_req.ssid.ssid, 813 &conn_req.ssid.length); 814 status = wlan_vdev_get_bss_peer_mld_mac(assoc_vdev, &conn_req.mld_addr); 815 if (QDF_IS_STATUS_ERROR(status)) { 816 mlo_debug("Get MLD addr failed"); 817 goto out; 818 } 819 820 conn_req.crypto.auth_type = 0; 821 conn_req.ml_parnter_info = sta_ctx->ml_partner_info; 822 mlo_allocate_and_copy_ies(&conn_req, sta_ctx->copied_conn_req); 823 824 status = wlan_cm_start_connect(vdev, &conn_req); 825 if (QDF_IS_STATUS_SUCCESS(status)) 826 mlo_update_connected_links(vdev, 1); 827 828 wlan_cm_free_connect_req_param(&conn_req); 829 830 out: 831 if (QDF_IS_STATUS_ERROR(status)) { 832 mlo_err("VDEV %d link switch connect request failed", 833 wlan_vdev_get_id(vdev)); 834 mlo_mgr_remove_link_switch_cmd(vdev); 835 } 836 837 return status; 838 } 839 840 static void 841 mlo_mgr_link_switch_connect_success_trans_state(struct wlan_objmgr_vdev *vdev) 842 { 843 enum mlo_link_switch_req_state curr_state; 844 845 /* 846 * If connection is success, then sending link switch failure to FW 847 * might result in not updating VDEV to link mapping in FW and FW may 848 * immediately send next link switch with params corresponding to 849 * pre-link switch which may vary post-link switch in host and might 850 * not be valid and results in Host-FW out-of-sync. 851 * 852 * Force the result of link switch in align with link switch connect 853 * so that Host and FW are not out of sync. 854 */ 855 mlo_dev_lock_acquire(vdev->mlo_dev_ctx); 856 curr_state = vdev->mlo_dev_ctx->link_ctx->last_req.state; 857 vdev->mlo_dev_ctx->link_ctx->last_req.state = 858 MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS; 859 mlo_dev_lock_release(vdev->mlo_dev_ctx); 860 861 if (curr_state != MLO_LINK_SWITCH_STATE_CONNECT_NEW_LINK) 862 mlo_debug("Current link switch state %d changed", curr_state); 863 } 864 865 void mlo_mgr_link_switch_connect_done(struct wlan_objmgr_vdev *vdev, 866 QDF_STATUS status) 867 { 868 struct wlan_mlo_link_switch_req *req; 869 870 req = &vdev->mlo_dev_ctx->link_ctx->last_req; 871 if (QDF_IS_STATUS_SUCCESS(status)) { 872 mlo_mgr_link_switch_connect_success_trans_state(vdev); 873 } else { 874 mlo_update_connected_links(vdev, 0); 875 mlo_err("VDEV %d link switch connect failed", req->vdev_id); 876 } 877 878 mlo_mgr_remove_link_switch_cmd(vdev); 879 880 if (QDF_IS_STATUS_ERROR(status)) 881 mlo_mgr_restore_rso_upon_link_switch_failure( 882 wlan_mlo_get_assoc_link_vdev(vdev)); 883 } 884 885 static enum wlan_mlo_link_switch_notify_reason 886 mlo_mgr_link_switch_get_notify_reason(struct wlan_objmgr_vdev *vdev) 887 { 888 enum mlo_link_switch_req_state curr_state; 889 enum wlan_mlo_link_switch_notify_reason notify_reason; 890 891 curr_state = mlo_mgr_link_switch_get_curr_state(vdev->mlo_dev_ctx); 892 switch (curr_state) { 893 case MLO_LINK_SWITCH_STATE_IDLE: 894 notify_reason = MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_PRE_SER; 895 break; 896 case MLO_LINK_SWITCH_STATE_INIT: 897 notify_reason = 898 MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_POST_SER; 899 break; 900 case MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS: 901 notify_reason = MLO_LINK_SWITCH_NOTIFY_REASON_STOP_SUCCESS; 902 break; 903 default: 904 notify_reason = MLO_LINK_SWITCH_NOTIFY_REASON_STOP_FAILURE; 905 break; 906 } 907 908 return notify_reason; 909 } 910 911 static QDF_STATUS 912 mlo_mgr_start_link_switch(struct wlan_objmgr_vdev *vdev, 913 struct wlan_serialization_command *cmd) 914 { 915 QDF_STATUS status = QDF_STATUS_E_INVAL; 916 uint8_t vdev_id, old_link_id, new_link_id; 917 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 918 struct wlan_mlo_link_switch_req *req = &mlo_dev_ctx->link_ctx->last_req; 919 struct qdf_mac_addr bssid; 920 921 vdev_id = wlan_vdev_get_id(vdev); 922 old_link_id = req->curr_ieee_link_id; 923 new_link_id = req->new_ieee_link_id; 924 925 mlo_debug("VDEV %d start link switch", vdev_id); 926 mlo_mgr_link_switch_trans_next_state(mlo_dev_ctx); 927 928 if (!wlan_cm_is_vdev_connected(vdev)) { 929 mlo_err("VDEV %d not in connected state", vdev_id); 930 return status; 931 } 932 933 status = wlan_vdev_get_bss_peer_mac(vdev, &bssid); 934 if (QDF_IS_STATUS_ERROR(status)) 935 return status; 936 937 status = wlan_vdev_get_bss_peer_mld_mac(vdev, &req->peer_mld_addr); 938 if (QDF_IS_STATUS_ERROR(status)) 939 return status; 940 941 status = mlo_mgr_link_switch_notify(vdev, req); 942 if (QDF_IS_STATUS_ERROR(status)) 943 return status; 944 945 wlan_vdev_mlme_set_mlo_link_switch_in_progress(vdev); 946 status = mlo_mgr_link_switch_trans_next_state(mlo_dev_ctx); 947 if (QDF_IS_STATUS_ERROR(status)) 948 return status; 949 950 status = wlan_cm_disconnect(vdev, CM_MLO_LINK_SWITCH_DISCONNECT, 951 REASON_FW_TRIGGERED_LINK_SWITCH, &bssid); 952 953 if (QDF_IS_STATUS_ERROR(status)) 954 mlo_err("VDEV %d disconnect request not handled", req->vdev_id); 955 956 return status; 957 } 958 959 static QDF_STATUS 960 mlo_mgr_ser_link_switch_cb(struct wlan_serialization_command *cmd, 961 enum wlan_serialization_cb_reason cb_reason) 962 { 963 struct wlan_objmgr_vdev *vdev; 964 QDF_STATUS status = QDF_STATUS_SUCCESS; 965 struct wlan_mlo_link_switch_req *req; 966 enum qdf_hang_reason reason = QDF_VDEV_ACTIVE_SER_LINK_SWITCH_TIMEOUT; 967 968 if (!cmd) { 969 mlo_err("cmd is NULL, reason: %d", cb_reason); 970 QDF_ASSERT(0); 971 return QDF_STATUS_E_NULL_VALUE; 972 } 973 974 vdev = cmd->vdev; 975 req = &vdev->mlo_dev_ctx->link_ctx->last_req; 976 977 switch (cb_reason) { 978 case WLAN_SER_CB_ACTIVATE_CMD: 979 status = mlo_mgr_start_link_switch(vdev, cmd); 980 if (QDF_IS_STATUS_ERROR(status)) { 981 mlo_mgr_link_switch_trans_abort_state(vdev->mlo_dev_ctx); 982 mlo_mgr_link_switch_notify(vdev, req); 983 } 984 break; 985 case WLAN_SER_CB_RELEASE_MEM_CMD: 986 mlo_mgr_link_switch_complete(vdev); 987 break; 988 case WLAN_SER_CB_CANCEL_CMD: 989 mlo_err("Link switch cmd cancelled"); 990 break; 991 case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT: 992 mlo_err("Link switch active cmd timeout"); 993 wlan_cm_trigger_panic_on_cmd_timeout(vdev, reason); 994 break; 995 default: 996 QDF_ASSERT(0); 997 mlo_mgr_link_switch_complete(vdev); 998 break; 999 } 1000 1001 return status; 1002 } 1003 1004 void mlo_mgr_remove_link_switch_cmd(struct wlan_objmgr_vdev *vdev) 1005 { 1006 struct wlan_serialization_queued_cmd_info cmd_info; 1007 enum mlo_link_switch_req_state cur_state; 1008 uint8_t vdev_id = wlan_vdev_get_id(vdev); 1009 struct wlan_mlo_link_switch_req *req; 1010 1011 cur_state = mlo_mgr_link_switch_get_curr_state(vdev->mlo_dev_ctx); 1012 if (cur_state == MLO_LINK_SWITCH_STATE_IDLE) 1013 return; 1014 1015 req = &vdev->mlo_dev_ctx->link_ctx->last_req; 1016 mlo_mgr_link_switch_notify(vdev, req); 1017 1018 /* Force queue disconnect on failure */ 1019 if (cur_state != MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS && 1020 cur_state >= MLO_LINK_SWITCH_STATE_DISCONNECT_CURR_LINK && 1021 !wlan_cm_is_vdev_connected(vdev)) { 1022 mlo_mgr_link_switch_defer_disconnect_req(vdev, 1023 CM_MLME_DISCONNECT, 1024 REASON_HOST_TRIGGERED_LINK_DELETE); 1025 } 1026 1027 /* Handle any pending disconnect */ 1028 mlo_handle_pending_disconnect(vdev); 1029 1030 if (req->reason == MLO_LINK_SWITCH_REASON_HOST_FORCE) { 1031 mlo_debug("Link switch not serialized"); 1032 mlo_mgr_link_switch_complete(vdev); 1033 return; 1034 } 1035 1036 cmd_info.cmd_id = (vdev_id << 16) + (req->new_ieee_link_id << 8) + 1037 (req->curr_ieee_link_id); 1038 cmd_info.req_type = WLAN_SER_CANCEL_NON_SCAN_CMD; 1039 cmd_info.cmd_type = WLAN_SER_CMD_MLO_VDEV_LINK_SWITCH; 1040 cmd_info.vdev = vdev; 1041 cmd_info.queue_type = WLAN_SERIALIZATION_ACTIVE_QUEUE; 1042 1043 wlan_serialization_remove_cmd(&cmd_info); 1044 } 1045 1046 #define MLO_MGR_MAX_LSWITCH_TIMEOUT 35000 1047 1048 QDF_STATUS mlo_mgr_ser_link_switch_cmd(struct wlan_objmgr_vdev *vdev, 1049 struct wlan_mlo_link_switch_req *req) 1050 { 1051 QDF_STATUS status; 1052 enum wlan_serialization_status ser_cmd_status; 1053 struct wlan_serialization_command cmd = {0}; 1054 uint8_t vdev_id = wlan_vdev_get_id(vdev); 1055 struct mlo_link_switch_context *link_ctx; 1056 1057 if (!vdev->mlo_dev_ctx) { 1058 mlo_err("ML dev ctx NULL, reject link switch"); 1059 return QDF_STATUS_E_INVAL; 1060 } 1061 1062 link_ctx = vdev->mlo_dev_ctx->link_ctx; 1063 link_ctx->last_req = *req; 1064 1065 cmd.cmd_type = WLAN_SER_CMD_MLO_VDEV_LINK_SWITCH; 1066 cmd.cmd_id = (vdev_id << 16) + (req->new_ieee_link_id << 8) + 1067 (req->curr_ieee_link_id); 1068 cmd.cmd_cb = mlo_mgr_ser_link_switch_cb; 1069 cmd.source = WLAN_UMAC_COMP_MLO_MGR; 1070 cmd.is_high_priority = false; 1071 cmd.cmd_timeout_duration = MLO_MGR_MAX_LSWITCH_TIMEOUT; 1072 cmd.vdev = vdev; 1073 cmd.is_blocking = true; 1074 1075 if (req->reason == MLO_LINK_SWITCH_REASON_HOST_FORCE) { 1076 mlo_debug("Do not serialize link switch"); 1077 status = mlo_mgr_start_link_switch(vdev, &cmd); 1078 if (QDF_IS_STATUS_ERROR(status)) { 1079 mlo_mgr_link_switch_trans_abort_state(vdev->mlo_dev_ctx); 1080 mlo_mgr_link_switch_notify(vdev, req); 1081 } 1082 return status; 1083 } 1084 1085 ser_cmd_status = wlan_serialization_request(&cmd); 1086 switch (ser_cmd_status) { 1087 case WLAN_SER_CMD_PENDING: 1088 mlo_debug("Link switch cmd in pending queue"); 1089 break; 1090 case WLAN_SER_CMD_ACTIVE: 1091 mlo_debug("Link switch cmd in active queue"); 1092 break; 1093 default: 1094 return QDF_STATUS_E_INVAL; 1095 } 1096 1097 return QDF_STATUS_SUCCESS; 1098 } 1099 1100 QDF_STATUS mlo_mgr_link_switch_notify(struct wlan_objmgr_vdev *vdev, 1101 struct wlan_mlo_link_switch_req *req) 1102 { 1103 int8_t i; 1104 QDF_STATUS status, ret_status = QDF_STATUS_SUCCESS; 1105 enum wlan_mlo_link_switch_notify_reason notify_reason; 1106 struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx(); 1107 1108 if (!mlo_mgr_ctx) { 1109 mlo_err("Global mlo mgr NULL"); 1110 return QDF_STATUS_E_NULL_VALUE; 1111 } 1112 1113 notify_reason = mlo_mgr_link_switch_get_notify_reason(vdev); 1114 for (i = 0; i < WLAN_UMAC_COMP_ID_MAX; i++) { 1115 if (!mlo_mgr_ctx->lswitch_notifier[i].in_use) 1116 continue; 1117 1118 status = mlo_mgr_ctx->lswitch_notifier[i].cb(vdev, req, 1119 notify_reason); 1120 if (QDF_IS_STATUS_SUCCESS(status)) 1121 continue; 1122 1123 mlo_debug("Link switch notify %d failed in %d", 1124 notify_reason, i); 1125 ret_status = status; 1126 if (notify_reason == MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_PRE_SER) 1127 break; 1128 } 1129 1130 return ret_status; 1131 } 1132 1133 QDF_STATUS 1134 mlo_mgr_link_switch_validate_request(struct wlan_objmgr_vdev *vdev, 1135 struct wlan_mlo_link_switch_req *req) 1136 { 1137 QDF_STATUS status = QDF_STATUS_E_INVAL; 1138 uint8_t vdev_id = wlan_vdev_get_id(vdev); 1139 struct mlo_link_info *new_link_info; 1140 1141 if (req->curr_ieee_link_id >= WLAN_INVALID_LINK_ID || 1142 req->new_ieee_link_id >= WLAN_INVALID_LINK_ID) { 1143 mlo_err("Invalid link params, curr link id %d, new link id %d", 1144 req->curr_ieee_link_id, req->new_ieee_link_id); 1145 return status; 1146 } 1147 1148 new_link_info = mlo_mgr_get_ap_link_by_link_id(vdev->mlo_dev_ctx, 1149 req->new_ieee_link_id); 1150 if (!new_link_info) { 1151 mlo_err("New link id %d not part of association", 1152 req->new_ieee_link_id); 1153 return status; 1154 } 1155 1156 if (new_link_info->vdev_id != WLAN_INVALID_VDEV_ID) { 1157 mlo_err("requested link already active on other vdev:%d", 1158 new_link_info->vdev_id); 1159 return status; 1160 } 1161 1162 if (!mlo_is_mld_sta(vdev)) { 1163 mlo_err("Link switch req not valid for VDEV %d", vdev_id); 1164 return status; 1165 } 1166 1167 if (!wlan_cm_is_vdev_connected(vdev)) { 1168 mlo_err("VDEV %d not in connected state", vdev_id); 1169 return status; 1170 } 1171 1172 if (mlo_mgr_is_link_switch_in_progress(vdev)) { 1173 mlo_err("Link switch already in progress"); 1174 return status; 1175 } 1176 1177 if (wlan_vdev_get_link_id(vdev) != req->curr_ieee_link_id) { 1178 mlo_err("VDEV %d link id wrong, curr link id %d", 1179 vdev_id, wlan_vdev_get_link_id(vdev)); 1180 return status; 1181 } 1182 1183 /* Notify callers on the new link switch request before serializing */ 1184 status = mlo_mgr_link_switch_notify(vdev, req); 1185 if (QDF_IS_STATUS_ERROR(status)) { 1186 mlo_err("Link switch rejected in pre-serialize notify"); 1187 return status; 1188 } 1189 1190 return QDF_STATUS_SUCCESS; 1191 } 1192 1193 QDF_STATUS mlo_mgr_link_switch_request_params(struct wlan_objmgr_psoc *psoc, 1194 void *evt_params) 1195 { 1196 QDF_STATUS status; 1197 struct wlan_mlo_link_switch_cnf cnf_params = {0}; 1198 struct wlan_mlo_link_switch_req *req; 1199 struct wlan_objmgr_vdev *vdev; 1200 1201 if (!evt_params) { 1202 mlo_err("Invalid params"); 1203 return QDF_STATUS_E_INVAL; 1204 } 1205 1206 req = (struct wlan_mlo_link_switch_req *)evt_params; 1207 1208 /* The reference is released on Link Switch status confirm to FW */ 1209 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, req->vdev_id, 1210 WLAN_MLO_MGR_ID); 1211 if (!vdev) { 1212 mlo_err("Invalid link switch VDEV %d", req->vdev_id); 1213 1214 /* Fill reject params here and send to FW as VDEV is invalid */ 1215 cnf_params.vdev_id = req->vdev_id; 1216 cnf_params.status = MLO_LINK_SWITCH_CNF_STATUS_REJECT; 1217 mlo_mgr_link_switch_send_cnf_cmd(psoc, &cnf_params); 1218 return QDF_STATUS_E_INVAL; 1219 } 1220 1221 mlo_debug("VDEV %d, curr_link_id %d, new_link_id %d, new_freq %d, new_phymode: %d, reason %d", 1222 req->vdev_id, req->curr_ieee_link_id, req->new_ieee_link_id, 1223 req->new_primary_freq, req->new_phymode, req->reason); 1224 1225 status = mlo_mgr_link_switch_validate_request(vdev, req); 1226 if (QDF_IS_STATUS_ERROR(status)) { 1227 mlo_debug("Link switch params/request invalid"); 1228 mlo_mgr_link_switch_complete(vdev); 1229 return QDF_STATUS_E_INVAL; 1230 } 1231 1232 status = mlo_mgr_ser_link_switch_cmd(vdev, req); 1233 if (QDF_IS_STATUS_ERROR(status)) { 1234 mlo_err("Failed to serialize link switch command"); 1235 mlo_mgr_link_switch_complete(vdev); 1236 } 1237 1238 return status; 1239 } 1240 1241 #define IS_LINK_SET(link_bitmap, link_id) ((link_bitmap) & (BIT(link_id))) 1242 1243 static void mlo_mgr_update_link_state(struct wlan_mlo_dev_context *mld_ctx, 1244 uint32_t active_link_bitmap) 1245 { 1246 uint8_t i; 1247 struct mlo_link_info *link_info; 1248 1249 for (i = 0; i < WLAN_MAX_ML_BSS_LINKS; i++) { 1250 link_info = &mld_ctx->link_ctx->links_info[i]; 1251 1252 if (IS_LINK_SET(active_link_bitmap, link_info->link_id)) 1253 link_info->is_link_active = true; 1254 else 1255 link_info->is_link_active = false; 1256 } 1257 } 1258 1259 QDF_STATUS 1260 mlo_mgr_link_state_switch_info_handler(struct wlan_objmgr_psoc *psoc, 1261 struct mlo_link_switch_state_info *info) 1262 { 1263 uint8_t i; 1264 struct wlan_mlo_dev_context *mld_ctx = NULL; 1265 1266 wlan_mlo_get_mlpeer_by_peer_mladdr( 1267 &info->link_switch_param[0].mld_addr, &mld_ctx); 1268 1269 if (!mld_ctx) { 1270 mlo_err("mlo dev ctx for mld_mac: " QDF_MAC_ADDR_FMT " not found", 1271 QDF_MAC_ADDR_REF(info->link_switch_param[0].mld_addr.bytes)); 1272 return QDF_STATUS_E_INVAL; 1273 } 1274 1275 for (i = 0; i < info->num_params; i++) { 1276 wlan_connectivity_mld_link_status_event( 1277 psoc, 1278 &info->link_switch_param[i]); 1279 mlo_mgr_update_link_state( 1280 mld_ctx, 1281 info->link_switch_param[i].active_link_bitmap); 1282 } 1283 1284 return QDF_STATUS_SUCCESS; 1285 } 1286 1287 QDF_STATUS mlo_mgr_link_switch_complete(struct wlan_objmgr_vdev *vdev) 1288 { 1289 enum mlo_link_switch_req_state state; 1290 struct wlan_mlo_link_switch_cnf params = {0}; 1291 struct mlo_link_switch_context *link_ctx; 1292 struct wlan_mlo_link_switch_req *req; 1293 struct wlan_objmgr_psoc *psoc; 1294 1295 /* Not checking NULL value as reference is already taken for vdev */ 1296 psoc = wlan_vdev_get_psoc(vdev); 1297 1298 link_ctx = vdev->mlo_dev_ctx->link_ctx; 1299 req = &link_ctx->last_req; 1300 1301 state = mlo_mgr_link_switch_get_curr_state(vdev->mlo_dev_ctx); 1302 if (state != MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS) 1303 params.status = MLO_LINK_SWITCH_CNF_STATUS_REJECT; 1304 else 1305 params.status = MLO_LINK_SWITCH_CNF_STATUS_ACCEPT; 1306 1307 params.vdev_id = wlan_vdev_get_id(vdev); 1308 params.reason = MLO_LINK_SWITCH_CNF_REASON_BSS_PARAMS_CHANGED; 1309 1310 mlo_mgr_link_switch_send_cnf_cmd(psoc, ¶ms); 1311 1312 mlo_mgr_link_switch_init_state(vdev->mlo_dev_ctx); 1313 wlan_vdev_mlme_clear_mlo_link_switch_in_progress(vdev); 1314 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 1315 return QDF_STATUS_SUCCESS; 1316 } 1317 1318 QDF_STATUS 1319 mlo_mgr_link_switch_send_cnf_cmd(struct wlan_objmgr_psoc *psoc, 1320 struct wlan_mlo_link_switch_cnf *cnf_params) 1321 { 1322 QDF_STATUS status; 1323 struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops; 1324 1325 mlo_debug("VDEV %d link switch completed, %s", cnf_params->vdev_id, 1326 (cnf_params->status == MLO_LINK_SWITCH_CNF_STATUS_ACCEPT) ? 1327 "success" : "fail"); 1328 1329 mlo_tx_ops = &psoc->soc_cb.tx_ops->mlo_ops; 1330 if (!mlo_tx_ops || !mlo_tx_ops->send_mlo_link_switch_cnf_cmd) { 1331 mlo_err("handler is not registered"); 1332 return QDF_STATUS_E_INVAL; 1333 } 1334 1335 status = mlo_tx_ops->send_mlo_link_switch_cnf_cmd(psoc, cnf_params); 1336 if (QDF_IS_STATUS_ERROR(status)) 1337 mlo_err("Link switch status update to FW failed"); 1338 1339 return status; 1340 } 1341 1342 QDF_STATUS 1343 mlo_mgr_link_switch_defer_disconnect_req(struct wlan_objmgr_vdev *vdev, 1344 enum wlan_cm_source source, 1345 enum wlan_reason_code reason) 1346 { 1347 struct wlan_mlo_dev_context *mlo_dev_ctx; 1348 struct wlan_mlo_sta *sta_ctx; 1349 1350 if (!mlo_mgr_is_link_switch_in_progress(vdev)) { 1351 mlo_info("Link switch not in progress"); 1352 return QDF_STATUS_E_INVAL; 1353 } 1354 1355 mlo_dev_ctx = vdev->mlo_dev_ctx; 1356 sta_ctx = mlo_dev_ctx->sta_ctx; 1357 1358 if (!sta_ctx) { 1359 mlo_err("sta ctx null"); 1360 return QDF_STATUS_E_NULL_VALUE; 1361 } 1362 1363 /* Move current link switch to abort state */ 1364 mlo_mgr_link_switch_trans_abort_state(mlo_dev_ctx); 1365 1366 if (sta_ctx->disconn_req) { 1367 mlo_debug("Pending disconnect from source %d, reason %d", 1368 sta_ctx->disconn_req->source, 1369 sta_ctx->disconn_req->reason_code); 1370 return QDF_STATUS_E_ALREADY; 1371 } 1372 1373 sta_ctx->disconn_req = 1374 qdf_mem_malloc(sizeof(struct wlan_cm_disconnect_req)); 1375 if (!sta_ctx->disconn_req) 1376 return QDF_STATUS_E_NOMEM; 1377 1378 sta_ctx->disconn_req->vdev_id = wlan_vdev_get_id(vdev); 1379 sta_ctx->disconn_req->source = source; 1380 sta_ctx->disconn_req->reason_code = reason; 1381 1382 mlo_debug("Deferred disconnect source: %d, reason: %d", source, reason); 1383 return QDF_STATUS_SUCCESS; 1384 } 1385 #endif 1386