• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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