1189251Ssam/* 2189251Ssam * wpa_supplicant - WPA/RSN IE and KDE processing 3189251Ssam * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi> 4189251Ssam * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7189251Ssam */ 8189251Ssam 9189251Ssam#include "includes.h" 10189251Ssam 11189251Ssam#include "common.h" 12189251Ssam#include "wpa.h" 13189251Ssam#include "pmksa_cache.h" 14214734Srpaulo#include "common/ieee802_11_defs.h" 15189251Ssam#include "wpa_i.h" 16189251Ssam#include "wpa_ie.h" 17189251Ssam 18189251Ssam 19189251Ssam/** 20189251Ssam * wpa_parse_wpa_ie - Parse WPA/RSN IE 21189251Ssam * @wpa_ie: Pointer to WPA or RSN IE 22189251Ssam * @wpa_ie_len: Length of the WPA/RSN IE 23189251Ssam * @data: Pointer to data area for parsing results 24189251Ssam * Returns: 0 on success, -1 on failure 25189251Ssam * 26189251Ssam * Parse the contents of WPA or RSN IE and write the parsed data into data. 27189251Ssam */ 28189251Ssamint wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len, 29189251Ssam struct wpa_ie_data *data) 30189251Ssam{ 31189251Ssam if (wpa_ie_len >= 1 && wpa_ie[0] == WLAN_EID_RSN) 32189251Ssam return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data); 33189251Ssam else 34189251Ssam return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data); 35189251Ssam} 36189251Ssam 37189251Ssam 38189251Ssamstatic int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len, 39189251Ssam int pairwise_cipher, int group_cipher, 40189251Ssam int key_mgmt) 41189251Ssam{ 42189251Ssam u8 *pos; 43189251Ssam struct wpa_ie_hdr *hdr; 44252726Srpaulo u32 suite; 45189251Ssam 46189251Ssam if (wpa_ie_len < sizeof(*hdr) + WPA_SELECTOR_LEN + 47189251Ssam 2 + WPA_SELECTOR_LEN + 2 + WPA_SELECTOR_LEN) 48189251Ssam return -1; 49189251Ssam 50189251Ssam hdr = (struct wpa_ie_hdr *) wpa_ie; 51189251Ssam hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC; 52189251Ssam RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE); 53189251Ssam WPA_PUT_LE16(hdr->version, WPA_VERSION); 54189251Ssam pos = (u8 *) (hdr + 1); 55189251Ssam 56252726Srpaulo suite = wpa_cipher_to_suite(WPA_PROTO_WPA, group_cipher); 57252726Srpaulo if (suite == 0) { 58189251Ssam wpa_printf(MSG_WARNING, "Invalid group cipher (%d).", 59189251Ssam group_cipher); 60189251Ssam return -1; 61189251Ssam } 62252726Srpaulo RSN_SELECTOR_PUT(pos, suite); 63189251Ssam pos += WPA_SELECTOR_LEN; 64189251Ssam 65189251Ssam *pos++ = 1; 66189251Ssam *pos++ = 0; 67252726Srpaulo suite = wpa_cipher_to_suite(WPA_PROTO_WPA, pairwise_cipher); 68252726Srpaulo if (suite == 0 || 69252726Srpaulo (!wpa_cipher_valid_pairwise(pairwise_cipher) && 70252726Srpaulo pairwise_cipher != WPA_CIPHER_NONE)) { 71189251Ssam wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).", 72189251Ssam pairwise_cipher); 73189251Ssam return -1; 74189251Ssam } 75252726Srpaulo RSN_SELECTOR_PUT(pos, suite); 76189251Ssam pos += WPA_SELECTOR_LEN; 77189251Ssam 78189251Ssam *pos++ = 1; 79189251Ssam *pos++ = 0; 80189251Ssam if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) { 81189251Ssam RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X); 82189251Ssam } else if (key_mgmt == WPA_KEY_MGMT_PSK) { 83189251Ssam RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X); 84189251Ssam } else if (key_mgmt == WPA_KEY_MGMT_WPA_NONE) { 85189251Ssam RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_NONE); 86252726Srpaulo } else if (key_mgmt == WPA_KEY_MGMT_CCKM) { 87252726Srpaulo RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_CCKM); 88189251Ssam } else { 89189251Ssam wpa_printf(MSG_WARNING, "Invalid key management type (%d).", 90189251Ssam key_mgmt); 91189251Ssam return -1; 92189251Ssam } 93189251Ssam pos += WPA_SELECTOR_LEN; 94189251Ssam 95189251Ssam /* WPA Capabilities; use defaults, so no need to include it */ 96189251Ssam 97189251Ssam hdr->len = (pos - wpa_ie) - 2; 98189251Ssam 99189251Ssam WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len); 100189251Ssam 101189251Ssam return pos - wpa_ie; 102189251Ssam} 103189251Ssam 104189251Ssam 105189251Ssamstatic int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len, 106189251Ssam int pairwise_cipher, int group_cipher, 107189251Ssam int key_mgmt, int mgmt_group_cipher, 108189251Ssam struct wpa_sm *sm) 109189251Ssam{ 110189251Ssam#ifndef CONFIG_NO_WPA2 111189251Ssam u8 *pos; 112189251Ssam struct rsn_ie_hdr *hdr; 113189251Ssam u16 capab; 114252726Srpaulo u32 suite; 115189251Ssam 116189251Ssam if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN + 117189251Ssam 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 + 118189251Ssam (sm->cur_pmksa ? 2 + PMKID_LEN : 0)) { 119189251Ssam wpa_printf(MSG_DEBUG, "RSN: Too short IE buffer (%lu bytes)", 120189251Ssam (unsigned long) rsn_ie_len); 121189251Ssam return -1; 122189251Ssam } 123189251Ssam 124189251Ssam hdr = (struct rsn_ie_hdr *) rsn_ie; 125189251Ssam hdr->elem_id = WLAN_EID_RSN; 126189251Ssam WPA_PUT_LE16(hdr->version, RSN_VERSION); 127189251Ssam pos = (u8 *) (hdr + 1); 128189251Ssam 129252726Srpaulo suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher); 130252726Srpaulo if (suite == 0) { 131189251Ssam wpa_printf(MSG_WARNING, "Invalid group cipher (%d).", 132189251Ssam group_cipher); 133189251Ssam return -1; 134189251Ssam } 135252726Srpaulo RSN_SELECTOR_PUT(pos, suite); 136189251Ssam pos += RSN_SELECTOR_LEN; 137189251Ssam 138189251Ssam *pos++ = 1; 139189251Ssam *pos++ = 0; 140252726Srpaulo suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher); 141252726Srpaulo if (suite == 0 || 142252726Srpaulo (!wpa_cipher_valid_pairwise(pairwise_cipher) && 143252726Srpaulo pairwise_cipher != WPA_CIPHER_NONE)) { 144189251Ssam wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).", 145189251Ssam pairwise_cipher); 146189251Ssam return -1; 147189251Ssam } 148252726Srpaulo RSN_SELECTOR_PUT(pos, suite); 149189251Ssam pos += RSN_SELECTOR_LEN; 150189251Ssam 151189251Ssam *pos++ = 1; 152189251Ssam *pos++ = 0; 153189251Ssam if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) { 154189251Ssam RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X); 155189251Ssam } else if (key_mgmt == WPA_KEY_MGMT_PSK) { 156189251Ssam RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X); 157252726Srpaulo } else if (key_mgmt == WPA_KEY_MGMT_CCKM) { 158252726Srpaulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_CCKM); 159189251Ssam#ifdef CONFIG_IEEE80211R 160189251Ssam } else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) { 161189251Ssam RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X); 162189251Ssam } else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) { 163189251Ssam RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK); 164189251Ssam#endif /* CONFIG_IEEE80211R */ 165189251Ssam#ifdef CONFIG_IEEE80211W 166189251Ssam } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA256) { 167189251Ssam RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256); 168189251Ssam } else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) { 169189251Ssam RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256); 170189251Ssam#endif /* CONFIG_IEEE80211W */ 171252726Srpaulo#ifdef CONFIG_SAE 172252726Srpaulo } else if (key_mgmt == WPA_KEY_MGMT_SAE) { 173252726Srpaulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE); 174252726Srpaulo } else if (key_mgmt == WPA_KEY_MGMT_FT_SAE) { 175252726Srpaulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE); 176252726Srpaulo#endif /* CONFIG_SAE */ 177189251Ssam } else { 178189251Ssam wpa_printf(MSG_WARNING, "Invalid key management type (%d).", 179189251Ssam key_mgmt); 180189251Ssam return -1; 181189251Ssam } 182189251Ssam pos += RSN_SELECTOR_LEN; 183189251Ssam 184189251Ssam /* RSN Capabilities */ 185189251Ssam capab = 0; 186189251Ssam#ifdef CONFIG_IEEE80211W 187214734Srpaulo if (sm->mfp) 188189251Ssam capab |= WPA_CAPABILITY_MFPC; 189214734Srpaulo if (sm->mfp == 2) 190214734Srpaulo capab |= WPA_CAPABILITY_MFPR; 191189251Ssam#endif /* CONFIG_IEEE80211W */ 192189251Ssam WPA_PUT_LE16(pos, capab); 193189251Ssam pos += 2; 194189251Ssam 195189251Ssam if (sm->cur_pmksa) { 196189251Ssam /* PMKID Count (2 octets, little endian) */ 197189251Ssam *pos++ = 1; 198189251Ssam *pos++ = 0; 199189251Ssam /* PMKID */ 200189251Ssam os_memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN); 201189251Ssam pos += PMKID_LEN; 202189251Ssam } 203189251Ssam 204189251Ssam#ifdef CONFIG_IEEE80211W 205189251Ssam if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) { 206189251Ssam if (!sm->cur_pmksa) { 207189251Ssam /* PMKID Count */ 208189251Ssam WPA_PUT_LE16(pos, 0); 209189251Ssam pos += 2; 210189251Ssam } 211189251Ssam 212189251Ssam /* Management Group Cipher Suite */ 213189251Ssam RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); 214189251Ssam pos += RSN_SELECTOR_LEN; 215189251Ssam } 216189251Ssam#endif /* CONFIG_IEEE80211W */ 217189251Ssam 218189251Ssam hdr->len = (pos - rsn_ie) - 2; 219189251Ssam 220189251Ssam WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len); 221189251Ssam 222189251Ssam return pos - rsn_ie; 223189251Ssam#else /* CONFIG_NO_WPA2 */ 224189251Ssam return -1; 225189251Ssam#endif /* CONFIG_NO_WPA2 */ 226189251Ssam} 227189251Ssam 228189251Ssam 229189251Ssam/** 230189251Ssam * wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy 231189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init() 232189251Ssam * @wpa_ie: Pointer to memory area for the generated WPA/RSN IE 233189251Ssam * @wpa_ie_len: Maximum length of the generated WPA/RSN IE 234189251Ssam * Returns: Length of the generated WPA/RSN IE or -1 on failure 235189251Ssam */ 236189251Ssamint wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len) 237189251Ssam{ 238189251Ssam if (sm->proto == WPA_PROTO_RSN) 239189251Ssam return wpa_gen_wpa_ie_rsn(wpa_ie, wpa_ie_len, 240189251Ssam sm->pairwise_cipher, 241189251Ssam sm->group_cipher, 242189251Ssam sm->key_mgmt, sm->mgmt_group_cipher, 243189251Ssam sm); 244189251Ssam else 245189251Ssam return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len, 246189251Ssam sm->pairwise_cipher, 247189251Ssam sm->group_cipher, 248189251Ssam sm->key_mgmt); 249189251Ssam} 250189251Ssam 251189251Ssam 252189251Ssam/** 253189251Ssam * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs 254189251Ssam * @pos: Pointer to the IE header 255189251Ssam * @end: Pointer to the end of the Key Data buffer 256189251Ssam * @ie: Pointer to parsed IE data 257189251Ssam * Returns: 0 on success, 1 if end mark is found, -1 on failure 258189251Ssam */ 259189251Ssamstatic int wpa_parse_generic(const u8 *pos, const u8 *end, 260189251Ssam struct wpa_eapol_ie_parse *ie) 261189251Ssam{ 262189251Ssam if (pos[1] == 0) 263189251Ssam return 1; 264189251Ssam 265189251Ssam if (pos[1] >= 6 && 266189251Ssam RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE && 267189251Ssam pos[2 + WPA_SELECTOR_LEN] == 1 && 268189251Ssam pos[2 + WPA_SELECTOR_LEN + 1] == 0) { 269189251Ssam ie->wpa_ie = pos; 270189251Ssam ie->wpa_ie_len = pos[1] + 2; 271214734Srpaulo wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key", 272214734Srpaulo ie->wpa_ie, ie->wpa_ie_len); 273189251Ssam return 0; 274189251Ssam } 275189251Ssam 276189251Ssam if (pos + 1 + RSN_SELECTOR_LEN < end && 277189251Ssam pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN && 278189251Ssam RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) { 279189251Ssam ie->pmkid = pos + 2 + RSN_SELECTOR_LEN; 280214734Srpaulo wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key", 281214734Srpaulo pos, pos[1] + 2); 282189251Ssam return 0; 283189251Ssam } 284189251Ssam 285189251Ssam if (pos[1] > RSN_SELECTOR_LEN + 2 && 286189251Ssam RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) { 287189251Ssam ie->gtk = pos + 2 + RSN_SELECTOR_LEN; 288189251Ssam ie->gtk_len = pos[1] - RSN_SELECTOR_LEN; 289214734Srpaulo wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key", 290214734Srpaulo pos, pos[1] + 2); 291189251Ssam return 0; 292189251Ssam } 293189251Ssam 294189251Ssam if (pos[1] > RSN_SELECTOR_LEN + 2 && 295189251Ssam RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) { 296189251Ssam ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN; 297189251Ssam ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN; 298214734Srpaulo wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key", 299214734Srpaulo pos, pos[1] + 2); 300189251Ssam return 0; 301189251Ssam } 302189251Ssam 303189251Ssam#ifdef CONFIG_PEERKEY 304189251Ssam if (pos[1] > RSN_SELECTOR_LEN + 2 && 305189251Ssam RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) { 306189251Ssam ie->smk = pos + 2 + RSN_SELECTOR_LEN; 307189251Ssam ie->smk_len = pos[1] - RSN_SELECTOR_LEN; 308214734Srpaulo wpa_hexdump_key(MSG_DEBUG, "WPA: SMK in EAPOL-Key", 309214734Srpaulo pos, pos[1] + 2); 310189251Ssam return 0; 311189251Ssam } 312189251Ssam 313189251Ssam if (pos[1] > RSN_SELECTOR_LEN + 2 && 314189251Ssam RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) { 315189251Ssam ie->nonce = pos + 2 + RSN_SELECTOR_LEN; 316189251Ssam ie->nonce_len = pos[1] - RSN_SELECTOR_LEN; 317214734Srpaulo wpa_hexdump(MSG_DEBUG, "WPA: Nonce in EAPOL-Key", 318214734Srpaulo pos, pos[1] + 2); 319189251Ssam return 0; 320189251Ssam } 321189251Ssam 322189251Ssam if (pos[1] > RSN_SELECTOR_LEN + 2 && 323189251Ssam RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) { 324189251Ssam ie->lifetime = pos + 2 + RSN_SELECTOR_LEN; 325189251Ssam ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN; 326214734Srpaulo wpa_hexdump(MSG_DEBUG, "WPA: Lifetime in EAPOL-Key", 327214734Srpaulo pos, pos[1] + 2); 328189251Ssam return 0; 329189251Ssam } 330189251Ssam 331189251Ssam if (pos[1] > RSN_SELECTOR_LEN + 2 && 332189251Ssam RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) { 333189251Ssam ie->error = pos + 2 + RSN_SELECTOR_LEN; 334189251Ssam ie->error_len = pos[1] - RSN_SELECTOR_LEN; 335214734Srpaulo wpa_hexdump(MSG_DEBUG, "WPA: Error in EAPOL-Key", 336214734Srpaulo pos, pos[1] + 2); 337189251Ssam return 0; 338189251Ssam } 339189251Ssam#endif /* CONFIG_PEERKEY */ 340189251Ssam 341189251Ssam#ifdef CONFIG_IEEE80211W 342189251Ssam if (pos[1] > RSN_SELECTOR_LEN + 2 && 343189251Ssam RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) { 344189251Ssam ie->igtk = pos + 2 + RSN_SELECTOR_LEN; 345189251Ssam ie->igtk_len = pos[1] - RSN_SELECTOR_LEN; 346214734Srpaulo wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK in EAPOL-Key", 347214734Srpaulo pos, pos[1] + 2); 348189251Ssam return 0; 349189251Ssam } 350189251Ssam#endif /* CONFIG_IEEE80211W */ 351189251Ssam 352189251Ssam return 0; 353189251Ssam} 354189251Ssam 355189251Ssam 356189251Ssam/** 357189251Ssam * wpa_supplicant_parse_ies - Parse EAPOL-Key Key Data IEs 358189251Ssam * @buf: Pointer to the Key Data buffer 359189251Ssam * @len: Key Data Length 360189251Ssam * @ie: Pointer to parsed IE data 361189251Ssam * Returns: 0 on success, -1 on failure 362189251Ssam */ 363189251Ssamint wpa_supplicant_parse_ies(const u8 *buf, size_t len, 364189251Ssam struct wpa_eapol_ie_parse *ie) 365189251Ssam{ 366189251Ssam const u8 *pos, *end; 367189251Ssam int ret = 0; 368189251Ssam 369189251Ssam os_memset(ie, 0, sizeof(*ie)); 370189251Ssam for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) { 371189251Ssam if (pos[0] == 0xdd && 372189251Ssam ((pos == buf + len - 1) || pos[1] == 0)) { 373189251Ssam /* Ignore padding */ 374189251Ssam break; 375189251Ssam } 376189251Ssam if (pos + 2 + pos[1] > end) { 377189251Ssam wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data " 378189251Ssam "underflow (ie=%d len=%d pos=%d)", 379189251Ssam pos[0], pos[1], (int) (pos - buf)); 380189251Ssam wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data", 381189251Ssam buf, len); 382189251Ssam ret = -1; 383189251Ssam break; 384189251Ssam } 385189251Ssam if (*pos == WLAN_EID_RSN) { 386189251Ssam ie->rsn_ie = pos; 387189251Ssam ie->rsn_ie_len = pos[1] + 2; 388214734Srpaulo wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key", 389214734Srpaulo ie->rsn_ie, ie->rsn_ie_len); 390189251Ssam } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) { 391189251Ssam ie->mdie = pos; 392189251Ssam ie->mdie_len = pos[1] + 2; 393214734Srpaulo wpa_hexdump(MSG_DEBUG, "WPA: MDIE in EAPOL-Key", 394214734Srpaulo ie->mdie, ie->mdie_len); 395214734Srpaulo } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) { 396214734Srpaulo ie->ftie = pos; 397214734Srpaulo ie->ftie_len = pos[1] + 2; 398214734Srpaulo wpa_hexdump(MSG_DEBUG, "WPA: FTIE in EAPOL-Key", 399214734Srpaulo ie->ftie, ie->ftie_len); 400214734Srpaulo } else if (*pos == WLAN_EID_TIMEOUT_INTERVAL && pos[1] >= 5) { 401214734Srpaulo if (pos[2] == WLAN_TIMEOUT_REASSOC_DEADLINE) { 402214734Srpaulo ie->reassoc_deadline = pos; 403214734Srpaulo wpa_hexdump(MSG_DEBUG, "WPA: Reassoc Deadline " 404214734Srpaulo "in EAPOL-Key", 405214734Srpaulo ie->reassoc_deadline, pos[1] + 2); 406214734Srpaulo } else if (pos[2] == WLAN_TIMEOUT_KEY_LIFETIME) { 407214734Srpaulo ie->key_lifetime = pos; 408214734Srpaulo wpa_hexdump(MSG_DEBUG, "WPA: KeyLifetime " 409214734Srpaulo "in EAPOL-Key", 410214734Srpaulo ie->key_lifetime, pos[1] + 2); 411214734Srpaulo } else { 412214734Srpaulo wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized " 413214734Srpaulo "EAPOL-Key Key Data IE", 414214734Srpaulo pos, 2 + pos[1]); 415214734Srpaulo } 416252726Srpaulo } else if (*pos == WLAN_EID_LINK_ID) { 417252726Srpaulo if (pos[1] >= 18) { 418252726Srpaulo ie->lnkid = pos; 419252726Srpaulo ie->lnkid_len = pos[1] + 2; 420252726Srpaulo } 421252726Srpaulo } else if (*pos == WLAN_EID_EXT_CAPAB) { 422252726Srpaulo ie->ext_capab = pos; 423252726Srpaulo ie->ext_capab_len = pos[1] + 2; 424252726Srpaulo } else if (*pos == WLAN_EID_SUPP_RATES) { 425252726Srpaulo ie->supp_rates = pos; 426252726Srpaulo ie->supp_rates_len = pos[1] + 2; 427252726Srpaulo } else if (*pos == WLAN_EID_EXT_SUPP_RATES) { 428252726Srpaulo ie->ext_supp_rates = pos; 429252726Srpaulo ie->ext_supp_rates_len = pos[1] + 2; 430189251Ssam } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) { 431189251Ssam ret = wpa_parse_generic(pos, end, ie); 432189251Ssam if (ret < 0) 433189251Ssam break; 434189251Ssam if (ret > 0) { 435189251Ssam ret = 0; 436189251Ssam break; 437189251Ssam } 438189251Ssam } else { 439189251Ssam wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key " 440189251Ssam "Key Data IE", pos, 2 + pos[1]); 441189251Ssam } 442189251Ssam } 443189251Ssam 444189251Ssam return ret; 445189251Ssam} 446