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