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