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 "hostapd.h" 15 #include "ap_config.h" 16 #include "beacon.h" 17 #include "sta_info.h" 18 #include "ieee802_11.h" 19 #include "dfs.h" 20 21 static u8 ieee80211_he_ppet_size(u8 ppe_thres_hdr, const u8 *phy_cap_info) 22 { 23 u8 sz = 0, ru; 24 25 if ((phy_cap_info[HE_PHYCAP_PPE_THRESHOLD_PRESENT_IDX] & 26 HE_PHYCAP_PPE_THRESHOLD_PRESENT) == 0) 27 return 0; 28 29 ru = (ppe_thres_hdr >> HE_PPE_THRES_RU_INDEX_BITMASK_SHIFT) & 30 HE_PPE_THRES_RU_INDEX_BITMASK_MASK; 31 while (ru) { 32 if (ru & 0x1) 33 sz++; 34 ru >>= 1; 35 } 36 37 sz *= 1 + (ppe_thres_hdr & HE_PPE_THRES_NSS_MASK); 38 sz = (sz * 6) + 7; 39 if (sz % 8) 40 sz += 8; 41 sz /= 8; 42 43 return sz; 44 } 45 46 47 u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid, 48 enum ieee80211_op_mode opmode) 49 { 50 struct ieee80211_he_capabilities *cap; 51 struct hostapd_hw_modes *mode = hapd->iface->current_mode; 52 u8 he_oper_chwidth = ~HE_PHYCAP_CHANNEL_WIDTH_MASK; 53 u8 *pos = eid; 54 u8 ie_size = 0, mcs_nss_size = 0, ppet_size = 0; 55 56 if (!mode) 57 return eid; 58 59 ie_size = sizeof(struct ieee80211_he_capabilities); 60 ppet_size = ieee80211_he_ppet_size(mode->he_capab[opmode].ppet[0], 61 mode->he_capab[opmode].phy_cap); 62 63 switch (hapd->iface->conf->he_oper_chwidth) { 64 case CHANWIDTH_80P80MHZ: 65 he_oper_chwidth |= 66 HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G; 67 mcs_nss_size += 4; 68 /* fall through */ 69 case CHANWIDTH_160MHZ: 70 he_oper_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G; 71 mcs_nss_size += 4; 72 /* fall through */ 73 case CHANWIDTH_80MHZ: 74 case CHANWIDTH_USE_HT: 75 he_oper_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G | 76 HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G; 77 mcs_nss_size += 4; 78 break; 79 } 80 81 ie_size += mcs_nss_size + ppet_size; 82 83 *pos++ = WLAN_EID_EXTENSION; 84 *pos++ = 1 + ie_size; 85 *pos++ = WLAN_EID_EXT_HE_CAPABILITIES; 86 87 cap = (struct ieee80211_he_capabilities *) pos; 88 os_memset(cap, 0, sizeof(*cap)); 89 90 os_memcpy(cap->he_mac_capab_info, mode->he_capab[opmode].mac_cap, 91 HE_MAX_MAC_CAPAB_SIZE); 92 os_memcpy(cap->he_phy_capab_info, mode->he_capab[opmode].phy_cap, 93 HE_MAX_PHY_CAPAB_SIZE); 94 os_memcpy(cap->optional, mode->he_capab[opmode].mcs, mcs_nss_size); 95 if (ppet_size) 96 os_memcpy(&cap->optional[mcs_nss_size], 97 mode->he_capab[opmode].ppet, ppet_size); 98 99 if (hapd->iface->conf->he_phy_capab.he_su_beamformer) 100 cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMER_CAPAB_IDX] |= 101 HE_PHYCAP_SU_BEAMFORMER_CAPAB; 102 else 103 cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMER_CAPAB_IDX] &= 104 ~HE_PHYCAP_SU_BEAMFORMER_CAPAB; 105 106 if (hapd->iface->conf->he_phy_capab.he_su_beamformee) 107 cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMEE_CAPAB_IDX] |= 108 HE_PHYCAP_SU_BEAMFORMEE_CAPAB; 109 else 110 cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMEE_CAPAB_IDX] &= 111 ~HE_PHYCAP_SU_BEAMFORMEE_CAPAB; 112 113 if (hapd->iface->conf->he_phy_capab.he_mu_beamformer) 114 cap->he_phy_capab_info[HE_PHYCAP_MU_BEAMFORMER_CAPAB_IDX] |= 115 HE_PHYCAP_MU_BEAMFORMER_CAPAB; 116 else 117 cap->he_phy_capab_info[HE_PHYCAP_MU_BEAMFORMER_CAPAB_IDX] &= 118 ~HE_PHYCAP_MU_BEAMFORMER_CAPAB; 119 120 cap->he_phy_capab_info[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &= 121 he_oper_chwidth; 122 123 pos += ie_size; 124 125 return pos; 126 } 127 128 129 u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid) 130 { 131 struct ieee80211_he_operation *oper; 132 u8 *pos = eid; 133 int oper_size = 6; 134 u32 params = 0; 135 136 if (!hapd->iface->current_mode) 137 return eid; 138 139 *pos++ = WLAN_EID_EXTENSION; 140 *pos++ = 1 + oper_size; 141 *pos++ = WLAN_EID_EXT_HE_OPERATION; 142 143 oper = (struct ieee80211_he_operation *) pos; 144 os_memset(oper, 0, sizeof(*oper)); 145 146 if (hapd->iface->conf->he_op.he_default_pe_duration) 147 params |= (hapd->iface->conf->he_op.he_default_pe_duration << 148 HE_OPERATION_DFLT_PE_DURATION_OFFSET); 149 150 if (hapd->iface->conf->he_op.he_twt_required) 151 params |= HE_OPERATION_TWT_REQUIRED; 152 153 if (hapd->iface->conf->he_op.he_rts_threshold) 154 params |= (hapd->iface->conf->he_op.he_rts_threshold << 155 HE_OPERATION_RTS_THRESHOLD_OFFSET); 156 157 if (hapd->iface->conf->he_op.he_bss_color) 158 params |= (hapd->iface->conf->he_op.he_bss_color << 159 HE_OPERATION_BSS_COLOR_OFFSET); 160 161 /* HE minimum required basic MCS and NSS for STAs */ 162 oper->he_mcs_nss_set = 163 host_to_le16(hapd->iface->conf->he_op.he_basic_mcs_nss_set); 164 165 /* TODO: conditional MaxBSSID Indicator subfield */ 166 167 oper->he_oper_params = host_to_le32(params); 168 169 pos += oper_size; 170 171 return pos; 172 } 173 174 175 u8 * hostapd_eid_he_mu_edca_parameter_set(struct hostapd_data *hapd, u8 *eid) 176 { 177 struct ieee80211_he_mu_edca_parameter_set *edca; 178 u8 *pos; 179 size_t i; 180 181 pos = (u8 *) &hapd->iface->conf->he_mu_edca; 182 for (i = 0; i < sizeof(*edca); i++) { 183 if (pos[i]) 184 break; 185 } 186 if (i == sizeof(*edca)) 187 return eid; /* no MU EDCA Parameters configured */ 188 189 pos = eid; 190 *pos++ = WLAN_EID_EXTENSION; 191 *pos++ = 1 + sizeof(*edca); 192 *pos++ = WLAN_EID_EXT_HE_MU_EDCA_PARAMS; 193 194 edca = (struct ieee80211_he_mu_edca_parameter_set *) pos; 195 os_memcpy(edca, &hapd->iface->conf->he_mu_edca, sizeof(*edca)); 196 197 wpa_hexdump(MSG_DEBUG, "HE: MU EDCA Parameter Set element", 198 pos, sizeof(*edca)); 199 200 pos += sizeof(*edca); 201 202 return pos; 203 } 204 205 206 u8 * hostapd_eid_spatial_reuse(struct hostapd_data *hapd, u8 *eid) 207 { 208 struct ieee80211_spatial_reuse *spr; 209 u8 *pos = eid, *spr_param; 210 u8 sz = 1; 211 212 if (!hapd->iface->conf->spr.sr_control) 213 return eid; 214 215 if (hapd->iface->conf->spr.sr_control & 216 SPATIAL_REUSE_NON_SRG_OFFSET_PRESENT) 217 sz++; 218 219 if (hapd->iface->conf->spr.sr_control & 220 SPATIAL_REUSE_SRG_INFORMATION_PRESENT) 221 sz += 18; 222 223 *pos++ = WLAN_EID_EXTENSION; 224 *pos++ = 1 + sz; 225 *pos++ = WLAN_EID_EXT_SPATIAL_REUSE; 226 227 spr = (struct ieee80211_spatial_reuse *) pos; 228 os_memset(spr, 0, sizeof(*spr)); 229 230 spr->sr_ctrl = hapd->iface->conf->spr.sr_control; 231 pos++; 232 spr_param = spr->params; 233 if (spr->sr_ctrl & SPATIAL_REUSE_NON_SRG_OFFSET_PRESENT) { 234 *spr_param++ = 235 hapd->iface->conf->spr.non_srg_obss_pd_max_offset; 236 pos++; 237 } 238 if (spr->sr_ctrl & SPATIAL_REUSE_SRG_INFORMATION_PRESENT) { 239 *spr_param++ = hapd->iface->conf->spr.srg_obss_pd_min_offset; 240 *spr_param++ = hapd->iface->conf->spr.srg_obss_pd_max_offset; 241 pos += 18; 242 } 243 244 return pos; 245 } 246 247 248 void hostapd_get_he_capab(struct hostapd_data *hapd, 249 const struct ieee80211_he_capabilities *he_cap, 250 struct ieee80211_he_capabilities *neg_he_cap, 251 size_t he_capab_len) 252 { 253 if (!he_cap) 254 return; 255 256 if (he_capab_len > sizeof(*neg_he_cap)) 257 he_capab_len = sizeof(*neg_he_cap); 258 /* TODO: mask out unsupported features */ 259 260 os_memcpy(neg_he_cap, he_cap, he_capab_len); 261 } 262 263 264 static int check_valid_he_mcs(struct hostapd_data *hapd, const u8 *sta_he_capab, 265 enum ieee80211_op_mode opmode) 266 { 267 u16 sta_rx_mcs_set, ap_tx_mcs_set; 268 u8 mcs_count = 0; 269 const u16 *ap_mcs_set, *sta_mcs_set; 270 int i; 271 272 if (!hapd->iface->current_mode) 273 return 1; 274 ap_mcs_set = (u16 *) hapd->iface->current_mode->he_capab[opmode].mcs; 275 sta_mcs_set = (u16 *) ((const struct ieee80211_he_capabilities *) 276 sta_he_capab)->optional; 277 278 /* 279 * Disable HE capabilities for STAs for which there is not even a single 280 * allowed MCS in any supported number of streams, i.e., STA is 281 * advertising 3 (not supported) as HE MCS rates for all supported 282 * band/stream cases. 283 */ 284 switch (hapd->iface->conf->he_oper_chwidth) { 285 case CHANWIDTH_80P80MHZ: 286 mcs_count = 3; 287 break; 288 case CHANWIDTH_160MHZ: 289 mcs_count = 2; 290 break; 291 default: 292 mcs_count = 1; 293 break; 294 } 295 296 for (i = 0; i < mcs_count; i++) { 297 int j; 298 299 /* AP Tx MCS map vs. STA Rx MCS map */ 300 sta_rx_mcs_set = WPA_GET_LE16((const u8 *) &sta_mcs_set[i * 2]); 301 ap_tx_mcs_set = WPA_GET_LE16((const u8 *) 302 &ap_mcs_set[(i * 2) + 1]); 303 304 for (j = 0; j < HE_NSS_MAX_STREAMS; j++) { 305 if (((ap_tx_mcs_set >> (j * 2)) & 0x3) == 3) 306 continue; 307 308 if (((sta_rx_mcs_set >> (j * 2)) & 0x3) == 3) 309 continue; 310 311 return 1; 312 } 313 } 314 315 wpa_printf(MSG_DEBUG, 316 "No matching HE MCS found between AP TX and STA RX"); 317 318 return 0; 319 } 320 321 322 u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta, 323 enum ieee80211_op_mode opmode, const u8 *he_capab, 324 size_t he_capab_len) 325 { 326 if (!he_capab || !hapd->iconf->ieee80211ax || 327 !check_valid_he_mcs(hapd, he_capab, opmode) || 328 he_capab_len > sizeof(struct ieee80211_he_capabilities)) { 329 sta->flags &= ~WLAN_STA_HE; 330 os_free(sta->he_capab); 331 sta->he_capab = NULL; 332 return WLAN_STATUS_SUCCESS; 333 } 334 335 if (!sta->he_capab) { 336 sta->he_capab = 337 os_zalloc(sizeof(struct ieee80211_he_capabilities)); 338 if (!sta->he_capab) 339 return WLAN_STATUS_UNSPECIFIED_FAILURE; 340 } 341 342 sta->flags |= WLAN_STA_HE; 343 os_memset(sta->he_capab, 0, sizeof(struct ieee80211_he_capabilities)); 344 os_memcpy(sta->he_capab, he_capab, he_capab_len); 345 sta->he_capab_len = he_capab_len; 346 347 return WLAN_STATUS_SUCCESS; 348 } 349