wpa_ie.c revision 6c0da2bb83f6915d8260912362692d1a742e057b
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 */ 28int 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 38static 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 105static 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 if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B) { 177 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B); 178 } else { 179 wpa_printf(MSG_WARNING, "Invalid key management type (%d).", 180 key_mgmt); 181 return -1; 182 } 183 pos += RSN_SELECTOR_LEN; 184 185 /* RSN Capabilities */ 186 capab = 0; 187#ifdef CONFIG_IEEE80211W 188 if (sm->mfp) 189 capab |= WPA_CAPABILITY_MFPC; 190 if (sm->mfp == 2) 191 capab |= WPA_CAPABILITY_MFPR; 192#endif /* CONFIG_IEEE80211W */ 193 WPA_PUT_LE16(pos, capab); 194 pos += 2; 195 196 if (sm->cur_pmksa) { 197 /* PMKID Count (2 octets, little endian) */ 198 *pos++ = 1; 199 *pos++ = 0; 200 /* PMKID */ 201 os_memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN); 202 pos += PMKID_LEN; 203 } 204 205#ifdef CONFIG_IEEE80211W 206 if (wpa_cipher_valid_mgmt_group(mgmt_group_cipher)) { 207 if (!sm->cur_pmksa) { 208 /* PMKID Count */ 209 WPA_PUT_LE16(pos, 0); 210 pos += 2; 211 } 212 213 /* Management Group Cipher Suite */ 214 RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN, 215 mgmt_group_cipher)); 216 pos += RSN_SELECTOR_LEN; 217 } 218#endif /* CONFIG_IEEE80211W */ 219 220 hdr->len = (pos - rsn_ie) - 2; 221 222 WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len); 223 224 return pos - rsn_ie; 225} 226 227 228#ifdef CONFIG_HS20 229static int wpa_gen_wpa_ie_osen(u8 *wpa_ie, size_t wpa_ie_len, 230 int pairwise_cipher, int group_cipher, 231 int key_mgmt) 232{ 233 u8 *pos, *len; 234 u32 suite; 235 236 if (wpa_ie_len < 2 + 4 + RSN_SELECTOR_LEN + 237 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN) 238 return -1; 239 240 pos = wpa_ie; 241 *pos++ = WLAN_EID_VENDOR_SPECIFIC; 242 len = pos++; /* to be filled */ 243 WPA_PUT_BE24(pos, OUI_WFA); 244 pos += 3; 245 *pos++ = HS20_OSEN_OUI_TYPE; 246 247 /* Group Data Cipher Suite */ 248 suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher); 249 if (suite == 0) { 250 wpa_printf(MSG_WARNING, "Invalid group cipher (%d).", 251 group_cipher); 252 return -1; 253 } 254 RSN_SELECTOR_PUT(pos, suite); 255 pos += RSN_SELECTOR_LEN; 256 257 /* Pairwise Cipher Suite Count and List */ 258 WPA_PUT_LE16(pos, 1); 259 pos += 2; 260 suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher); 261 if (suite == 0 || 262 (!wpa_cipher_valid_pairwise(pairwise_cipher) && 263 pairwise_cipher != WPA_CIPHER_NONE)) { 264 wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).", 265 pairwise_cipher); 266 return -1; 267 } 268 RSN_SELECTOR_PUT(pos, suite); 269 pos += RSN_SELECTOR_LEN; 270 271 /* AKM Suite Count and List */ 272 WPA_PUT_LE16(pos, 1); 273 pos += 2; 274 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN); 275 pos += RSN_SELECTOR_LEN; 276 277 *len = pos - len - 1; 278 279 WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len); 280 281 return pos - wpa_ie; 282} 283#endif /* CONFIG_HS20 */ 284 285 286/** 287 * wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy 288 * @sm: Pointer to WPA state machine data from wpa_sm_init() 289 * @wpa_ie: Pointer to memory area for the generated WPA/RSN IE 290 * @wpa_ie_len: Maximum length of the generated WPA/RSN IE 291 * Returns: Length of the generated WPA/RSN IE or -1 on failure 292 */ 293int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len) 294{ 295 if (sm->proto == WPA_PROTO_RSN) 296 return wpa_gen_wpa_ie_rsn(wpa_ie, wpa_ie_len, 297 sm->pairwise_cipher, 298 sm->group_cipher, 299 sm->key_mgmt, sm->mgmt_group_cipher, 300 sm); 301#ifdef CONFIG_HS20 302 else if (sm->proto == WPA_PROTO_OSEN) 303 return wpa_gen_wpa_ie_osen(wpa_ie, wpa_ie_len, 304 sm->pairwise_cipher, 305 sm->group_cipher, 306 sm->key_mgmt); 307#endif /* CONFIG_HS20 */ 308 else 309 return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len, 310 sm->pairwise_cipher, 311 sm->group_cipher, 312 sm->key_mgmt); 313} 314 315 316/** 317 * wpa_parse_vendor_specific - Parse Vendor Specific IEs 318 * @pos: Pointer to the IE header 319 * @end: Pointer to the end of the Key Data buffer 320 * @ie: Pointer to parsed IE data 321 * Returns: 0 on success, 1 if end mark is found, -1 on failure 322 */ 323static int wpa_parse_vendor_specific(const u8 *pos, const u8 *end, 324 struct wpa_eapol_ie_parse *ie) 325{ 326 unsigned int oui; 327 328 if (pos[1] < 4) { 329 wpa_printf(MSG_MSGDUMP, "Too short vendor specific IE ignored (len=%u)", 330 pos[1]); 331 return 1; 332 } 333 334 oui = WPA_GET_BE24(&pos[2]); 335 if (oui == OUI_MICROSOFT && pos[5] == WMM_OUI_TYPE && pos[1] > 4) { 336 if (pos[6] == WMM_OUI_SUBTYPE_INFORMATION_ELEMENT) { 337 ie->wmm = &pos[2]; 338 ie->wmm_len = pos[1]; 339 wpa_hexdump(MSG_DEBUG, "WPA: WMM IE", 340 ie->wmm, ie->wmm_len); 341 } else if (pos[6] == WMM_OUI_SUBTYPE_PARAMETER_ELEMENT) { 342 ie->wmm = &pos[2]; 343 ie->wmm_len = pos[1]; 344 wpa_hexdump(MSG_DEBUG, "WPA: WMM Parameter Element", 345 ie->wmm, ie->wmm_len); 346 } 347 } 348 return 0; 349} 350 351 352/** 353 * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs 354 * @pos: Pointer to the IE header 355 * @end: Pointer to the end of the Key Data buffer 356 * @ie: Pointer to parsed IE data 357 * Returns: 0 on success, 1 if end mark is found, -1 on failure 358 */ 359static int wpa_parse_generic(const u8 *pos, const u8 *end, 360 struct wpa_eapol_ie_parse *ie) 361{ 362 if (pos[1] == 0) 363 return 1; 364 365 if (pos[1] >= 6 && 366 RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE && 367 pos[2 + WPA_SELECTOR_LEN] == 1 && 368 pos[2 + WPA_SELECTOR_LEN + 1] == 0) { 369 ie->wpa_ie = pos; 370 ie->wpa_ie_len = pos[1] + 2; 371 wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key", 372 ie->wpa_ie, ie->wpa_ie_len); 373 return 0; 374 } 375 376 if (pos + 1 + RSN_SELECTOR_LEN < end && 377 pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN && 378 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) { 379 ie->pmkid = pos + 2 + RSN_SELECTOR_LEN; 380 wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key", 381 pos, pos[1] + 2); 382 return 0; 383 } 384 385 if (pos[1] > RSN_SELECTOR_LEN + 2 && 386 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) { 387 ie->gtk = pos + 2 + RSN_SELECTOR_LEN; 388 ie->gtk_len = pos[1] - RSN_SELECTOR_LEN; 389 wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key", 390 pos, pos[1] + 2); 391 return 0; 392 } 393 394 if (pos[1] > RSN_SELECTOR_LEN + 2 && 395 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) { 396 ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN; 397 ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN; 398 wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key", 399 pos, pos[1] + 2); 400 return 0; 401 } 402 403#ifdef CONFIG_PEERKEY 404 if (pos[1] > RSN_SELECTOR_LEN + 2 && 405 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) { 406 ie->smk = pos + 2 + RSN_SELECTOR_LEN; 407 ie->smk_len = pos[1] - RSN_SELECTOR_LEN; 408 wpa_hexdump_key(MSG_DEBUG, "WPA: SMK in EAPOL-Key", 409 pos, pos[1] + 2); 410 return 0; 411 } 412 413 if (pos[1] > RSN_SELECTOR_LEN + 2 && 414 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) { 415 ie->nonce = pos + 2 + RSN_SELECTOR_LEN; 416 ie->nonce_len = pos[1] - RSN_SELECTOR_LEN; 417 wpa_hexdump(MSG_DEBUG, "WPA: Nonce in EAPOL-Key", 418 pos, pos[1] + 2); 419 return 0; 420 } 421 422 if (pos[1] > RSN_SELECTOR_LEN + 2 && 423 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) { 424 ie->lifetime = pos + 2 + RSN_SELECTOR_LEN; 425 ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN; 426 wpa_hexdump(MSG_DEBUG, "WPA: Lifetime in EAPOL-Key", 427 pos, pos[1] + 2); 428 return 0; 429 } 430 431 if (pos[1] > RSN_SELECTOR_LEN + 2 && 432 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) { 433 ie->error = pos + 2 + RSN_SELECTOR_LEN; 434 ie->error_len = pos[1] - RSN_SELECTOR_LEN; 435 wpa_hexdump(MSG_DEBUG, "WPA: Error in EAPOL-Key", 436 pos, pos[1] + 2); 437 return 0; 438 } 439#endif /* CONFIG_PEERKEY */ 440 441#ifdef CONFIG_IEEE80211W 442 if (pos[1] > RSN_SELECTOR_LEN + 2 && 443 RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) { 444 ie->igtk = pos + 2 + RSN_SELECTOR_LEN; 445 ie->igtk_len = pos[1] - RSN_SELECTOR_LEN; 446 wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK in EAPOL-Key", 447 pos, pos[1] + 2); 448 return 0; 449 } 450#endif /* CONFIG_IEEE80211W */ 451 452#ifdef CONFIG_P2P 453 if (pos[1] >= RSN_SELECTOR_LEN + 1 && 454 RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) { 455 ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN; 456 wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key", 457 ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN); 458 return 0; 459 } 460 461 if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 && 462 RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) { 463 ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN; 464 wpa_hexdump(MSG_DEBUG, 465 "WPA: IP Address Allocation in EAPOL-Key", 466 ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN); 467 return 0; 468 } 469#endif /* CONFIG_P2P */ 470 471 return 0; 472} 473 474 475/** 476 * wpa_supplicant_parse_ies - Parse EAPOL-Key Key Data IEs 477 * @buf: Pointer to the Key Data buffer 478 * @len: Key Data Length 479 * @ie: Pointer to parsed IE data 480 * Returns: 0 on success, -1 on failure 481 */ 482int wpa_supplicant_parse_ies(const u8 *buf, size_t len, 483 struct wpa_eapol_ie_parse *ie) 484{ 485 const u8 *pos, *end; 486 int ret = 0; 487 488 os_memset(ie, 0, sizeof(*ie)); 489 for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) { 490 if (pos[0] == 0xdd && 491 ((pos == buf + len - 1) || pos[1] == 0)) { 492 /* Ignore padding */ 493 break; 494 } 495 if (pos + 2 + pos[1] > end) { 496 wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data " 497 "underflow (ie=%d len=%d pos=%d)", 498 pos[0], pos[1], (int) (pos - buf)); 499 wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data", 500 buf, len); 501 ret = -1; 502 break; 503 } 504 if (*pos == WLAN_EID_RSN) { 505 ie->rsn_ie = pos; 506 ie->rsn_ie_len = pos[1] + 2; 507 wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key", 508 ie->rsn_ie, ie->rsn_ie_len); 509 } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) { 510 ie->mdie = pos; 511 ie->mdie_len = pos[1] + 2; 512 wpa_hexdump(MSG_DEBUG, "WPA: MDIE in EAPOL-Key", 513 ie->mdie, ie->mdie_len); 514 } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) { 515 ie->ftie = pos; 516 ie->ftie_len = pos[1] + 2; 517 wpa_hexdump(MSG_DEBUG, "WPA: FTIE in EAPOL-Key", 518 ie->ftie, ie->ftie_len); 519 } else if (*pos == WLAN_EID_TIMEOUT_INTERVAL && pos[1] >= 5) { 520 if (pos[2] == WLAN_TIMEOUT_REASSOC_DEADLINE) { 521 ie->reassoc_deadline = pos; 522 wpa_hexdump(MSG_DEBUG, "WPA: Reassoc Deadline " 523 "in EAPOL-Key", 524 ie->reassoc_deadline, pos[1] + 2); 525 } else if (pos[2] == WLAN_TIMEOUT_KEY_LIFETIME) { 526 ie->key_lifetime = pos; 527 wpa_hexdump(MSG_DEBUG, "WPA: KeyLifetime " 528 "in EAPOL-Key", 529 ie->key_lifetime, pos[1] + 2); 530 } else { 531 wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized " 532 "EAPOL-Key Key Data IE", 533 pos, 2 + pos[1]); 534 } 535 } else if (*pos == WLAN_EID_LINK_ID) { 536 if (pos[1] >= 18) { 537 ie->lnkid = pos; 538 ie->lnkid_len = pos[1] + 2; 539 } 540 } else if (*pos == WLAN_EID_EXT_CAPAB) { 541 ie->ext_capab = pos; 542 ie->ext_capab_len = pos[1] + 2; 543 } else if (*pos == WLAN_EID_SUPP_RATES) { 544 ie->supp_rates = pos; 545 ie->supp_rates_len = pos[1] + 2; 546 } else if (*pos == WLAN_EID_EXT_SUPP_RATES) { 547 ie->ext_supp_rates = pos; 548 ie->ext_supp_rates_len = pos[1] + 2; 549 } else if (*pos == WLAN_EID_HT_CAP) { 550 ie->ht_capabilities = pos + 2; 551 ie->ht_capabilities_len = pos[1]; 552 } else if (*pos == WLAN_EID_VHT_AID) { 553 if (pos[1] >= 2) 554 ie->aid = WPA_GET_LE16(pos + 2) & 0x3fff; 555 } else if (*pos == WLAN_EID_VHT_CAP) { 556 ie->vht_capabilities = pos + 2; 557 ie->vht_capabilities_len = pos[1]; 558 } else if (*pos == WLAN_EID_QOS && pos[1] >= 1) { 559 ie->qosinfo = pos[2]; 560 } else if (*pos == WLAN_EID_SUPPORTED_CHANNELS) { 561 ie->supp_channels = pos + 2; 562 ie->supp_channels_len = pos[1]; 563 } else if (*pos == WLAN_EID_SUPPORTED_OPERATING_CLASSES) { 564 /* 565 * The value of the Length field of the Supported 566 * Operating Classes element is between 2 and 253. 567 * Silently skip invalid elements to avoid interop 568 * issues when trying to use the value. 569 */ 570 if (pos[1] >= 2 && pos[1] <= 253) { 571 ie->supp_oper_classes = pos + 2; 572 ie->supp_oper_classes_len = pos[1]; 573 } 574 } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) { 575 ret = wpa_parse_generic(pos, end, ie); 576 if (ret < 0) 577 break; 578 if (ret > 0) { 579 ret = 0; 580 break; 581 } 582 583 ret = wpa_parse_vendor_specific(pos, end, ie); 584 if (ret < 0) 585 break; 586 if (ret > 0) { 587 ret = 0; 588 break; 589 } 590 } else { 591 wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key " 592 "Key Data IE", pos, 2 + pos[1]); 593 } 594 } 595 596 return ret; 597} 598