Line data Source code
1 : /*
2 : * IEEE 802.11 Common routines
3 : * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
4 : *
5 : * This software may be distributed under the terms of the BSD license.
6 : * See README for more details.
7 : */
8 :
9 : #include "includes.h"
10 :
11 : #include "common.h"
12 : #include "defs.h"
13 : #include "ieee802_11_defs.h"
14 : #include "ieee802_11_common.h"
15 :
16 :
17 39354 : static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
18 : struct ieee802_11_elems *elems,
19 : int show_errors)
20 : {
21 : unsigned int oui;
22 :
23 : /* first 3 bytes in vendor specific information element are the IEEE
24 : * OUI of the vendor. The following byte is used a vendor specific
25 : * sub-type. */
26 39354 : if (elen < 4) {
27 3 : if (show_errors) {
28 1 : wpa_printf(MSG_MSGDUMP, "short vendor specific "
29 : "information element ignored (len=%lu)",
30 : (unsigned long) elen);
31 : }
32 3 : return -1;
33 : }
34 :
35 39351 : oui = WPA_GET_BE24(pos);
36 39351 : switch (oui) {
37 : case OUI_MICROSOFT:
38 : /* Microsoft/Wi-Fi information elements are further typed and
39 : * subtyped */
40 27179 : switch (pos[3]) {
41 : case 1:
42 : /* Microsoft OUI (00:50:F2) with OUI Type 1:
43 : * real WPA information element */
44 135 : elems->wpa_ie = pos;
45 135 : elems->wpa_ie_len = elen;
46 135 : break;
47 : case WMM_OUI_TYPE:
48 : /* WMM information element */
49 16862 : if (elen < 5) {
50 1 : wpa_printf(MSG_MSGDUMP, "short WMM "
51 : "information element ignored "
52 : "(len=%lu)",
53 : (unsigned long) elen);
54 1 : return -1;
55 : }
56 16861 : switch (pos[4]) {
57 : case WMM_OUI_SUBTYPE_INFORMATION_ELEMENT:
58 : case WMM_OUI_SUBTYPE_PARAMETER_ELEMENT:
59 : /*
60 : * Share same pointer since only one of these
61 : * is used and they start with same data.
62 : * Length field can be used to distinguish the
63 : * IEs.
64 : */
65 16840 : elems->wmm = pos;
66 16840 : elems->wmm_len = elen;
67 16840 : break;
68 : case WMM_OUI_SUBTYPE_TSPEC_ELEMENT:
69 20 : elems->wmm_tspec = pos;
70 20 : elems->wmm_tspec_len = elen;
71 20 : break;
72 : default:
73 1 : wpa_printf(MSG_EXCESSIVE, "unknown WMM "
74 : "information element ignored "
75 : "(subtype=%d len=%lu)",
76 1 : pos[4], (unsigned long) elen);
77 1 : return -1;
78 : }
79 16860 : break;
80 : case 4:
81 : /* Wi-Fi Protected Setup (WPS) IE */
82 10181 : elems->wps_ie = pos;
83 10181 : elems->wps_ie_len = elen;
84 10181 : break;
85 : default:
86 1 : wpa_printf(MSG_EXCESSIVE, "Unknown Microsoft "
87 : "information element ignored "
88 : "(type=%d len=%lu)",
89 1 : pos[3], (unsigned long) elen);
90 1 : return -1;
91 : }
92 27176 : break;
93 :
94 : case OUI_WFA:
95 12139 : switch (pos[3]) {
96 : case P2P_OUI_TYPE:
97 : /* Wi-Fi Alliance - P2P IE */
98 10296 : elems->p2p = pos;
99 10296 : elems->p2p_len = elen;
100 10296 : break;
101 : case WFD_OUI_TYPE:
102 : /* Wi-Fi Alliance - WFD IE */
103 275 : elems->wfd = pos;
104 275 : elems->wfd_len = elen;
105 275 : break;
106 : case HS20_INDICATION_OUI_TYPE:
107 : /* Hotspot 2.0 */
108 1564 : elems->hs20 = pos;
109 1564 : elems->hs20_len = elen;
110 1564 : break;
111 : case HS20_OSEN_OUI_TYPE:
112 : /* Hotspot 2.0 OSEN */
113 3 : elems->osen = pos;
114 3 : elems->osen_len = elen;
115 3 : break;
116 : default:
117 1 : wpa_printf(MSG_MSGDUMP, "Unknown WFA "
118 : "information element ignored "
119 : "(type=%d len=%lu)",
120 1 : pos[3], (unsigned long) elen);
121 1 : return -1;
122 : }
123 12138 : break;
124 :
125 : case OUI_BROADCOM:
126 9 : switch (pos[3]) {
127 : case VENDOR_HT_CAPAB_OUI_TYPE:
128 2 : elems->vendor_ht_cap = pos;
129 2 : elems->vendor_ht_cap_len = elen;
130 2 : break;
131 : case VENDOR_VHT_TYPE:
132 12 : if (elen > 4 &&
133 9 : (pos[4] == VENDOR_VHT_SUBTYPE ||
134 3 : pos[4] == VENDOR_VHT_SUBTYPE2)) {
135 6 : elems->vendor_vht = pos;
136 6 : elems->vendor_vht_len = elen;
137 : } else
138 0 : return -1;
139 6 : break;
140 : default:
141 1 : wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom "
142 : "information element ignored "
143 : "(type=%d len=%lu)",
144 1 : pos[3], (unsigned long) elen);
145 1 : return -1;
146 : }
147 8 : break;
148 :
149 : default:
150 72 : wpa_printf(MSG_EXCESSIVE, "unknown vendor specific "
151 : "information element ignored (vendor OUI "
152 : "%02x:%02x:%02x len=%lu)",
153 72 : pos[0], pos[1], pos[2], (unsigned long) elen);
154 24 : return -1;
155 : }
156 :
157 39322 : return 0;
158 : }
159 :
160 :
161 : /**
162 : * ieee802_11_parse_elems - Parse information elements in management frames
163 : * @start: Pointer to the start of IEs
164 : * @len: Length of IE buffer in octets
165 : * @elems: Data structure for parsed elements
166 : * @show_errors: Whether to show parsing errors in debug log
167 : * Returns: Parsing result
168 : */
169 27617 : ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
170 : struct ieee802_11_elems *elems,
171 : int show_errors)
172 : {
173 27617 : size_t left = len;
174 27617 : const u8 *pos = start;
175 27617 : int unknown = 0;
176 :
177 27617 : os_memset(elems, 0, sizeof(*elems));
178 :
179 259497 : while (left >= 2) {
180 : u8 id, elen;
181 :
182 204266 : id = *pos++;
183 204266 : elen = *pos++;
184 204266 : left -= 2;
185 :
186 204266 : if (elen > left) {
187 3 : if (show_errors) {
188 2 : wpa_printf(MSG_DEBUG, "IEEE 802.11 element "
189 : "parse failed (id=%d elen=%d "
190 : "left=%lu)",
191 : id, elen, (unsigned long) left);
192 2 : wpa_hexdump(MSG_MSGDUMP, "IEs", start, len);
193 : }
194 3 : return ParseFailed;
195 : }
196 :
197 204263 : switch (id) {
198 : case WLAN_EID_SSID:
199 16461 : elems->ssid = pos;
200 16461 : elems->ssid_len = elen;
201 16461 : break;
202 : case WLAN_EID_SUPP_RATES:
203 24166 : elems->supp_rates = pos;
204 24166 : elems->supp_rates_len = elen;
205 24166 : break;
206 : case WLAN_EID_DS_PARAMS:
207 13093 : elems->ds_params = pos;
208 13093 : elems->ds_params_len = elen;
209 13093 : break;
210 : case WLAN_EID_CF_PARAMS:
211 : case WLAN_EID_TIM:
212 5767 : break;
213 : case WLAN_EID_CHALLENGE:
214 1 : elems->challenge = pos;
215 1 : elems->challenge_len = elen;
216 1 : break;
217 : case WLAN_EID_ERP_INFO:
218 6243 : elems->erp_info = pos;
219 6243 : elems->erp_info_len = elen;
220 6243 : break;
221 : case WLAN_EID_EXT_SUPP_RATES:
222 17064 : elems->ext_supp_rates = pos;
223 17064 : elems->ext_supp_rates_len = elen;
224 17064 : break;
225 : case WLAN_EID_VENDOR_SPECIFIC:
226 39354 : if (ieee802_11_parse_vendor_specific(pos, elen,
227 : elems,
228 : show_errors))
229 32 : unknown++;
230 39354 : break;
231 : case WLAN_EID_RSN:
232 8257 : elems->rsn_ie = pos;
233 8257 : elems->rsn_ie_len = elen;
234 8257 : break;
235 : case WLAN_EID_PWR_CAPABILITY:
236 2 : break;
237 : case WLAN_EID_SUPPORTED_CHANNELS:
238 1 : elems->supp_channels = pos;
239 1 : elems->supp_channels_len = elen;
240 1 : break;
241 : case WLAN_EID_MOBILITY_DOMAIN:
242 1934 : elems->mdie = pos;
243 1934 : elems->mdie_len = elen;
244 1934 : break;
245 : case WLAN_EID_FAST_BSS_TRANSITION:
246 1180 : elems->ftie = pos;
247 1180 : elems->ftie_len = elen;
248 1180 : break;
249 : case WLAN_EID_TIMEOUT_INTERVAL:
250 1 : elems->timeout_int = pos;
251 1 : elems->timeout_int_len = elen;
252 1 : break;
253 : case WLAN_EID_HT_CAP:
254 23160 : elems->ht_capabilities = pos;
255 23160 : elems->ht_capabilities_len = elen;
256 23160 : break;
257 : case WLAN_EID_HT_OPERATION:
258 13923 : elems->ht_operation = pos;
259 13923 : elems->ht_operation_len = elen;
260 13923 : break;
261 : case WLAN_EID_MESH_CONFIG:
262 144 : elems->mesh_config = pos;
263 144 : elems->mesh_config_len = elen;
264 144 : break;
265 : case WLAN_EID_MESH_ID:
266 3257 : elems->mesh_id = pos;
267 3257 : elems->mesh_id_len = elen;
268 3257 : break;
269 : case WLAN_EID_PEER_MGMT:
270 111 : elems->peer_mgmt = pos;
271 111 : elems->peer_mgmt_len = elen;
272 111 : break;
273 : case WLAN_EID_VHT_CAP:
274 132 : elems->vht_capabilities = pos;
275 132 : elems->vht_capabilities_len = elen;
276 132 : break;
277 : case WLAN_EID_VHT_OPERATION:
278 46 : elems->vht_operation = pos;
279 46 : elems->vht_operation_len = elen;
280 46 : break;
281 : case WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION:
282 2 : if (elen != 1)
283 1 : break;
284 1 : elems->vht_opmode_notif = pos;
285 1 : break;
286 : case WLAN_EID_LINK_ID:
287 2 : if (elen < 18)
288 1 : break;
289 1 : elems->link_id = pos;
290 1 : break;
291 : case WLAN_EID_INTERWORKING:
292 1383 : elems->interworking = pos;
293 1383 : elems->interworking_len = elen;
294 1383 : break;
295 : case WLAN_EID_QOS_MAP_SET:
296 4 : if (elen < 16)
297 1 : break;
298 3 : elems->qos_map_set = pos;
299 3 : elems->qos_map_set_len = elen;
300 3 : break;
301 : case WLAN_EID_EXT_CAPAB:
302 19816 : elems->ext_capab = pos;
303 19816 : elems->ext_capab_len = elen;
304 19816 : break;
305 : case WLAN_EID_BSS_MAX_IDLE_PERIOD:
306 7620 : if (elen < 3)
307 1 : break;
308 7619 : elems->bss_max_idle_period = pos;
309 7619 : break;
310 : case WLAN_EID_SSID_LIST:
311 1 : elems->ssid_list = pos;
312 1 : elems->ssid_list_len = elen;
313 1 : break;
314 : case WLAN_EID_AMPE:
315 0 : elems->ampe = pos;
316 0 : elems->ampe_len = elen;
317 0 : break;
318 : case WLAN_EID_MIC:
319 25 : elems->mic = pos;
320 25 : elems->mic_len = elen;
321 : /* after mic everything is encrypted, so stop. */
322 25 : left = elen;
323 25 : break;
324 : default:
325 1113 : unknown++;
326 1113 : if (!show_errors)
327 1099 : break;
328 14 : wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse "
329 : "ignored unknown element (id=%d elen=%d)",
330 : id, elen);
331 14 : break;
332 : }
333 :
334 204263 : left -= elen;
335 204263 : pos += elen;
336 : }
337 :
338 27614 : if (left)
339 3 : return ParseFailed;
340 :
341 27611 : return unknown ? ParseUnknown : ParseOK;
342 : }
343 :
344 :
345 244 : int ieee802_11_ie_count(const u8 *ies, size_t ies_len)
346 : {
347 244 : int count = 0;
348 : const u8 *pos, *end;
349 :
350 244 : if (ies == NULL)
351 221 : return 0;
352 :
353 23 : pos = ies;
354 23 : end = ies + ies_len;
355 :
356 68 : while (pos + 2 <= end) {
357 23 : if (pos + 2 + pos[1] > end)
358 1 : break;
359 22 : count++;
360 22 : pos += 2 + pos[1];
361 : }
362 :
363 23 : return count;
364 : }
365 :
366 :
367 12603 : struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
368 : u32 oui_type)
369 : {
370 : struct wpabuf *buf;
371 : const u8 *end, *pos, *ie;
372 :
373 12603 : pos = ies;
374 12603 : end = ies + ies_len;
375 12603 : ie = NULL;
376 :
377 88338 : while (pos + 1 < end) {
378 73330 : if (pos + 2 + pos[1] > end)
379 1 : return NULL;
380 93870 : if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
381 20541 : WPA_GET_BE32(&pos[2]) == oui_type) {
382 10197 : ie = pos;
383 10197 : break;
384 : }
385 63132 : pos += 2 + pos[1];
386 : }
387 :
388 12602 : if (ie == NULL)
389 2405 : return NULL; /* No specified vendor IE found */
390 :
391 10197 : buf = wpabuf_alloc(ies_len);
392 10197 : if (buf == NULL)
393 0 : return NULL;
394 :
395 : /*
396 : * There may be multiple vendor IEs in the message, so need to
397 : * concatenate their data fields.
398 : */
399 37128 : while (pos + 1 < end) {
400 16734 : if (pos + 2 + pos[1] > end)
401 0 : break;
402 31999 : if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
403 15265 : WPA_GET_BE32(&pos[2]) == oui_type)
404 10226 : wpabuf_put_data(buf, pos + 6, pos[1] - 4);
405 16734 : pos += 2 + pos[1];
406 : }
407 :
408 10197 : return buf;
409 : }
410 :
411 :
412 19328 : const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len)
413 : {
414 : u16 fc, type, stype;
415 :
416 : /*
417 : * PS-Poll frames are 16 bytes. All other frames are
418 : * 24 bytes or longer.
419 : */
420 19328 : if (len < 16)
421 0 : return NULL;
422 :
423 19328 : fc = le_to_host16(hdr->frame_control);
424 19328 : type = WLAN_FC_GET_TYPE(fc);
425 19328 : stype = WLAN_FC_GET_STYPE(fc);
426 :
427 19328 : switch (type) {
428 : case WLAN_FC_TYPE_DATA:
429 1 : if (len < 24)
430 0 : return NULL;
431 1 : switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
432 : case WLAN_FC_FROMDS | WLAN_FC_TODS:
433 : case WLAN_FC_TODS:
434 1 : return hdr->addr1;
435 : case WLAN_FC_FROMDS:
436 0 : return hdr->addr2;
437 : default:
438 0 : return NULL;
439 : }
440 : case WLAN_FC_TYPE_CTRL:
441 0 : if (stype != WLAN_FC_STYPE_PSPOLL)
442 0 : return NULL;
443 0 : return hdr->addr1;
444 : case WLAN_FC_TYPE_MGMT:
445 19327 : return hdr->addr3;
446 : default:
447 0 : return NULL;
448 : }
449 : }
450 :
451 :
452 42 : int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
453 : const char *name, const char *val)
454 : {
455 : int num, v;
456 : const char *pos;
457 : struct hostapd_wmm_ac_params *ac;
458 :
459 : /* skip 'wme_ac_' or 'wmm_ac_' prefix */
460 42 : pos = name + 7;
461 42 : if (os_strncmp(pos, "be_", 3) == 0) {
462 6 : num = 0;
463 6 : pos += 3;
464 36 : } else if (os_strncmp(pos, "bk_", 3) == 0) {
465 13 : num = 1;
466 13 : pos += 3;
467 23 : } else if (os_strncmp(pos, "vi_", 3) == 0) {
468 11 : num = 2;
469 11 : pos += 3;
470 12 : } else if (os_strncmp(pos, "vo_", 3) == 0) {
471 11 : num = 3;
472 11 : pos += 3;
473 : } else {
474 1 : wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos);
475 1 : return -1;
476 : }
477 :
478 41 : ac = &wmm_ac_params[num];
479 :
480 41 : if (os_strcmp(pos, "aifs") == 0) {
481 6 : v = atoi(val);
482 6 : if (v < 1 || v > 255) {
483 2 : wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v);
484 2 : return -1;
485 : }
486 4 : ac->aifs = v;
487 35 : } else if (os_strcmp(pos, "cwmin") == 0) {
488 6 : v = atoi(val);
489 6 : if (v < 0 || v > 12) {
490 2 : wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v);
491 2 : return -1;
492 : }
493 4 : ac->cwmin = v;
494 29 : } else if (os_strcmp(pos, "cwmax") == 0) {
495 6 : v = atoi(val);
496 6 : if (v < 0 || v > 12) {
497 2 : wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v);
498 2 : return -1;
499 : }
500 4 : ac->cwmax = v;
501 23 : } else if (os_strcmp(pos, "txop_limit") == 0) {
502 6 : v = atoi(val);
503 6 : if (v < 0 || v > 0xffff) {
504 2 : wpa_printf(MSG_ERROR, "Invalid txop value %d", v);
505 2 : return -1;
506 : }
507 4 : ac->txop_limit = v;
508 17 : } else if (os_strcmp(pos, "acm") == 0) {
509 16 : v = atoi(val);
510 16 : if (v < 0 || v > 1) {
511 2 : wpa_printf(MSG_ERROR, "Invalid acm value %d", v);
512 2 : return -1;
513 : }
514 14 : ac->admission_control_mandatory = v;
515 : } else {
516 1 : wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos);
517 1 : return -1;
518 : }
519 :
520 30 : return 0;
521 : }
522 :
523 :
524 339320 : enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
525 : {
526 339320 : enum hostapd_hw_mode mode = NUM_HOSTAPD_MODES;
527 :
528 339320 : if (freq >= 2412 && freq <= 2472) {
529 116335 : mode = HOSTAPD_MODE_IEEE80211G;
530 116335 : *channel = (freq - 2407) / 5;
531 222985 : } else if (freq == 2484) {
532 8919 : mode = HOSTAPD_MODE_IEEE80211B;
533 8919 : *channel = 14;
534 214066 : } else if (freq >= 4900 && freq < 5000) {
535 0 : mode = HOSTAPD_MODE_IEEE80211A;
536 0 : *channel = (freq - 4000) / 5;
537 214066 : } else if (freq >= 5000 && freq < 5900) {
538 214066 : mode = HOSTAPD_MODE_IEEE80211A;
539 214066 : *channel = (freq - 5000) / 5;
540 0 : } else if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) {
541 0 : mode = HOSTAPD_MODE_IEEE80211AD;
542 0 : *channel = (freq - 56160) / 2160;
543 : }
544 :
545 339320 : return mode;
546 : }
547 :
548 :
549 : static const char *us_op_class_cc[] = {
550 : "US", "CA", NULL
551 : };
552 :
553 : static const char *eu_op_class_cc[] = {
554 : "AL", "AM", "AT", "AZ", "BA", "BE", "BG", "BY", "CH", "CY", "CZ", "DE",
555 : "DK", "EE", "EL", "ES", "FI", "FR", "GE", "HR", "HU", "IE", "IS", "IT",
556 : "LI", "LT", "LU", "LV", "MD", "ME", "MK", "MT", "NL", "NO", "PL", "PT",
557 : "RO", "RS", "RU", "SE", "SI", "SK", "TR", "UA", "UK", NULL
558 : };
559 :
560 : static const char *jp_op_class_cc[] = {
561 : "JP", NULL
562 : };
563 :
564 : static const char *cn_op_class_cc[] = {
565 : "CN", "CA", NULL
566 : };
567 :
568 :
569 36886 : static int country_match(const char *cc[], const char *country)
570 : {
571 : int i;
572 :
573 36886 : if (country == NULL)
574 36864 : return 0;
575 145 : for (i = 0; cc[i]; i++) {
576 129 : if (cc[i][0] == country[0] && cc[i][1] == country[1])
577 6 : return 1;
578 : }
579 :
580 16 : return 0;
581 : }
582 :
583 :
584 0 : static int ieee80211_chan_to_freq_us(u8 op_class, u8 chan)
585 : {
586 0 : switch (op_class) {
587 : case 12: /* channels 1..11 */
588 : case 32: /* channels 1..7; 40 MHz */
589 : case 33: /* channels 5..11; 40 MHz */
590 0 : if (chan < 1 || chan > 11)
591 0 : return -1;
592 0 : return 2407 + 5 * chan;
593 : case 1: /* channels 36,40,44,48 */
594 : case 2: /* channels 52,56,60,64; dfs */
595 : case 22: /* channels 36,44; 40 MHz */
596 : case 23: /* channels 52,60; 40 MHz */
597 : case 27: /* channels 40,48; 40 MHz */
598 : case 28: /* channels 56,64; 40 MHz */
599 0 : if (chan < 36 || chan > 64)
600 0 : return -1;
601 0 : return 5000 + 5 * chan;
602 : case 4: /* channels 100-144 */
603 : case 24: /* channels 100-140; 40 MHz */
604 0 : if (chan < 100 || chan > 144)
605 0 : return -1;
606 0 : return 5000 + 5 * chan;
607 : case 3: /* channels 149,153,157,161 */
608 : case 25: /* channels 149,157; 40 MHz */
609 : case 26: /* channels 149,157; 40 MHz */
610 : case 30: /* channels 153,161; 40 MHz */
611 : case 31: /* channels 153,161; 40 MHz */
612 0 : if (chan < 149 || chan > 161)
613 0 : return -1;
614 0 : return 5000 + 5 * chan;
615 : case 34: /* 60 GHz band, channels 1..3 */
616 0 : if (chan < 1 || chan > 3)
617 0 : return -1;
618 0 : return 56160 + 2160 * chan;
619 : }
620 0 : return -1;
621 : }
622 :
623 :
624 6 : static int ieee80211_chan_to_freq_eu(u8 op_class, u8 chan)
625 : {
626 6 : switch (op_class) {
627 : case 4: /* channels 1..13 */
628 : case 11: /* channels 1..9; 40 MHz */
629 : case 12: /* channels 5..13; 40 MHz */
630 0 : if (chan < 1 || chan > 13)
631 0 : return -1;
632 0 : return 2407 + 5 * chan;
633 : case 1: /* channels 36,40,44,48 */
634 : case 2: /* channels 52,56,60,64; dfs */
635 : case 5: /* channels 36,44; 40 MHz */
636 : case 6: /* channels 52,60; 40 MHz */
637 : case 8: /* channels 40,48; 40 MHz */
638 : case 9: /* channels 56,64; 40 MHz */
639 1 : if (chan < 36 || chan > 64)
640 0 : return -1;
641 1 : return 5000 + 5 * chan;
642 : case 3: /* channels 100-140 */
643 : case 7: /* channels 100-132; 40 MHz */
644 : case 10: /* channels 104-136; 40 MHz */
645 : case 16: /* channels 100-140 */
646 0 : if (chan < 100 || chan > 140)
647 0 : return -1;
648 0 : return 5000 + 5 * chan;
649 : case 17: /* channels 149,153,157,161,165,169 */
650 0 : if (chan < 149 || chan > 169)
651 0 : return -1;
652 0 : return 5000 + 5 * chan;
653 : case 18: /* 60 GHz band, channels 1..4 */
654 0 : if (chan < 1 || chan > 4)
655 0 : return -1;
656 0 : return 56160 + 2160 * chan;
657 : }
658 5 : return -1;
659 : }
660 :
661 :
662 0 : static int ieee80211_chan_to_freq_jp(u8 op_class, u8 chan)
663 : {
664 0 : switch (op_class) {
665 : case 30: /* channels 1..13 */
666 : case 56: /* channels 1..9; 40 MHz */
667 : case 57: /* channels 5..13; 40 MHz */
668 0 : if (chan < 1 || chan > 13)
669 0 : return -1;
670 0 : return 2407 + 5 * chan;
671 : case 31: /* channel 14 */
672 0 : if (chan != 14)
673 0 : return -1;
674 0 : return 2414 + 5 * chan;
675 : case 1: /* channels 34,38,42,46(old) or 36,40,44,48 */
676 : case 32: /* channels 52,56,60,64 */
677 : case 33: /* channels 52,56,60,64 */
678 : case 36: /* channels 36,44; 40 MHz */
679 : case 37: /* channels 52,60; 40 MHz */
680 : case 38: /* channels 52,60; 40 MHz */
681 : case 41: /* channels 40,48; 40 MHz */
682 : case 42: /* channels 56,64; 40 MHz */
683 : case 43: /* channels 56,64; 40 MHz */
684 0 : if (chan < 34 || chan > 64)
685 0 : return -1;
686 0 : return 5000 + 5 * chan;
687 : case 34: /* channels 100-140 */
688 : case 35: /* channels 100-140 */
689 : case 39: /* channels 100-132; 40 MHz */
690 : case 40: /* channels 100-132; 40 MHz */
691 : case 44: /* channels 104-136; 40 MHz */
692 : case 45: /* channels 104-136; 40 MHz */
693 : case 58: /* channels 100-140 */
694 0 : if (chan < 100 || chan > 140)
695 0 : return -1;
696 0 : return 5000 + 5 * chan;
697 : case 59: /* 60 GHz band, channels 1..4 */
698 0 : if (chan < 1 || chan > 3)
699 0 : return -1;
700 0 : return 56160 + 2160 * chan;
701 : }
702 0 : return -1;
703 : }
704 :
705 :
706 0 : static int ieee80211_chan_to_freq_cn(u8 op_class, u8 chan)
707 : {
708 0 : switch (op_class) {
709 : case 7: /* channels 1..13 */
710 : case 8: /* channels 1..9; 40 MHz */
711 : case 9: /* channels 5..13; 40 MHz */
712 0 : if (chan < 1 || chan > 13)
713 0 : return -1;
714 0 : return 2407 + 5 * chan;
715 : case 1: /* channels 36,40,44,48 */
716 : case 2: /* channels 52,56,60,64; dfs */
717 : case 4: /* channels 36,44; 40 MHz */
718 : case 5: /* channels 52,60; 40 MHz */
719 0 : if (chan < 36 || chan > 64)
720 0 : return -1;
721 0 : return 5000 + 5 * chan;
722 : case 3: /* channels 149,153,157,161,165 */
723 : case 6: /* channels 149,157; 40 MHz */
724 0 : if (chan < 149 || chan > 165)
725 0 : return -1;
726 0 : return 5000 + 5 * chan;
727 : }
728 0 : return -1;
729 : }
730 :
731 :
732 9221 : static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan)
733 : {
734 : /* Table E-4 in IEEE Std 802.11-2012 - Global operating classes */
735 9221 : switch (op_class) {
736 : case 81:
737 : /* channels 1..13 */
738 8834 : if (chan < 1 || chan > 13)
739 1 : return -1;
740 8833 : return 2407 + 5 * chan;
741 : case 82:
742 : /* channel 14 */
743 0 : if (chan != 14)
744 0 : return -1;
745 0 : return 2414 + 5 * chan;
746 : case 83: /* channels 1..9; 40 MHz */
747 : case 84: /* channels 5..13; 40 MHz */
748 0 : if (chan < 1 || chan > 13)
749 0 : return -1;
750 0 : return 2407 + 5 * chan;
751 : case 115: /* channels 36,40,44,48; indoor only */
752 : case 116: /* channels 36,44; 40 MHz; indoor only */
753 : case 117: /* channels 40,48; 40 MHz; indoor only */
754 : case 118: /* channels 52,56,60,64; dfs */
755 : case 119: /* channels 52,60; 40 MHz; dfs */
756 : case 120: /* channels 56,64; 40 MHz; dfs */
757 147 : if (chan < 36 || chan > 64)
758 0 : return -1;
759 147 : return 5000 + 5 * chan;
760 : case 121: /* channels 100-140 */
761 : case 122: /* channels 100-142; 40 MHz */
762 : case 123: /* channels 104-136; 40 MHz */
763 0 : if (chan < 100 || chan > 140)
764 0 : return -1;
765 0 : return 5000 + 5 * chan;
766 : case 124: /* channels 149,153,157,161 */
767 : case 125: /* channels 149,153,157,161,165,169 */
768 : case 126: /* channels 149,157; 40 MHz */
769 : case 127: /* channels 153,161; 40 MHz */
770 168 : if (chan < 149 || chan > 161)
771 0 : return -1;
772 168 : return 5000 + 5 * chan;
773 : case 128: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
774 : case 130: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
775 72 : if (chan < 36 || chan > 161)
776 0 : return -1;
777 72 : return 5000 + 5 * chan;
778 : case 129: /* center freqs 50, 114; 160 MHz */
779 0 : if (chan < 50 || chan > 114)
780 0 : return -1;
781 0 : return 5000 + 5 * chan;
782 : case 180: /* 60 GHz band, channels 1..4 */
783 0 : if (chan < 1 || chan > 4)
784 0 : return -1;
785 0 : return 56160 + 2160 * chan;
786 : }
787 0 : return -1;
788 : }
789 :
790 : /**
791 : * ieee80211_chan_to_freq - Convert channel info to frequency
792 : * @country: Country code, if known; otherwise, global operating class is used
793 : * @op_class: Operating class
794 : * @chan: Channel number
795 : * Returns: Frequency in MHz or -1 if the specified channel is unknown
796 : */
797 9222 : int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan)
798 : {
799 : int freq;
800 :
801 9222 : if (country_match(us_op_class_cc, country)) {
802 0 : freq = ieee80211_chan_to_freq_us(op_class, chan);
803 0 : if (freq > 0)
804 0 : return freq;
805 : }
806 :
807 9222 : if (country_match(eu_op_class_cc, country)) {
808 6 : freq = ieee80211_chan_to_freq_eu(op_class, chan);
809 6 : if (freq > 0)
810 1 : return freq;
811 : }
812 :
813 9221 : if (country_match(jp_op_class_cc, country)) {
814 0 : freq = ieee80211_chan_to_freq_jp(op_class, chan);
815 0 : if (freq > 0)
816 0 : return freq;
817 : }
818 :
819 9221 : if (country_match(cn_op_class_cc, country)) {
820 0 : freq = ieee80211_chan_to_freq_cn(op_class, chan);
821 0 : if (freq > 0)
822 0 : return freq;
823 : }
824 :
825 9221 : return ieee80211_chan_to_freq_global(op_class, chan);
826 : }
827 :
828 :
829 644 : int ieee80211_is_dfs(int freq)
830 : {
831 : /* TODO: this could be more accurate to better cover all domains */
832 644 : return (freq >= 5260 && freq <= 5320) || (freq >= 5500 && freq <= 5700);
833 : }
834 :
835 :
836 9684 : static int is_11b(u8 rate)
837 : {
838 9684 : return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16;
839 : }
840 :
841 :
842 1191 : int supp_rates_11b_only(struct ieee802_11_elems *elems)
843 : {
844 1191 : int num_11b = 0, num_others = 0;
845 : int i;
846 :
847 1191 : if (elems->supp_rates == NULL && elems->ext_supp_rates == NULL)
848 0 : return 0;
849 :
850 10719 : for (i = 0; elems->supp_rates && i < elems->supp_rates_len; i++) {
851 9528 : if (is_11b(elems->supp_rates[i]))
852 156 : num_11b++;
853 : else
854 9372 : num_others++;
855 : }
856 :
857 2538 : for (i = 0; elems->ext_supp_rates && i < elems->ext_supp_rates_len;
858 156 : i++) {
859 156 : if (is_11b(elems->ext_supp_rates[i]))
860 0 : num_11b++;
861 : else
862 156 : num_others++;
863 : }
864 :
865 1191 : return num_11b > 0 && num_others == 0;
866 : }
867 :
868 :
869 52373 : const char * fc2str(u16 fc)
870 : {
871 52373 : u16 stype = WLAN_FC_GET_STYPE(fc);
872 : #define C2S(x) case x: return #x;
873 :
874 52373 : switch (WLAN_FC_GET_TYPE(fc)) {
875 : case WLAN_FC_TYPE_MGMT:
876 52373 : switch (stype) {
877 3699 : C2S(WLAN_FC_STYPE_ASSOC_REQ)
878 2260 : C2S(WLAN_FC_STYPE_ASSOC_RESP)
879 1750 : C2S(WLAN_FC_STYPE_REASSOC_REQ)
880 306 : C2S(WLAN_FC_STYPE_REASSOC_RESP)
881 5919 : C2S(WLAN_FC_STYPE_PROBE_REQ)
882 3052 : C2S(WLAN_FC_STYPE_PROBE_RESP)
883 0 : C2S(WLAN_FC_STYPE_BEACON)
884 0 : C2S(WLAN_FC_STYPE_ATIM)
885 1451 : C2S(WLAN_FC_STYPE_DISASSOC)
886 7496 : C2S(WLAN_FC_STYPE_AUTH)
887 6317 : C2S(WLAN_FC_STYPE_DEAUTH)
888 20123 : C2S(WLAN_FC_STYPE_ACTION)
889 : }
890 0 : break;
891 : case WLAN_FC_TYPE_CTRL:
892 0 : switch (stype) {
893 0 : C2S(WLAN_FC_STYPE_PSPOLL)
894 0 : C2S(WLAN_FC_STYPE_RTS)
895 0 : C2S(WLAN_FC_STYPE_CTS)
896 0 : C2S(WLAN_FC_STYPE_ACK)
897 0 : C2S(WLAN_FC_STYPE_CFEND)
898 0 : C2S(WLAN_FC_STYPE_CFENDACK)
899 : }
900 0 : break;
901 : case WLAN_FC_TYPE_DATA:
902 0 : switch (stype) {
903 0 : C2S(WLAN_FC_STYPE_DATA)
904 0 : C2S(WLAN_FC_STYPE_DATA_CFACK)
905 0 : C2S(WLAN_FC_STYPE_DATA_CFPOLL)
906 0 : C2S(WLAN_FC_STYPE_DATA_CFACKPOLL)
907 0 : C2S(WLAN_FC_STYPE_NULLFUNC)
908 0 : C2S(WLAN_FC_STYPE_CFACK)
909 0 : C2S(WLAN_FC_STYPE_CFPOLL)
910 0 : C2S(WLAN_FC_STYPE_CFACKPOLL)
911 0 : C2S(WLAN_FC_STYPE_QOS_DATA)
912 0 : C2S(WLAN_FC_STYPE_QOS_DATA_CFACK)
913 0 : C2S(WLAN_FC_STYPE_QOS_DATA_CFPOLL)
914 0 : C2S(WLAN_FC_STYPE_QOS_DATA_CFACKPOLL)
915 0 : C2S(WLAN_FC_STYPE_QOS_NULL)
916 0 : C2S(WLAN_FC_STYPE_QOS_CFPOLL)
917 0 : C2S(WLAN_FC_STYPE_QOS_CFACKPOLL)
918 : }
919 0 : break;
920 : }
921 0 : return "WLAN_FC_TYPE_UNKNOWN";
922 : #undef C2S
923 : }
|