1 /* 2 * hostapd / IEEE 802.11ac VHT 3 * Copyright (c) 2002-2009, Jouni Malinen <j (at) 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 u8 *pos = eid; 26 27 if (!hapd->iconf->ieee80211ac || !hapd->iface->current_mode || 28 hapd->conf->disable_11ac) 29 return eid; 30 31 *pos++ = WLAN_EID_VHT_CAP; 32 *pos++ = sizeof(*cap); 33 34 cap = (struct ieee80211_vht_capabilities *) pos; 35 os_memset(cap, 0, sizeof(*cap)); 36 cap->vht_capabilities_info = host_to_le32( 37 hapd->iface->conf->vht_capab); 38 39 /* Supported MCS set comes from hw */ 40 os_memcpy(&cap->vht_supported_mcs_set, 41 hapd->iface->current_mode->vht_mcs_set, 8); 42 43 pos += sizeof(*cap); 44 45 return pos; 46 } 47 48 49 u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid) 50 { 51 struct ieee80211_vht_operation *oper; 52 u8 *pos = eid; 53 54 if (!hapd->iconf->ieee80211ac || hapd->conf->disable_11ac) 55 return eid; 56 57 *pos++ = WLAN_EID_VHT_OPERATION; 58 *pos++ = sizeof(*oper); 59 60 oper = (struct ieee80211_vht_operation *) pos; 61 os_memset(oper, 0, sizeof(*oper)); 62 63 /* 64 * center freq = 5 GHz + (5 * index) 65 * So index 42 gives center freq 5.210 GHz 66 * which is channel 42 in 5G band 67 */ 68 oper->vht_op_info_chan_center_freq_seg0_idx = 69 hapd->iconf->vht_oper_centr_freq_seg0_idx; 70 oper->vht_op_info_chan_center_freq_seg1_idx = 71 hapd->iconf->vht_oper_centr_freq_seg1_idx; 72 73 oper->vht_op_info_chwidth = hapd->iconf->vht_oper_chwidth; 74 75 /* VHT Basic MCS set comes from hw */ 76 /* Hard code 1 stream, MCS0-7 is a min Basic VHT MCS rates */ 77 oper->vht_basic_mcs_set = host_to_le16(0xfffc); 78 pos += sizeof(*oper); 79 80 return pos; 81 } 82 83 84 u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta, 85 const u8 *vht_capab, size_t vht_capab_len) 86 { 87 /* Disable VHT caps for STAs associated to no-VHT BSSes. */ 88 if (!vht_capab || 89 vht_capab_len < sizeof(struct ieee80211_vht_capabilities) || 90 hapd->conf->disable_11ac) { 91 sta->flags &= ~WLAN_STA_VHT; 92 os_free(sta->vht_capabilities); 93 sta->vht_capabilities = NULL; 94 return WLAN_STATUS_SUCCESS; 95 } 96 97 if (sta->vht_capabilities == NULL) { 98 sta->vht_capabilities = 99 os_zalloc(sizeof(struct ieee80211_vht_capabilities)); 100 if (sta->vht_capabilities == NULL) 101 return WLAN_STATUS_UNSPECIFIED_FAILURE; 102 } 103 104 sta->flags |= WLAN_STA_VHT; 105 os_memcpy(sta->vht_capabilities, vht_capab, 106 sizeof(struct ieee80211_vht_capabilities)); 107 108 return WLAN_STATUS_SUCCESS; 109 } 110 111 112 u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta, 113 const u8 *vht_oper_notif) 114 { 115 if (!vht_oper_notif) { 116 sta->flags &= ~WLAN_STA_VHT_OPMODE_ENABLED; 117 return WLAN_STATUS_SUCCESS; 118 } 119 120 sta->flags |= WLAN_STA_VHT_OPMODE_ENABLED; 121 sta->vht_opmode = *vht_oper_notif; 122 return WLAN_STATUS_SUCCESS; 123 } 124 125 126 void hostapd_get_vht_capab(struct hostapd_data *hapd, 127 struct ieee80211_vht_capabilities *vht_cap, 128 struct ieee80211_vht_capabilities *neg_vht_cap) 129 { 130 u32 cap, own_cap, sym_caps; 131 132 if (vht_cap == NULL) 133 return; 134 os_memcpy(neg_vht_cap, vht_cap, sizeof(*neg_vht_cap)); 135 136 cap = le_to_host32(neg_vht_cap->vht_capabilities_info); 137 own_cap = hapd->iconf->vht_capab; 138 139 /* mask out symmetric VHT capabilities we don't support */ 140 sym_caps = VHT_CAP_SHORT_GI_80 | VHT_CAP_SHORT_GI_160; 141 cap &= ~sym_caps | (own_cap & sym_caps); 142 143 /* mask out beamformer/beamformee caps if not supported */ 144 if (!(own_cap & VHT_CAP_SU_BEAMFORMER_CAPABLE)) 145 cap &= ~(VHT_CAP_SU_BEAMFORMEE_CAPABLE | 146 VHT_CAP_BEAMFORMEE_STS_MAX); 147 148 if (!(own_cap & VHT_CAP_SU_BEAMFORMEE_CAPABLE)) 149 cap &= ~(VHT_CAP_SU_BEAMFORMER_CAPABLE | 150 VHT_CAP_SOUNDING_DIMENSION_MAX); 151 152 if (!(own_cap & VHT_CAP_MU_BEAMFORMER_CAPABLE)) 153 cap &= ~VHT_CAP_MU_BEAMFORMEE_CAPABLE; 154 155 if (!(own_cap & VHT_CAP_MU_BEAMFORMEE_CAPABLE)) 156 cap &= ~VHT_CAP_MU_BEAMFORMER_CAPABLE; 157 158 /* mask channel widths we don't support */ 159 switch (own_cap & VHT_CAP_SUPP_CHAN_WIDTH_MASK) { 160 case VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ: 161 break; 162 case VHT_CAP_SUPP_CHAN_WIDTH_160MHZ: 163 if (cap & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) { 164 cap &= ~VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; 165 cap |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; 166 } 167 break; 168 default: 169 cap &= ~VHT_CAP_SUPP_CHAN_WIDTH_MASK; 170 break; 171 } 172 173 if (!(cap & VHT_CAP_SUPP_CHAN_WIDTH_MASK)) 174 cap &= ~VHT_CAP_SHORT_GI_160; 175 176 /* 177 * if we don't support RX STBC, mask out TX STBC in the STA's HT caps 178 * if we don't support TX STBC, mask out RX STBC in the STA's HT caps 179 */ 180 if (!(own_cap & VHT_CAP_RXSTBC_MASK)) 181 cap &= ~VHT_CAP_TXSTBC; 182 if (!(own_cap & VHT_CAP_TXSTBC)) 183 cap &= ~VHT_CAP_RXSTBC_MASK; 184 185 neg_vht_cap->vht_capabilities_info = host_to_le32(cap); 186 } 187