~ubuntu-branches/ubuntu/gutsy/wpasupplicant/gutsy

« back to all changes in this revision

Viewing changes to src/rsn_supp/wpa_ie.c

  • Committer: Bazaar Package Importer
  • Author(s): Reinhard Tartler, Alexander Sack
  • Date: 2007-08-26 16:06:57 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20070826160657-2m8pxoweuxe8f93t
Tags: 0.6.0+0.5.8-0ubuntu1
* New upstream release
* remove patch 11_erroneous_manpage_ref, applied upstream
* remove patch 25_wpas_dbus_unregister_iface_fix, applied upstream

[ Alexander Sack ]
* bumping upstream version to replace development version 0.6.0 with
  this package from stable release branch.
* attempt to fix wierd timeout and high latency issues by going
  back to stable upstream version (0.5.9) (LP: #140763,
  LP: #141233).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * wpa_supplicant - WPA/RSN IE and KDE processing
3
 
 * Copyright (c) 2003-2007, 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 "wpa.h"
19
 
#include "config_ssid.h"
20
 
#include "pmksa_cache.h"
21
 
#include "ieee802_11_defs.h"
22
 
#include "wpa_i.h"
23
 
#include "wpa_ie.h"
24
 
 
25
 
 
26
 
static int wpa_selector_to_bitfield(const u8 *s)
27
 
{
28
 
        if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE)
29
 
                return WPA_CIPHER_NONE;
30
 
        if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP40)
31
 
                return WPA_CIPHER_WEP40;
32
 
        if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP)
33
 
                return WPA_CIPHER_TKIP;
34
 
        if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP)
35
 
                return WPA_CIPHER_CCMP;
36
 
        if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP104)
37
 
                return WPA_CIPHER_WEP104;
38
 
        return 0;
39
 
}
40
 
 
41
 
 
42
 
static int wpa_key_mgmt_to_bitfield(const u8 *s)
43
 
{
44
 
        if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_UNSPEC_802_1X)
45
 
                return WPA_KEY_MGMT_IEEE8021X;
46
 
        if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X)
47
 
                return WPA_KEY_MGMT_PSK;
48
 
        if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_NONE)
49
 
                return WPA_KEY_MGMT_WPA_NONE;
50
 
        return 0;
51
 
}
52
 
 
53
 
 
54
 
static int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
55
 
                                struct wpa_ie_data *data)
56
 
{
57
 
        const struct wpa_ie_hdr *hdr;
58
 
        const u8 *pos;
59
 
        int left;
60
 
        int i, count;
61
 
 
62
 
        os_memset(data, 0, sizeof(*data));
63
 
        data->proto = WPA_PROTO_WPA;
64
 
        data->pairwise_cipher = WPA_CIPHER_TKIP;
65
 
        data->group_cipher = WPA_CIPHER_TKIP;
66
 
        data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
67
 
        data->capabilities = 0;
68
 
        data->pmkid = NULL;
69
 
        data->num_pmkid = 0;
70
 
        data->mgmt_group_cipher = 0;
71
 
 
72
 
        if (wpa_ie_len == 0) {
73
 
                /* No WPA IE - fail silently */
74
 
                return -1;
75
 
        }
76
 
 
77
 
        if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) {
78
 
                wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
79
 
                           __func__, (unsigned long) wpa_ie_len);
80
 
                return -1;
81
 
        }
82
 
 
83
 
        hdr = (const struct wpa_ie_hdr *) wpa_ie;
84
 
 
85
 
        if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC ||
86
 
            hdr->len != wpa_ie_len - 2 ||
87
 
            RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE ||
88
 
            WPA_GET_LE16(hdr->version) != WPA_VERSION) {
89
 
                wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
90
 
                           __func__);
91
 
                return -1;
92
 
        }
93
 
 
94
 
        pos = (const u8 *) (hdr + 1);
95
 
        left = wpa_ie_len - sizeof(*hdr);
96
 
 
97
 
        if (left >= WPA_SELECTOR_LEN) {
98
 
                data->group_cipher = wpa_selector_to_bitfield(pos);
99
 
                pos += WPA_SELECTOR_LEN;
100
 
                left -= WPA_SELECTOR_LEN;
101
 
        } else if (left > 0) {
102
 
                wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
103
 
                           __func__, left);
