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