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 9009 : 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 9009 : if (elen < 4) {
27 0 : if (show_errors) {
28 0 : wpa_printf(MSG_MSGDUMP, "short vendor specific "
29 : "information element ignored (len=%lu)",
30 : (unsigned long) elen);
31 : }
32 0 : return -1;
33 : }
34 :
35 9009 : oui = WPA_GET_BE24(pos);
36 9009 : switch (oui) {
37 : case OUI_MICROSOFT:
38 : /* Microsoft/Wi-Fi information elements are further typed and
39 : * subtyped */
40 6328 : switch (pos[3]) {
41 : case 1:
42 : /* Microsoft OUI (00:50:F2) with OUI Type 1:
43 : * real WPA information element */
44 59 : elems->wpa_ie = pos;
45 59 : elems->wpa_ie_len = elen;
46 59 : break;
47 : case WMM_OUI_TYPE:
48 : /* WMM information element */
49 3967 : if (elen < 5) {
50 0 : wpa_printf(MSG_MSGDUMP, "short WMM "
51 : "information element ignored "
52 : "(len=%lu)",
53 : (unsigned long) elen);
54 0 : return -1;
55 : }
56 3967 : 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 3967 : elems->wmm = pos;
66 3967 : elems->wmm_len = elen;
67 3967 : break;
68 : case WMM_OUI_SUBTYPE_TSPEC_ELEMENT:
69 0 : elems->wmm_tspec = pos;
70 0 : elems->wmm_tspec_len = elen;
71 0 : break;
72 : default:
73 0 : wpa_printf(MSG_EXCESSIVE, "unknown WMM "
74 : "information element ignored "
75 : "(subtype=%d len=%lu)",
76 0 : pos[4], (unsigned long) elen);
77 0 : return -1;
78 : }
79 3967 : break;
80 : case 4:
81 : /* Wi-Fi Protected Setup (WPS) IE */
82 2302 : elems->wps_ie = pos;
83 2302 : elems->wps_ie_len = elen;
84 2302 : break;
85 : default:
86 0 : wpa_printf(MSG_EXCESSIVE, "Unknown Microsoft "
87 : "information element ignored "
88 : "(type=%d len=%lu)",
89 0 : pos[3], (unsigned long) elen);
90 0 : return -1;
91 : }
92 6328 : break;
93 :
94 : case OUI_WFA:
95 2681 : switch (pos[3]) {
96 : case P2P_OUI_TYPE:
97 : /* Wi-Fi Alliance - P2P IE */
98 1836 : elems->p2p = pos;
99 1836 : elems->p2p_len = elen;
100 1836 : break;
101 : case WFD_OUI_TYPE:
102 : /* Wi-Fi Alliance - WFD IE */
103 0 : elems->wfd = pos;
104 0 : elems->wfd_len = elen;
105 0 : break;
106 : case HS20_INDICATION_OUI_TYPE:
107 : /* Hotspot 2.0 */
108 843 : elems->hs20 = pos;
109 843 : elems->hs20_len = elen;
110 843 : break;
111 : case HS20_OSEN_OUI_TYPE:
112 : /* Hotspot 2.0 OSEN */
113 2 : elems->osen = pos;
114 2 : elems->osen_len = elen;
115 2 : break;
116 : default:
117 0 : wpa_printf(MSG_MSGDUMP, "Unknown WFA "
118 : "information element ignored "
119 : "(type=%d len=%lu)",
120 0 : pos[3], (unsigned long) elen);
121 0 : return -1;
122 : }
123 2681 : break;
124 :
125 : case OUI_BROADCOM:
126 0 : switch (pos[3]) {
127 : case VENDOR_HT_CAPAB_OUI_TYPE:
128 0 : elems->vendor_ht_cap = pos;
129 0 : elems->vendor_ht_cap_len = elen;
130 0 : break;
131 : default:
132 0 : wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom "
133 : "information element ignored "
134 : "(type=%d len=%lu)",
135 0 : pos[3], (unsigned long) elen);
136 0 : return -1;
137 : }
138 0 : break;
139 :
140 : default:
141 0 : wpa_printf(MSG_EXCESSIVE, "unknown vendor specific "
142 : "information element ignored (vendor OUI "
143 : "%02x:%02x:%02x len=%lu)",
144 0 : pos[0], pos[1], pos[2], (unsigned long) elen);
145 0 : return -1;
146 : }
147 :
148 9009 : return 0;
149 : }
150 :
151 :
152 : /**
153 : * ieee802_11_parse_elems - Parse information elements in management frames
154 : * @start: Pointer to the start of IEs
155 : * @len: Length of IE buffer in octets
156 : * @elems: Data structure for parsed elements
157 : * @show_errors: Whether to show parsing errors in debug log
158 : * Returns: Parsing result
159 : */
160 5638 : ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
161 : struct ieee802_11_elems *elems,
162 : int show_errors)
163 : {
164 5638 : size_t left = len;
165 5638 : const u8 *pos = start;
166 5638 : int unknown = 0;
167 :
168 5638 : os_memset(elems, 0, sizeof(*elems));
169 :
170 65860 : while (left >= 2) {
171 : u8 id, elen;
172 :
173 54584 : id = *pos++;
174 54584 : elen = *pos++;
175 54584 : left -= 2;
176 :
177 54584 : if (elen > left) {
178 0 : if (show_errors) {
179 0 : wpa_printf(MSG_DEBUG, "IEEE 802.11 element "
180 : "parse failed (id=%d elen=%d "
181 : "left=%lu)",
182 : id, elen, (unsigned long) left);
183 0 : wpa_hexdump(MSG_MSGDUMP, "IEs", start, len);
184 : }
185 0 : return ParseFailed;
186 : }
187 :
188 54584 : switch (id) {
189 : case WLAN_EID_SSID:
190 5638 : elems->ssid = pos;
191 5638 : elems->ssid_len = elen;
192 5638 : break;
193 : case WLAN_EID_SUPP_RATES:
194 5638 : elems->supp_rates = pos;
195 5638 : elems->supp_rates_len = elen;
196 5638 : break;
197 : case WLAN_EID_DS_PARAMS:
198 4206 : elems->ds_params = pos;
199 4206 : elems->ds_params_len = elen;
200 4206 : break;
201 : case WLAN_EID_CF_PARAMS:
202 : case WLAN_EID_TIM:
203 2676 : break;
204 : case WLAN_EID_CHALLENGE:
205 0 : elems->challenge = pos;
206 0 : elems->challenge_len = elen;
207 0 : break;
208 : case WLAN_EID_ERP_INFO:
209 2625 : elems->erp_info = pos;
210 2625 : elems->erp_info_len = elen;
211 2625 : break;
212 : case WLAN_EID_EXT_SUPP_RATES:
213 5137 : elems->ext_supp_rates = pos;
214 5137 : elems->ext_supp_rates_len = elen;
215 5137 : break;
216 : case WLAN_EID_VENDOR_SPECIFIC:
217 9009 : if (ieee802_11_parse_vendor_specific(pos, elen,
218 : elems,
219 : show_errors))
220 0 : unknown++;
221 9009 : break;
222 : case WLAN_EID_RSN:
223 2982 : elems->rsn_ie = pos;
224 2982 : elems->rsn_ie_len = elen;
225 2982 : break;
226 : case WLAN_EID_PWR_CAPABILITY:
227 0 : break;
228 : case WLAN_EID_SUPPORTED_CHANNELS:
229 0 : elems->supp_channels = pos;
230 0 : elems->supp_channels_len = elen;
231 0 : break;
232 : case WLAN_EID_MOBILITY_DOMAIN:
233 916 : elems->mdie = pos;
234 916 : elems->mdie_len = elen;
235 916 : break;
236 : case WLAN_EID_FAST_BSS_TRANSITION:
237 221 : elems->ftie = pos;
238 221 : elems->ftie_len = elen;
239 221 : break;
240 : case WLAN_EID_TIMEOUT_INTERVAL:
241 0 : elems->timeout_int = pos;
242 0 : elems->timeout_int_len = elen;
243 0 : break;
244 : case WLAN_EID_HT_CAP:
245 5594 : elems->ht_capabilities = pos;
246 5594 : elems->ht_capabilities_len = elen;
247 5594 : break;
248 : case WLAN_EID_HT_OPERATION:
249 2662 : elems->ht_operation = pos;
250 2662 : elems->ht_operation_len = elen;
251 2662 : break;
252 : case WLAN_EID_VHT_CAP:
253 1659 : elems->vht_capabilities = pos;
254 1659 : elems->vht_capabilities_len = elen;
255 1659 : break;
256 : case WLAN_EID_VHT_OPERATION:
257 0 : elems->vht_operation = pos;
258 0 : elems->vht_operation_len = elen;
259 0 : break;
260 : case WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION:
261 0 : if (elen != 1)
262 0 : break;
263 0 : elems->vht_opmode_notif = pos;
264 0 : break;
265 : case WLAN_EID_LINK_ID:
266 0 : if (elen < 18)
267 0 : break;
268 0 : elems->link_id = pos;
269 0 : break;
270 : case WLAN_EID_INTERWORKING:
271 762 : elems->interworking = pos;
272 762 : elems->interworking_len = elen;
273 762 : break;
274 : case WLAN_EID_QOS_MAP_SET:
275 0 : if (elen < 16)
276 0 : break;
277 0 : elems->qos_map_set = pos;
278 0 : elems->qos_map_set_len = elen;
279 0 : break;
280 : case WLAN_EID_EXT_CAPAB:
281 4200 : elems->ext_capab = pos;
282 4200 : elems->ext_capab_len = elen;
283 4200 : break;
284 : case WLAN_EID_BSS_MAX_IDLE_PERIOD:
285 0 : if (elen < 3)
286 0 : break;
287 0 : elems->bss_max_idle_period = pos;
288 0 : break;
289 : case WLAN_EID_SSID_LIST:
290 0 : elems->ssid_list = pos;
291 0 : elems->ssid_list_len = elen;
292 0 : break;
293 : default:
294 659 : unknown++;
295 659 : if (!show_errors)
296 659 : break;
297 0 : wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse "
298 : "ignored unknown element (id=%d elen=%d)",
299 : id, elen);
300 0 : break;
301 : }
302 :
303 54584 : left -= elen;
304 54584 : pos += elen;
305 : }
306 :
307 5638 : if (left)
308 0 : return ParseFailed;
309 :
310 5638 : return unknown ? ParseUnknown : ParseOK;
311 : }
312 :
313 :
314 0 : int ieee802_11_ie_count(const u8 *ies, size_t ies_len)
315 : {
316 0 : int count = 0;
317 : const u8 *pos, *end;
318 :
319 0 : if (ies == NULL)
320 0 : return 0;
321 :
322 0 : pos = ies;
323 0 : end = ies + ies_len;
324 :
325 0 : while (pos + 2 <= end) {
326 0 : if (pos + 2 + pos[1] > end)
327 0 : break;
328 0 : count++;
329 0 : pos += 2 + pos[1];
330 : }
331 :
332 0 : return count;
333 : }
334 :
335 :
336 249 : struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
337 : u32 oui_type)
338 : {
339 : struct wpabuf *buf;
340 : const u8 *end, *pos, *ie;
341 :
342 249 : pos = ies;
343 249 : end = ies + ies_len;
344 249 : ie = NULL;
345 :
346 1980 : while (pos + 1 < end) {
347 1731 : if (pos + 2 + pos[1] > end)
348 0 : return NULL;
349 2064 : if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
350 333 : WPA_GET_BE32(&pos[2]) == oui_type) {
351 249 : ie = pos;
352 249 : break;
353 : }
354 1482 : pos += 2 + pos[1];
355 : }
356 :
357 249 : if (ie == NULL)
358 0 : return NULL; /* No specified vendor IE found */
359 :
360 249 : buf = wpabuf_alloc(ies_len);
361 249 : if (buf == NULL)
362 0 : return NULL;
363 :
364 : /*
365 : * There may be multiple vendor IEs in the message, so need to
366 : * concatenate their data fields.
367 : */
368 910 : while (pos + 1 < end) {
369 412 : if (pos + 2 + pos[1] > end)
370 0 : break;
371 824 : if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
372 412 : WPA_GET_BE32(&pos[2]) == oui_type)
373 249 : wpabuf_put_data(buf, pos + 6, pos[1] - 4);
374 412 : pos += 2 + pos[1];
375 : }
376 :
377 249 : return buf;
378 : }
379 :
380 :
381 11520 : const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len)
382 : {
383 : u16 fc, type, stype;
384 :
385 : /*
386 : * PS-Poll frames are 16 bytes. All other frames are
387 : * 24 bytes or longer.
388 : */
389 11520 : if (len < 16)
390 0 : return NULL;
391 :
392 11520 : fc = le_to_host16(hdr->frame_control);
393 11520 : type = WLAN_FC_GET_TYPE(fc);
394 11520 : stype = WLAN_FC_GET_STYPE(fc);
395 :
396 11520 : switch (type) {
397 : case WLAN_FC_TYPE_DATA:
398 0 : if (len < 24)
399 0 : return NULL;
400 0 : switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
401 : case WLAN_FC_FROMDS | WLAN_FC_TODS:
402 : case WLAN_FC_TODS:
403 0 : return hdr->addr1;
404 : case WLAN_FC_FROMDS:
405 0 : return hdr->addr2;
406 : default:
407 0 : return NULL;
408 : }
409 : case WLAN_FC_TYPE_CTRL:
410 0 : if (stype != WLAN_FC_STYPE_PSPOLL)
411 0 : return NULL;
412 0 : return hdr->addr1;
413 : case WLAN_FC_TYPE_MGMT:
414 11520 : return hdr->addr3;
415 : default:
416 0 : return NULL;
417 : }
418 : }
419 :
420 :
421 32 : int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
422 : const char *name, const char *val)
423 : {
424 : int num, v;
425 : const char *pos;
426 : struct hostapd_wmm_ac_params *ac;
427 :
428 : /* skip 'wme_ac_' or 'wmm_ac_' prefix */
429 32 : pos = name + 7;
430 32 : if (os_strncmp(pos, "be_", 3) == 0) {
431 6 : num = 0;
432 6 : pos += 3;
433 26 : } else if (os_strncmp(pos, "bk_", 3) == 0) {
434 13 : num = 1;
435 13 : pos += 3;
436 13 : } else if (os_strncmp(pos, "vi_", 3) == 0) {
437 6 : num = 2;
438 6 : pos += 3;
439 7 : } else if (os_strncmp(pos, "vo_", 3) == 0) {
440 6 : num = 3;
441 6 : pos += 3;
442 : } else {
443 1 : wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos);
444 1 : return -1;
445 : }
446 :
447 31 : ac = &wmm_ac_params[num];
448 :
449 31 : if (os_strcmp(pos, "aifs") == 0) {
450 6 : v = atoi(val);
451 6 : if (v < 1 || v > 255) {
452 2 : wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v);
453 2 : return -1;
454 : }
455 4 : ac->aifs = v;
456 25 : } else if (os_strcmp(pos, "cwmin") == 0) {
457 6 : v = atoi(val);
458 6 : if (v < 0 || v > 12) {
459 2 : wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v);
460 2 : return -1;
461 : }
462 4 : ac->cwmin = v;
463 19 : } else if (os_strcmp(pos, "cwmax") == 0) {
464 6 : v = atoi(val);
465 6 : if (v < 0 || v > 12) {
466 2 : wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v);
467 2 : return -1;
468 : }
469 4 : ac->cwmax = v;
470 13 : } else if (os_strcmp(pos, "txop_limit") == 0) {
471 6 : v = atoi(val);
472 6 : if (v < 0 || v > 0xffff) {
473 2 : wpa_printf(MSG_ERROR, "Invalid txop value %d", v);
474 2 : return -1;
475 : }
476 4 : ac->txop_limit = v;
477 7 : } else if (os_strcmp(pos, "acm") == 0) {
478 6 : v = atoi(val);
479 6 : if (v < 0 || v > 1) {
480 2 : wpa_printf(MSG_ERROR, "Invalid acm value %d", v);
481 2 : return -1;
482 : }
483 4 : ac->admission_control_mandatory = v;
484 : } else {
485 1 : wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos);
486 1 : return -1;
487 : }
488 :
489 20 : return 0;
490 : }
491 :
492 :
493 23990 : enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
494 : {
495 23990 : enum hostapd_hw_mode mode = NUM_HOSTAPD_MODES;
496 :
497 23990 : if (freq >= 2412 && freq <= 2472) {
498 8210 : mode = HOSTAPD_MODE_IEEE80211G;
499 8210 : *channel = (freq - 2407) / 5;
500 15780 : } else if (freq == 2484) {
501 632 : mode = HOSTAPD_MODE_IEEE80211B;
502 632 : *channel = 14;
503 15148 : } else if (freq >= 4900 && freq < 5000) {
504 0 : mode = HOSTAPD_MODE_IEEE80211A;
505 0 : *channel = (freq - 4000) / 5;
506 15148 : } else if (freq >= 5000 && freq < 5900) {
507 15148 : mode = HOSTAPD_MODE_IEEE80211A;
508 15148 : *channel = (freq - 5000) / 5;
509 0 : } else if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) {
510 0 : mode = HOSTAPD_MODE_IEEE80211AD;
511 0 : *channel = (freq - 56160) / 2160;
512 : }
513 :
514 23990 : return mode;
515 : }
516 :
517 :
518 0 : static int is_11b(u8 rate)
519 : {
520 0 : return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16;
521 : }
522 :
523 :
524 0 : int supp_rates_11b_only(struct ieee802_11_elems *elems)
525 : {
526 0 : int num_11b = 0, num_others = 0;
527 : int i;
528 :
529 0 : if (elems->supp_rates == NULL && elems->ext_supp_rates == NULL)
530 0 : return 0;
531 :
532 0 : for (i = 0; elems->supp_rates && i < elems->supp_rates_len; i++) {
533 0 : if (is_11b(elems->supp_rates[i]))
534 0 : num_11b++;
535 : else
536 0 : num_others++;
537 : }
538 :
539 0 : for (i = 0; elems->ext_supp_rates && i < elems->ext_supp_rates_len;
540 0 : i++) {
541 0 : if (is_11b(elems->ext_supp_rates[i]))
542 0 : num_11b++;
543 : else
544 0 : num_others++;
545 : }
546 :
547 0 : return num_11b > 0 && num_others == 0;
548 : }
549 :
550 :
551 16134 : const char * fc2str(u16 fc)
552 : {
553 16134 : u16 stype = WLAN_FC_GET_STYPE(fc);
554 : #define C2S(x) case x: return #x;
555 :
556 16134 : switch (WLAN_FC_GET_TYPE(fc)) {
557 : case WLAN_FC_TYPE_MGMT:
558 16134 : switch (stype) {
559 1706 : C2S(WLAN_FC_STYPE_ASSOC_REQ)
560 1052 : C2S(WLAN_FC_STYPE_ASSOC_RESP)
561 908 : C2S(WLAN_FC_STYPE_REASSOC_REQ)
562 258 : C2S(WLAN_FC_STYPE_REASSOC_RESP)
563 2139 : C2S(WLAN_FC_STYPE_PROBE_REQ)
564 1351 : C2S(WLAN_FC_STYPE_PROBE_RESP)
565 0 : C2S(WLAN_FC_STYPE_BEACON)
566 0 : C2S(WLAN_FC_STYPE_ATIM)
567 655 : C2S(WLAN_FC_STYPE_DISASSOC)
568 3154 : C2S(WLAN_FC_STYPE_AUTH)
569 3093 : C2S(WLAN_FC_STYPE_DEAUTH)
570 1818 : C2S(WLAN_FC_STYPE_ACTION)
571 : }
572 0 : break;
573 : case WLAN_FC_TYPE_CTRL:
574 0 : switch (stype) {
575 0 : C2S(WLAN_FC_STYPE_PSPOLL)
576 0 : C2S(WLAN_FC_STYPE_RTS)
577 0 : C2S(WLAN_FC_STYPE_CTS)
578 0 : C2S(WLAN_FC_STYPE_ACK)
579 0 : C2S(WLAN_FC_STYPE_CFEND)
580 0 : C2S(WLAN_FC_STYPE_CFENDACK)
581 : }
582 0 : break;
583 : case WLAN_FC_TYPE_DATA:
584 0 : switch (stype) {
585 0 : C2S(WLAN_FC_STYPE_DATA)
586 0 : C2S(WLAN_FC_STYPE_DATA_CFACK)
587 0 : C2S(WLAN_FC_STYPE_DATA_CFPOLL)
588 0 : C2S(WLAN_FC_STYPE_DATA_CFACKPOLL)
589 0 : C2S(WLAN_FC_STYPE_NULLFUNC)
590 0 : C2S(WLAN_FC_STYPE_CFACK)
591 0 : C2S(WLAN_FC_STYPE_CFPOLL)
592 0 : C2S(WLAN_FC_STYPE_CFACKPOLL)
593 0 : C2S(WLAN_FC_STYPE_QOS_DATA)
594 0 : C2S(WLAN_FC_STYPE_QOS_DATA_CFACK)
595 0 : C2S(WLAN_FC_STYPE_QOS_DATA_CFPOLL)
596 0 : C2S(WLAN_FC_STYPE_QOS_DATA_CFACKPOLL)
597 0 : C2S(WLAN_FC_STYPE_QOS_NULL)
598 0 : C2S(WLAN_FC_STYPE_QOS_CFPOLL)
599 0 : C2S(WLAN_FC_STYPE_QOS_CFACKPOLL)
600 : }
601 0 : break;
602 : }
603 0 : return "WLAN_FC_TYPE_UNKNOWN";
604 : #undef C2S
605 : }
|