104
 
                return -1;
105
 
        }
106
 
 
107
 
        if (left >= 2) {
108
 
                data->pairwise_cipher = 0;
109
 
                count = WPA_GET_LE16(pos);
110
 
                pos += 2;
111
 
                left -= 2;
112
 
                if (count == 0 || left < count * WPA_SELECTOR_LEN) {
113
 
                        wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
114
 
                                   "count %u left %u", __func__, count, left);
115
 
                        return -1;
116
 
                }
117
 
                for (i = 0; i < count; i++) {
118
 
                        data->pairwise_cipher |= wpa_selector_to_bitfield(pos);
119
 
                        pos += WPA_SELECTOR_LEN;
120
 
                        left -= WPA_SELECTOR_LEN;
121
 
                }
122
 
        } else if (left == 1) {
123
 
                wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
124
 
                           __func__);
125
 
                return -1;
126
 
        }
127
 
 
128
 
        if (left >= 2) {
129
 
                data->key_mgmt = 0;
130
 
                count = WPA_GET_LE16(pos);
131
 
                pos += 2;
132
 
                left -= 2;
133
 
                if (count == 0 || left < count * WPA_SELECTOR_LEN) {
134
 
                        wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
135
 
                                   "count %u left %u", __func__, count, left);
136
 
                        return -1;
137
 
                }
138
 
                for (i = 0; i < count; i++) {
139
 
                        data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos);
140
 
                        pos += WPA_SELECTOR_LEN;
141
 
                        left -= WPA_SELECTOR_LEN;
142
 
                }
143
 
        } else if (left == 1) {
144
 
                wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
145
 
                           __func__);
146
 
                return -1;
147
 
        }
148
 
 
149
 
        if (left >= 2) {
150
 
                data->capabilities = WPA_GET_LE16(pos);
151
 
                pos += 2;
152
 
                left -= 2;
153
 
        }
154
 
 
155
 
        if (left > 0) {
156
 
                wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored",
157
 
                           __func__, left);
158
 
        }
159
 
 
160
 
        return 0;
161
 
}
162
 
 
163
 
 
164
 
/**
165
 
 * wpa_parse_wpa_ie - Parse WPA/RSN IE
166
 
 * @wpa_ie: Pointer to WPA or RSN IE
167
 
 * @wpa_ie_len: Length of the WPA/RSN IE
168
 
 * @data: Pointer to data area for parsing results
169
 
 * Returns: 0 on success, -1 on failure
170
 
 *
171
 
 * Parse the contents of WPA or RSN IE and write the parsed data into data.
172
 
 */
173
 
int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len,
174
 
                     struct wpa_ie_data *data)
175
 
{
176
 
        if (wpa_ie_len >= 1 && wpa_ie[0] == WLAN_EID_RSN)
177
 
                return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data);
178
 
        else
179
 
                return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data);
180
 
}
181
 
 
182
 
 
183
 
static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
184
 
                              int pairwise_cipher, int group_cipher,
185
 
                              int key_mgmt)
186
 
{
187
 
        u8 *pos;
188
 
        struct wpa_ie_hdr *hdr;
189
 
 
190
 
        if (wpa_ie_len < sizeof(*hdr) + WPA_SELECTOR_LEN +
191
 
            2 + WPA_SELECTOR_LEN + 2 + WPA_SELECTOR_LEN)
192
 
                return -1;
193
 
 
194
 
        hdr = (struct wpa_ie_hdr *) wpa_ie;
195
 
        hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC;
196
 
        RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE);
197
 
        WPA_PUT_LE16(hdr->version, WPA_VERSION);
198
 
        pos = (u8 *) (hdr + 1);
199
 
 
200
 
        if (group_cipher == WPA_CIPHER_CCMP) {
201
 
                RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
202
 
        } else if (group_cipher == WPA_CIPHER_TKIP) {
203
 
                RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
204
 
        } else if (group_cipher == WPA_CIPHER_WEP104) {
205
 
                RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP104);
206
 
        } else if (group_cipher == WPA_CIPHER_WEP40) {
207
 
                RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP40);
