1 /* 2 * Copyright (c) 2021, The Linux Foundation. All rights reserved. 3 * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 /** 19 * DOC : lim_mlo.c 20 * 21 * WLAN Host Device Driver file for 802.11be (Extremely High Throughput) 22 * support. 23 * 24 */ 25 26 #include "lim_mlo.h" 27 #include "sch_api.h" 28 #include "lim_types.h" 29 #include "wlan_mlo_mgr_ap.h" 30 #include "wlan_mlo_mgr_op.h" 31 #include <wlan_mlo_mgr_peer.h> 32 #include <lim_assoc_utils.h> 33 #include <wlan_mlo_mgr_peer.h> 34 #include <lim_utils.h> 35 #include <utils_mlo.h> 36 37 QDF_STATUS lim_cu_info_from_rnr_per_link_id(const uint8_t *rnr, 38 uint8_t linkid, uint8_t *bpcc, 39 uint8_t *aui) 40 { 41 const uint8_t *data, *rnr_end; 42 struct neighbor_ap_info_field *neighbor_ap_info; 43 uint8_t tbtt_type, tbtt_len, tbtt_count; 44 uint8_t mld_pos, mld_id, link_id; 45 struct rnr_mld_info *mld_param; 46 int32_t i, len; 47 uint8_t nbr_ap_info_len = sizeof(struct neighbor_ap_info_field); 48 49 if (!rnr) 50 return QDF_STATUS_E_INVAL; 51 52 rnr_end = rnr + rnr[TAG_LEN_POS] + MIN_IE_LEN; 53 data = rnr + PAYLOAD_START_POS; 54 while ((data + sizeof(struct neighbor_ap_info_field)) <= rnr_end) { 55 neighbor_ap_info = (struct neighbor_ap_info_field *)data; 56 tbtt_count = neighbor_ap_info->tbtt_header.tbtt_info_count; 57 tbtt_len = neighbor_ap_info->tbtt_header.tbtt_info_length; 58 tbtt_type = neighbor_ap_info->tbtt_header.tbbt_info_fieldtype; 59 len = tbtt_len * (tbtt_count + 1) + nbr_ap_info_len; 60 if (data + len > rnr_end) { 61 pe_debug("error about rnr length"); 62 return QDF_STATUS_E_INVAL; 63 } 64 65 if (tbtt_len >= 66 TBTT_NEIGHBOR_AP_BSSID_S_SSID_BSS_PARAM_20MHZ_PSD_MLD_PARAM) 67 mld_pos = 68 TBTT_NEIGHBOR_AP_BSSID_S_SSID_BSS_PARAM_20MHZ_PSD; 69 else 70 mld_pos = 0; 71 72 if (mld_pos == 0 || tbtt_type != 0) { 73 data += len; 74 continue; 75 } 76 77 data += nbr_ap_info_len; 78 for (i = 0; i < tbtt_count + 1; i++) { 79 mld_param = (struct rnr_mld_info *)&data[mld_pos]; 80 mld_id = mld_param->mld_id; 81 if (mld_id == 0) { 82 link_id = mld_param->link_id; 83 if (linkid == link_id) { 84 *bpcc = mld_param->bss_param_change_cnt; 85 *aui = mld_param->all_updates_included; 86 pe_debug("rnr bpcc %d, aui %d, linkid %d", 87 *bpcc, *aui, linkid); 88 return QDF_STATUS_SUCCESS; 89 } 90 } 91 data += tbtt_len; 92 } 93 } 94 95 return QDF_STATUS_E_INVAL; 96 } 97 98 QDF_STATUS lim_get_bpcc_from_mlo_ie(tSchBeaconStruct *bcn, uint8_t *bpcc) 99 { 100 struct sir_multi_link_ie *mlo_ie; 101 QDF_STATUS status = QDF_STATUS_E_INVAL; 102 103 if (!bcn) 104 return status; 105 106 mlo_ie = &bcn->mlo_ie; 107 if (mlo_ie->mlo_ie_present && 108 mlo_ie->mlo_ie.bss_param_change_cnt_present) { 109 *bpcc = mlo_ie->mlo_ie.bss_param_change_count; 110 pe_debug("mlie bpcc %d", *bpcc); 111 status = QDF_STATUS_SUCCESS; 112 } else { 113 *bpcc = 0; 114 } 115 116 return status; 117 } 118 119 bool lim_check_cu_happens(struct wlan_objmgr_vdev *vdev, uint8_t new_bpcc) 120 { 121 uint8_t bpcc; 122 uint8_t vdev_id; 123 QDF_STATUS status; 124 125 if (!vdev || !wlan_vdev_mlme_is_mlo_vdev(vdev)) 126 return false; 127 128 vdev_id = wlan_vdev_get_id(vdev); 129 130 status = wlan_mlo_get_cu_bpcc(vdev, &bpcc); 131 if (QDF_IS_STATUS_ERROR(status)) 132 return false; 133 134 if (new_bpcc == 0 && bpcc == 0) 135 return false; 136 137 pe_debug_rl("vdev id %d new bpcc %d, old bpcc %d", 138 vdev_id, new_bpcc, bpcc); 139 if (new_bpcc && new_bpcc < bpcc) 140 return false; 141 142 wlan_mlo_set_cu_bpcc(vdev, new_bpcc); 143 144 return true; 145 } 146 147 /** 148 * lim_send_mlo_ie_update() - mlo ie is changed, populate new beacon template 149 * @session: pe session 150 * 151 * Return: void 152 */ 153 static void lim_send_mlo_ie_update(struct mac_context *mac_ctx, 154 struct pe_session *session) 155 { 156 if (QDF_IS_STATUS_ERROR( 157 sch_set_fixed_beacon_fields(mac_ctx, session))) { 158 pe_err("Unable to update mlo IE in beacon"); 159 return; 160 } 161 162 lim_send_beacon_ind(mac_ctx, session, REASON_MLO_IE_UPDATE); 163 } 164 165 QDF_STATUS lim_partner_link_info_change(struct wlan_objmgr_vdev *vdev) 166 { 167 struct pe_session *session; 168 struct mac_context *mac; 169 170 mac = cds_get_context(QDF_MODULE_ID_PE); 171 if (!mac) { 172 pe_err("mac ctx is null"); 173 return QDF_STATUS_E_INVAL; 174 } 175 if (!vdev) { 176 pe_err("vdev is null"); 177 return QDF_STATUS_E_INVAL; 178 } 179 session = pe_find_session_by_vdev_id( 180 mac, vdev->vdev_objmgr.vdev_id); 181 if (!session) { 182 pe_err("session is NULL"); 183 return QDF_STATUS_E_INVAL; 184 } 185 186 if (session->mlo_link_info.bcn_tmpl_exist) 187 lim_send_mlo_ie_update(mac, session); 188 189 return QDF_STATUS_SUCCESS; 190 } 191 192 void lim_mlo_release_vdev_ref(struct wlan_objmgr_vdev *vdev) 193 { 194 wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); 195 } 196 197 struct pe_session *pe_find_partner_session_by_link_id( 198 struct pe_session *session, uint8_t link_id) 199 { 200 struct wlan_objmgr_vdev *vdev; 201 struct mac_context *mac; 202 struct pe_session *partner_session; 203 204 mac = cds_get_context(QDF_MODULE_ID_PE); 205 if (!mac) { 206 pe_err("mac ctx is null"); 207 return NULL; 208 } 209 210 if (!session) { 211 pe_err("session is null"); 212 return NULL; 213 } 214 215 vdev = mlo_get_vdev_by_link_id(session->vdev, link_id, 216 WLAN_LEGACY_MAC_ID); 217 218 if (!vdev) { 219 pe_err("vdev is null"); 220 return NULL; 221 } 222 223 partner_session = pe_find_session_by_vdev_id( 224 mac, vdev->vdev_objmgr.vdev_id); 225 226 if (!partner_session) 227 wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); 228 229 return partner_session; 230 } 231 232 void lim_get_mlo_vdev_list(struct pe_session *session, uint16_t *vdev_count, 233 struct wlan_objmgr_vdev **wlan_vdev_list) 234 { 235 mlo_ap_get_vdev_list(session->vdev, vdev_count, 236 wlan_vdev_list); 237 } 238 239 /** 240 * lim_mlo_get_assoc_link_session_sta_ds() - get assoc link session and sta ds 241 * @session: pe session 242 * @partner_peer_idx: aid 243 * @assoc_session: assoc link session 244 * @assoc_sta: assoc sta ds 245 * 246 * Return: void 247 */ 248 static void lim_mlo_get_assoc_link_session_sta_ds( 249 struct pe_session *session, 250 uint16_t partner_peer_idx, 251 struct pe_session **assoc_session, 252 tpDphHashNode *assoc_sta) 253 { 254 struct wlan_mlo_peer_context *mlo_peer_ctx; 255 struct wlan_objmgr_peer *peer; 256 uint16_t aid = 0; 257 struct mac_context *mac; 258 struct wlan_objmgr_vdev *vdev; 259 struct pe_session *partner_session; 260 261 *assoc_session = NULL; 262 *assoc_sta = NULL; 263 mac = cds_get_context(QDF_MODULE_ID_PE); 264 if (!mac) { 265 pe_err("mac ctx is null"); 266 return; 267 } 268 if (!session) { 269 pe_err("session is NULL"); 270 return; 271 } 272 273 mlo_peer_ctx = wlan_mlo_get_mlpeer_by_aid(session->vdev->mlo_dev_ctx, 274 partner_peer_idx); 275 if (!mlo_peer_ctx) { 276 pe_err("mlo peer ctx is null"); 277 return; 278 } 279 peer = wlan_mlo_peer_get_assoc_peer(mlo_peer_ctx); 280 if (!peer) { 281 pe_err("peer is null"); 282 return; 283 } 284 vdev = wlan_peer_get_vdev(peer); 285 if (!vdev) { 286 pe_err("vdev is null"); 287 return; 288 } 289 partner_session = pe_find_session_by_vdev_id( 290 mac, vdev->vdev_objmgr.vdev_id); 291 292 if (!partner_session) { 293 pe_err("assoc session is null"); 294 return; 295 } 296 *assoc_sta = dph_lookup_hash_entry(mac, peer->macaddr, &aid, 297 &partner_session->dph.dphHashTable); 298 *assoc_session = partner_session; 299 } 300 301 /** 302 * lim_mlo_update_cleanup_trigger () - update clean up trigger 303 * @session: pointer to session 304 * @sta_ds: sta ds 305 * @clnup_tri: clean up trigger 306 * 307 * Return: Void 308 */ 309 static void lim_mlo_update_cleanup_trigger(struct pe_session *session, 310 tpDphHashNode sta_ds, 311 uint16_t clnup_tri) 312 { 313 tpDphHashNode assoc_sta = NULL; 314 struct pe_session *link_session; 315 struct pe_session *assoc_session = NULL; 316 struct mac_context *mac_ctx; 317 tpDphHashNode link_sta; 318 uint8_t link_id; 319 int link; 320 uint8_t *sta_addr; 321 uint16_t assoc_id; 322 323 mac_ctx = cds_get_context(QDF_MODULE_ID_PE); 324 if (!mac_ctx) { 325 pe_err("mac ctx is null"); 326 return; 327 } 328 if (!session) { 329 pe_err("session is null"); 330 return; 331 } 332 if (!sta_ds) { 333 pe_err("sta ds is null"); 334 return; 335 } 336 337 if (lim_is_mlo_recv_assoc(sta_ds)) { 338 assoc_sta = sta_ds; 339 } else { 340 lim_mlo_get_assoc_link_session_sta_ds(session, sta_ds->assocId, 341 &assoc_session, 342 &assoc_sta); 343 if (!assoc_sta) { 344 pe_err("assoc link sta ds is null"); 345 return; 346 } 347 348 assoc_sta->mlmStaContext.cleanupTrigger = clnup_tri; 349 } 350 for (link = 0; link < assoc_sta->mlo_info.num_partner_links; link++) { 351 link_id = assoc_sta->mlo_info.partner_link_info[link].link_id; 352 link_session = pe_find_partner_session_by_link_id(session, 353 link_id); 354 if (!link_session) 355 continue; 356 sta_addr = 357 assoc_sta->mlo_info.partner_link_info[link].link_addr.bytes; 358 link_sta = dph_lookup_hash_entry( 359 mac_ctx, 360 sta_addr, 361 &assoc_id, 362 &link_session->dph.dphHashTable); 363 if (!link_sta || link_sta == sta_ds) { 364 lim_mlo_release_vdev_ref(link_session->vdev); 365 continue; 366 } 367 link_sta->mlmStaContext.cleanupTrigger = clnup_tri; 368 lim_mlo_release_vdev_ref(link_session->vdev); 369 } 370 } 371 372 void lim_mlo_notify_peer_disconn(struct pe_session *pe_session, 373 tpDphHashNode sta_ds) 374 { 375 struct wlan_objmgr_peer *peer; 376 struct mac_context *mac_ctx; 377 378 if (!pe_session) { 379 pe_err("pe session is null"); 380 return; 381 } 382 if (!sta_ds) { 383 pe_err("sta ds is null"); 384 return; 385 } 386 mac_ctx = pe_session->mac_ctx; 387 if (!mac_ctx) { 388 pe_err("mac context is null"); 389 return; 390 } 391 392 peer = wlan_objmgr_get_peer_by_mac(mac_ctx->psoc, 393 sta_ds->staAddr, 394 WLAN_LEGACY_MAC_ID); 395 if (!peer) { 396 pe_err("peer is null"); 397 return; 398 } 399 400 if (wlan_peer_mlme_flag_ext_get(peer, WLAN_PEER_FEXT_MLO)) { 401 if (wlan_vdev_mlme_is_mlo_ap(pe_session->vdev)) 402 lim_mlo_update_cleanup_trigger( 403 pe_session, sta_ds, 404 sta_ds->mlmStaContext.cleanupTrigger); 405 wlan_mlo_partner_peer_disconnect_notify(peer); 406 } 407 408 wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID); 409 } 410 411 void lim_mlo_sta_notify_peer_disconn(struct pe_session *pe_session) 412 { 413 struct wlan_objmgr_peer *peer; 414 struct mac_context *mac_ctx; 415 416 if (!pe_session) { 417 pe_err("pe session is null"); 418 return; 419 } 420 mac_ctx = pe_session->mac_ctx; 421 if (!mac_ctx) { 422 pe_err("mac context is null"); 423 return; 424 } 425 426 peer = wlan_objmgr_get_peer_by_mac(mac_ctx->psoc, 427 pe_session->bssId, 428 WLAN_LEGACY_MAC_ID); 429 if (!peer) { 430 pe_err("peer is null"); 431 return; 432 } 433 434 if (wlan_peer_mlme_flag_ext_get(peer, WLAN_PEER_FEXT_MLO)) 435 wlan_mlo_partner_peer_disconnect_notify(peer); 436 437 wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID); 438 } 439 440 void lim_mlo_roam_peer_disconn_del(struct wlan_objmgr_vdev *vdev) 441 { 442 struct wlan_objmgr_peer *peer; 443 struct wlan_objmgr_psoc *psoc; 444 QDF_STATUS status = QDF_STATUS_SUCCESS; 445 struct qdf_mac_addr bssid; 446 447 if (!vdev) { 448 pe_err("vdev is null"); 449 return; 450 } 451 452 psoc = wlan_vdev_get_psoc(vdev); 453 if (!psoc) { 454 pe_err("psoc is null"); 455 return; 456 } 457 458 status = wlan_vdev_get_bss_peer_mac(vdev, &bssid); 459 if (QDF_IS_STATUS_ERROR(status)) { 460 pe_debug("vdev id %d : failed to get bssid", 461 wlan_vdev_get_id(vdev)); 462 return; 463 } 464 465 peer = wlan_objmgr_get_peer_by_mac(psoc, 466 bssid.bytes, 467 WLAN_LEGACY_MAC_ID); 468 if (!peer) { 469 pe_err("peer is null"); 470 return; 471 } 472 473 if (wlan_peer_mlme_flag_ext_get(peer, WLAN_PEER_FEXT_MLO)) { 474 pe_debug("vdev id %d disconn del peer", wlan_vdev_get_id(vdev)); 475 wlan_mlo_partner_peer_disconnect_notify(peer); 476 wlan_mlo_link_peer_delete(peer); 477 } 478 479 wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID); 480 } 481 482 void lim_mlo_cleanup_partner_peer(struct wlan_objmgr_peer *peer) 483 { 484 struct mac_context *mac_ctx; 485 uint16_t aid; 486 tpDphHashNode sta_ds; 487 struct pe_session *pe_session; 488 tpSirAssocReq tmp_assoc_req; 489 struct wlan_objmgr_vdev *vdev; 490 491 mac_ctx = cds_get_context(QDF_MODULE_ID_PE); 492 if (!mac_ctx) { 493 pe_err("mac ctx is null"); 494 return; 495 } 496 497 vdev = wlan_peer_get_vdev(peer); 498 if (!vdev) { 499 pe_err("vdev is null"); 500 return; 501 } 502 503 pe_session = pe_find_session_by_vdev_id( 504 mac_ctx, vdev->vdev_objmgr.vdev_id); 505 if (!pe_session) { 506 pe_err("pe session is null"); 507 return; 508 } 509 510 sta_ds = dph_lookup_hash_entry(mac_ctx, peer->macaddr, &aid, 511 &pe_session->dph.dphHashTable); 512 513 if (!sta_ds) { 514 pe_err("sta ds is null"); 515 return; 516 } 517 518 lim_cleanup_rx_path(mac_ctx, sta_ds, pe_session, true); 519 520 if (pe_session->parsedAssocReq) { 521 tmp_assoc_req = pe_session->parsedAssocReq[sta_ds->assocId]; 522 if (tmp_assoc_req) { 523 lim_free_assoc_req_frm_buf(tmp_assoc_req); 524 qdf_mem_free(tmp_assoc_req); 525 tmp_assoc_req = NULL; 526 } 527 528 pe_session->parsedAssocReq[sta_ds->assocId] = NULL; 529 } 530 } 531 532 void lim_mlo_set_mld_mac_peer(tpDphHashNode sta_ds, 533 uint8_t peer_mld_addr[QDF_MAC_ADDR_SIZE]) 534 { 535 WLAN_ADDR_COPY(sta_ds->mld_addr, peer_mld_addr); 536 } 537 538 bool lim_is_mlo_conn(struct pe_session *session, tpDphHashNode sta_ds) 539 { 540 bool mlo_conn = false; 541 542 if (!sta_ds) { 543 pe_err("sta ds is null"); 544 return mlo_conn; 545 } 546 547 if (!session) { 548 pe_err("session is null"); 549 return mlo_conn; 550 } 551 552 if (wlan_vdev_mlme_is_mlo_vdev(session->vdev) && 553 !qdf_is_macaddr_zero((struct qdf_mac_addr *)sta_ds->mld_addr)) 554 mlo_conn = true; 555 556 return mlo_conn; 557 } 558 559 void lim_set_mlo_recv_assoc(tpDphHashNode sta_ds, bool mlo_recv_assoc_frm) 560 { 561 if (!sta_ds) { 562 pe_err("sta ds is null"); 563 return; 564 } 565 566 sta_ds->recv_assoc_frm = mlo_recv_assoc_frm; 567 } 568 569 bool lim_is_mlo_recv_assoc(tpDphHashNode sta_ds) 570 { 571 if (!sta_ds) { 572 pe_err("sta ds is null"); 573 return false; 574 } 575 576 return sta_ds->recv_assoc_frm; 577 } 578 579 QDF_STATUS lim_mlo_proc_assoc_req_frm(struct wlan_objmgr_vdev *vdev, 580 struct wlan_mlo_peer_context *ml_peer, 581 struct qdf_mac_addr *link_addr, 582 qdf_nbuf_t buf) 583 { 584 struct mac_context *mac_ctx; 585 struct pe_session *session; 586 tSirMacAddr sa; 587 uint8_t sub_type; 588 uint32_t frame_len; 589 uint8_t *frm_body; 590 tpSirMacMgmtHdr pHdr; 591 tSirMacFrameCtl fc; 592 tpSirAssocReq assoc_req; 593 QDF_STATUS status; 594 qdf_size_t link_frame_len = 0; 595 struct qdf_mac_addr link_bssid; 596 597 if (!vdev) { 598 pe_err("vdev is null"); 599 return QDF_STATUS_E_INVAL; 600 } 601 602 if (!ml_peer) { 603 pe_err("ml_peer is null"); 604 return QDF_STATUS_E_INVAL; 605 } 606 607 if (!link_addr) { 608 pe_err("link addr is null"); 609 return QDF_STATUS_E_INVAL; 610 } 611 612 if (!buf) { 613 pe_err("assoq req buf is null"); 614 return QDF_STATUS_E_INVAL; 615 } 616 617 mac_ctx = cds_get_context(QDF_MODULE_ID_PE); 618 if (!mac_ctx) { 619 pe_err("mac ctx is null"); 620 return QDF_STATUS_E_INVAL; 621 } 622 623 session = pe_find_session_by_vdev_id( 624 mac_ctx, vdev->vdev_objmgr.vdev_id); 625 if (!session) { 626 pe_err("session is NULL"); 627 return QDF_STATUS_E_INVAL; 628 } 629 630 if (qdf_nbuf_len(buf) <= sizeof(*pHdr)) { 631 pe_err("invalid buf"); 632 return QDF_STATUS_E_INVAL; 633 } 634 635 frame_len = qdf_nbuf_len(buf) - sizeof(*pHdr); 636 frm_body = qdf_nbuf_data(buf) + sizeof(*pHdr); 637 pHdr = (tpSirMacMgmtHdr)qdf_nbuf_data(buf); 638 fc = pHdr->fc; 639 640 if (fc.type == SIR_MAC_MGMT_FRAME) { 641 if (fc.subType == SIR_MAC_MGMT_ASSOC_REQ) { 642 sub_type = LIM_ASSOC; 643 } else if (fc.subType == SIR_MAC_MGMT_REASSOC_REQ) { 644 sub_type = LIM_REASSOC; 645 } else { 646 pe_err("invalid mgt_type %d, sub_type %d", 647 fc.type, fc.subType); 648 return QDF_STATUS_E_INVAL; 649 } 650 } else { 651 pe_err("invalid mgt_type %d, sub_type %d", 652 fc.type, fc.subType); 653 return QDF_STATUS_E_INVAL; 654 } 655 656 qdf_mem_copy(sa, link_addr->bytes, QDF_MAC_ADDR_SIZE); 657 status = lim_check_assoc_req(mac_ctx, sub_type, sa, session); 658 if (QDF_IS_STATUS_ERROR(status)) 659 return status; 660 661 /* Allocate memory for the Assoc Request frame */ 662 assoc_req = qdf_mem_malloc(sizeof(*assoc_req)); 663 if (!assoc_req) 664 return QDF_STATUS_E_NOMEM; 665 666 assoc_req->assoc_req_buf = qdf_nbuf_copy(buf); 667 if (!assoc_req->assoc_req_buf) { 668 pe_err("partner link assoc request buf clone failed"); 669 qdf_mem_free(assoc_req); 670 return QDF_STATUS_E_NOMEM; 671 } 672 qdf_copy_macaddr(&link_bssid, (struct qdf_mac_addr *)session->bssId); 673 status = util_gen_link_assoc_req( 674 frm_body, frame_len, sub_type == LIM_REASSOC, 675 0, 676 link_bssid, 677 qdf_nbuf_data(assoc_req->assoc_req_buf), 678 qdf_nbuf_len(assoc_req->assoc_req_buf), 679 &link_frame_len); 680 if (QDF_IS_STATUS_ERROR(status)) { 681 pe_warn("Partner Assoc Req frame gen error. source addr:" 682 QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(sa)); 683 lim_free_assoc_req_frm_buf(assoc_req); 684 qdf_mem_free(assoc_req); 685 return status; 686 } 687 688 qdf_nbuf_set_len(assoc_req->assoc_req_buf, link_frame_len); 689 assoc_req->assocReqFrame = qdf_nbuf_data(assoc_req->assoc_req_buf) + 690 sizeof(*pHdr); 691 assoc_req->assocReqFrameLength = link_frame_len - sizeof(*pHdr); 692 693 qdf_copy_macaddr((struct qdf_mac_addr *)assoc_req->mld_mac, 694 &ml_peer->peer_mld_addr); 695 return lim_proc_assoc_req_frm_cmn(mac_ctx, sub_type, session, sa, 696 assoc_req, ml_peer->assoc_id); 697 } 698 699 void lim_mlo_ap_sta_assoc_suc(struct wlan_objmgr_peer *peer) 700 { 701 struct mac_context *mac; 702 tpDphHashNode sta; 703 struct pe_session *pe_session; 704 struct wlan_objmgr_vdev *vdev; 705 uint16_t aid = 0; 706 707 mac = cds_get_context(QDF_MODULE_ID_PE); 708 if (!mac) { 709 pe_err("mac ctx is null"); 710 return; 711 } 712 if (!peer) { 713 pe_err("peer is null"); 714 return; 715 } 716 vdev = wlan_peer_get_vdev(peer); 717 718 pe_session = pe_find_session_by_vdev_id( 719 mac, vdev->vdev_objmgr.vdev_id); 720 721 if (!pe_session) { 722 pe_err("pe_session is NULL"); 723 return; 724 } 725 sta = dph_lookup_hash_entry(mac, peer->macaddr, &aid, 726 &pe_session->dph.dphHashTable); 727 if (!sta) { 728 pe_err("sta ds is null"); 729 return; 730 } 731 if (lim_send_mlm_assoc_ind(mac, sta, pe_session) != QDF_STATUS_SUCCESS) 732 lim_reject_association(mac, sta->staAddr, 733 sta->mlmStaContext.subType, 734 true, sta->mlmStaContext.authType, 735 sta->assocId, true, 736 STATUS_UNSPECIFIED_FAILURE, 737 pe_session); 738 } 739 740 void lim_ap_mlo_sta_peer_ind(struct mac_context *mac, 741 struct pe_session *pe_session, 742 tpDphHashNode sta, 743 bool add_sta_rsp_status) 744 { 745 tpSirAssocReq assoc_req; 746 struct wlan_mlo_peer_context *ml_peer; 747 struct wlan_objmgr_peer *peer; 748 struct mlo_partner_info info; 749 struct mlo_link_info *linfo; 750 751 if (!sta) { 752 pe_err("sta ds is null"); 753 return; 754 } 755 if (add_sta_rsp_status) { 756 peer = wlan_objmgr_get_peer_by_mac(mac->psoc, 757 sta->staAddr, 758 WLAN_LEGACY_MAC_ID); 759 if (!peer) { 760 pe_err("peer is null"); 761 return; 762 } 763 764 if (lim_is_mlo_recv_assoc(sta)) { 765 assoc_req = pe_session->parsedAssocReq[sta->assocId]; 766 if (assoc_req->mlo_info.num_partner_links < 767 QDF_ARRAY_SIZE( 768 assoc_req->mlo_info.partner_link_info)) { 769 qdf_mem_copy(&info, &assoc_req->mlo_info, 770 sizeof(info)); 771 linfo = 772 &info.partner_link_info[info.num_partner_links]; 773 linfo->link_id = wlan_vdev_get_link_id( 774 pe_session->vdev); 775 qdf_mem_copy(linfo->link_addr.bytes, 776 sta->staAddr, QDF_MAC_ADDR_SIZE); 777 info.num_partner_links++; 778 wlan_mlo_peer_create(pe_session->vdev, peer, 779 &info, 780 assoc_req->assoc_req_buf, 781 sta->assocId); 782 } else { 783 pe_err("invalid partner link number %d", 784 assoc_req->mlo_info.num_partner_links); 785 } 786 } else { 787 ml_peer = wlan_mlo_get_mlpeer_by_aid( 788 pe_session->vdev->mlo_dev_ctx, 789 sta->assocId); 790 if (ml_peer) 791 wlan_mlo_link_peer_attach(ml_peer, peer, NULL); 792 } 793 wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID); 794 } else { 795 if (!lim_is_mlo_recv_assoc(sta)) { 796 ml_peer = wlan_mlo_get_mlpeer_by_aid( 797 pe_session->vdev->mlo_dev_ctx, 798 sta->assocId); 799 if (ml_peer) 800 wlan_mlo_partner_peer_create_failed_notify( 801 ml_peer); 802 } 803 } 804 } 805 806 bool lim_mlo_partner_auth_type(struct pe_session *session, 807 uint16_t partner_peer_idx, 808 tAniAuthType *auth_type) 809 { 810 bool status = false; 811 struct pe_session *assoc_link_session = NULL; 812 813 tpDphHashNode sta_ds = NULL; 814 815 lim_mlo_get_assoc_link_session_sta_ds(session, partner_peer_idx, 816 &assoc_link_session, &sta_ds); 817 818 if (sta_ds) { 819 *auth_type = sta_ds->mlmStaContext.authType; 820 status = true; 821 } else { 822 pe_err("sta ds is null"); 823 } 824 825 return status; 826 } 827 828 void lim_mlo_ap_sta_assoc_fail(struct wlan_objmgr_peer *peer) 829 { 830 struct mac_context *mac; 831 struct wlan_objmgr_vdev *vdev; 832 tpDphHashNode sta; 833 struct pe_session *pe_session; 834 uint16_t aid = 0; 835 836 mac = cds_get_context(QDF_MODULE_ID_PE); 837 if (!mac) { 838 pe_err("mac ctx is null"); 839 return; 840 } 841 if (!peer) { 842 pe_err("peer is null"); 843 return; 844 } 845 vdev = wlan_peer_get_vdev(peer); 846 if (!vdev) { 847 pe_err("vdev is null"); 848 return; 849 } 850 pe_session = pe_find_session_by_vdev_id( 851 mac, vdev->vdev_objmgr.vdev_id); 852 853 if (!pe_session) { 854 pe_err("pe_session is NULL"); 855 return; 856 } 857 sta = dph_lookup_hash_entry(mac, peer->macaddr, &aid, 858 &pe_session->dph.dphHashTable); 859 if (!sta) { 860 pe_err("sta ds is null"); 861 return; 862 } 863 lim_reject_association(mac, sta->staAddr, 864 sta->mlmStaContext.subType, 865 true, sta->mlmStaContext.authType, 866 sta->assocId, true, 867 STATUS_UNSPECIFIED_FAILURE, 868 pe_session); 869 } 870 871 void lim_mlo_delete_link_peer(struct pe_session *pe_session, 872 tpDphHashNode sta_ds) 873 { 874 struct wlan_objmgr_peer *peer; 875 struct mac_context *mac; 876 877 mac = cds_get_context(QDF_MODULE_ID_PE); 878 if (!mac) { 879 pe_err("mac ctx is null"); 880 return; 881 } 882 if (!pe_session) { 883 pe_err("pe session is null"); 884 return; 885 } 886 if (!sta_ds) { 887 pe_err("sta ds is null"); 888 return; 889 } 890 if (!lim_is_mlo_conn(pe_session, sta_ds)) 891 return; 892 893 peer = wlan_objmgr_get_peer_by_mac(mac->psoc, 894 sta_ds->staAddr, 895 WLAN_LEGACY_MAC_ID); 896 if (!peer) { 897 pe_err("peer is null"); 898 return; 899 } 900 901 wlan_mlo_link_peer_delete(peer); 902 903 wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID); 904 } 905 906 #if defined(SAP_MULTI_LINK_EMULATION) 907 QDF_STATUS lim_mlo_assoc_ind_upper_layer(struct mac_context *mac, 908 struct pe_session *pe_session, 909 struct mlo_partner_info *mlo_info) 910 { 911 return QDF_STATUS_SUCCESS; 912 } 913 #else 914 QDF_STATUS lim_mlo_assoc_ind_upper_layer(struct mac_context *mac, 915 struct pe_session *pe_session, 916 struct mlo_partner_info *mlo_info) 917 { 918 int link; 919 uint8_t link_id; 920 struct qdf_mac_addr *link_addr; 921 struct pe_session *lk_session; 922 tpDphHashNode sta; 923 uint16_t aid; 924 struct assoc_ind *sme_assoc_ind; 925 struct scheduler_msg msg; 926 tpLimMlmAssocInd lim_assoc_ind; 927 QDF_STATUS status = QDF_STATUS_E_FAILURE; 928 929 if (!mac) { 930 pe_err("mac is NULL"); 931 return status; 932 } 933 934 if (!pe_session) { 935 pe_err("pe_session is NULL"); 936 return status; 937 } 938 939 if (!mlo_info) { 940 pe_err("mlo_info is NULL"); 941 return status; 942 } 943 944 status = QDF_STATUS_SUCCESS; 945 for (link = 0; link < mlo_info->num_partner_links; link++) { 946 link_id = mlo_info->partner_link_info[link].link_id; 947 link_addr = &mlo_info->partner_link_info[link].link_addr; 948 lk_session = pe_find_partner_session_by_link_id(pe_session, 949 link_id); 950 if (!lk_session) { 951 pe_err("link_session is NULL"); 952 status = QDF_STATUS_E_FAILURE; 953 break; 954 } 955 sta = dph_lookup_hash_entry(mac, link_addr->bytes, &aid, 956 &lk_session->dph.dphHashTable); 957 if (!sta) { 958 pe_err("sta_ds is NULL"); 959 status = QDF_STATUS_E_FAILURE; 960 lim_mlo_release_vdev_ref(lk_session->vdev); 961 break; 962 } 963 lim_assoc_ind = qdf_mem_malloc(sizeof(tLimMlmAssocInd)); 964 if (!lim_assoc_ind) { 965 pe_err("lim assoc ind allocate error"); 966 qdf_mem_free(lk_session->parsedAssocReq[sta->assocId]); 967 lk_session->parsedAssocReq[sta->assocId] = NULL; 968 status = QDF_STATUS_E_FAILURE; 969 lim_mlo_release_vdev_ref(lk_session->vdev); 970 break; 971 } 972 973 if (!lim_fill_lim_assoc_ind_params(lim_assoc_ind, mac, 974 sta, lk_session)) { 975 pe_err("lim assoc ind fill error"); 976 qdf_mem_free(lim_assoc_ind); 977 qdf_mem_free(lk_session->parsedAssocReq[sta->assocId]); 978 lk_session->parsedAssocReq[sta->assocId] = NULL; 979 status = QDF_STATUS_E_FAILURE; 980 lim_mlo_release_vdev_ref(lk_session->vdev); 981 break; 982 } 983 sme_assoc_ind = qdf_mem_malloc(sizeof(struct assoc_ind)); 984 if (!sme_assoc_ind) { 985 pe_err("sme assoc ind allocate error"); 986 qdf_mem_free(lim_assoc_ind); 987 qdf_mem_free(lk_session->parsedAssocReq[sta->assocId]); 988 lk_session->parsedAssocReq[sta->assocId] = NULL; 989 status = QDF_STATUS_E_FAILURE; 990 lim_mlo_release_vdev_ref(lk_session->vdev); 991 break; 992 } 993 994 sme_assoc_ind->messageType = eWNI_SME_ASSOC_IND_UPPER_LAYER; 995 lim_fill_sme_assoc_ind_params(mac, lim_assoc_ind, sme_assoc_ind, 996 lk_session, true); 997 998 qdf_mem_zero(&msg, sizeof(struct scheduler_msg)); 999 msg.type = eWNI_SME_ASSOC_IND_UPPER_LAYER; 1000 msg.bodyptr = sme_assoc_ind; 1001 msg.bodyval = 0; 1002 sme_assoc_ind->reassocReq = sta->mlmStaContext.subType; 1003 sme_assoc_ind->timingMeasCap = sta->timingMeasCap; 1004 MTRACE(mac_trace_msg_tx(mac, lk_session->peSessionId, 1005 msg.type)); 1006 lim_sys_process_mmh_msg_api(mac, &msg); 1007 1008 qdf_mem_free(lim_assoc_ind); 1009 lim_free_assoc_req_frm_buf( 1010 lk_session->parsedAssocReq[sta->assocId]); 1011 qdf_mem_free(lk_session->parsedAssocReq[sta->assocId]); 1012 lk_session->parsedAssocReq[sta->assocId] = NULL; 1013 lim_mlo_release_vdev_ref(lk_session->vdev); 1014 } 1015 1016 return status; 1017 } 1018 #endif 1019 1020 void lim_mlo_save_mlo_info(tpDphHashNode sta_ds, 1021 struct mlo_partner_info *mlo_info) 1022 { 1023 if (!sta_ds) { 1024 pe_err("sta ds is null"); 1025 return; 1026 } 1027 1028 qdf_mem_copy(&sta_ds->mlo_info, mlo_info, sizeof(sta_ds->mlo_info)); 1029 } 1030 1031 QDF_STATUS lim_fill_complete_mlo_ie(struct pe_session *session, 1032 uint16_t total_len, uint8_t *target) 1033 { 1034 struct wlan_mlo_sta_profile *sta_prof; 1035 uint16_t mlo_ie_total_len; 1036 uint8_t *buf, *pbuf; 1037 uint16_t i; 1038 uint16_t consumed = 0; 1039 uint16_t index = 0; 1040 struct wlan_mlo_ie *mlo_ie; 1041 1042 if (!session) 1043 return QDF_STATUS_E_INVAL; 1044 1045 mlo_ie = &session->mlo_ie; 1046 if (total_len > WLAN_MAX_IE_LEN + MIN_IE_LEN) 1047 mlo_ie->data[TAG_LEN_POS] = WLAN_MAX_IE_LEN; 1048 else 1049 mlo_ie->data[TAG_LEN_POS] = total_len - MIN_IE_LEN; 1050 1051 buf = qdf_mem_malloc(total_len); 1052 if (!buf) 1053 return QDF_STATUS_E_NOMEM; 1054 1055 pbuf = buf; 1056 qdf_mem_copy(pbuf, mlo_ie->data, mlo_ie->num_data); 1057 pbuf += mlo_ie->num_data; 1058 1059 for (i = 0; i < mlo_ie->num_sta_profile; i++) { 1060 sta_prof = &mlo_ie->sta_profile[i]; 1061 qdf_mem_copy(pbuf, sta_prof->data, sta_prof->num_data); 1062 pbuf += sta_prof->num_data; 1063 } 1064 1065 target[consumed++] = buf[index++]; 1066 target[consumed++] = buf[index++]; 1067 mlo_ie_total_len = pbuf - buf - MIN_IE_LEN; 1068 if (mlo_ie_total_len > total_len - MIN_IE_LEN) { 1069 pe_err("Invalid len: %u, %u", mlo_ie_total_len, total_len); 1070 qdf_mem_free(buf); 1071 return QDF_STATUS_E_INVAL; 1072 } 1073 1074 for (i = 0; i < mlo_ie_total_len; i++) { 1075 if (i && (i % WLAN_MAX_IE_LEN) == 0) { 1076 /* add fragmentation IE and length */ 1077 target[consumed++] = WLAN_ELEMID_FRAGMENT; 1078 if ((mlo_ie_total_len - i) > WLAN_MAX_IE_LEN) 1079 target[consumed++] = WLAN_MAX_IE_LEN; 1080 else 1081 target[consumed++] = mlo_ie_total_len - i; 1082 } 1083 target[consumed++] = buf[index++]; 1084 } 1085 qdf_mem_free(buf); 1086 pe_debug("pack mlo ie %d bytes, expected to copy %d bytes", 1087 consumed, total_len); 1088 qdf_trace_hex_dump(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, 1089 target, consumed); 1090 1091 return QDF_STATUS_SUCCESS; 1092 } 1093 1094 uint16_t lim_caculate_mlo_ie_length(struct wlan_mlo_ie *mlo_ie) 1095 { 1096 struct wlan_mlo_sta_profile *sta_prof; 1097 uint16_t total_len; 1098 uint16_t i, tmp; 1099 1100 total_len = mlo_ie->num_data; 1101 for (i = 0; i < mlo_ie->num_sta_profile; i++) { 1102 sta_prof = &mlo_ie->sta_profile[i]; 1103 total_len += sta_prof->num_data; 1104 } 1105 1106 if (total_len > WLAN_MAX_IE_LEN + MIN_IE_LEN) { 1107 /* ML IE max length WLAN_MAX_IE_LEN + MIN_IE_LEN */ 1108 tmp = total_len - (WLAN_MAX_IE_LEN + MIN_IE_LEN); 1109 while (tmp > WLAN_MAX_IE_LEN) { 1110 /* add one flagmentation IE */ 1111 total_len += MIN_IE_LEN; 1112 tmp -= WLAN_MAX_IE_LEN; 1113 } 1114 /* add one flagmentation IE */ 1115 total_len += MIN_IE_LEN; 1116 } 1117 return total_len; 1118 } 1119 1120 QDF_STATUS lim_store_mlo_ie_raw_info(uint8_t *ie, uint8_t *sta_prof_ie, 1121 uint32_t total_len, 1122 struct wlan_mlo_ie *mlo_ie) 1123 { 1124 uint32_t i, frag_num = 0, sta_index; 1125 /* ml_ie_len = total_len - 2 * frag_num, does not include 1126 * WLAN_ELEMID_FRAGMENT IE and LEN 1127 */ 1128 uint32_t ml_ie_len; 1129 uint32_t index, copied; 1130 uint8_t *pfrm; 1131 uint8_t *buf; 1132 struct wlan_mlo_sta_profile *sta_prof; 1133 uint8_t *sta_data; 1134 /* Per STA profile frag or not */ 1135 bool frag = FALSE; 1136 1137 if (!ie) 1138 return QDF_STATUS_E_INVAL; 1139 1140 qdf_mem_zero(mlo_ie, sizeof(*mlo_ie)); 1141 1142 /* assume element ID + LEN + extension element ID + multi-link control + 1143 * common info length always less than WLAN_MAX_IE_LEN 1144 */ 1145 mlo_ie->num_data = sta_prof_ie - ie; 1146 if (mlo_ie->num_data > WLAN_MLO_IE_COM_MAX_LEN) { 1147 mlo_ie->num_data = 0; 1148 return QDF_STATUS_E_INVAL; 1149 } 1150 qdf_mem_copy(mlo_ie->data, ie, mlo_ie->num_data); 1151 1152 /* Count how many frag IE */ 1153 pfrm = ie; 1154 ml_ie_len = pfrm[TAG_LEN_POS] + MIN_IE_LEN; 1155 while (ml_ie_len < total_len) { 1156 frag_num++; 1157 pfrm += MIN_IE_LEN + pfrm[TAG_LEN_POS]; 1158 ml_ie_len += pfrm[TAG_LEN_POS] + MIN_IE_LEN; 1159 } 1160 ml_ie_len = total_len - frag_num * MIN_IE_LEN; 1161 1162 pe_debug_rl("ml_ie_len: %d, total_len: %d, frag_num: %d", ml_ie_len, 1163 total_len, frag_num); 1164 1165 buf = qdf_mem_malloc(total_len); 1166 if (!buf) 1167 return QDF_STATUS_E_NOMEM; 1168 1169 /* Copy the raw info and skip frag IE */ 1170 index = 0; 1171 copied = 0; 1172 buf[index++] = ie[copied++]; 1173 buf[index++] = ie[copied++]; 1174 for (i = 0; i < ml_ie_len - MIN_IE_LEN; i++) { 1175 /* skip the frag IE */ 1176 if (i && (i % WLAN_MAX_IE_LEN) == 0) 1177 copied += MIN_IE_LEN; 1178 buf[index++] = ie[copied++]; 1179 } 1180 1181 /* copy sta profile from buf, it has copied the common info */ 1182 sta_index = 0; 1183 copied = mlo_ie->num_data; 1184 pfrm = buf + copied; 1185 while (copied < ml_ie_len && sta_index < WLAN_MLO_MAX_VDEVS && 1186 pfrm[ID_POS] == WLAN_ML_LINFO_SUBELEMID_PERSTAPROFILE) { 1187 sta_prof = &mlo_ie->sta_profile[sta_index]; 1188 sta_data = sta_prof->data; 1189 index = 0; 1190 1191 sta_data[index++] = buf[copied++]; 1192 sta_data[index++] = buf[copied++]; 1193 do { 1194 if (index + pfrm[TAG_LEN_POS] > 1195 WLAN_STA_PROFILE_MAX_LEN) { 1196 qdf_mem_free(buf); 1197 pe_debug("no enough buf to store sta prof"); 1198 return QDF_STATUS_E_INVAL; 1199 } 1200 1201 for (i = 0; i < pfrm[TAG_LEN_POS]; i++) 1202 sta_data[index++] = buf[copied++]; 1203 sta_prof->num_data = index; 1204 1205 if (copied < ml_ie_len && 1206 pfrm[TAG_LEN_POS] == WLAN_MAX_IE_LEN && 1207 pfrm[WLAN_MAX_IE_LEN + MIN_IE_LEN] == 1208 WLAN_ML_LINFO_SUBELEMID_FRAGMENT) { 1209 frag = TRUE; 1210 /* skip sta profile frag IE */ 1211 copied += MIN_IE_LEN; 1212 } else { 1213 frag = FALSE; 1214 } 1215 pfrm += pfrm[TAG_LEN_POS] + MIN_IE_LEN; 1216 } while (frag); 1217 pe_debug_rl("sta index: %d, sta_data len: %d, copied: %d", 1218 sta_index, index, copied); 1219 sta_index++; 1220 } 1221 1222 mlo_ie->num_sta_profile = sta_index; 1223 qdf_mem_free(buf); 1224 return QDF_STATUS_SUCCESS; 1225 } 1226 1227 QDF_STATUS lim_add_frag_ie_for_sta_profile(uint8_t *data, uint16_t *len) 1228 { 1229 uint16_t total_len; 1230 uint16_t tmp, i; 1231 uint8_t *buf; 1232 uint16_t consumed = 0; 1233 uint16_t index = 0; 1234 1235 total_len = *len; 1236 buf = qdf_mem_malloc(total_len); 1237 if (!buf) 1238 return QDF_STATUS_E_NOMEM; 1239 1240 qdf_mem_copy(buf, data, total_len); 1241 1242 if (total_len > WLAN_MAX_IE_LEN + MIN_IE_LEN) { 1243 /* ML IE max length WLAN_MAX_IE_LEN + MIN_IE_LEN */ 1244 tmp = total_len - (WLAN_MAX_IE_LEN + MIN_IE_LEN); 1245 while (tmp > WLAN_MAX_IE_LEN) { 1246 /* add one flagmentation IE */ 1247 total_len += MIN_IE_LEN; 1248 tmp -= WLAN_MAX_IE_LEN; 1249 } 1250 /* add one flagmentation IE */ 1251 total_len += MIN_IE_LEN; 1252 } 1253 1254 data[consumed++] = buf[index++]; 1255 data[consumed++] = buf[index++]; 1256 for (i = 0; i < (*len - MIN_IE_LEN); i++) { 1257 data[consumed++] = buf[index++]; 1258 if (i && (i % WLAN_MAX_IE_LEN) == 0) { 1259 data[consumed++] = WLAN_ML_LINFO_SUBELEMID_FRAGMENT; 1260 if ((*len - MIN_IE_LEN - i) > WLAN_MAX_IE_LEN) 1261 data[consumed++] = WLAN_MAX_IE_LEN; 1262 else 1263 data[consumed++] = *len - MIN_IE_LEN - i; 1264 } 1265 } 1266 1267 *len = total_len; 1268 qdf_mem_free(buf); 1269 1270 return QDF_STATUS_SUCCESS; 1271 } 1272 1273 uint16_t 1274 lim_fill_assoc_req_mlo_ie(struct mac_context *mac_ctx, 1275 struct pe_session *session, 1276 tDot11fAssocRequest *frm) 1277 { 1278 QDF_STATUS status; 1279 1280 session->mlo_ie_total_len = 0; 1281 qdf_mem_zero(&session->mlo_ie, sizeof(session->mlo_ie)); 1282 if ((wlan_vdev_mlme_get_opmode(session->vdev) == QDF_STA_MODE) && 1283 wlan_vdev_mlme_is_mlo_vdev(session->vdev)) { 1284 status = 1285 populate_dot11f_assoc_req_mlo_ie(mac_ctx, session, frm); 1286 if (QDF_IS_STATUS_SUCCESS(status)) 1287 session->mlo_ie_total_len = 1288 lim_caculate_mlo_ie_length(&session->mlo_ie); 1289 } 1290 1291 return session->mlo_ie_total_len; 1292 } 1293 1294 uint16_t 1295 lim_send_assoc_rsp_mgmt_frame_mlo(struct mac_context *mac_ctx, 1296 struct pe_session *session, 1297 tpDphHashNode sta, 1298 tDot11fAssocResponse *frm) 1299 { 1300 QDF_STATUS status; 1301 1302 session->mlo_ie_total_len = 0; 1303 qdf_mem_zero(&session->mlo_ie, sizeof(session->mlo_ie)); 1304 status = populate_dot11f_assoc_rsp_mlo_ie(mac_ctx, session, sta, frm); 1305 if (QDF_IS_STATUS_SUCCESS(status)) 1306 session->mlo_ie_total_len = 1307 lim_caculate_mlo_ie_length(&session->mlo_ie); 1308 1309 return session->mlo_ie_total_len; 1310 } 1311 1312 uint16_t 1313 lim_send_bcn_frame_mlo(struct mac_context *mac_ctx, 1314 struct pe_session *session) 1315 { 1316 QDF_STATUS status; 1317 1318 session->mlo_ie_total_len = 0; 1319 qdf_mem_zero(&session->mlo_ie, sizeof(session->mlo_ie)); 1320 status = populate_dot11f_bcn_mlo_ie(mac_ctx, session); 1321 if (QDF_IS_STATUS_SUCCESS(status)) 1322 session->mlo_ie_total_len = 1323 lim_caculate_mlo_ie_length(&session->mlo_ie); 1324 1325 return session->mlo_ie_total_len; 1326 } 1327 1328 uint16_t 1329 lim_send_probe_req_frame_mlo(struct mac_context *mac_ctx, 1330 struct pe_session *session) 1331 { 1332 QDF_STATUS status; 1333 1334 session->mlo_ie_total_len = 0; 1335 qdf_mem_zero(&session->mlo_ie, sizeof(session->mlo_ie)); 1336 status = populate_dot11f_probe_req_mlo_ie(mac_ctx, session); 1337 if (QDF_IS_STATUS_SUCCESS(status)) 1338 session->mlo_ie_total_len = 1339 lim_caculate_mlo_ie_length(&session->mlo_ie); 1340 1341 return session->mlo_ie_total_len; 1342 } 1343 1344 uint16_t 1345 lim_send_tdls_mgmt_frame_mlo(struct mac_context *mac_ctx, 1346 struct pe_session *session) 1347 { 1348 QDF_STATUS status; 1349 1350 session->mlo_ie_total_len = 0; 1351 qdf_mem_zero(&session->mlo_ie, sizeof(session->mlo_ie)); 1352 status = populate_dot11f_tdls_mgmt_mlo_ie(mac_ctx, session); 1353 if (QDF_IS_STATUS_SUCCESS(status)) 1354 session->mlo_ie_total_len = 1355 lim_caculate_mlo_ie_length(&session->mlo_ie); 1356 1357 return session->mlo_ie_total_len; 1358 } 1359 1360 uint16_t 1361 lim_get_frame_mlo_ie_len(struct pe_session *session) 1362 { 1363 if (session) 1364 return session->mlo_ie_total_len; 1365 else 1366 return 0; 1367 } 1368 1369 bool 1370 lim_is_ml_peer_state_disconn(struct mac_context *mac_ctx, 1371 struct pe_session *session, 1372 uint8_t *mac_addr) 1373 { 1374 struct wlan_objmgr_peer *peer; 1375 struct wlan_mlo_peer_context *ml_peer = NULL; 1376 bool is_ml_peer_disconn = false; 1377 1378 peer = wlan_objmgr_get_peer_by_mac(mac_ctx->psoc, mac_addr, 1379 WLAN_LEGACY_MAC_ID); 1380 1381 if (!peer) { 1382 pe_err("peer is NULL"); 1383 return is_ml_peer_disconn; 1384 } 1385 1386 if ((session->opmode == QDF_STA_MODE) && 1387 wlan_vdev_mlme_is_mlo_vdev(session->vdev)) 1388 ml_peer = peer->mlo_peer_ctx; 1389 1390 if (!ml_peer) { 1391 pe_err("ML peer ctx not found"); 1392 goto end; 1393 } 1394 1395 if (QDF_IS_STATUS_SUCCESS(wlan_mlo_peer_is_disconnect_progress(ml_peer))) 1396 is_ml_peer_disconn = true; 1397 1398 end: 1399 wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID); 1400 return is_ml_peer_disconn; 1401 } 1402 1403 bool lim_is_emlsr_band_supported(struct pe_session *session) 1404 { 1405 uint8_t i; 1406 uint32_t freq; 1407 struct mlo_partner_info *partner_info; 1408 1409 if (!session->lim_join_req) { 1410 /* Initial connection */ 1411 partner_info = &session->ml_partner_info; 1412 } else { 1413 /* Roaming */ 1414 partner_info = &session->lim_join_req->partner_info; 1415 } 1416 1417 if (wlan_reg_is_24ghz_ch_freq(session->curr_op_freq)) 1418 return false; 1419 1420 for (i = 0; i < partner_info->num_partner_links; i++) { 1421 freq = partner_info->partner_link_info[i].chan_freq; 1422 if (wlan_reg_is_24ghz_ch_freq(freq)) 1423 return false; 1424 } 1425 1426 return true; 1427 } 1428