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