208
 
        } else {
209
 
                wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
210
 
                           group_cipher);
211
 
                return -1;
212
 
        }
213
 
        pos += WPA_SELECTOR_LEN;
214
 
 
215
 
        *pos++ = 1;
216
 
        *pos++ = 0;
217
 
        if (pairwise_cipher == WPA_CIPHER_CCMP) {
218
 
                RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
219
 
        } else if (pairwise_cipher == WPA_CIPHER_TKIP) {
220
 
                RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
221
 
        } else if (pairwise_cipher == WPA_CIPHER_NONE) {
222
 
                RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE);
223
 
        } else {
224
 
                wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
225
 
                           pairwise_cipher);
226
 
                return -1;
227
 
        }
228
 
        pos += WPA_SELECTOR_LEN;
229
 
 
230
 
        *pos++ = 1;
231
 
        *pos++ = 0;
232
 
        if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
233
 
                RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X);
234
 
        } else if (key_mgmt == WPA_KEY_MGMT_PSK) {
235
 
                RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X);
236
 
        } else if (key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
237
 
                RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_NONE);
238
 
        } else {
239
 
                wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
240
 
                           key_mgmt);
241
 
                return -1;
242
 
        }
243
 
        pos += WPA_SELECTOR_LEN;
244
 
 
245
 
        /* WPA Capabilities; use defaults, so no need to include it */
246
 
 
247
 
        hdr->len = (pos - wpa_ie) - 2;
248
 
 
249
 
        WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len);
250
 
 
251
 
        return pos - wpa_ie;
252
 
}
253
 
 
254
 
 
255
 
static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
256
 
                              int pairwise_cipher, int group_cipher,
257
 
                              int key_mgmt, int mgmt_group_cipher,
258
 
                              struct wpa_sm *sm)
259
 
{
260
 
#ifndef CONFIG_NO_WPA2
261
 
        u8 *pos;
262
 
        struct rsn_ie_hdr *hdr;
263
 
        u16 capab;
264
 
 
265
 
        if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN +
266
 
            2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 +
267
 
            (sm->cur_pmksa ? 2 + PMKID_LEN : 0)) {
268
 
                wpa_printf(MSG_DEBUG, "RSN: Too short IE buffer (%lu bytes)",
269
 
                           (unsigned long) rsn_ie_len);
270
 
                return -1;
271
 
        }
272
 
 
273
 
        hdr = (struct rsn_ie_hdr *) rsn_ie;
274
 
        hdr->elem_id = WLAN_EID_RSN;
275
 
        WPA_PUT_LE16(hdr->version, RSN_VERSION);
276
 
        pos = (u8 *) (hdr + 1);
277
 
 
278
 
        if (group_cipher == WPA_CIPHER_CCMP) {
279
 
                RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
280
 
        } else if (group_cipher == WPA_CIPHER_TKIP) {
281
 
                RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
282
 
        } else if (group_cipher == WPA_CIPHER_WEP104) {
283
 
                RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP104);
284
 
        } else if (group_cipher == WPA_CIPHER_WEP40) {
285
 
                RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP40);
286
 
        } else {
287
 
                wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
288
 
                           group_cipher);
289
 
                return -1;
290
 
        }
291
 
        pos += RSN_SELECTOR_LEN;
292
 
 
293
 
        *pos++ = 1;
294
 
        *pos++ = 0;
295
 
        if (pairwise_cipher == WPA_CIPHER_CCMP) {
296
 
                RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
297
 
        } else if (pairwise_cipher == WPA_CIPHER_TKIP) {
298
 
                RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
299
 
        } else if (pairwise_cipher == WPA_CIPHER_NONE) {
300
 
                RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE);
301
 
        } else {
302
 
                wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
303
 
                           pairwise_cipher);
304
 
                return -1;
305
 
        }
306
 
        pos += RSN_SELECTOR_LEN;
307
 
 
308
 
        *pos++ = 1;
309
 
        *pos++ = 0;
310
 
        if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
311
 
                RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X);
312
 
        } else if (key_mgmt == WPA_KEY_MGMT_PSK) {
313
 
                RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X);
314
 
#ifdef CONFIG_IEEE80211R
315
 
        } else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
316
 
                RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
