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