1 /* 2 * Copyright (c) 2021, The Linux Foundation. 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 STA related api's 19 */ 20 21 #include <wlan_cmn.h> 22 #include <wlan_mlo_mgr_sta.h> 23 #include <wlan_cm_public_struct.h> 24 #include <wlan_mlo_mgr_main.h> 25 #include <wlan_cm_api.h> 26 #include <wlan_mlo_mgr_cmn.h> 27 #include <wlan_scan_api.h> 28 29 #ifdef WLAN_FEATURE_11BE_MLO 30 /** 31 * mlo_disconnect_no_lock - Start the disconnection process without acquiring 32 * ML dev lock 33 * 34 * @vdev: pointer to vdev 35 * @source: source of the request (can be connect or disconnect request) 36 * @reason_code: reason for disconnect 37 * @bssid: BSSID 38 * 39 * Return: QDF_STATUS 40 */ 41 static QDF_STATUS mlo_disconnect_no_lock(struct wlan_objmgr_vdev *vdev, 42 enum wlan_cm_source source, 43 enum wlan_reason_code reason_code, 44 struct qdf_mac_addr *bssid); 45 /* 46 * mlo_get_assoc_link_vdev - API to get assoc link vdev 47 * 48 * @mlo_dev_ctx: pointer to mlo dev context 49 * 50 * Return: MLD assoc link vdev 51 */ 52 static inline struct wlan_objmgr_vdev * 53 mlo_get_assoc_link_vdev(struct wlan_mlo_dev_context *mlo_dev_ctx) 54 { 55 uint8_t i = 0; 56 57 if (!mlo_dev_ctx) 58 return NULL; 59 60 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 61 if (!mlo_dev_ctx->wlan_vdev_list[i]) 62 continue; 63 64 if (wlan_vdev_mlme_is_mlo_vdev(mlo_dev_ctx->wlan_vdev_list[i]) && 65 !wlan_vdev_mlme_is_mlo_link_vdev(mlo_dev_ctx->wlan_vdev_list[i])) 66 return mlo_dev_ctx->wlan_vdev_list[i]; 67 } 68 return NULL; 69 } 70 71 struct wlan_objmgr_vdev * 72 ucfg_mlo_get_assoc_link_vdev(struct wlan_objmgr_vdev *vdev) 73 { 74 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 75 76 if (!mlo_dev_ctx || !wlan_vdev_mlme_is_mlo_vdev(vdev)) 77 return NULL; 78 79 return mlo_get_assoc_link_vdev(mlo_dev_ctx); 80 } 81 82 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 83 static QDF_STATUS 84 mlo_validate_connect_req(struct wlan_mlo_dev_context *mlo_dev_ctx, 85 struct wlan_cm_connect_req *req) 86 { 87 /* check back to back connect handling */ 88 return QDF_STATUS_SUCCESS; 89 } 90 #else 91 /** 92 * mlo_is_mld_connected - Check whether MLD is connected 93 * 94 * @vdev: pointer to vdev 95 * 96 * Return: true if mld is connected, false otherwise 97 */ 98 static inline 99 bool mlo_is_mld_connected(struct wlan_objmgr_vdev *vdev) 100 { 101 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 102 uint8_t i = 0; 103 104 if (!mlo_dev_ctx || !wlan_vdev_mlme_is_mlo_vdev(vdev)) 105 return true; 106 107 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 108 if (!mlo_dev_ctx->wlan_vdev_list[i]) 109 continue; 110 111 if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links)) { 112 if (!wlan_cm_is_vdev_connected(mlo_dev_ctx->wlan_vdev_list[i])) 113 return false; 114 } 115 } 116 return true; 117 } 118 119 bool ucfg_mlo_is_mld_connected(struct wlan_objmgr_vdev *vdev) 120 { 121 return mlo_is_mld_connected(vdev); 122 } 123 124 /** 125 * mlo_is_mld_disconnected - Check whether MLD is disconnected 126 * 127 * @vdev: pointer to vdev 128 * 129 * Return: true if mld is disconnected, false otherwise 130 */ 131 static inline 132 bool mlo_is_mld_disconnected(struct wlan_objmgr_vdev *vdev) 133 { 134 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 135 uint8_t i = 0; 136 137 if (!mlo_dev_ctx || !wlan_vdev_mlme_is_mlo_vdev(vdev)) 138 return true; 139 140 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 141 if (!mlo_dev_ctx->wlan_vdev_list[i]) 142 continue; 143 144 if (!wlan_cm_is_vdev_disconnected(mlo_dev_ctx->wlan_vdev_list[i])) 145 return false; 146 } 147 return true; 148 } 149 150 bool ucfg_mlo_is_mld_disconnected(struct wlan_objmgr_vdev *vdev) 151 { 152 return mlo_is_mld_disconnected(vdev); 153 } 154 155 static void 156 mlo_cm_handle_connect_in_disconnection_state(struct wlan_objmgr_vdev *vdev, 157 struct wlan_cm_connect_req *req) 158 { 159 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 160 struct wlan_mlo_sta *sta_ctx = mlo_dev_ctx->sta_ctx; 161 162 if (!sta_ctx->connect_req) 163 sta_ctx->connect_req = qdf_mem_malloc( 164 sizeof(struct wlan_cm_connect_req)); 165 166 if (sta_ctx->connect_req) 167 qdf_mem_copy(sta_ctx->connect_req, req, 168 sizeof(struct wlan_cm_connect_req)); 169 else 170 mlo_err("Failed to allocate connect req"); 171 } 172 173 static void 174 mlo_cm_handle_connect_in_connection_state(struct wlan_objmgr_vdev *vdev, 175 struct wlan_cm_connect_req *req) 176 { 177 mlo_disconnect_no_lock(vdev, CM_SB_DISCONNECT, 178 REASON_UNSPEC_FAILURE, NULL); 179 mlo_cm_handle_connect_in_disconnection_state(vdev, req); 180 } 181 182 static QDF_STATUS 183 mlo_validate_connect_req(struct wlan_mlo_dev_context *mlo_dev_ctx, 184 struct wlan_cm_connect_req *req) 185 { 186 uint8_t i = 0; 187 QDF_STATUS status = QDF_STATUS_SUCCESS; 188 189 // Handle connect in various states 190 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 191 if (!mlo_dev_ctx->wlan_vdev_list[i]) 192 continue; 193 194 if ((wlan_cm_is_vdev_connected(mlo_dev_ctx->wlan_vdev_list[i])) || 195 (wlan_cm_is_vdev_connecting(mlo_dev_ctx->wlan_vdev_list[i])) || 196 (wlan_cm_is_vdev_roaming(mlo_dev_ctx->wlan_vdev_list[i]))) { 197 mlo_cm_handle_connect_in_connection_state(mlo_dev_ctx->wlan_vdev_list[i], req); 198 return QDF_STATUS_E_BUSY; 199 } else if (wlan_cm_is_vdev_disconnecting(mlo_dev_ctx->wlan_vdev_list[i])) { 200 mlo_cm_handle_connect_in_disconnection_state(mlo_dev_ctx->wlan_vdev_list[i], req); 201 return QDF_STATUS_E_BUSY; 202 } 203 204 /* 205 * mlo_connect: update wlan_connect_req_links in 206 * wlan_cfg80211_conect on osif_cm_connect, 207 * Validate pre checks for connection 208 */ 209 if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connect_req_links)) { 210 status = mlo_mlme_validate_conn_req( 211 mlo_dev_ctx->wlan_vdev_list[i], NULL); 212 if (status != QDF_STATUS_SUCCESS) 213 return status; 214 } 215 } 216 return status; 217 } 218 #endif 219 220 QDF_STATUS mlo_connect(struct wlan_objmgr_vdev *vdev, 221 struct wlan_cm_connect_req *req) 222 { 223 struct wlan_mlo_dev_context *mlo_dev_ctx; 224 struct wlan_mlo_sta *sta_ctx; 225 QDF_STATUS status = QDF_STATUS_SUCCESS; 226 227 if (qdf_mem_cmp(vdev->vdev_mlme.macaddr, 228 vdev->vdev_mlme.linkaddr, 229 QDF_MAC_ADDR_SIZE)) 230 return wlan_cm_start_connect(vdev, req); 231 232 mlo_dev_ctx = vdev->mlo_dev_ctx; 233 sta_ctx = mlo_dev_ctx->sta_ctx; 234 if (mlo_dev_ctx && wlan_vdev_mlme_is_mlo_vdev(vdev)) { 235 mlo_dev_lock_acquire(mlo_dev_ctx); 236 status = mlo_validate_connect_req(mlo_dev_ctx, req); 237 238 if (!sta_ctx->orig_conn_req) 239 sta_ctx->orig_conn_req = qdf_mem_malloc( 240 sizeof(struct wlan_cm_connect_req)); 241 242 mlo_debug("storing orig connect req"); 243 if (sta_ctx->orig_conn_req) { 244 qdf_mem_copy(sta_ctx->orig_conn_req, req, 245 sizeof(struct wlan_cm_connect_req)); 246 } else { 247 mlo_err("Failed to allocate orig connect req"); 248 return QDF_STATUS_E_NOMEM; 249 } 250 251 if (QDF_IS_STATUS_SUCCESS(status)) 252 status = wlan_cm_start_connect(vdev, req); 253 254 mlo_dev_lock_release(mlo_dev_ctx); 255 return status; 256 } 257 258 return wlan_cm_start_connect(vdev, req); 259 } 260 261 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 262 static inline void 263 mlo_update_connect_req_chan_info(struct wlan_cm_connect_req *req) 264 { } 265 #else 266 static inline void 267 mlo_update_connect_req_chan_info(struct wlan_cm_connect_req *req) 268 { 269 req->chan_freq = 0; 270 req->chan_freq_hint = 0; 271 } 272 #endif 273 274 /** 275 * mlo_prepare_and_send_connect- Prepare and send the connect req 276 * 277 * @vdev: vdev pointer 278 * @ml_parnter_info: ml partner link info 279 * @link_info: link info on which connect req will be sent 280 * @ssid: ssid to connect 281 * 282 * Return: none 283 */ 284 285 static void 286 mlo_prepare_and_send_connect(struct wlan_objmgr_vdev *vdev, 287 struct mlo_partner_info ml_parnter_info, 288 struct mlo_link_info link_info, 289 struct wlan_ssid ssid) 290 { 291 struct wlan_cm_connect_req req = {0}; 292 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 293 struct wlan_mlo_sta *sta_ctx = mlo_dev_ctx->sta_ctx; 294 295 mlo_debug("Partner link connect mac:" QDF_MAC_ADDR_FMT "vdev_id:%d", 296 QDF_MAC_ADDR_REF(wlan_vdev_mlme_get_macaddr(vdev)), 297 wlan_vdev_get_id(vdev)); 298 299 qdf_mem_copy(&req, sta_ctx->orig_conn_req, 300 sizeof(struct wlan_cm_connect_req)); 301 302 mlo_update_connect_req_chan_info(&req); 303 304 qdf_mem_copy(req.bssid.bytes, 305 link_info.link_addr.bytes, 306 QDF_MAC_ADDR_SIZE); 307 308 qdf_mem_copy(&req.ml_parnter_info, 309 &ml_parnter_info, 310 sizeof(struct mlo_partner_info)); 311 312 req.ssid.length = ssid.length; 313 qdf_mem_copy(&req.ssid.ssid, &ssid.ssid, ssid.length); 314 315 req.assoc_ie.len = sta_ctx->orig_conn_req->assoc_ie.len; 316 req.assoc_ie.ptr = qdf_mem_malloc(req.assoc_ie.len); 317 if (req.assoc_ie.ptr) { 318 qdf_mem_copy(req.assoc_ie.ptr, 319 sta_ctx->orig_conn_req->assoc_ie.ptr, 320 req.assoc_ie.len); 321 } else { 322 req.assoc_ie.len = 0; 323 mlo_err("Failed to allocate assoc IE"); 324 } 325 326 wlan_cm_start_connect(vdev, &req); 327 if (req.assoc_ie.ptr) { 328 qdf_mem_free(req.assoc_ie.ptr); 329 req.assoc_ie.ptr = NULL; 330 req.assoc_ie.len = 0; 331 } 332 } 333 334 /** 335 * mlo_send_link_connect- Create/Issue the connection on secondary link 336 * 337 * @vdev: vdev pointer 338 * @mlo_dev_ctx: ml dev context 339 * @assoc_rsp: assoc response 340 * @ml_parnter_info: ml partner link info 341 * 342 * Return: none 343 */ 344 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 345 static void 346 mlo_send_link_connect(struct wlan_objmgr_vdev *vdev, 347 struct wlan_mlo_dev_context *mlo_dev_ctx, 348 struct element_info *assoc_rsp, 349 struct mlo_partner_info ml_parnter_info) 350 { 351 /* Create the secondary interface, Send keys if the last link */ 352 uint8_t i; 353 struct wlan_ssid ssid = {0}; 354 355 mlo_debug("Sending link connect on partner interface"); 356 wlan_vdev_mlme_get_ssid( 357 vdev, ssid.ssid, 358 &ssid.length); 359 360 if (!ml_parnter_info.num_partner_links) { 361 mlo_err("No patner info in connect resp"); 362 return; 363 } 364 365 if(wlan_vdev_mlme_is_mlo_link_vdev(vdev)) 366 return; 367 368 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 369 if (!mlo_dev_ctx->wlan_vdev_list[i] || 370 (mlo_dev_ctx->wlan_vdev_list[i] == vdev)) 371 continue; 372 wlan_vdev_mlme_feat_ext2_cap_set(mlo_dev_ctx->wlan_vdev_list[i], 373 WLAN_VDEV_FEXT2_MLO_STA_LINK); 374 mlo_prepare_and_send_connect( 375 mlo_dev_ctx->wlan_vdev_list[i], 376 ml_parnter_info, 377 ml_parnter_info.partner_link_info[i], 378 ssid); 379 } 380 } 381 #else 382 static void 383 mlo_send_link_connect(struct wlan_objmgr_vdev *vdev, 384 struct wlan_mlo_dev_context *mlo_dev_ctx, 385 struct element_info *assoc_rsp, 386 struct mlo_partner_info ml_parnter_info) 387 { 388 struct wlan_ssid ssid = {0}; 389 uint8_t i = 0; 390 uint8_t j = 0; 391 392 if (!ml_parnter_info.num_partner_links) { 393 mlo_err("No patner info in connect resp"); 394 return; 395 } 396 397 mlo_dev_lock_acquire(mlo_dev_ctx); 398 if (wlan_cm_is_vdev_connected(vdev)) { 399 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 400 if (!mlo_dev_ctx->wlan_vdev_list[i]) 401 continue; 402 /* 403 * mlo_connect: update wlan_connected_links bitmap from 404 * assoc resp parsing 405 */ 406 if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links)) { 407 if (wlan_cm_is_vdev_disconnected( 408 mlo_dev_ctx->wlan_vdev_list[i])) { 409 for (j = 0; j < ml_parnter_info.num_partner_links; j++) { 410 if (mlo_dev_ctx->wlan_vdev_list[i]->vdev_mlme.mlo_link_id == 411 ml_parnter_info.partner_link_info[j].link_id) 412 break; 413 } 414 if (j < ml_parnter_info.num_partner_links) { 415 wlan_vdev_mlme_get_ssid( 416 vdev, ssid.ssid, 417 &ssid.length); 418 mlo_prepare_and_send_connect( 419 mlo_dev_ctx->wlan_vdev_list[i], 420 ml_parnter_info, 421 ml_parnter_info.partner_link_info[j], 422 ssid); 423 } 424 mlo_dev_lock_release(mlo_dev_ctx); 425 return; 426 } 427 } 428 } 429 } 430 mlo_dev_lock_release(mlo_dev_ctx); 431 } 432 #endif 433 434 void mlo_sta_link_connect_notify(struct wlan_objmgr_vdev *vdev, 435 struct wlan_cm_connect_resp *rsp) 436 { 437 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 438 439 if (mlo_dev_ctx && wlan_vdev_mlme_is_mlo_vdev(vdev)) { 440 mlo_debug("Vdev: %d", wlan_vdev_get_id(vdev)); 441 if (wlan_cm_is_vdev_disconnected(vdev)) { 442 // Connect Failure 443 if (vdev == mlo_get_assoc_link_vdev(mlo_dev_ctx)) { 444 return; 445 } else { 446 if (rsp->reason == CM_NO_CANDIDATE_FOUND || 447 rsp->reason == CM_HW_MODE_FAILURE || 448 rsp->reason == CM_SER_FAILURE) 449 mlo_disconnect_no_lock( 450 vdev, CM_OSIF_DISCONNECT, 451 REASON_UNSPEC_FAILURE, NULL); 452 else 453 mlo_disconnect( 454 vdev, CM_OSIF_DISCONNECT, 455 REASON_UNSPEC_FAILURE, NULL); 456 return; 457 } 458 } 459 if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev)) { 460 if (mlo_dev_ctx->sta_ctx->assoc_rsp.ptr) { 461 qdf_mem_free(mlo_dev_ctx->sta_ctx->assoc_rsp.ptr); 462 mlo_dev_ctx->sta_ctx->assoc_rsp.ptr = NULL; 463 } 464 mlo_dev_ctx->sta_ctx->assoc_rsp.len = 465 rsp->connect_ies.assoc_rsp.len; 466 mlo_dev_ctx->sta_ctx->assoc_rsp.ptr = 467 qdf_mem_malloc(rsp->connect_ies.assoc_rsp.len); 468 if (!mlo_dev_ctx->sta_ctx->assoc_rsp.ptr) { 469 QDF_ASSERT(0); 470 return; 471 } 472 qdf_mem_copy(mlo_dev_ctx->sta_ctx->assoc_rsp.ptr, 473 rsp->connect_ies.assoc_rsp.ptr, 474 rsp->connect_ies.assoc_rsp.len); 475 } 476 mlo_send_link_connect(vdev, mlo_dev_ctx, 477 &rsp->connect_ies.assoc_rsp, 478 rsp->ml_parnter_info); 479 } 480 } 481 482 /* 483 * mlo_get_connected_link_vdev - API to get 1st connected link vdev 484 * 485 * @mlo_dev_ctx: mlo dev ctx 486 * 487 * Return: 1st connected link vdev in ML dev, NULL if none of the link vdev 488 * is connected 489 */ 490 static struct wlan_objmgr_vdev 491 *mlo_get_connected_link_vdev(struct wlan_mlo_dev_context *mlo_dev_ctx) 492 { 493 uint8_t i = 0; 494 495 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 496 if (!mlo_dev_ctx->wlan_vdev_list[i]) 497 continue; 498 499 if ((mlo_dev_ctx->wlan_vdev_list[i] != 500 mlo_get_assoc_link_vdev(mlo_dev_ctx)) && 501 wlan_cm_is_vdev_connected(mlo_dev_ctx->wlan_vdev_list[i])) 502 return mlo_dev_ctx->wlan_vdev_list[i]; 503 } 504 505 return NULL; 506 } 507 508 /** 509 * mlo_send_link_disconnect- Issue the disconnect request on MLD links 510 * 511 * @mlo_dev_ctx: pointer to mlo dev context 512 * @source: disconnect source 513 * @reason_code: disconnect reason 514 * @bssid: bssid of AP to disconnect, can be null if not known 515 * 516 * Return: QDF_STATUS 517 */ 518 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 519 static QDF_STATUS 520 mlo_send_link_disconnect(struct wlan_mlo_dev_context *mlo_dev_ctx, 521 enum wlan_cm_source source, 522 enum wlan_reason_code reason_code, 523 struct qdf_mac_addr *bssid) 524 { 525 uint8_t i = 0; 526 527 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 528 if (!mlo_dev_ctx->wlan_vdev_list[i]) 529 continue; 530 531 if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links) && 532 mlo_dev_ctx->wlan_vdev_list[i] != mlo_get_assoc_link_vdev(mlo_dev_ctx)) 533 wlan_cm_disconnect(mlo_dev_ctx->wlan_vdev_list[i], 534 source, reason_code, NULL); 535 } 536 537 wlan_cm_disconnect(mlo_get_assoc_link_vdev(mlo_dev_ctx), 538 source, reason_code, NULL); 539 return QDF_STATUS_SUCCESS; 540 } 541 542 static QDF_STATUS 543 mlo_send_link_disconnect_sync(struct wlan_mlo_dev_context *mlo_dev_ctx, 544 enum wlan_cm_source source, 545 enum wlan_reason_code reason_code, 546 struct qdf_mac_addr *bssid) 547 { 548 uint8_t i = 0; 549 550 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 551 if (!mlo_dev_ctx->wlan_vdev_list[i]) 552 continue; 553 554 if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links) && 555 mlo_dev_ctx->wlan_vdev_list[i] != mlo_get_assoc_link_vdev(mlo_dev_ctx)) 556 wlan_cm_disconnect_sync(mlo_dev_ctx->wlan_vdev_list[i], 557 source, reason_code); 558 } 559 560 wlan_cm_disconnect_sync(mlo_get_assoc_link_vdev(mlo_dev_ctx), 561 source, reason_code); 562 return QDF_STATUS_SUCCESS; 563 } 564 #else 565 static QDF_STATUS 566 mlo_send_link_disconnect(struct wlan_mlo_dev_context *mlo_dev_ctx, 567 enum wlan_cm_source source, 568 enum wlan_reason_code reason_code, 569 struct qdf_mac_addr *bssid) 570 { 571 uint8_t i = 0; 572 QDF_STATUS status = QDF_STATUS_E_ALREADY; 573 574 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 575 if (!mlo_dev_ctx->wlan_vdev_list[i]) 576 continue; 577 578 if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links)) { 579 if (wlan_cm_is_vdev_connecting( 580 mlo_dev_ctx->wlan_vdev_list[i]) || 581 wlan_cm_is_vdev_disconnecting( 582 mlo_dev_ctx->wlan_vdev_list[i]) || 583 wlan_cm_is_vdev_roaming( 584 mlo_dev_ctx->wlan_vdev_list[i])) { 585 wlan_cm_disconnect(mlo_dev_ctx->wlan_vdev_list[i], 586 source, reason_code, NULL); 587 return QDF_STATUS_SUCCESS; 588 } 589 } 590 } 591 592 return status; 593 } 594 595 static QDF_STATUS 596 mlo_send_link_disconnect_sync(struct wlan_mlo_dev_context *mlo_dev_ctx, 597 enum wlan_cm_source source, 598 enum wlan_reason_code reason_code, 599 struct qdf_mac_addr *bssid) 600 { 601 uint8_t i = 0; 602 QDF_STATUS status = QDF_STATUS_E_ALREADY; 603 604 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 605 if (!mlo_dev_ctx->wlan_vdev_list[i]) 606 continue; 607 608 if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links)) { 609 if (wlan_cm_is_vdev_connecting( 610 mlo_dev_ctx->wlan_vdev_list[i]) || 611 wlan_cm_is_vdev_disconnecting( 612 mlo_dev_ctx->wlan_vdev_list[i]) || 613 wlan_cm_is_vdev_roaming( 614 mlo_dev_ctx->wlan_vdev_list[i])) { 615 wlan_cm_disconnect_sync( 616 mlo_dev_ctx->wlan_vdev_list[i], 617 source, reason_code); 618 return QDF_STATUS_SUCCESS; 619 } 620 } 621 } 622 623 return status; 624 } 625 #endif 626 627 static QDF_STATUS mlo_disconnect_no_lock(struct wlan_objmgr_vdev *vdev, 628 enum wlan_cm_source source, 629 enum wlan_reason_code reason_code, 630 struct qdf_mac_addr *bssid) 631 { 632 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 633 struct wlan_objmgr_vdev *tmp_vdev = vdev; 634 struct wlan_mlo_sta *sta_ctx = NULL; 635 QDF_STATUS status = QDF_STATUS_SUCCESS; 636 637 if (mlo_dev_ctx) { 638 sta_ctx = mlo_dev_ctx->sta_ctx; 639 if (!sta_ctx) 640 return QDF_STATUS_E_FAILURE; 641 642 if (sta_ctx->connect_req) { 643 qdf_mem_free(sta_ctx->connect_req); 644 sta_ctx->connect_req = NULL; 645 } 646 647 if (sta_ctx->orig_conn_req) { 648 qdf_mem_free(sta_ctx->orig_conn_req); 649 sta_ctx->orig_conn_req = NULL; 650 } 651 652 status = mlo_send_link_disconnect(mlo_dev_ctx, source, 653 reason_code, bssid); 654 655 if (QDF_IS_STATUS_SUCCESS(status)) 656 return status; 657 658 tmp_vdev = mlo_get_connected_link_vdev(mlo_dev_ctx); 659 if (tmp_vdev) { 660 status = wlan_cm_disconnect(tmp_vdev, source, 661 reason_code, NULL); 662 return status; 663 } 664 tmp_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx); 665 if (tmp_vdev) { 666 status = wlan_cm_disconnect(tmp_vdev, source, 667 reason_code, NULL); 668 return status; 669 } 670 } 671 672 return status; 673 } 674 675 QDF_STATUS mlo_disconnect(struct wlan_objmgr_vdev *vdev, 676 enum wlan_cm_source source, 677 enum wlan_reason_code reason_code, 678 struct qdf_mac_addr *bssid) 679 { 680 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 681 struct wlan_objmgr_vdev *tmp_vdev = NULL; 682 struct wlan_mlo_sta *sta_ctx = NULL; 683 QDF_STATUS status = QDF_STATUS_SUCCESS; 684 685 if (mlo_dev_ctx && wlan_vdev_mlme_is_mlo_vdev(vdev)) { 686 sta_ctx = mlo_dev_ctx->sta_ctx; 687 mlo_dev_lock_acquire(mlo_dev_ctx); 688 if (sta_ctx->connect_req) { 689 qdf_mem_free(sta_ctx->connect_req); 690 sta_ctx->connect_req = NULL; 691 } 692 693 if (sta_ctx->orig_conn_req) { 694 qdf_mem_free(sta_ctx->orig_conn_req); 695 sta_ctx->orig_conn_req = NULL; 696 } 697 698 status = mlo_send_link_disconnect(mlo_dev_ctx, source, 699 reason_code, bssid); 700 701 if (QDF_IS_STATUS_SUCCESS(status)) { 702 mlo_dev_lock_release(mlo_dev_ctx); 703 return status; 704 } 705 706 tmp_vdev = mlo_get_connected_link_vdev(mlo_dev_ctx); 707 if (tmp_vdev) { 708 status = wlan_cm_disconnect(tmp_vdev, source, 709 reason_code, NULL); 710 mlo_dev_lock_release(mlo_dev_ctx); 711 return status; 712 } 713 tmp_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx); 714 if (tmp_vdev) { 715 status = wlan_cm_disconnect(tmp_vdev, source, 716 reason_code, NULL); 717 mlo_dev_lock_release(mlo_dev_ctx); 718 return status; 719 } 720 mlo_dev_lock_release(mlo_dev_ctx); 721 return status; 722 } 723 return wlan_cm_disconnect(vdev, source, 724 reason_code, NULL); 725 } 726 727 QDF_STATUS mlo_sync_disconnect(struct wlan_objmgr_vdev *vdev, 728 enum wlan_cm_source source, 729 enum wlan_reason_code reason_code, 730 struct qdf_mac_addr *bssid) 731 { 732 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 733 struct wlan_objmgr_vdev *tmp_vdev = NULL; 734 struct wlan_mlo_sta *sta_ctx = NULL; 735 QDF_STATUS status = QDF_STATUS_SUCCESS; 736 737 if (mlo_dev_ctx && wlan_vdev_mlme_is_mlo_vdev(vdev)) { 738 sta_ctx = mlo_dev_ctx->sta_ctx; 739 if (sta_ctx->connect_req) { 740 qdf_mem_free(sta_ctx->connect_req); 741 sta_ctx->connect_req = NULL; 742 } 743 744 if (sta_ctx->orig_conn_req) { 745 qdf_mem_free(sta_ctx->orig_conn_req); 746 sta_ctx->orig_conn_req = NULL; 747 } 748 749 status = mlo_send_link_disconnect_sync(mlo_dev_ctx, source, 750 reason_code, bssid); 751 752 if (QDF_IS_STATUS_SUCCESS(status)) 753 return status; 754 755 tmp_vdev = mlo_get_connected_link_vdev(mlo_dev_ctx); 756 if (tmp_vdev) { 757 status = wlan_cm_disconnect_sync(tmp_vdev, source, 758 reason_code); 759 return status; 760 } 761 tmp_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx); 762 if (tmp_vdev) { 763 status = wlan_cm_disconnect_sync(tmp_vdev, source, 764 reason_code); 765 return status; 766 } 767 return status; 768 } 769 return wlan_cm_disconnect_sync(vdev, source, 770 reason_code); 771 } 772 773 /** 774 * mlo_handle_disconnect_resp- Issue desired actions on partner link vdev 775 * 776 * @mlo_dev_ctx: pointer to mlo dev context 777 * @resp: disconnect resp 778 * 779 * Return: none 780 */ 781 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 782 static 783 void mlo_handle_disconnect_resp(struct wlan_mlo_dev_context *mlo_dev_ctx, 784 struct wlan_cm_discon_rsp *resp) 785 { 786 /* If it is secondary link then delete vdev object from mlo device. */ 787 } 788 #else 789 static 790 void mlo_handle_disconnect_resp(struct wlan_mlo_dev_context *mlo_dev_ctx, 791 struct wlan_cm_discon_rsp *resp) 792 { 793 struct wlan_objmgr_vdev *assoc_vdev = NULL; 794 enum wlan_cm_source source; 795 enum wlan_reason_code reason_code; 796 uint8_t i = 0; 797 798 mlo_dev_lock_acquire(mlo_dev_ctx); 799 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 800 if (!mlo_dev_ctx->wlan_vdev_list[i]) 801 continue; 802 803 if (qdf_test_bit(i, mlo_dev_ctx->sta_ctx->wlan_connected_links)) { 804 if (wlan_cm_is_vdev_connected( 805 mlo_dev_ctx->wlan_vdev_list[i])) { 806 if (wlan_vdev_mlme_is_mlo_link_vdev( 807 mlo_dev_ctx->wlan_vdev_list[i])) { 808 source = resp->req.req.source; 809 reason_code = resp->req.req.reason_code; 810 wlan_cm_disconnect(mlo_dev_ctx->wlan_vdev_list[i], 811 source, reason_code, NULL); 812 mlo_dev_lock_release(mlo_dev_ctx); 813 return; 814 } 815 } 816 } 817 } 818 assoc_vdev = mlo_get_assoc_link_vdev(mlo_dev_ctx); 819 if (assoc_vdev && wlan_cm_is_vdev_connected(assoc_vdev)) { 820 source = resp->req.req.source; 821 reason_code = resp->req.req.reason_code; 822 wlan_cm_disconnect(assoc_vdev, 823 source, reason_code, NULL); 824 mlo_dev_lock_release(mlo_dev_ctx); 825 return; 826 } 827 mlo_dev_lock_release(mlo_dev_ctx); 828 } 829 #endif 830 831 void mlo_sta_link_disconn_notify(struct wlan_objmgr_vdev *vdev, 832 struct wlan_cm_discon_rsp *resp) 833 { 834 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 835 struct wlan_mlo_sta *sta_ctx = NULL; 836 837 if (!mlo_dev_ctx || !(wlan_vdev_mlme_is_mlo_vdev(vdev))) 838 return; 839 840 sta_ctx = mlo_dev_ctx->sta_ctx; 841 if (!sta_ctx) 842 return; 843 844 if (!wlan_cm_is_vdev_disconnected(vdev)) 845 return; 846 847 if (vdev == mlo_get_assoc_link_vdev(mlo_dev_ctx)) { 848 if (sta_ctx->connect_req) { 849 mlo_connect(mlo_get_assoc_link_vdev(mlo_dev_ctx), 850 sta_ctx->connect_req); 851 qdf_mem_free(sta_ctx->connect_req); 852 sta_ctx->connect_req = NULL; 853 } 854 return; 855 } 856 857 mlo_handle_disconnect_resp(mlo_dev_ctx, resp); 858 } 859 860 bool mlo_is_mld_sta(struct wlan_objmgr_vdev *vdev) 861 { 862 if ((wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE) && 863 wlan_vdev_mlme_is_mlo_vdev(vdev)) 864 return true; 865 866 return false; 867 } 868 869 #ifndef WLAN_FEATURE_11BE_MLO_ADV_FEATURE 870 void mlo_iterate_connected_vdev_list(struct wlan_objmgr_vdev *vdev, 871 mlo_vdev_op_handler handler, 872 void *arg) 873 { 874 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 875 struct wlan_mlo_sta *sta_ctx = NULL; 876 uint8_t i = 0; 877 878 if (!mlo_dev_ctx || !(wlan_vdev_mlme_is_mlo_vdev(vdev))) 879 return; 880 881 sta_ctx = mlo_dev_ctx->sta_ctx; 882 if (!sta_ctx) 883 return; 884 885 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 886 if (!mlo_dev_ctx->wlan_vdev_list[i]) 887 continue; 888 if (qdf_test_bit(i, sta_ctx->wlan_connected_links)) { 889 if (handler) 890 handler(mlo_dev_ctx->wlan_vdev_list[i], arg); 891 } 892 } 893 } 894 895 896 void mlo_update_connect_req_links(struct wlan_objmgr_vdev *vdev, uint8_t value) 897 { 898 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 899 struct wlan_mlo_sta *sta_ctx = NULL; 900 uint8_t i = 0; 901 902 if (!mlo_dev_ctx) 903 return; 904 905 sta_ctx = mlo_dev_ctx->sta_ctx; 906 if (!sta_ctx) 907 return; 908 909 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 910 if (!mlo_dev_ctx->wlan_vdev_list[i]) 911 continue; 912 913 if (vdev == mlo_dev_ctx->wlan_vdev_list[i]) { 914 if (value) 915 qdf_set_bit(i, sta_ctx->wlan_connect_req_links); 916 else 917 qdf_clear_bit(i, sta_ctx->wlan_connect_req_links); 918 } 919 } 920 } 921 922 void mlo_clear_connect_req_links_bmap(struct wlan_objmgr_vdev *vdev) 923 { 924 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 925 struct wlan_mlo_sta *sta_ctx = NULL; 926 927 if (!mlo_dev_ctx) 928 return; 929 930 sta_ctx = mlo_dev_ctx->sta_ctx; 931 if (!sta_ctx) 932 return; 933 934 qdf_mem_zero(sta_ctx->wlan_connect_req_links, 935 sizeof(sta_ctx->wlan_connect_req_links)); 936 } 937 938 void mlo_update_connected_links(struct wlan_objmgr_vdev *vdev, uint8_t value) 939 { 940 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 941 struct wlan_mlo_sta *sta_ctx = NULL; 942 uint8_t i = 0; 943 944 if (!mlo_dev_ctx) 945 return; 946 947 sta_ctx = mlo_dev_ctx->sta_ctx; 948 if (!sta_ctx) 949 return; 950 951 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 952 if (!mlo_dev_ctx->wlan_vdev_list[i]) 953 continue; 954 955 if (vdev == mlo_dev_ctx->wlan_vdev_list[i]) { 956 if (value) 957 qdf_set_bit(i, sta_ctx->wlan_connected_links); 958 else 959 qdf_clear_bit(i, sta_ctx->wlan_connected_links); 960 } 961 } 962 } 963 964 void mlo_clear_connected_links_bmap(struct wlan_objmgr_vdev *vdev) 965 { 966 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 967 struct wlan_mlo_sta *sta_ctx = NULL; 968 969 if (!mlo_dev_ctx) 970 return; 971 972 sta_ctx = mlo_dev_ctx->sta_ctx; 973 if (!sta_ctx) 974 return; 975 976 qdf_mem_zero(sta_ctx->wlan_connected_links, 977 sizeof(sta_ctx->wlan_connected_links)); 978 } 979 980 struct wlan_objmgr_vdev * 981 mlo_get_ml_vdev_by_mac(struct wlan_objmgr_vdev *vdev, 982 struct qdf_mac_addr *macaddr) 983 { 984 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 985 uint8_t i = 0; 986 987 if (!mlo_dev_ctx) 988 return NULL; 989 990 for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { 991 if (!mlo_dev_ctx->wlan_vdev_list[i]) 992 continue; 993 994 if(qdf_mem_cmp(macaddr, 995 wlan_vdev_mlme_get_macaddr(mlo_dev_ctx->wlan_vdev_list[i]), 996 QDF_MAC_ADDR_SIZE) == 0) { 997 return mlo_dev_ctx->wlan_vdev_list[i]; 998 } 999 } 1000 return NULL; 1001 } 1002 #endif 1003 1004 qdf_freq_t 1005 mlo_get_chan_freq_by_bssid(struct wlan_objmgr_pdev *pdev, 1006 struct qdf_mac_addr *bssid) 1007 { 1008 struct scan_filter *scan_filter; 1009 int8_t ch_freq = 0; 1010 qdf_list_t *list = NULL; 1011 struct scan_cache_node *first_node = NULL; 1012 qdf_list_node_t *cur_node = NULL; 1013 1014 scan_filter = qdf_mem_malloc(sizeof(*scan_filter)); 1015 if (!scan_filter) 1016 return ch_freq; 1017 1018 scan_filter->num_of_bssid = 1; 1019 qdf_mem_copy(scan_filter->bssid_list[0].bytes, 1020 bssid, sizeof(struct qdf_mac_addr)); 1021 list = wlan_scan_get_result(pdev, scan_filter); 1022 qdf_mem_free(scan_filter); 1023 1024 if (!list || (list && !qdf_list_size(list))) { 1025 mlo_debug("scan list empty"); 1026 goto error; 1027 } 1028 1029 qdf_list_peek_front(list, &cur_node); 1030 first_node = qdf_container_of(cur_node, 1031 struct scan_cache_node, 1032 node); 1033 if (first_node && first_node->entry) 1034 ch_freq = first_node->entry->channel.chan_freq; 1035 error: 1036 if (list) 1037 wlan_scan_purge_results(list); 1038 1039 return ch_freq; 1040 } 1041 1042 void mlo_get_assoc_rsp(struct wlan_objmgr_vdev *vdev, 1043 struct element_info **assoc_rsp_frame) 1044 { 1045 struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; 1046 struct wlan_mlo_sta *sta_ctx = mlo_dev_ctx->sta_ctx; 1047 1048 if (!mlo_dev_ctx || !mlo_dev_ctx->sta_ctx) 1049 return; 1050 1051 if (!sta_ctx->assoc_rsp.len || !sta_ctx->assoc_rsp.ptr) { 1052 mlo_err("Assoc Resp info is empty"); 1053 return; 1054 } 1055 1056 *assoc_rsp_frame = &sta_ctx->assoc_rsp; 1057 } 1058 #endif 1059