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_er_su_disable) 196 params |= HE_OPERATION_ER_SU_DISABLE; 197 198 if (hapd->iface->conf->he_op.he_bss_color_disabled) 199 params |= HE_OPERATION_BSS_COLOR_DISABLED; 200 if (hapd->iface->conf->he_op.he_bss_color_partial) 201 params |= HE_OPERATION_BSS_COLOR_PARTIAL; 202 params |= hapd->iface->conf->he_op.he_bss_color << 203 HE_OPERATION_BSS_COLOR_OFFSET; 204 205 /* HE minimum required basic MCS and NSS for STAs */ 206 oper->he_mcs_nss_set = 207 host_to_le16(hapd->iface->conf->he_op.he_basic_mcs_nss_set); 208 209 /* TODO: conditional MaxBSSID Indicator subfield */ 210 211 pos += 6; /* skip the fixed part */ 212 213 if (is_6ghz_op_class(hapd->iconf->op_class)) { 214 u8 seg0 = hostapd_get_oper_centr_freq_seg0_idx(hapd->iconf); 215 u8 seg1 = hostapd_get_oper_centr_freq_seg1_idx(hapd->iconf); 216 217 if (!seg0) 218 seg0 = hapd->iconf->channel; 219 220 params |= HE_OPERATION_6GHZ_OPER_INFO; 221 222 /* 6 GHz Operation Information field 223 * IEEE P802.11ax/D8.0, 9.4.2.249 HE Operation element, 224 * Figure 9-788k 225 */ 226 *pos++ = hapd->iconf->channel; /* Primary Channel */ 227 228 /* Control: Channel Width */ 229 if (seg1) 230 *pos++ = 3; 231 else 232 *pos++ = center_idx_to_bw_6ghz(seg0); 233 234 /* Channel Center Freq Seg0/Seg1 */ 235 if (hapd->iconf->he_oper_chwidth == 2) { 236 /* 237 * Seg 0 indicates the channel center frequency index of 238 * the 160 MHz channel. 239 */ 240 seg1 = seg0; 241 if (hapd->iconf->channel < seg0) 242 seg0 -= 8; 243 else 244 seg0 += 8; 245 } 246 247 *pos++ = seg0; 248 *pos++ = seg1; 249 /* Minimum Rate */ 250 *pos++ = 6; /* TODO: what should be set here? */ 251 } 252 253 oper->he_oper_params = host_to_le32(params); 254 255 return pos; 256 } 257 258 259 u8 * hostapd_eid_he_mu_edca_parameter_set(struct hostapd_data *hapd, u8 *eid) 260 { 261 struct ieee80211_he_mu_edca_parameter_set *edca; 262 u8 *pos; 263 size_t i; 264 265 pos = (u8 *) &hapd->iface->conf->he_mu_edca; 266 for (i = 0; i < sizeof(*edca); i++) { 267 if (pos[i]) 268 break; 269 } 270 if (i == sizeof(*edca)) 271 return eid; /* no MU EDCA Parameters configured */ 272 273 pos = eid; 274 *pos++ = WLAN_EID_EXTENSION; 275 *pos++ = 1 + sizeof(*edca); 276 *pos++ = WLAN_EID_EXT_HE_MU_EDCA_PARAMS; 277 278 edca = (struct ieee80211_he_mu_edca_parameter_set *) pos; 279 os_memcpy(edca, &hapd->iface->conf->he_mu_edca, sizeof(*edca)); 280 281 wpa_hexdump(MSG_DEBUG, "HE: MU EDCA Parameter Set element", 282 pos, sizeof(*edca)); 283 284 pos += sizeof(*edca); 285 286 return pos; 287 } 288 289 290 u8 * hostapd_eid_spatial_reuse(struct hostapd_data *hapd, u8 *eid) 291 { 292 struct ieee80211_spatial_reuse *spr; 293 u8 *pos = eid, *spr_param; 294 u8 sz = 1; 295 296 if (!hapd->iface->conf->spr.sr_control) 297 return eid; 298 299 if (hapd->iface->conf->spr.sr_control & 300 SPATIAL_REUSE_NON_SRG_OFFSET_PRESENT) 301 sz++; 302 303 if (hapd->iface->conf->spr.sr_control & 304 SPATIAL_REUSE_SRG_INFORMATION_PRESENT) 305 sz += 18; 306 307 *pos++ = WLAN_EID_EXTENSION; 308 *pos++ = 1 + sz; 309 *pos++ = WLAN_EID_EXT_SPATIAL_REUSE; 310 311 spr = (struct ieee80211_spatial_reuse *) pos; 312 os_memset(spr, 0, sizeof(*spr)); 313 314 spr->sr_ctrl = hapd->iface->conf->spr.sr_control; 315 pos++; 316 spr_param = spr->params; 317 if (spr->sr_ctrl & SPATIAL_REUSE_NON_SRG_OFFSET_PRESENT) { 318 *spr_param++ = 319 hapd->iface->conf->spr.non_srg_obss_pd_max_offset; 320 pos++; 321 } 322 if (spr->sr_ctrl & SPATIAL_REUSE_SRG_INFORMATION_PRESENT) { 323 *spr_param++ = hapd->iface->conf->spr.srg_obss_pd_min_offset; 324 *spr_param++ = hapd->iface->conf->spr.srg_obss_pd_max_offset; 325 os_memcpy(spr_param, 326 hapd->iface->conf->spr.srg_bss_color_bitmap, 8); 327 spr_param += 8; 328 os_memcpy(spr_param, 329 hapd->iface->conf->spr.srg_partial_bssid_bitmap, 8); 330 pos += 18; 331 } 332 333 return pos; 334 } 335 336 337 u8 * hostapd_eid_he_6ghz_band_cap(struct hostapd_data *hapd, u8 *eid) 338 { 339 struct hostapd_config *conf = hapd->iface->conf; 340 struct hostapd_hw_modes *mode = hapd->iface->current_mode; 341 struct he_capabilities *he_cap; 342 struct ieee80211_he_6ghz_band_cap *cap; 343 u16 capab; 344 u8 *pos; 345 346 if (!mode || !is_6ghz_op_class(hapd->iconf->op_class) || 347 !is_6ghz_freq(hapd->iface->freq)) 348 return eid; 349 350 he_cap = &mode->he_capab[IEEE80211_MODE_AP]; 351 capab = he_cap->he_6ghz_capa & HE_6GHZ_BAND_CAP_MIN_MPDU_START; 352 capab |= (conf->he_6ghz_max_ampdu_len_exp << 353 HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_SHIFT) & 354 HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_MASK; 355 capab |= (conf->he_6ghz_max_mpdu << 356 HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_SHIFT) & 357 HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_MASK; 358 capab |= HE_6GHZ_BAND_CAP_SMPS_DISABLED; 359 if (conf->he_6ghz_rx_ant_pat) 360 capab |= HE_6GHZ_BAND_CAP_RX_ANTPAT_CONS; 361 if (conf->he_6ghz_tx_ant_pat) 362 capab |= HE_6GHZ_BAND_CAP_TX_ANTPAT_CONS; 363 364 pos = eid; 365 *pos++ = WLAN_EID_EXTENSION; 366 *pos++ = 1 + sizeof(*cap); 367 *pos++ = WLAN_EID_EXT_HE_6GHZ_BAND_CAP; 368 369 cap = (struct ieee80211_he_6ghz_band_cap *) pos; 370 cap->capab = host_to_le16(capab); 371 pos += sizeof(*cap); 372 373 return pos; 374 } 375 376 377 void hostapd_get_he_capab(struct hostapd_data *hapd, 378 const struct ieee80211_he_capabilities *he_cap, 379 struct ieee80211_he_capabilities *neg_he_cap, 380 size_t he_capab_len) 381 { 382 if (!he_cap) 383 return; 384 385 if (he_capab_len > sizeof(*neg_he_cap)) 386 he_capab_len = sizeof(*neg_he_cap); 387 /* TODO: mask out unsupported features */ 388 389 os_memcpy(neg_he_cap, he_cap, he_capab_len); 390 } 391 392 393 static int check_valid_he_mcs(struct hostapd_data *hapd, const u8 *sta_he_capab, 394 enum ieee80211_op_mode opmode) 395 { 396 u16 sta_rx_mcs_set, ap_tx_mcs_set; 397 u8 mcs_count = 0; 398 const u16 *ap_mcs_set, *sta_mcs_set; 399 int i; 400 401 if (!hapd->iface->current_mode) 402 return 1; 403 ap_mcs_set = (u16 *) hapd->iface->current_mode->he_capab[opmode].mcs; 404 sta_mcs_set = (u16 *) ((const struct ieee80211_he_capabilities *) 405 sta_he_capab)->optional; 406 407 /* 408 * Disable HE capabilities for STAs for which there is not even a single 409 * allowed MCS in any supported number of streams, i.e., STA is 410 * advertising 3 (not supported) as HE MCS rates for all supported 411 * band/stream cases. 412 */ 413 switch (hapd->iface->conf->he_oper_chwidth) { 414 case CHANWIDTH_80P80MHZ: 415 mcs_count = 3; 416 break; 417 case CHANWIDTH_160MHZ: 418 mcs_count = 2; 419 break; 420 default: 421 mcs_count = 1; 422 break; 423 } 424 425 for (i = 0; i < mcs_count; i++) { 426 int j; 427 428 /* AP Tx MCS map vs. STA Rx MCS map */ 429 sta_rx_mcs_set = WPA_GET_LE16((const u8 *) &sta_mcs_set[i * 2]); 430 ap_tx_mcs_set = WPA_GET_LE16((const u8 *) 431 &ap_mcs_set[(i * 2) + 1]); 432 433 for (j = 0; j < HE_NSS_MAX_STREAMS; j++) { 434 if (((ap_tx_mcs_set >> (j * 2)) & 0x3) == 3) 435 continue; 436 437 if (((sta_rx_mcs_set >> (j * 2)) & 0x3) == 3) 438 continue; 439 440 return 1; 441 } 442 } 443 444 wpa_printf(MSG_DEBUG, 445 "No matching HE MCS found between AP TX and STA RX"); 446 447 return 0; 448 } 449 450 451 u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta, 452 enum ieee80211_op_mode opmode, const u8 *he_capab, 453 size_t he_capab_len) 454 { 455 if (!he_capab || !(sta->flags & WLAN_STA_WMM) || 456 !hapd->iconf->ieee80211ax || hapd->conf->disable_11ax || 457 !check_valid_he_mcs(hapd, he_capab, opmode) || 458 ieee80211_invalid_he_cap_size(he_capab, he_capab_len) || 459 he_capab_len > sizeof(struct ieee80211_he_capabilities)) { 460 sta->flags &= ~WLAN_STA_HE; 461 os_free(sta->he_capab); 462 sta->he_capab = NULL; 463 return WLAN_STATUS_SUCCESS; 464 } 465 466 if (!sta->he_capab) { 467 sta->he_capab = 468 os_zalloc(sizeof(struct ieee80211_he_capabilities)); 469 if (!sta->he_capab) 470 return WLAN_STATUS_UNSPECIFIED_FAILURE; 471 } 472 473 sta->flags |= WLAN_STA_HE; 474 os_memset(sta->he_capab, 0, sizeof(struct ieee80211_he_capabilities)); 475 os_memcpy(sta->he_capab, he_capab, he_capab_len); 476 sta->he_capab_len = he_capab_len; 477 478 return WLAN_STATUS_SUCCESS; 479 } 480 481 482 u16 copy_sta_he_6ghz_capab(struct hostapd_data *hapd, struct sta_info *sta, 483 const u8 *he_6ghz_capab) 484 { 485 if (!he_6ghz_capab || !hapd->iconf->ieee80211ax || 486 hapd->conf->disable_11ax || 487 !is_6ghz_op_class(hapd->iconf->op_class)) { 488 sta->flags &= ~WLAN_STA_6GHZ; 489 os_free(sta->he_6ghz_capab); 490 sta->he_6ghz_capab = NULL; 491 return WLAN_STATUS_SUCCESS; 492 } 493 494 if (!sta->he_6ghz_capab) { 495 sta->he_6ghz_capab = 496 os_zalloc(sizeof(struct ieee80211_he_6ghz_band_cap)); 497 if (!sta->he_6ghz_capab) 498 return WLAN_STATUS_UNSPECIFIED_FAILURE; 499 } 500 501 sta->flags |= WLAN_STA_6GHZ; 502 os_memcpy(sta->he_6ghz_capab, he_6ghz_capab, 503 sizeof(struct ieee80211_he_6ghz_band_cap)); 504 505 return WLAN_STATUS_SUCCESS; 506 } 507 508 509 int hostapd_get_he_twt_responder(struct hostapd_data *hapd, 510 enum ieee80211_op_mode mode) 511 { 512 u8 *mac_cap; 513 514 if (!hapd->iface->current_mode || 515 !hapd->iface->current_mode->he_capab[mode].he_supported) 516 return 0; 517 518 mac_cap = hapd->iface->current_mode->he_capab[mode].mac_cap; 519 520 return !!(mac_cap[HE_MAC_CAPAB_0] & HE_MACCAP_TWT_RESPONDER) && 521 hapd->iface->conf->he_op.he_twt_responder; 522 } 523