op_classes.c revision 1.1 1 1.1 christos /*
2 1.1 christos * Operating classes
3 1.1 christos * Copyright(c) 2015 Intel Deutschland GmbH
4 1.1 christos * Contact Information:
5 1.1 christos * Intel Linux Wireless <ilw (at) linux.intel.com>
6 1.1 christos * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
7 1.1 christos *
8 1.1 christos * This software may be distributed under the terms of the BSD license.
9 1.1 christos * See README for more details.
10 1.1 christos */
11 1.1 christos
12 1.1 christos #include "utils/includes.h"
13 1.1 christos
14 1.1 christos #include "utils/common.h"
15 1.1 christos #include "common/ieee802_11_common.h"
16 1.1 christos #include "wpa_supplicant_i.h"
17 1.1 christos
18 1.1 christos
19 1.1 christos static enum chan_allowed allow_channel(struct hostapd_hw_modes *mode, u8 chan,
20 1.1 christos unsigned int *flags)
21 1.1 christos {
22 1.1 christos int i;
23 1.1 christos
24 1.1 christos for (i = 0; i < mode->num_channels; i++) {
25 1.1 christos if (mode->channels[i].chan == chan)
26 1.1 christos break;
27 1.1 christos }
28 1.1 christos
29 1.1 christos if (i == mode->num_channels ||
30 1.1 christos (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED))
31 1.1 christos return NOT_ALLOWED;
32 1.1 christos
33 1.1 christos if (flags)
34 1.1 christos *flags = mode->channels[i].flag;
35 1.1 christos
36 1.1 christos if (mode->channels[i].flag & HOSTAPD_CHAN_NO_IR)
37 1.1 christos return NO_IR;
38 1.1 christos
39 1.1 christos return ALLOWED;
40 1.1 christos }
41 1.1 christos
42 1.1 christos
43 1.1 christos static int get_center_80mhz(struct hostapd_hw_modes *mode, u8 channel)
44 1.1 christos {
45 1.1 christos u8 center_channels[] = { 42, 58, 106, 122, 138, 155 };
46 1.1 christos size_t i;
47 1.1 christos
48 1.1 christos if (mode->mode != HOSTAPD_MODE_IEEE80211A)
49 1.1 christos return 0;
50 1.1 christos
51 1.1 christos for (i = 0; i < ARRAY_SIZE(center_channels); i++) {
52 1.1 christos /*
53 1.1 christos * In 80 MHz, the bandwidth "spans" 12 channels (e.g., 36-48),
54 1.1 christos * so the center channel is 6 channels away from the start/end.
55 1.1 christos */
56 1.1 christos if (channel >= center_channels[i] - 6 &&
57 1.1 christos channel <= center_channels[i] + 6)
58 1.1 christos return center_channels[i];
59 1.1 christos }
60 1.1 christos
61 1.1 christos return 0;
62 1.1 christos }
63 1.1 christos
64 1.1 christos
65 1.1 christos static enum chan_allowed verify_80mhz(struct hostapd_hw_modes *mode, u8 channel)
66 1.1 christos {
67 1.1 christos u8 center_chan;
68 1.1 christos unsigned int i;
69 1.1 christos unsigned int no_ir = 0;
70 1.1 christos
71 1.1 christos center_chan = get_center_80mhz(mode, channel);
72 1.1 christos if (!center_chan)
73 1.1 christos return NOT_ALLOWED;
74 1.1 christos
75 1.1 christos /* check all the channels are available */
76 1.1 christos for (i = 0; i < 4; i++) {
77 1.1 christos unsigned int flags;
78 1.1 christos u8 adj_chan = center_chan - 6 + i * 4;
79 1.1 christos
80 1.1 christos if (allow_channel(mode, adj_chan, &flags) == NOT_ALLOWED)
81 1.1 christos return NOT_ALLOWED;
82 1.1 christos
83 1.1 christos if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_70)) ||
84 1.1 christos (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_50)) ||
85 1.1 christos (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_30)) ||
86 1.1 christos (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_10)))
87 1.1 christos return NOT_ALLOWED;
88 1.1 christos
89 1.1 christos if (flags & HOSTAPD_CHAN_NO_IR)
90 1.1 christos no_ir = 1;
91 1.1 christos }
92 1.1 christos
93 1.1 christos if (no_ir)
94 1.1 christos return NO_IR;
95 1.1 christos
96 1.1 christos return ALLOWED;
97 1.1 christos }
98 1.1 christos
99 1.1 christos
100 1.1 christos static int get_center_160mhz(struct hostapd_hw_modes *mode, u8 channel)
101 1.1 christos {
102 1.1 christos u8 center_channels[] = { 50, 114 };
103 1.1 christos unsigned int i;
104 1.1 christos
105 1.1 christos if (mode->mode != HOSTAPD_MODE_IEEE80211A)
106 1.1 christos return 0;
107 1.1 christos
108 1.1 christos for (i = 0; i < ARRAY_SIZE(center_channels); i++) {
109 1.1 christos /*
110 1.1 christos * In 160 MHz, the bandwidth "spans" 28 channels (e.g., 36-64),
111 1.1 christos * so the center channel is 14 channels away from the start/end.
112 1.1 christos */
113 1.1 christos if (channel >= center_channels[i] - 14 &&
114 1.1 christos channel <= center_channels[i] + 14)
115 1.1 christos return center_channels[i];
116 1.1 christos }
117 1.1 christos
118 1.1 christos return 0;
119 1.1 christos }
120 1.1 christos
121 1.1 christos
122 1.1 christos static enum chan_allowed verify_160mhz(struct hostapd_hw_modes *mode,
123 1.1 christos u8 channel)
124 1.1 christos {
125 1.1 christos u8 center_chan;
126 1.1 christos unsigned int i;
127 1.1 christos unsigned int no_ir = 0;
128 1.1 christos
129 1.1 christos center_chan = get_center_160mhz(mode, channel);
130 1.1 christos if (!center_chan)
131 1.1 christos return NOT_ALLOWED;
132 1.1 christos
133 1.1 christos /* Check all the channels are available */
134 1.1 christos for (i = 0; i < 8; i++) {
135 1.1 christos unsigned int flags;
136 1.1 christos u8 adj_chan = center_chan - 14 + i * 4;
137 1.1 christos
138 1.1 christos if (allow_channel(mode, adj_chan, &flags) == NOT_ALLOWED)
139 1.1 christos return NOT_ALLOWED;
140 1.1 christos
141 1.1 christos if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_150)) ||
142 1.1 christos (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_130)) ||
143 1.1 christos (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_110)) ||
144 1.1 christos (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_90)) ||
145 1.1 christos (i == 4 && !(flags & HOSTAPD_CHAN_VHT_90_70)) ||
146 1.1 christos (i == 5 && !(flags & HOSTAPD_CHAN_VHT_110_50)) ||
147 1.1 christos (i == 6 && !(flags & HOSTAPD_CHAN_VHT_130_30)) ||
148 1.1 christos (i == 7 && !(flags & HOSTAPD_CHAN_VHT_150_10)))
149 1.1 christos return NOT_ALLOWED;
150 1.1 christos
151 1.1 christos if (flags & HOSTAPD_CHAN_NO_IR)
152 1.1 christos no_ir = 1;
153 1.1 christos }
154 1.1 christos
155 1.1 christos if (no_ir)
156 1.1 christos return NO_IR;
157 1.1 christos
158 1.1 christos return ALLOWED;
159 1.1 christos }
160 1.1 christos
161 1.1 christos
162 1.1 christos enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 channel,
163 1.1 christos u8 bw)
164 1.1 christos {
165 1.1 christos unsigned int flag = 0;
166 1.1 christos enum chan_allowed res, res2;
167 1.1 christos
168 1.1 christos res2 = res = allow_channel(mode, channel, &flag);
169 1.1 christos if (bw == BW40MINUS) {
170 1.1 christos if (!(flag & HOSTAPD_CHAN_HT40MINUS))
171 1.1 christos return NOT_ALLOWED;
172 1.1 christos res2 = allow_channel(mode, channel - 4, NULL);
173 1.1 christos } else if (bw == BW40PLUS) {
174 1.1 christos if (!(flag & HOSTAPD_CHAN_HT40PLUS))
175 1.1 christos return NOT_ALLOWED;
176 1.1 christos res2 = allow_channel(mode, channel + 4, NULL);
177 1.1 christos } else if (bw == BW80) {
178 1.1 christos /*
179 1.1 christos * channel is a center channel and as such, not necessarily a
180 1.1 christos * valid 20 MHz channels. Override earlier allow_channel()
181 1.1 christos * result and use only the 80 MHz specific version.
182 1.1 christos */
183 1.1 christos res2 = res = verify_80mhz(mode, channel);
184 1.1 christos } else if (bw == BW160) {
185 1.1 christos /*
186 1.1 christos * channel is a center channel and as such, not necessarily a
187 1.1 christos * valid 20 MHz channels. Override earlier allow_channel()
188 1.1 christos * result and use only the 160 MHz specific version.
189 1.1 christos */
190 1.1 christos res2 = res = verify_160mhz(mode, channel);
191 1.1 christos } else if (bw == BW80P80) {
192 1.1 christos /*
193 1.1 christos * channel is a center channel and as such, not necessarily a
194 1.1 christos * valid 20 MHz channels. Override earlier allow_channel()
195 1.1 christos * result and use only the 80 MHz specific version.
196 1.1 christos */
197 1.1 christos res2 = res = verify_80mhz(mode, channel);
198 1.1 christos }
199 1.1 christos
200 1.1 christos if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
201 1.1 christos return NOT_ALLOWED;
202 1.1 christos
203 1.1 christos if (res == NO_IR || res2 == NO_IR)
204 1.1 christos return NO_IR;
205 1.1 christos
206 1.1 christos return ALLOWED;
207 1.1 christos }
208 1.1 christos
209 1.1 christos
210 1.1 christos static int wpas_op_class_supported(struct wpa_supplicant *wpa_s,
211 1.1 christos const struct oper_class_map *op_class)
212 1.1 christos {
213 1.1 christos int chan;
214 1.1 christos size_t i;
215 1.1 christos struct hostapd_hw_modes *mode;
216 1.1 christos int found;
217 1.1 christos
218 1.1 christos mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op_class->mode);
219 1.1 christos if (!mode)
220 1.1 christos return 0;
221 1.1 christos
222 1.1 christos if (op_class->op_class == 128) {
223 1.1 christos u8 channels[] = { 42, 58, 106, 122, 138, 155 };
224 1.1 christos
225 1.1 christos for (i = 0; i < ARRAY_SIZE(channels); i++) {
226 1.1 christos if (verify_channel(mode, channels[i], op_class->bw) !=
227 1.1 christos NOT_ALLOWED)
228 1.1 christos return 1;
229 1.1 christos }
230 1.1 christos
231 1.1 christos return 0;
232 1.1 christos }
233 1.1 christos
234 1.1 christos if (op_class->op_class == 129) {
235 1.1 christos /* Check if either 160 MHz channels is allowed */
236 1.1 christos return verify_channel(mode, 50, op_class->bw) != NOT_ALLOWED ||
237 1.1 christos verify_channel(mode, 114, op_class->bw) != NOT_ALLOWED;
238 1.1 christos }
239 1.1 christos
240 1.1 christos if (op_class->op_class == 130) {
241 1.1 christos /* Need at least two non-contiguous 80 MHz segments */
242 1.1 christos found = 0;
243 1.1 christos
244 1.1 christos if (verify_channel(mode, 42, op_class->bw) != NOT_ALLOWED ||
245 1.1 christos verify_channel(mode, 58, op_class->bw) != NOT_ALLOWED)
246 1.1 christos found++;
247 1.1 christos if (verify_channel(mode, 106, op_class->bw) != NOT_ALLOWED ||
248 1.1 christos verify_channel(mode, 122, op_class->bw) != NOT_ALLOWED ||
249 1.1 christos verify_channel(mode, 138, op_class->bw) != NOT_ALLOWED)
250 1.1 christos found++;
251 1.1 christos if (verify_channel(mode, 106, op_class->bw) != NOT_ALLOWED &&
252 1.1 christos verify_channel(mode, 138, op_class->bw) != NOT_ALLOWED)
253 1.1 christos found++;
254 1.1 christos if (verify_channel(mode, 155, op_class->bw) != NOT_ALLOWED)
255 1.1 christos found++;
256 1.1 christos
257 1.1 christos if (found >= 2)
258 1.1 christos return 1;
259 1.1 christos
260 1.1 christos return 0;
261 1.1 christos }
262 1.1 christos
263 1.1 christos found = 0;
264 1.1 christos for (chan = op_class->min_chan; chan <= op_class->max_chan;
265 1.1 christos chan += op_class->inc) {
266 1.1 christos if (verify_channel(mode, chan, op_class->bw) != NOT_ALLOWED) {
267 1.1 christos found = 1;
268 1.1 christos break;
269 1.1 christos }
270 1.1 christos }
271 1.1 christos
272 1.1 christos return found;
273 1.1 christos }
274 1.1 christos
275 1.1 christos
276 1.1 christos size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s, int freq, u8 *pos,
277 1.1 christos size_t len)
278 1.1 christos {
279 1.1 christos struct wpabuf *buf;
280 1.1 christos u8 op, current, chan;
281 1.1 christos u8 *ie_len;
282 1.1 christos size_t res;
283 1.1 christos
284 1.1 christos /*
285 1.1 christos * Assume 20 MHz channel for now.
286 1.1 christos * TODO: Use the secondary channel and VHT channel width that will be
287 1.1 christos * used after association.
288 1.1 christos */
289 1.1 christos if (ieee80211_freq_to_channel_ext(freq, 0, VHT_CHANWIDTH_USE_HT,
290 1.1 christos ¤t, &chan) == NUM_HOSTAPD_MODES)
291 1.1 christos return 0;
292 1.1 christos
293 1.1 christos /*
294 1.1 christos * Need 3 bytes for EID, length, and current operating class, plus
295 1.1 christos * 1 byte for every other supported operating class.
296 1.1 christos */
297 1.1 christos buf = wpabuf_alloc(global_op_class_size + 3);
298 1.1 christos if (!buf)
299 1.1 christos return 0;
300 1.1 christos
301 1.1 christos wpabuf_put_u8(buf, WLAN_EID_SUPPORTED_OPERATING_CLASSES);
302 1.1 christos /* Will set the length later, putting a placeholder */
303 1.1 christos ie_len = wpabuf_put(buf, 1);
304 1.1 christos wpabuf_put_u8(buf, current);
305 1.1 christos
306 1.1 christos for (op = 0; global_op_class[op].op_class; op++) {
307 1.1 christos if (wpas_op_class_supported(wpa_s, &global_op_class[op]))
308 1.1 christos wpabuf_put_u8(buf, global_op_class[op].op_class);
309 1.1 christos }
310 1.1 christos
311 1.1 christos *ie_len = wpabuf_len(buf) - 2;
312 1.1 christos if (*ie_len < 2 || wpabuf_len(buf) > len) {
313 1.1 christos wpa_printf(MSG_ERROR,
314 1.1 christos "Failed to add supported operating classes IE");
315 1.1 christos res = 0;
316 1.1 christos } else {
317 1.1 christos os_memcpy(pos, wpabuf_head(buf), wpabuf_len(buf));
318 1.1 christos res = wpabuf_len(buf);
319 1.1 christos wpa_hexdump_buf(MSG_DEBUG,
320 1.1 christos "Added supported operating classes IE", buf);
321 1.1 christos }
322 1.1 christos
323 1.1 christos wpabuf_free(buf);
324 1.1 christos return res;
325 1.1 christos }
326