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