]> git.ipfire.org Git - thirdparty/hostap.git/blame - wpa_supplicant/op_classes.c
tests: sigma_dut controlled STA and beacon protection
[thirdparty/hostap.git] / wpa_supplicant / op_classes.c
CommitLineData
065c029a 1/*
2 * Operating classes
3 * Copyright(c) 2015 Intel Deutschland GmbH
4 * Contact Information:
5 * Intel Linux Wireless <ilw@linux.intel.com>
6 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
7 *
8 * This software may be distributed under the terms of the BSD license.
9 * See README for more details.
10 */
11
12#include "utils/includes.h"
13
14#include "utils/common.h"
15#include "common/ieee802_11_common.h"
16#include "wpa_supplicant_i.h"
2b9713d6 17#include "bss.h"
065c029a 18
19
89450024
JM
20static enum chan_allowed allow_channel(struct hostapd_hw_modes *mode,
21 u8 op_class, u8 chan,
065c029a 22 unsigned int *flags)
23{
24 int i;
89450024 25 int is_6ghz = op_class >= 131 && op_class <= 135;
065c029a 26
27 for (i = 0; i < mode->num_channels; i++) {
89450024
JM
28 int chan_is_6ghz;
29
30 chan_is_6ghz = mode->channels[i].freq > 5940 &&
31 mode->channels[i].freq <= 7105;
32 if (is_6ghz == chan_is_6ghz && mode->channels[i].chan == chan)
065c029a 33 break;
34 }
35
36 if (i == mode->num_channels ||
37 (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED))
38 return NOT_ALLOWED;
39
40 if (flags)
41 *flags = mode->channels[i].flag;
42
1ac4dba3
AS
43 if (mode->channels[i].flag & HOSTAPD_CHAN_NO_IR)
44 return NO_IR;
45
065c029a 46 return ALLOWED;
47}
48
49
50static int get_center_80mhz(struct hostapd_hw_modes *mode, u8 channel)
51{
52 u8 center_channels[] = { 42, 58, 106, 122, 138, 155 };
53 size_t i;
54
55 if (mode->mode != HOSTAPD_MODE_IEEE80211A)
56 return 0;
57
58 for (i = 0; i < ARRAY_SIZE(center_channels); i++) {
59 /*
60 * In 80 MHz, the bandwidth "spans" 12 channels (e.g., 36-48),
61 * so the center channel is 6 channels away from the start/end.
62 */
63 if (channel >= center_channels[i] - 6 &&
64 channel <= center_channels[i] + 6)
65 return center_channels[i];
66 }
67
68 return 0;
69}
70
71
89450024
JM
72static enum chan_allowed verify_80mhz(struct hostapd_hw_modes *mode,
73 u8 op_class, u8 channel)
065c029a 74{
75 u8 center_chan;
76 unsigned int i;
1ac4dba3 77 unsigned int no_ir = 0;
065c029a 78
79 center_chan = get_center_80mhz(mode, channel);
80 if (!center_chan)
81 return NOT_ALLOWED;
82
83 /* check all the channels are available */
84 for (i = 0; i < 4; i++) {
85 unsigned int flags;
86 u8 adj_chan = center_chan - 6 + i * 4;
87
89450024
JM
88 if (allow_channel(mode, op_class, adj_chan, &flags) ==
89 NOT_ALLOWED)
065c029a 90 return NOT_ALLOWED;
91
92 if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_70)) ||
93 (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_50)) ||
94 (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_30)) ||
95 (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_10)))
96 return NOT_ALLOWED;
1ac4dba3
AS
97
98 if (flags & HOSTAPD_CHAN_NO_IR)
99 no_ir = 1;
065c029a 100 }
101
1ac4dba3
AS
102 if (no_ir)
103 return NO_IR;
104
065c029a 105 return ALLOWED;
106}
107
108
109static int get_center_160mhz(struct hostapd_hw_modes *mode, u8 channel)
110{
111 u8 center_channels[] = { 50, 114 };
112 unsigned int i;
113
114 if (mode->mode != HOSTAPD_MODE_IEEE80211A)
115 return 0;
116
117 for (i = 0; i < ARRAY_SIZE(center_channels); i++) {
118 /*
119 * In 160 MHz, the bandwidth "spans" 28 channels (e.g., 36-64),
120 * so the center channel is 14 channels away from the start/end.
121 */
122 if (channel >= center_channels[i] - 14 &&
123 channel <= center_channels[i] + 14)
124 return center_channels[i];
125 }
126
127 return 0;
128}
129
130
131static enum chan_allowed verify_160mhz(struct hostapd_hw_modes *mode,
89450024 132 u8 op_class, u8 channel)
065c029a 133{
134 u8 center_chan;
135 unsigned int i;
1ac4dba3 136 unsigned int no_ir = 0;
065c029a 137
138 center_chan = get_center_160mhz(mode, channel);
139 if (!center_chan)
140 return NOT_ALLOWED;
141
142 /* Check all the channels are available */
143 for (i = 0; i < 8; i++) {
144 unsigned int flags;
145 u8 adj_chan = center_chan - 14 + i * 4;
146
89450024
JM
147 if (allow_channel(mode, op_class, adj_chan, &flags) ==
148 NOT_ALLOWED)
065c029a 149 return NOT_ALLOWED;
150
151 if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_150)) ||
152 (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_130)) ||
153 (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_110)) ||
154 (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_90)) ||
155 (i == 4 && !(flags & HOSTAPD_CHAN_VHT_90_70)) ||
156 (i == 5 && !(flags & HOSTAPD_CHAN_VHT_110_50)) ||
157 (i == 6 && !(flags & HOSTAPD_CHAN_VHT_130_30)) ||
158 (i == 7 && !(flags & HOSTAPD_CHAN_VHT_150_10)))
159 return NOT_ALLOWED;
1ac4dba3
AS
160
161 if (flags & HOSTAPD_CHAN_NO_IR)
162 no_ir = 1;
065c029a 163 }
164
1ac4dba3
AS
165 if (no_ir)
166 return NO_IR;
167
065c029a 168 return ALLOWED;
169}
170
171
89450024
JM
172enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 op_class,
173 u8 channel, u8 bw)
065c029a 174{
175 unsigned int flag = 0;
176 enum chan_allowed res, res2;
177
89450024 178 res2 = res = allow_channel(mode, op_class, channel, &flag);
065c029a 179 if (bw == BW40MINUS) {
180 if (!(flag & HOSTAPD_CHAN_HT40MINUS))
181 return NOT_ALLOWED;
89450024 182 res2 = allow_channel(mode, op_class, channel - 4, NULL);
065c029a 183 } else if (bw == BW40PLUS) {
184 if (!(flag & HOSTAPD_CHAN_HT40PLUS))
185 return NOT_ALLOWED;
89450024 186 res2 = allow_channel(mode, op_class, channel + 4, NULL);
065c029a 187 } else if (bw == BW80) {
188 /*
189 * channel is a center channel and as such, not necessarily a
190 * valid 20 MHz channels. Override earlier allow_channel()
191 * result and use only the 80 MHz specific version.
192 */
89450024 193 res2 = res = verify_80mhz(mode, op_class, channel);
065c029a 194 } else if (bw == BW160) {
195 /*
196 * channel is a center channel and as such, not necessarily a
197 * valid 20 MHz channels. Override earlier allow_channel()
198 * result and use only the 160 MHz specific version.
199 */
89450024 200 res2 = res = verify_160mhz(mode, op_class, channel);
065c029a 201 } else if (bw == BW80P80) {
202 /*
203 * channel is a center channel and as such, not necessarily a
204 * valid 20 MHz channels. Override earlier allow_channel()
205 * result and use only the 80 MHz specific version.
206 */
89450024 207 res2 = res = verify_80mhz(mode, op_class, channel);
065c029a 208 }
209
210 if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
211 return NOT_ALLOWED;
212
1ac4dba3
AS
213 if (res == NO_IR || res2 == NO_IR)
214 return NO_IR;
215
065c029a 216 return ALLOWED;
217}
218
219
220static int wpas_op_class_supported(struct wpa_supplicant *wpa_s,
cb828507 221 struct wpa_ssid *ssid,
065c029a 222 const struct oper_class_map *op_class)
223{
224 int chan;
225 size_t i;
226 struct hostapd_hw_modes *mode;
227 int found;
b06d60a9
BG
228 int z;
229 int freq2 = 0;
230 int freq5 = 0;
065c029a 231
d0e116f6
VK
232 mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op_class->mode,
233 is_6ghz_op_class(op_class->op_class));
065c029a 234 if (!mode)
235 return 0;
236
b06d60a9
BG
237 /* If we are configured to disable certain things, take that into
238 * account here. */
8f8c423a 239 if (ssid && ssid->freq_list && ssid->freq_list[0]) {
b06d60a9
BG
240 for (z = 0; ; z++) {
241 int f = ssid->freq_list[z];
242
243 if (f == 0)
244 break; /* end of list */
245 if (f > 4000 && f < 6000)
246 freq5 = 1;
247 else if (f > 2400 && f < 2500)
248 freq2 = 1;
249 }
250 } else {
251 /* No frequencies specified, can use anything hardware supports.
252 */
253 freq2 = freq5 = 1;
254 }
255
256 if (op_class->op_class >= 115 && op_class->op_class <= 130 && !freq5)
257 return 0;
258 if (op_class->op_class >= 81 && op_class->op_class <= 84 && !freq2)
259 return 0;
260
cb828507 261#ifdef CONFIG_HT_OVERRIDES
8f8c423a 262 if (ssid && ssid->disable_ht) {
cb828507
BG
263 switch (op_class->op_class) {
264 case 83:
265 case 84:
266 case 104:
267 case 105:
268 case 116:
269 case 117:
270 case 119:
271 case 120:
272 case 122:
273 case 123:
274 case 126:
275 case 127:
276 case 128:
277 case 129:
278 case 130:
279 /* Disable >= 40 MHz channels if HT is disabled */
280 return 0;
281 }
282 }
283#endif /* CONFIG_HT_OVERRIDES */
284
285#ifdef CONFIG_VHT_OVERRIDES
8f8c423a 286 if (ssid && ssid->disable_vht) {
cb828507
BG
287 if (op_class->op_class >= 128 && op_class->op_class <= 130) {
288 /* Disable >= 80 MHz channels if VHT is disabled */
289 return 0;
290 }
291 }
292#endif /* CONFIG_VHT_OVERRIDES */
293
065c029a 294 if (op_class->op_class == 128) {
295 u8 channels[] = { 42, 58, 106, 122, 138, 155 };
296
297 for (i = 0; i < ARRAY_SIZE(channels); i++) {
89450024
JM
298 if (verify_channel(mode, op_class->op_class,
299 channels[i], op_class->bw) !=
1ac4dba3 300 NOT_ALLOWED)
065c029a 301 return 1;
302 }
303
304 return 0;
305 }
306
307 if (op_class->op_class == 129) {
308 /* Check if either 160 MHz channels is allowed */
89450024
JM
309 return verify_channel(mode, op_class->op_class, 50,
310 op_class->bw) != NOT_ALLOWED ||
311 verify_channel(mode, op_class->op_class, 114,
312 op_class->bw) != NOT_ALLOWED;
065c029a 313 }
314
315 if (op_class->op_class == 130) {
316 /* Need at least two non-contiguous 80 MHz segments */
317 found = 0;
318
89450024
JM
319 if (verify_channel(mode, op_class->op_class, 42,
320 op_class->bw) != NOT_ALLOWED ||
321 verify_channel(mode, op_class->op_class, 58,
322 op_class->bw) != NOT_ALLOWED)
065c029a 323 found++;
89450024
JM
324 if (verify_channel(mode, op_class->op_class, 106,
325 op_class->bw) != NOT_ALLOWED ||
326 verify_channel(mode, op_class->op_class, 122,
327 op_class->bw) != NOT_ALLOWED ||
328 verify_channel(mode, op_class->op_class, 138,
329 op_class->bw) != NOT_ALLOWED)
065c029a 330 found++;
89450024
JM
331 if (verify_channel(mode, op_class->op_class, 106,
332 op_class->bw) != NOT_ALLOWED &&
333 verify_channel(mode, op_class->op_class, 138,
334 op_class->bw) != NOT_ALLOWED)
065c029a 335 found++;
89450024
JM
336 if (verify_channel(mode, op_class->op_class, 155,
337 op_class->bw) != NOT_ALLOWED)
065c029a 338 found++;
339
340 if (found >= 2)
341 return 1;
342
343 return 0;
344 }
345
346 found = 0;
347 for (chan = op_class->min_chan; chan <= op_class->max_chan;
348 chan += op_class->inc) {
89450024
JM
349 if (verify_channel(mode, op_class->op_class, chan,
350 op_class->bw) != NOT_ALLOWED) {
065c029a 351 found = 1;
352 break;
353 }
354 }
355
356 return found;
357}
358
359
2b9713d6
AB
360static int wpas_sta_secondary_channel_offset(struct wpa_bss *bss, u8 *current,
361 u8 *channel)
362{
363
364 u8 *ies, phy_type;
365 size_t ies_len;
366
367 if (!bss)
368 return -1;
369 ies = (u8 *) (bss + 1);
370 ies_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len;
371 return wpas_get_op_chan_phy(bss->freq, ies, ies_len, current,
372 channel, &phy_type);
373}
374
375
cb828507
BG
376size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s,
377 struct wpa_ssid *ssid,
2b9713d6 378 struct wpa_bss *bss, u8 *pos, size_t len)
065c029a 379{
380 struct wpabuf *buf;
381 u8 op, current, chan;
382 u8 *ie_len;
383 size_t res;
384
385 /*
2b9713d6
AB
386 * Determine the current operating class correct mode based on
387 * advertised BSS capabilities, if available. Fall back to a less
388 * accurate guess based on frequency if the needed IEs are not available
389 * or used.
065c029a 390 */
2b9713d6
AB
391 if (wpas_sta_secondary_channel_offset(bss, &current, &chan) < 0 &&
392 ieee80211_freq_to_channel_ext(bss->freq, 0, CHANWIDTH_USE_HT,
065c029a 393 &current, &chan) == NUM_HOSTAPD_MODES)
394 return 0;
395
396 /*
397 * Need 3 bytes for EID, length, and current operating class, plus
398 * 1 byte for every other supported operating class.
399 */
400 buf = wpabuf_alloc(global_op_class_size + 3);
401 if (!buf)
402 return 0;
403
404 wpabuf_put_u8(buf, WLAN_EID_SUPPORTED_OPERATING_CLASSES);
405 /* Will set the length later, putting a placeholder */
406 ie_len = wpabuf_put(buf, 1);
407 wpabuf_put_u8(buf, current);
408
409 for (op = 0; global_op_class[op].op_class; op++) {
cb828507 410 if (wpas_op_class_supported(wpa_s, ssid, &global_op_class[op]))
065c029a 411 wpabuf_put_u8(buf, global_op_class[op].op_class);
412 }
413
414 *ie_len = wpabuf_len(buf) - 2;
415 if (*ie_len < 2 || wpabuf_len(buf) > len) {
416 wpa_printf(MSG_ERROR,
417 "Failed to add supported operating classes IE");
418 res = 0;
419 } else {
420 os_memcpy(pos, wpabuf_head(buf), wpabuf_len(buf));
421 res = wpabuf_len(buf);
422 wpa_hexdump_buf(MSG_DEBUG,
423 "Added supported operating classes IE", buf);
424 }
425
426 wpabuf_free(buf);
427 return res;
428}
8f8c423a
JM
429
430
431int * wpas_supp_op_classes(struct wpa_supplicant *wpa_s)
432{
433 int op;
434 unsigned int pos, max_num = 0;
435 int *classes;
436
437 for (op = 0; global_op_class[op].op_class; op++)
438 max_num++;
439 classes = os_zalloc((max_num + 1) * sizeof(int));
440 if (!classes)
441 return NULL;
442
443 for (op = 0, pos = 0; global_op_class[op].op_class; op++) {
444 if (wpas_op_class_supported(wpa_s, NULL, &global_op_class[op]))
445 classes[pos++] = global_op_class[op].op_class;
446 }
447
448 return classes;
449}