Branch data 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 : 17397 : 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 [ - + ]: 17397 : 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 : 17397 : oui = WPA_GET_BE24(pos);
36 [ + + - - ]: 17397 : switch (oui) {
37 : : case OUI_MICROSOFT:
38 : : /* Microsoft/Wi-Fi information elements are further typed and
39 : : * subtyped */
40 [ + + + - ]: 8220 : switch (pos[3]) {
41 : : case 1:
42 : : /* Microsoft OUI (00:50:F2) with OUI Type 1:
43 : : * real WPA information element */
44 : 65 : elems->wpa_ie = pos;
45 : 65 : elems->wpa_ie_len = elen;
46 : 65 : break;
47 : : case WMM_OUI_TYPE:
48 : : /* WMM information element */
49 [ - + ]: 3688 : 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 [ + - - ]: 3688 : 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 : 3688 : elems->wmm = pos;
66 : 3688 : elems->wmm_len = elen;
67 : 3688 : 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 : 3688 : break;
80 : : case 4:
81 : : /* Wi-Fi Protected Setup (WPS) IE */
82 : 4467 : elems->wps_ie = pos;
83 : 4467 : elems->wps_ie_len = elen;
84 : 4467 : 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 : 8220 : break;
93 : :
94 : : case OUI_WFA:
95 [ + + + + : 9177 : switch (pos[3]) {
- ]
96 : : case P2P_OUI_TYPE:
97 : : /* Wi-Fi Alliance - P2P IE */
98 : 4591 : elems->p2p = pos;
99 : 4591 : elems->p2p_len = elen;
100 : 4591 : break;
101 : : case WFD_OUI_TYPE:
102 : : /* Wi-Fi Alliance - WFD IE */
103 : 3741 : elems->wfd = pos;
104 : 3741 : elems->wfd_len = elen;
105 : 3741 : 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)\n",
120 : 0 : pos[3], (unsigned long) elen);
121 : 0 : return -1;
122 : : }
123 : 9177 : 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 : 17397 : 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 : 7921 : ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
161 : : struct ieee802_11_elems *elems,
162 : : int show_errors)
163 : : {
164 : 7921 : size_t left = len;
165 : 7921 : const u8 *pos = start;
166 : 7921 : int unknown = 0;
167 : :
168 : 7921 : os_memset(elems, 0, sizeof(*elems));
169 : :
170 [ + + ]: 70747 : while (left >= 2) {
171 : : u8 id, elen;
172 : :
173 : 62826 : id = *pos++;
174 : 62826 : elen = *pos++;
175 : 62826 : left -= 2;
176 : :
177 [ - + ]: 62826 : 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 [ + + + + : 62826 : switch (id) {
- + + + +
- - + + -
+ + + - -
- + + + +
- + ]
189 : : case WLAN_EID_SSID:
190 : 5545 : elems->ssid = pos;
191 : 5545 : elems->ssid_len = elen;
192 : 5545 : break;
193 : : case WLAN_EID_SUPP_RATES:
194 : 6901 : elems->supp_rates = pos;
195 : 6901 : elems->supp_rates_len = elen;
196 : 6901 : break;
197 : : case WLAN_EID_DS_PARAMS:
198 : 4633 : elems->ds_params = pos;
199 : 4633 : elems->ds_params_len = elen;
200 : 4633 : break;
201 : : case WLAN_EID_CF_PARAMS:
202 : : case WLAN_EID_TIM:
203 : 1393 : 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 : 1465 : elems->erp_info = pos;
210 : 1465 : elems->erp_info_len = elen;
211 : 1465 : break;
212 : : case WLAN_EID_EXT_SUPP_RATES:
213 : 3878 : elems->ext_supp_rates = pos;
214 : 3878 : elems->ext_supp_rates_len = elen;
215 : 3878 : break;
216 : : case WLAN_EID_VENDOR_SPECIFIC:
217 [ - + ]: 17397 : if (ieee802_11_parse_vendor_specific(pos, elen,
218 : : elems,
219 : : show_errors))
220 : 0 : unknown++;
221 : 17397 : break;
222 : : case WLAN_EID_RSN:
223 : 1959 : elems->rsn_ie = pos;
224 : 1959 : elems->rsn_ie_len = elen;
225 : 1959 : 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 : 310 : elems->mdie = pos;
234 : 310 : elems->mdie_len = elen;
235 : 310 : break;
236 : : case WLAN_EID_FAST_BSS_TRANSITION:
237 : 80 : elems->ftie = pos;
238 : 80 : elems->ftie_len = elen;
239 : 80 : 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 : 6350 : elems->ht_capabilities = pos;
246 : 6350 : elems->ht_capabilities_len = elen;
247 : 6350 : break;
248 : : case WLAN_EID_HT_OPERATION:
249 : 2801 : elems->ht_operation = pos;
250 : 2801 : elems->ht_operation_len = elen;
251 : 2801 : break;
252 : : case WLAN_EID_VHT_CAP:
253 : 2697 : elems->vht_capabilities = pos;
254 : 2697 : elems->vht_capabilities_len = elen;
255 : 2697 : 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 : 701 : elems->interworking = pos;
272 : 701 : elems->interworking_len = elen;
273 : 701 : break;
274 : : case WLAN_EID_QOS_MAP_SET:
275 [ - + ]: 2 : if (elen < 16)
276 : 0 : break;
277 : 2 : elems->qos_map_set = pos;
278 : 2 : elems->qos_map_set_len = elen;
279 : 2 : break;
280 : : case WLAN_EID_EXT_CAPAB:
281 : 4727 : elems->ext_capab = pos;
282 : 4727 : elems->ext_capab_len = elen;
283 : 4727 : break;
284 : : case WLAN_EID_BSS_MAX_IDLE_PERIOD:
285 [ - + ]: 1356 : if (elen < 3)
286 : 0 : break;
287 : 1356 : elems->bss_max_idle_period = pos;
288 : 1356 : 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 : 631 : unknown++;
295 [ + + ]: 631 : if (!show_errors)
296 : 629 : break;
297 : 2 : wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse "
298 : : "ignored unknown element (id=%d elen=%d)",
299 : : id, elen);
300 : 2 : break;
301 : : }
302 : :
303 : 62826 : left -= elen;
304 : 62826 : pos += elen;
305 : : }
306 : :
307 [ - + ]: 7921 : if (left)
308 : 0 : return ParseFailed;
309 : :
310 : 7921 : return unknown ? ParseUnknown : ParseOK;
311 : : }
312 : :
313 : :
314 : 16 : int ieee802_11_ie_count(const u8 *ies, size_t ies_len)
315 : : {
316 : 16 : int count = 0;
317 : : const u8 *pos, *end;
318 : :
319 [ + - ]: 16 : if (ies == NULL)
320 : 16 : 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 : 16 : return count;
333 : : }
334 : :
335 : :
336 : 7159 : 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 : 7159 : pos = ies;
343 : 7159 : end = ies + ies_len;
344 : 7159 : ie = NULL;
345 : :
346 [ + + ]: 44608 : while (pos + 1 < end) {
347 [ - + ]: 44051 : if (pos + 2 + pos[1] > end)
348 : 0 : return NULL;
349 [ + + ]: 58590 : if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
[ + - + + ]
350 : 14539 : WPA_GET_BE32(&pos[2]) == oui_type) {
351 : 6602 : ie = pos;
352 : 6602 : break;
353 : : }
354 : 37449 : pos += 2 + pos[1];
355 : : }
356 : :
357 [ + + ]: 7159 : if (ie == NULL)
358 : 557 : return NULL; /* No specified vendor IE found */
359 : :
360 : 6602 : buf = wpabuf_alloc(ies_len);
361 [ - + ]: 6602 : 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 [ + + ]: 19205 : while (pos + 1 < end) {
369 [ - + ]: 12603 : if (pos + 2 + pos[1] > end)
370 : 0 : break;
371 [ + - ]: 25206 : if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
[ + - + + ]
372 : 12603 : WPA_GET_BE32(&pos[2]) == oui_type)
373 : 6603 : wpabuf_put_data(buf, pos + 6, pos[1] - 4);
374 : 12603 : pos += 2 + pos[1];
375 : : }
376 : :
377 : 7159 : return buf;
378 : : }
379 : :
380 : :
381 : 5156 : 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 [ - + ]: 5156 : if (len < 16)
390 : 0 : return NULL;
391 : :
392 : 5156 : fc = le_to_host16(hdr->frame_control);
393 : 5156 : type = WLAN_FC_GET_TYPE(fc);
394 : 5156 : stype = WLAN_FC_GET_STYPE(fc);
395 : :
396 [ - - + - ]: 5156 : 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 : 5156 : return hdr->addr3;
415 : : default:
416 : 5156 : return NULL;
417 : : }
418 : : }
419 : :
420 : :
421 : 20 : 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 : 20 : pos = name + 7;
430 [ + + ]: 20 : if (os_strncmp(pos, "be_", 3) == 0) {
431 : 5 : num = 0;
432 : 5 : pos += 3;
433 [ + + ]: 15 : } else if (os_strncmp(pos, "bk_", 3) == 0) {
434 : 5 : num = 1;
435 : 5 : pos += 3;
436 [ + + ]: 10 : } else if (os_strncmp(pos, "vi_", 3) == 0) {
437 : 5 : num = 2;
438 : 5 : pos += 3;
439 [ + - ]: 5 : } else if (os_strncmp(pos, "vo_", 3) == 0) {
440 : 5 : num = 3;
441 : 5 : pos += 3;
442 : : } else {
443 : 0 : wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos);
444 : 0 : return -1;
445 : : }
446 : :
447 : 20 : ac = &wmm_ac_params[num];
448 : :
449 [ + + ]: 20 : if (os_strcmp(pos, "aifs") == 0) {
450 : 4 : v = atoi(val);
451 [ - + ][ + - ]: 4 : if (v < 1 || v > 255) {
452 : 0 : wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v);
453 : 0 : return -1;
454 : : }
455 : 4 : ac->aifs = v;
456 [ + + ]: 16 : } else if (os_strcmp(pos, "cwmin") == 0) {
457 : 4 : v = atoi(val);
458 [ - + ][ + - ]: 4 : if (v < 0 || v > 12) {
459 : 0 : wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v);
460 : 0 : return -1;
461 : : }
462 : 4 : ac->cwmin = v;
463 [ + + ]: 12 : } else if (os_strcmp(pos, "cwmax") == 0) {
464 : 4 : v = atoi(val);
465 [ - + ][ + - ]: 4 : if (v < 0 || v > 12) {
466 : 0 : wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v);
467 : 0 : return -1;
468 : : }
469 : 4 : ac->cwmax = v;
470 [ + + ]: 8 : } else if (os_strcmp(pos, "txop_limit") == 0) {
471 : 4 : v = atoi(val);
472 [ - + ][ + - ]: 4 : if (v < 0 || v > 0xffff) {
473 : 0 : wpa_printf(MSG_ERROR, "Invalid txop value %d", v);
474 : 0 : return -1;
475 : : }
476 : 4 : ac->txop_limit = v;
477 [ + - ]: 4 : } else if (os_strcmp(pos, "acm") == 0) {
478 : 4 : v = atoi(val);
479 [ - + ][ + - ]: 4 : if (v < 0 || v > 1) {
480 : 0 : wpa_printf(MSG_ERROR, "Invalid acm value %d", v);
481 : 0 : return -1;
482 : : }
483 : 4 : ac->admission_control_mandatory = v;
484 : : } else {
485 : 0 : wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos);
486 : 0 : return -1;
487 : : }
488 : :
489 : 20 : return 0;
490 : : }
491 : :
492 : :
493 : 81300 : enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
494 : : {
495 : 81300 : enum hostapd_hw_mode mode = NUM_HOSTAPD_MODES;
496 : :
497 [ + - ][ + + ]: 81300 : if (freq >= 2412 && freq <= 2472) {
498 : 27875 : mode = HOSTAPD_MODE_IEEE80211G;
499 : 27875 : *channel = (freq - 2407) / 5;
500 [ + + ]: 53425 : } else if (freq == 2484) {
501 : 2137 : mode = HOSTAPD_MODE_IEEE80211B;
502 : 2137 : *channel = 14;
503 [ + - ][ - + ]: 51288 : } else if (freq >= 4900 && freq < 5000) {
504 : 0 : mode = HOSTAPD_MODE_IEEE80211A;
505 : 0 : *channel = (freq - 4000) / 5;
506 [ + - ][ + - ]: 51288 : } else if (freq >= 5000 && freq < 5900) {
507 : 51288 : mode = HOSTAPD_MODE_IEEE80211A;
508 : 51288 : *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 : 81300 : return mode;
515 : : }
516 : :
517 : :
518 : 4024 : static int is_11b(u8 rate)
519 : : {
520 [ + + ][ + + ]: 4024 : return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16;
[ + + ][ + + ]
521 : : }
522 : :
523 : :
524 : 496 : int supp_rates_11b_only(struct ieee802_11_elems *elems)
525 : : {
526 : 496 : int num_11b = 0, num_others = 0;
527 : : int i;
528 : :
529 [ - + ][ # # ]: 496 : if (elems->supp_rates == NULL && elems->ext_supp_rates == NULL)
530 : 0 : return 0;
531 : :
532 [ + - ][ + + ]: 4464 : for (i = 0; elems->supp_rates && i < elems->supp_rates_len; i++) {
533 [ + + ]: 3968 : if (is_11b(elems->supp_rates[i]))
534 : 56 : num_11b++;
535 : : else
536 : 3912 : num_others++;
537 : : }
538 : :
539 [ + + ][ + + ]: 552 : for (i = 0; elems->ext_supp_rates && i < elems->ext_supp_rates_len;
540 : 56 : i++) {
541 [ - + ]: 56 : if (is_11b(elems->ext_supp_rates[i]))
542 : 0 : num_11b++;
543 : : else
544 : 56 : num_others++;
545 : : }
546 : :
547 [ + + ][ - + ]: 496 : return num_11b > 0 && num_others == 0;
548 : : }
|