xref: /freebsd/contrib/wpa/src/ap/ieee802_11_vht.c (revision d4eeb02986980bf33dd56c41ceb9fc5f180c0d47)
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