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