Line data Source code
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 52 : u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid)
23 : {
24 : struct ieee80211_vht_capabilities *cap;
25 52 : struct hostapd_hw_modes *mode = hapd->iface->current_mode;
26 52 : u8 *pos = eid;
27 :
28 52 : if (!mode)
29 0 : return eid;
30 :
31 56 : if (mode->mode == HOSTAPD_MODE_IEEE80211G && hapd->conf->vendor_vht &&
32 4 : mode->vht_capab == 0 && hapd->iface->hw_features) {
33 : int i;
34 :
35 0 : for (i = 0; i < hapd->iface->num_hw_features; i++) {
36 0 : if (hapd->iface->hw_features[i].mode ==
37 : HOSTAPD_MODE_IEEE80211A) {
38 0 : mode = &hapd->iface->hw_features[i];
39 0 : break;
40 : }
41 : }
42 : }
43 :
44 52 : *pos++ = WLAN_EID_VHT_CAP;
45 52 : *pos++ = sizeof(*cap);
46 :
47 52 : cap = (struct ieee80211_vht_capabilities *) pos;
48 52 : os_memset(cap, 0, sizeof(*cap));
49 52 : cap->vht_capabilities_info = host_to_le32(
50 : hapd->iface->conf->vht_capab);
51 :
52 : /* Supported MCS set comes from hw */
53 52 : os_memcpy(&cap->vht_supported_mcs_set, mode->vht_mcs_set, 8);
54 :
55 52 : pos += sizeof(*cap);
56 :
57 52 : return pos;
58 : }
59 :
60 :
61 52 : u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
62 : {
63 : struct ieee80211_vht_operation *oper;
64 52 : u8 *pos = eid;
65 :
66 52 : *pos++ = WLAN_EID_VHT_OPERATION;
67 52 : *pos++ = sizeof(*oper);
68 :
69 52 : oper = (struct ieee80211_vht_operation *) pos;
70 52 : 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 52 : oper->vht_op_info_chan_center_freq_seg0_idx =
78 52 : hapd->iconf->vht_oper_centr_freq_seg0_idx;
79 52 : oper->vht_op_info_chan_center_freq_seg1_idx =
80 52 : hapd->iconf->vht_oper_centr_freq_seg1_idx;
81 :
82 52 : 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 52 : oper->vht_basic_mcs_set = host_to_le16(0xfffc);
87 52 : pos += sizeof(*oper);
88 :
89 52 : return pos;
90 : }
91 :
92 :
93 14 : 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 14 : if (!mode)
102 0 : 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 14 : os_memcpy(&ap_vht_cap.vht_supported_mcs_set, mode->vht_mcs_set,
111 : sizeof(ap_vht_cap.vht_supported_mcs_set));
112 14 : vht_cap = (const struct ieee80211_vht_capabilities *) sta_vht_capab;
113 :
114 : /* AP Tx MCS map vs. STA Rx MCS map */
115 14 : sta_rx_mcs_set = le_to_host16(vht_cap->vht_supported_mcs_set.rx_map);
116 14 : ap_tx_mcs_set = le_to_host16(ap_vht_cap.vht_supported_mcs_set.tx_map);
117 :
118 14 : for (i = 0; i < VHT_RX_NSS_MAX_STREAMS; i++) {
119 14 : if ((ap_tx_mcs_set & (0x3 << (i * 2))) == 3)
120 0 : continue;
121 :
122 14 : if ((sta_rx_mcs_set & (0x3 << (i * 2))) == 3)
123 0 : continue;
124 :
125 14 : return 1;
126 : }
127 :
128 0 : wpa_printf(MSG_DEBUG,
129 : "No matching VHT MCS found between AP TX and STA RX");
130 0 : return 0;
131 : }
132 :
133 :
134 2154 : 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 2154 : if (!vht_capab ||
139 14 : vht_capab_len < sizeof(struct ieee80211_vht_capabilities) ||
140 28 : hapd->conf->disable_11ac ||
141 14 : !check_valid_vht_mcs(hapd->iface->current_mode, vht_capab)) {
142 2140 : sta->flags &= ~WLAN_STA_VHT;
143 2140 : os_free(sta->vht_capabilities);
144 2140 : sta->vht_capabilities = NULL;
145 2140 : return WLAN_STATUS_SUCCESS;
146 : }
147 :
148 14 : if (sta->vht_capabilities == NULL) {
149 14 : sta->vht_capabilities =
150 14 : os_zalloc(sizeof(struct ieee80211_vht_capabilities));
151 14 : if (sta->vht_capabilities == NULL)
152 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
153 : }
154 :
155 14 : sta->flags |= WLAN_STA_VHT;
156 14 : os_memcpy(sta->vht_capabilities, vht_capab,
157 : sizeof(struct ieee80211_vht_capabilities));
158 :
159 14 : return WLAN_STATUS_SUCCESS;
160 : }
161 :
162 :
163 2 : 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 3 : if (!ie || len < 5 + 2 + sizeof(struct ieee80211_vht_capabilities) ||
170 1 : hapd->conf->disable_11ac)
171 : goto no_capab;
172 :
173 : /* The VHT Capabilities element embedded in vendor VHT */
174 1 : vht_capab = ie + 5;
175 1 : if (vht_capab[0] != WLAN_EID_VHT_CAP)
176 0 : goto no_capab;
177 1 : vht_capab_len = vht_capab[1];
178 2 : if (vht_capab_len < sizeof(struct ieee80211_vht_capabilities) ||
179 1 : (int) vht_capab_len > ie + len - vht_capab - 2)
180 : goto no_capab;
181 1 : vht_capab += 2;
182 :
183 1 : if (sta->vht_capabilities == NULL) {
184 1 : sta->vht_capabilities =
185 1 : os_zalloc(sizeof(struct ieee80211_vht_capabilities));
186 1 : if (sta->vht_capabilities == NULL)
187 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
188 : }
189 :
190 1 : sta->flags |= WLAN_STA_VHT | WLAN_STA_VENDOR_VHT;
191 1 : os_memcpy(sta->vht_capabilities, vht_capab,
192 : sizeof(struct ieee80211_vht_capabilities));
193 1 : return WLAN_STATUS_SUCCESS;
194 :
195 : no_capab:
196 1 : sta->flags &= ~WLAN_STA_VENDOR_VHT;
197 1 : return WLAN_STATUS_SUCCESS;
198 : }
199 :
200 :
201 4 : u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid)
202 : {
203 4 : u8 *pos = eid;
204 :
205 4 : if (!hapd->iface->current_mode)
206 0 : return eid;
207 :
208 4 : *pos++ = WLAN_EID_VENDOR_SPECIFIC;
209 4 : *pos++ = (5 + /* The Vendor OUI, type and subtype */
210 : 2 + sizeof(struct ieee80211_vht_capabilities) +
211 : 2 + sizeof(struct ieee80211_vht_operation));
212 :
213 4 : WPA_PUT_BE32(pos, (OUI_BROADCOM << 8) | VENDOR_VHT_TYPE);
214 4 : pos += 4;
215 4 : *pos++ = VENDOR_VHT_SUBTYPE;
216 4 : pos = hostapd_eid_vht_capabilities(hapd, pos);
217 4 : pos = hostapd_eid_vht_operation(hapd, pos);
218 :
219 4 : return pos;
220 : }
221 :
222 :
223 2154 : u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
224 : const u8 *vht_oper_notif)
225 : {
226 2154 : if (!vht_oper_notif) {
227 2154 : sta->flags &= ~WLAN_STA_VHT_OPMODE_ENABLED;
228 2154 : return WLAN_STATUS_SUCCESS;
229 : }
230 :
231 0 : sta->flags |= WLAN_STA_VHT_OPMODE_ENABLED;
232 0 : sta->vht_opmode = *vht_oper_notif;
233 0 : return WLAN_STATUS_SUCCESS;
234 : }
235 :
236 :
237 15 : 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 15 : if (vht_cap == NULL)
244 15 : return;
245 15 : os_memcpy(neg_vht_cap, vht_cap, sizeof(*neg_vht_cap));
246 :
247 15 : cap = le_to_host32(neg_vht_cap->vht_capabilities_info);
248 15 : own_cap = hapd->iconf->vht_capab;
249 :
250 : /* mask out symmetric VHT capabilities we don't support */
251 15 : sym_caps = VHT_CAP_SHORT_GI_80 | VHT_CAP_SHORT_GI_160;
252 15 : cap &= ~sym_caps | (own_cap & sym_caps);
253 :
254 : /* mask out beamformer/beamformee caps if not supported */
255 15 : if (!(own_cap & VHT_CAP_SU_BEAMFORMER_CAPABLE))
256 15 : cap &= ~(VHT_CAP_SU_BEAMFORMEE_CAPABLE |
257 : VHT_CAP_BEAMFORMEE_STS_MAX);
258 :
259 15 : if (!(own_cap & VHT_CAP_SU_BEAMFORMEE_CAPABLE))
260 15 : cap &= ~(VHT_CAP_SU_BEAMFORMER_CAPABLE |
261 : VHT_CAP_SOUNDING_DIMENSION_MAX);
262 :
263 15 : if (!(own_cap & VHT_CAP_MU_BEAMFORMER_CAPABLE))
264 15 : cap &= ~VHT_CAP_MU_BEAMFORMEE_CAPABLE;
265 :
266 15 : if (!(own_cap & VHT_CAP_MU_BEAMFORMEE_CAPABLE))
267 15 : cap &= ~VHT_CAP_MU_BEAMFORMER_CAPABLE;
268 :
269 : /* mask channel widths we don't support */
270 15 : switch (own_cap & VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
271 : case VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ:
272 0 : break;
273 : case VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
274 0 : if (cap & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) {
275 0 : cap &= ~VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
276 0 : cap |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
277 : }
278 0 : break;
279 : default:
280 15 : cap &= ~VHT_CAP_SUPP_CHAN_WIDTH_MASK;
281 15 : break;
282 : }
283 :
284 15 : if (!(cap & VHT_CAP_SUPP_CHAN_WIDTH_MASK))
285 15 : 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 15 : if (!(own_cap & VHT_CAP_RXSTBC_MASK))
292 14 : cap &= ~VHT_CAP_TXSTBC;
293 15 : if (!(own_cap & VHT_CAP_TXSTBC))
294 14 : cap &= ~VHT_CAP_RXSTBC_MASK;
295 :
296 15 : neg_vht_cap->vht_capabilities_info = host_to_le32(cap);
297 : }
|