1 /*
2 * Copyright (c) 2011-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
6 * any purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all
8 * copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 /*
21 *
22 * This file sch_api.cc contains functions related to the API exposed
23 * by scheduler module
24 *
25 * Author: Sandesh Goel
26 * Date: 02/25/02
27 * History:-
28 * Date Modified by Modification Information
29 * --------------------------------------------------------------------
30 *
31 */
32 #include "cds_api.h"
33 #include "ani_global.h"
34 #include "wni_cfg.h"
35
36 #include "sir_mac_prot_def.h"
37 #include "sir_mac_prop_exts.h"
38 #include "sir_common.h"
39
40 #include "lim_api.h"
41
42 #include "sch_api.h"
43
44 #include "lim_trace.h"
45 #include "lim_types.h"
46 #include "lim_utils.h"
47
48 #include "wma_types.h"
49 #include "lim_mlo.h"
50
51 #include <target_if_vdev_mgr_tx_ops.h>
52 #include <wlan_cmn_ieee80211.h>
53 #include <wlan_mgmt_txrx_utils_api.h>
54 #include <wlan_p2p_cfg_api.h>
55
56 /* Fils Discovery Frame */
57 /**
58 * struct fd_action_header - FILS Discovery Action frame header
59 * @action_header: WLAN Action frame header
60 * @fd_frame_cntl: FILS Discovery Frame Control
61 * @timestamp: Time stamp
62 * @bcn_interval: Beacon Interval
63 * @elem: variable len sub element fields
64 */
65 struct fd_action_header {
66 struct action_frm_hdr action_header;
67 uint16_t fd_frame_cntl;
68 uint8_t timestamp[WLAN_TIMESTAMP_LEN];
69 uint16_t bcn_interval;
70 uint8_t elem[];
71 } qdf_packed;
72
73 /**
74 * struct tpe_ie - Transmit Power Enevolpe IE
75 * @tpe_header: WLAN IE Header
76 * @max_tx_pwr_count: Maximum Transmit Power Count
77 * @max_tx_pwr_interpret: Maximum Transmit Power Interpretation
78 * @max_tx_pwr_category: Maximum Transmit Power category
79 * @tx_pwr_info: Transmit power Information
80 * @elem: variable len sub element fields
81 */
82 struct tpe_ie {
83 struct ie_header tpe_header;
84 union {
85 struct {
86 uint8_t max_tx_pwr_count:3;
87 uint8_t max_tx_pwr_interpret:3;
88 uint8_t max_tx_pwr_category:2;
89 };
90 uint8_t tx_pwr_info;
91 };
92 uint8_t elem[];
93 } qdf_packed;
94
95 #ifdef WLAN_FEATURE_11BE_MLO
96 /**
97 * lim_notify_link_info() - notify partner link to update beacon template
98 * @pe_session: pointer to pe session
99 *
100 * Return: void
101 */
lim_notify_link_info(struct pe_session * pe_session)102 static void lim_notify_link_info(struct pe_session *pe_session)
103 {
104 struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS];
105 uint16_t vdev_count = 0;
106 int link;
107
108 if (!pe_session->mlo_link_info.upt_bcn_mlo_ie &&
109 !mlme_is_notify_co_located_ap_update_rnr(pe_session->vdev))
110 return;
111 pe_session->mlo_link_info.upt_bcn_mlo_ie = false;
112 mlme_set_notify_co_located_ap_update_rnr(pe_session->vdev, false);
113 pe_debug("vdev id %d mlo notify beacon change info to partner link",
114 wlan_vdev_get_id(pe_session->vdev));
115 lim_get_mlo_vdev_list(pe_session, &vdev_count,
116 wlan_vdev_list);
117 for (link = 0; link < vdev_count; link++) {
118 if (!wlan_vdev_list[link])
119 continue;
120 if (wlan_vdev_list[link] == pe_session->vdev) {
121 lim_mlo_release_vdev_ref(wlan_vdev_list[link]);
122 continue;
123 }
124 lim_partner_link_info_change(wlan_vdev_list[link]);
125 lim_mlo_release_vdev_ref(wlan_vdev_list[link]);
126 }
127 }
128
129 /**
130 * lim_update_sch_mlo_partner() - update partner information needed in mlo IE
131 * @mac: pointer to mac
132 * @pe_session: pointer to pe session
133 * @bcn_param: pointer to tpSendbeaconParams
134 *
135 * Return: void
136 */
lim_update_sch_mlo_partner(struct mac_context * mac,struct pe_session * pe_session,tpSendbeaconParams bcn_param)137 static void lim_update_sch_mlo_partner(struct mac_context *mac,
138 struct pe_session *pe_session,
139 tpSendbeaconParams bcn_param)
140 {
141 int link;
142 struct ml_sch_partner_info *sch_info;
143 struct ml_bcn_partner_info *bcn_info;
144
145 bcn_param->mlo_partner.num_links = mac->sch.sch_mlo_partner.num_links;
146 for (link = 0; link < mac->sch.sch_mlo_partner.num_links; link++) {
147 sch_info = &mac->sch.sch_mlo_partner.partner_info[link];
148 bcn_info = &bcn_param->mlo_partner.partner_info[link];
149 bcn_info->vdev_id = sch_info->vdev_id;
150 bcn_info->beacon_interval = sch_info->beacon_interval;
151 bcn_info->csa_switch_count_offset = sch_info->bcn_csa_cnt_ofst;
152 bcn_info->ext_csa_switch_count_offset =
153 sch_info->bcn_ext_csa_cnt_ofst;
154 }
155 }
156 #else
lim_notify_link_info(struct pe_session * pe_session)157 static void lim_notify_link_info(struct pe_session *pe_session)
158 {
159 }
160
lim_update_sch_mlo_partner(struct mac_context * mac,struct pe_session * pe_session,tpSendbeaconParams bcn_param)161 static void lim_update_sch_mlo_partner(struct mac_context *mac,
162 struct pe_session *pe_session,
163 tpSendbeaconParams bcn_param)
164 {
165 }
166 #endif
167
168 #ifdef WLAN_FEATURE_11BE
169 /**
170 * lim_fd_cap_channel_width320() - populate the capability field for
171 * 320 channel width in the fils discovery template
172 * @pe_session: pointer to pe session
173 * @fd_cap: pointer to fils discovery capability variable
174 *
175 * Return: void
176 */
lim_fd_cap_channel_width320(struct pe_session * pe_session,uint8_t * fd_cap)177 static void lim_fd_cap_channel_width320(struct pe_session *pe_session,
178 uint8_t *fd_cap)
179 {
180 if (pe_session->ch_width == CH_WIDTH_320MHZ) {
181 *fd_cap |= (WLAN_FD_CHWIDTH_320 << WLAN_FD_CAP_BSS_CHWIDTH_S);
182 } else {
183 pe_err("channel width : %d is not supported",
184 pe_session->ch_width);
185 }
186 }
187
188 /**
189 * lim_populate_fd_capability() - populate the capability field for
190 * EHT phymode in the fils discovery template
191 * @cur_phymode: current phymode
192 * @fd_cap: pointer to fils discovery capability variable
193 *
194 * Return: void
195 */
lim_fd_cap_phymode_EHT(enum wlan_phymode phymode,uint8_t * fd_cap)196 static void lim_fd_cap_phymode_EHT(enum wlan_phymode phymode, uint8_t *fd_cap)
197 {
198 switch (phymode) {
199 case WLAN_PHYMODE_11BEA_EHT20:
200 case WLAN_PHYMODE_11BEG_EHT20:
201 case WLAN_PHYMODE_11BEA_EHT40:
202 case WLAN_PHYMODE_11BEG_EHT40:
203 case WLAN_PHYMODE_11BEG_EHT40PLUS:
204 case WLAN_PHYMODE_11BEG_EHT40MINUS:
205 case WLAN_PHYMODE_11BEA_EHT80:
206 case WLAN_PHYMODE_11BEA_EHT160:
207 case WLAN_PHYMODE_11BEA_EHT320:
208 *fd_cap |= (WLAN_FD_CAP_PHY_INDEX_EHT <<
209 WLAN_FD_CAP_PHY_INDEX_S);
210 break;
211 default:
212 *fd_cap |= (WLAN_FD_CAP_PHY_INDEX_NON_HT_OFDM <<
213 WLAN_FD_CAP_PHY_INDEX_S);
214 break;
215 }
216 }
217 #else
lim_fd_cap_channel_width320(struct pe_session * pe_session,uint8_t * fd_cap)218 static void lim_fd_cap_channel_width320(struct pe_session *pe_session,
219 uint8_t *fd_cap)
220 {
221 pe_err("channel width : %d is not supported", pe_session->ch_width);
222 }
223
lim_fd_cap_phymode_EHT(enum wlan_phymode phymode,uint8_t * fd_cap)224 static void lim_fd_cap_phymode_EHT(enum wlan_phymode phymode, uint8_t *fd_cap)
225 {
226 *fd_cap |= (WLAN_FD_CAP_PHY_INDEX_NON_HT_OFDM <<
227 WLAN_FD_CAP_PHY_INDEX_S);
228 }
229 #endif /* WLAN_FEATURE_11BE */
230
231 /**
232 * lim_populate_fd_capability() - populate the capability field in the
233 * fils discovery template
234 * @pe_session: pointer to pe session
235 * @cur_phymode: current phymode
236 * @fd_cap: pointer to fils discovery capability array
237 *
238 * Return: void
239 */
lim_populate_fd_capability(struct pe_session * pe_session,enum wlan_phymode cur_phymode,uint8_t * fd_cap)240 static void lim_populate_fd_capability(struct pe_session *pe_session,
241 enum wlan_phymode cur_phymode,
242 uint8_t *fd_cap)
243 {
244 /* Setting ESS and Privacy bits */
245 fd_cap[0] |= ((!WLAN_FD_CAP_ESS_ENABLE << WLAN_FD_CAP_ESS_S) |
246 ((pe_session->privacy) << WLAN_FD_CAP_PRIVACY_S));
247
248 /* Channel Width Selection */
249 switch (pe_session->ch_width) {
250 case CH_WIDTH_20MHZ:
251 fd_cap[0] |= (WLAN_FD_CHWIDTH_20 << WLAN_FD_CAP_BSS_CHWIDTH_S);
252 break;
253 case CH_WIDTH_40MHZ:
254 fd_cap[0] |= (WLAN_FD_CHWIDTH_40 << WLAN_FD_CAP_BSS_CHWIDTH_S);
255 break;
256 case CH_WIDTH_80MHZ:
257 fd_cap[0] |= (WLAN_FD_CHWIDTH_80 << WLAN_FD_CAP_BSS_CHWIDTH_S);
258 break;
259 case CH_WIDTH_160MHZ:
260 case CH_WIDTH_80P80MHZ:
261 fd_cap[0] |= (WLAN_FD_CHWIDTH_160_80_80 <<
262 WLAN_FD_CAP_BSS_CHWIDTH_S);
263 break;
264 default:
265 lim_fd_cap_channel_width320(pe_session, &fd_cap[0]);
266 break;
267 }
268
269 /* Max Num of Spatial Steam */
270 switch (pe_session->nss) {
271 case WLAN_FD_CAP_NSS_MODE_1:
272 case WLAN_FD_CAP_NSS_MODE_2:
273 fd_cap[0] |= ((pe_session->nss - 1) << WLAN_FD_CAP_NSS_S);
274 break;
275 case WLAN_FD_CAP_NSS_MODE_3:
276 case WLAN_FD_CAP_NSS_MODE_4:
277 case WLAN_FD_CAP_NSS_MODE_5:
278 case WLAN_FD_CAP_NSS_MODE_6:
279 case WLAN_FD_CAP_NSS_MODE_7:
280 case WLAN_FD_CAP_NSS_MODE_8:
281 fd_cap[0] |= (WLAN_FD_CAP_NSS_GTE_5 << WLAN_FD_CAP_NSS_S);
282 break;
283 default:
284 pe_err("NSS value: %d is not supported", pe_session->nss);
285 break;
286 }
287
288 /* Set PHY index */
289 switch (cur_phymode) {
290 case WLAN_PHYMODE_11AXA_HE20:
291 case WLAN_PHYMODE_11AXG_HE20:
292 case WLAN_PHYMODE_11AXA_HE40:
293 case WLAN_PHYMODE_11AXG_HE40:
294 case WLAN_PHYMODE_11AXG_HE40PLUS:
295 case WLAN_PHYMODE_11AXG_HE40MINUS:
296 case WLAN_PHYMODE_11AXA_HE80:
297 case WLAN_PHYMODE_11AXA_HE160:
298 case WLAN_PHYMODE_11AXA_HE80_80:
299 fd_cap[1] |= (WLAN_FD_CAP_PHY_INDEX_HE <<
300 WLAN_FD_CAP_PHY_INDEX_S);
301 break;
302 case WLAN_PHYMODE_11AC_VHT20:
303 case WLAN_PHYMODE_11AC_VHT40:
304 case WLAN_PHYMODE_11AC_VHT80:
305 case WLAN_PHYMODE_11AC_VHT160:
306 case WLAN_PHYMODE_11AC_VHT80_80:
307 fd_cap[1] |= (WLAN_FD_CAP_PHY_INDEX_VHT <<
308 WLAN_FD_CAP_PHY_INDEX_S);
309 break;
310 case WLAN_PHYMODE_11NA_HT20:
311 case WLAN_PHYMODE_11NG_HT20:
312 case WLAN_PHYMODE_11NG_HT40PLUS:
313 case WLAN_PHYMODE_11NG_HT40MINUS:
314 case WLAN_PHYMODE_11NG_HT40:
315 case WLAN_PHYMODE_11NA_HT40:
316 fd_cap[1] |= (WLAN_FD_CAP_PHY_INDEX_HT <<
317 WLAN_FD_CAP_PHY_INDEX_S);
318 break;
319 default:
320 lim_fd_cap_phymode_EHT(cur_phymode, &fd_cap[1]);
321 break;
322 }
323
324 /* FILS Min Rate */
325 fd_cap[1] |= (WLAN_FD_CAP_MIN_RATE << WLAN_FD_CAP_MIN_RATE_S);
326 }
327
328 /**
329 * lim_populate_fd_tmpl_frame() - populate the fils discovery frame
330 * @mac: pointer to mac structure
331 * @frm: pointer to fils discovery frame
332 * @pe_session:pointer to pe session
333 * @frame_size: pointer to fils discovery frame size
334 *
335 * return: success: QDF_STATUS_SUCCESS failure: QDF_STATUS_E_FAILURE
336 */
lim_populate_fd_tmpl_frame(struct mac_context * mac,struct pe_session * pe_session,uint8_t * frm,uint32_t * frame_size)337 static QDF_STATUS lim_populate_fd_tmpl_frame(struct mac_context *mac,
338 struct pe_session *pe_session,
339 uint8_t *frm, uint32_t *frame_size)
340 {
341 uint16_t fd_cntl_subfield = 0;
342 struct fd_action_header *fd_header;
343 struct wlan_objmgr_vdev *vdev;
344 uint8_t fd_cap[WLAN_FD_CAP_LEN] = {0};
345 uint8_t length = 0;
346 uint8_t ssid_len = 0, ssid[WLAN_SSID_MAX_LEN + 1] = {0};
347 uint32_t shortssid;
348 uint16_t chwidth = pe_session->ch_width;
349 qdf_freq_t cur_chan_freq = pe_session->curr_op_freq;
350 struct wlan_channel *des_chan;
351 enum wlan_phymode cur_phymode;
352 uint16_t tpe_num = 0;
353 tDot11fIEtransmit_power_env tpe[WLAN_MAX_NUM_TPE_IE];
354 struct tpe_ie *tpe_ie;
355 uint8_t i, idx;
356 tSirMacMgmtHdr *mac_hdr;
357 struct qdf_mac_addr broadcast_mac_addr = QDF_MAC_ADDR_BCAST_INIT;
358
359 pe_debug("FD TMPL freq: %d chWidth: %d", cur_chan_freq, chwidth);
360
361 vdev = pe_session->vdev;
362 if (!vdev) {
363 pe_err("VDEV is NULL");
364 return QDF_STATUS_E_FAILURE;
365 }
366
367 des_chan = wlan_vdev_mlme_get_des_chan(vdev);
368 if (!des_chan) {
369 pe_err("des_chan is NULL");
370 return QDF_STATUS_E_FAILURE;
371 }
372
373 cur_phymode = des_chan->ch_phymode;
374
375 lim_populate_mac_header(mac, frm, SIR_MAC_MGMT_FRAME,
376 SIR_MAC_MGMT_ACTION, broadcast_mac_addr.bytes,
377 pe_session->self_mac_addr);
378 mac_hdr = (tpSirMacMgmtHdr)frm;
379 sir_copy_mac_addr(mac_hdr->bssId, pe_session->bssId);
380 frm += sizeof(*mac_hdr);
381 *frame_size = sizeof(*mac_hdr);
382
383 /* filling fd header */
384 fd_header = (struct fd_action_header *)frm;
385 fd_header->action_header.action_category = ACTION_CATEGORY_PUBLIC;
386 fd_header->action_header.action_code = WLAN_ACTION_FILS_DISCOVERY;
387
388 /*
389 * FILS DIscovery Frame Control Subfield - 2 byte
390 * Enable Short SSID
391 * When the Short SSID Indicator subfield is equal to 1,
392 * the SSID Length subfield is equal to 3
393 */
394 fd_cntl_subfield = WLAN_FD_SSID_LEN_PRES(WLAN_FD_FRAMECNTL_SHORTSSID_LEN);
395 fd_cntl_subfield |= WLAN_FD_FRAMECNTL_SHORTSSID;
396
397 if (wlan_reg_is_6ghz_chan_freq(cur_chan_freq)) {
398 fd_cntl_subfield |= WLAN_FD_FRAMECNTL_CAP;
399 length = WLAN_FD_CAP_LEN;
400 }
401
402 /* For 80+80 set Channel center freq segment 1 */
403 if (IS_WLAN_PHYMODE_160MHZ(cur_phymode)) {
404 fd_cntl_subfield |= WLAN_FD_FRAMECNTL_CH_CENTERFREQ;
405 length += 1;
406 }
407
408 /* Update the length field */
409 /*Indicates length from FD cap to Mobility Domain */
410 if (length)
411 fd_cntl_subfield |= WLAN_FD_FRAMECNTL_LEN_PRES;
412
413 /* FD Control - 2 bytes */
414 fd_header->fd_frame_cntl = qdf_cpu_to_le16(fd_cntl_subfield);
415
416 /* Timestamp - 8 bytes */
417 qdf_mem_zero(fd_header->timestamp, sizeof(fd_header->timestamp));
418
419 /* Beacon Interval - 2 bytes */
420 fd_header->bcn_interval =
421 qdf_cpu_to_le16(pe_session->beaconParams.beaconInterval);
422
423 *frame_size += sizeof(*fd_header);
424
425 /* Variable length data */
426 frm = &fd_header->elem[0];
427
428 /* Short SSID - 4 bytes */
429 wlan_vdev_mlme_get_ssid(vdev, ssid, &ssid_len);
430 shortssid = wlan_construct_shortssid(ssid, ssid_len);
431 *(uint32_t *)frm = qdf_cpu_to_le32(shortssid);
432 frm += 4;
433 *frame_size += 4;
434
435 /* Length - 1 byte */
436 if (length) {
437 *frm = length;
438 pe_debug("length: %d", length);
439 frm++;
440 *frame_size += length + 1;
441 }
442
443 /* FD Capabilities - 2 bytes */
444 if (WLAN_FD_IS_CAP_PRESENT(fd_cntl_subfield)) {
445 lim_populate_fd_capability(pe_session, cur_phymode, &fd_cap[0]);
446 qdf_mem_copy(frm, fd_cap, WLAN_FD_CAP_LEN);
447 frm += WLAN_FD_CAP_LEN;
448 }
449
450 /* Channel Center Freq Segment 1 - 1 byte */
451 if (WLAN_FD_IS_FRAMECNTL_CH_CENTERFREQ(fd_cntl_subfield)) {
452 /* spec has seg0 and seg1 naming while we use seg1 and seg2 */
453 *frm = des_chan->ch_freq_seg1;
454 frm++;
455 }
456
457 /* Add TPE IE */
458 if ((wlan_reg_is_6ghz_chan_freq(cur_chan_freq)) ||
459 (pe_session->vhtCapability)) {
460 populate_dot11f_tx_power_env(mac, &tpe[0], chwidth,
461 cur_chan_freq, &tpe_num, false);
462 if (tpe_num > WLAN_MAX_NUM_TPE_IE) {
463 pe_err("tpe_num %d greater than max size", tpe_num);
464 return QDF_STATUS_E_FAILURE;
465 }
466
467 for (idx = 0; idx < tpe_num; idx++) {
468 /* filling tpe_header header */
469 tpe_ie = (struct tpe_ie *)frm;
470 tpe_ie->tpe_header.ie_id = WLAN_ELEMID_VHT_TX_PWR_ENVLP;
471
472 if (tpe[idx].num_tx_power > WLAN_MAX_NUM_TPE_IE) {
473 pe_err("num_tx_power %d greater than max num",
474 tpe[idx].num_tx_power);
475 return QDF_STATUS_E_FAILURE;
476 }
477
478 /* +1 for including tx power info */
479 tpe_ie->tpe_header.ie_len = tpe[idx].num_tx_power + 1;
480
481 if (tpe_ie->tpe_header.ie_len < WLAN_TPE_IE_MIN_LEN ||
482 tpe_ie->tpe_header.ie_len > WLAN_TPE_IE_MAX_LEN) {
483 pe_err("tpe length %d less than min len or greater than max len",
484 tpe_ie->tpe_header.ie_len);
485 return QDF_STATUS_E_FAILURE;
486 }
487
488 tpe_ie->max_tx_pwr_count = tpe[idx].max_tx_pwr_count;
489 tpe_ie->max_tx_pwr_interpret =
490 tpe[idx].max_tx_pwr_interpret;
491 tpe_ie->max_tx_pwr_category =
492 tpe[idx].max_tx_pwr_category;
493 frm = &tpe_ie->elem[0];
494
495 for (i = 0; i < tpe[idx].num_tx_power; i++) {
496 *frm = tpe[idx].tx_power[i];
497 frm++;
498 }
499
500 /* +2 for including element id and length */
501 *frame_size += tpe_ie->tpe_header.ie_len + 2;
502 }
503 }
504
505 return QDF_STATUS_SUCCESS;
506 }
507
508 /**
509 * lim_send_fils_discovery_template() - send fils discovery template to
510 * target_if
511 * @mac: pointer to mac structure
512 * @pe_session:pe session
513 *
514 * return: status
515 */
lim_send_fils_discovery_template(struct mac_context * mac,struct pe_session * pe_session)516 static QDF_STATUS lim_send_fils_discovery_template(struct mac_context *mac,
517 struct pe_session *pe_session)
518 {
519 struct fils_discovery_tmpl_params *fd_params;
520 QDF_STATUS status = QDF_STATUS_E_FAILURE;
521 uint32_t n_bytes = sizeof(*fd_params);
522
523 fd_params = qdf_mem_malloc(n_bytes);
524
525 if (!fd_params)
526 return QDF_STATUS_E_NOMEM;
527
528 fd_params->vdev_id = pe_session->vdev_id;
529
530 fd_params->frm = qdf_mem_malloc(SIR_MAX_FD_TMPL_SIZE);
531 if (!(fd_params->frm)) {
532 qdf_mem_free(fd_params);
533 return QDF_STATUS_E_NOMEM;
534 }
535
536 status = lim_populate_fd_tmpl_frame(mac, pe_session, fd_params->frm,
537 &n_bytes);
538
539 if (QDF_IS_STATUS_ERROR(status)) {
540 pe_err("FAIL bytes %d retcode[%X]", n_bytes, status);
541 goto memfree;
542 }
543
544 fd_params->tmpl_len = n_bytes;
545 fd_params->tmpl_len_aligned = roundup(fd_params->tmpl_len,
546 sizeof(uint32_t));
547
548 /* Sending data to wmi layer via target_if */
549 status = target_if_vdev_mgr_send_fd_tmpl(pe_session->vdev,
550 fd_params);
551 if (QDF_IS_STATUS_ERROR(status)) {
552 pe_err("FAIL bytes %d retcode[%X]", n_bytes, status);
553 }
554
555 memfree:
556 qdf_mem_free(fd_params->frm);
557 qdf_mem_free(fd_params);
558 return status;
559 }
560
sch_send_beacon_req(struct mac_context * mac,uint8_t * beaconPayload,uint16_t size,struct pe_session * pe_session,enum sir_bcn_update_reason reason)561 QDF_STATUS sch_send_beacon_req(struct mac_context *mac, uint8_t *beaconPayload,
562 uint16_t size, struct pe_session *pe_session,
563 enum sir_bcn_update_reason reason)
564 {
565 struct scheduler_msg msgQ = {0};
566 tpSendbeaconParams beaconParams = NULL;
567 QDF_STATUS retCode;
568
569 if (LIM_IS_AP_ROLE(pe_session) &&
570 (mac->sch.beacon_changed)) {
571 retCode = lim_send_probe_rsp_template_to_hal(mac,
572 pe_session,
573 &pe_session->DefProbeRspIeBitmap[0]);
574 if (QDF_STATUS_SUCCESS != retCode)
575 pe_err("FAILED to send probe response template with retCode %d",
576 retCode);
577 /*Fils Discovery Template */
578 retCode = lim_send_fils_discovery_template(mac, pe_session);
579 if (QDF_STATUS_SUCCESS != retCode)
580 pe_err("FAILED to send fils discovery template retCode %d",
581 retCode);
582 }
583
584 beaconParams = qdf_mem_malloc(sizeof(tSendbeaconParams));
585 if (!beaconParams)
586 return QDF_STATUS_E_NOMEM;
587
588 msgQ.type = WMA_SEND_BEACON_REQ;
589
590 /* No Dialog Token reqd, as a response is not solicited */
591 msgQ.reserved = 0;
592
593 /* Fill in tSendbeaconParams members */
594 qdf_mem_copy(beaconParams->bssId, pe_session->bssId,
595 sizeof(pe_session->bssId));
596
597
598 beaconParams->timIeOffset = pe_session->schBeaconOffsetBegin;
599 if (pe_session->dfsIncludeChanSwIe) {
600 beaconParams->csa_count_offset = mac->sch.csa_count_offset;
601 beaconParams->ecsa_count_offset = mac->sch.ecsa_count_offset;
602 }
603 lim_update_sch_mlo_partner(mac, pe_session, beaconParams);
604 beaconParams->vdev_id = pe_session->smeSessionId;
605 beaconParams->reason = reason;
606
607 /* p2pIeOffset should be atleast greater than timIeOffset */
608 if ((mac->sch.p2p_ie_offset != 0) &&
609 (mac->sch.p2p_ie_offset <
610 pe_session->schBeaconOffsetBegin)) {
611 pe_err("Invalid p2pIeOffset:[%d]",
612 mac->sch.p2p_ie_offset);
613 QDF_ASSERT(0);
614 qdf_mem_free(beaconParams);
615 return QDF_STATUS_E_FAILURE;
616 }
617 beaconParams->p2pIeOffset = mac->sch.p2p_ie_offset;
618
619 if (size > SIR_MAX_BEACON_SIZE) {
620 pe_err("beacon size (%d) exceed host limit %d",
621 size, SIR_MAX_BEACON_SIZE);
622 QDF_ASSERT(0);
623 qdf_mem_free(beaconParams);
624 return QDF_STATUS_E_FAILURE;
625 }
626 qdf_mem_copy(beaconParams->beacon, beaconPayload, size);
627
628 beaconParams->beaconLength = (uint32_t) size;
629 msgQ.bodyptr = beaconParams;
630 msgQ.bodyval = 0;
631
632 MTRACE(mac_trace_msg_tx(mac, pe_session->peSessionId, msgQ.type));
633 retCode = wma_post_ctrl_msg(mac, &msgQ);
634 if (QDF_STATUS_SUCCESS != retCode)
635 pe_err("Posting SEND_BEACON_REQ to HAL failed, reason=%X",
636 retCode);
637
638 if (QDF_IS_STATUS_SUCCESS(retCode)) {
639 if (wlan_vdev_mlme_is_mlo_ap(pe_session->vdev))
640 lim_notify_link_info(pe_session);
641 else
642 lim_ap_mlme_vdev_rnr_notify(pe_session);
643 }
644
645 return retCode;
646 }
647
lim_remove_p2p_ie_from_add_ie(struct mac_context * mac,struct pe_session * pe_session,uint8_t * addIeWoP2pIe,uint32_t * addnIELenWoP2pIe)648 static uint32_t lim_remove_p2p_ie_from_add_ie(struct mac_context *mac,
649 struct pe_session *pe_session,
650 uint8_t *addIeWoP2pIe,
651 uint32_t *addnIELenWoP2pIe)
652 {
653 uint32_t left = pe_session->add_ie_params.probeRespDataLen;
654 uint8_t *ptr = pe_session->add_ie_params.probeRespData_buff;
655 uint8_t elem_id, elem_len;
656 uint32_t offset = 0;
657 uint8_t eid = 0xDD;
658
659 qdf_mem_copy(addIeWoP2pIe, ptr, left);
660 *addnIELenWoP2pIe = left;
661
662 if (addIeWoP2pIe) {
663 while (left >= 2) {
664 elem_id = ptr[0];
665 elem_len = ptr[1];
666 left -= 2;
667 if (elem_len > left) {
668 pe_err("Invalid IEs");
669 return QDF_STATUS_E_FAILURE;
670 }
671 if ((elem_id == eid) &&
672 (!qdf_mem_cmp(&ptr[2],
673 "\x50\x6f\x9a\x09", 4))) {
674 left -= elem_len;
675 ptr += (elem_len + 2);
676 qdf_mem_copy(&addIeWoP2pIe[offset], ptr, left);
677 *addnIELenWoP2pIe -= (2 + elem_len);
678 } else {
679 left -= elem_len;
680 ptr += (elem_len + 2);
681 offset += 2 + elem_len;
682 }
683 }
684 }
685 return QDF_STATUS_SUCCESS;
686 }
687
lim_send_probe_rsp_template_to_hal(struct mac_context * mac,struct pe_session * pe_session,uint32_t * IeBitmap)688 uint32_t lim_send_probe_rsp_template_to_hal(struct mac_context *mac,
689 struct pe_session *pe_session,
690 uint32_t *IeBitmap)
691 {
692 struct scheduler_msg msgQ = {0};
693 uint8_t *pFrame2Hal = pe_session->pSchProbeRspTemplate;
694 tpSendProbeRespParams pprobeRespParams = NULL;
695 uint32_t retCode = QDF_STATUS_E_FAILURE;
696 uint32_t nPayload, nBytes = 0, nStatus;
697 tpSirMacMgmtHdr pMacHdr;
698 uint32_t addnIEPresent = false;
699 uint8_t *addIE = NULL;
700 uint8_t *addIeWoP2pIe = NULL;
701 uint32_t addnIELenWoP2pIe = 0;
702 uint32_t retStatus;
703 tDot11fIEExtCap extracted_extcap;
704 bool extcap_present = false;
705 tDot11fProbeResponse *prb_rsp_frm;
706 QDF_STATUS status;
707 uint16_t addn_ielen = 0;
708 uint16_t mlo_ie_len;
709
710 /* Check if probe response IE is present or not */
711 addnIEPresent = (pe_session->add_ie_params.probeRespDataLen != 0);
712 if (addnIEPresent) {
713 /*
714 * probe response template should not have P2P IE.
715 * In case probe request has P2P IE or WPS IE, the
716 * probe request will be forwarded to the Host and
717 * Host will send the probe response. In other cases
718 * FW will send the probe response. So, if the template
719 * has P2P IE, the probe response sent to non P2P devices
720 * by the FW, may also have P2P IE which will fail
721 * P2P cert case 6.1.3
722 */
723 addIeWoP2pIe = qdf_mem_malloc(pe_session->add_ie_params.
724 probeRespDataLen);
725 if (!addIeWoP2pIe)
726 return QDF_STATUS_E_NOMEM;
727
728 retStatus = lim_remove_p2p_ie_from_add_ie(mac, pe_session,
729 addIeWoP2pIe, &addnIELenWoP2pIe);
730 if (retStatus != QDF_STATUS_SUCCESS) {
731 qdf_mem_free(addIeWoP2pIe);
732 return QDF_STATUS_E_FAILURE;
733 }
734
735 /* Probe rsp IE available */
736 /*need to check the data length */
737 addIE = qdf_mem_malloc(addnIELenWoP2pIe);
738 if (!addIE) {
739 qdf_mem_free(addIeWoP2pIe);
740 return QDF_STATUS_E_NOMEM;
741 }
742 addn_ielen = addnIELenWoP2pIe;
743
744 if (addn_ielen <= WNI_CFG_PROBE_RSP_ADDNIE_DATA1_LEN &&
745 addn_ielen && (nBytes + addn_ielen) <= SIR_MAX_PACKET_SIZE)
746 qdf_mem_copy(addIE, addIeWoP2pIe, addnIELenWoP2pIe);
747
748 qdf_mem_free(addIeWoP2pIe);
749
750 qdf_mem_zero((uint8_t *)&extracted_extcap,
751 sizeof(tDot11fIEExtCap));
752 status = lim_strip_extcap_update_struct(mac, addIE,
753 &addn_ielen, &extracted_extcap);
754 if (QDF_STATUS_SUCCESS != status) {
755 pe_debug("extcap not extracted");
756 } else {
757 extcap_present = true;
758 }
759 }
760
761 /*
762 * Extcap IE now support variable length, merge Extcap IE from addn_ie
763 * may change the frame size. Therefore, MUST merge ExtCap IE before
764 * dot11f get packed payload size.
765 */
766 prb_rsp_frm = &pe_session->probeRespFrame;
767 if (extcap_present) {
768 lim_merge_extcap_struct(&prb_rsp_frm->ExtCap,
769 &extracted_extcap,
770 true);
771 populate_dot11f_bcn_prot_extcaps(mac, pe_session,
772 &prb_rsp_frm->ExtCap);
773 }
774
775 nStatus = dot11f_get_packed_probe_response_size(mac,
776 &pe_session->probeRespFrame, &nPayload);
777 if (DOT11F_FAILED(nStatus)) {
778 pe_err("Failed to calculate the packed size for a Probe Response (0x%08x)",
779 nStatus);
780 /* We'll fall back on the worst case scenario: */
781 nPayload = sizeof(tDot11fProbeResponse);
782 } else if (DOT11F_WARNED(nStatus)) {
783 pe_err("There were warnings while calculating the packed size for a Probe Response (0x%08x)",
784 nStatus);
785 }
786
787 mlo_ie_len = lim_get_frame_mlo_ie_len(pe_session);
788 nBytes += nPayload + sizeof(tSirMacMgmtHdr) + mlo_ie_len;
789
790 if (addnIEPresent) {
791 if ((nBytes + addn_ielen) <= SIR_MAX_PROBE_RESP_SIZE)
792 nBytes += addn_ielen;
793 else
794 addnIEPresent = false; /* Dont include the IE. */
795 }
796
797 /* Make sure we are not exceeding allocated len */
798 if (nBytes > SIR_MAX_PROBE_RESP_SIZE) {
799 pe_err("nBytes %d greater than max size", nBytes);
800 qdf_mem_free(addIE);
801 return QDF_STATUS_E_FAILURE;
802 }
803
804 /* Paranoia: */
805 qdf_mem_zero(pFrame2Hal, nBytes);
806
807 /* Next, we fill out the buffer descriptor: */
808 lim_populate_mac_header(mac, pFrame2Hal, SIR_MAC_MGMT_FRAME,
809 SIR_MAC_MGMT_PROBE_RSP,
810 pe_session->self_mac_addr,
811 pe_session->self_mac_addr);
812
813 pMacHdr = (tpSirMacMgmtHdr) pFrame2Hal;
814
815 sir_copy_mac_addr(pMacHdr->bssId, pe_session->bssId);
816
817 /* That done, pack the Probe Response: */
818 nStatus =
819 dot11f_pack_probe_response(mac, &pe_session->probeRespFrame,
820 pFrame2Hal + sizeof(tSirMacMgmtHdr),
821 nPayload, &nPayload);
822
823 if (DOT11F_FAILED(nStatus)) {
824 pe_err("Failed to pack a Probe Response (0x%08x)",
825 nStatus);
826
827 qdf_mem_free(addIE);
828 return retCode; /* allocated! */
829 } else if (DOT11F_WARNED(nStatus)) {
830 pe_warn("There were warnings while packing a P"
831 "robe Response (0x%08x)", nStatus);
832 }
833
834 if (mlo_ie_len) {
835 status = lim_fill_complete_mlo_ie(pe_session, mlo_ie_len,
836 pFrame2Hal + sizeof(tSirMacMgmtHdr) +
837 nPayload);
838 if (QDF_IS_STATUS_ERROR(status)) {
839 pe_debug("assemble ml ie error");
840 mlo_ie_len = 0;
841 }
842 nPayload += mlo_ie_len;
843 }
844
845 if (addnIEPresent) {
846 qdf_mem_copy(&pFrame2Hal[nBytes - addn_ielen],
847 &addIE[0], addn_ielen);
848 }
849
850 qdf_mem_free(addIE);
851
852 pprobeRespParams = qdf_mem_malloc(sizeof(tSendProbeRespParams));
853 if (!pprobeRespParams) {
854 pe_err("malloc failed for bytes %d", nBytes);
855 } else {
856 sir_copy_mac_addr(pprobeRespParams->bssId, pe_session->bssId);
857 qdf_mem_copy(pprobeRespParams->probeRespTemplate,
858 pFrame2Hal, nBytes);
859 pprobeRespParams->probeRespTemplateLen = nBytes;
860 qdf_mem_copy(pprobeRespParams->ucProxyProbeReqValidIEBmap,
861 IeBitmap, (sizeof(uint32_t) * 8));
862 if (pe_session->opmode == QDF_P2P_GO_MODE &&
863 cfg_p2p_is_go_ignore_non_p2p_probe_req(mac->psoc)) {
864 pe_debug("GO ignore non-P2P probe req");
865 pprobeRespParams->go_ignore_non_p2p_probe_req = true;
866 }
867
868 msgQ.type = WMA_SEND_PROBE_RSP_TMPL;
869 msgQ.reserved = 0;
870 msgQ.bodyptr = pprobeRespParams;
871 msgQ.bodyval = 0;
872
873 retCode = wma_post_ctrl_msg(mac, &msgQ);
874 if (QDF_STATUS_SUCCESS != retCode) {
875 pe_err("FAIL bytes %d retcode[%X]", nBytes, retCode);
876 qdf_mem_free(pprobeRespParams);
877 }
878 }
879
880 return retCode;
881 }
882
883 /**
884 * sch_gen_timing_advert_frame() - Generate the TA frame and populate the buffer
885 * @mac: the global MAC context
886 * @self_addr: the self MAC address
887 * @buf: the buffer that will contain the frame
888 * @timestamp_offset: return for the offset of the timestamp field
889 * @time_value_offset: return for the time_value field in the TA IE
890 *
891 * Return: the length of the buffer on success and error code on failure.
892 */
sch_gen_timing_advert_frame(struct mac_context * mac_ctx,tSirMacAddr self_addr,uint8_t ** buf,uint32_t * timestamp_offset,uint32_t * time_value_offset)893 int sch_gen_timing_advert_frame(struct mac_context *mac_ctx, tSirMacAddr self_addr,
894 uint8_t **buf, uint32_t *timestamp_offset, uint32_t *time_value_offset)
895 {
896 tDot11fTimingAdvertisementFrame frame = {};
897 uint32_t payload_size, buf_size;
898 QDF_STATUS status;
899 uint32_t ret;
900 struct qdf_mac_addr wildcard_bssid = {
901 {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
902 };
903
904 /* Populate the TA fields */
905 status = populate_dot11f_timing_advert_frame(mac_ctx, &frame);
906 if (!QDF_IS_STATUS_SUCCESS(status)) {
907 pe_err("Error populating TA frame %x", status);
908 return qdf_status_to_os_return(status);
909 }
910
911 ret = dot11f_get_packed_timing_advertisement_frame_size(mac_ctx,
912 &frame, &payload_size);
913 if (DOT11F_FAILED(ret)) {
914 pe_err("Error getting packed frame size %x", ret);
915 return -EINVAL;
916 }
917 if (DOT11F_WARNED(ret))
918 pe_warn("Warning getting packed frame size");
919
920 buf_size = sizeof(tSirMacMgmtHdr) + payload_size;
921 *buf = qdf_mem_malloc(buf_size);
922 if (!*buf)
923 return -ENOMEM;
924
925 payload_size = 0;
926 ret = dot11f_pack_timing_advertisement_frame(mac_ctx, &frame,
927 *buf + sizeof(tSirMacMgmtHdr), buf_size -
928 sizeof(tSirMacMgmtHdr), &payload_size);
929 pe_debug("TA payload size2 = %d", payload_size);
930 if (DOT11F_FAILED(ret)) {
931 pe_err("Error packing frame %x", ret);
932 goto fail;
933 }
934 if (DOT11F_WARNED(ret))
935 pe_warn("Warning packing frame");
936
937 lim_populate_mac_header(mac_ctx, *buf, SIR_MAC_MGMT_FRAME,
938 SIR_MAC_MGMT_TIME_ADVERT, wildcard_bssid.bytes, self_addr);
939
940 /* The timestamp field is right after the header */
941 *timestamp_offset = sizeof(tSirMacMgmtHdr);
942
943 *time_value_offset = sizeof(tSirMacMgmtHdr) +
944 sizeof(tDot11fFfTimeStamp) + sizeof(tDot11fFfCapabilities);
945
946 /* Add the Country IE length */
947 dot11f_get_packed_ie_country(mac_ctx, &frame.Country,
948 time_value_offset);
949 /* Add 2 for Country IE EID and Length fields */
950 *time_value_offset += 2;
951
952 /* Add the PowerConstraint IE size */
953 if (frame.Country.present == 1)
954 *time_value_offset += 3;
955
956 /* Add the offset inside TA IE */
957 *time_value_offset += 3;
958
959 return payload_size + sizeof(tSirMacMgmtHdr);
960
961 fail:
962 qdf_mem_free(*buf);
963 *buf = NULL;
964 return -EINVAL;
965 }
966