1 /*
2 * IEEE 802.11 Common routines
3 * Copyright (c) 2002-2012, 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 "ieee802_11_defs.h"
13 #include "ieee802_11_common.h"
14
15
ieee802_11_parse_vendor_specific(const u8 * pos,size_t elen,struct ieee802_11_elems * elems,int show_errors)16 static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
17 struct ieee802_11_elems *elems,
18 int show_errors)
19 {
20 unsigned int oui;
21
22 /* first 3 bytes in vendor specific information element are the IEEE
23 * OUI of the vendor. The following byte is used a vendor specific
24 * sub-type. */
25 if (elen < 4) {
26 if (show_errors) {
27 wpa_printf(MSG_MSGDUMP, "short vendor specific "
28 "information element ignored (len=%lu)",
29 (unsigned long) elen);
30 }
31 return -1;
32 }
33
34 oui = WPA_GET_BE24(pos);
35 switch (oui) {
36 case OUI_MICROSOFT:
37 /* Microsoft/Wi-Fi information elements are further typed and
38 * subtyped */
39 switch (pos[3]) {
40 case 1:
41 /* Microsoft OUI (00:50:F2) with OUI Type 1:
42 * real WPA information element */
43 elems->wpa_ie = pos;
44 elems->wpa_ie_len = elen;
45 break;
46 case WMM_OUI_TYPE:
47 /* WMM information element */
48 if (elen < 5) {
49 wpa_printf(MSG_MSGDUMP, "short WMM "
50 "information element ignored "
51 "(len=%lu)",
52 (unsigned long) elen);
53 return -1;
54 }
55 switch (pos[4]) {
56 case WMM_OUI_SUBTYPE_INFORMATION_ELEMENT:
57 case WMM_OUI_SUBTYPE_PARAMETER_ELEMENT:
58 /*
59 * Share same pointer since only one of these
60 * is used and they start with same data.
61 * Length field can be used to distinguish the
62 * IEs.
63 */
64 elems->wmm = pos;
65 elems->wmm_len = elen;
66 break;
67 case WMM_OUI_SUBTYPE_TSPEC_ELEMENT:
68 elems->wmm_tspec = pos;
69 elems->wmm_tspec_len = elen;
70 break;
71 default:
72 wpa_printf(MSG_EXCESSIVE, "unknown WMM "
73 "information element ignored "
74 "(subtype=%d len=%lu)",
75 pos[4], (unsigned long) elen);
76 return -1;
77 }
78 break;
79 case 4:
80 /* Wi-Fi Protected Setup (WPS) IE */
81 elems->wps_ie = pos;
82 elems->wps_ie_len = elen;
83 break;
84 default:
85 wpa_printf(MSG_EXCESSIVE, "Unknown Microsoft "
86 "information element ignored "
87 "(type=%d len=%lu)",
88 pos[3], (unsigned long) elen);
89 return -1;
90 }
91 break;
92
93 case OUI_WFA:
94 switch (pos[3]) {
95 case P2P_OUI_TYPE:
96 /* Wi-Fi Alliance - P2P IE */
97 elems->p2p = pos;
98 elems->p2p_len = elen;
99 break;
100 case WFD_OUI_TYPE:
101 /* Wi-Fi Alliance - WFD IE */
102 elems->wfd = pos;
103 elems->wfd_len = elen;
104 break;
105 case HS20_INDICATION_OUI_TYPE:
106 /* Hotspot 2.0 */
107 elems->hs20 = pos;
108 elems->hs20_len = elen;
109 break;
110 default:
111 wpa_printf(MSG_MSGDUMP, "Unknown WFA "
112 "information element ignored "
113 "(type=%d len=%lu)\n",
114 pos[3], (unsigned long) elen);
115 return -1;
116 }
117 break;
118
119 case OUI_BROADCOM:
120 switch (pos[3]) {
121 case VENDOR_HT_CAPAB_OUI_TYPE:
122 elems->vendor_ht_cap = pos;
123 elems->vendor_ht_cap_len = elen;
124 break;
125 default:
126 wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom "
127 "information element ignored "
128 "(type=%d len=%lu)",
129 pos[3], (unsigned long) elen);
130 return -1;
131 }
132 break;
133
134 default:
135 wpa_printf(MSG_EXCESSIVE, "unknown vendor specific "
136 "information element ignored (vendor OUI "
137 "%02x:%02x:%02x len=%lu)",
138 pos[0], pos[1], pos[2], (unsigned long) elen);
139 return -1;
140 }
141
142 return 0;
143 }
144
145
146 /**
147 * ieee802_11_parse_elems - Parse information elements in management frames
148 * @start: Pointer to the start of IEs
149 * @len: Length of IE buffer in octets
150 * @elems: Data structure for parsed elements
151 * @show_errors: Whether to show parsing errors in debug log
152 * Returns: Parsing result
153 */
ieee802_11_parse_elems(const u8 * start,size_t len,struct ieee802_11_elems * elems,int show_errors)154 ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
155 struct ieee802_11_elems *elems,
156 int show_errors)
157 {
158 size_t left = len;
159 const u8 *pos = start;
160 int unknown = 0;
161
162 os_memset(elems, 0, sizeof(*elems));
163
164 while (left >= 2) {
165 u8 id, elen;
166
167 id = *pos++;
168 elen = *pos++;
169 left -= 2;
170
171 if (elen > left) {
172 if (show_errors) {
173 wpa_printf(MSG_DEBUG, "IEEE 802.11 element "
174 "parse failed (id=%d elen=%d "
175 "left=%lu)",
176 id, elen, (unsigned long) left);
177 wpa_hexdump(MSG_MSGDUMP, "IEs", start, len);
178 }
179 return ParseFailed;
180 }
181
182 switch (id) {
183 case WLAN_EID_SSID:
184 elems->ssid = pos;
185 elems->ssid_len = elen;
186 break;
187 case WLAN_EID_SUPP_RATES:
188 elems->supp_rates = pos;
189 elems->supp_rates_len = elen;
190 break;
191 case WLAN_EID_FH_PARAMS:
192 elems->fh_params = pos;
193 elems->fh_params_len = elen;
194 break;
195 case WLAN_EID_DS_PARAMS:
196 elems->ds_params = pos;
197 elems->ds_params_len = elen;
198 break;
199 case WLAN_EID_CF_PARAMS:
200 elems->cf_params = pos;
201 elems->cf_params_len = elen;
202 break;
203 case WLAN_EID_TIM:
204 elems->tim = pos;
205 elems->tim_len = elen;
206 break;
207 case WLAN_EID_IBSS_PARAMS:
208 elems->ibss_params = pos;
209 elems->ibss_params_len = elen;
210 break;
211 case WLAN_EID_CHALLENGE:
212 elems->challenge = pos;
213 elems->challenge_len = elen;
214 break;
215 case WLAN_EID_ERP_INFO:
216 elems->erp_info = pos;
217 elems->erp_info_len = elen;
218 break;
219 case WLAN_EID_EXT_SUPP_RATES:
220 elems->ext_supp_rates = pos;
221 elems->ext_supp_rates_len = elen;
222 break;
223 case WLAN_EID_VENDOR_SPECIFIC:
224 if (ieee802_11_parse_vendor_specific(pos, elen,
225 elems,
226 show_errors))
227 unknown++;
228 break;
229 case WLAN_EID_RSN:
230 elems->rsn_ie = pos;
231 elems->rsn_ie_len = elen;
232 break;
233 case WLAN_EID_PWR_CAPABILITY:
234 elems->power_cap = pos;
235 elems->power_cap_len = elen;
236 break;
237 case WLAN_EID_SUPPORTED_CHANNELS:
238 elems->supp_channels = pos;
239 elems->supp_channels_len = elen;
240 break;
241 case WLAN_EID_MOBILITY_DOMAIN:
242 elems->mdie = pos;
243 elems->mdie_len = elen;
244 break;
245 case WLAN_EID_FAST_BSS_TRANSITION:
246 elems->ftie = pos;
247 elems->ftie_len = elen;
248 break;
249 case WLAN_EID_TIMEOUT_INTERVAL:
250 elems->timeout_int = pos;
251 elems->timeout_int_len = elen;
252 break;
253 case WLAN_EID_HT_CAP:
254 elems->ht_capabilities = pos;
255 elems->ht_capabilities_len = elen;
256 break;
257 case WLAN_EID_HT_OPERATION:
258 elems->ht_operation = pos;
259 elems->ht_operation_len = elen;
260 break;
261 case WLAN_EID_VHT_CAP:
262 elems->vht_capabilities = pos;
263 elems->vht_capabilities_len = elen;
264 break;
265 case WLAN_EID_VHT_OPERATION:
266 elems->vht_operation = pos;
267 elems->vht_operation_len = elen;
268 break;
269 case WLAN_EID_LINK_ID:
270 if (elen < 18)
271 break;
272 elems->link_id = pos;
273 break;
274 case WLAN_EID_INTERWORKING:
275 elems->interworking = pos;
276 elems->interworking_len = elen;
277 break;
278 case WLAN_EID_EXT_CAPAB:
279 elems->ext_capab = pos;
280 elems->ext_capab_len = elen;
281 break;
282 case WLAN_EID_BSS_MAX_IDLE_PERIOD:
283 if (elen < 3)
284 break;
285 elems->bss_max_idle_period = pos;
286 break;
287 case WLAN_EID_SSID_LIST:
288 elems->ssid_list = pos;
289 elems->ssid_list_len = elen;
290 break;
291 default:
292 unknown++;
293 if (!show_errors)
294 break;
295 wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse "
296 "ignored unknown element (id=%d elen=%d)",
297 id, elen);
298 break;
299 }
300
301 left -= elen;
302 pos += elen;
303 }
304
305 if (left)
306 return ParseFailed;
307
308 return unknown ? ParseUnknown : ParseOK;
309 }
310
311
ieee802_11_ie_count(const u8 * ies,size_t ies_len)312 int ieee802_11_ie_count(const u8 *ies, size_t ies_len)
313 {
314 int count = 0;
315 const u8 *pos, *end;
316
317 if (ies == NULL)
318 return 0;
319
320 pos = ies;
321 end = ies + ies_len;
322
323 while (pos + 2 <= end) {
324 if (pos + 2 + pos[1] > end)
325 break;
326 count++;
327 pos += 2 + pos[1];
328 }
329
330 return count;
331 }
332
333
ieee802_11_vendor_ie_concat(const u8 * ies,size_t ies_len,u32 oui_type)334 struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
335 u32 oui_type)
336 {
337 struct wpabuf *buf;
338 const u8 *end, *pos, *ie;
339
340 pos = ies;
341 end = ies + ies_len;
342 ie = NULL;
343
344 while (pos + 1 < end) {
345 if (pos + 2 + pos[1] > end)
346 return NULL;
347 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
348 WPA_GET_BE32(&pos[2]) == oui_type) {
349 ie = pos;
350 break;
351 }
352 pos += 2 + pos[1];
353 }
354
355 if (ie == NULL)
356 return NULL; /* No specified vendor IE found */
357
358 buf = wpabuf_alloc(ies_len);
359 if (buf == NULL)
360 return NULL;
361
362 /*
363 * There may be multiple vendor IEs in the message, so need to
364 * concatenate their data fields.
365 */
366 while (pos + 1 < end) {
367 if (pos + 2 + pos[1] > end)
368 break;
369 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
370 WPA_GET_BE32(&pos[2]) == oui_type)
371 wpabuf_put_data(buf, pos + 6, pos[1] - 4);
372 pos += 2 + pos[1];
373 }
374
375 return buf;
376 }
377
378
get_hdr_bssid(const struct ieee80211_hdr * hdr,size_t len)379 const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len)
380 {
381 u16 fc, type, stype;
382
383 /*
384 * PS-Poll frames are 16 bytes. All other frames are
385 * 24 bytes or longer.
386 */
387 if (len < 16)
388 return NULL;
389
390 fc = le_to_host16(hdr->frame_control);
391 type = WLAN_FC_GET_TYPE(fc);
392 stype = WLAN_FC_GET_STYPE(fc);
393
394 switch (type) {
395 case WLAN_FC_TYPE_DATA:
396 if (len < 24)
397 return NULL;
398 switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
399 case WLAN_FC_FROMDS | WLAN_FC_TODS:
400 case WLAN_FC_TODS:
401 return hdr->addr1;
402 case WLAN_FC_FROMDS:
403 return hdr->addr2;
404 default:
405 return NULL;
406 }
407 case WLAN_FC_TYPE_CTRL:
408 if (stype != WLAN_FC_STYPE_PSPOLL)
409 return NULL;
410 return hdr->addr1;
411 case WLAN_FC_TYPE_MGMT:
412 return hdr->addr3;
413 default:
414 return NULL;
415 }
416 }
417
418
hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],const char * name,const char * val)419 int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
420 const char *name, const char *val)
421 {
422 int num, v;
423 const char *pos;
424 struct hostapd_wmm_ac_params *ac;
425
426 /* skip 'wme_ac_' or 'wmm_ac_' prefix */
427 pos = name + 7;
428 if (os_strncmp(pos, "be_", 3) == 0) {
429 num = 0;
430 pos += 3;
431 } else if (os_strncmp(pos, "bk_", 3) == 0) {
432 num = 1;
433 pos += 3;
434 } else if (os_strncmp(pos, "vi_", 3) == 0) {
435 num = 2;
436 pos += 3;
437 } else if (os_strncmp(pos, "vo_", 3) == 0) {
438 num = 3;
439 pos += 3;
440 } else {
441 wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos);
442 return -1;
443 }
444
445 ac = &wmm_ac_params[num];
446
447 if (os_strcmp(pos, "aifs") == 0) {
448 v = atoi(val);
449 if (v < 1 || v > 255) {
450 wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v);
451 return -1;
452 }
453 ac->aifs = v;
454 } else if (os_strcmp(pos, "cwmin") == 0) {
455 v = atoi(val);
456 if (v < 0 || v > 12) {
457 wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v);
458 return -1;
459 }
460 ac->cwmin = v;
461 } else if (os_strcmp(pos, "cwmax") == 0) {
462 v = atoi(val);
463 if (v < 0 || v > 12) {
464 wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v);
465 return -1;
466 }
467 ac->cwmax = v;
468 } else if (os_strcmp(pos, "txop_limit") == 0) {
469 v = atoi(val);
470 if (v < 0 || v > 0xffff) {
471 wpa_printf(MSG_ERROR, "Invalid txop value %d", v);
472 return -1;
473 }
474 ac->txop_limit = v;
475 } else if (os_strcmp(pos, "acm") == 0) {
476 v = atoi(val);
477 if (v < 0 || v > 1) {
478 wpa_printf(MSG_ERROR, "Invalid acm value %d", v);
479 return -1;
480 }
481 ac->admission_control_mandatory = v;
482 } else {
483 wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos);
484 return -1;
485 }
486
487 return 0;
488 }
489