• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * IEEE 802.11 Common routines
3  * Copyright (c) 2002-2009, 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 
ieee802_11_parse_vendor_specific(const u8 * pos,size_t elen,struct ieee802_11_elems * elems,int show_errors)22 static int ieee802_11_parse_vendor_specific(const 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_EXCESSIVE, "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_EXCESSIVE, "Unknown Microsoft "
92 				   "information element ignored "
93 				   "(type=%d len=%lu)",
94 				   pos[3], (unsigned long) elen);
95 			return -1;
96 		}
97 		break;
98 
99 	case OUI_WFA:
100 		switch (pos[3]) {
101 		case P2P_OUI_TYPE:
102 			/* Wi-Fi Alliance - P2P IE */
103 			elems->p2p = pos;
104 			elems->p2p_len = elen;
105 			break;
106 		default:
107 			wpa_printf(MSG_MSGDUMP, "Unknown WFA "
108 				   "information element ignored "
109 				   "(type=%d len=%lu)\n",
110 				   pos[3], (unsigned long) elen);
111 			return -1;
112 		}
113 		break;
114 
115 	case OUI_BROADCOM:
116 		switch (pos[3]) {
117 		case VENDOR_HT_CAPAB_OUI_TYPE:
118 			elems->vendor_ht_cap = pos;
119 			elems->vendor_ht_cap_len = elen;
120 			break;
121 		default:
122 			wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom "
123 				   "information element ignored "
124 				   "(type=%d len=%lu)",
125 				   pos[3], (unsigned long) elen);
126 			return -1;
127 		}
128 		break;
129 
130 	default:
131 		wpa_printf(MSG_EXCESSIVE, "unknown vendor specific "
132 			   "information element ignored (vendor OUI "
133 			   "%02x:%02x:%02x len=%lu)",
134 			   pos[0], pos[1], pos[2], (unsigned long) elen);
135 		return -1;
136 	}
137 
138 	return 0;
139 }
140 
141 
142 /**
143  * ieee802_11_parse_elems - Parse information elements in management frames
144  * @start: Pointer to the start of IEs
145  * @len: Length of IE buffer in octets
146  * @elems: Data structure for parsed elements
147  * @show_errors: Whether to show parsing errors in debug log
148  * Returns: Parsing result
149  */
ieee802_11_parse_elems(const u8 * start,size_t len,struct ieee802_11_elems * elems,int show_errors)150 ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
151 				struct ieee802_11_elems *elems,
152 				int show_errors)
153 {
154 	size_t left = len;
155 	const u8 *pos = start;
156 	int unknown = 0;
157 
158 	os_memset(elems, 0, sizeof(*elems));
159 
160 	while (left >= 2) {
161 		u8 id, elen;
162 
163 		id = *pos++;
164 		elen = *pos++;
165 		left -= 2;
166 
167 		if (elen > left) {
168 			if (show_errors) {
169 				wpa_printf(MSG_DEBUG, "IEEE 802.11 element "
170 					   "parse failed (id=%d elen=%d "
171 					   "left=%lu)",
172 					   id, elen, (unsigned long) left);
173 				wpa_hexdump(MSG_MSGDUMP, "IEs", start, len);
174 			}
175 			return ParseFailed;
176 		}
177 
178 		switch (id) {
179 		case WLAN_EID_SSID:
180 			elems->ssid = pos;
181 			elems->ssid_len = elen;
182 			break;
183 		case WLAN_EID_SUPP_RATES:
184 			elems->supp_rates = pos;
185 			elems->supp_rates_len = elen;
186 			break;
187 		case WLAN_EID_FH_PARAMS:
188 			elems->fh_params = pos;
189 			elems->fh_params_len = elen;
190 			break;
191 		case WLAN_EID_DS_PARAMS:
192 			elems->ds_params = pos;
193 			elems->ds_params_len = elen;
194 			break;
195 		case WLAN_EID_CF_PARAMS:
196 			elems->cf_params = pos;
197 			elems->cf_params_len = elen;
198 			break;
199 		case WLAN_EID_TIM:
200 			elems->tim = pos;
201 			elems->tim_len = elen;
202 			break;
203 		case WLAN_EID_IBSS_PARAMS:
204 			elems->ibss_params = pos;
205 			elems->ibss_params_len = elen;
206 			break;
207 		case WLAN_EID_CHALLENGE:
208 			elems->challenge = pos;
209 			elems->challenge_len = elen;
210 			break;
211 		case WLAN_EID_ERP_INFO:
212 			elems->erp_info = pos;
213 			elems->erp_info_len = elen;
214 			break;
215 		case WLAN_EID_EXT_SUPP_RATES:
216 			elems->ext_supp_rates = pos;
217 			elems->ext_supp_rates_len = elen;
218 			break;
219 		case WLAN_EID_VENDOR_SPECIFIC:
220 			if (ieee802_11_parse_vendor_specific(pos, elen,
221 							     elems,
222 							     show_errors))
223 				unknown++;
224 			break;
225 		case WLAN_EID_RSN:
226 			elems->rsn_ie = pos;
227 			elems->rsn_ie_len = elen;
228 			break;
229 		case WLAN_EID_PWR_CAPABILITY:
230 			elems->power_cap = pos;
231 			elems->power_cap_len = elen;
232 			break;
233 		case WLAN_EID_SUPPORTED_CHANNELS:
234 			elems->supp_channels = pos;
235 			elems->supp_channels_len = elen;
236 			break;
237 		case WLAN_EID_MOBILITY_DOMAIN:
238 			elems->mdie = pos;
239 			elems->mdie_len = elen;
240 			break;
241 		case WLAN_EID_FAST_BSS_TRANSITION:
242 			elems->ftie = pos;
243 			elems->ftie_len = elen;
244 			break;
245 		case WLAN_EID_TIMEOUT_INTERVAL:
246 			elems->timeout_int = pos;
247 			elems->timeout_int_len = elen;
248 			break;
249 		case WLAN_EID_HT_CAP:
250 			elems->ht_capabilities = pos;
251 			elems->ht_capabilities_len = elen;
252 			break;
253 		case WLAN_EID_HT_OPERATION:
254 			elems->ht_operation = pos;
255 			elems->ht_operation_len = elen;
256 			break;
257 		case WLAN_EID_LINK_ID:
258 			if (elen < 18)
259 				break;
260 			elems->link_id = pos;
261 			break;
262 		default:
263 			unknown++;
264 			if (!show_errors)
265 				break;
266 			wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse "
267 				   "ignored unknown element (id=%d elen=%d)",
268 				   id, elen);
269 			break;
270 		}
271 
272 		left -= elen;
273 		pos += elen;
274 	}
275 
276 	if (left)
277 		return ParseFailed;
278 
279 	return unknown ? ParseUnknown : ParseOK;
280 }
281 
282 
ieee802_11_ie_count(const u8 * ies,size_t ies_len)283 int ieee802_11_ie_count(const u8 *ies, size_t ies_len)
284 {
285 	int count = 0;
286 	const u8 *pos, *end;
287 
288 	if (ies == NULL)
289 		return 0;
290 
291 	pos = ies;
292 	end = ies + ies_len;
293 
294 	while (pos + 2 <= end) {
295 		if (pos + 2 + pos[1] > end)
296 			break;
297 		count++;
298 		pos += 2 + pos[1];
299 	}
300 
301 	return count;
302 }
303 
304 
ieee802_11_vendor_ie_concat(const u8 * ies,size_t ies_len,u32 oui_type)305 struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
306 					    u32 oui_type)
307 {
308 	struct wpabuf *buf;
309 	const u8 *end, *pos, *ie;
310 
311 	pos = ies;
312 	end = ies + ies_len;
313 	ie = NULL;
314 
315 	while (pos + 1 < end) {
316 		if (pos + 2 + pos[1] > end)
317 			return NULL;
318 		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
319 		    WPA_GET_BE32(&pos[2]) == oui_type) {
320 			ie = pos;
321 			break;
322 		}
323 		pos += 2 + pos[1];
324 	}
325 
326 	if (ie == NULL)
327 		return NULL; /* No specified vendor IE found */
328 
329 	buf = wpabuf_alloc(ies_len);
330 	if (buf == NULL)
331 		return NULL;
332 
333 	/*
334 	 * There may be multiple vendor IEs in the message, so need to
335 	 * concatenate their data fields.
336 	 */
337 	while (pos + 1 < end) {
338 		if (pos + 2 + pos[1] > end)
339 			break;
340 		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
341 		    WPA_GET_BE32(&pos[2]) == oui_type)
342 			wpabuf_put_data(buf, pos + 6, pos[1] - 4);
343 		pos += 2 + pos[1];
344 	}
345 
346 	return buf;
347 }
348