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