xref: /freebsd/contrib/wpa/src/ap/ieee802_11_vht.c (revision 71e72c9e91c4b8007a4292e09669e8b549c29e97)
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 "common/hw_features_common.h"
16 #include "hostapd.h"
17 #include "ap_config.h"
18 #include "sta_info.h"
19 #include "beacon.h"
20 #include "ieee802_11.h"
21 #include "dfs.h"
22 
23 
24 static struct hostapd_hw_modes *
mode_for_vht_capab(struct hostapd_data * hapd,struct hostapd_hw_modes * mode)25 mode_for_vht_capab(struct hostapd_data *hapd, struct hostapd_hw_modes *mode)
26 {
27 	if (mode->mode == HOSTAPD_MODE_IEEE80211G && hapd->conf->vendor_vht &&
28 	    mode->vht_capab == 0 && hapd->iface->hw_features) {
29 		int i;
30 
31 		for (i = 0; i < hapd->iface->num_hw_features; i++) {
32 			if (hapd->iface->hw_features[i].mode ==
33 			    HOSTAPD_MODE_IEEE80211A)
34 				return &hapd->iface->hw_features[i];
35 		}
36 	}
37 
38 	return mode;
39 }
40 
41 
hostapd_eid_vht_capabilities(struct hostapd_data * hapd,u8 * eid,u32 nsts)42 u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid, u32 nsts)
43 {
44 	struct ieee80211_vht_capabilities *cap;
45 	struct hostapd_hw_modes *mode = hapd->iface->current_mode;
46 	u8 *pos = eid;
47 
48 	if (!mode || is_6ghz_op_class(hapd->iconf->op_class))
49 		return eid;
50 
51 	mode = mode_for_vht_capab(hapd, mode);
52 
53 	*pos++ = WLAN_EID_VHT_CAP;
54 	*pos++ = sizeof(*cap);
55 
56 	cap = (struct ieee80211_vht_capabilities *) pos;
57 	os_memset(cap, 0, sizeof(*cap));
58 	cap->vht_capabilities_info = host_to_le32(
59 		hapd->iface->conf->vht_capab);
60 
61 	if (nsts != 0) {
62 		u32 hapd_nsts;
63 
64 		hapd_nsts = le_to_host32(cap->vht_capabilities_info);
65 		hapd_nsts = (hapd_nsts >> VHT_CAP_BEAMFORMEE_STS_OFFSET) & 7;
66 		cap->vht_capabilities_info &=
67 			~(host_to_le32(hapd_nsts <<
68 				       VHT_CAP_BEAMFORMEE_STS_OFFSET));
69 		cap->vht_capabilities_info |=
70 			host_to_le32(nsts << VHT_CAP_BEAMFORMEE_STS_OFFSET);
71 	}
72 
73 	/* Supported MCS set comes from hw */
74 	os_memcpy(&cap->vht_supported_mcs_set, mode->vht_mcs_set, 8);
75 
76 	pos += sizeof(*cap);
77 
78 	return pos;
79 }
80 
81 
hostapd_eid_vht_operation(struct hostapd_data * hapd,u8 * eid)82 u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
83 {
84 	struct ieee80211_vht_operation *oper;
85 	u8 *pos = eid;
86 	enum oper_chan_width oper_chwidth =
87 		hostapd_get_oper_chwidth(hapd->iconf);
88 	u8 seg0 = hapd->iconf->vht_oper_centr_freq_seg0_idx;
89 	u8 seg1 = hapd->iconf->vht_oper_centr_freq_seg1_idx;
90 #ifdef CONFIG_IEEE80211BE
91 	u16 punct_bitmap = hostapd_get_punct_bitmap(hapd);
92 #endif /* CONFIG_IEEE80211BE */
93 
94 	if (is_6ghz_op_class(hapd->iconf->op_class))
95 		return eid;
96 
97 	*pos++ = WLAN_EID_VHT_OPERATION;
98 	*pos++ = sizeof(*oper);
99 
100 	oper = (struct ieee80211_vht_operation *) pos;
101 	os_memset(oper, 0, sizeof(*oper));
102 
103 #ifdef CONFIG_IEEE80211BE
104 	if (punct_bitmap) {
105 		oper_chwidth = hostapd_get_oper_chwidth(hapd->iconf);
106 		seg0 = hostapd_get_oper_centr_freq_seg0_idx(hapd->iconf);
107 		seg1 = hostapd_get_oper_centr_freq_seg1_idx(hapd->iconf);
108 		punct_update_legacy_bw(punct_bitmap,
109 				       hapd->iconf->channel,
110 				       &oper_chwidth, &seg0, &seg1);
111 	}
112 #endif /* CONFIG_IEEE80211BE */
113 
114 	/*
115 	 * center freq = 5 GHz + (5 * index)
116 	 * So index 42 gives center freq 5.210 GHz
117 	 * which is channel 42 in 5G band
118 	 */
119 	oper->vht_op_info_chan_center_freq_seg0_idx = seg0;
120 	oper->vht_op_info_chan_center_freq_seg1_idx = seg1;
121 
122 	oper->vht_op_info_chwidth = oper_chwidth;
123 	if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ) {
124 		/*
125 		 * Convert 160 MHz channel width to new style as interop
126 		 * workaround.
127 		 */
128 		oper->vht_op_info_chwidth = CHANWIDTH_80MHZ;
129 		oper->vht_op_info_chan_center_freq_seg1_idx =
130 			oper->vht_op_info_chan_center_freq_seg0_idx;
131 		if (hapd->iconf->channel <
132 		    hapd->iconf->vht_oper_centr_freq_seg0_idx)
133 			oper->vht_op_info_chan_center_freq_seg0_idx -= 8;
134 		else
135 			oper->vht_op_info_chan_center_freq_seg0_idx += 8;
136 	} else if (oper_chwidth == CONF_OPER_CHWIDTH_80P80MHZ) {
137 		/*
138 		 * Convert 80+80 MHz channel width to new style as interop
139 		 * workaround.
140 		 */
141 		oper->vht_op_info_chwidth = CHANWIDTH_80MHZ;
142 	}
143 
144 	/* VHT Basic MCS set comes from hw */
145 	/* Hard code 1 stream, MCS0-7 is a min Basic VHT MCS rates */
146 	oper->vht_basic_mcs_set = host_to_le16(0xfffc);
147 	pos += sizeof(*oper);
148 
149 	return pos;
150 }
151 
152 
check_valid_vht_mcs(struct hostapd_data * hapd,const u8 * sta_vht_capab)153 static int check_valid_vht_mcs(struct hostapd_data *hapd,
154 			       const u8 *sta_vht_capab)
155 {
156 	struct hostapd_hw_modes *mode = hapd->iface->current_mode;
157 	const struct ieee80211_vht_capabilities *vht_cap;
158 	struct ieee80211_vht_capabilities ap_vht_cap;
159 	u16 sta_rx_mcs_set, ap_tx_mcs_set;
160 	int i;
161 
162 	if (!mode)
163 		return 1;
164 	mode = mode_for_vht_capab(hapd, mode);
165 
166 	/*
167 	 * Disable VHT caps for STAs for which there is not even a single
168 	 * allowed MCS in any supported number of streams, i.e., STA is
169 	 * advertising 3 (not supported) as VHT MCS rates for all supported
170 	 * stream cases.
171 	 */
172 	os_memcpy(&ap_vht_cap.vht_supported_mcs_set, mode->vht_mcs_set,
173 		  sizeof(ap_vht_cap.vht_supported_mcs_set));
174 	vht_cap = (const struct ieee80211_vht_capabilities *) sta_vht_capab;
175 
176 	/* AP Tx MCS map vs. STA Rx MCS map */
177 	sta_rx_mcs_set = le_to_host16(vht_cap->vht_supported_mcs_set.rx_map);
178 	ap_tx_mcs_set = le_to_host16(ap_vht_cap.vht_supported_mcs_set.tx_map);
179 
180 	for (i = 0; i < VHT_RX_NSS_MAX_STREAMS; i++) {
181 		if (((ap_tx_mcs_set >> (i * 2)) & 0x3) == 3)
182 			continue;
183 
184 		if (((sta_rx_mcs_set >> (i * 2)) & 0x3) == 3)
185 			continue;
186 
187 		return 1;
188 	}
189 
190 	wpa_printf(MSG_DEBUG,
191 		   "No matching VHT MCS found between AP TX and STA RX");
192 	return 0;
193 }
194 
195 
copy_sta_vht_capab(struct hostapd_data * hapd,struct sta_info * sta,const u8 * vht_capab)196 u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
197 		       const u8 *vht_capab)
198 {
199 	/* Disable VHT caps for STAs associated to no-VHT BSSes. */
200 	if (!vht_capab || !(sta->flags & WLAN_STA_WMM) ||
201 	    !hostapd_is_vht_enabled(hapd) ||
202 	    !check_valid_vht_mcs(hapd, vht_capab) ||
203 	    !(sta->flags & WLAN_STA_HT)) {
204 		sta->flags &= ~WLAN_STA_VHT;
205 		os_free(sta->vht_capabilities);
206 		sta->vht_capabilities = NULL;
207 		return WLAN_STATUS_SUCCESS;
208 	}
209 
210 	if (sta->vht_capabilities == NULL) {
211 		sta->vht_capabilities =
212 			os_zalloc(sizeof(struct ieee80211_vht_capabilities));
213 		if (sta->vht_capabilities == NULL)
214 			return WLAN_STATUS_UNSPECIFIED_FAILURE;
215 	}
216 
217 	sta->flags |= WLAN_STA_VHT;
218 	os_memcpy(sta->vht_capabilities, vht_capab,
219 		  sizeof(struct ieee80211_vht_capabilities));
220 
221 	return WLAN_STATUS_SUCCESS;
222 }
223 
224 
copy_sta_vht_oper(struct hostapd_data * hapd,struct sta_info * sta,const u8 * vht_oper)225 u16 copy_sta_vht_oper(struct hostapd_data *hapd, struct sta_info *sta,
226 		      const u8 *vht_oper)
227 {
228 	if (!vht_oper || !(sta->flags & WLAN_STA_VHT)) {
229 		os_free(sta->vht_operation);
230 		sta->vht_operation = NULL;
231 		return WLAN_STATUS_SUCCESS;
232 	}
233 
234 	if (!sta->vht_operation) {
235 		sta->vht_operation =
236 			os_zalloc(sizeof(struct ieee80211_vht_operation));
237 		if (!sta->vht_operation)
238 			return WLAN_STATUS_UNSPECIFIED_FAILURE;
239 	}
240 
241 	os_memcpy(sta->vht_operation, vht_oper,
242 		  sizeof(struct ieee80211_vht_operation));
243 
244 	return WLAN_STATUS_SUCCESS;
245 }
246 
247 
copy_sta_vendor_vht(struct hostapd_data * hapd,struct sta_info * sta,const u8 * ie,size_t len)248 u16 copy_sta_vendor_vht(struct hostapd_data *hapd, struct sta_info *sta,
249 			const u8 *ie, size_t len)
250 {
251 	const u8 *vht_capab;
252 	unsigned int vht_capab_len;
253 
254 	if (!ie || len < 5 + 2 + sizeof(struct ieee80211_vht_capabilities) ||
255 	    hapd->conf->disable_11ac)
256 		goto no_capab;
257 
258 	/* The VHT Capabilities element embedded in vendor VHT */
259 	vht_capab = ie + 5;
260 	if (vht_capab[0] != WLAN_EID_VHT_CAP)
261 		goto no_capab;
262 	vht_capab_len = vht_capab[1];
263 	if (vht_capab_len < sizeof(struct ieee80211_vht_capabilities) ||
264 	    (int) vht_capab_len > ie + len - vht_capab - 2)
265 		goto no_capab;
266 	vht_capab += 2;
267 
268 	if (sta->vht_capabilities == NULL) {
269 		sta->vht_capabilities =
270 			os_zalloc(sizeof(struct ieee80211_vht_capabilities));
271 		if (sta->vht_capabilities == NULL)
272 			return WLAN_STATUS_UNSPECIFIED_FAILURE;
273 	}
274 
275 	sta->flags |= WLAN_STA_VHT | WLAN_STA_VENDOR_VHT;
276 	os_memcpy(sta->vht_capabilities, vht_capab,
277 		  sizeof(struct ieee80211_vht_capabilities));
278 	return WLAN_STATUS_SUCCESS;
279 
280 no_capab:
281 	sta->flags &= ~WLAN_STA_VENDOR_VHT;
282 	return WLAN_STATUS_SUCCESS;
283 }
284 
285 
hostapd_eid_vendor_vht(struct hostapd_data * hapd,u8 * eid)286 u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid)
287 {
288 	u8 *pos = eid;
289 
290 	/* Vendor VHT is applicable only to 2.4 GHz */
291 	if (!hapd->iface->current_mode ||
292 	    hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
293 		return eid;
294 
295 	*pos++ = WLAN_EID_VENDOR_SPECIFIC;
296 	*pos++ = (5 +		/* The Vendor OUI, type and subtype */
297 		  2 + sizeof(struct ieee80211_vht_capabilities) +
298 		  2 + sizeof(struct ieee80211_vht_operation));
299 
300 	WPA_PUT_BE32(pos, (OUI_BROADCOM << 8) | VENDOR_VHT_TYPE);
301 	pos += 4;
302 	*pos++ = VENDOR_VHT_SUBTYPE;
303 	pos = hostapd_eid_vht_capabilities(hapd, pos, 0);
304 	pos = hostapd_eid_vht_operation(hapd, pos);
305 
306 	return pos;
307 }
308 
309 
set_sta_vht_opmode(struct hostapd_data * hapd,struct sta_info * sta,const u8 * vht_oper_notif)310 u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
311 		       const u8 *vht_oper_notif)
312 {
313 	if (!vht_oper_notif) {
314 		sta->flags &= ~WLAN_STA_VHT_OPMODE_ENABLED;
315 		return WLAN_STATUS_SUCCESS;
316 	}
317 
318 	sta->flags |= WLAN_STA_VHT_OPMODE_ENABLED;
319 	sta->vht_opmode = *vht_oper_notif;
320 	return WLAN_STATUS_SUCCESS;
321 }
322 
323 
hostapd_get_vht_capab(struct hostapd_data * hapd,struct ieee80211_vht_capabilities * vht_cap,struct ieee80211_vht_capabilities * neg_vht_cap)324 void hostapd_get_vht_capab(struct hostapd_data *hapd,
325 			   struct ieee80211_vht_capabilities *vht_cap,
326 			   struct ieee80211_vht_capabilities *neg_vht_cap)
327 {
328 	u32 cap, own_cap, sym_caps;
329 
330 	if (vht_cap == NULL)
331 		return;
332 	os_memcpy(neg_vht_cap, vht_cap, sizeof(*neg_vht_cap));
333 
334 	cap = le_to_host32(neg_vht_cap->vht_capabilities_info);
335 	own_cap = hapd->iconf->vht_capab;
336 
337 	/* mask out symmetric VHT capabilities we don't support */
338 	sym_caps = VHT_CAP_SHORT_GI_80 | VHT_CAP_SHORT_GI_160;
339 	cap &= ~sym_caps | (own_cap & sym_caps);
340 
341 	/* mask out beamformer/beamformee caps if not supported */
342 	if (!(own_cap & VHT_CAP_SU_BEAMFORMER_CAPABLE))
343 		cap &= ~(VHT_CAP_SU_BEAMFORMEE_CAPABLE |
344 			 VHT_CAP_BEAMFORMEE_STS_MAX);
345 
346 	if (!(own_cap & VHT_CAP_SU_BEAMFORMEE_CAPABLE))
347 		cap &= ~(VHT_CAP_SU_BEAMFORMER_CAPABLE |
348 			 VHT_CAP_SOUNDING_DIMENSION_MAX);
349 
350 	if (!(own_cap & VHT_CAP_MU_BEAMFORMER_CAPABLE))
351 		cap &= ~VHT_CAP_MU_BEAMFORMEE_CAPABLE;
352 
353 	if (!(own_cap & VHT_CAP_MU_BEAMFORMEE_CAPABLE))
354 		cap &= ~VHT_CAP_MU_BEAMFORMER_CAPABLE;
355 
356 	/* mask channel widths we don't support */
357 	switch (own_cap & VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
358 	case VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ:
359 		break;
360 	case VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
361 		if (cap & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) {
362 			cap &= ~VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
363 			cap |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
364 		}
365 		break;
366 	default:
367 		cap &= ~VHT_CAP_SUPP_CHAN_WIDTH_MASK;
368 		break;
369 	}
370 
371 	if (!(cap & VHT_CAP_SUPP_CHAN_WIDTH_MASK))
372 		cap &= ~VHT_CAP_SHORT_GI_160;
373 
374 	/*
375 	 * if we don't support RX STBC, mask out TX STBC in the STA's HT caps
376 	 * if we don't support TX STBC, mask out RX STBC in the STA's HT caps
377 	 */
378 	if (!(own_cap & VHT_CAP_RXSTBC_MASK))
379 		cap &= ~VHT_CAP_TXSTBC;
380 	if (!(own_cap & VHT_CAP_TXSTBC))
381 		cap &= ~VHT_CAP_RXSTBC_MASK;
382 
383 	neg_vht_cap->vht_capabilities_info = host_to_le32(cap);
384 }
385