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 default:
112 wpa_printf(MSG_MSGDUMP, "Unknown WFA "
113 "information element ignored "
114 "(type=%d len=%lu)\n",
115 pos[3], (unsigned long) elen);
116 return -1;
117 }
118 break;
119
120 case OUI_BROADCOM:
121 switch (pos[3]) {
122 case VENDOR_HT_CAPAB_OUI_TYPE:
123 elems->vendor_ht_cap = pos;
124 elems->vendor_ht_cap_len = elen;
125 break;
126 default:
127 wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom "
128 "information element ignored "
129 "(type=%d len=%lu)",
130 pos[3], (unsigned long) elen);
131 return -1;
132 }
133 break;
134
135 default:
136 wpa_printf(MSG_EXCESSIVE, "unknown vendor specific "
137 "information element ignored (vendor OUI "
138 "%02x:%02x:%02x len=%lu)",
139 pos[0], pos[1], pos[2], (unsigned long) elen);
140 return -1;
141 }
142
143 return 0;
144 }
145
146
147 /**
148 * ieee802_11_parse_elems - Parse information elements in management frames
149 * @start: Pointer to the start of IEs
150 * @len: Length of IE buffer in octets
151 * @elems: Data structure for parsed elements
152 * @show_errors: Whether to show parsing errors in debug log
153 * Returns: Parsing result
154 */
ieee802_11_parse_elems(const u8 * start,size_t len,struct ieee802_11_elems * elems,int show_errors)155 ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
156 struct ieee802_11_elems *elems,
157 int show_errors)
158 {
159 size_t left = len;
160 const u8 *pos = start;
161 int unknown = 0;
162
163 os_memset(elems, 0, sizeof(*elems));
164
165 while (left >= 2) {
166 u8 id, elen;
167
168 id = *pos++;
169 elen = *pos++;
170 left -= 2;
171
172 if (elen > left) {
173 if (show_errors) {
174 wpa_printf(MSG_DEBUG, "IEEE 802.11 element "
175 "parse failed (id=%d elen=%d "
176 "left=%lu)",
177 id, elen, (unsigned long) left);
178 wpa_hexdump(MSG_MSGDUMP, "IEs", start, len);
179 }
180 return ParseFailed;
181 }
182
183 switch (id) {
184 case WLAN_EID_SSID:
185 elems->ssid = pos;
186 elems->ssid_len = elen;
187 break;
188 case WLAN_EID_SUPP_RATES:
189 elems->supp_rates = pos;
190 elems->supp_rates_len = elen;
191 break;
192 case WLAN_EID_FH_PARAMS:
193 elems->fh_params = pos;
194 elems->fh_params_len = elen;
195 break;
196 case WLAN_EID_DS_PARAMS:
197 elems->ds_params = pos;
198 elems->ds_params_len = elen;
199 break;
200 case WLAN_EID_CF_PARAMS:
201 elems->cf_params = pos;
202 elems->cf_params_len = elen;
203 break;
204 case WLAN_EID_TIM:
205 elems->tim = pos;
206 elems->tim_len = elen;
207 break;
208 case WLAN_EID_IBSS_PARAMS:
209 elems->ibss_params = pos;
210 elems->ibss_params_len = elen;
211 break;
212 case WLAN_EID_CHALLENGE:
213 elems->challenge = pos;
214 elems->challenge_len = elen;
215 break;
216 case WLAN_EID_ERP_INFO:
217 elems->erp_info = pos;
218 elems->erp_info_len = elen;
219 break;
220 case WLAN_EID_EXT_SUPP_RATES:
221 elems->ext_supp_rates = pos;
222 elems->ext_supp_rates_len = elen;
223 break;
224 case WLAN_EID_VENDOR_SPECIFIC:
225 if (ieee802_11_parse_vendor_specific(pos, elen,
226 elems,
227 show_errors))
228 unknown++;
229 break;
230 case WLAN_EID_RSN:
231 elems->rsn_ie = pos;
232 elems->rsn_ie_len = elen;
233 break;
234 case WLAN_EID_PWR_CAPABILITY:
235 elems->power_cap = pos;
236 elems->power_cap_len = elen;
237 break;
238 case WLAN_EID_SUPPORTED_CHANNELS:
239 elems->supp_channels = pos;
240 elems->supp_channels_len = elen;
241 break;
242 case WLAN_EID_MOBILITY_DOMAIN:
243 elems->mdie = pos;
244 elems->mdie_len = elen;
245 break;
246 case WLAN_EID_FAST_BSS_TRANSITION:
247 elems->ftie = pos;
248 elems->ftie_len = elen;
249 break;
250 case WLAN_EID_TIMEOUT_INTERVAL:
251 elems->timeout_int = pos;
252 elems->timeout_int_len = elen;
253 break;
254 case WLAN_EID_HT_CAP:
255 elems->ht_capabilities = pos;
256 elems->ht_capabilities_len = elen;
257 break;
258 case WLAN_EID_HT_OPERATION:
259 elems->ht_operation = pos;
260 elems->ht_operation_len = elen;
261 break;
262 case WLAN_EID_VHT_CAP:
263 elems->vht_capabilities = pos;
264 elems->vht_capabilities_len = elen;
265 break;
266 case WLAN_EID_VHT_OPERATION:
267 elems->vht_operation = pos;
268 elems->vht_operation_len = elen;
269 break;
270 case WLAN_EID_LINK_ID:
271 if (elen < 18)
272 break;
273 elems->link_id = pos;
274 break;
275 case WLAN_EID_INTERWORKING:
276 elems->interworking = pos;
277 elems->interworking_len = elen;
278 break;
279 case WLAN_EID_EXT_CAPAB:
280 elems->ext_capab = pos;
281 elems->ext_capab_len = elen;
282 break;
283 case WLAN_EID_BSS_MAX_IDLE_PERIOD:
284 if (elen < 3)
285 break;
286 elems->bss_max_idle_period = pos;
287 break;
288 case WLAN_EID_SSID_LIST:
289 elems->ssid_list = pos;
290 elems->ssid_list_len = elen;
291 break;
292 default:
293 unknown++;
294 if (!show_errors)
295 break;
296 wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse "
297 "ignored unknown element (id=%d elen=%d)",
298 id, elen);
299 break;
300 }
301
302 left -= elen;
303 pos += elen;
304 }
305
306 if (left)
307 return ParseFailed;
308
309 return unknown ? ParseUnknown : ParseOK;
310 }
311
312
ieee802_11_ie_count(const u8 * ies,size_t ies_len)313 int ieee802_11_ie_count(const u8 *ies, size_t ies_len)
314 {
315 int count = 0;
316 const u8 *pos, *end;
317
318 if (ies == NULL)
319 return 0;
320
321 pos = ies;
322 end = ies + ies_len;
323
324 while (pos + 2 <= end) {
325 if (pos + 2 + pos[1] > end)
326 break;
327 count++;
328 pos += 2 + pos[1];
329 }
330
331 return count;
332 }
333
334
ieee802_11_vendor_ie_concat(const u8 * ies,size_t ies_len,u32 oui_type)335 struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
336 u32 oui_type)
337 {
338 struct wpabuf *buf;
339 const u8 *end, *pos, *ie;
340
341 pos = ies;
342 end = ies + ies_len;
343 ie = NULL;
344
345 while (pos + 1 < end) {
346 if (pos + 2 + pos[1] > end)
347 return NULL;
348 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
349 WPA_GET_BE32(&pos[2]) == oui_type) {
350 ie = pos;
351 break;
352 }
353 pos += 2 + pos[1];
354 }
355
356 if (ie == NULL)
357 return NULL; /* No specified vendor IE found */
358
359 buf = wpabuf_alloc(ies_len);
360 if (buf == NULL)
361 return NULL;
362
363 /*
364 * There may be multiple vendor IEs in the message, so need to
365 * concatenate their data fields.
366 */
367 while (pos + 1 < end) {
368 if (pos + 2 + pos[1] > end)
369 break;
370 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
371 WPA_GET_BE32(&pos[2]) == oui_type)
372 wpabuf_put_data(buf, pos + 6, pos[1] - 4);
373 pos += 2 + pos[1];
374 }
375
376 return buf;
377 }
378
379
get_hdr_bssid(const struct ieee80211_hdr * hdr,size_t len)380 const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len)
381 {
382 u16 fc, type, stype;
383
384 /*
385 * PS-Poll frames are 16 bytes. All other frames are
386 * 24 bytes or longer.
387 */
388 if (len < 16)
389 return NULL;
390
391 fc = le_to_host16(hdr->frame_control);
392 type = WLAN_FC_GET_TYPE(fc);
393 stype = WLAN_FC_GET_STYPE(fc);
394
395 switch (type) {
396 case WLAN_FC_TYPE_DATA:
397 if (len < 24)
398 return NULL;
399 switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
400 case WLAN_FC_FROMDS | WLAN_FC_TODS:
401 case WLAN_FC_TODS:
402 return hdr->addr1;
403 case WLAN_FC_FROMDS:
404 return hdr->addr2;
405 default:
406 return NULL;
407 }
408 case WLAN_FC_TYPE_CTRL:
409 if (stype != WLAN_FC_STYPE_PSPOLL)
410 return NULL;
411 return hdr->addr1;
412 case WLAN_FC_TYPE_MGMT:
413 return hdr->addr3;
414 default:
415 return NULL;
416 }
417 }
418
419
hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],const char * name,const char * val)420 int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
421 const char *name, const char *val)
422 {
423 int num, v;
424 const char *pos;
425 struct hostapd_wmm_ac_params *ac;
426
427 /* skip 'wme_ac_' or 'wmm_ac_' prefix */
428 pos = name + 7;
429 if (os_strncmp(pos, "be_", 3) == 0) {
430 num = 0;
431 pos += 3;
432 } else if (os_strncmp(pos, "bk_", 3) == 0) {
433 num = 1;
434 pos += 3;
435 } else if (os_strncmp(pos, "vi_", 3) == 0) {
436 num = 2;
437 pos += 3;
438 } else if (os_strncmp(pos, "vo_", 3) == 0) {
439 num = 3;
440 pos += 3;
441 } else {
442 wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos);
443 return -1;
444 }
445
446 ac = &wmm_ac_params[num];
447
448 if (os_strcmp(pos, "aifs") == 0) {
449 v = atoi(val);
450 if (v < 1 || v > 255) {
451 wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v);
452 return -1;
453 }
454 ac->aifs = v;
455 } else if (os_strcmp(pos, "cwmin") == 0) {
456 v = atoi(val);
457 if (v < 0 || v > 12) {
458 wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v);
459 return -1;
460 }
461 ac->cwmin = v;
462 } else if (os_strcmp(pos, "cwmax") == 0) {
463 v = atoi(val);
464 if (v < 0 || v > 12) {
465 wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v);
466 return -1;
467 }
468 ac->cwmax = v;
469 } else if (os_strcmp(pos, "txop_limit") == 0) {
470 v = atoi(val);
471 if (v < 0 || v > 0xffff) {
472 wpa_printf(MSG_ERROR, "Invalid txop value %d", v);
473 return -1;
474 }
475 ac->txop_limit = v;
476 } else if (os_strcmp(pos, "acm") == 0) {
477 v = atoi(val);
478 if (v < 0 || v > 1) {
479 wpa_printf(MSG_ERROR, "Invalid acm value %d", v);
480 return -1;
481 }
482 ac->admission_control_mandatory = v;
483 } else {
484 wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos);
485 return -1;
486 }
487
488 return 0;
489 }
490
491
ieee80211_freq_to_chan(int freq,u8 * channel)492 enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
493 {
494 enum hostapd_hw_mode mode = NUM_HOSTAPD_MODES;
495
496 if (freq >= 2412 && freq <= 2472) {
497 mode = HOSTAPD_MODE_IEEE80211G;
498 *channel = (freq - 2407) / 5;
499 } else if (freq == 2484) {
500 mode = HOSTAPD_MODE_IEEE80211B;
501 *channel = 14;
502 } else if (freq >= 4900 && freq < 5000) {
503 mode = HOSTAPD_MODE_IEEE80211A;
504 *channel = (freq - 4000) / 5;
505 } else if (freq >= 5000 && freq < 5900) {
506 mode = HOSTAPD_MODE_IEEE80211A;
507 *channel = (freq - 5000) / 5;
508 } else if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) {
509 mode = HOSTAPD_MODE_IEEE80211AD;
510 *channel = (freq - 56160) / 2160;
511 }
512
513 return mode;
514 }
515
516
is_11b(u8 rate)517 static int is_11b(u8 rate)
518 {
519 return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16;
520 }
521
522
supp_rates_11b_only(struct ieee802_11_elems * elems)523 int supp_rates_11b_only(struct ieee802_11_elems *elems)
524 {
525 int num_11b = 0, num_others = 0;
526 int i;
527
528 if (elems->supp_rates == NULL && elems->ext_supp_rates == NULL)
529 return 0;
530
531 for (i = 0; elems->supp_rates && i < elems->supp_rates_len; i++) {
532 if (is_11b(elems->supp_rates[i]))
533 num_11b++;
534 else
535 num_others++;
536 }
537
538 for (i = 0; elems->ext_supp_rates && i < elems->ext_supp_rates_len;
539 i++) {
540 if (is_11b(elems->ext_supp_rates[i]))
541 num_11b++;
542 else
543 num_others++;
544 }
545
546 return num_11b > 0 && num_others == 0;
547 }
548