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