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