317
 
        } else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) {
318
 
                RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
319
 
#endif /* CONFIG_IEEE80211R */
320
 
        } else {
321
 
                wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
322
 
                           key_mgmt);
323
 
                return -1;
324
 
        }
325
 
        pos += RSN_SELECTOR_LEN;
326
 
 
327
 
        /* RSN Capabilities */
328
 
        capab = 0;
329
 
#ifdef CONFIG_IEEE80211W
330
 
        if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC)
331
 
                capab |= WPA_CAPABILITY_MGMT_FRAME_PROTECTION;
332
 
#endif /* CONFIG_IEEE80211W */
333
 
        WPA_PUT_LE16(pos, capab);
334
 
        pos += 2;
335
 
 
336
 
        if (sm->cur_pmksa) {
337
 
                /* PMKID Count (2 octets, little endian) */
338
 
                *pos++ = 1;
339
 
                *pos++ = 0;
340
 
                /* PMKID */
341
 
                os_memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN);
342
 
                pos += PMKID_LEN;
343
 
        }
344
 
 
345
 
#ifdef CONFIG_IEEE80211W
346
 
        if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
347
 
                if (!sm->cur_pmksa) {
348
 
                        /* PMKID Count */
349
 
                        WPA_PUT_LE16(pos, 0);
350
 
                        pos += 2;
351
 
                }
352
 
 
353
 
                /* Management Group Cipher Suite */
354
 
                RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
355
 
                pos += RSN_SELECTOR_LEN;
356
 
        }
357
 
#endif /* CONFIG_IEEE80211W */
358
 
 
359
 
        hdr->len = (pos - rsn_ie) - 2;
360
 
 
361
 
        WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len);
362
 
 
363
 
        return pos - rsn_ie;
364
 
#else /* CONFIG_NO_WPA2 */
365
 
        return -1;
366
 
#endif /* CONFIG_NO_WPA2 */
367
 
}
368
 
 
369
 
 
370
 
/**
371
 
 * wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy
372
 
 * @sm: Pointer to WPA state machine data from wpa_sm_init()
373
 
 * @wpa_ie: Pointer to memory area for the generated WPA/RSN IE
374
 
 * @wpa_ie_len: Maximum length of the generated WPA/RSN IE
375
 
 * Returns: Length of the generated WPA/RSN IE or -1 on failure
376
 
 */
377
 
int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len)
378
 
{
379
 
        if (sm->proto == WPA_PROTO_RSN)
380
 
                return wpa_gen_wpa_ie_rsn(wpa_ie, wpa_ie_len,
381
 
                                          sm->pairwise_cipher,
382
 
                                          sm->group_cipher,
383
 
                                          sm->key_mgmt, sm->mgmt_group_cipher,
384
 
                                          sm);
385
 
        else
386
 
                return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len,
387
 
                                          sm->pairwise_cipher,
388
 
                                          sm->group_cipher,
389
 
                                          sm->key_mgmt);
390
 
}
391
 
 
392
 
 
393
 
/**
394
 
 * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
395
 
 * @pos: Pointer to the IE header
396
 
 * @end: Pointer to the end of the Key Data buffer
397
 
 * @ie: Pointer to parsed IE data
398
 
 * Returns: 0 on success, 1 if end mark is found, -1 on failure
399
 
 */
400
 
static int wpa_parse_generic(const u8 *pos, const u8 *end,
401
 
                             struct wpa_eapol_ie_parse *ie)
402
 
