TDLS: Clean up add/set peer operations
[mech_eap.git] / src / rsn_supp / wpa_ie.c
1 /*
2  * wpa_supplicant - WPA/RSN IE and KDE processing
3  * Copyright (c) 2003-2008, 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 "wpa.h"
13 #include "pmksa_cache.h"
14 #include "common/ieee802_11_defs.h"
15 #include "wpa_i.h"
16 #include "wpa_ie.h"
17
18
19 /**
20  * wpa_parse_wpa_ie - Parse WPA/RSN IE
21  * @wpa_ie: Pointer to WPA or RSN IE
22  * @wpa_ie_len: Length of the WPA/RSN IE
23  * @data: Pointer to data area for parsing results
24  * Returns: 0 on success, -1 on failure
25  *
26  * Parse the contents of WPA or RSN IE and write the parsed data into data.
27  */
28 int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len,
29                      struct wpa_ie_data *data)
30 {
31         if (wpa_ie_len >= 1 && wpa_ie[0] == WLAN_EID_RSN)
32                 return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data);
33         else
34                 return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data);
35 }
36
37
38 static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
39                               int pairwise_cipher, int group_cipher,
40                               int key_mgmt)
41 {
42         u8 *pos;
43         struct wpa_ie_hdr *hdr;
44         u32 suite;
45
46         if (wpa_ie_len < sizeof(*hdr) + WPA_SELECTOR_LEN +
47             2 + WPA_SELECTOR_LEN + 2 + WPA_SELECTOR_LEN)
48                 return -1;
49
50         hdr = (struct wpa_ie_hdr *) wpa_ie;
51         hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC;
52         RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE);
53         WPA_PUT_LE16(hdr->version, WPA_VERSION);
54         pos = (u8 *) (hdr + 1);
55
56         suite = wpa_cipher_to_suite(WPA_PROTO_WPA, group_cipher);
57         if (suite == 0) {
58                 wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
59                            group_cipher);
60                 return -1;
61         }
62         RSN_SELECTOR_PUT(pos, suite);
63         pos += WPA_SELECTOR_LEN;
64
65         *pos++ = 1;
66         *pos++ = 0;
67         suite = wpa_cipher_to_suite(WPA_PROTO_WPA, pairwise_cipher);
68         if (suite == 0 ||
69             (!wpa_cipher_valid_pairwise(pairwise_cipher) &&
70              pairwise_cipher != WPA_CIPHER_NONE)) {
71                 wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
72                            pairwise_cipher);
73                 return -1;
74         }
75         RSN_SELECTOR_PUT(pos, suite);
76         pos += WPA_SELECTOR_LEN;
77
78         *pos++ = 1;
79         *pos++ = 0;
80         if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
81                 RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X);
82         } else if (key_mgmt == WPA_KEY_MGMT_PSK) {
83                 RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X);
84         } else if (key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
85                 RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_NONE);
86         } else if (key_mgmt == WPA_KEY_MGMT_CCKM) {
87                 RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_CCKM);
88         } else {
89                 wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
90                            key_mgmt);
91                 return -1;
92         }
93         pos += WPA_SELECTOR_LEN;
94
95         /* WPA Capabilities; use defaults, so no need to include it */
96
97         hdr->len = (pos - wpa_ie) - 2;
98
99         WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len);
100
101         return pos - wpa_ie;
102 }
103
104
105 static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
106                               int pairwise_cipher, int group_cipher,
107                               int key_mgmt, int mgmt_group_cipher,
108                               struct wpa_sm *sm)
109 {
110         u8 *pos;
111         struct rsn_ie_hdr *hdr;
112         u16 capab;
113         u32 suite;
114
115         if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN +
116             2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 +
117             (sm->cur_pmksa ? 2 + PMKID_LEN : 0)) {
118                 wpa_printf(MSG_DEBUG, "RSN: Too short IE buffer (%lu bytes)",
119                            (unsigned long) rsn_ie_len);
120                 return -1;
121         }
122
123         hdr = (struct rsn_ie_hdr *) rsn_ie;
124         hdr->elem_id = WLAN_EID_RSN;
125         WPA_PUT_LE16(hdr->version, RSN_VERSION);
126         pos = (u8 *) (hdr + 1);
127
128         suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher);
129         if (suite == 0) {
130                 wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
131                            group_cipher);
132                 return -1;
133         }
134         RSN_SELECTOR_PUT(pos, suite);
135         pos += RSN_SELECTOR_LEN;
136
137         *pos++ = 1;
138         *pos++ = 0;
139         suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher);
140         if (suite == 0 ||
141             (!wpa_cipher_valid_pairwise(pairwise_cipher) &&
142              pairwise_cipher != WPA_CIPHER_NONE)) {
143                 wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
144                            pairwise_cipher);
145                 return -1;
146         }
147         RSN_SELECTOR_PUT(pos, suite);
148         pos += RSN_SELECTOR_LEN;
149
150         *pos++ = 1;
151         *pos++ = 0;
152         if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
153                 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X);
154         } else if (key_mgmt == WPA_KEY_MGMT_PSK) {
155                 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X);
156         } else if (key_mgmt == WPA_KEY_MGMT_CCKM) {
157                 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_CCKM);
158 #ifdef CONFIG_IEEE80211R
159         } else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
160                 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
161         } else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) {
162                 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
163 #endif /* CONFIG_IEEE80211R */
164 #ifdef CONFIG_IEEE80211W
165         } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA256) {
166                 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
167         } else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) {
168                 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
169 #endif /* CONFIG_IEEE80211W */
170 #ifdef CONFIG_SAE
171         } else if (key_mgmt == WPA_KEY_MGMT_SAE) {
172                 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
173         } else if (key_mgmt == WPA_KEY_MGMT_FT_SAE) {
174                 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
175 #endif /* CONFIG_SAE */
176         } else {
177                 wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
178                            key_mgmt);
179                 return -1;
180         }
181         pos += RSN_SELECTOR_LEN;
182
183         /* RSN Capabilities */
184         capab = 0;
185 #ifdef CONFIG_IEEE80211W
186         if (sm->mfp)
187                 capab |= WPA_CAPABILITY_MFPC;
188         if (sm->mfp == 2)
189                 capab |= WPA_CAPABILITY_MFPR;
190 #endif /* CONFIG_IEEE80211W */
191         WPA_PUT_LE16(pos, capab);
192         pos += 2;
193
194         if (sm->cur_pmksa) {
195                 /* PMKID Count (2 octets, little endian) */
196                 *pos++ = 1;
197                 *pos++ = 0;
198                 /* PMKID */
199                 os_memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN);
200                 pos += PMKID_LEN;
201         }
202
203 #ifdef CONFIG_IEEE80211W
204         if (wpa_cipher_valid_mgmt_group(mgmt_group_cipher)) {
205                 if (!sm->cur_pmksa) {
206                         /* PMKID Count */
207                         WPA_PUT_LE16(pos, 0);
208                         pos += 2;
209                 }
210
211                 /* Management Group Cipher Suite */
212                 RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN,
213                                                           mgmt_group_cipher));
214                 pos += RSN_SELECTOR_LEN;
215         }
216 #endif /* CONFIG_IEEE80211W */
217
218         hdr->len = (pos - rsn_ie) - 2;
219
220         WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len);
221
222         return pos - rsn_ie;
223 }
224
225
226 #ifdef CONFIG_HS20
227 static int wpa_gen_wpa_ie_osen(u8 *wpa_ie, size_t wpa_ie_len,
228                                int pairwise_cipher, int group_cipher,
229                                int key_mgmt)
230 {
231         u8 *pos, *len;
232         u32 suite;
233
234         if (wpa_ie_len < 2 + 4 + RSN_SELECTOR_LEN +
235             2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN)
236                 return -1;
237
238         pos = wpa_ie;
239         *pos++ = WLAN_EID_VENDOR_SPECIFIC;
240         len = pos++; /* to be filled */
241         WPA_PUT_BE24(pos, OUI_WFA);
242         pos += 3;
243         *pos++ = HS20_OSEN_OUI_TYPE;
244
245         /* Group Data Cipher Suite */
246         suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher);
247         if (suite == 0) {
248                 wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
249                            group_cipher);
250                 return -1;
251         }
252         RSN_SELECTOR_PUT(pos, suite);
253         pos += RSN_SELECTOR_LEN;
254
255         /* Pairwise Cipher Suite Count and List */
256         WPA_PUT_LE16(pos, 1);
257         pos += 2;
258         suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher);
259         if (suite == 0 ||
260             (!wpa_cipher_valid_pairwise(pairwise_cipher) &&
261              pairwise_cipher != WPA_CIPHER_NONE)) {
262                 wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
263                            pairwise_cipher);
264                 return -1;
265         }
266         RSN_SELECTOR_PUT(pos, suite);
267         pos += RSN_SELECTOR_LEN;
268
269         /* AKM Suite Count and List */
270         WPA_PUT_LE16(pos, 1);
271         pos += 2;
272         RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN);
273         pos += RSN_SELECTOR_LEN;
274
275         *len = pos - len - 1;
276
277         WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len);
278
279         return pos - wpa_ie;
280 }
281 #endif /* CONFIG_HS20 */
282
283
284 /**
285  * wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy
286  * @sm: Pointer to WPA state machine data from wpa_sm_init()
287  * @wpa_ie: Pointer to memory area for the generated WPA/RSN IE
288  * @wpa_ie_len: Maximum length of the generated WPA/RSN IE
289  * Returns: Length of the generated WPA/RSN IE or -1 on failure
290  */
291 int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len)
292 {
293         if (sm->proto == WPA_PROTO_RSN)
294                 return wpa_gen_wpa_ie_rsn(wpa_ie, wpa_ie_len,
295                                           sm->pairwise_cipher,
296                                           sm->group_cipher,
297                                           sm->key_mgmt, sm->mgmt_group_cipher,
298                                           sm);
299 #ifdef CONFIG_HS20
300         else if (sm->proto == WPA_PROTO_OSEN)
301                 return wpa_gen_wpa_ie_osen(wpa_ie, wpa_ie_len,
302                                            sm->pairwise_cipher,
303                                            sm->group_cipher,
304                                            sm->key_mgmt);
305 #endif /* CONFIG_HS20 */
306         else
307                 return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len,
308                                           sm->pairwise_cipher,
309                                           sm->group_cipher,
310                                           sm->key_mgmt);
311 }
312
313
314 /**
315  * wpa_parse_vendor_specific - Parse Vendor Specific IEs
316  * @pos: Pointer to the IE header
317  * @end: Pointer to the end of the Key Data buffer
318  * @ie: Pointer to parsed IE data
319  * Returns: 0 on success, 1 if end mark is found, -1 on failure
320  */
321 static int wpa_parse_vendor_specific(const u8 *pos, const u8 *end,
322                                      struct wpa_eapol_ie_parse *ie)
323 {
324         unsigned int oui;
325
326         if (pos[1] < 4) {
327                 wpa_printf(MSG_MSGDUMP, "Too short vendor specific IE ignored (len=%u)",
328                            pos[1]);
329                 return 1;
330         }
331
332         oui = WPA_GET_BE24(&pos[2]);
333         if (oui == OUI_MICROSOFT && pos[5] == WMM_OUI_TYPE && pos[1] > 4) {
334                 if (pos[6] == WMM_OUI_SUBTYPE_INFORMATION_ELEMENT) {
335                         ie->wmm = &pos[2];
336                         ie->wmm_len = pos[1];
337                         wpa_hexdump(MSG_DEBUG, "WPA: WMM IE",
338                                     ie->wmm, ie->wmm_len);
339                 } else if (pos[6] == WMM_OUI_SUBTYPE_PARAMETER_ELEMENT) {
340                         ie->wmm = &pos[2];
341                         ie->wmm_len = pos[1];
342                         wpa_hexdump(MSG_DEBUG, "WPA: WMM Parameter Element",
343                                     ie->wmm, ie->wmm_len);
344                 }
345         }
346         return 0;
347 }
348
349
350 /**
351  * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
352  * @pos: Pointer to the IE header
353  * @end: Pointer to the end of the Key Data buffer
354  * @ie: Pointer to parsed IE data
355  * Returns: 0 on success, 1 if end mark is found, -1 on failure
356  */
357 static int wpa_parse_generic(const u8 *pos, const u8 *end,
358                              struct wpa_eapol_ie_parse *ie)
359 {
360         if (pos[1] == 0)
361                 return 1;
362
363         if (pos[1] >= 6 &&
364             RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
365             pos[2 + WPA_SELECTOR_LEN] == 1 &&
366             pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
367                 ie->wpa_ie = pos;
368                 ie->wpa_ie_len = pos[1] + 2;
369                 wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key",
370                             ie->wpa_ie, ie->wpa_ie_len);
371                 return 0;
372         }
373
374         if (pos + 1 + RSN_SELECTOR_LEN < end &&
375             pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
376             RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
377                 ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
378                 wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key",
379                             pos, pos[1] + 2);
380                 return 0;
381         }
382
383         if (pos[1] > RSN_SELECTOR_LEN + 2 &&
384             RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
385                 ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
386                 ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
387                 wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key",
388                                 pos, pos[1] + 2);
389                 return 0;
390         }
391
392         if (pos[1] > RSN_SELECTOR_LEN + 2 &&
393             RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
394                 ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
395                 ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
396                 wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key",
397                             pos, pos[1] + 2);
398                 return 0;
399         }
400
401 #ifdef CONFIG_PEERKEY
402         if (pos[1] > RSN_SELECTOR_LEN + 2 &&
403             RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) {
404                 ie->smk = pos + 2 + RSN_SELECTOR_LEN;
405                 ie->smk_len = pos[1] - RSN_SELECTOR_LEN;
406                 wpa_hexdump_key(MSG_DEBUG, "WPA: SMK in EAPOL-Key",
407                                 pos, pos[1] + 2);
408                 return 0;
409         }
410
411         if (pos[1] > RSN_SELECTOR_LEN + 2 &&
412             RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) {
413                 ie->nonce = pos + 2 + RSN_SELECTOR_LEN;
414                 ie->nonce_len = pos[1] - RSN_SELECTOR_LEN;
415                 wpa_hexdump(MSG_DEBUG, "WPA: Nonce in EAPOL-Key",
416                             pos, pos[1] + 2);
417                 return 0;
418         }
419
420         if (pos[1] > RSN_SELECTOR_LEN + 2 &&
421             RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) {
422                 ie->lifetime = pos + 2 + RSN_SELECTOR_LEN;
423                 ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN;
424                 wpa_hexdump(MSG_DEBUG, "WPA: Lifetime in EAPOL-Key",
425                             pos, pos[1] + 2);
426                 return 0;
427         }
428
429         if (pos[1] > RSN_SELECTOR_LEN + 2 &&
430             RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) {
431                 ie->error = pos + 2 + RSN_SELECTOR_LEN;
432                 ie->error_len = pos[1] - RSN_SELECTOR_LEN;
433                 wpa_hexdump(MSG_DEBUG, "WPA: Error in EAPOL-Key",
434                             pos, pos[1] + 2);
435                 return 0;
436         }
437 #endif /* CONFIG_PEERKEY */
438
439 #ifdef CONFIG_IEEE80211W
440         if (pos[1] > RSN_SELECTOR_LEN + 2 &&
441             RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
442                 ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
443                 ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
444                 wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK in EAPOL-Key",
445                                 pos, pos[1] + 2);
446                 return 0;
447         }
448 #endif /* CONFIG_IEEE80211W */
449
450 #ifdef CONFIG_P2P
451         if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
452             RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) {
453                 ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN;
454                 wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key",
455                             ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN);
456                 return 0;
457         }
458
459         if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 &&
460             RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) {
461                 ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN;
462                 wpa_hexdump(MSG_DEBUG,
463                             "WPA: IP Address Allocation in EAPOL-Key",
464                             ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN);
465                 return 0;
466         }
467 #endif /* CONFIG_P2P */
468
469         return 0;
470 }
471
472
473 /**
474  * wpa_supplicant_parse_ies - Parse EAPOL-Key Key Data IEs
475  * @buf: Pointer to the Key Data buffer
476  * @len: Key Data Length
477  * @ie: Pointer to parsed IE data
478  * Returns: 0 on success, -1 on failure
479  */
480 int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
481                              struct wpa_eapol_ie_parse *ie)
482 {
483         const u8 *pos, *end;
484         int ret = 0;
485
486         os_memset(ie, 0, sizeof(*ie));
487         for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) {
488                 if (pos[0] == 0xdd &&
489                     ((pos == buf + len - 1) || pos[1] == 0)) {
490                         /* Ignore padding */
491                         break;
492                 }
493                 if (pos + 2 + pos[1] > end) {
494                         wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
495                                    "underflow (ie=%d len=%d pos=%d)",
496                                    pos[0], pos[1], (int) (pos - buf));
497                         wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data",
498                                         buf, len);
499                         ret = -1;
500                         break;
501                 }
502                 if (*pos == WLAN_EID_RSN) {
503                         ie->rsn_ie = pos;
504                         ie->rsn_ie_len = pos[1] + 2;
505                         wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key",
506                                     ie->rsn_ie, ie->rsn_ie_len);
507                 } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
508                         ie->mdie = pos;
509                         ie->mdie_len = pos[1] + 2;
510                         wpa_hexdump(MSG_DEBUG, "WPA: MDIE in EAPOL-Key",
511                                     ie->mdie, ie->mdie_len);
512                 } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) {
513                         ie->ftie = pos;
514                         ie->ftie_len = pos[1] + 2;
515                         wpa_hexdump(MSG_DEBUG, "WPA: FTIE in EAPOL-Key",
516                                     ie->ftie, ie->ftie_len);
517                 } else if (*pos == WLAN_EID_TIMEOUT_INTERVAL && pos[1] >= 5) {
518                         if (pos[2] == WLAN_TIMEOUT_REASSOC_DEADLINE) {
519                                 ie->reassoc_deadline = pos;
520                                 wpa_hexdump(MSG_DEBUG, "WPA: Reassoc Deadline "
521                                             "in EAPOL-Key",
522                                             ie->reassoc_deadline, pos[1] + 2);
523                         } else if (pos[2] == WLAN_TIMEOUT_KEY_LIFETIME) {
524                                 ie->key_lifetime = pos;
525                                 wpa_hexdump(MSG_DEBUG, "WPA: KeyLifetime "
526                                             "in EAPOL-Key",
527                                             ie->key_lifetime, pos[1] + 2);
528                         } else {
529                                 wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized "
530                                             "EAPOL-Key Key Data IE",
531                                             pos, 2 + pos[1]);
532                         }
533                 } else if (*pos == WLAN_EID_LINK_ID) {
534                         if (pos[1] >= 18) {
535                                 ie->lnkid = pos;
536                                 ie->lnkid_len = pos[1] + 2;
537                         }
538                 } else if (*pos == WLAN_EID_EXT_CAPAB) {
539                         ie->ext_capab = pos;
540                         ie->ext_capab_len = pos[1] + 2;
541                 } else if (*pos == WLAN_EID_SUPP_RATES) {
542                         ie->supp_rates = pos;
543                         ie->supp_rates_len = pos[1] + 2;
544                 } else if (*pos == WLAN_EID_EXT_SUPP_RATES) {
545                         ie->ext_supp_rates = pos;
546                         ie->ext_supp_rates_len = pos[1] + 2;
547                 } else if (*pos == WLAN_EID_HT_CAP) {
548                         ie->ht_capabilities = pos + 2;
549                         ie->ht_capabilities_len = pos[1];
550                 } else if (*pos == WLAN_EID_VHT_AID) {
551                         if (pos[1] >= 2)
552                                 ie->aid = WPA_GET_LE16(pos + 2);
553                 } else if (*pos == WLAN_EID_VHT_CAP) {
554                         ie->vht_capabilities = pos + 2;
555                         ie->vht_capabilities_len = pos[1];
556                 } else if (*pos == WLAN_EID_QOS && pos[1] >= 1) {
557                         ie->qosinfo = pos[2];
558                 } else if (*pos == WLAN_EID_SUPPORTED_CHANNELS) {
559                         ie->supp_channels = pos + 2;
560                         ie->supp_channels_len = pos[1];
561                 } else if (*pos == WLAN_EID_SUPPORTED_OPERATING_CLASSES) {
562                         /*
563                          * The value of the Length field of the Supported
564                          * Operating Classes element is between 2 and 253.
565                          * Silently skip invalid elements to avoid interop
566                          * issues when trying to use the value.
567                          */
568                         if (pos[1] >= 2 && pos[1] <= 253) {
569                                 ie->supp_oper_classes = pos + 2;
570                                 ie->supp_oper_classes_len = pos[1];
571                         }
572                 } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
573                         ret = wpa_parse_generic(pos, end, ie);
574                         if (ret < 0)
575                                 break;
576                         if (ret > 0) {
577                                 ret = 0;
578                                 break;
579                         }
580
581                         ret = wpa_parse_vendor_specific(pos, end, ie);
582                         if (ret < 0)
583                                 break;
584                         if (ret > 0) {
585                                 ret = 0;
586                                 break;
587                         }
588                 } else {
589                         wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
590                                     "Key Data IE", pos, 2 + pos[1]);
591                 }
592         }
593
594         return ret;
595 }