]> git.ipfire.org Git - thirdparty/hostap.git/blob - src/rsn_supp/wpa_ie.c
TDLS: Work around interop issues with supported operating class
[thirdparty/hostap.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 (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
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, RSN_CIPHER_SUITE_AES_128_CMAC);
213 pos += RSN_SELECTOR_LEN;
214 }
215 #endif /* CONFIG_IEEE80211W */
216
217 hdr->len = (pos - rsn_ie) - 2;
218
219 WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len);
220
221 return pos - rsn_ie;
222 }
223
224
225 #ifdef CONFIG_HS20
226 static int wpa_gen_wpa_ie_osen(u8 *wpa_ie, size_t wpa_ie_len,
227 int pairwise_cipher, int group_cipher,
228 int key_mgmt)
229 {
230 u8 *pos, *len;
231 u32 suite;
232
233 if (wpa_ie_len < 2 + 4 + RSN_SELECTOR_LEN +
234 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN)
235 return -1;
236
237 pos = wpa_ie;
238 *pos++ = WLAN_EID_VENDOR_SPECIFIC;
239 len = pos++; /* to be filled */
240 WPA_PUT_BE24(pos, OUI_WFA);
241 pos += 3;
242 *pos++ = HS20_OSEN_OUI_TYPE;
243
244 /* Group Data Cipher Suite */
245 suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher);
246 if (suite == 0) {
247 wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
248 group_cipher);
249 return -1;
250 }
251 RSN_SELECTOR_PUT(pos, suite);
252 pos += RSN_SELECTOR_LEN;
253
254 /* Pairwise Cipher Suite Count and List */
255 WPA_PUT_LE16(pos, 1);
256 pos += 2;
257 suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher);
258 if (suite == 0 ||
259 (!wpa_cipher_valid_pairwise(pairwise_cipher) &&
260 pairwise_cipher != WPA_CIPHER_NONE)) {
261 wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
262 pairwise_cipher);
263 return -1;
264 }
265 RSN_SELECTOR_PUT(pos, suite);
266 pos += RSN_SELECTOR_LEN;
267
268 /* AKM Suite Count and List */
269 WPA_PUT_LE16(pos, 1);
270 pos += 2;
271 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN);
272 pos += RSN_SELECTOR_LEN;
273
274 *len = pos - len - 1;
275
276 WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len);
277
278 return pos - wpa_ie;
279 }
280 #endif /* CONFIG_HS20 */
281
282
283 /**
284 * wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy
285 * @sm: Pointer to WPA state machine data from wpa_sm_init()
286 * @wpa_ie: Pointer to memory area for the generated WPA/RSN IE
287 * @wpa_ie_len: Maximum length of the generated WPA/RSN IE
288 * Returns: Length of the generated WPA/RSN IE or -1 on failure
289 */
290 int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len)
291 {
292 if (sm->proto == WPA_PROTO_RSN)
293 return wpa_gen_wpa_ie_rsn(wpa_ie, wpa_ie_len,
294 sm->pairwise_cipher,
295 sm->group_cipher,
296 sm->key_mgmt, sm->mgmt_group_cipher,
297 sm);
298 #ifdef CONFIG_HS20
299 else if (sm->proto == WPA_PROTO_OSEN)
300 return wpa_gen_wpa_ie_osen(wpa_ie, wpa_ie_len,
301 sm->pairwise_cipher,
302 sm->group_cipher,
303 sm->key_mgmt);
304 #endif /* CONFIG_HS20 */
305 else
306 return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len,
307 sm->pairwise_cipher,
308 sm->group_cipher,
309 sm->key_mgmt);
310 }
311
312
313 /**
314 * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
315 * @pos: Pointer to the IE header
316 * @end: Pointer to the end of the Key Data buffer
317 * @ie: Pointer to parsed IE data
318 * Returns: 0 on success, 1 if end mark is found, -1 on failure
319 */
320 static int wpa_parse_generic(const u8 *pos, const u8 *end,
321 struct wpa_eapol_ie_parse *ie)
322 {
323 if (pos[1] == 0)
324 return 1;
325
326 if (pos[1] >= 6 &&
327 RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
328 pos[2 + WPA_SELECTOR_LEN] == 1 &&
329 pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
330 ie->wpa_ie = pos;
331 ie->wpa_ie_len = pos[1] + 2;
332 wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key",
333 ie->wpa_ie, ie->wpa_ie_len);
334 return 0;
335 }
336
337 if (pos + 1 + RSN_SELECTOR_LEN < end &&
338 pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
339 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
340 ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
341 wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key",
342 pos, pos[1] + 2);
343 return 0;
344 }
345
346 if (pos[1] > RSN_SELECTOR_LEN + 2 &&
347 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
348 ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
349 ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
350 wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key",
351 pos, pos[1] + 2);
352 return 0;
353 }
354
355 if (pos[1] > RSN_SELECTOR_LEN + 2 &&
356 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
357 ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
358 ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
359 wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key",
360 pos, pos[1] + 2);
361 return 0;
362 }
363
364 #ifdef CONFIG_PEERKEY
365 if (pos[1] > RSN_SELECTOR_LEN + 2 &&
366 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) {
367 ie->smk = pos + 2 + RSN_SELECTOR_LEN;
368 ie->smk_len = pos[1] - RSN_SELECTOR_LEN;
369 wpa_hexdump_key(MSG_DEBUG, "WPA: SMK in EAPOL-Key",
370 pos, pos[1] + 2);
371 return 0;
372 }
373
374 if (pos[1] > RSN_SELECTOR_LEN + 2 &&
375 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) {
376 ie->nonce = pos + 2 + RSN_SELECTOR_LEN;
377 ie->nonce_len = pos[1] - RSN_SELECTOR_LEN;
378 wpa_hexdump(MSG_DEBUG, "WPA: Nonce 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_LIFETIME) {
385 ie->lifetime = pos + 2 + RSN_SELECTOR_LEN;
386 ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN;
387 wpa_hexdump(MSG_DEBUG, "WPA: Lifetime 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_ERROR) {
394 ie->error = pos + 2 + RSN_SELECTOR_LEN;
395 ie->error_len = pos[1] - RSN_SELECTOR_LEN;
396 wpa_hexdump(MSG_DEBUG, "WPA: Error in EAPOL-Key",
397 pos, pos[1] + 2);
398 return 0;
399 }
400 #endif /* CONFIG_PEERKEY */
401
402 #ifdef CONFIG_IEEE80211W
403 if (pos[1] > RSN_SELECTOR_LEN + 2 &&
404 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
405 ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
406 ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
407 wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK in EAPOL-Key",
408 pos, pos[1] + 2);
409 return 0;
410 }
411 #endif /* CONFIG_IEEE80211W */
412
413 #ifdef CONFIG_P2P
414 if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
415 RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) {
416 ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN;
417 wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key",
418 ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN);
419 return 0;
420 }
421
422 if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 &&
423 RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) {
424 ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN;
425 wpa_hexdump(MSG_DEBUG,
426 "WPA: IP Address Allocation in EAPOL-Key",
427 ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN);
428 return 0;
429 }
430 #endif /* CONFIG_P2P */
431
432 return 0;
433 }
434
435
436 /**
437 * wpa_supplicant_parse_ies - Parse EAPOL-Key Key Data IEs
438 * @buf: Pointer to the Key Data buffer
439 * @len: Key Data Length
440 * @ie: Pointer to parsed IE data
441 * Returns: 0 on success, -1 on failure
442 */
443 int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
444 struct wpa_eapol_ie_parse *ie)
445 {
446 const u8 *pos, *end;
447 int ret = 0;
448
449 os_memset(ie, 0, sizeof(*ie));
450 for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) {
451 if (pos[0] == 0xdd &&
452 ((pos == buf + len - 1) || pos[1] == 0)) {
453 /* Ignore padding */
454 break;
455 }
456 if (pos + 2 + pos[1] > end) {
457 wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
458 "underflow (ie=%d len=%d pos=%d)",
459 pos[0], pos[1], (int) (pos - buf));
460 wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data",
461 buf, len);
462 ret = -1;
463 break;
464 }
465 if (*pos == WLAN_EID_RSN) {
466 ie->rsn_ie = pos;
467 ie->rsn_ie_len = pos[1] + 2;
468 wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key",
469 ie->rsn_ie, ie->rsn_ie_len);
470 } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
471 ie->mdie = pos;
472 ie->mdie_len = pos[1] + 2;
473 wpa_hexdump(MSG_DEBUG, "WPA: MDIE in EAPOL-Key",
474 ie->mdie, ie->mdie_len);
475 } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) {
476 ie->ftie = pos;
477 ie->ftie_len = pos[1] + 2;
478 wpa_hexdump(MSG_DEBUG, "WPA: FTIE in EAPOL-Key",
479 ie->ftie, ie->ftie_len);
480 } else if (*pos == WLAN_EID_TIMEOUT_INTERVAL && pos[1] >= 5) {
481 if (pos[2] == WLAN_TIMEOUT_REASSOC_DEADLINE) {
482 ie->reassoc_deadline = pos;
483 wpa_hexdump(MSG_DEBUG, "WPA: Reassoc Deadline "
484 "in EAPOL-Key",
485 ie->reassoc_deadline, pos[1] + 2);
486 } else if (pos[2] == WLAN_TIMEOUT_KEY_LIFETIME) {
487 ie->key_lifetime = pos;
488 wpa_hexdump(MSG_DEBUG, "WPA: KeyLifetime "
489 "in EAPOL-Key",
490 ie->key_lifetime, pos[1] + 2);
491 } else {
492 wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized "
493 "EAPOL-Key Key Data IE",
494 pos, 2 + pos[1]);
495 }
496 } else if (*pos == WLAN_EID_LINK_ID) {
497 if (pos[1] >= 18) {
498 ie->lnkid = pos;
499 ie->lnkid_len = pos[1] + 2;
500 }
501 } else if (*pos == WLAN_EID_EXT_CAPAB) {
502 ie->ext_capab = pos;
503 ie->ext_capab_len = pos[1] + 2;
504 } else if (*pos == WLAN_EID_SUPP_RATES) {
505 ie->supp_rates = pos;
506 ie->supp_rates_len = pos[1] + 2;
507 } else if (*pos == WLAN_EID_EXT_SUPP_RATES) {
508 ie->ext_supp_rates = pos;
509 ie->ext_supp_rates_len = pos[1] + 2;
510 } else if (*pos == WLAN_EID_HT_CAP) {
511 ie->ht_capabilities = pos + 2;
512 ie->ht_capabilities_len = pos[1];
513 } else if (*pos == WLAN_EID_VHT_AID) {
514 if (pos[1] >= 2)
515 ie->aid = WPA_GET_LE16(pos + 2);
516 } else if (*pos == WLAN_EID_VHT_CAP) {
517 ie->vht_capabilities = pos + 2;
518 ie->vht_capabilities_len = pos[1];
519 } else if (*pos == WLAN_EID_QOS && pos[1] >= 1) {
520 ie->qosinfo = pos[2];
521 } else if (*pos == WLAN_EID_SUPPORTED_CHANNELS) {
522 ie->supp_channels = pos + 2;
523 ie->supp_channels_len = pos[1];
524 } else if (*pos == WLAN_EID_SUPPORTED_OPERATING_CLASSES) {
525 /*
526 * The value of the Length field of the Supported
527 * Operating Classes element is between 2 and 253.
528 * Silently skip invalid elements to avoid interop
529 * issues when trying to use the value.
530 */
531 if (pos[1] >= 2 && pos[1] <= 253) {
532 ie->supp_oper_classes = pos + 2;
533 ie->supp_oper_classes_len = pos[1];
534 }
535 } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
536 ret = wpa_parse_generic(pos, end, ie);
537 if (ret < 0)
538 break;
539 if (ret > 0) {
540 ret = 0;
541 break;
542 }
543 } else {
544 wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
545 "Key Data IE", pos, 2 + pos[1]);
546 }
547 }
548
549 return ret;
550 }