1 /* 2 * hostapd / IEEE 802.11ax HE 3 * Copyright (c) 2016-2017, Qualcomm Atheros, Inc. 4 * Copyright (c) 2019 John Crispin <john@phrozen.org> 5 * 6 * This software may be distributed under the terms of the BSD license. 7 * See README for more details. 8 */ 9 10 #include "utils/includes.h" 11 12 #include "utils/common.h" 13 #include "common/ieee802_11_defs.h" 14 #include "common/ieee802_11_common.h" 15 #include "hostapd.h" 16 #include "ap_config.h" 17 #include "beacon.h" 18 #include "sta_info.h" 19 #include "ieee802_11.h" 20 #include "dfs.h" 21 22 static u8 ieee80211_he_ppet_size(u8 ppe_thres_hdr, const u8 *phy_cap_info) 23 { 24 u8 sz = 0, ru; 25 26 if ((phy_cap_info[HE_PHYCAP_PPE_THRESHOLD_PRESENT_IDX] & 27 HE_PHYCAP_PPE_THRESHOLD_PRESENT) == 0) 28 return 0; 29 30 ru = (ppe_thres_hdr >> HE_PPE_THRES_RU_INDEX_BITMASK_SHIFT) & 31 HE_PPE_THRES_RU_INDEX_BITMASK_MASK; 32 while (ru) { 33 if (ru & 0x1) 34 sz++; 35 ru >>= 1; 36 } 37 38 sz *= 1 + (ppe_thres_hdr & HE_PPE_THRES_NSS_MASK); 39 sz = (sz * 6) + 7; 40 if (sz % 8) 41 sz += 8; 42 sz /= 8; 43 44 return sz; 45 } 46 47 48 static u8 ieee80211_he_mcs_set_size(const u8 *phy_cap_info) 49 { 50 u8 sz = 4; 51 52 if (phy_cap_info[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] & 53 HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G) 54 sz += 4; 55 if (phy_cap_info[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] & 56 HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G) 57 sz += 4; 58 59 return sz; 60 } 61 62 63 static int ieee80211_invalid_he_cap_size(const u8 *buf, size_t len) 64 { 65 struct ieee80211_he_capabilities *cap; 66 size_t cap_len; 67 68 cap = (struct ieee80211_he_capabilities *) buf; 69 cap_len = sizeof(*cap) - sizeof(cap->optional); 70 if (len < cap_len) 71 return 1; 72 73 cap_len += ieee80211_he_mcs_set_size(cap->he_phy_capab_info); 74 if (len < cap_len) 75 return 1; 76 77 cap_len += ieee80211_he_ppet_size(buf[cap_len], cap->he_phy_capab_info); 78 79 return len != cap_len; 80 } 81 82 83 u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid, 84 enum ieee80211_op_mode opmode) 85 { 86 struct ieee80211_he_capabilities *cap; 87 struct hostapd_hw_modes *mode = hapd->iface->current_mode; 88 u8 he_oper_chwidth = ~HE_PHYCAP_CHANNEL_WIDTH_MASK; 89 u8 *pos = eid; 90 u8 ie_size = 0, mcs_nss_size = 4, ppet_size = 0; 91 92 if (!mode) 93 return eid; 94 95 ie_size = sizeof(*cap) - sizeof(cap->optional); 96 ppet_size = ieee80211_he_ppet_size(mode->he_capab[opmode].ppet[0], 97 mode->he_capab[opmode].phy_cap); 98 99 switch (hapd->iface->conf->he_oper_chwidth) { 100 case CHANWIDTH_80P80MHZ: 101 he_oper_chwidth |= 102 HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G; 103 mcs_nss_size += 4; 104 /* fall through */ 105 case CHANWIDTH_160MHZ: 106 he_oper_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G; 107 mcs_nss_size += 4; 108 /* fall through */ 109 case CHANWIDTH_80MHZ: 110 case CHANWIDTH_USE_HT: 111 he_oper_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G | 112 HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G; 113 break; 114 } 115 116 ie_size += mcs_nss_size + ppet_size; 117 118 *pos++ = WLAN_EID_EXTENSION; 119 *pos++ = 1 + ie_size; 120 *pos++ = WLAN_EID_EXT_HE_CAPABILITIES; 121 122 cap = (struct ieee80211_he_capabilities *) pos; 123 os_memset(cap, 0, sizeof(*cap)); 124 125 os_memcpy(cap->he_mac_capab_info, mode->he_capab[opmode].mac_cap, 126 HE_MAX_MAC_CAPAB_SIZE); 127 os_memcpy(cap->he_phy_capab_info, mode->he_capab[opmode].phy_cap, 128 HE_MAX_PHY_CAPAB_SIZE); 129 os_memcpy(cap->optional, mode->he_capab[opmode].mcs, mcs_nss_size); 130 if (ppet_size) 131 os_memcpy(&cap->optional[mcs_nss_size], 132 mode->he_capab[opmode].ppet, ppet_size); 133 134 if (hapd->iface->conf->he_phy_capab.he_su_beamformer) 135 cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMER_CAPAB_IDX] |= 136 HE_PHYCAP_SU_BEAMFORMER_CAPAB; 137 else 138 cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMER_CAPAB_IDX] &= 139 ~HE_PHYCAP_SU_BEAMFORMER_CAPAB; 140 141 if (hapd->iface->conf->he_phy_capab.he_su_beamformee) 142 cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMEE_CAPAB_IDX] |= 143 HE_PHYCAP_SU_BEAMFORMEE_CAPAB; 144 else 145 cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMEE_CAPAB_IDX] &= 146 ~HE_PHYCAP_SU_BEAMFORMEE_CAPAB; 147 148 if (hapd->iface->conf->he_phy_capab.he_mu_beamformer) 149 cap->he_phy_capab_info[HE_PHYCAP_MU_BEAMFORMER_CAPAB_IDX] |= 150 HE_PHYCAP_MU_BEAMFORMER_CAPAB; 151 else 152 cap->he_phy_capab_info[HE_PHYCAP_MU_BEAMFORMER_CAPAB_IDX] &= 153 ~HE_PHYCAP_MU_BEAMFORMER_CAPAB; 154 155 cap->he_phy_capab_info[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &= 156 he_oper_chwidth; 157 158 pos += ie_size; 159 160 return pos; 161 } 162 163 164 u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid) 165 { 166 struct ieee80211_he_operation *oper; 167 u8 *pos = eid; 168 int oper_size = 6; 169 u32 params = 0; 170 171 if (!hapd->iface->current_mode) 172 return eid; 173 174 if (is_6ghz_op_class(hapd->iconf->op_class)) 175 oper_size += 5; 176 177 *pos++ = WLAN_EID_EXTENSION; 178 *pos++ = 1 + oper_size; 179 *pos++ = WLAN_EID_EXT_HE_OPERATION; 180 181 oper = (struct ieee80211_he_operation *) pos; 182 os_memset(oper, 0, sizeof(*oper)); 183 184 if (hapd->iface->conf->he_op.he_default_pe_duration) 185 params |= (hapd->iface->conf->he_op.he_default_pe_duration << 186 HE_OPERATION_DFLT_PE_DURATION_OFFSET); 187 188 if (hapd->iface->conf->he_op.he_twt_required) 189 params |= HE_OPERATION_TWT_REQUIRED; 190 191 if (hapd->iface->conf->he_op.he_rts_threshold) 192 params |= (hapd->iface->conf->he_op.he_rts_threshold << 193 HE_OPERATION_RTS_THRESHOLD_OFFSET); 194 195 if (hapd->iface->conf->he_op.he_bss_color_disabled) 196 params |= HE_OPERATION_BSS_COLOR_DISABLED; 197 if (hapd->iface->conf->he_op.he_bss_color_partial) 198 params |= HE_OPERATION_BSS_COLOR_PARTIAL; 199 params |= hapd->iface->conf->he_op.he_bss_color << 200 HE_OPERATION_BSS_COLOR_OFFSET; 201 202 /* HE minimum required basic MCS and NSS for STAs */ 203 oper->he_mcs_nss_set = 204 host_to_le16(hapd->iface->conf->he_op.he_basic_mcs_nss_set); 205 206 /* TODO: conditional MaxBSSID Indicator subfield */ 207 208 pos += 6; /* skip the fixed part */ 209 210 if (is_6ghz_op_class(hapd->iconf->op_class)) { 211 u8 seg0 = hostapd_get_oper_centr_freq_seg0_idx(hapd->iconf); 212 u8 seg1 = hostapd_get_oper_centr_freq_seg1_idx(hapd->iconf); 213 214 if (!seg0) 215 seg0 = hapd->iconf->channel; 216 217 params |= HE_OPERATION_6GHZ_OPER_INFO; 218 219 /* 6 GHz Operation Information field 220 * IEEE P802.11ax/D8.0, 9.4.2.249 HE Operation element, 221 * Figure 9-788k 222 */ 223 *pos++ = hapd->iconf->channel; /* Primary Channel */ 224 225 /* Control: Channel Width */ 226 if (seg1) 227 *pos++ = 3; 228 else 229 *pos++ = center_idx_to_bw_6ghz(seg0); 230 231 /* Channel Center Freq Seg0/Seg1 */ 232 if (hapd->iconf->he_oper_chwidth == 2) { 233 /* 234 * Seg 0 indicates the channel center frequency index of 235 * the 160 MHz channel. 236 */ 237 seg1 = seg0; 238 if (hapd->iconf->channel < seg0) 239 seg0 -= 8; 240 else 241 seg0 += 8; 242 } 243 244 *pos++ = seg0; 245 *pos++ = seg1; 246 /* Minimum Rate */ 247 *pos++ = 6; /* TODO: what should be set here? */ 248 } 249 250 oper->he_oper_params = host_to_le32(params); 251 252 return pos; 253 } 254 255 256 u8 * hostapd_eid_he_mu_edca_parameter_set(struct hostapd_data *hapd, u8 *eid) 257 { 258 struct ieee80211_he_mu_edca_parameter_set *edca; 259 u8 *pos; 260 size_t i; 261 262 pos = (u8 *) &hapd->iface->conf->he_mu_edca; 263 for (i = 0; i < sizeof(*edca); i++) { 264 if (pos[i]) 265 break; 266 } 267 if (i == sizeof(*edca)) 268 return eid; /* no MU EDCA Parameters configured */ 269 270 pos = eid; 271 *pos++ = WLAN_EID_EXTENSION; 272 *pos++ = 1 + sizeof(*edca); 273 *pos++ = WLAN_EID_EXT_HE_MU_EDCA_PARAMS; 274 275 edca = (struct ieee80211_he_mu_edca_parameter_set *) pos; 276 os_memcpy(edca, &hapd->iface->conf->he_mu_edca, sizeof(*edca)); 277 278 wpa_hexdump(MSG_DEBUG, "HE: MU EDCA Parameter Set element", 279 pos, sizeof(*edca)); 280 281 pos += sizeof(*edca); 282 283 return pos; 284 } 285 286 287 u8 * hostapd_eid_spatial_reuse(struct hostapd_data *hapd, u8 *eid) 288 { 289 struct ieee80211_spatial_reuse *spr; 290 u8 *pos = eid, *spr_param; 291 u8 sz = 1; 292 293 if (!hapd->iface->conf->spr.sr_control) 294 return eid; 295 296 if (hapd->iface->conf->spr.sr_control & 297 SPATIAL_REUSE_NON_SRG_OFFSET_PRESENT) 298 sz++; 299 300 if (hapd->iface->conf->spr.sr_control & 301 SPATIAL_REUSE_SRG_INFORMATION_PRESENT) 302 sz += 18; 303 304 *pos++ = WLAN_EID_EXTENSION; 305 *pos++ = 1 + sz; 306 *pos++ = WLAN_EID_EXT_SPATIAL_REUSE; 307 308 spr = (struct ieee80211_spatial_reuse *) pos; 309 os_memset(spr, 0, sizeof(*spr)); 310 311 spr->sr_ctrl = hapd->iface->conf->spr.sr_control; 312 pos++; 313 spr_param = spr->params; 314 if (spr->sr_ctrl & SPATIAL_REUSE_NON_SRG_OFFSET_PRESENT) { 315 *spr_param++ = 316 hapd->iface->conf->spr.non_srg_obss_pd_max_offset; 317 pos++; 318 } 319 if (spr->sr_ctrl & SPATIAL_REUSE_SRG_INFORMATION_PRESENT) { 320 *spr_param++ = hapd->iface->conf->spr.srg_obss_pd_min_offset; 321 *spr_param++ = hapd->iface->conf->spr.srg_obss_pd_max_offset; 322 os_memcpy(spr_param, 323 hapd->iface->conf->spr.srg_bss_color_bitmap, 8); 324 spr_param += 8; 325 os_memcpy(spr_param, 326 hapd->iface->conf->spr.srg_partial_bssid_bitmap, 8); 327 pos += 18; 328 } 329 330 return pos; 331 } 332 333 334 u8 * hostapd_eid_he_6ghz_band_cap(struct hostapd_data *hapd, u8 *eid) 335 { 336 struct hostapd_config *conf = hapd->iface->conf; 337 struct hostapd_hw_modes *mode = hapd->iface->current_mode; 338 struct he_capabilities *he_cap; 339 struct ieee80211_he_6ghz_band_cap *cap; 340 u16 capab; 341 u8 *pos; 342 343 if (!mode || !is_6ghz_op_class(hapd->iconf->op_class) || 344 !is_6ghz_freq(hapd->iface->freq)) 345 return eid; 346 347 he_cap = &mode->he_capab[IEEE80211_MODE_AP]; 348 capab = he_cap->he_6ghz_capa & HE_6GHZ_BAND_CAP_MIN_MPDU_START; 349 capab |= (conf->he_6ghz_max_ampdu_len_exp << 350 HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_SHIFT) & 351 HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_MASK; 352 capab |= (conf->he_6ghz_max_mpdu << 353 HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_SHIFT) & 354 HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_MASK; 355 capab |= HE_6GHZ_BAND_CAP_SMPS_DISABLED; 356 if (conf->he_6ghz_rx_ant_pat) 357 capab |= HE_6GHZ_BAND_CAP_RX_ANTPAT_CONS; 358 if (conf->he_6ghz_tx_ant_pat) 359 capab |= HE_6GHZ_BAND_CAP_TX_ANTPAT_CONS; 360 361 pos = eid; 362 *pos++ = WLAN_EID_EXTENSION; 363 *pos++ = 1 + sizeof(*cap); 364 *pos++ = WLAN_EID_EXT_HE_6GHZ_BAND_CAP; 365 366 cap = (struct ieee80211_he_6ghz_band_cap *) pos; 367 cap->capab = host_to_le16(capab); 368 pos += sizeof(*cap); 369 370 return pos; 371 } 372 373 374 void hostapd_get_he_capab(struct hostapd_data *hapd, 375 const struct ieee80211_he_capabilities *he_cap, 376 struct ieee80211_he_capabilities *neg_he_cap, 377 size_t he_capab_len) 378 { 379 if (!he_cap) 380 return; 381 382 if (he_capab_len > sizeof(*neg_he_cap)) 383 he_capab_len = sizeof(*neg_he_cap); 384 /* TODO: mask out unsupported features */ 385 386 os_memcpy(neg_he_cap, he_cap, he_capab_len); 387 } 388 389 390 static int check_valid_he_mcs(struct hostapd_data *hapd, const u8 *sta_he_capab, 391 enum ieee80211_op_mode opmode) 392 { 393 u16 sta_rx_mcs_set, ap_tx_mcs_set; 394 u8 mcs_count = 0; 395 const u16 *ap_mcs_set, *sta_mcs_set; 396 int i; 397 398 if (!hapd->iface->current_mode) 399 return 1; 400 ap_mcs_set = (u16 *) hapd->iface->current_mode->he_capab[opmode].mcs; 401 sta_mcs_set = (u16 *) ((const struct ieee80211_he_capabilities *) 402 sta_he_capab)->optional; 403 404 /* 405 * Disable HE capabilities for STAs for which there is not even a single 406 * allowed MCS in any supported number of streams, i.e., STA is 407 * advertising 3 (not supported) as HE MCS rates for all supported 408 * band/stream cases. 409 */ 410 switch (hapd->iface->conf->he_oper_chwidth) { 411 case CHANWIDTH_80P80MHZ: 412 mcs_count = 3; 413 break; 414 case CHANWIDTH_160MHZ: 415 mcs_count = 2; 416 break; 417 default: 418 mcs_count = 1; 419 break; 420 } 421 422 for (i = 0; i < mcs_count; i++) { 423 int j; 424 425 /* AP Tx MCS map vs. STA Rx MCS map */ 426 sta_rx_mcs_set = WPA_GET_LE16((const u8 *) &sta_mcs_set[i * 2]); 427 ap_tx_mcs_set = WPA_GET_LE16((const u8 *) 428 &ap_mcs_set[(i * 2) + 1]); 429 430 for (j = 0; j < HE_NSS_MAX_STREAMS; j++) { 431 if (((ap_tx_mcs_set >> (j * 2)) & 0x3) == 3) 432 continue; 433 434 if (((sta_rx_mcs_set >> (j * 2)) & 0x3) == 3) 435 continue; 436 437 return 1; 438 } 439 } 440 441 wpa_printf(MSG_DEBUG, 442 "No matching HE MCS found between AP TX and STA RX"); 443 444 return 0; 445 } 446 447 448 u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta, 449 enum ieee80211_op_mode opmode, const u8 *he_capab, 450 size_t he_capab_len) 451 { 452 if (!he_capab || !(sta->flags & WLAN_STA_WMM) || 453 !hapd->iconf->ieee80211ax || hapd->conf->disable_11ax || 454 !check_valid_he_mcs(hapd, he_capab, opmode) || 455 ieee80211_invalid_he_cap_size(he_capab, he_capab_len) || 456 he_capab_len > sizeof(struct ieee80211_he_capabilities)) { 457 sta->flags &= ~WLAN_STA_HE; 458 os_free(sta->he_capab); 459 sta->he_capab = NULL; 460 return WLAN_STATUS_SUCCESS; 461 } 462 463 if (!sta->he_capab) { 464 sta->he_capab = 465 os_zalloc(sizeof(struct ieee80211_he_capabilities)); 466 if (!sta->he_capab) 467 return WLAN_STATUS_UNSPECIFIED_FAILURE; 468 } 469 470 sta->flags |= WLAN_STA_HE; 471 os_memset(sta->he_capab, 0, sizeof(struct ieee80211_he_capabilities)); 472 os_memcpy(sta->he_capab, he_capab, he_capab_len); 473 sta->he_capab_len = he_capab_len; 474 475 return WLAN_STATUS_SUCCESS; 476 } 477 478 479 u16 copy_sta_he_6ghz_capab(struct hostapd_data *hapd, struct sta_info *sta, 480 const u8 *he_6ghz_capab) 481 { 482 if (!he_6ghz_capab || !hapd->iconf->ieee80211ax || 483 hapd->conf->disable_11ax || 484 !is_6ghz_op_class(hapd->iconf->op_class)) { 485 sta->flags &= ~WLAN_STA_6GHZ; 486 os_free(sta->he_6ghz_capab); 487 sta->he_6ghz_capab = NULL; 488 return WLAN_STATUS_SUCCESS; 489 } 490 491 if (!sta->he_6ghz_capab) { 492 sta->he_6ghz_capab = 493 os_zalloc(sizeof(struct ieee80211_he_6ghz_band_cap)); 494 if (!sta->he_6ghz_capab) 495 return WLAN_STATUS_UNSPECIFIED_FAILURE; 496 } 497 498 sta->flags |= WLAN_STA_6GHZ; 499 os_memcpy(sta->he_6ghz_capab, he_6ghz_capab, 500 sizeof(struct ieee80211_he_6ghz_band_cap)); 501 502 return WLAN_STATUS_SUCCESS; 503 } 504 505 506 int hostapd_get_he_twt_responder(struct hostapd_data *hapd, 507 enum ieee80211_op_mode mode) 508 { 509 u8 *mac_cap; 510 511 if (!hapd->iface->current_mode || 512 !hapd->iface->current_mode->he_capab[mode].he_supported) 513 return 0; 514 515 mac_cap = hapd->iface->current_mode->he_capab[mode].mac_cap; 516 517 return !!(mac_cap[HE_MAC_CAPAB_0] & HE_MACCAP_TWT_RESPONDER) && 518 hapd->iface->conf->he_op.he_twt_responder; 519 } 520