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 
22 static 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  */
134 ParseRes 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