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 */ 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 */ 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 157 static void lim_notify_link_info(struct pe_session *pe_session) 158 { 159 } 160 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 */ 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 */ 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 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 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 */ 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 */ 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 */ 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 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 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 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 */ 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