1 /* 2 * hostapd / IEEE 802.11ac VHT 3 * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of BSD license 7 * 8 * See README and COPYING for more details. 9 */ 10 11 #include "utils/includes.h" 12 13 #include "utils/common.h" 14 #include "common/ieee802_11_defs.h" 15 #include "common/hw_features_common.h" 16 #include "hostapd.h" 17 #include "ap_config.h" 18 #include "sta_info.h" 19 #include "beacon.h" 20 #include "ieee802_11.h" 21 #include "dfs.h" 22 23 24 u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid, u32 nsts) 25 { 26 struct ieee80211_vht_capabilities *cap; 27 struct hostapd_hw_modes *mode = hapd->iface->current_mode; 28 u8 *pos = eid; 29 30 if (!mode || is_6ghz_op_class(hapd->iconf->op_class)) 31 return eid; 32 33 if (mode->mode == HOSTAPD_MODE_IEEE80211G && hapd->conf->vendor_vht && 34 mode->vht_capab == 0 && hapd->iface->hw_features) { 35 int i; 36 37 for (i = 0; i < hapd->iface->num_hw_features; i++) { 38 if (hapd->iface->hw_features[i].mode == 39 HOSTAPD_MODE_IEEE80211A) { 40 mode = &hapd->iface->hw_features[i]; 41 break; 42 } 43 } 44 } 45 46 *pos++ = WLAN_EID_VHT_CAP; 47 *pos++ = sizeof(*cap); 48 49 cap = (struct ieee80211_vht_capabilities *) pos; 50 os_memset(cap, 0, sizeof(*cap)); 51 cap->vht_capabilities_info = host_to_le32( 52 hapd->iface->conf->vht_capab); 53 54 if (nsts != 0) { 55 u32 hapd_nsts; 56 57 hapd_nsts = le_to_host32(cap->vht_capabilities_info); 58 hapd_nsts = (hapd_nsts >> VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7; 59 cap->vht_capabilities_info &= 60 ~(host_to_le32(hapd_nsts << 61 VHT_CAP_BEAMFORMEE_STS_OFFSET)); 62 cap->vht_capabilities_info |= 63 host_to_le32(nsts << VHT_CAP_BEAMFORMEE_STS_OFFSET); 64 } 65 66 /* Supported MCS set comes from hw */ 67 os_memcpy(&cap->vht_supported_mcs_set, mode->vht_mcs_set, 8); 68 69 pos += sizeof(*cap); 70 71 return pos; 72 } 73 74 75 u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid) 76 { 77 struct ieee80211_vht_operation *oper; 78 u8 *pos = eid; 79 enum oper_chan_width oper_chwidth = 80 hostapd_get_oper_chwidth(hapd->iconf); 81 u8 seg0 = hapd->iconf->vht_oper_centr_freq_seg0_idx; 82 u8 seg1 = hapd->iconf->vht_oper_centr_freq_seg1_idx; 83 #ifdef CONFIG_IEEE80211BE 84 u16 punct_bitmap = hostapd_get_punct_bitmap(hapd); 85 #endif /* CONFIG_IEEE80211BE */ 86 87 if (is_6ghz_op_class(hapd->iconf->op_class)) 88 return eid; 89 90 *pos++ = WLAN_EID_VHT_OPERATION; 91 *pos++ = sizeof(*oper); 92 93 oper = (struct ieee80211_vht_operation *) pos; 94 os_memset(oper, 0, sizeof(*oper)); 95 96 #ifdef CONFIG_IEEE80211BE 97 if (punct_bitmap) { 98 punct_update_legacy_bw(punct_bitmap, 99 hapd->iconf->channel, 100 &oper_chwidth, &seg0, &seg1); 101 } 102 #endif /* CONFIG_IEEE80211BE */ 103 104 /* 105 * center freq = 5 GHz + (5 * index) 106 * So index 42 gives center freq 5.210 GHz 107 * which is channel 42 in 5G band 108 */ 109 oper->vht_op_info_chan_center_freq_seg0_idx = seg0; 110 oper->vht_op_info_chan_center_freq_seg1_idx = seg1; 111 112 oper->vht_op_info_chwidth = oper_chwidth; 113 if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ) { 114 /* 115 * Convert 160 MHz channel width to new style as interop 116 * workaround. 117 */ 118 oper->vht_op_info_chwidth = CHANWIDTH_80MHZ; 119 oper->vht_op_info_chan_center_freq_seg1_idx = 120 oper->vht_op_info_chan_center_freq_seg0_idx; 121 if (hapd->iconf->channel < 122 hapd->iconf->vht_oper_centr_freq_seg0_idx) 123 oper->vht_op_info_chan_center_freq_seg0_idx -= 8; 124 else 125 oper->vht_op_info_chan_center_freq_seg0_idx += 8; 126 } else if (oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ) { 127 /* 128 * Convert 80+80 MHz channel width to new style as interop 129 * workaround. 130 */ 131 oper->vht_op_info_chwidth = CHANWIDTH_80MHZ; 132 } 133 134 /* VHT Basic MCS set comes from hw */ 135 /* Hard code 1 stream, MCS0-7 is a min Basic VHT MCS rates */ 136 oper->vht_basic_mcs_set = host_to_le16(0xfffc); 137 pos += sizeof(*oper); 138 139 return pos; 140 } 141 142 143 static int check_valid_vht_mcs(struct hostapd_hw_modes *mode, 144 const u8 *sta_vht_capab) 145 { 146 const struct ieee80211_vht_capabilities *vht_cap; 147 struct ieee80211_vht_capabilities ap_vht_cap; 148 u16 sta_rx_mcs_set, ap_tx_mcs_set; 149 int i; 150 151 if (!mode) 152 return 1; 153 154 /* 155 * Disable VHT caps for STAs for which there is not even a single 156 * allowed MCS in any supported number of streams, i.e., STA is 157 * advertising 3 (not supported) as VHT MCS rates for all supported 158 * stream cases. 159 */ 160 os_memcpy(&ap_vht_cap.vht_supported_mcs_set, mode->vht_mcs_set, 161 sizeof(ap_vht_cap.vht_supported_mcs_set)); 162 vht_cap = (const struct ieee80211_vht_capabilities *) sta_vht_capab; 163 164 /* AP Tx MCS map vs. STA Rx MCS map */ 165 sta_rx_mcs_set = le_to_host16(vht_cap->vht_supported_mcs_set.rx_map); 166 ap_tx_mcs_set = le_to_host16(ap_vht_cap.vht_supported_mcs_set.tx_map); 167 168 for (i = 0; i < VHT_RX_NSS_MAX_STREAMS; i++) { 169 if ((ap_tx_mcs_set & (0x3 << (i * 2))) == 3) 170 continue; 171 172 if ((sta_rx_mcs_set & (0x3 << (i * 2))) == 3) 173 continue; 174 175 return 1; 176 } 177 178 wpa_printf(MSG_DEBUG, 179 "No matching VHT MCS found between AP TX and STA RX"); 180 return 0; 181 } 182 183 184 u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta, 185 const u8 *vht_capab) 186 { 187 /* Disable VHT caps for STAs associated to no-VHT BSSes. */ 188 if (!vht_capab || !(sta->flags & WLAN_STA_WMM) || 189 !hapd->iconf->ieee80211ac || hapd->conf->disable_11ac || 190 !check_valid_vht_mcs(hapd->iface->current_mode, vht_capab)) { 191 sta->flags &= ~WLAN_STA_VHT; 192 os_free(sta->vht_capabilities); 193 sta->vht_capabilities = NULL; 194 return WLAN_STATUS_SUCCESS; 195 } 196 197 if (sta->vht_capabilities == NULL) { 198 sta->vht_capabilities = 199 os_zalloc(sizeof(struct ieee80211_vht_capabilities)); 200 if (sta->vht_capabilities == NULL) 201 return WLAN_STATUS_UNSPECIFIED_FAILURE; 202 } 203 204 sta->flags |= WLAN_STA_VHT; 205 os_memcpy(sta->vht_capabilities, vht_capab, 206 sizeof(struct ieee80211_vht_capabilities)); 207 208 return WLAN_STATUS_SUCCESS; 209 } 210 211 212 u16 copy_sta_vht_oper(struct hostapd_data *hapd, struct sta_info *sta, 213 const u8 *vht_oper) 214 { 215 if (!vht_oper) { 216 os_free(sta->vht_operation); 217 sta->vht_operation = NULL; 218 return WLAN_STATUS_SUCCESS; 219 } 220 221 if (!sta->vht_operation) { 222 sta->vht_operation = 223 os_zalloc(sizeof(struct ieee80211_vht_operation)); 224 if (!sta->vht_operation) 225 return WLAN_STATUS_UNSPECIFIED_FAILURE; 226 } 227 228 os_memcpy(sta->vht_operation, vht_oper, 229 sizeof(struct ieee80211_vht_operation)); 230 231 return WLAN_STATUS_SUCCESS; 232 } 233 234 235 u16 copy_sta_vendor_vht(struct hostapd_data *hapd, struct sta_info *sta, 236 const u8 *ie, size_t len) 237 { 238 const u8 *vht_capab; 239 unsigned int vht_capab_len; 240 241 if (!ie || len < 5 + 2 + sizeof(struct ieee80211_vht_capabilities) || 242 hapd->conf->disable_11ac) 243 goto no_capab; 244 245 /* The VHT Capabilities element embedded in vendor VHT */ 246 vht_capab = ie + 5; 247 if (vht_capab[0] != WLAN_EID_VHT_CAP) 248 goto no_capab; 249 vht_capab_len = vht_capab[1]; 250 if (vht_capab_len < sizeof(struct ieee80211_vht_capabilities) || 251 (int) vht_capab_len > ie + len - vht_capab - 2) 252 goto no_capab; 253 vht_capab += 2; 254 255 if (sta->vht_capabilities == NULL) { 256 sta->vht_capabilities = 257 os_zalloc(sizeof(struct ieee80211_vht_capabilities)); 258 if (sta->vht_capabilities == NULL) 259 return WLAN_STATUS_UNSPECIFIED_FAILURE; 260 } 261 262 sta->flags |= WLAN_STA_VHT | WLAN_STA_VENDOR_VHT; 263 os_memcpy(sta->vht_capabilities, vht_capab, 264 sizeof(struct ieee80211_vht_capabilities)); 265 return WLAN_STATUS_SUCCESS; 266 267 no_capab: 268 sta->flags &= ~WLAN_STA_VENDOR_VHT; 269 return WLAN_STATUS_SUCCESS; 270 } 271 272 273 u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid) 274 { 275 u8 *pos = eid; 276 277 /* Vendor VHT is applicable only to 2.4 GHz */ 278 if (!hapd->iface->current_mode || 279 hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G) 280 return eid; 281 282 *pos++ = WLAN_EID_VENDOR_SPECIFIC; 283 *pos++ = (5 + /* The Vendor OUI, type and subtype */ 284 2 + sizeof(struct ieee80211_vht_capabilities) + 285 2 + sizeof(struct ieee80211_vht_operation)); 286 287 WPA_PUT_BE32(pos, (OUI_BROADCOM << 8) | VENDOR_VHT_TYPE); 288 pos += 4; 289 *pos++ = VENDOR_VHT_SUBTYPE; 290 pos = hostapd_eid_vht_capabilities(hapd, pos, 0); 291 pos = hostapd_eid_vht_operation(hapd, pos); 292 293 return pos; 294 } 295 296 297 u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta, 298 const u8 *vht_oper_notif) 299 { 300 if (!vht_oper_notif) { 301 sta->flags &= ~WLAN_STA_VHT_OPMODE_ENABLED; 302 return WLAN_STATUS_SUCCESS; 303 } 304 305 sta->flags |= WLAN_STA_VHT_OPMODE_ENABLED; 306 sta->vht_opmode = *vht_oper_notif; 307 return WLAN_STATUS_SUCCESS; 308 } 309 310 311 void hostapd_get_vht_capab(struct hostapd_data *hapd, 312 struct ieee80211_vht_capabilities *vht_cap, 313 struct ieee80211_vht_capabilities *neg_vht_cap) 314 { 315 u32 cap, own_cap, sym_caps; 316 317 if (vht_cap == NULL) 318 return; 319 os_memcpy(neg_vht_cap, vht_cap, sizeof(*neg_vht_cap)); 320 321 cap = le_to_host32(neg_vht_cap->vht_capabilities_info); 322 own_cap = hapd->iconf->vht_capab; 323 324 /* mask out symmetric VHT capabilities we don't support */ 325 sym_caps = VHT_CAP_SHORT_GI_80 | VHT_CAP_SHORT_GI_160; 326 cap &= ~sym_caps | (own_cap & sym_caps); 327 328 /* mask out beamformer/beamformee caps if not supported */ 329 if (!(own_cap & VHT_CAP_SU_BEAMFORMER_CAPABLE)) 330 cap &= ~(VHT_CAP_SU_BEAMFORMEE_CAPABLE | 331 VHT_CAP_BEAMFORMEE_STS_MAX); 332 333 if (!(own_cap & VHT_CAP_SU_BEAMFORMEE_CAPABLE)) 334 cap &= ~(VHT_CAP_SU_BEAMFORMER_CAPABLE | 335 VHT_CAP_SOUNDING_DIMENSION_MAX); 336 337 if (!(own_cap & VHT_CAP_MU_BEAMFORMER_CAPABLE)) 338 cap &= ~VHT_CAP_MU_BEAMFORMEE_CAPABLE; 339 340 if (!(own_cap & VHT_CAP_MU_BEAMFORMEE_CAPABLE)) 341 cap &= ~VHT_CAP_MU_BEAMFORMER_CAPABLE; 342 343 /* mask channel widths we don't support */ 344 switch (own_cap & VHT_CAP_SUPP_CHAN_WIDTH_MASK) { 345 case VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ: 346 break; 347 case VHT_CAP_SUPP_CHAN_WIDTH_160MHZ: 348 if (cap & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) { 349 cap &= ~VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; 350 cap |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; 351 } 352 break; 353 default: 354 cap &= ~VHT_CAP_SUPP_CHAN_WIDTH_MASK; 355 break; 356 } 357 358 if (!(cap & VHT_CAP_SUPP_CHAN_WIDTH_MASK)) 359 cap &= ~VHT_CAP_SHORT_GI_160; 360 361 /* 362 * if we don't support RX STBC, mask out TX STBC in the STA's HT caps 363 * if we don't support TX STBC, mask out RX STBC in the STA's HT caps 364 */ 365 if (!(own_cap & VHT_CAP_RXSTBC_MASK)) 366 cap &= ~VHT_CAP_TXSTBC; 367 if (!(own_cap & VHT_CAP_TXSTBC)) 368 cap &= ~VHT_CAP_RXSTBC_MASK; 369 370 neg_vht_cap->vht_capabilities_info = host_to_le32(cap); 371 } 372