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 30 void mlo_mgr_update_link_info_mac_addr(struct wlan_objmgr_vdev *vdev, 31 struct wlan_mlo_link_mac_update *ml_mac_update) 32 { 33 struct mlo_link_info *link_info; 34 uint8_t link_info_iter; 35 struct mlo_vdev_link_mac_info *link_mac_info; 36 37 if (!vdev || !vdev->mlo_dev_ctx || !ml_mac_update) 38 return; 39 40 link_mac_info = &ml_mac_update->link_mac_info[0]; 41 link_info = &vdev->mlo_dev_ctx->link_ctx->links_info[0]; 42 43 for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS; 44 link_info_iter++) { 45 qdf_mem_copy(&link_info->link_addr, 46 &link_mac_info->link_mac_addr, 47 QDF_MAC_ADDR_SIZE); 48 49 link_info->vdev_id = link_mac_info->vdev_id; 50 mlo_debug("Update STA Link info for vdev_id %d, link_addr:" QDF_MAC_ADDR_FMT, 51 link_info->vdev_id, 52 QDF_MAC_ADDR_REF(link_info->link_addr.bytes)); 53 link_mac_info++; 54 link_info++; 55 } 56 } 57 58 void mlo_mgr_update_ap_link_info(struct wlan_objmgr_vdev *vdev, uint8_t link_id, 59 uint8_t *ap_link_addr, 60 struct wlan_channel channel) 61 { 62 struct mlo_link_info *link_info; 63 uint8_t link_info_iter; 64 65 if (!vdev || !vdev->mlo_dev_ctx || !ap_link_addr) 66 return; 67 68 link_info = &vdev->mlo_dev_ctx->link_ctx->links_info[0]; 69 for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS; 70 link_info_iter++) { 71 if (qdf_is_macaddr_zero(&link_info->ap_link_addr)) 72 break; 73 74 link_info++; 75 } 76 77 if (link_info_iter == WLAN_MAX_ML_BSS_LINKS) 78 return; 79 80 qdf_mem_copy(&link_info->ap_link_addr, ap_link_addr, QDF_MAC_ADDR_SIZE); 81 82 qdf_mem_copy(link_info->link_chan_info, &channel, sizeof(channel)); 83 link_info->link_status_flags = 0; 84 link_info->link_id = link_id; 85 86 mlo_debug("Update AP Link info for link_id: %d, vdev_id:%d, link_addr:" QDF_MAC_ADDR_FMT, 87 link_info->link_id, link_info->vdev_id, 88 QDF_MAC_ADDR_REF(link_info->ap_link_addr.bytes)); 89 } 90 91 void mlo_mgr_update_ap_channel_info(struct wlan_objmgr_vdev *vdev, uint8_t link_id, 92 uint8_t *ap_link_addr, 93 struct wlan_channel channel) 94 { 95 struct mlo_link_info *link_info; 96 97 if (!vdev || !vdev->mlo_dev_ctx || !ap_link_addr) 98 return; 99 100 link_info = mlo_mgr_get_ap_link_by_link_id(vdev, link_id); 101 if (!link_info) 102 return; 103 104 qdf_mem_copy(link_info->link_chan_info, &channel, 105 sizeof(*link_info->link_chan_info)); 106 107 mlo_debug("Update AP Channel info link_id: %d, vdev_id:%d, link_addr:" QDF_MAC_ADDR_FMT, 108 link_info->link_id, link_info->vdev_id, 109 QDF_MAC_ADDR_REF(link_info->ap_link_addr.bytes)); 110 mlo_debug("Ch_freq: %d, freq1: %d, freq2: %d phy_mode: %d", 111 link_info->link_chan_info->ch_freq, 112 link_info->link_chan_info->ch_cfreq1, 113 link_info->link_chan_info->ch_cfreq2, 114 link_info->link_chan_info->ch_phymode); 115 } 116 117 void mlo_mgr_update_link_info_reset(struct wlan_mlo_dev_context *ml_dev) 118 { 119 struct mlo_link_info *link_info; 120 uint8_t link_info_iter; 121 122 if (!ml_dev) 123 return; 124 125 link_info = &ml_dev->link_ctx->links_info[0]; 126 127 for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS; 128 link_info_iter++) { 129 qdf_mem_zero(&link_info->link_addr, QDF_MAC_ADDR_SIZE); 130 qdf_mem_zero(&link_info->ap_link_addr, QDF_MAC_ADDR_SIZE); 131 qdf_mem_zero(link_info->link_chan_info, 132 sizeof(*link_info->link_chan_info)); 133 link_info->vdev_id = WLAN_INVALID_VDEV_ID; 134 link_info->link_id = WLAN_INVALID_LINK_ID; 135 link_info->link_status_flags = 0; 136 link_info++; 137 } 138 } 139 140 void mlo_mgr_reset_ap_link_info(struct wlan_objmgr_vdev *vdev) 141 { 142 struct mlo_link_info *link_info; 143 uint8_t link_info_iter; 144 struct wlan_objmgr_psoc *psoc; 145 146 if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->link_ctx) 147 return; 148 149 psoc = wlan_vdev_get_psoc(vdev); 150 if (!psoc) { 151 mlo_err("psoc NULL"); 152 return; 153 } 154 155 link_info = &vdev->mlo_dev_ctx->link_ctx->links_info[0]; 156 157 for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS; 158 link_info_iter++) { 159 if (!qdf_is_macaddr_zero(&link_info->ap_link_addr) && 160 !qdf_is_macaddr_zero(&link_info->link_addr)) 161 wlan_crypto_free_key_by_link_id( 162 psoc, 163 &link_info->link_addr, 164 link_info->link_id); 165 qdf_mem_zero(&link_info->ap_link_addr, QDF_MAC_ADDR_SIZE); 166 qdf_mem_zero(link_info->link_chan_info, 167 sizeof(*link_info->link_chan_info)); 168 link_info->link_id = WLAN_INVALID_LINK_ID; 169 link_info->link_status_flags = 0; 170 link_info++; 171 } 172 } 173 174 struct mlo_link_info 175 *mlo_mgr_get_ap_link_by_link_id(struct wlan_objmgr_vdev *vdev, int link_id) 176 { 177 struct mlo_link_info *link_info; 178 uint8_t link_info_iter; 179 180 if (!vdev || link_id < 0 || link_id > 15) 181 return NULL; 182 183 link_info = &vdev->mlo_dev_ctx->link_ctx->links_info[0]; 184 for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS; 185 link_info_iter++) { 186 if (link_info->link_id == link_id) 187 return link_info; 188 link_info++; 189 } 190 191 return NULL; 192 } 193 194 struct mlo_link_info 195 *mlo_mgr_get_ap_link(struct wlan_objmgr_vdev *vdev) 196 { 197 if (!vdev || !vdev->mlo_dev_ctx) 198 return NULL; 199 200 return &vdev->mlo_dev_ctx->link_ctx->links_info[0]; 201 } 202 203 static 204 void mlo_mgr_alloc_link_info_wmi_chan(struct wlan_mlo_dev_context *ml_dev) 205 { 206 struct mlo_link_info *link_info; 207 uint8_t link_info_iter; 208 209 if (!ml_dev) 210 return; 211 212 link_info = &ml_dev->link_ctx->links_info[0]; 213 for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS; 214 link_info_iter++) { 215 link_info->link_chan_info = 216 qdf_mem_malloc(sizeof(*link_info->link_chan_info)); 217 if (!link_info->link_chan_info) 218 return; 219 link_info++; 220 } 221 } 222 223 static 224 void mlo_mgr_free_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 if (link_info->link_chan_info) 236 qdf_mem_free(link_info->link_chan_info); 237 link_info++; 238 } 239 } 240 241 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 242 struct wlan_objmgr_vdev * 243 mlo_mgr_link_switch_get_assoc_vdev(struct wlan_objmgr_vdev *vdev) 244 { 245 uint8_t vdev_id; 246 struct wlan_objmgr_psoc *psoc; 247 struct wlan_objmgr_vdev *assoc_vdev; 248 249 if (!vdev) 250 return NULL; 251 252 if (!mlo_mgr_is_link_switch_on_assoc_vdev(vdev)) 253 return NULL; 254 255 vdev_id = vdev->mlo_dev_ctx->link_ctx->last_req.vdev_id; 256 psoc = wlan_vdev_get_psoc(vdev); 257 if (!psoc) { 258 mlo_err("PSOC NULL"); 259 return NULL; 260 } 261 262 assoc_vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, 263 WLAN_MLO_MGR_ID); 264 265 return assoc_vdev; 266 } 267 268 bool mlo_mgr_is_link_switch_in_progress(struct wlan_objmgr_vdev *vdev) 269 { 270 enum mlo_link_switch_req_state state; 271 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 272 273 if (!mlo_dev_ctx) 274 return false; 275 276 state = mlo_mgr_link_switch_get_curr_state(mlo_dev_ctx); 277 return (state != MLO_LINK_SWITCH_STATE_IDLE); 278 } 279 280 bool mlo_mgr_is_link_switch_on_assoc_vdev(struct wlan_objmgr_vdev *vdev) 281 { 282 if (!mlo_mgr_is_link_switch_in_progress(vdev)) 283 return false; 284 285 return vdev->mlo_dev_ctx->link_ctx->last_req.restore_vdev_flag; 286 } 287 288 void mlo_mgr_link_switch_init_state(struct wlan_mlo_dev_context *mlo_dev_ctx) 289 { 290 mlo_dev_lock_acquire(mlo_dev_ctx); 291 mlo_dev_ctx->link_ctx->last_req.state = MLO_LINK_SWITCH_STATE_IDLE; 292 mlo_dev_lock_release(mlo_dev_ctx); 293 } 294 295 QDF_STATUS 296 mlo_mgr_link_switch_trans_next_state(struct wlan_mlo_dev_context *mlo_dev_ctx) 297 { 298 QDF_STATUS status = QDF_STATUS_SUCCESS; 299 enum mlo_link_switch_req_state cur_state, next_state; 300 301 mlo_dev_lock_acquire(mlo_dev_ctx); 302 cur_state = mlo_dev_ctx->link_ctx->last_req.state; 303 switch (cur_state) { 304 case MLO_LINK_SWITCH_STATE_IDLE: 305 next_state = MLO_LINK_SWITCH_STATE_DISCONNECT_CURR_LINK; 306 break; 307 case MLO_LINK_SWITCH_STATE_DISCONNECT_CURR_LINK: 308 next_state = MLO_LINK_SWITCH_STATE_SET_MAC_ADDR; 309 break; 310 case MLO_LINK_SWITCH_STATE_SET_MAC_ADDR: 311 next_state = MLO_LINK_SWITCH_STATE_CONNECT_NEW_LINK; 312 break; 313 case MLO_LINK_SWITCH_STATE_CONNECT_NEW_LINK: 314 next_state = MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS; 315 break; 316 case MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS: 317 next_state = MLO_LINK_SWITCH_STATE_IDLE; 318 break; 319 case MLO_LINK_SWITCH_STATE_ABORT_TRANS: 320 next_state = MLO_LINK_SWITCH_STATE_ABORT_TRANS; 321 status = QDF_STATUS_E_PERM; 322 mlo_debug("State transition not allowed"); 323 break; 324 default: 325 QDF_ASSERT(0); 326 break; 327 } 328 mlo_dev_ctx->link_ctx->last_req.state = next_state; 329 mlo_dev_lock_release(mlo_dev_ctx); 330 331 return status; 332 } 333 334 void 335 mlo_mgr_link_switch_trans_abort_state(struct wlan_mlo_dev_context *mlo_dev_ctx) 336 { 337 enum mlo_link_switch_req_state next_state = 338 MLO_LINK_SWITCH_STATE_ABORT_TRANS; 339 340 mlo_dev_lock_acquire(mlo_dev_ctx); 341 mlo_dev_ctx->link_ctx->last_req.state = next_state; 342 mlo_dev_lock_release(mlo_dev_ctx); 343 } 344 345 enum mlo_link_switch_req_state 346 mlo_mgr_link_switch_get_curr_state(struct wlan_mlo_dev_context *mlo_dev_ctx) 347 { 348 enum mlo_link_switch_req_state state; 349 350 mlo_dev_lock_acquire(mlo_dev_ctx); 351 state = mlo_dev_ctx->link_ctx->last_req.state; 352 mlo_dev_lock_release(mlo_dev_ctx); 353 354 return state; 355 } 356 357 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 358 static void 359 mlo_mgr_reset_roam_state_for_link_vdev(struct wlan_objmgr_vdev *vdev, 360 struct wlan_objmgr_vdev *assoc_vdev) 361 { 362 QDF_STATUS status; 363 364 status = wlan_cm_roam_state_change(wlan_vdev_get_pdev(vdev), 365 wlan_vdev_get_id(assoc_vdev), 366 WLAN_ROAM_DEINIT, 367 REASON_ROAM_LINK_SWITCH_ASSOC_VDEV_CHANGE); 368 if (QDF_IS_STATUS_ERROR(status)) 369 mlo_err("vdev:%d failed to change RSO state to deinit", 370 wlan_vdev_get_id(assoc_vdev)); 371 } 372 #else 373 static inline void 374 mlo_mgr_reset_roam_state_for_link_vdev(struct wlan_objmgr_vdev *vdev, 375 struct wlan_objmgr_vdev *assoc_vdev) 376 {} 377 #endif 378 379 QDF_STATUS mlo_mgr_link_switch_notification(struct wlan_objmgr_vdev *vdev, 380 struct wlan_mlo_link_switch_req *lswitch_req) 381 { 382 uint8_t idx; 383 uint16_t vdev_count; 384 struct wlan_objmgr_vdev *assoc_vdev; 385 struct wlan_mlo_sta *sta_ctx; 386 struct wlan_objmgr_vdev *vdev_list[WLAN_UMAC_MLO_MAX_VDEVS]; 387 QDF_STATUS status = QDF_STATUS_E_INVAL; 388 struct mlo_mgr_context *g_mlo_ctx = wlan_objmgr_get_mlo_ctx(); 389 QDF_STATUS(*cb)(struct wlan_objmgr_vdev *vdev, 390 uint8_t non_trans_vdev_id); 391 392 if (!vdev->mlo_dev_ctx) 393 return status; 394 395 sta_ctx = vdev->mlo_dev_ctx->sta_ctx; 396 if (!sta_ctx) 397 return status; 398 399 assoc_vdev = wlan_mlo_get_assoc_link_vdev(vdev); 400 if (!assoc_vdev) 401 return status; 402 403 cb = g_mlo_ctx->osif_ops->mlo_mgr_osif_link_switch_notification; 404 405 if (lswitch_req->restore_vdev_flag) { 406 wlan_vdev_mlme_clear_mlo_link_vdev(vdev); 407 wlan_vdev_mlme_set_mlo_link_vdev(assoc_vdev); 408 mlo_mgr_reset_roam_state_for_link_vdev(vdev, assoc_vdev); 409 410 lswitch_req->restore_vdev_flag = false; 411 412 status = cb(assoc_vdev, wlan_vdev_get_id(vdev)); 413 return status; 414 } 415 416 if (wlan_vdev_get_id(assoc_vdev) != lswitch_req->vdev_id) { 417 mlo_debug("Not on assoc VDEV no need to swap"); 418 return QDF_STATUS_SUCCESS; 419 } 420 421 mlo_sta_get_vdev_list(vdev, &vdev_count, vdev_list); 422 for (idx = 0; idx < vdev_count; idx++) { 423 if (wlan_vdev_get_id(vdev_list[idx]) != lswitch_req->vdev_id && 424 qdf_test_bit(idx, sta_ctx->wlan_connected_links)) { 425 wlan_vdev_mlme_clear_mlo_link_vdev(vdev_list[idx]); 426 wlan_vdev_mlme_set_mlo_link_vdev(assoc_vdev); 427 lswitch_req->restore_vdev_flag = true; 428 429 status = cb(assoc_vdev, 430 wlan_vdev_get_id(vdev_list[idx])); 431 break; 432 } 433 434 mlo_release_vdev_ref(vdev_list[idx]); 435 } 436 437 for (; idx < vdev_count; idx++) 438 mlo_release_vdev_ref(vdev_list[idx]); 439 440 return status; 441 } 442 443 QDF_STATUS mlo_mgr_link_switch_init(struct wlan_mlo_dev_context *ml_dev) 444 { 445 ml_dev->link_ctx = 446 qdf_mem_malloc(sizeof(struct mlo_link_switch_context)); 447 448 if (!ml_dev->link_ctx) 449 return QDF_STATUS_E_NOMEM; 450 451 mlo_mgr_link_switch_init_state(ml_dev); 452 mlo_mgr_alloc_link_info_wmi_chan(ml_dev); 453 mlo_mgr_update_link_info_reset(ml_dev); 454 455 return QDF_STATUS_SUCCESS; 456 } 457 458 QDF_STATUS mlo_mgr_link_switch_deinit(struct wlan_mlo_dev_context *ml_dev) 459 { 460 mlo_mgr_free_link_info_wmi_chan(ml_dev); 461 qdf_mem_free(ml_dev->link_ctx); 462 ml_dev->link_ctx = NULL; 463 return QDF_STATUS_SUCCESS; 464 } 465 466 void 467 mlo_mgr_osif_update_connect_info(struct wlan_objmgr_vdev *vdev, int32_t link_id) 468 { 469 struct mlo_mgr_context *g_mlo_ctx = wlan_objmgr_get_mlo_ctx(); 470 struct mlo_link_info *link_info; 471 QDF_STATUS(*osif_bss_update_cb)(struct qdf_mac_addr *self_mac, 472 struct qdf_mac_addr *bssid, 473 int32_t link_id); 474 475 if (!g_mlo_ctx || !vdev->mlo_dev_ctx || !g_mlo_ctx->osif_ops || 476 !g_mlo_ctx->osif_ops->mlo_mgr_osif_update_bss_info) 477 return; 478 479 link_info = mlo_mgr_get_ap_link_by_link_id(vdev, link_id); 480 if (!link_info) 481 return; 482 483 mlo_debug("VDEV ID %d, Link ID %d, STA MAC " QDF_MAC_ADDR_FMT ", BSSID " QDF_MAC_ADDR_FMT, 484 link_info->vdev_id, link_id, 485 QDF_MAC_ADDR_REF(link_info->link_addr.bytes), 486 QDF_MAC_ADDR_REF(link_info->ap_link_addr.bytes)); 487 osif_bss_update_cb = g_mlo_ctx->osif_ops->mlo_mgr_osif_update_bss_info; 488 489 osif_bss_update_cb(&link_info->link_addr, &link_info->ap_link_addr, 490 link_id); 491 } 492 493 QDF_STATUS mlo_mgr_link_switch_disconnect_done(struct wlan_objmgr_vdev *vdev, 494 QDF_STATUS discon_status, 495 bool is_link_switch_resp) 496 { 497 QDF_STATUS status; 498 enum mlo_link_switch_req_state cur_state; 499 struct mlo_link_info *new_link_info; 500 struct qdf_mac_addr mac_addr, mld_addr; 501 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 502 struct wlan_mlo_link_switch_req *req = &mlo_dev_ctx->link_ctx->last_req; 503 504 if (!is_link_switch_resp) { 505 mlo_mgr_link_switch_trans_abort_state(mlo_dev_ctx); 506 return QDF_STATUS_SUCCESS; 507 } 508 509 cur_state = mlo_mgr_link_switch_get_curr_state(mlo_dev_ctx); 510 if (QDF_IS_STATUS_ERROR(discon_status) || 511 cur_state != MLO_LINK_SWITCH_STATE_DISCONNECT_CURR_LINK) { 512 mlo_err("VDEV %d link switch disconnect req failed", 513 req->vdev_id); 514 mlo_mgr_remove_link_switch_cmd(vdev); 515 return QDF_STATUS_SUCCESS; 516 } 517 518 mlo_debug("VDEV %d link switch disconnect complete", 519 wlan_vdev_get_id(vdev)); 520 521 new_link_info = 522 mlo_mgr_get_ap_link_by_link_id(vdev, req->new_ieee_link_id); 523 if (!new_link_info) { 524 mlo_err("New link not found in mlo dev ctx"); 525 mlo_mgr_remove_link_switch_cmd(vdev); 526 return QDF_STATUS_E_INVAL; 527 } 528 529 qdf_copy_macaddr(&mld_addr, &mlo_dev_ctx->mld_addr); 530 qdf_copy_macaddr(&mac_addr, &new_link_info->link_addr); 531 532 status = mlo_mgr_link_switch_trans_next_state(mlo_dev_ctx); 533 if (QDF_IS_STATUS_ERROR(status)) { 534 mlo_mgr_remove_link_switch_cmd(vdev); 535 return status; 536 } 537 538 status = wlan_vdev_mlme_send_set_mac_addr(mac_addr, mld_addr, vdev); 539 if (QDF_IS_STATUS_ERROR(status)) 540 mlo_mgr_remove_link_switch_cmd(vdev); 541 542 return status; 543 } 544 545 QDF_STATUS mlo_mgr_link_switch_set_mac_addr_resp(struct wlan_objmgr_vdev *vdev, 546 uint8_t resp_status) 547 { 548 QDF_STATUS status = QDF_STATUS_E_INVAL; 549 enum mlo_link_switch_req_state cur_state; 550 struct mlo_mgr_context *g_mlo_ctx = wlan_objmgr_get_mlo_ctx(); 551 struct wlan_mlo_link_switch_req *req; 552 struct mlo_link_info *new_link_info; 553 554 if (resp_status) { 555 mlo_err("VDEV %d set MAC address response %d", 556 wlan_vdev_get_id(vdev), resp_status); 557 mlo_mgr_remove_link_switch_cmd(vdev); 558 return status; 559 } 560 561 if (!g_mlo_ctx) { 562 mlo_err("global mlo ctx NULL"); 563 mlo_mgr_remove_link_switch_cmd(vdev); 564 return status; 565 } 566 567 req = &vdev->mlo_dev_ctx->link_ctx->last_req; 568 cur_state = mlo_mgr_link_switch_get_curr_state(vdev->mlo_dev_ctx); 569 if (cur_state != MLO_LINK_SWITCH_STATE_SET_MAC_ADDR) { 570 mlo_err("Link switch cmd flushed, there can be MAC addr mismatch with FW"); 571 mlo_mgr_remove_link_switch_cmd(vdev); 572 return status; 573 } 574 575 new_link_info = 576 mlo_mgr_get_ap_link_by_link_id(vdev, req->new_ieee_link_id); 577 if (!new_link_info) { 578 mlo_mgr_remove_link_switch_cmd(vdev); 579 return status; 580 } 581 582 wlan_vdev_mlme_set_macaddr(vdev, new_link_info->link_addr.bytes); 583 wlan_vdev_mlme_set_linkaddr(vdev, new_link_info->link_addr.bytes); 584 585 status = g_mlo_ctx->osif_ops->mlo_mgr_osif_update_mac_addr( 586 req->curr_ieee_link_id, 587 req->new_ieee_link_id, 588 req->vdev_id); 589 590 status = mlo_mgr_link_switch_trans_next_state(vdev->mlo_dev_ctx); 591 if (QDF_IS_STATUS_ERROR(status)) { 592 mlo_mgr_remove_link_switch_cmd(vdev); 593 return status; 594 } 595 596 status = mlo_mgr_link_switch_start_connect(vdev); 597 598 return status; 599 } 600 601 QDF_STATUS mlo_mgr_link_switch_start_connect(struct wlan_objmgr_vdev *vdev) 602 { 603 QDF_STATUS status = QDF_STATUS_E_INVAL; 604 struct wlan_cm_connect_req conn_req = {0}; 605 struct mlo_link_info *mlo_link_info; 606 uint8_t *vdev_mac; 607 struct wlan_mlo_sta *sta_ctx; 608 struct wlan_mlo_link_switch_req *req = 609 &vdev->mlo_dev_ctx->link_ctx->last_req; 610 611 sta_ctx = vdev->mlo_dev_ctx->sta_ctx; 612 613 mlo_link_info = 614 mlo_mgr_get_ap_link_by_link_id(vdev, req->new_ieee_link_id); 615 616 if (!mlo_link_info) { 617 mlo_err("New link ID not found"); 618 goto out; 619 } 620 621 vdev_mac = wlan_vdev_mlme_get_linkaddr(vdev); 622 if (!qdf_is_macaddr_equal(&mlo_link_info->link_addr, 623 (struct qdf_mac_addr *)vdev_mac)) { 624 mlo_err("MAC address not equal for the new Link ID VDEV: " QDF_MAC_ADDR_FMT ", MLO_LINK: " QDF_MAC_ADDR_FMT, 625 QDF_MAC_ADDR_REF(vdev_mac), 626 QDF_MAC_ADDR_REF(mlo_link_info->link_addr.bytes)); 627 goto out; 628 } 629 630 wlan_vdev_set_link_id(vdev, req->new_ieee_link_id); 631 copied_conn_req_lock_acquire(sta_ctx); 632 if (sta_ctx->copied_conn_req) { 633 qdf_mem_copy(&conn_req, sta_ctx->copied_conn_req, 634 sizeof(struct wlan_cm_connect_req)); 635 } else { 636 copied_conn_req_lock_release(sta_ctx); 637 goto out; 638 } 639 copied_conn_req_lock_release(sta_ctx); 640 641 conn_req.vdev_id = wlan_vdev_get_id(vdev); 642 conn_req.source = CM_MLO_LINK_SWITCH_CONNECT; 643 qdf_copy_macaddr(&conn_req.bssid, &mlo_link_info->ap_link_addr); 644 mlo_allocate_and_copy_ies(&conn_req, sta_ctx->copied_conn_req); 645 conn_req.crypto.auth_type = 0; 646 conn_req.ml_parnter_info = sta_ctx->ml_partner_info; 647 status = wlan_cm_start_connect(vdev, &conn_req); 648 if (QDF_IS_STATUS_SUCCESS(status)) 649 mlo_update_connected_links(vdev, 1); 650 651 wlan_cm_free_connect_req_param(&conn_req); 652 653 out: 654 if (QDF_IS_STATUS_ERROR(status)) { 655 mlo_err("VDEV %d link switch connect request failed", 656 wlan_vdev_get_id(vdev)); 657 mlo_mgr_remove_link_switch_cmd(vdev); 658 } 659 660 return status; 661 } 662 663 void mlo_mgr_link_switch_connect_done(struct wlan_objmgr_vdev *vdev, 664 QDF_STATUS status) 665 { 666 struct wlan_mlo_link_switch_req *req; 667 668 req = &vdev->mlo_dev_ctx->link_ctx->last_req; 669 if (QDF_IS_STATUS_SUCCESS(status)) 670 mlo_mgr_link_switch_trans_next_state(vdev->mlo_dev_ctx); 671 else 672 mlo_err("VDEV %d link switch connect failed", req->vdev_id); 673 674 mlo_mgr_remove_link_switch_cmd(vdev); 675 } 676 677 static QDF_STATUS 678 mlo_mgr_start_link_switch(struct wlan_objmgr_vdev *vdev, 679 struct wlan_serialization_command *cmd) 680 { 681 int i; 682 QDF_STATUS status = QDF_STATUS_E_INVAL; 683 uint8_t vdev_id, old_link_id, new_link_id; 684 struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx(); 685 struct mlo_link_switch_context *link_ctx = vdev->mlo_dev_ctx->link_ctx; 686 struct wlan_mlo_link_switch_req *req = &link_ctx->last_req; 687 struct qdf_mac_addr bssid; 688 689 if (!mlo_mgr_ctx) { 690 mlo_err("Global mlo mgr NULL"); 691 return status; 692 } 693 694 vdev_id = wlan_vdev_get_id(vdev); 695 old_link_id = req->curr_ieee_link_id; 696 new_link_id = req->new_ieee_link_id; 697 698 mlo_debug("VDEV %d start link switch", vdev_id); 699 if (!wlan_cm_is_vdev_connected(vdev) || 700 wlan_vdev_get_link_id(vdev) != old_link_id) { 701 mlo_err("Link switch req link id mismatch, curr link id %d", 702 wlan_vdev_get_link_id(vdev)); 703 return status; 704 } 705 706 if (!wlan_cm_is_vdev_connected(vdev)) { 707 mlo_err("VDEV %d not in connected state", vdev_id); 708 return status; 709 } 710 711 status = wlan_vdev_get_bss_peer_mac(vdev, &bssid); 712 if (QDF_IS_STATUS_ERROR(status)) 713 return status; 714 715 status = wlan_vdev_get_bss_peer_mld_mac(vdev, &req->peer_mld_addr); 716 if (QDF_IS_STATUS_ERROR(status)) 717 return status; 718 719 for (i = 0; i < WLAN_UMAC_COMP_ID_MAX; i++) { 720 if (!mlo_mgr_ctx->lswitch_notifier[i].in_use) 721 continue; 722 723 status = mlo_mgr_ctx->lswitch_notifier[i].cb(vdev, req); 724 if (QDF_IS_STATUS_ERROR(status)) { 725 mlme_err("Link switch start rejected by %d", i); 726 return status; 727 } 728 } 729 730 wlan_vdev_mlme_set_mlo_link_switch_in_progress(vdev); 731 status = mlo_mgr_link_switch_trans_next_state(vdev->mlo_dev_ctx); 732 if (QDF_IS_STATUS_ERROR(status)) 733 return status; 734 735 status = wlan_cm_disconnect(vdev, CM_MLO_LINK_SWITCH_DISCONNECT, 736 REASON_FW_TRIGGERED_LINK_SWITCH, &bssid); 737 738 if (QDF_IS_STATUS_ERROR(status)) 739 mlo_err("VDEV %d disconnect request not handled", req->vdev_id); 740 741 return status; 742 } 743 744 static QDF_STATUS 745 mlo_mgr_ser_link_switch_cb(struct wlan_serialization_command *cmd, 746 enum wlan_serialization_cb_reason reason) 747 { 748 struct wlan_objmgr_vdev *vdev; 749 QDF_STATUS status = QDF_STATUS_SUCCESS; 750 751 if (!cmd) { 752 mlo_err("cmd is NULL, reason: %d", reason); 753 QDF_ASSERT(0); 754 return QDF_STATUS_E_NULL_VALUE; 755 } 756 757 vdev = cmd->vdev; 758 switch (reason) { 759 case WLAN_SER_CB_ACTIVATE_CMD: 760 status = mlo_mgr_start_link_switch(vdev, cmd); 761 break; 762 case WLAN_SER_CB_RELEASE_MEM_CMD: 763 mlo_mgr_link_switch_complete(vdev); 764 break; 765 case WLAN_SER_CB_CANCEL_CMD: 766 mlo_err("Link switch cmd cancelled"); 767 break; 768 case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT: 769 mlo_err("Link switch active cmd timeout"); 770 break; 771 default: 772 QDF_ASSERT(0); 773 mlo_mgr_link_switch_complete(vdev); 774 break; 775 } 776 777 return status; 778 } 779 780 void mlo_mgr_remove_link_switch_cmd(struct wlan_objmgr_vdev *vdev) 781 { 782 QDF_STATUS status; 783 struct wlan_serialization_queued_cmd_info cmd_info; 784 enum mlo_link_switch_req_state cur_state; 785 uint8_t vdev_id = wlan_vdev_get_id(vdev); 786 struct wlan_mlo_link_switch_req *req; 787 788 req = &vdev->mlo_dev_ctx->link_ctx->last_req; 789 if (req->restore_vdev_flag) { 790 status = mlo_mgr_link_switch_notification(vdev, req); 791 if (QDF_IS_STATUS_ERROR(status)) { 792 mlo_err("Failed to restore deflink in OSIF"); 793 req->restore_vdev_flag = false; 794 } 795 } 796 797 cur_state = mlo_mgr_link_switch_get_curr_state(vdev->mlo_dev_ctx); 798 if (cur_state == MLO_LINK_SWITCH_STATE_IDLE) 799 return; 800 801 cmd_info.cmd_id = (vdev_id << 16) + (req->new_ieee_link_id << 8) + 802 (req->curr_ieee_link_id); 803 cmd_info.req_type = WLAN_SER_CANCEL_NON_SCAN_CMD; 804 cmd_info.cmd_type = WLAN_SER_CMD_MLO_VDEV_LINK_SWITCH; 805 cmd_info.vdev = vdev; 806 cmd_info.queue_type = WLAN_SERIALIZATION_ACTIVE_QUEUE; 807 808 wlan_serialization_remove_cmd(&cmd_info); 809 } 810 811 #define MLO_MGR_MAX_LSWITCH_TIMEOUT 35000 812 813 QDF_STATUS mlo_mgr_ser_link_switch_cmd(struct wlan_objmgr_vdev *vdev, 814 struct wlan_mlo_link_switch_req *req) 815 { 816 enum wlan_serialization_status ser_cmd_status; 817 struct wlan_serialization_command cmd = {0}; 818 uint8_t vdev_id = wlan_vdev_get_id(vdev); 819 struct mlo_link_switch_context *link_ctx; 820 821 if (!vdev->mlo_dev_ctx) { 822 mlo_err("ML dev ctx NULL, reject link switch"); 823 return QDF_STATUS_E_INVAL; 824 } 825 826 link_ctx = vdev->mlo_dev_ctx->link_ctx; 827 link_ctx->last_req = *req; 828 829 cmd.cmd_type = WLAN_SER_CMD_MLO_VDEV_LINK_SWITCH; 830 cmd.cmd_id = (vdev_id << 16) + (req->new_ieee_link_id << 8) + 831 (req->curr_ieee_link_id); 832 cmd.cmd_cb = mlo_mgr_ser_link_switch_cb; 833 cmd.source = WLAN_UMAC_COMP_MLO_MGR; 834 cmd.is_high_priority = false; 835 cmd.cmd_timeout_duration = MLO_MGR_MAX_LSWITCH_TIMEOUT; 836 cmd.vdev = vdev; 837 cmd.is_blocking = true; 838 839 ser_cmd_status = wlan_serialization_request(&cmd); 840 switch (ser_cmd_status) { 841 case WLAN_SER_CMD_PENDING: 842 mlo_debug("Link switch cmd in pending queue"); 843 break; 844 case WLAN_SER_CMD_ACTIVE: 845 mlo_debug("Link switch cmd in active queue"); 846 break; 847 default: 848 return QDF_STATUS_E_INVAL; 849 } 850 851 return QDF_STATUS_SUCCESS; 852 } 853 854 QDF_STATUS 855 mlo_mgr_link_switch_validate_request(struct wlan_objmgr_vdev *vdev, 856 struct wlan_mlo_link_switch_req *req) 857 { 858 QDF_STATUS status = QDF_STATUS_E_INVAL; 859 uint8_t vdev_id = wlan_vdev_get_id(vdev); 860 861 if (req->curr_ieee_link_id >= WLAN_INVALID_LINK_ID || 862 req->new_ieee_link_id >= WLAN_INVALID_LINK_ID) { 863 mlo_err("Invalid link params, curr link id %d, new link id %d", 864 req->curr_ieee_link_id, req->new_ieee_link_id); 865 return status; 866 } 867 868 if (!mlo_mgr_get_ap_link_by_link_id(vdev, req->new_ieee_link_id)) { 869 mlo_err("New link id %d not part of association", 870 req->new_ieee_link_id); 871 return status; 872 } 873 874 if (!mlo_is_mld_sta(vdev)) { 875 mlo_err("Link switch req not valid for VDEV %d", vdev_id); 876 return status; 877 } 878 879 if (!wlan_cm_is_vdev_connected(vdev)) { 880 mlo_err("VDEV %d not in connected state", vdev_id); 881 return status; 882 } 883 884 if (mlo_mgr_is_link_switch_in_progress(vdev)) { 885 mlo_err("Link switch already in progress"); 886 return status; 887 } 888 889 if (wlan_vdev_get_link_id(vdev) != req->curr_ieee_link_id) { 890 mlo_err("VDEV %d link id wrong, curr link id %d", 891 vdev_id, wlan_vdev_get_link_id(vdev)); 892 return status; 893 } 894 895 return QDF_STATUS_SUCCESS; 896 } 897 898 QDF_STATUS mlo_mgr_link_switch_request_params(struct wlan_objmgr_psoc *psoc, 899 void *evt_params) 900 { 901 QDF_STATUS status; 902 struct wlan_mlo_link_switch_cnf cnf_params = {0}; 903 struct wlan_mlo_link_switch_req *req; 904 struct wlan_objmgr_vdev *vdev; 905 906 if (!evt_params) { 907 mlo_err("Invalid params"); 908 return QDF_STATUS_E_INVAL; 909 } 910 911 req = (struct wlan_mlo_link_switch_req *)evt_params; 912 913 /* The reference is released on Link Switch status confirm to FW */ 914 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, req->vdev_id, 915 WLAN_MLO_MGR_ID); 916 if (!vdev) { 917 mlo_err("Invalid link switch VDEV %d", req->vdev_id); 918 919 /* Fill reject params here and send to FW as VDEV is invalid */ 920 cnf_params.vdev_id = req->vdev_id; 921 cnf_params.status = MLO_LINK_SWITCH_CNF_STATUS_REJECT; 922 mlo_mgr_link_switch_send_cnf_cmd(psoc, &cnf_params); 923 return QDF_STATUS_E_INVAL; 924 } 925 926 status = mlo_mgr_link_switch_validate_request(vdev, req); 927 if (QDF_IS_STATUS_ERROR(status)) { 928 mlo_debug("Link switch params/request invalid"); 929 mlo_mgr_link_switch_complete(vdev); 930 return QDF_STATUS_E_INVAL; 931 } 932 933 mlo_debug("VDEV %d, curr_link_id %d, new_link_id %d, new_freq %d, new_phymode: %d, reason %d", 934 req->vdev_id, req->curr_ieee_link_id, req->new_ieee_link_id, 935 req->new_primary_freq, req->new_phymode, req->reason); 936 937 status = mlo_mgr_ser_link_switch_cmd(vdev, req); 938 if (QDF_IS_STATUS_ERROR(status)) { 939 mlo_err("Failed to serialize link switch command"); 940 mlo_mgr_link_switch_complete(vdev); 941 } 942 943 return status; 944 } 945 946 QDF_STATUS mlo_mgr_link_switch_complete(struct wlan_objmgr_vdev *vdev) 947 { 948 enum mlo_link_switch_req_state state; 949 struct wlan_mlo_link_switch_cnf params = {0}; 950 struct mlo_link_switch_context *link_ctx; 951 struct wlan_mlo_link_switch_req *req; 952 struct wlan_objmgr_psoc *psoc; 953 954 /* Not checking NULL value as reference is already taken for vdev */ 955 psoc = wlan_vdev_get_psoc(vdev); 956 957 link_ctx = vdev->mlo_dev_ctx->link_ctx; 958 req = &link_ctx->last_req; 959 960 state = mlo_mgr_link_switch_get_curr_state(vdev->mlo_dev_ctx); 961 if (state != MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS) 962 params.status = MLO_LINK_SWITCH_CNF_STATUS_REJECT; 963 else 964 params.status = MLO_LINK_SWITCH_CNF_STATUS_ACCEPT; 965 966 params.vdev_id = wlan_vdev_get_id(vdev); 967 params.reason = MLO_LINK_SWITCH_CNF_REASON_BSS_PARAMS_CHANGED; 968 969 mlo_mgr_link_switch_send_cnf_cmd(psoc, ¶ms); 970 971 mlo_mgr_link_switch_init_state(vdev->mlo_dev_ctx); 972 wlan_vdev_mlme_clear_mlo_link_switch_in_progress(vdev); 973 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 974 return QDF_STATUS_SUCCESS; 975 } 976 977 QDF_STATUS 978 mlo_mgr_link_switch_send_cnf_cmd(struct wlan_objmgr_psoc *psoc, 979 struct wlan_mlo_link_switch_cnf *cnf_params) 980 { 981 QDF_STATUS status; 982 struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops; 983 984 mlo_debug("VDEV %d link switch completed, %s", cnf_params->vdev_id, 985 (cnf_params->status == MLO_LINK_SWITCH_CNF_STATUS_ACCEPT) ? 986 "success" : "fail"); 987 988 mlo_tx_ops = &psoc->soc_cb.tx_ops->mlo_ops; 989 if (!mlo_tx_ops || !mlo_tx_ops->send_mlo_link_switch_cnf_cmd) { 990 mlo_err("handler is not registered"); 991 return QDF_STATUS_E_INVAL; 992 } 993 994 status = mlo_tx_ops->send_mlo_link_switch_cnf_cmd(psoc, cnf_params); 995 if (QDF_IS_STATUS_ERROR(status)) 996 mlo_err("Link switch status update to FW failed"); 997 998 return status; 999 } 1000 #endif 1001