1 /* 2 * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022-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 lim_prop_exts_utils.cc contains the utility functions 23 * to populate, parse proprietary extensions required to 24 * support ANI feature set. 25 * 26 * Author: Chandra Modumudi 27 * Date: 11/27/02 28 * History:- 29 * Date Modified by Modification Information 30 * -------------------------------------------------------------------- 31 * 32 */ 33 #include "ani_global.h" 34 #include "wni_cfg.h" 35 #include "sir_common.h" 36 #include "sir_debug.h" 37 #include "utils_api.h" 38 #include "lim_api.h" 39 #include "lim_types.h" 40 #include "lim_utils.h" 41 #include "lim_assoc_utils.h" 42 #include "lim_prop_exts_utils.h" 43 #include "lim_ser_des_utils.h" 44 #include "lim_trace.h" 45 #include "lim_ft_defs.h" 46 #include "lim_session.h" 47 #include "wma.h" 48 #include "wlan_utility.h" 49 50 #ifdef FEATURE_WLAN_ESE 51 /** 52 * get_local_power_constraint_probe_response() - extracts local constraint 53 * from probe response 54 * @beacon_struct: beacon structure 55 * @local_constraint: local constraint pointer 56 * @session: A pointer to session entry. 57 * 58 * Return: None 59 */ 60 static void get_local_power_constraint_probe_response( 61 tpSirProbeRespBeacon beacon_struct, 62 int8_t *local_constraint, 63 struct pe_session *session) 64 { 65 if (beacon_struct->eseTxPwr.present) 66 *local_constraint = 67 beacon_struct->eseTxPwr.power_limit; 68 } 69 70 /** 71 * get_ese_version_ie_probe_response() - extracts ESE version IE 72 * from probe response 73 * @mac_ctx: MAC context 74 * @beacon_struct: beacon structure 75 * @session: A pointer to session entry. 76 * 77 * Return: None 78 */ 79 static void get_ese_version_ie_probe_response(struct mac_context *mac_ctx, 80 tpSirProbeRespBeacon beacon_struct, 81 struct pe_session *session) 82 { 83 if (mac_ctx->mlme_cfg->lfr.ese_enabled) 84 session->is_ese_version_ie_present = 85 beacon_struct->is_ese_ver_ie_present; 86 } 87 #else 88 static void get_local_power_constraint_probe_response( 89 tpSirProbeRespBeacon beacon_struct, 90 int8_t *local_constraint, 91 struct pe_session *session) 92 { 93 94 } 95 96 static inline void get_ese_version_ie_probe_response(struct mac_context *mac_ctx, 97 tpSirProbeRespBeacon beacon_struct, 98 struct pe_session *session) 99 { 100 } 101 #endif 102 103 #ifdef WLAN_FEATURE_11AX 104 static void lim_extract_he_op(struct pe_session *session, 105 tSirProbeRespBeacon *beacon_struct) 106 { 107 uint8_t fw_vht_ch_wd; 108 uint8_t ap_bcon_ch_width; 109 uint8_t center_freq_diff; 110 111 if (!session->he_capable) 112 return; 113 if (!beacon_struct->he_op.present) { 114 return; 115 } 116 qdf_mem_copy(&session->he_op, &beacon_struct->he_op, 117 sizeof(session->he_op)); 118 if (!session->he_6ghz_band) 119 return; 120 if (!session->he_op.oper_info_6g_present) { 121 session->ap_defined_power_type_6g = REG_CURRENT_MAX_AP_TYPE; 122 return; 123 } 124 session->ch_width = session->he_op.oper_info_6g.info.ch_width; 125 session->ch_center_freq_seg0 = 126 session->he_op.oper_info_6g.info.center_freq_seg0; 127 session->ch_center_freq_seg1 = 128 session->he_op.oper_info_6g.info.center_freq_seg1; 129 session->ap_defined_power_type_6g = 130 session->he_op.oper_info_6g.info.reg_info; 131 if (session->ap_defined_power_type_6g < REG_INDOOR_AP || 132 session->ap_defined_power_type_6g > REG_MAX_SUPP_AP_TYPE) { 133 session->ap_defined_power_type_6g = REG_CURRENT_MAX_AP_TYPE; 134 pe_debug("AP power type invalid, defaulting to MAX_AP_TYPE"); 135 } 136 137 pe_debug("6G op info: ch_wd %d cntr_freq_seg0 %d cntr_freq_seg1 %d", 138 session->ch_width, session->ch_center_freq_seg0, 139 session->ch_center_freq_seg1); 140 141 if (!session->ch_center_freq_seg1) 142 return; 143 144 fw_vht_ch_wd = wma_get_vht_ch_width(); 145 if (fw_vht_ch_wd <= WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) { 146 session->ch_width = CH_WIDTH_80MHZ; 147 session->ch_center_freq_seg1 = 0; 148 return; 149 } 150 center_freq_diff = abs(session->ch_center_freq_seg1 - 151 session->ch_center_freq_seg0); 152 if (center_freq_diff == 8) { 153 ap_bcon_ch_width = CH_WIDTH_160MHZ; 154 } else if (center_freq_diff > 16) { 155 ap_bcon_ch_width = CH_WIDTH_80P80MHZ; 156 } else { 157 session->ch_width = CH_WIDTH_80MHZ; 158 session->ch_center_freq_seg1 = 0; 159 return; 160 } 161 162 if ((ap_bcon_ch_width == CH_WIDTH_80P80MHZ) && 163 (fw_vht_ch_wd != WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ)) { 164 session->ch_width = CH_WIDTH_80MHZ; 165 session->ch_center_freq_seg1 = 0; 166 } 167 } 168 169 static bool lim_validate_he160_mcs_map(struct mac_context *mac_ctx, 170 uint16_t peer_rx, uint16_t peer_tx, 171 uint8_t nss) 172 { 173 uint16_t rx_he_mcs_map; 174 uint16_t tx_he_mcs_map; 175 uint16_t he_mcs_map; 176 177 he_mcs_map = *((uint16_t *)mac_ctx->mlme_cfg->he_caps.dot11_he_cap. 178 tx_he_mcs_map_160); 179 rx_he_mcs_map = HE_INTERSECT_MCS(peer_rx, he_mcs_map); 180 181 he_mcs_map = *((uint16_t *)mac_ctx->mlme_cfg->he_caps.dot11_he_cap. 182 rx_he_mcs_map_160); 183 tx_he_mcs_map = HE_INTERSECT_MCS(peer_tx, he_mcs_map); 184 185 if (nss == NSS_1x1_MODE) { 186 rx_he_mcs_map |= HE_MCS_INV_MSK_4_NSS(1); 187 tx_he_mcs_map |= HE_MCS_INV_MSK_4_NSS(1); 188 } else if (nss == NSS_2x2_MODE) { 189 rx_he_mcs_map |= (HE_MCS_INV_MSK_4_NSS(1) & 190 HE_MCS_INV_MSK_4_NSS(2)); 191 tx_he_mcs_map |= (HE_MCS_INV_MSK_4_NSS(1) & 192 HE_MCS_INV_MSK_4_NSS(2)); 193 } 194 195 return ((rx_he_mcs_map != HE_MCS_ALL_DISABLED) && 196 (tx_he_mcs_map != HE_MCS_ALL_DISABLED)); 197 } 198 199 static void lim_check_is_he_mcs_valid(struct pe_session *session, 200 tSirProbeRespBeacon *beacon_struct) 201 { 202 uint8_t i; 203 uint16_t mcs_map; 204 205 if (!session->he_capable || !beacon_struct->he_cap.present) 206 return; 207 208 mcs_map = beacon_struct->he_cap.rx_he_mcs_map_lt_80; 209 for (i = 0; i < session->nss; i++) { 210 if (((mcs_map >> (i * 2)) & 0x3) != 0x3) 211 return; 212 } 213 session->he_capable = false; 214 if (session->vhtCapability) 215 session->dot11mode = MLME_DOT11_MODE_11AC; 216 else 217 session->dot11mode = MLME_DOT11_MODE_11N; 218 pe_err("vdev %d: Invalid LT80 MCS map 0x%x with NSS %d, falback to dot11mode %d", 219 session->vdev_id, mcs_map, session->nss, session->dot11mode); 220 } 221 222 void lim_update_he_bw_cap_mcs(struct pe_session *session, 223 tSirProbeRespBeacon *beacon) 224 { 225 uint8_t is_80mhz; 226 uint8_t sta_prefer_80mhz_over_160mhz; 227 228 if (!session->he_capable) 229 return; 230 231 sta_prefer_80mhz_over_160mhz = 232 session->mac_ctx->mlme_cfg->sta.sta_prefer_80mhz_over_160mhz; 233 if ((session->opmode == QDF_STA_MODE || 234 session->opmode == QDF_P2P_CLIENT_MODE) && 235 beacon && beacon->he_cap.present) { 236 if (!beacon->he_cap.chan_width_2) { 237 is_80mhz = 1; 238 } else if (beacon->he_cap.chan_width_2 && 239 !lim_validate_he160_mcs_map(session->mac_ctx, 240 *((uint16_t *)beacon->he_cap.rx_he_mcs_map_160), 241 *((uint16_t *)beacon->he_cap.tx_he_mcs_map_160), 242 session->nss)) { 243 is_80mhz = 1; 244 if (session->ch_width == CH_WIDTH_160MHZ) { 245 pe_debug("HE160 Rx/Tx MCS is not valid, falling back to 80MHz"); 246 session->ch_width = CH_WIDTH_80MHZ; 247 } 248 } else if (sta_prefer_80mhz_over_160mhz == 249 STA_PREFER_BW_80MHZ) { 250 is_80mhz = 1; 251 if (session->ch_width == CH_WIDTH_160MHZ) { 252 pe_debug("STA preferred HE80 over HE160, falling back to 80MHz"); 253 session->ch_width = CH_WIDTH_80MHZ; 254 } 255 } else { 256 is_80mhz = 0; 257 } 258 } else { 259 is_80mhz = 1; 260 } 261 262 if (session->ch_width <= CH_WIDTH_80MHZ && is_80mhz) { 263 session->he_config.chan_width_2 = 0; 264 session->he_config.chan_width_3 = 0; 265 } else if (session->ch_width == CH_WIDTH_160MHZ) { 266 session->he_config.chan_width_3 = 0; 267 } 268 /* Reset the > 20MHz caps for 20MHz connection */ 269 if (session->ch_width == CH_WIDTH_20MHZ) { 270 session->he_config.chan_width_0 = 0; 271 session->he_config.chan_width_1 = 0; 272 session->he_config.chan_width_2 = 0; 273 session->he_config.chan_width_3 = 0; 274 session->he_config.chan_width_4 = 0; 275 session->he_config.chan_width_5 = 0; 276 session->he_config.chan_width_6 = 0; 277 session->he_config.he_ppdu_20_in_40Mhz_2G = 0; 278 session->he_config.he_ppdu_20_in_160_80p80Mhz = 0; 279 session->he_config.he_ppdu_80_in_160_80p80Mhz = 0; 280 } 281 if (WLAN_REG_IS_24GHZ_CH_FREQ(session->curr_op_freq)) { 282 session->he_config.chan_width_1 = 0; 283 session->he_config.chan_width_2 = 0; 284 session->he_config.chan_width_3 = 0; 285 session->he_config.chan_width_5 = 0; 286 session->he_config.chan_width_6 = 0; 287 } else { 288 session->he_config.chan_width_0 = 0; 289 session->he_config.chan_width_4 = 0; 290 session->he_config.chan_width_6 = 0; 291 } 292 if (!session->he_config.chan_width_2) { 293 session->he_config.bfee_sts_gt_80 = 0; 294 session->he_config.num_sounding_gt_80 = 0; 295 session->he_config.he_ppdu_20_in_160_80p80Mhz = 0; 296 session->he_config.he_ppdu_80_in_160_80p80Mhz = 0; 297 *(uint16_t *)session->he_config.rx_he_mcs_map_160 = 298 HE_MCS_ALL_DISABLED; 299 *(uint16_t *)session->he_config.tx_he_mcs_map_160 = 300 HE_MCS_ALL_DISABLED; 301 } 302 if (!session->he_config.chan_width_3) { 303 *(uint16_t *)session->he_config.rx_he_mcs_map_80_80 = 304 HE_MCS_ALL_DISABLED; 305 *(uint16_t *)session->he_config.tx_he_mcs_map_80_80 = 306 HE_MCS_ALL_DISABLED; 307 } 308 } 309 310 void lim_update_he_mcs_12_13_map(struct wlan_objmgr_psoc *psoc, 311 uint8_t vdev_id, uint16_t he_mcs_12_13_map) 312 { 313 struct wlan_objmgr_vdev *vdev; 314 315 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, 316 WLAN_LEGACY_MAC_ID); 317 if (!vdev) { 318 pe_err("vdev not found for id: %d", vdev_id); 319 return; 320 } 321 wlan_vdev_obj_lock(vdev); 322 wlan_vdev_mlme_set_he_mcs_12_13_map(vdev, he_mcs_12_13_map); 323 wlan_vdev_obj_unlock(vdev); 324 wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); 325 } 326 #else 327 static inline void lim_extract_he_op(struct pe_session *session, 328 tSirProbeRespBeacon *beacon_struct) 329 {} 330 static void lim_check_is_he_mcs_valid(struct pe_session *session, 331 tSirProbeRespBeacon *beacon_struct) 332 { 333 } 334 335 void lim_update_he_mcs_12_13_map(struct wlan_objmgr_psoc *psoc, 336 uint8_t vdev_id, uint16_t he_mcs_12_13_map) 337 { 338 } 339 #endif 340 341 #ifdef WLAN_FEATURE_11BE 342 void lim_extract_eht_op(struct pe_session *session, 343 tSirProbeRespBeacon *beacon_struct) 344 { 345 uint32_t max_eht_bw; 346 347 if (!session->eht_capable) 348 return; 349 350 if (!beacon_struct->eht_op.present) 351 return; 352 353 if (!beacon_struct->eht_op.eht_op_information_present) 354 return; 355 356 qdf_mem_copy(&session->eht_op, &beacon_struct->eht_op, 357 sizeof(session->eht_op)); 358 359 max_eht_bw = wma_get_eht_ch_width(); 360 361 if (session->eht_op.channel_width == WLAN_EHT_CHWIDTH_320) { 362 if (max_eht_bw == WNI_CFG_EHT_CHANNEL_WIDTH_320MHZ) { 363 session->ch_width = CH_WIDTH_320MHZ; 364 } else if (max_eht_bw == WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) { 365 session->ch_width = CH_WIDTH_160MHZ; 366 } else { 367 session->ch_width = CH_WIDTH_80MHZ; 368 session->ch_center_freq_seg1 = 0; 369 } 370 } else if (session->eht_op.channel_width == WLAN_EHT_CHWIDTH_160) { 371 if (max_eht_bw >= WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) { 372 session->ch_width = CH_WIDTH_160MHZ; 373 } else { 374 session->ch_width = CH_WIDTH_80MHZ; 375 session->ch_center_freq_seg1 = 0; 376 } 377 } else if (session->eht_op.channel_width == WLAN_EHT_CHWIDTH_80) { 378 session->ch_width = CH_WIDTH_80MHZ; 379 session->ch_center_freq_seg1 = 0; 380 } else if (session->eht_op.channel_width == WLAN_EHT_CHWIDTH_40) { 381 session->ch_width = CH_WIDTH_40MHZ; 382 session->ch_center_freq_seg1 = 0; 383 } else { 384 session->ch_width = CH_WIDTH_20MHZ; 385 session->ch_center_freq_seg1 = 0; 386 } 387 388 session->ch_center_freq_seg0 = session->eht_op.ccfs0; 389 session->ch_center_freq_seg1 = session->eht_op.ccfs1; 390 } 391 392 void lim_update_eht_bw_cap_mcs(struct pe_session *session, 393 tSirProbeRespBeacon *beacon) 394 { 395 if (!session->eht_capable) 396 return; 397 398 if ((session->opmode == QDF_STA_MODE || 399 session->opmode == QDF_P2P_CLIENT_MODE) && 400 beacon && beacon->eht_cap.present) { 401 if (!beacon->eht_cap.support_320mhz_6ghz) 402 session->eht_config.support_320mhz_6ghz = 0; 403 if (!beacon->eht_cap.support_320mhz_6ghz || 404 !beacon->eht_cap.su_beamformer) 405 session->eht_config.num_sounding_dim_320mhz = 0; 406 } 407 } 408 #endif 409 410 #ifdef WLAN_FEATURE_11BE_MLO 411 void lim_objmgr_update_emlsr_caps(struct wlan_objmgr_psoc *psoc, 412 uint8_t vdev_id, tpSirAssocRsp assoc_rsp) 413 { 414 struct wlan_objmgr_vdev *vdev; 415 bool ap_emlsr_cap = false; 416 417 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, 418 WLAN_LEGACY_MAC_ID); 419 if (!vdev) { 420 pe_err("vdev not found for id: %d", vdev_id); 421 return; 422 } 423 424 /* Check for assoc link vdev to extract emlsr cap from assoc rsp */ 425 if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev)) { 426 ap_emlsr_cap = 427 assoc_rsp->mlo_ie.mlo_ie.eml_capabilities_info.emlsr_support; 428 429 if (!(wlan_vdev_mlme_cap_get(vdev, WLAN_VDEV_C_EMLSR_CAP) && 430 ap_emlsr_cap)) { 431 if (!wlan_vdev_mlme_cap_get(vdev, WLAN_VDEV_C_EMLSR_CAP) 432 && ap_emlsr_cap) 433 pe_debug("No eMLSR STA supp but recvd EML caps in assc rsp"); 434 else 435 pe_debug("EML caps not present in assoc rsp"); 436 wlan_vdev_obj_lock(vdev); 437 wlan_vdev_mlme_cap_clear(vdev, WLAN_VDEV_C_EMLSR_CAP); 438 wlan_vdev_obj_unlock(vdev); 439 } else { 440 pe_debug("EML caps present in assoc rsp"); 441 } 442 } else { 443 pe_debug("no change required for link vdev"); 444 } 445 446 wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); 447 } 448 #endif 449 450 void lim_objmgr_update_vdev_nss(struct wlan_objmgr_psoc *psoc, 451 uint8_t vdev_id, uint8_t nss) 452 { 453 struct wlan_objmgr_vdev *vdev; 454 455 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, 456 WLAN_LEGACY_MAC_ID); 457 if (!vdev) { 458 pe_err("vdev not found for id: %d", vdev_id); 459 return; 460 } 461 wlan_vdev_obj_lock(vdev); 462 wlan_vdev_mlme_set_nss(vdev, nss); 463 wlan_vdev_obj_unlock(vdev); 464 wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); 465 } 466 467 #ifdef WLAN_ADAPTIVE_11R 468 /** 469 * lim_extract_adaptive_11r_cap() - check if the AP has adaptive 11r 470 * IE 471 * @ie: Pointer to the IE 472 * @ie_len: ie Length 473 * 474 * Return: True if adaptive 11r IE is present 475 */ 476 static bool lim_extract_adaptive_11r_cap(uint8_t *ie, uint16_t ie_len) 477 { 478 const uint8_t *adaptive_ie; 479 uint8_t data; 480 bool adaptive_11r; 481 482 adaptive_ie = wlan_get_vendor_ie_ptr_from_oui(LIM_ADAPTIVE_11R_OUI, 483 LIM_ADAPTIVE_11R_OUI_SIZE, 484 ie, ie_len); 485 if (!adaptive_ie) 486 return false; 487 488 if ((adaptive_ie[1] < (OUI_LENGTH + 1)) || 489 (adaptive_ie[1] > MAX_ADAPTIVE_11R_IE_LEN)) 490 return false; 491 492 data = *(adaptive_ie + OUI_LENGTH + 2); 493 adaptive_11r = (data & 0x1) ? true : false; 494 495 return adaptive_11r; 496 } 497 498 #else 499 static inline bool lim_extract_adaptive_11r_cap(uint8_t *ie, uint16_t ie_len) 500 { 501 return false; 502 } 503 #endif 504 505 #ifdef WLAN_FEATURE_11AX 506 static void lim_check_peer_ldpc_and_update(struct pe_session *session, 507 tSirProbeRespBeacon *beacon_struct) 508 { 509 /* 510 * In 2.4G if AP supports HE till MCS 0-9 we can associate 511 * with HE mode instead downgrading to 11ac 512 */ 513 if (session->he_capable && 514 WLAN_REG_IS_24GHZ_CH_FREQ(session->curr_op_freq) && 515 beacon_struct->he_cap.present && 516 lim_check_he_80_mcs11_supp(session, &beacon_struct->he_cap) && 517 !beacon_struct->he_cap.ldpc_coding) { 518 session->he_capable = false; 519 pe_err("LDPC check failed for HE operation"); 520 if (session->vhtCapability) { 521 session->dot11mode = MLME_DOT11_MODE_11AC; 522 pe_debug("Update dot11mode to 11ac"); 523 } else { 524 session->dot11mode = MLME_DOT11_MODE_11N; 525 pe_debug("Update dot11mode to 11N"); 526 } 527 } 528 } 529 #else 530 static void lim_check_peer_ldpc_and_update(struct pe_session *session, 531 tSirProbeRespBeacon *beacon_struct) 532 {} 533 #endif 534 535 static 536 void lim_update_ch_width_for_p2p_client(struct mac_context *mac, 537 struct pe_session *session, 538 uint32_t ch_freq) 539 { 540 struct ch_params ch_params = {0}; 541 542 if (session->dot11mode < MLME_DOT11_MODE_11AC) 543 return; 544 /* 545 * Some IOT AP's/P2P-GO's (e.g. make: Wireless-AC 9560160MHz as P2P GO), 546 * send beacon with 20mhz and assoc resp with 80mhz and 547 * after assoc resp, next beacon also has 80mhz. 548 * Connection is expected to happen in better possible 549 * bandwidth(80MHz in this case). 550 * Start the vdev with max supported ch_width in order to support this. 551 * It'll be downgraded to appropriate ch_width or the same would be 552 * continued based on assoc resp. 553 * Restricting this check for p2p client and 5G only and this may be 554 * extended to STA based on wider testing results with multiple AP's. 555 * Limit it to 80MHz as 80+80 is channel specific and 160MHz is not 556 * supported in p2p. 557 */ 558 ch_params.ch_width = CH_WIDTH_80MHZ; 559 560 wlan_reg_set_channel_params_for_pwrmode(mac->pdev, ch_freq, 0, 561 &ch_params, 562 REG_CURRENT_PWR_MODE); 563 if (ch_params.ch_width == CH_WIDTH_20MHZ) 564 ch_params.sec_ch_offset = PHY_SINGLE_CHANNEL_CENTERED; 565 566 session->htSupportedChannelWidthSet = ch_params.sec_ch_offset ? 1 : 0; 567 session->htRecommendedTxWidthSet = session->htSupportedChannelWidthSet; 568 session->htSecondaryChannelOffset = ch_params.sec_ch_offset; 569 session->ch_width = ch_params.ch_width; 570 session->ch_center_freq_seg0 = ch_params.center_freq_seg0; 571 session->ch_center_freq_seg1 = ch_params.center_freq_seg1; 572 pe_debug("Start P2P_CLI in ch freq %d max supported ch_width: %u cbmode: %u seg0: %u, seg1: %u", 573 ch_freq, ch_params.ch_width, ch_params.sec_ch_offset, 574 session->ch_center_freq_seg0, session->ch_center_freq_seg1); 575 } 576 577 void lim_extract_ap_capability(struct mac_context *mac_ctx, uint8_t *p_ie, 578 uint16_t ie_len, uint8_t *qos_cap, 579 uint8_t *uapsd, int8_t *local_constraint, 580 struct pe_session *session, 581 bool *is_pwr_constraint) 582 { 583 tSirProbeRespBeacon *beacon_struct; 584 uint8_t ap_bcon_ch_width; 585 bool new_ch_width_dfn = false; 586 tDot11fIEVHTOperation *vht_op; 587 uint8_t fw_vht_ch_wd; 588 uint8_t vht_ch_wd; 589 uint8_t center_freq_diff; 590 struct s_ext_cap *ext_cap; 591 uint8_t chan_center_freq_seg1; 592 tDot11fIEVHTCaps *vht_caps; 593 uint8_t channel = 0; 594 uint8_t sta_prefer_80mhz_over_160mhz; 595 struct mlme_vht_capabilities_info *mlme_vht_cap; 596 QDF_STATUS status; 597 598 beacon_struct = qdf_mem_malloc(sizeof(tSirProbeRespBeacon)); 599 if (!beacon_struct) 600 return; 601 602 *qos_cap = 0; 603 *uapsd = 0; 604 sta_prefer_80mhz_over_160mhz = 605 session->mac_ctx->mlme_cfg->sta.sta_prefer_80mhz_over_160mhz; 606 607 status = sir_parse_beacon_ie(mac_ctx, beacon_struct, p_ie, 608 (uint32_t)ie_len); 609 if (QDF_IS_STATUS_ERROR(status)) { 610 pe_err("sir_parse_beacon_ie failed to parse beacon"); 611 qdf_mem_free(beacon_struct); 612 return; 613 } 614 615 mlme_vht_cap = &mac_ctx->mlme_cfg->vht_caps.vht_cap_info; 616 if (beacon_struct->wmeInfoPresent || 617 beacon_struct->wmeEdcaPresent || 618 beacon_struct->HTCaps.present) 619 LIM_BSS_CAPS_SET(WME, *qos_cap); 620 621 if (LIM_BSS_CAPS_GET(WME, *qos_cap) && beacon_struct->wsmCapablePresent) 622 LIM_BSS_CAPS_SET(WSM, *qos_cap); 623 624 if (beacon_struct->HTCaps.present) 625 mac_ctx->lim.htCapabilityPresentInBeacon = 1; 626 else 627 mac_ctx->lim.htCapabilityPresentInBeacon = 0; 628 629 vht_op = &beacon_struct->VHTOperation; 630 vht_caps = &beacon_struct->VHTCaps; 631 if (IS_BSS_VHT_CAPABLE(beacon_struct->VHTCaps) && vht_op->present && 632 session->vhtCapability) { 633 session->vhtCapabilityPresentInBeacon = 1; 634 635 if (((beacon_struct->Vendor1IEPresent && 636 beacon_struct->vendor_vht_ie.present && 637 beacon_struct->Vendor3IEPresent)) && 638 (((beacon_struct->VHTCaps.txMCSMap & VHT_MCS_3x3_MASK) == 639 VHT_MCS_3x3_MASK) && 640 ((beacon_struct->VHTCaps.txMCSMap & VHT_MCS_2x2_MASK) != 641 VHT_MCS_2x2_MASK))) 642 session->vht_config.su_beam_formee = 0; 643 } else { 644 session->vhtCapabilityPresentInBeacon = 0; 645 } 646 647 if (session->vhtCapabilityPresentInBeacon == 1 && 648 !session->htSupportedChannelWidthSet) { 649 if (!mac_ctx->mlme_cfg->vht_caps.vht_cap_info.enable_txbf_20mhz) 650 session->vht_config.su_beam_formee = 0; 651 652 if (session->opmode == QDF_P2P_CLIENT_MODE && 653 !wlan_reg_is_24ghz_ch_freq(beacon_struct->chan_freq) && 654 mac_ctx->roam.configParam.channelBondingMode5GHz) 655 lim_update_ch_width_for_p2p_client( 656 mac_ctx, session, 657 beacon_struct->chan_freq); 658 659 } else if (session->vhtCapabilityPresentInBeacon && vht_op->chanWidth) { 660 /* If VHT is supported min 80 MHz support is must */ 661 ap_bcon_ch_width = vht_op->chanWidth; 662 if (vht_caps->vht_extended_nss_bw_cap) { 663 if (!vht_caps->extended_nss_bw_supp) 664 chan_center_freq_seg1 = 665 vht_op->chan_center_freq_seg1; 666 else 667 chan_center_freq_seg1 = 668 beacon_struct->HTInfo.chan_center_freq_seg2; 669 } else { 670 chan_center_freq_seg1 = vht_op->chan_center_freq_seg1; 671 } 672 if (chan_center_freq_seg1 && 673 (ap_bcon_ch_width == WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ)) { 674 new_ch_width_dfn = true; 675 if (chan_center_freq_seg1 > 676 vht_op->chan_center_freq_seg0) 677 center_freq_diff = chan_center_freq_seg1 - 678 vht_op->chan_center_freq_seg0; 679 else 680 center_freq_diff = vht_op->chan_center_freq_seg0 - 681 chan_center_freq_seg1; 682 if (center_freq_diff == 8) 683 ap_bcon_ch_width = 684 WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ; 685 else if (center_freq_diff > 16) 686 ap_bcon_ch_width = 687 WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ; 688 else 689 ap_bcon_ch_width = 690 WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ; 691 } 692 693 fw_vht_ch_wd = wma_get_vht_ch_width(); 694 vht_ch_wd = QDF_MIN(fw_vht_ch_wd, ap_bcon_ch_width); 695 696 if ((vht_ch_wd > WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) && 697 (ap_bcon_ch_width == 698 WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ) && 699 mlme_vht_cap->restricted_80p80_bw_supp) { 700 if ((chan_center_freq_seg1 == 138 && 701 vht_op->chan_center_freq_seg0 == 155) || 702 (vht_op->chan_center_freq_seg0 == 138 && 703 chan_center_freq_seg1 == 155)) 704 vht_ch_wd = 705 WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ; 706 else 707 vht_ch_wd = WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ; 708 } 709 /* 710 * If the supported channel width is greater than 80MHz and 711 * AP supports Nss > 1 in 160MHz mode then connect the STA 712 * in 2x2 80MHz mode instead of connecting in 160MHz mode. 713 */ 714 if (vht_ch_wd > WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) { 715 if (sta_prefer_80mhz_over_160mhz == STA_PREFER_BW_80MHZ) 716 vht_ch_wd = WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ; 717 else if ((sta_prefer_80mhz_over_160mhz == 718 STA_PREFER_BW_VHT80MHZ) && 719 (!(IS_VHT_NSS_1x1(beacon_struct->VHTCaps.txMCSMap)) && 720 (!IS_VHT_NSS_1x1(beacon_struct->VHTCaps.rxMCSMap)))) 721 vht_ch_wd = WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ; 722 } 723 /* 724 * VHT OP IE old definition: 725 * vht_op->chan_center_freq_seg0: center freq of 80MHz/160MHz/ 726 * primary 80 in 80+80MHz. 727 * 728 * vht_op->chan_center_freq_seg1: center freq of secondary 80 729 * in 80+80MHz. 730 * 731 * VHT OP IE NEW definition: 732 * vht_op->chan_center_freq_seg0: center freq of 80MHz/primary 733 * 80 in 80+80MHz/center freq of the 80 MHz channel segment 734 * that contains the primary channel in 160MHz mode. 735 * 736 * vht_op->chan_center_freq_seg1: center freq of secondary 80 737 * in 80+80MHz/center freq of 160MHz. 738 */ 739 session->ch_center_freq_seg0 = vht_op->chan_center_freq_seg0; 740 session->ch_center_freq_seg1 = chan_center_freq_seg1; 741 channel = wlan_reg_freq_to_chan(mac_ctx->pdev, 742 beacon_struct->chan_freq); 743 if (vht_ch_wd == WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) { 744 /* DUT or AP supports only 160MHz */ 745 if (ap_bcon_ch_width == 746 WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) { 747 /* AP is in 160MHz mode */ 748 if (!new_ch_width_dfn) { 749 session->ch_center_freq_seg1 = 750 vht_op->chan_center_freq_seg0; 751 session->ch_center_freq_seg0 = 752 lim_get_80Mhz_center_channel(channel); 753 } 754 } else { 755 /* DUT supports only 160MHz and AP is 756 * in 80+80 mode 757 */ 758 vht_ch_wd = WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ; 759 session->ch_center_freq_seg1 = 0; 760 session->ch_center_freq_seg0 = 761 lim_get_80Mhz_center_channel(channel); 762 } 763 } else if (vht_ch_wd == WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) { 764 /* DUT or AP supports only 80MHz */ 765 session->ch_center_freq_seg0 = 766 lim_get_80Mhz_center_channel(channel); 767 session->ch_center_freq_seg1 = 0; 768 } 769 session->ch_width = vht_ch_wd + 1; 770 session->ap_ch_width = session->ch_width; 771 } 772 773 if (session->vhtCapability && session->vhtCapabilityPresentInBeacon && 774 beacon_struct->ext_cap.present) { 775 ext_cap = (struct s_ext_cap *)beacon_struct->ext_cap.bytes; 776 session->gLimOperatingMode.present = 777 ext_cap->oper_mode_notification; 778 if (ext_cap->oper_mode_notification) { 779 uint8_t self_nss = 0; 780 781 if (!wlan_reg_is_24ghz_ch_freq(session->curr_op_freq)) 782 self_nss = mac_ctx->vdev_type_nss_5g.sta; 783 else 784 self_nss = mac_ctx->vdev_type_nss_2g.sta; 785 786 if (CH_WIDTH_160MHZ > session->ch_width) 787 session->gLimOperatingMode.chanWidth = 788 session->ch_width; 789 else 790 session->gLimOperatingMode.chanWidth = 791 CH_WIDTH_160MHZ; 792 /** Populate vdev nss in OMN ie of assoc requse for 793 * WFA CERT test scenario. 794 */ 795 if (ext_cap->beacon_protection_enable && 796 session->opmode == QDF_STA_MODE && 797 !session->nss_forced_1x1 && 798 lim_get_nss_supported_by_ap( 799 &beacon_struct->VHTCaps, 800 &beacon_struct->HTCaps, 801 &beacon_struct->he_cap) == NSS_1x1_MODE) 802 session->gLimOperatingMode.rxNSS = self_nss - 1; 803 else 804 session->gLimOperatingMode.rxNSS = 805 session->nss - 1; 806 } else { 807 pe_err("AP does not support op_mode rx"); 808 } 809 } 810 811 lim_check_is_he_mcs_valid(session, beacon_struct); 812 lim_check_peer_ldpc_and_update(session, beacon_struct); 813 lim_extract_he_op(session, beacon_struct); 814 lim_extract_eht_op(session, beacon_struct); 815 if (!mac_ctx->usr_eht_testbed_cfg) 816 lim_update_he_bw_cap_mcs(session, beacon_struct); 817 lim_update_eht_bw_cap_mcs(session, beacon_struct); 818 /* Extract the UAPSD flag from WMM Parameter element */ 819 if (beacon_struct->wmeEdcaPresent) 820 *uapsd = beacon_struct->edcaParams.qosInfo.uapsd; 821 822 if (mac_ctx->mlme_cfg->sta.allow_tpc_from_ap) { 823 if (beacon_struct->powerConstraintPresent) { 824 *local_constraint = 825 beacon_struct->localPowerConstraint. 826 localPowerConstraints; 827 *is_pwr_constraint = true; 828 } else { 829 get_local_power_constraint_probe_response( 830 beacon_struct, local_constraint, session); 831 *is_pwr_constraint = false; 832 } 833 } 834 835 get_ese_version_ie_probe_response(mac_ctx, beacon_struct, session); 836 837 session->country_info_present = false; 838 /* Initializing before first use */ 839 if (beacon_struct->countryInfoPresent) 840 session->country_info_present = true; 841 /* Check if Extended caps are present in probe resp or not */ 842 if (beacon_struct->ext_cap.present) 843 session->is_ext_caps_present = true; 844 /* Update HS 2.0 Information Element */ 845 if (beacon_struct->hs20vendor_ie.present) { 846 pe_debug("HS20 Indication Element Present, rel#: %u id: %u", 847 beacon_struct->hs20vendor_ie.release_num, 848 beacon_struct->hs20vendor_ie.hs_id_present); 849 qdf_mem_copy(&session->hs20vendor_ie, 850 &beacon_struct->hs20vendor_ie, 851 sizeof(tDot11fIEhs20vendor_ie) - 852 sizeof(beacon_struct->hs20vendor_ie.hs_id)); 853 if (beacon_struct->hs20vendor_ie.hs_id_present) 854 qdf_mem_copy(&session->hs20vendor_ie.hs_id, 855 &beacon_struct->hs20vendor_ie.hs_id, 856 sizeof(beacon_struct->hs20vendor_ie.hs_id)); 857 } 858 859 lim_objmgr_update_vdev_nss(mac_ctx->psoc, session->smeSessionId, 860 session->nss); 861 862 session->is_adaptive_11r_connection = 863 lim_extract_adaptive_11r_cap(p_ie, ie_len); 864 qdf_mem_free(beacon_struct); 865 return; 866 } /****** end lim_extract_ap_capability() ******/ 867 868 /** 869 * lim_get_htcb_state 870 * 871 ***FUNCTION: 872 * This routing provides the translation of Airgo Enum to HT enum for determining 873 * secondary channel offset. 874 * Airgo Enum is required for backward compatibility purposes. 875 * 876 * 877 ***NOTE: 878 * 879 * @param mac - Pointer to Global MAC structure 880 * @return The corresponding HT enumeration 881 */ 882 ePhyChanBondState lim_get_htcb_state(ePhyChanBondState aniCBMode) 883 { 884 switch (aniCBMode) { 885 case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW: 886 case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED: 887 case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH: 888 case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: 889 return PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; 890 case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW: 891 case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED: 892 case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH: 893 case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: 894 return PHY_DOUBLE_CHANNEL_LOW_PRIMARY; 895 case PHY_QUADRUPLE_CHANNEL_20MHZ_CENTERED_40MHZ_CENTERED: 896 return PHY_SINGLE_CHANNEL_CENTERED; 897 default: 898 return PHY_SINGLE_CHANNEL_CENTERED; 899 } 900 } 901