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