1 /* 2 * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 /* 18 * DOC: contains MLO manager 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_mlo_dev_context *mlo_dev_ctx, 284 struct csa_offload_params *csa_param, 285 uint8_t link_id) 286 { 287 struct mlo_link_info *link_info; 288 uint16_t bw_val; 289 290 if (!mlo_dev_ctx) { 291 mlo_err("invalid mlo dev ctx"); 292 goto done; 293 } 294 295 bw_val = wlan_reg_get_bw_value(csa_param->new_ch_width); 296 297 link_info = mlo_mgr_get_ap_link_by_link_id(mlo_dev_ctx, link_id); 298 if (!link_info) { 299 mlo_err("invalid link_info"); 300 goto done; 301 } 302 303 link_info->link_chan_info->ch_freq = 304 csa_param->csa_chan_freq; 305 link_info->link_chan_info->ch_cfreq1 = 306 csa_param->new_ch_freq_seg1; 307 link_info->link_chan_info->ch_cfreq2 = 308 csa_param->new_ch_freq_seg2; 309 310 link_info->link_chan_info->ch_phymode = 311 wlan_eht_chan_phy_mode( 312 csa_param->csa_chan_freq, 313 bw_val, csa_param->new_ch_width); 314 return true; 315 done: 316 return false; 317 } 318 319 struct wlan_objmgr_vdev * 320 mlo_mgr_link_switch_get_assoc_vdev(struct wlan_objmgr_vdev *vdev) 321 { 322 uint8_t vdev_id; 323 struct wlan_objmgr_psoc *psoc; 324 struct wlan_objmgr_vdev *assoc_vdev; 325 326 if (!vdev) 327 return NULL; 328 329 if (!mlo_mgr_is_link_switch_on_assoc_vdev(vdev)) 330 return NULL; 331 332 vdev_id = vdev->mlo_dev_ctx->link_ctx->last_req.vdev_id; 333 psoc = wlan_vdev_get_psoc(vdev); 334 if (!psoc) { 335 mlo_err("PSOC NULL"); 336 return NULL; 337 } 338 339 assoc_vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, 340 WLAN_MLO_MGR_ID); 341 342 return assoc_vdev; 343 } 344 345 bool mlo_mgr_is_link_switch_in_progress(struct wlan_objmgr_vdev *vdev) 346 { 347 enum mlo_link_switch_req_state state; 348 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 349 350 if (!mlo_dev_ctx) 351 return false; 352 353 state = mlo_mgr_link_switch_get_curr_state(mlo_dev_ctx); 354 return (state > MLO_LINK_SWITCH_STATE_INIT); 355 } 356 357 bool mlo_mgr_is_link_switch_on_assoc_vdev(struct wlan_objmgr_vdev *vdev) 358 { 359 if (!mlo_mgr_is_link_switch_in_progress(vdev)) 360 return false; 361 362 return vdev->mlo_dev_ctx->link_ctx->last_req.restore_vdev_flag; 363 } 364 365 void mlo_mgr_link_switch_init_state(struct wlan_mlo_dev_context *mlo_dev_ctx) 366 { 367 mlo_dev_lock_acquire(mlo_dev_ctx); 368 mlo_dev_ctx->link_ctx->last_req.state = MLO_LINK_SWITCH_STATE_IDLE; 369 mlo_dev_lock_release(mlo_dev_ctx); 370 } 371 372 QDF_STATUS 373 mlo_mgr_link_switch_trans_next_state(struct wlan_mlo_dev_context *mlo_dev_ctx) 374 { 375 QDF_STATUS status = QDF_STATUS_SUCCESS; 376 enum mlo_link_switch_req_state cur_state, next_state; 377 378 mlo_dev_lock_acquire(mlo_dev_ctx); 379 cur_state = mlo_dev_ctx->link_ctx->last_req.state; 380 switch (cur_state) { 381 case MLO_LINK_SWITCH_STATE_IDLE: 382 next_state = MLO_LINK_SWITCH_STATE_INIT; 383 break; 384 case MLO_LINK_SWITCH_STATE_INIT: 385 next_state = MLO_LINK_SWITCH_STATE_DISCONNECT_CURR_LINK; 386 break; 387 case MLO_LINK_SWITCH_STATE_DISCONNECT_CURR_LINK: 388 next_state = MLO_LINK_SWITCH_STATE_SET_MAC_ADDR; 389 break; 390 case MLO_LINK_SWITCH_STATE_SET_MAC_ADDR: 391 next_state = MLO_LINK_SWITCH_STATE_CONNECT_NEW_LINK; 392 break; 393 case MLO_LINK_SWITCH_STATE_CONNECT_NEW_LINK: 394 next_state = MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS; 395 break; 396 case MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS: 397 next_state = MLO_LINK_SWITCH_STATE_IDLE; 398 break; 399 case MLO_LINK_SWITCH_STATE_ABORT_TRANS: 400 next_state = cur_state; 401 status = QDF_STATUS_E_PERM; 402 mlo_debug("State transition not allowed"); 403 break; 404 default: 405 QDF_ASSERT(0); 406 break; 407 } 408 mlo_dev_ctx->link_ctx->last_req.state = next_state; 409 mlo_dev_lock_release(mlo_dev_ctx); 410 411 return status; 412 } 413 414 void 415 mlo_mgr_link_switch_trans_abort_state(struct wlan_mlo_dev_context *mlo_dev_ctx) 416 { 417 enum mlo_link_switch_req_state next_state = 418 MLO_LINK_SWITCH_STATE_ABORT_TRANS; 419 420 mlo_dev_lock_acquire(mlo_dev_ctx); 421 mlo_dev_ctx->link_ctx->last_req.state = next_state; 422 mlo_dev_lock_release(mlo_dev_ctx); 423 } 424 425 enum mlo_link_switch_req_state 426 mlo_mgr_link_switch_get_curr_state(struct wlan_mlo_dev_context *mlo_dev_ctx) 427 { 428 enum mlo_link_switch_req_state state; 429 430 mlo_dev_lock_acquire(mlo_dev_ctx); 431 state = mlo_dev_ctx->link_ctx->last_req.state; 432 mlo_dev_lock_release(mlo_dev_ctx); 433 434 return state; 435 } 436 437 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 438 static void 439 mlo_mgr_reset_roam_state_for_link_vdev(struct wlan_objmgr_vdev *vdev, 440 struct wlan_objmgr_vdev *assoc_vdev) 441 { 442 QDF_STATUS status; 443 444 status = wlan_cm_roam_state_change(wlan_vdev_get_pdev(vdev), 445 wlan_vdev_get_id(assoc_vdev), 446 WLAN_ROAM_DEINIT, 447 REASON_ROAM_LINK_SWITCH_ASSOC_VDEV_CHANGE); 448 if (QDF_IS_STATUS_ERROR(status)) 449 mlo_err("vdev:%d failed to change RSO state to deinit", 450 wlan_vdev_get_id(assoc_vdev)); 451 } 452 #else 453 static inline void 454 mlo_mgr_reset_roam_state_for_link_vdev(struct wlan_objmgr_vdev *vdev, 455 struct wlan_objmgr_vdev *assoc_vdev) 456 {} 457 #endif 458 459 static QDF_STATUS 460 mlo_mgr_link_switch_osif_notification(struct wlan_objmgr_vdev *vdev, 461 struct wlan_mlo_link_switch_req *lswitch_req) 462 { 463 uint8_t idx; 464 uint16_t vdev_count; 465 struct wlan_objmgr_vdev *assoc_vdev; 466 struct wlan_mlo_sta *sta_ctx; 467 struct wlan_objmgr_vdev *vdev_list[WLAN_UMAC_MLO_MAX_VDEVS]; 468 QDF_STATUS status = QDF_STATUS_E_INVAL; 469 struct mlo_mgr_context *g_mlo_ctx = wlan_objmgr_get_mlo_ctx(); 470 QDF_STATUS(*cb)(struct wlan_objmgr_vdev *vdev, 471 uint8_t non_trans_vdev_id); 472 473 if (!vdev->mlo_dev_ctx) 474 return status; 475 476 sta_ctx = vdev->mlo_dev_ctx->sta_ctx; 477 if (!sta_ctx) 478 return status; 479 480 assoc_vdev = wlan_mlo_get_assoc_link_vdev(vdev); 481 if (!assoc_vdev) 482 return status; 483 484 cb = g_mlo_ctx->osif_ops->mlo_mgr_osif_link_switch_notification; 485 486 if (lswitch_req->restore_vdev_flag) { 487 wlan_vdev_mlme_clear_mlo_link_vdev(vdev); 488 wlan_vdev_mlme_set_mlo_link_vdev(assoc_vdev); 489 mlo_mgr_reset_roam_state_for_link_vdev(vdev, assoc_vdev); 490 491 lswitch_req->restore_vdev_flag = false; 492 493 status = cb(assoc_vdev, wlan_vdev_get_id(vdev)); 494 if (QDF_IS_STATUS_ERROR(status)) 495 mlo_debug("OSIF deflink restore failed"); 496 497 return status; 498 } 499 500 if (wlan_vdev_get_id(assoc_vdev) != lswitch_req->vdev_id) { 501 mlo_debug("Not on assoc VDEV no need to swap"); 502 return QDF_STATUS_SUCCESS; 503 } 504 505 mlo_sta_get_vdev_list(vdev, &vdev_count, vdev_list); 506 for (idx = 0; idx < vdev_count; idx++) { 507 if (wlan_vdev_get_id(vdev_list[idx]) != lswitch_req->vdev_id && 508 qdf_test_bit(idx, sta_ctx->wlan_connected_links)) { 509 wlan_vdev_mlme_clear_mlo_link_vdev(vdev_list[idx]); 510 wlan_vdev_mlme_set_mlo_link_vdev(assoc_vdev); 511 lswitch_req->restore_vdev_flag = true; 512 513 status = cb(assoc_vdev, 514 wlan_vdev_get_id(vdev_list[idx])); 515 break; 516 } 517 518 mlo_release_vdev_ref(vdev_list[idx]); 519 } 520 521 for (; idx < vdev_count; idx++) 522 mlo_release_vdev_ref(vdev_list[idx]); 523 524 return status; 525 } 526 527 QDF_STATUS 528 mlo_mgr_link_switch_notification(struct wlan_objmgr_vdev *vdev, 529 struct wlan_mlo_link_switch_req *lswitch_req, 530 enum wlan_mlo_link_switch_notify_reason notify_reason) 531 { 532 QDF_STATUS status; 533 534 if ((notify_reason == MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_PRE_SER || 535 notify_reason == 536 MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_POST_SER) && 537 mlo_is_chan_switch_in_progress(vdev)) { 538 mlo_debug("CSA is in progress on one of ML vdevs, abort link switch"); 539 return QDF_STATUS_E_AGAIN; 540 } 541 542 if (notify_reason == MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_PRE_SER) 543 return QDF_STATUS_SUCCESS; 544 545 status = mlo_mgr_link_switch_osif_notification(vdev, lswitch_req); 546 return status; 547 } 548 549 QDF_STATUS mlo_mgr_link_switch_init(struct wlan_objmgr_psoc *psoc, 550 struct wlan_mlo_dev_context *ml_dev) 551 { 552 ml_dev->link_ctx = 553 qdf_mem_malloc(sizeof(struct mlo_link_switch_context)); 554 555 if (!ml_dev->link_ctx) 556 return QDF_STATUS_E_NOMEM; 557 558 mlo_mgr_link_switch_init_state(ml_dev); 559 mlo_mgr_alloc_link_info_wmi_chan(ml_dev); 560 mlo_mgr_update_link_info_reset(psoc, ml_dev); 561 562 return QDF_STATUS_SUCCESS; 563 } 564 565 QDF_STATUS mlo_mgr_link_switch_deinit(struct wlan_mlo_dev_context *ml_dev) 566 { 567 mlo_mgr_free_link_info_wmi_chan(ml_dev); 568 qdf_mem_free(ml_dev->link_ctx); 569 ml_dev->link_ctx = NULL; 570 return QDF_STATUS_SUCCESS; 571 } 572 573 void 574 mlo_mgr_osif_update_connect_info(struct wlan_objmgr_vdev *vdev, int32_t link_id) 575 { 576 struct mlo_mgr_context *g_mlo_ctx = wlan_objmgr_get_mlo_ctx(); 577 struct mlo_link_info *link_info; 578 QDF_STATUS(*osif_bss_update_cb)(struct qdf_mac_addr *self_mac, 579 struct qdf_mac_addr *bssid, 580 int32_t link_id); 581 582 if (!g_mlo_ctx || !vdev->mlo_dev_ctx || !g_mlo_ctx->osif_ops || 583 !g_mlo_ctx->osif_ops->mlo_mgr_osif_update_bss_info) 584 return; 585 586 link_info = mlo_mgr_get_ap_link_by_link_id(vdev->mlo_dev_ctx, link_id); 587 if (!link_info) 588 return; 589 590 mlo_debug("VDEV ID %d, Link ID %d, STA MAC " QDF_MAC_ADDR_FMT ", BSSID " QDF_MAC_ADDR_FMT, 591 link_info->vdev_id, link_id, 592 QDF_MAC_ADDR_REF(link_info->link_addr.bytes), 593 QDF_MAC_ADDR_REF(link_info->ap_link_addr.bytes)); 594 osif_bss_update_cb = g_mlo_ctx->osif_ops->mlo_mgr_osif_update_bss_info; 595 596 osif_bss_update_cb(&link_info->link_addr, &link_info->ap_link_addr, 597 link_id); 598 } 599 600 QDF_STATUS mlo_mgr_link_switch_disconnect_done(struct wlan_objmgr_vdev *vdev, 601 QDF_STATUS discon_status, 602 bool is_link_switch_resp) 603 { 604 QDF_STATUS status; 605 enum mlo_link_switch_req_state cur_state; 606 struct mlo_link_info *new_link_info; 607 struct qdf_mac_addr mac_addr, mld_addr; 608 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 609 struct wlan_mlo_link_switch_req *req = &mlo_dev_ctx->link_ctx->last_req; 610 611 if (!is_link_switch_resp) { 612 mlo_mgr_link_switch_trans_abort_state(mlo_dev_ctx); 613 return QDF_STATUS_SUCCESS; 614 } 615 616 cur_state = mlo_mgr_link_switch_get_curr_state(mlo_dev_ctx); 617 if (QDF_IS_STATUS_ERROR(discon_status) || 618 cur_state != MLO_LINK_SWITCH_STATE_DISCONNECT_CURR_LINK) { 619 mlo_err("VDEV %d link switch disconnect req failed", 620 req->vdev_id); 621 mlo_mgr_remove_link_switch_cmd(vdev); 622 return QDF_STATUS_SUCCESS; 623 } 624 625 mlo_debug("VDEV %d link switch disconnect complete", 626 wlan_vdev_get_id(vdev)); 627 628 new_link_info = 629 mlo_mgr_get_ap_link_by_link_id(vdev->mlo_dev_ctx, 630 req->new_ieee_link_id); 631 if (!new_link_info) { 632 mlo_err("New link not found in mlo dev ctx"); 633 mlo_mgr_remove_link_switch_cmd(vdev); 634 return QDF_STATUS_E_INVAL; 635 } 636 637 qdf_copy_macaddr(&mld_addr, &mlo_dev_ctx->mld_addr); 638 qdf_copy_macaddr(&mac_addr, &new_link_info->link_addr); 639 640 status = mlo_mgr_link_switch_trans_next_state(mlo_dev_ctx); 641 if (QDF_IS_STATUS_ERROR(status)) { 642 mlo_mgr_remove_link_switch_cmd(vdev); 643 return status; 644 } 645 646 status = wlan_vdev_mlme_send_set_mac_addr(mac_addr, mld_addr, vdev); 647 if (QDF_IS_STATUS_ERROR(status)) { 648 mlo_debug("VDEV %d set MAC addr FW request failed", 649 req->vdev_id); 650 mlo_mgr_remove_link_switch_cmd(vdev); 651 } 652 653 return status; 654 } 655 656 QDF_STATUS mlo_mgr_link_switch_set_mac_addr_resp(struct wlan_objmgr_vdev *vdev, 657 uint8_t resp_status) 658 { 659 QDF_STATUS status = QDF_STATUS_E_INVAL; 660 enum mlo_link_switch_req_state cur_state; 661 struct mlo_mgr_context *g_mlo_ctx = wlan_objmgr_get_mlo_ctx(); 662 struct wlan_mlo_link_switch_req *req; 663 struct mlo_link_info *new_link_info; 664 665 if (resp_status) { 666 mlo_err("VDEV %d set MAC address response %d", 667 wlan_vdev_get_id(vdev), resp_status); 668 mlo_mgr_remove_link_switch_cmd(vdev); 669 return status; 670 } 671 672 if (!g_mlo_ctx) { 673 mlo_err("global mlo ctx NULL"); 674 mlo_mgr_remove_link_switch_cmd(vdev); 675 return status; 676 } 677 678 req = &vdev->mlo_dev_ctx->link_ctx->last_req; 679 cur_state = mlo_mgr_link_switch_get_curr_state(vdev->mlo_dev_ctx); 680 if (cur_state != MLO_LINK_SWITCH_STATE_SET_MAC_ADDR) { 681 mlo_err("Link switch cmd flushed, there can be MAC addr mismatch with FW"); 682 mlo_mgr_remove_link_switch_cmd(vdev); 683 return status; 684 } 685 686 new_link_info = 687 mlo_mgr_get_ap_link_by_link_id(vdev->mlo_dev_ctx, 688 req->new_ieee_link_id); 689 if (!new_link_info) { 690 mlo_mgr_remove_link_switch_cmd(vdev); 691 return status; 692 } 693 694 wlan_vdev_mlme_set_macaddr(vdev, new_link_info->link_addr.bytes); 695 wlan_vdev_mlme_set_linkaddr(vdev, new_link_info->link_addr.bytes); 696 697 status = g_mlo_ctx->osif_ops->mlo_mgr_osif_update_mac_addr( 698 req->curr_ieee_link_id, 699 req->new_ieee_link_id, 700 req->vdev_id); 701 if (QDF_IS_STATUS_ERROR(status)) { 702 mlo_debug("VDEV %d OSIF MAC addr update failed %d", 703 req->vdev_id, status); 704 mlo_mgr_remove_link_switch_cmd(vdev); 705 return status; 706 } 707 708 status = mlo_mgr_link_switch_trans_next_state(vdev->mlo_dev_ctx); 709 if (QDF_IS_STATUS_ERROR(status)) { 710 mlo_mgr_remove_link_switch_cmd(vdev); 711 return status; 712 } 713 714 status = mlo_mgr_link_switch_start_connect(vdev); 715 716 return status; 717 } 718 719 QDF_STATUS mlo_mgr_link_switch_start_connect(struct wlan_objmgr_vdev *vdev) 720 { 721 QDF_STATUS status = QDF_STATUS_E_INVAL; 722 struct wlan_cm_connect_req conn_req = {0}; 723 struct mlo_link_info *mlo_link_info; 724 uint8_t *vdev_mac; 725 struct wlan_mlo_sta *sta_ctx; 726 struct wlan_mlo_link_switch_req *req = 727 &vdev->mlo_dev_ctx->link_ctx->last_req; 728 729 sta_ctx = vdev->mlo_dev_ctx->sta_ctx; 730 731 mlo_link_info = 732 mlo_mgr_get_ap_link_by_link_id(vdev->mlo_dev_ctx, 733 req->new_ieee_link_id); 734 735 if (!mlo_link_info) { 736 mlo_err("New link ID not found"); 737 goto out; 738 } 739 740 vdev_mac = wlan_vdev_mlme_get_linkaddr(vdev); 741 if (!qdf_is_macaddr_equal(&mlo_link_info->link_addr, 742 (struct qdf_mac_addr *)vdev_mac)) { 743 mlo_err("MAC address not equal for the new Link ID VDEV: " QDF_MAC_ADDR_FMT ", MLO_LINK: " QDF_MAC_ADDR_FMT, 744 QDF_MAC_ADDR_REF(vdev_mac), 745 QDF_MAC_ADDR_REF(mlo_link_info->link_addr.bytes)); 746 goto out; 747 } 748 749 wlan_vdev_set_link_id(vdev, req->new_ieee_link_id); 750 copied_conn_req_lock_acquire(sta_ctx); 751 if (sta_ctx->copied_conn_req) { 752 qdf_mem_copy(&conn_req, sta_ctx->copied_conn_req, 753 sizeof(struct wlan_cm_connect_req)); 754 } else { 755 copied_conn_req_lock_release(sta_ctx); 756 goto out; 757 } 758 copied_conn_req_lock_release(sta_ctx); 759 760 conn_req.vdev_id = wlan_vdev_get_id(vdev); 761 conn_req.source = CM_MLO_LINK_SWITCH_CONNECT; 762 qdf_copy_macaddr(&conn_req.bssid, &mlo_link_info->ap_link_addr); 763 mlo_allocate_and_copy_ies(&conn_req, sta_ctx->copied_conn_req); 764 conn_req.crypto.auth_type = 0; 765 conn_req.ml_parnter_info = sta_ctx->ml_partner_info; 766 status = wlan_cm_start_connect(vdev, &conn_req); 767 if (QDF_IS_STATUS_SUCCESS(status)) 768 mlo_update_connected_links(vdev, 1); 769 770 wlan_cm_free_connect_req_param(&conn_req); 771 772 out: 773 if (QDF_IS_STATUS_ERROR(status)) { 774 mlo_err("VDEV %d link switch connect request failed", 775 wlan_vdev_get_id(vdev)); 776 mlo_mgr_remove_link_switch_cmd(vdev); 777 } 778 779 return status; 780 } 781 782 static void 783 mlo_mgr_link_switch_connect_success_trans_state(struct wlan_objmgr_vdev *vdev) 784 { 785 enum mlo_link_switch_req_state curr_state; 786 787 /* 788 * If connection is success, then sending link switch failure to FW 789 * might result in not updating VDEV to link mapping in FW and FW may 790 * immediately send next link switch with params corresponding to 791 * pre-link switch which may vary post-link switch in host and might 792 * not be valid and results in Host-FW out-of-sync. 793 * 794 * Force the result of link switch in align with link switch connect 795 * so that Host and FW are not out of sync. 796 */ 797 mlo_dev_lock_acquire(vdev->mlo_dev_ctx); 798 curr_state = vdev->mlo_dev_ctx->link_ctx->last_req.state; 799 vdev->mlo_dev_ctx->link_ctx->last_req.state = 800 MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS; 801 mlo_dev_lock_release(vdev->mlo_dev_ctx); 802 803 if (curr_state != MLO_LINK_SWITCH_STATE_CONNECT_NEW_LINK) 804 mlo_debug("Current link switch state %d changed", curr_state); 805 } 806 807 void mlo_mgr_link_switch_connect_done(struct wlan_objmgr_vdev *vdev, 808 QDF_STATUS status) 809 { 810 struct wlan_mlo_link_switch_req *req; 811 812 req = &vdev->mlo_dev_ctx->link_ctx->last_req; 813 if (QDF_IS_STATUS_SUCCESS(status)) 814 mlo_mgr_link_switch_connect_success_trans_state(vdev); 815 else 816 mlo_err("VDEV %d link switch connect failed", req->vdev_id); 817 818 mlo_mgr_remove_link_switch_cmd(vdev); 819 } 820 821 static enum wlan_mlo_link_switch_notify_reason 822 mlo_mgr_link_switch_get_notify_reason(struct wlan_objmgr_vdev *vdev) 823 { 824 enum mlo_link_switch_req_state curr_state; 825 enum wlan_mlo_link_switch_notify_reason notify_reason; 826 827 curr_state = mlo_mgr_link_switch_get_curr_state(vdev->mlo_dev_ctx); 828 switch (curr_state) { 829 case MLO_LINK_SWITCH_STATE_IDLE: 830 notify_reason = MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_PRE_SER; 831 break; 832 case MLO_LINK_SWITCH_STATE_INIT: 833 notify_reason = 834 MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_POST_SER; 835 break; 836 case MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS: 837 notify_reason = MLO_LINK_SWITCH_NOTIFY_REASON_STOP_SUCCESS; 838 break; 839 default: 840 notify_reason = MLO_LINK_SWITCH_NOTIFY_REASON_STOP_FAILURE; 841 break; 842 } 843 844 return notify_reason; 845 } 846 847 static QDF_STATUS 848 mlo_mgr_start_link_switch(struct wlan_objmgr_vdev *vdev, 849 struct wlan_serialization_command *cmd) 850 { 851 QDF_STATUS status = QDF_STATUS_E_INVAL; 852 uint8_t vdev_id, old_link_id, new_link_id; 853 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 854 struct wlan_mlo_link_switch_req *req = &mlo_dev_ctx->link_ctx->last_req; 855 struct qdf_mac_addr bssid; 856 857 vdev_id = wlan_vdev_get_id(vdev); 858 old_link_id = req->curr_ieee_link_id; 859 new_link_id = req->new_ieee_link_id; 860 861 mlo_debug("VDEV %d start link switch", vdev_id); 862 mlo_mgr_link_switch_trans_next_state(mlo_dev_ctx); 863 864 if (!wlan_cm_is_vdev_connected(vdev)) { 865 mlo_err("VDEV %d not in connected state", vdev_id); 866 return status; 867 } 868 869 status = wlan_vdev_get_bss_peer_mac(vdev, &bssid); 870 if (QDF_IS_STATUS_ERROR(status)) 871 return status; 872 873 status = wlan_vdev_get_bss_peer_mld_mac(vdev, &req->peer_mld_addr); 874 if (QDF_IS_STATUS_ERROR(status)) 875 return status; 876 877 status = mlo_mgr_link_switch_notify(vdev, req); 878 if (QDF_IS_STATUS_ERROR(status)) 879 return status; 880 881 wlan_vdev_mlme_set_mlo_link_switch_in_progress(vdev); 882 status = mlo_mgr_link_switch_trans_next_state(mlo_dev_ctx); 883 if (QDF_IS_STATUS_ERROR(status)) 884 return status; 885 886 status = wlan_cm_disconnect(vdev, CM_MLO_LINK_SWITCH_DISCONNECT, 887 REASON_FW_TRIGGERED_LINK_SWITCH, &bssid); 888 889 if (QDF_IS_STATUS_ERROR(status)) 890 mlo_err("VDEV %d disconnect request not handled", req->vdev_id); 891 892 return status; 893 } 894 895 static QDF_STATUS 896 mlo_mgr_ser_link_switch_cb(struct wlan_serialization_command *cmd, 897 enum wlan_serialization_cb_reason cb_reason) 898 { 899 struct wlan_objmgr_vdev *vdev; 900 QDF_STATUS status = QDF_STATUS_SUCCESS; 901 struct wlan_mlo_link_switch_req *req; 902 enum qdf_hang_reason reason = QDF_VDEV_ACTIVE_SER_LINK_SWITCH_TIMEOUT; 903 904 if (!cmd) { 905 mlo_err("cmd is NULL, reason: %d", cb_reason); 906 QDF_ASSERT(0); 907 return QDF_STATUS_E_NULL_VALUE; 908 } 909 910 vdev = cmd->vdev; 911 req = &vdev->mlo_dev_ctx->link_ctx->last_req; 912 913 switch (cb_reason) { 914 case WLAN_SER_CB_ACTIVATE_CMD: 915 status = mlo_mgr_start_link_switch(vdev, cmd); 916 if (QDF_IS_STATUS_ERROR(status)) { 917 mlo_mgr_link_switch_trans_abort_state(vdev->mlo_dev_ctx); 918 mlo_mgr_link_switch_notify(vdev, req); 919 } 920 break; 921 case WLAN_SER_CB_RELEASE_MEM_CMD: 922 mlo_mgr_link_switch_complete(vdev); 923 break; 924 case WLAN_SER_CB_CANCEL_CMD: 925 mlo_err("Link switch cmd cancelled"); 926 break; 927 case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT: 928 mlo_err("Link switch active cmd timeout"); 929 wlan_cm_trigger_panic_on_cmd_timeout(vdev, reason); 930 break; 931 default: 932 QDF_ASSERT(0); 933 mlo_mgr_link_switch_complete(vdev); 934 break; 935 } 936 937 return status; 938 } 939 940 void mlo_mgr_remove_link_switch_cmd(struct wlan_objmgr_vdev *vdev) 941 { 942 struct wlan_serialization_queued_cmd_info cmd_info; 943 enum mlo_link_switch_req_state cur_state; 944 uint8_t vdev_id = wlan_vdev_get_id(vdev); 945 struct wlan_mlo_link_switch_req *req; 946 947 cur_state = mlo_mgr_link_switch_get_curr_state(vdev->mlo_dev_ctx); 948 if (cur_state == MLO_LINK_SWITCH_STATE_IDLE) 949 return; 950 951 req = &vdev->mlo_dev_ctx->link_ctx->last_req; 952 mlo_mgr_link_switch_notify(vdev, req); 953 954 /* Handle any pending disconnect */ 955 mlo_handle_pending_disconnect(vdev); 956 957 if (req->reason == MLO_LINK_SWITCH_REASON_HOST_FORCE) { 958 mlo_debug("Link switch not serialized"); 959 mlo_mgr_link_switch_complete(vdev); 960 return; 961 } 962 963 cmd_info.cmd_id = (vdev_id << 16) + (req->new_ieee_link_id << 8) + 964 (req->curr_ieee_link_id); 965 cmd_info.req_type = WLAN_SER_CANCEL_NON_SCAN_CMD; 966 cmd_info.cmd_type = WLAN_SER_CMD_MLO_VDEV_LINK_SWITCH; 967 cmd_info.vdev = vdev; 968 cmd_info.queue_type = WLAN_SERIALIZATION_ACTIVE_QUEUE; 969 970 wlan_serialization_remove_cmd(&cmd_info); 971 } 972 973 #define MLO_MGR_MAX_LSWITCH_TIMEOUT 35000 974 975 QDF_STATUS mlo_mgr_ser_link_switch_cmd(struct wlan_objmgr_vdev *vdev, 976 struct wlan_mlo_link_switch_req *req) 977 { 978 QDF_STATUS status; 979 enum wlan_serialization_status ser_cmd_status; 980 struct wlan_serialization_command cmd = {0}; 981 uint8_t vdev_id = wlan_vdev_get_id(vdev); 982 struct mlo_link_switch_context *link_ctx; 983 984 if (!vdev->mlo_dev_ctx) { 985 mlo_err("ML dev ctx NULL, reject link switch"); 986 return QDF_STATUS_E_INVAL; 987 } 988 989 link_ctx = vdev->mlo_dev_ctx->link_ctx; 990 link_ctx->last_req = *req; 991 992 cmd.cmd_type = WLAN_SER_CMD_MLO_VDEV_LINK_SWITCH; 993 cmd.cmd_id = (vdev_id << 16) + (req->new_ieee_link_id << 8) + 994 (req->curr_ieee_link_id); 995 cmd.cmd_cb = mlo_mgr_ser_link_switch_cb; 996 cmd.source = WLAN_UMAC_COMP_MLO_MGR; 997 cmd.is_high_priority = false; 998 cmd.cmd_timeout_duration = MLO_MGR_MAX_LSWITCH_TIMEOUT; 999 cmd.vdev = vdev; 1000 cmd.is_blocking = true; 1001 1002 if (req->reason == MLO_LINK_SWITCH_REASON_HOST_FORCE) { 1003 mlo_debug("Do not serialize link switch"); 1004 status = mlo_mgr_start_link_switch(vdev, &cmd); 1005 if (QDF_IS_STATUS_ERROR(status)) { 1006 mlo_mgr_link_switch_trans_abort_state(vdev->mlo_dev_ctx); 1007 mlo_mgr_link_switch_notify(vdev, req); 1008 } 1009 return status; 1010 } 1011 1012 ser_cmd_status = wlan_serialization_request(&cmd); 1013 switch (ser_cmd_status) { 1014 case WLAN_SER_CMD_PENDING: 1015 mlo_debug("Link switch cmd in pending queue"); 1016 break; 1017 case WLAN_SER_CMD_ACTIVE: 1018 mlo_debug("Link switch cmd in active queue"); 1019 break; 1020 default: 1021 return QDF_STATUS_E_INVAL; 1022 } 1023 1024 return QDF_STATUS_SUCCESS; 1025 } 1026 1027 QDF_STATUS mlo_mgr_link_switch_notify(struct wlan_objmgr_vdev *vdev, 1028 struct wlan_mlo_link_switch_req *req) 1029 { 1030 int8_t i; 1031 QDF_STATUS status, ret_status = QDF_STATUS_SUCCESS; 1032 enum wlan_mlo_link_switch_notify_reason notify_reason; 1033 struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx(); 1034 1035 if (!mlo_mgr_ctx) { 1036 mlo_err("Global mlo mgr NULL"); 1037 return QDF_STATUS_E_NULL_VALUE; 1038 } 1039 1040 notify_reason = mlo_mgr_link_switch_get_notify_reason(vdev); 1041 for (i = 0; i < WLAN_UMAC_COMP_ID_MAX; i++) { 1042 if (!mlo_mgr_ctx->lswitch_notifier[i].in_use) 1043 continue; 1044 1045 status = mlo_mgr_ctx->lswitch_notifier[i].cb(vdev, req, 1046 notify_reason); 1047 if (QDF_IS_STATUS_SUCCESS(status)) 1048 continue; 1049 1050 mlo_debug("Link switch notify %d failed in %d", 1051 notify_reason, i); 1052 ret_status = status; 1053 if (notify_reason == MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_PRE_SER) 1054 break; 1055 } 1056 1057 return ret_status; 1058 } 1059 1060 QDF_STATUS 1061 mlo_mgr_link_switch_validate_request(struct wlan_objmgr_vdev *vdev, 1062 struct wlan_mlo_link_switch_req *req) 1063 { 1064 QDF_STATUS status = QDF_STATUS_E_INVAL; 1065 uint8_t vdev_id = wlan_vdev_get_id(vdev); 1066 struct mlo_link_info *new_link_info; 1067 1068 if (req->curr_ieee_link_id >= WLAN_INVALID_LINK_ID || 1069 req->new_ieee_link_id >= WLAN_INVALID_LINK_ID) { 1070 mlo_err("Invalid link params, curr link id %d, new link id %d", 1071 req->curr_ieee_link_id, req->new_ieee_link_id); 1072 return status; 1073 } 1074 1075 new_link_info = mlo_mgr_get_ap_link_by_link_id(vdev->mlo_dev_ctx, 1076 req->new_ieee_link_id); 1077 if (!new_link_info) { 1078 mlo_err("New link id %d not part of association", 1079 req->new_ieee_link_id); 1080 return status; 1081 } 1082 1083 if (new_link_info->vdev_id != WLAN_INVALID_VDEV_ID) { 1084 mlo_err("requested link already active on other vdev:%d", 1085 new_link_info->vdev_id); 1086 return status; 1087 } 1088 1089 if (!mlo_is_mld_sta(vdev)) { 1090 mlo_err("Link switch req not valid for VDEV %d", vdev_id); 1091 return status; 1092 } 1093 1094 if (!wlan_cm_is_vdev_connected(vdev)) { 1095 mlo_err("VDEV %d not in connected state", vdev_id); 1096 return status; 1097 } 1098 1099 if (mlo_mgr_is_link_switch_in_progress(vdev)) { 1100 mlo_err("Link switch already in progress"); 1101 return status; 1102 } 1103 1104 if (wlan_vdev_get_link_id(vdev) != req->curr_ieee_link_id) { 1105 mlo_err("VDEV %d link id wrong, curr link id %d", 1106 vdev_id, wlan_vdev_get_link_id(vdev)); 1107 return status; 1108 } 1109 1110 /* Notify callers on the new link switch request before serializing */ 1111 status = mlo_mgr_link_switch_notify(vdev, req); 1112 if (QDF_IS_STATUS_ERROR(status)) { 1113 mlo_err("Link switch rejected in pre-serialize notify"); 1114 return status; 1115 } 1116 1117 return QDF_STATUS_SUCCESS; 1118 } 1119 1120 QDF_STATUS mlo_mgr_link_switch_request_params(struct wlan_objmgr_psoc *psoc, 1121 void *evt_params) 1122 { 1123 QDF_STATUS status; 1124 struct wlan_mlo_link_switch_cnf cnf_params = {0}; 1125 struct wlan_mlo_link_switch_req *req; 1126 struct wlan_objmgr_vdev *vdev; 1127 1128 if (!evt_params) { 1129 mlo_err("Invalid params"); 1130 return QDF_STATUS_E_INVAL; 1131 } 1132 1133 req = (struct wlan_mlo_link_switch_req *)evt_params; 1134 1135 /* The reference is released on Link Switch status confirm to FW */ 1136 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, req->vdev_id, 1137 WLAN_MLO_MGR_ID); 1138 if (!vdev) { 1139 mlo_err("Invalid link switch VDEV %d", req->vdev_id); 1140 1141 /* Fill reject params here and send to FW as VDEV is invalid */ 1142 cnf_params.vdev_id = req->vdev_id; 1143 cnf_params.status = MLO_LINK_SWITCH_CNF_STATUS_REJECT; 1144 mlo_mgr_link_switch_send_cnf_cmd(psoc, &cnf_params); 1145 return QDF_STATUS_E_INVAL; 1146 } 1147 1148 mlo_debug("VDEV %d, curr_link_id %d, new_link_id %d, new_freq %d, new_phymode: %d, reason %d", 1149 req->vdev_id, req->curr_ieee_link_id, req->new_ieee_link_id, 1150 req->new_primary_freq, req->new_phymode, req->reason); 1151 1152 status = mlo_mgr_link_switch_validate_request(vdev, req); 1153 if (QDF_IS_STATUS_ERROR(status)) { 1154 mlo_debug("Link switch params/request invalid"); 1155 mlo_mgr_link_switch_complete(vdev); 1156 return QDF_STATUS_E_INVAL; 1157 } 1158 1159 status = mlo_mgr_ser_link_switch_cmd(vdev, req); 1160 if (QDF_IS_STATUS_ERROR(status)) { 1161 mlo_err("Failed to serialize link switch command"); 1162 mlo_mgr_link_switch_complete(vdev); 1163 } 1164 1165 return status; 1166 } 1167 1168 QDF_STATUS 1169 mlo_mgr_link_state_switch_info_handler(struct wlan_objmgr_psoc *psoc, 1170 struct mlo_link_switch_state_info *info) 1171 { 1172 uint8_t i; 1173 1174 for (i = 0; i < info->num_params; i++) 1175 wlan_connectivity_mld_link_status_event(psoc, 1176 &info->link_switch_param[i]); 1177 1178 return QDF_STATUS_SUCCESS; 1179 } 1180 1181 QDF_STATUS mlo_mgr_link_switch_complete(struct wlan_objmgr_vdev *vdev) 1182 { 1183 enum mlo_link_switch_req_state state; 1184 struct wlan_mlo_link_switch_cnf params = {0}; 1185 struct mlo_link_switch_context *link_ctx; 1186 struct wlan_mlo_link_switch_req *req; 1187 struct wlan_objmgr_psoc *psoc; 1188 1189 /* Not checking NULL value as reference is already taken for vdev */ 1190 psoc = wlan_vdev_get_psoc(vdev); 1191 1192 link_ctx = vdev->mlo_dev_ctx->link_ctx; 1193 req = &link_ctx->last_req; 1194 1195 state = mlo_mgr_link_switch_get_curr_state(vdev->mlo_dev_ctx); 1196 if (state != MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS) 1197 params.status = MLO_LINK_SWITCH_CNF_STATUS_REJECT; 1198 else 1199 params.status = MLO_LINK_SWITCH_CNF_STATUS_ACCEPT; 1200 1201 params.vdev_id = wlan_vdev_get_id(vdev); 1202 params.reason = MLO_LINK_SWITCH_CNF_REASON_BSS_PARAMS_CHANGED; 1203 1204 mlo_mgr_link_switch_send_cnf_cmd(psoc, ¶ms); 1205 1206 mlo_mgr_link_switch_init_state(vdev->mlo_dev_ctx); 1207 wlan_vdev_mlme_clear_mlo_link_switch_in_progress(vdev); 1208 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 1209 return QDF_STATUS_SUCCESS; 1210 } 1211 1212 QDF_STATUS 1213 mlo_mgr_link_switch_send_cnf_cmd(struct wlan_objmgr_psoc *psoc, 1214 struct wlan_mlo_link_switch_cnf *cnf_params) 1215 { 1216 QDF_STATUS status; 1217 struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops; 1218 1219 mlo_debug("VDEV %d link switch completed, %s", cnf_params->vdev_id, 1220 (cnf_params->status == MLO_LINK_SWITCH_CNF_STATUS_ACCEPT) ? 1221 "success" : "fail"); 1222 1223 mlo_tx_ops = &psoc->soc_cb.tx_ops->mlo_ops; 1224 if (!mlo_tx_ops || !mlo_tx_ops->send_mlo_link_switch_cnf_cmd) { 1225 mlo_err("handler is not registered"); 1226 return QDF_STATUS_E_INVAL; 1227 } 1228 1229 status = mlo_tx_ops->send_mlo_link_switch_cnf_cmd(psoc, cnf_params); 1230 if (QDF_IS_STATUS_ERROR(status)) 1231 mlo_err("Link switch status update to FW failed"); 1232 1233 return status; 1234 } 1235 1236 QDF_STATUS 1237 mlo_mgr_link_switch_defer_disconnect_req(struct wlan_objmgr_vdev *vdev, 1238 enum wlan_cm_source source, 1239 enum wlan_reason_code reason) 1240 { 1241 struct wlan_mlo_dev_context *mlo_dev_ctx; 1242 struct wlan_mlo_sta *sta_ctx; 1243 1244 if (!mlo_mgr_is_link_switch_in_progress(vdev)) { 1245 mlo_info("Link switch not in progress"); 1246 return QDF_STATUS_E_INVAL; 1247 } 1248 1249 mlo_dev_ctx = vdev->mlo_dev_ctx; 1250 sta_ctx = mlo_dev_ctx->sta_ctx; 1251 1252 if (!sta_ctx) { 1253 mlo_err("sta ctx null"); 1254 return QDF_STATUS_E_NULL_VALUE; 1255 } 1256 1257 /* Move current link switch to abort state */ 1258 mlo_mgr_link_switch_trans_abort_state(mlo_dev_ctx); 1259 1260 if (sta_ctx->disconn_req) { 1261 mlo_debug("Pending disconnect from source %d, reason %d", 1262 sta_ctx->disconn_req->source, 1263 sta_ctx->disconn_req->reason_code); 1264 return QDF_STATUS_E_ALREADY; 1265 } 1266 1267 sta_ctx->disconn_req = 1268 qdf_mem_malloc(sizeof(struct wlan_cm_disconnect_req)); 1269 if (!sta_ctx->disconn_req) 1270 return QDF_STATUS_E_NOMEM; 1271 1272 sta_ctx->disconn_req->vdev_id = wlan_vdev_get_id(vdev); 1273 sta_ctx->disconn_req->source = source; 1274 sta_ctx->disconn_req->reason_code = reason; 1275 1276 mlo_debug("Deferred disconnect source: %d, reason: %d", source, reason); 1277 return QDF_STATUS_SUCCESS; 1278 } 1279 #endif 1280