Home | History | Annotate | Download | only in rsn_supp
      1 /*
      2  * wpa_supplicant - WPA/RSN IE and KDE processing
      3  * Copyright (c) 2003-2008, Jouni Malinen <j (at) 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) & 0x3fff;
    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 }
    596