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