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 hapd->iconf->he_oper_chwidth;
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 oper_chwidth = hostapd_get_oper_chwidth(hapd->iconf);
233 seg0 = hostapd_get_oper_centr_freq_seg0_idx(
234 hapd->iconf);
235 punct_update_legacy_bw(punct_bitmap,
236 hapd->iconf->channel,
237 &oper_chwidth, &seg0, &seg1);
238 }
239 #endif /* CONFIG_IEEE80211BE */
240
241 if (!seg0)
242 seg0 = hapd->iconf->channel;
243
244 params |= HE_OPERATION_6GHZ_OPER_INFO;
245
246 /* 6 GHz Operation Information field
247 * IEEE Std 802.11ax-2021, 9.4.2.249 HE Operation element,
248 * Figure 9-788k
249 */
250 *pos++ = hapd->iconf->channel; /* Primary Channel */
251
252 /* Control:
253 * bits 0-1: Channel Width
254 * bit 2: Duplicate Beacon
255 * bits 3-5: Regulatory Info
256 */
257 /* Channel Width */
258 if (seg1)
259 control = 3;
260 else
261 control = center_idx_to_bw_6ghz(seg0);
262
263 control |= hapd->iconf->he_6ghz_reg_pwr_type <<
264 HE_6GHZ_OPER_INFO_CTRL_REG_INFO_SHIFT;
265
266 *pos++ = control;
267
268 /* Channel Center Freq Seg0/Seg1 */
269 if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ ||
270 oper_chwidth == CONF_OPER_CHWIDTH_320MHZ) {
271 /*
272 * Seg 0 indicates the channel center frequency index of
273 * the 160 MHz channel.
274 */
275 seg1 = seg0;
276 if (hapd->iconf->channel < seg0)
277 seg0 -= 8;
278 else
279 seg0 += 8;
280 }
281
282 *pos++ = seg0;
283 *pos++ = seg1;
284 /* Minimum Rate */
285 *pos++ = 6; /* TODO: what should be set here? */
286 }
287
288 oper->he_oper_params = host_to_le32(params);
289
290 return pos;
291 }
292
293
hostapd_eid_he_mu_edca_parameter_set(struct hostapd_data * hapd,u8 * eid)294 u8 * hostapd_eid_he_mu_edca_parameter_set(struct hostapd_data *hapd, u8 *eid)
295 {
296 struct ieee80211_he_mu_edca_parameter_set *edca;
297 u8 *pos;
298 size_t i;
299
300 pos = (u8 *) &hapd->iface->conf->he_mu_edca;
301 for (i = 0; i < sizeof(*edca); i++) {
302 if (pos[i])
303 break;
304 }
305 if (i == sizeof(*edca))
306 return eid; /* no MU EDCA Parameters configured */
307
308 pos = eid;
309 *pos++ = WLAN_EID_EXTENSION;
310 *pos++ = 1 + sizeof(*edca);
311 *pos++ = WLAN_EID_EXT_HE_MU_EDCA_PARAMS;
312
313 edca = (struct ieee80211_he_mu_edca_parameter_set *) pos;
314 os_memcpy(edca, &hapd->iface->conf->he_mu_edca, sizeof(*edca));
315
316 wpa_hexdump(MSG_DEBUG, "HE: MU EDCA Parameter Set element",
317 pos, sizeof(*edca));
318
319 pos += sizeof(*edca);
320
321 return pos;
322 }
323
324
hostapd_eid_spatial_reuse(struct hostapd_data * hapd,u8 * eid)325 u8 * hostapd_eid_spatial_reuse(struct hostapd_data *hapd, u8 *eid)
326 {
327 struct ieee80211_spatial_reuse *spr;
328 u8 *pos = eid, *spr_param;
329 u8 sz = 1;
330
331 if (!hapd->iface->conf->spr.sr_control)
332 return eid;
333
334 if (hapd->iface->conf->spr.sr_control &
335 SPATIAL_REUSE_NON_SRG_OFFSET_PRESENT)
336 sz++;
337
338 if (hapd->iface->conf->spr.sr_control &
339 SPATIAL_REUSE_SRG_INFORMATION_PRESENT)
340 sz += 18;
341
342 *pos++ = WLAN_EID_EXTENSION;
343 *pos++ = 1 + sz;
344 *pos++ = WLAN_EID_EXT_SPATIAL_REUSE;
345
346 spr = (struct ieee80211_spatial_reuse *) pos;
347 os_memset(spr, 0, sizeof(*spr));
348
349 spr->sr_ctrl = hapd->iface->conf->spr.sr_control;
350 pos++;
351 spr_param = spr->params;
352 if (spr->sr_ctrl & SPATIAL_REUSE_NON_SRG_OFFSET_PRESENT) {
353 *spr_param++ =
354 hapd->iface->conf->spr.non_srg_obss_pd_max_offset;
355 pos++;
356 }
357 if (spr->sr_ctrl & SPATIAL_REUSE_SRG_INFORMATION_PRESENT) {
358 *spr_param++ = hapd->iface->conf->spr.srg_obss_pd_min_offset;
359 *spr_param++ = hapd->iface->conf->spr.srg_obss_pd_max_offset;
360 os_memcpy(spr_param,
361 hapd->iface->conf->spr.srg_bss_color_bitmap, 8);
362 spr_param += 8;
363 os_memcpy(spr_param,
364 hapd->iface->conf->spr.srg_partial_bssid_bitmap, 8);
365 pos += 18;
366 }
367
368 return pos;
369 }
370
371
hostapd_eid_he_6ghz_band_cap(struct hostapd_data * hapd,u8 * eid)372 u8 * hostapd_eid_he_6ghz_band_cap(struct hostapd_data *hapd, u8 *eid)
373 {
374 struct hostapd_config *conf = hapd->iface->conf;
375 struct hostapd_hw_modes *mode = hapd->iface->current_mode;
376 struct he_capabilities *he_cap;
377 struct ieee80211_he_6ghz_band_cap *cap;
378 u16 capab;
379 u8 *pos;
380
381 if (!mode || !is_6ghz_op_class(hapd->iconf->op_class) ||
382 !is_6ghz_freq(hapd->iface->freq))
383 return eid;
384
385 he_cap = &mode->he_capab[IEEE80211_MODE_AP];
386 capab = he_cap->he_6ghz_capa & HE_6GHZ_BAND_CAP_MIN_MPDU_START;
387 capab |= (conf->he_6ghz_max_ampdu_len_exp <<
388 HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_SHIFT) &
389 HE_6GHZ_BAND_CAP_MAX_AMPDU_LEN_EXP_MASK;
390 capab |= (conf->he_6ghz_max_mpdu <<
391 HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_SHIFT) &
392 HE_6GHZ_BAND_CAP_MAX_MPDU_LEN_MASK;
393 capab |= HE_6GHZ_BAND_CAP_SMPS_DISABLED;
394 if (conf->he_6ghz_rx_ant_pat)
395 capab |= HE_6GHZ_BAND_CAP_RX_ANTPAT_CONS;
396 if (conf->he_6ghz_tx_ant_pat)
397 capab |= HE_6GHZ_BAND_CAP_TX_ANTPAT_CONS;
398
399 pos = eid;
400 *pos++ = WLAN_EID_EXTENSION;
401 *pos++ = 1 + sizeof(*cap);
402 *pos++ = WLAN_EID_EXT_HE_6GHZ_BAND_CAP;
403
404 cap = (struct ieee80211_he_6ghz_band_cap *) pos;
405 cap->capab = host_to_le16(capab);
406 pos += sizeof(*cap);
407
408 return pos;
409 }
410
411
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)412 void hostapd_get_he_capab(struct hostapd_data *hapd,
413 const struct ieee80211_he_capabilities *he_cap,
414 struct ieee80211_he_capabilities *neg_he_cap,
415 size_t he_capab_len)
416 {
417 if (!he_cap)
418 return;
419
420 if (he_capab_len > sizeof(*neg_he_cap))
421 he_capab_len = sizeof(*neg_he_cap);
422 /* TODO: mask out unsupported features */
423
424 os_memcpy(neg_he_cap, he_cap, he_capab_len);
425 }
426
427
check_valid_he_mcs(struct hostapd_data * hapd,const u8 * sta_he_capab,enum ieee80211_op_mode opmode)428 static int check_valid_he_mcs(struct hostapd_data *hapd, const u8 *sta_he_capab,
429 enum ieee80211_op_mode opmode)
430 {
431 u16 sta_rx_mcs_set, ap_tx_mcs_set;
432 u8 mcs_count = 0;
433 const u16 *ap_mcs_set, *sta_mcs_set;
434 int i;
435
436 if (!hapd->iface->current_mode)
437 return 1;
438 ap_mcs_set = (u16 *) hapd->iface->current_mode->he_capab[opmode].mcs;
439 sta_mcs_set = (u16 *) ((const struct ieee80211_he_capabilities *)
440 sta_he_capab)->optional;
441
442 /*
443 * Disable HE capabilities for STAs for which there is not even a single
444 * allowed MCS in any supported number of streams, i.e., STA is
445 * advertising 3 (not supported) as HE MCS rates for all supported
446 * band/stream cases.
447 */
448 switch (hapd->iface->conf->he_oper_chwidth) {
449 case CONF_OPER_CHWIDTH_80P80MHZ:
450 mcs_count = 3;
451 break;
452 case CONF_OPER_CHWIDTH_160MHZ:
453 mcs_count = 2;
454 break;
455 default:
456 mcs_count = 1;
457 break;
458 }
459
460 for (i = 0; i < mcs_count; i++) {
461 int j;
462
463 /* AP Tx MCS map vs. STA Rx MCS map */
464 sta_rx_mcs_set = WPA_GET_LE16((const u8 *) &sta_mcs_set[i * 2]);
465 ap_tx_mcs_set = WPA_GET_LE16((const u8 *)
466 &ap_mcs_set[(i * 2) + 1]);
467
468 for (j = 0; j < HE_NSS_MAX_STREAMS; j++) {
469 if (((ap_tx_mcs_set >> (j * 2)) & 0x3) == 3)
470 continue;
471
472 if (((sta_rx_mcs_set >> (j * 2)) & 0x3) == 3)
473 continue;
474
475 return 1;
476 }
477 }
478
479 wpa_printf(MSG_DEBUG,
480 "No matching HE MCS found between AP TX and STA RX");
481
482 return 0;
483 }
484
485
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)486 u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta,
487 enum ieee80211_op_mode opmode, const u8 *he_capab,
488 size_t he_capab_len)
489 {
490 if (!he_capab || !(sta->flags & WLAN_STA_WMM) ||
491 !hapd->iconf->ieee80211ax || hapd->conf->disable_11ax ||
492 !check_valid_he_mcs(hapd, he_capab, opmode) ||
493 ieee80211_invalid_he_cap_size(he_capab, he_capab_len) ||
494 he_capab_len > sizeof(struct ieee80211_he_capabilities)) {
495 sta->flags &= ~WLAN_STA_HE;
496 os_free(sta->he_capab);
497 sta->he_capab = NULL;
498 return WLAN_STATUS_SUCCESS;
499 }
500
501 if (!sta->he_capab) {
502 sta->he_capab =
503 os_zalloc(sizeof(struct ieee80211_he_capabilities));
504 if (!sta->he_capab)
505 return WLAN_STATUS_UNSPECIFIED_FAILURE;
506 }
507
508 sta->flags |= WLAN_STA_HE;
509 os_memset(sta->he_capab, 0, sizeof(struct ieee80211_he_capabilities));
510 os_memcpy(sta->he_capab, he_capab, he_capab_len);
511 sta->he_capab_len = he_capab_len;
512
513 return WLAN_STATUS_SUCCESS;
514 }
515
516
copy_sta_he_6ghz_capab(struct hostapd_data * hapd,struct sta_info * sta,const u8 * he_6ghz_capab)517 u16 copy_sta_he_6ghz_capab(struct hostapd_data *hapd, struct sta_info *sta,
518 const u8 *he_6ghz_capab)
519 {
520 if (!he_6ghz_capab || !hapd->iconf->ieee80211ax ||
521 hapd->conf->disable_11ax ||
522 !is_6ghz_op_class(hapd->iconf->op_class)) {
523 sta->flags &= ~WLAN_STA_6GHZ;
524 os_free(sta->he_6ghz_capab);
525 sta->he_6ghz_capab = NULL;
526 return WLAN_STATUS_SUCCESS;
527 }
528
529 if (!sta->he_6ghz_capab) {
530 sta->he_6ghz_capab =
531 os_zalloc(sizeof(struct ieee80211_he_6ghz_band_cap));
532 if (!sta->he_6ghz_capab)
533 return WLAN_STATUS_UNSPECIFIED_FAILURE;
534 }
535
536 sta->flags |= WLAN_STA_6GHZ;
537 os_memcpy(sta->he_6ghz_capab, he_6ghz_capab,
538 sizeof(struct ieee80211_he_6ghz_band_cap));
539
540 return WLAN_STATUS_SUCCESS;
541 }
542
543
hostapd_get_he_twt_responder(struct hostapd_data * hapd,enum ieee80211_op_mode mode)544 int hostapd_get_he_twt_responder(struct hostapd_data *hapd,
545 enum ieee80211_op_mode mode)
546 {
547 u8 *mac_cap;
548
549 if (!hapd->iface->current_mode ||
550 !hapd->iface->current_mode->he_capab[mode].he_supported ||
551 !hapd->iconf->ieee80211ax || hapd->conf->disable_11ax)
552 return 0;
553
554 mac_cap = hapd->iface->current_mode->he_capab[mode].mac_cap;
555
556 return !!(mac_cap[HE_MAC_CAPAB_0] & HE_MACCAP_TWT_RESPONDER) &&
557 hapd->iface->conf->he_op.he_twt_responder;
558 }
559
560
hostapd_eid_cca(struct hostapd_data * hapd,u8 * eid)561 u8 * hostapd_eid_cca(struct hostapd_data *hapd, u8 *eid)
562 {
563 if (!hapd->cca_in_progress)
564 return eid;
565
566 /* BSS Color Change Announcement element */
567 *eid++ = WLAN_EID_EXTENSION;
568 *eid++ = 3;
569 *eid++ = WLAN_EID_EXT_COLOR_CHANGE_ANNOUNCEMENT;
570 *eid++ = hapd->cca_count; /* Color Switch Countdown */
571 *eid++ = hapd->cca_color; /* New BSS Color Information */
572
573 return eid;
574 }
575