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