ieee802_11_common.c revision 209158
1/*
2 * IEEE 802.11 Common routines
3 * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 */
14
15#include "includes.h"
16
17#include "common.h"
18#include "ieee802_11_defs.h"
19#include "ieee802_11_common.h"
20
21
22static int ieee802_11_parse_vendor_specific(u8 *pos, size_t elen,
23					    struct ieee802_11_elems *elems,
24					    int show_errors)
25{
26	unsigned int oui;
27
28	/* first 3 bytes in vendor specific information element are the IEEE
29	 * OUI of the vendor. The following byte is used a vendor specific
30	 * sub-type. */
31	if (elen < 4) {
32		if (show_errors) {
33			wpa_printf(MSG_MSGDUMP, "short vendor specific "
34				   "information element ignored (len=%lu)",
35				   (unsigned long) elen);
36		}
37		return -1;
38	}
39
40	oui = WPA_GET_BE24(pos);
41	switch (oui) {
42	case OUI_MICROSOFT:
43		/* Microsoft/Wi-Fi information elements are further typed and
44		 * subtyped */
45		switch (pos[3]) {
46		case 1:
47			/* Microsoft OUI (00:50:F2) with OUI Type 1:
48			 * real WPA information element */
49			elems->wpa_ie = pos;
50			elems->wpa_ie_len = elen;
51			break;
52		case WMM_OUI_TYPE:
53			/* WMM information element */
54			if (elen < 5) {
55				wpa_printf(MSG_MSGDUMP, "short WMM "
56					   "information element ignored "
57					   "(len=%lu)",
58					   (unsigned long) elen);
59				return -1;
60			}
61			switch (pos[4]) {
62			case WMM_OUI_SUBTYPE_INFORMATION_ELEMENT:
63			case WMM_OUI_SUBTYPE_PARAMETER_ELEMENT:
64				/*
65				 * Share same pointer since only one of these
66				 * is used and they start with same data.
67				 * Length field can be used to distinguish the
68				 * IEs.
69				 */
70				elems->wmm = pos;
71				elems->wmm_len = elen;
72				break;
73			case WMM_OUI_SUBTYPE_TSPEC_ELEMENT:
74				elems->wmm_tspec = pos;
75				elems->wmm_tspec_len = elen;
76				break;
77			default:
78				wpa_printf(MSG_MSGDUMP, "unknown WMM "
79					   "information element ignored "
80					   "(subtype=%d len=%lu)",
81					   pos[4], (unsigned long) elen);
82				return -1;
83			}
84			break;
85		case 4:
86			/* Wi-Fi Protected Setup (WPS) IE */
87			elems->wps_ie = pos;
88			elems->wps_ie_len = elen;
89			break;
90		default:
91			wpa_printf(MSG_MSGDUMP, "Unknown Microsoft "
92				   "information element ignored "
93				   "(type=%d len=%lu)\n",
94				   pos[3], (unsigned long) elen);
95			return -1;
96		}
97		break;
98
99	case OUI_BROADCOM:
100		switch (pos[3]) {
101		case VENDOR_HT_CAPAB_OUI_TYPE:
102			elems->vendor_ht_cap = pos;
103			elems->vendor_ht_cap_len = elen;
104			break;
105		default:
106			wpa_printf(MSG_MSGDUMP, "Unknown Broadcom "
107				   "information element ignored "
108				   "(type=%d len=%lu)\n",
109				   pos[3], (unsigned long) elen);
110			return -1;
111		}
112		break;
113
114	default:
115		wpa_printf(MSG_MSGDUMP, "unknown vendor specific information "
116			   "element ignored (vendor OUI %02x:%02x:%02x "
117			   "len=%lu)",
118			   pos[0], pos[1], pos[2], (unsigned long) elen);
119		return -1;
120	}
121
122	return 0;
123}
124
125
126/**
127 * ieee802_11_parse_elems - Parse information elements in management frames
128 * @start: Pointer to the start of IEs
129 * @len: Length of IE buffer in octets
130 * @elems: Data structure for parsed elements
131 * @show_errors: Whether to show parsing errors in debug log
132 * Returns: Parsing result
133 */
134ParseRes ieee802_11_parse_elems(u8 *start, size_t len,
135				struct ieee802_11_elems *elems,
136				int show_errors)
137{
138	size_t left = len;
139	u8 *pos = start;
140	int unknown = 0;
141
142	os_memset(elems, 0, sizeof(*elems));
143
144	while (left >= 2) {
145		u8 id, elen;
146
147		id = *pos++;
148		elen = *pos++;
149		left -= 2;
150
151		if (elen > left) {
152			if (show_errors) {
153				wpa_printf(MSG_DEBUG, "IEEE 802.11 element "
154					   "parse failed (id=%d elen=%d "
155					   "left=%lu)",
156					   id, elen, (unsigned long) left);
157				wpa_hexdump(MSG_MSGDUMP, "IEs", start, len);
158			}
159			return ParseFailed;
160		}
161
162		switch (id) {
163		case WLAN_EID_SSID:
164			elems->ssid = pos;
165			elems->ssid_len = elen;
166			break;
167		case WLAN_EID_SUPP_RATES:
168			elems->supp_rates = pos;
169			elems->supp_rates_len = elen;
170			break;
171		case WLAN_EID_FH_PARAMS:
172			elems->fh_params = pos;
173			elems->fh_params_len = elen;
174			break;
175		case WLAN_EID_DS_PARAMS:
176			elems->ds_params = pos;
177			elems->ds_params_len = elen;
178			break;
179		case WLAN_EID_CF_PARAMS:
180			elems->cf_params = pos;
181			elems->cf_params_len = elen;
182			break;
183		case WLAN_EID_TIM:
184			elems->tim = pos;
185			elems->tim_len = elen;
186			break;
187		case WLAN_EID_IBSS_PARAMS:
188			elems->ibss_params = pos;
189			elems->ibss_params_len = elen;
190			break;
191		case WLAN_EID_CHALLENGE:
192			elems->challenge = pos;
193			elems->challenge_len = elen;
194			break;
195		case WLAN_EID_ERP_INFO:
196			elems->erp_info = pos;
197			elems->erp_info_len = elen;
198			break;
199		case WLAN_EID_EXT_SUPP_RATES:
200			elems->ext_supp_rates = pos;
201			elems->ext_supp_rates_len = elen;
202			break;
203		case WLAN_EID_VENDOR_SPECIFIC:
204			if (ieee802_11_parse_vendor_specific(pos, elen,
205							     elems,
206							     show_errors))
207				unknown++;
208			break;
209		case WLAN_EID_RSN:
210			elems->rsn_ie = pos;
211			elems->rsn_ie_len = elen;
212			break;
213		case WLAN_EID_PWR_CAPABILITY:
214			elems->power_cap = pos;
215			elems->power_cap_len = elen;
216			break;
217		case WLAN_EID_SUPPORTED_CHANNELS:
218			elems->supp_channels = pos;
219			elems->supp_channels_len = elen;
220			break;
221		case WLAN_EID_MOBILITY_DOMAIN:
222			elems->mdie = pos;
223			elems->mdie_len = elen;
224			break;
225		case WLAN_EID_FAST_BSS_TRANSITION:
226			elems->ftie = pos;
227			elems->ftie_len = elen;
228			break;
229		case WLAN_EID_TIMEOUT_INTERVAL:
230			elems->timeout_int = pos;
231			elems->timeout_int_len = elen;
232			break;
233		case WLAN_EID_HT_CAP:
234			elems->ht_capabilities = pos;
235			elems->ht_capabilities_len = elen;
236			break;
237		case WLAN_EID_HT_OPERATION:
238			elems->ht_operation = pos;
239			elems->ht_operation_len = elen;
240			break;
241		default:
242			unknown++;
243			if (!show_errors)
244				break;
245			wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse "
246				   "ignored unknown element (id=%d elen=%d)",
247				   id, elen);
248			break;
249		}
250
251		left -= elen;
252		pos += elen;
253	}
254
255	if (left)
256		return ParseFailed;
257
258	return unknown ? ParseUnknown : ParseOK;
259}
260