xref: /freebsd/contrib/wpa/src/ap/ieee802_11_he.c (revision 19261079)
1 /*
2  * hostapd / IEEE 802.11ax HE
3  * Copyright (c) 2016-2017, Qualcomm Atheros, Inc.
4  * Copyright (c) 2019 John Crispin <john@phrozen.org>
5  *
6  * This software may be distributed under the terms of the BSD license.
7  * See README for more details.
8  */
9 
10 #include "utils/includes.h"
11 
12 #include "utils/common.h"
13 #include "common/ieee802_11_defs.h"
14 #include "common/ieee802_11_common.h"
15 #include "hostapd.h"
16 #include "ap_config.h"
17 #include "beacon.h"
18 #include "sta_info.h"
19 #include "ieee802_11.h"
20 #include "dfs.h"
21 
22 static u8 ieee80211_he_ppet_size(u8 ppe_thres_hdr, const u8 *phy_cap_info)
23 {
24 	u8 sz = 0, ru;
25 
26 	if ((phy_cap_info[HE_PHYCAP_PPE_THRESHOLD_PRESENT_IDX] &
27 	     HE_PHYCAP_PPE_THRESHOLD_PRESENT) == 0)
28 		return 0;
29 
30 	ru = (ppe_thres_hdr >> HE_PPE_THRES_RU_INDEX_BITMASK_SHIFT) &
31 		HE_PPE_THRES_RU_INDEX_BITMASK_MASK;
32 	while (ru) {
33 		if (ru & 0x1)
34 			sz++;
35 		ru >>= 1;
36 	}
37 
38 	sz *= 1 + (ppe_thres_hdr & HE_PPE_THRES_NSS_MASK);
39 	sz = (sz * 6) + 7;
40 	if (sz % 8)
41 		sz += 8;
42 	sz /= 8;
43 
44 	return sz;
45 }
46 
47 
48 static u8 ieee80211_he_mcs_set_size(const u8 *phy_cap_info)
49 {
50 	u8 sz = 4;
51 
52 	if (phy_cap_info[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
53 	    HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)
54 		sz += 4;
55 	if (phy_cap_info[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &
56 	    HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G)
57 		sz += 4;
58 
59 	return sz;
60 }
61 
62 
63 static int ieee80211_invalid_he_cap_size(const u8 *buf, size_t len)
64 {
65 	struct ieee80211_he_capabilities *cap;
66 	size_t cap_len;
67 
68 	cap = (struct ieee80211_he_capabilities *) buf;
69 	cap_len = sizeof(*cap) - sizeof(cap->optional);
70 	if (len < cap_len)
71 		return 1;
72 
73 	cap_len += ieee80211_he_mcs_set_size(cap->he_phy_capab_info);
74 	if (len < cap_len)
75 		return 1;
76 
77 	cap_len += ieee80211_he_ppet_size(buf[cap_len], cap->he_phy_capab_info);
78 
79 	return len != cap_len;
80 }
81 
82 
83 u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid,
84 			  enum ieee80211_op_mode opmode)
85 {
86 	struct ieee80211_he_capabilities *cap;
87 	struct hostapd_hw_modes *mode = hapd->iface->current_mode;
88 	u8 he_oper_chwidth = ~HE_PHYCAP_CHANNEL_WIDTH_MASK;
89 	u8 *pos = eid;
90 	u8 ie_size = 0, mcs_nss_size = 4, ppet_size = 0;
91 
92 	if (!mode)
93 		return eid;
94 
95 	ie_size = sizeof(*cap) - sizeof(cap->optional);
96 	ppet_size = ieee80211_he_ppet_size(mode->he_capab[opmode].ppet[0],
97 					   mode->he_capab[opmode].phy_cap);
98 
99 	switch (hapd->iface->conf->he_oper_chwidth) {
100 	case CHANWIDTH_80P80MHZ:
101 		he_oper_chwidth |=
102 			HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G;
103 		mcs_nss_size += 4;
104 		/* fall through */
105 	case CHANWIDTH_160MHZ:
106 		he_oper_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
107 		mcs_nss_size += 4;
108 		/* fall through */
109 	case CHANWIDTH_80MHZ:
110 	case CHANWIDTH_USE_HT:
111 		he_oper_chwidth |= HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G |
112 			HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G;
113 		break;
114 	}
115 
116 	ie_size += mcs_nss_size + ppet_size;
117 
118 	*pos++ = WLAN_EID_EXTENSION;
119 	*pos++ = 1 + ie_size;
120 	*pos++ = WLAN_EID_EXT_HE_CAPABILITIES;
121 
122 	cap = (struct ieee80211_he_capabilities *) pos;
123 	os_memset(cap, 0, sizeof(*cap));
124 
125 	os_memcpy(cap->he_mac_capab_info, mode->he_capab[opmode].mac_cap,
126 		  HE_MAX_MAC_CAPAB_SIZE);
127 	os_memcpy(cap->he_phy_capab_info, mode->he_capab[opmode].phy_cap,
128 		  HE_MAX_PHY_CAPAB_SIZE);
129 	os_memcpy(cap->optional, mode->he_capab[opmode].mcs, mcs_nss_size);
130 	if (ppet_size)
131 		os_memcpy(&cap->optional[mcs_nss_size],
132 			  mode->he_capab[opmode].ppet,  ppet_size);
133 
134 	if (hapd->iface->conf->he_phy_capab.he_su_beamformer)
135 		cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMER_CAPAB_IDX] |=
136 			HE_PHYCAP_SU_BEAMFORMER_CAPAB;
137 	else
138 		cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMER_CAPAB_IDX] &=
139 			~HE_PHYCAP_SU_BEAMFORMER_CAPAB;
140 
141 	if (hapd->iface->conf->he_phy_capab.he_su_beamformee)
142 		cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMEE_CAPAB_IDX] |=
143 			HE_PHYCAP_SU_BEAMFORMEE_CAPAB;
144 	else
145 		cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMEE_CAPAB_IDX] &=
146 			~HE_PHYCAP_SU_BEAMFORMEE_CAPAB;
147 
148 	if (hapd->iface->conf->he_phy_capab.he_mu_beamformer)
149 		cap->he_phy_capab_info[HE_PHYCAP_MU_BEAMFORMER_CAPAB_IDX] |=
150 			HE_PHYCAP_MU_BEAMFORMER_CAPAB;
151 	else
152 		cap->he_phy_capab_info[HE_PHYCAP_MU_BEAMFORMER_CAPAB_IDX] &=
153 			~HE_PHYCAP_MU_BEAMFORMER_CAPAB;
154 
155 	cap->he_phy_capab_info[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] &=
156 		he_oper_chwidth;
157 
158 	pos += ie_size;
159 
160 	return pos;
161 }
162 
163 
164 u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid)
165 {
166 	struct ieee80211_he_operation *oper;
167 	u8 *pos = eid;
168 	int oper_size = 6;
169 	u32 params = 0;
170 
171 	if (!hapd->iface->current_mode)
172 		return eid;
173 
174 	if (is_6ghz_op_class(hapd->iconf->op_class))
175 		oper_size += 5;
176 
177 	*pos++ = WLAN_EID_EXTENSION;
178 	*pos++ = 1 + oper_size;
179 	*pos++ = WLAN_EID_EXT_HE_OPERATION;
180 
181 	oper = (struct ieee80211_he_operation *) pos;
182 	os_memset(oper, 0, sizeof(*oper));
183 
184 	if (hapd->iface->conf->he_op.he_default_pe_duration)
185 		params |= (hapd->iface->conf->he_op.he_default_pe_duration <<
186 			   HE_OPERATION_DFLT_PE_DURATION_OFFSET);
187 
188 	if (hapd->iface->conf->he_op.he_twt_required)
189 		params |= HE_OPERATION_TWT_REQUIRED;
190 
191 	if (hapd->iface->conf->he_op.he_rts_threshold)
192 		params |= (hapd->iface->conf->he_op.he_rts_threshold <<
193 			   HE_OPERATION_RTS_THRESHOLD_OFFSET);
194 
195 	if (hapd->iface->conf->he_op.he_bss_color_disabled)
196 		params |= HE_OPERATION_BSS_COLOR_DISABLED;
197 	if (hapd->iface->conf->he_op.he_bss_color_partial)
198 		params |= HE_OPERATION_BSS_COLOR_PARTIAL;
199 	params |= hapd->iface->conf->he_op.he_bss_color <<
200 		HE_OPERATION_BSS_COLOR_OFFSET;
201 
202 	/* HE minimum required basic MCS and NSS for STAs */
203 	oper->he_mcs_nss_set =
204 		host_to_le16(hapd->iface->conf->he_op.he_basic_mcs_nss_set);
205 
206 	/* TODO: conditional MaxBSSID Indicator subfield */
207 
208 	pos += 6; /* skip the fixed part */
209 
210 	if (is_6ghz_op_class(hapd->iconf->op_class)) {
211 		u8 seg0 = hostapd_get_oper_centr_freq_seg0_idx(hapd->iconf);
212 		u8 seg1 = hostapd_get_oper_centr_freq_seg1_idx(hapd->iconf);
213 
214 		if (!seg0)
215 			seg0 = hapd->iconf->channel;
216 
217 		params |= HE_OPERATION_6GHZ_OPER_INFO;
218 
219 		/* 6 GHz Operation Information field
220 		 * IEEE P802.11ax/D8.0, 9.4.2.249 HE Operation element,
221 		 * Figure 9-788k
222 		 */
223 		*pos++ = hapd->iconf->channel; /* Primary Channel */
224 
225 		/* Control: Channel Width */
226 		if (seg1)
227 			*pos++ = 3;
228 		else
229 			*pos++ = center_idx_to_bw_6ghz(seg0);
230 
231 		/* Channel Center Freq Seg0/Seg1 */
232 		if (hapd->iconf->he_oper_chwidth == 2) {
233 			/*
234 			 * Seg 0 indicates the channel center frequency index of
235 			 * the 160 MHz channel.
236 			 */
237 			seg1 = seg0;
238 			if (hapd->iconf->channel < seg0)
239 				seg0 -= 8;
240 			else
241 				seg0 += 8;
242 		}
243 
244 		*pos++ = seg0;
245 		*pos++ = seg1;
246 		/* Minimum Rate */
247 		*pos++ = 6; /* TODO: what should be set here? */
248 	}
249 
250 	oper->he_oper_params = host_to_le32(params);
251 
252 	return pos;
253 }
254 
255 
256 u8 * hostapd_eid_he_mu_edca_parameter_set(struct hostapd_data *hapd, u8 *eid)
257 {
258 	struct ieee80211_he_mu_edca_parameter_set *edca;
259 	u8 *pos;
260 	size_t i;
261 
262 	pos = (u8 *) &hapd->iface->conf->he_mu_edca;
263 	for (i = 0; i < sizeof(*edca); i++) {
264 		if (pos[i])
265 			break;
266 	}
267 	if (i == sizeof(*edca))
268 		return eid; /* no MU EDCA Parameters configured */
269 
270 	pos = eid;
271 	*pos++ = WLAN_EID_EXTENSION;
272 	*pos++ = 1 + sizeof(*edca);
273 	*pos++ = WLAN_EID_EXT_HE_MU_EDCA_PARAMS;
274 
275 	edca = (struct ieee80211_he_mu_edca_parameter_set *) pos;
276 	os_memcpy(edca, &hapd->iface->conf->he_mu_edca, sizeof(*edca));
277 
278 	wpa_hexdump(MSG_DEBUG, "HE: MU EDCA Parameter Set element",
279 		    pos, sizeof(*edca));
280 
281 	pos += sizeof(*edca);
282 
283 	return pos;
284 }
285 
286 
287 u8 * hostapd_eid_spatial_reuse(struct hostapd_data *hapd, u8 *eid)
288 {
289 	struct ieee80211_spatial_reuse *spr;
290 	u8 *pos = eid, *spr_param;
291 	u8 sz = 1;
292 
293 	if (!hapd->iface->conf->spr.sr_control)
294 		return eid;
295 
296 	if (hapd->iface->conf->spr.sr_control &
297 	    SPATIAL_REUSE_NON_SRG_OFFSET_PRESENT)
298 		sz++;
299 
300 	if (hapd->iface->conf->spr.sr_control &
301 	    SPATIAL_REUSE_SRG_INFORMATION_PRESENT)
302 		sz += 18;
303 
304 	*pos++ = WLAN_EID_EXTENSION;
305 	*pos++ = 1 + sz;
306 	*pos++ = WLAN_EID_EXT_SPATIAL_REUSE;
307 
308 	spr = (struct ieee80211_spatial_reuse *) pos;
309 	os_memset(spr, 0, sizeof(*spr));
310 
311 	spr->sr_ctrl = hapd->iface->conf->spr.sr_control;
312 	pos++;
313 	spr_param = spr->params;
314 	if (spr->sr_ctrl & SPATIAL_REUSE_NON_SRG_OFFSET_PRESENT) {
315 		*spr_param++ =
316 			hapd->iface->conf->spr.non_srg_obss_pd_max_offset;
317 		pos++;
318 	}
319 	if (spr->sr_ctrl & SPATIAL_REUSE_SRG_INFORMATION_PRESENT) {
320 		*spr_param++ = hapd->iface->conf->spr.srg_obss_pd_min_offset;
321 		*spr_param++ = hapd->iface->conf->spr.srg_obss_pd_max_offset;
322 		os_memcpy(spr_param,
323 			  hapd->iface->conf->spr.srg_bss_color_bitmap, 8);
324 		spr_param += 8;
325 		os_memcpy(spr_param,
326 			  hapd->iface->conf->spr.srg_partial_bssid_bitmap, 8);
327 		pos += 18;
328 	}
329 
330 	return pos;
331 }
332 
333 
334 u8 * hostapd_eid_he_6ghz_band_cap(struct hostapd_data *hapd, u8 *eid)
335 {
336 	struct hostapd_config *conf = hapd->iface->conf;
337 	struct hostapd_hw_modes *mode = hapd->iface->current_mode;
338 	struct he_capabilities *he_cap;
339 	struct ieee80211_he_6ghz_band_cap *cap;
340 	u16 capab;
341 	u8 *pos;
342 
343 	if (!mode || !is_6ghz_op_class(hapd->iconf->op_class) ||
344 	    !is_6ghz_freq(hapd->iface->freq))
345 		return eid;
346 
347 	he_cap = &mode->he_capab[IEEE80211_MODE_AP];
348 	capab = he_cap->he_6ghz_capa & HE_6GHZ_BAND_CAP_MIN_MPDU_START;
349 	capab |= (conf->he_6ghz_max_ampdu_len_exp <<
350 		  HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_SHIFT) &
351 		HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_MASK;
352 	capab |= (conf->he_6ghz_max_mpdu <<
353 		  HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_SHIFT) &
354 		HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_MASK;
355 	capab |= HE_6GHZ_BAND_CAP_SMPS_DISABLED;
356 	if (conf->he_6ghz_rx_ant_pat)
357 		capab |= HE_6GHZ_BAND_CAP_RX_ANTPAT_CONS;
358 	if (conf->he_6ghz_tx_ant_pat)
359 		capab |= HE_6GHZ_BAND_CAP_TX_ANTPAT_CONS;
360 
361 	pos = eid;
362 	*pos++ = WLAN_EID_EXTENSION;
363 	*pos++ = 1 + sizeof(*cap);
364 	*pos++ = WLAN_EID_EXT_HE_6GHZ_BAND_CAP;
365 
366 	cap = (struct ieee80211_he_6ghz_band_cap *) pos;
367 	cap->capab = host_to_le16(capab);
368 	pos += sizeof(*cap);
369 
370 	return pos;
371 }
372 
373 
374 void hostapd_get_he_capab(struct hostapd_data *hapd,
375 			  const struct ieee80211_he_capabilities *he_cap,
376 			  struct ieee80211_he_capabilities *neg_he_cap,
377 			  size_t he_capab_len)
378 {
379 	if (!he_cap)
380 		return;
381 
382 	if (he_capab_len > sizeof(*neg_he_cap))
383 		he_capab_len = sizeof(*neg_he_cap);
384 	/* TODO: mask out unsupported features */
385 
386 	os_memcpy(neg_he_cap, he_cap, he_capab_len);
387 }
388 
389 
390 static int check_valid_he_mcs(struct hostapd_data *hapd, const u8 *sta_he_capab,
391 			      enum ieee80211_op_mode opmode)
392 {
393 	u16 sta_rx_mcs_set, ap_tx_mcs_set;
394 	u8 mcs_count = 0;
395 	const u16 *ap_mcs_set, *sta_mcs_set;
396 	int i;
397 
398 	if (!hapd->iface->current_mode)
399 		return 1;
400 	ap_mcs_set = (u16 *) hapd->iface->current_mode->he_capab[opmode].mcs;
401 	sta_mcs_set = (u16 *) ((const struct ieee80211_he_capabilities *)
402 			       sta_he_capab)->optional;
403 
404 	/*
405 	 * Disable HE capabilities for STAs for which there is not even a single
406 	 * allowed MCS in any supported number of streams, i.e., STA is
407 	 * advertising 3 (not supported) as HE MCS rates for all supported
408 	 * band/stream cases.
409 	 */
410 	switch (hapd->iface->conf->he_oper_chwidth) {
411 	case CHANWIDTH_80P80MHZ:
412 		mcs_count = 3;
413 		break;
414 	case CHANWIDTH_160MHZ:
415 		mcs_count = 2;
416 		break;
417 	default:
418 		mcs_count = 1;
419 		break;
420 	}
421 
422 	for (i = 0; i < mcs_count; i++) {
423 		int j;
424 
425 		/* AP Tx MCS map vs. STA Rx MCS map */
426 		sta_rx_mcs_set = WPA_GET_LE16((const u8 *) &sta_mcs_set[i * 2]);
427 		ap_tx_mcs_set = WPA_GET_LE16((const u8 *)
428 					     &ap_mcs_set[(i * 2) + 1]);
429 
430 		for (j = 0; j < HE_NSS_MAX_STREAMS; j++) {
431 			if (((ap_tx_mcs_set >> (j * 2)) & 0x3) == 3)
432 				continue;
433 
434 			if (((sta_rx_mcs_set >> (j * 2)) & 0x3) == 3)
435 				continue;
436 
437 			return 1;
438 		}
439 	}
440 
441 	wpa_printf(MSG_DEBUG,
442 		   "No matching HE MCS found between AP TX and STA RX");
443 
444 	return 0;
445 }
446 
447 
448 u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta,
449 		      enum ieee80211_op_mode opmode, const u8 *he_capab,
450 		      size_t he_capab_len)
451 {
452 	if (!he_capab || !(sta->flags & WLAN_STA_WMM) ||
453 	    !hapd->iconf->ieee80211ax || hapd->conf->disable_11ax ||
454 	    !check_valid_he_mcs(hapd, he_capab, opmode) ||
455 	    ieee80211_invalid_he_cap_size(he_capab, he_capab_len) ||
456 	    he_capab_len > sizeof(struct ieee80211_he_capabilities)) {
457 		sta->flags &= ~WLAN_STA_HE;
458 		os_free(sta->he_capab);
459 		sta->he_capab = NULL;
460 		return WLAN_STATUS_SUCCESS;
461 	}
462 
463 	if (!sta->he_capab) {
464 		sta->he_capab =
465 			os_zalloc(sizeof(struct ieee80211_he_capabilities));
466 		if (!sta->he_capab)
467 			return WLAN_STATUS_UNSPECIFIED_FAILURE;
468 	}
469 
470 	sta->flags |= WLAN_STA_HE;
471 	os_memset(sta->he_capab, 0, sizeof(struct ieee80211_he_capabilities));
472 	os_memcpy(sta->he_capab, he_capab, he_capab_len);
473 	sta->he_capab_len = he_capab_len;
474 
475 	return WLAN_STATUS_SUCCESS;
476 }
477 
478 
479 u16 copy_sta_he_6ghz_capab(struct hostapd_data *hapd, struct sta_info *sta,
480 			   const u8 *he_6ghz_capab)
481 {
482 	if (!he_6ghz_capab || !hapd->iconf->ieee80211ax ||
483 	    hapd->conf->disable_11ax ||
484 	    !is_6ghz_op_class(hapd->iconf->op_class)) {
485 		sta->flags &= ~WLAN_STA_6GHZ;
486 		os_free(sta->he_6ghz_capab);
487 		sta->he_6ghz_capab = NULL;
488 		return WLAN_STATUS_SUCCESS;
489 	}
490 
491 	if (!sta->he_6ghz_capab) {
492 		sta->he_6ghz_capab =
493 			os_zalloc(sizeof(struct ieee80211_he_6ghz_band_cap));
494 		if (!sta->he_6ghz_capab)
495 			return WLAN_STATUS_UNSPECIFIED_FAILURE;
496 	}
497 
498 	sta->flags |= WLAN_STA_6GHZ;
499 	os_memcpy(sta->he_6ghz_capab, he_6ghz_capab,
500 		  sizeof(struct ieee80211_he_6ghz_band_cap));
501 
502 	return WLAN_STATUS_SUCCESS;
503 }
504 
505 
506 int hostapd_get_he_twt_responder(struct hostapd_data *hapd,
507 				 enum ieee80211_op_mode mode)
508 {
509 	u8 *mac_cap;
510 
511 	if (!hapd->iface->current_mode ||
512 	    !hapd->iface->current_mode->he_capab[mode].he_supported)
513 		return 0;
514 
515 	mac_cap = hapd->iface->current_mode->he_capab[mode].mac_cap;
516 
517 	return !!(mac_cap[HE_MAC_CAPAB_0] & HE_MACCAP_TWT_RESPONDER) &&
518 		hapd->iface->conf->he_op.he_twt_responder;
519 }
520