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
lim_cu_info_from_rnr_per_link_id(const uint8_t * rnr,uint8_t linkid,uint8_t * bpcc,uint8_t * aui)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
lim_get_bpcc_from_mlo_ie(tSchBeaconStruct * bcn,uint8_t * bpcc)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
lim_check_cu_happens(struct wlan_objmgr_vdev * vdev,uint8_t new_bpcc)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 */
lim_send_mlo_ie_update(struct mac_context * mac_ctx,struct pe_session * session)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
lim_partner_link_info_change(struct wlan_objmgr_vdev * vdev)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
lim_mlo_release_vdev_ref(struct wlan_objmgr_vdev * vdev)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
pe_find_partner_session_by_link_id(struct pe_session * session,uint8_t link_id)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
lim_get_mlo_vdev_list(struct pe_session * session,uint16_t * vdev_count,struct wlan_objmgr_vdev ** wlan_vdev_list)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 */
lim_mlo_get_assoc_link_session_sta_ds(struct pe_session * session,uint16_t partner_peer_idx,struct pe_session ** assoc_session,tpDphHashNode * assoc_sta)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 */
lim_mlo_update_cleanup_trigger(struct pe_session * session,tpDphHashNode sta_ds,uint16_t clnup_tri)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
lim_mlo_notify_peer_disconn(struct pe_session * pe_session,tpDphHashNode sta_ds)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
lim_mlo_sta_notify_peer_disconn(struct pe_session * pe_session)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
lim_mlo_roam_peer_disconn_del(struct wlan_objmgr_vdev * vdev)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
lim_mlo_cleanup_partner_peer(struct wlan_objmgr_peer * peer)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
lim_mlo_set_mld_mac_peer(tpDphHashNode sta_ds,uint8_t peer_mld_addr[QDF_MAC_ADDR_SIZE])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
lim_is_mlo_conn(struct pe_session * session,tpDphHashNode sta_ds)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
lim_set_mlo_recv_assoc(tpDphHashNode sta_ds,bool mlo_recv_assoc_frm)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
lim_is_mlo_recv_assoc(tpDphHashNode sta_ds)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
lim_mlo_proc_assoc_req_frm(struct wlan_objmgr_vdev * vdev,struct wlan_mlo_peer_context * ml_peer,struct qdf_mac_addr * link_addr,qdf_nbuf_t buf)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
lim_mlo_ap_sta_assoc_suc(struct wlan_objmgr_peer * peer)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
lim_ap_mlo_sta_peer_ind(struct mac_context * mac,struct pe_session * pe_session,tpDphHashNode sta,bool add_sta_rsp_status)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
lim_mlo_partner_auth_type(struct pe_session * session,uint16_t partner_peer_idx,tAniAuthType * auth_type)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
lim_mlo_ap_sta_assoc_fail(struct wlan_objmgr_peer * peer)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
lim_mlo_delete_link_peer(struct pe_session * pe_session,tpDphHashNode sta_ds)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)
lim_mlo_assoc_ind_upper_layer(struct mac_context * mac,struct pe_session * pe_session,struct mlo_partner_info * mlo_info)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
lim_mlo_assoc_ind_upper_layer(struct mac_context * mac,struct pe_session * pe_session,struct mlo_partner_info * mlo_info)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
lim_mlo_save_mlo_info(tpDphHashNode sta_ds,struct mlo_partner_info * mlo_info)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
lim_fill_complete_mlo_ie(struct pe_session * session,uint16_t total_len,uint8_t * target)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
lim_caculate_mlo_ie_length(struct wlan_mlo_ie * mlo_ie)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
lim_store_mlo_ie_raw_info(uint8_t * ie,uint8_t * sta_prof_ie,uint32_t total_len,struct wlan_mlo_ie * mlo_ie)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
lim_add_frag_ie_for_sta_profile(uint8_t * data,uint16_t * len)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
lim_fill_assoc_req_mlo_ie(struct mac_context * mac_ctx,struct pe_session * session,tDot11fAssocRequest * frm)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
lim_send_assoc_rsp_mgmt_frame_mlo(struct mac_context * mac_ctx,struct pe_session * session,tpDphHashNode sta,tDot11fAssocResponse * frm)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
lim_send_bcn_frame_mlo(struct mac_context * mac_ctx,struct pe_session * session)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
lim_send_probe_req_frame_mlo(struct mac_context * mac_ctx,struct pe_session * session)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
lim_send_tdls_mgmt_frame_mlo(struct mac_context * mac_ctx,struct pe_session * session)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
lim_get_frame_mlo_ie_len(struct pe_session * session)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
lim_is_ml_peer_state_disconn(struct mac_context * mac_ctx,struct pe_session * session,uint8_t * mac_addr)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
lim_is_emlsr_band_supported(struct pe_session * session)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