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