{
403
 
        if (pos[1] == 0)
404
 
                return 1;
405
 
 
406
 
        if (pos[1] >= 6 &&
407
 
            RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
408
 
            pos[2 + WPA_SELECTOR_LEN] == 1 &&
409
 
            pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
410
 
                ie->wpa_ie = pos;
411
 
                ie->wpa_ie_len = pos[1] + 2;
412
 
                return 0;
413
 
        }
414
 
 
415
 
        if (pos + 1 + RSN_SELECTOR_LEN < end &&
416
 
            pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
417
 
            RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
418
 
                ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
419
 
                return 0;
420
 
        }
421
 
 
422
 
        if (pos[1] > RSN_SELECTOR_LEN + 2 &&
423
 
            RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
424
 
                ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
425
 
                ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
426
 
                return 0;
427
 
        }
428
 
 
429
 
        if (pos[1] > RSN_SELECTOR_LEN + 2 &&
430
 
            RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
431
 
                ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
432
 
                ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
433
 
                return 0;
434
 
        }
435
 
 
436
 
#ifdef CONFIG_PEERKEY
437
 
        if (pos[1] > RSN_SELECTOR_LEN + 2 &&
438
 
            RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) {
439
 
                ie->smk = pos + 2 + RSN_SELECTOR_LEN;
440
 
                ie->smk_len = pos[1] - RSN_SELECTOR_LEN;
441
 
                return 0;
442
 
        }
443
 
 
444
 
        if (pos[1] > RSN_SELECTOR_LEN + 2 &&
445
 
            RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) {
446
 
                ie->nonce = pos + 2 + RSN_SELECTOR_LEN;
447
 
                ie->nonce_len = pos[1] - RSN_SELECTOR_LEN;
448
 
                return 0;
449
 
        }
450
 
 
451
 
        if (pos[1] > RSN_SELECTOR_LEN + 2 &&
452
 
            RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) {
453
 
                ie->lifetime = pos + 2 + RSN_SELECTOR_LEN;
454
 
                ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN;
455
 
                return 0;
456
 
        }
457
 
 
458
 
        if (pos[1] > RSN_SELECTOR_LEN + 2 &&
459
 
            RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) {
460
 
                ie->error = pos + 2 + RSN_SELECTOR_LEN;
461
 
                ie->error_len = pos[1] - RSN_SELECTOR_LEN;
462
 
                return 0;
463
 
        }
464
 
#endif /* CONFIG_PEERKEY */
465
 
 
466
 
#ifdef CONFIG_IEEE80211W
467
 
        if (pos[1] > RSN_SELECTOR_LEN + 2 &&
468
 
            RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
469
 
                ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
470
 
                ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
471
 
                return 0;
472
 
        }
473
 
#endif /* CONFIG_IEEE80211W */
474
 
 
475
 
        return 0;
476
 
}
477
 
 
478
 
 
479
 
/**
480
 
 * wpa_supplicant_parse_ies - Parse EAPOL-Key Key Data IEs
481
 
 * @buf: Pointer to the Key Data buffer
482
 
 * @len: Key Data Length
483
 
 * @ie: Pointer to parsed IE data
484
 
 * Returns: 0 on success, -1 on failure
485
 
 */
486
 
int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
487
 
                             struct wpa_eapol_ie_parse *ie)
488
 
{
489
 
        const u8 *pos, *end;
490
 
        int ret = 0;
491
 
 
492
 
        os_memset(ie, 0, sizeof(*ie));
493
 
        for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) {
494
 
                if (pos[0] == 0xdd &&
495
 
                    ((pos == buf + len - 1) || pos[1] == 0)) {
496
 
                        /* Ignore padding */
497
 
                        break;
498
 
                }
499
 
                if (pos + 2 + pos[1] > end) {
500
 
                        wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
501
 
                                   "underflow (ie=%d len=%d pos=%d)",
502
 
                                   pos[0], pos[1], (int) (pos - buf));
503
 
                        wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data",
504
 
                                        buf, len);
505
 
                        ret = -1;
506
 
                        break;
507
 
                }
508
 
                if (*pos == WLAN_EID_RSN) {
509
 
                        ie->rsn_ie = pos;
510
 
                        ie->rsn_ie_len = pos[1] + 2;
511
 
#ifdef CONFIG_IEEE80211R
512
 
                } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
513
 
                        ie->mdie = pos;
514
 
                        ie->mdie_len = pos[1] + 2;
515
 
#endif /* CONFIG_IEEE80211R */
516
 
                } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
517
 
                        ret = wpa_parse_generic(pos, end, ie);
518
 
                        if (ret < 0)
519
 
                                break;
520
 
                        if (ret > 0) {
521
 
                                ret = 0;
522
 
                                break;
523
 
                        }
524
 
                } else {
525
 
                        wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
526
 
                                    "Key Data IE", pos, 2 + pos[1]);
527
 
                }
528
 
        }
529
 
 
530
 
        return ret;
531
 
}