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 program is free software; you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License version 2 as
      7  * published by the Free Software Foundation.
      8  *
      9  * Alternatively, this software may be distributed under the terms of BSD
     10  * license.
     11  *
     12  * See README and COPYING for more details.
     13  */
     14 
     15 #include "includes.h"
     16 
     17 #include "common.h"
     18 #include "wpa.h"
     19 #include "pmksa_cache.h"
     20 #include "ieee802_11_defs.h"
     21 #include "wpa_i.h"
     22 #include "wpa_ie.h"
     23 
     24 
     25 static int wpa_selector_to_bitfield(const u8 *s)
     26 {
     27 	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE)
     28 		return WPA_CIPHER_NONE;
     29 	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP40)
     30 		return WPA_CIPHER_WEP40;
     31 	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP)
     32 		return WPA_CIPHER_TKIP;
     33 	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP)
     34 		return WPA_CIPHER_CCMP;
     35 	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP104)
     36 		return WPA_CIPHER_WEP104;
     37 	return 0;
     38 }
     39 
     40 
     41 static int wpa_key_mgmt_to_bitfield(const u8 *s)
     42 {
     43 	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_UNSPEC_802_1X)
     44 		return WPA_KEY_MGMT_IEEE8021X;
     45 	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X)
     46 		return WPA_KEY_MGMT_PSK;
     47 	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_NONE)
     48 		return WPA_KEY_MGMT_WPA_NONE;
     49 	return 0;
     50 }
     51 
     52 
     53 static int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
     54 				struct wpa_ie_data *data)
     55 {
     56 	const struct wpa_ie_hdr *hdr;
     57 	const u8 *pos;
     58 	int left;
     59 	int i, count;
     60 
     61 	os_memset(data, 0, sizeof(*data));
     62 	data->proto = WPA_PROTO_WPA;
     63 	data->pairwise_cipher = WPA_CIPHER_TKIP;
     64 	data->group_cipher = WPA_CIPHER_TKIP;
     65 	data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
     66 	data->capabilities = 0;
     67 	data->pmkid = NULL;
     68 	data->num_pmkid = 0;
     69 	data->mgmt_group_cipher = 0;
     70 
     71 	if (wpa_ie_len == 0) {
     72 		/* No WPA IE - fail silently */
     73 		return -1;
     74 	}
     75 
     76 	if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) {
     77 		wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
     78 			   __func__, (unsigned long) wpa_ie_len);
     79 		return -1;
     80 	}
     81 
     82 	hdr = (const struct wpa_ie_hdr *) wpa_ie;
     83 
     84 	if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC ||
     85 	    hdr->len != wpa_ie_len - 2 ||
     86 	    RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE ||
     87 	    WPA_GET_LE16(hdr->version) != WPA_VERSION) {
     88 		wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
     89 			   __func__);
     90 		return -1;
     91 	}
     92 
     93 	pos = (const u8 *) (hdr + 1);
     94 	left = wpa_ie_len - sizeof(*hdr);
     95 
     96 	if (left >= WPA_SELECTOR_LEN) {
     97 		data->group_cipher = wpa_selector_to_bitfield(pos);
     98 		pos += WPA_SELECTOR_LEN;
     99 		left -= WPA_SELECTOR_LEN;
    100 	} else if (left > 0) {
    101 		wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
    102 			   __func__, left);
    103 		return -1;
    104 	}
    105 
    106 	if (left >= 2) {
    107 		data->pairwise_cipher = 0;
    108 		count = WPA_GET_LE16(pos);
    109 		pos += 2;
    110 		left -= 2;
    111 		if (count == 0 || left < count * WPA_SELECTOR_LEN) {
    112 			wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
    113 				   "count %u left %u", __func__, count, left);
    114 			return -1;
    115 		}
    116 		for (i = 0; i < count; i++) {
    117 			data->pairwise_cipher |= wpa_selector_to_bitfield(pos);
    118 			pos += WPA_SELECTOR_LEN;
    119 			left -= WPA_SELECTOR_LEN;
    120 		}
    121 	} else if (left == 1) {
    122 		wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
    123 			   __func__);
    124 		return -1;
    125 	}
    126 
    127 	if (left >= 2) {
    128 		data->key_mgmt = 0;
    129 		count = WPA_GET_LE16(pos);
    130 		pos += 2;
    131 		left -= 2;
    132 		if (count == 0 || left < count * WPA_SELECTOR_LEN) {
    133 			wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
    134 				   "count %u left %u", __func__, count, left);
    135 			return -1;
    136 		}
    137 		for (i = 0; i < count; i++) {
    138 			data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos);
    139 			pos += WPA_SELECTOR_LEN;
    140 			left -= WPA_SELECTOR_LEN;
    141 		}
    142 	} else if (left == 1) {
    143 		wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
    144 			   __func__);
    145 		return -1;
    146 	}
    147 
    148 	if (left >= 2) {
    149 		data->capabilities = WPA_GET_LE16(pos);
    150 		pos += 2;
    151 		left -= 2;
    152 	}
    153 
    154 	if (left > 0) {
    155 		wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored",
    156 			   __func__, left);
    157 	}
    158 
    159 	return 0;
    160 }
    161 
    162 
    163 /**
    164  * wpa_parse_wpa_ie - Parse WPA/RSN IE
    165  * @wpa_ie: Pointer to WPA or RSN IE
    166  * @wpa_ie_len: Length of the WPA/RSN IE
    167  * @data: Pointer to data area for parsing results
    168  * Returns: 0 on success, -1 on failure
    169  *
    170  * Parse the contents of WPA or RSN IE and write the parsed data into data.
    171  */
    172 int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len,
    173 		     struct wpa_ie_data *data)
    174 {
    175 	if (wpa_ie_len >= 1 && wpa_ie[0] == WLAN_EID_RSN)
    176 		return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data);
    177 	else
    178 		return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data);
    179 }
    180 
    181 
    182 static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
    183 			      int pairwise_cipher, int group_cipher,
    184 			      int key_mgmt)
    185 {
    186 	u8 *pos;
    187 	struct wpa_ie_hdr *hdr;
    188 
    189 	if (wpa_ie_len < sizeof(*hdr) + WPA_SELECTOR_LEN +
    190 	    2 + WPA_SELECTOR_LEN + 2 + WPA_SELECTOR_LEN)
    191 		return -1;
    192 
    193 	hdr = (struct wpa_ie_hdr *) wpa_ie;
    194 	hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC;
    195 	RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE);
    196 	WPA_PUT_LE16(hdr->version, WPA_VERSION);
    197 	pos = (u8 *) (hdr + 1);
    198 
    199 	if (group_cipher == WPA_CIPHER_CCMP) {
    200 		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
    201 	} else if (group_cipher == WPA_CIPHER_TKIP) {
    202 		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
    203 	} else if (group_cipher == WPA_CIPHER_WEP104) {
    204 		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP104);
    205 	} else if (group_cipher == WPA_CIPHER_WEP40) {
    206 		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP40);
    207 	} else {
    208 		wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
    209 			   group_cipher);
    210 		return -1;
    211 	}
    212 	pos += WPA_SELECTOR_LEN;
    213 
    214 	*pos++ = 1;
    215 	*pos++ = 0;
    216 	if (pairwise_cipher == WPA_CIPHER_CCMP) {
    217 		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
    218 	} else if (pairwise_cipher == WPA_CIPHER_TKIP) {
    219 		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
    220 	} else if (pairwise_cipher == WPA_CIPHER_NONE) {
    221 		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE);
    222 	} else {
    223 		wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
    224 			   pairwise_cipher);
    225 		return -1;
    226 	}
    227 	pos += WPA_SELECTOR_LEN;
    228 
    229 	*pos++ = 1;
    230 	*pos++ = 0;
    231 	if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
    232 		RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X);
    233 	} else if (key_mgmt == WPA_KEY_MGMT_PSK) {
    234 		RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X);
    235 	} else if (key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
    236 		RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_NONE);
    237 	} else {
    238 		wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
    239 			   key_mgmt);
    240 		return -1;
    241 	}
    242 	pos += WPA_SELECTOR_LEN;
    243 
    244 	/* WPA Capabilities; use defaults, so no need to include it */
    245 
    246 	hdr->len = (pos - wpa_ie) - 2;
    247 
    248 	WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len);
    249 
    250 	return pos - wpa_ie;
    251 }
    252 
    253 
    254 static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
    255 			      int pairwise_cipher, int group_cipher,
    256 			      int key_mgmt, int mgmt_group_cipher,
    257 			      struct wpa_sm *sm)
    258 {
    259 #ifndef CONFIG_NO_WPA2
    260 	u8 *pos;
    261 	struct rsn_ie_hdr *hdr;
    262 	u16 capab;
    263 
    264 	if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN +
    265 	    2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 +
    266 	    (sm->cur_pmksa ? 2 + PMKID_LEN : 0)) {
    267 		wpa_printf(MSG_DEBUG, "RSN: Too short IE buffer (%lu bytes)",
    268 			   (unsigned long) rsn_ie_len);
    269 		return -1;
    270 	}
    271 
    272 	hdr = (struct rsn_ie_hdr *) rsn_ie;
    273 	hdr->elem_id = WLAN_EID_RSN;
    274 	WPA_PUT_LE16(hdr->version, RSN_VERSION);
    275 	pos = (u8 *) (hdr + 1);
    276 
    277 	if (group_cipher == WPA_CIPHER_CCMP) {
    278 		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
    279 	} else if (group_cipher == WPA_CIPHER_TKIP) {
    280 		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
    281 	} else if (group_cipher == WPA_CIPHER_WEP104) {
    282 		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP104);
    283 	} else if (group_cipher == WPA_CIPHER_WEP40) {
    284 		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP40);
    285 	} else {
    286 		wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
    287 			   group_cipher);
    288 		return -1;
    289 	}
    290 	pos += RSN_SELECTOR_LEN;
    291 
    292 	*pos++ = 1;
    293 	*pos++ = 0;
    294 	if (pairwise_cipher == WPA_CIPHER_CCMP) {
    295 		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
    296 	} else if (pairwise_cipher == WPA_CIPHER_TKIP) {
    297 		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
    298 	} else if (pairwise_cipher == WPA_CIPHER_NONE) {
    299 		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE);
    300 	} else {
    301 		wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
    302 			   pairwise_cipher);
    303 		return -1;
    304 	}
    305 	pos += RSN_SELECTOR_LEN;
    306 
    307 	*pos++ = 1;
    308 	*pos++ = 0;
    309 	if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
    310 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X);
    311 	} else if (key_mgmt == WPA_KEY_MGMT_PSK) {
    312 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X);
    313 #ifdef CONFIG_IEEE80211R
    314 	} else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
    315 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
    316 	} else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) {
    317 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
    318 #endif /* CONFIG_IEEE80211R */
    319 #ifdef CONFIG_IEEE80211W
    320 	} else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA256) {
    321 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
    322 	} else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) {
    323 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
    324 #endif /* CONFIG_IEEE80211W */
    325 	} else {
    326 		wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
    327 			   key_mgmt);
    328 		return -1;
    329 	}
    330 	pos += RSN_SELECTOR_LEN;
    331 
    332 	/* RSN Capabilities */
    333 	capab = 0;
    334 #ifdef CONFIG_IEEE80211W
    335 	if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC)
    336 		capab |= WPA_CAPABILITY_MFPC;
    337 #endif /* CONFIG_IEEE80211W */
    338 	WPA_PUT_LE16(pos, capab);
    339 	pos += 2;
    340 
    341 	if (sm->cur_pmksa) {
    342 		/* PMKID Count (2 octets, little endian) */
    343 		*pos++ = 1;
    344 		*pos++ = 0;
    345 		/* PMKID */
    346 		os_memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN);
    347 		pos += PMKID_LEN;
    348 	}
    349 
    350 #ifdef CONFIG_IEEE80211W
    351 	if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
    352 		if (!sm->cur_pmksa) {
    353 			/* PMKID Count */
    354 			WPA_PUT_LE16(pos, 0);
    355 			pos += 2;
    356 		}
    357 
    358 		/* Management Group Cipher Suite */
    359 		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
    360 		pos += RSN_SELECTOR_LEN;
    361 	}
    362 #endif /* CONFIG_IEEE80211W */
    363 
    364 	hdr->len = (pos - rsn_ie) - 2;
    365 
    366 	WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len);
    367 
    368 	return pos - rsn_ie;
    369 #else /* CONFIG_NO_WPA2 */
    370 	return -1;
    371 #endif /* CONFIG_NO_WPA2 */
    372 }
    373 
    374 
    375 /**
    376  * wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy
    377  * @sm: Pointer to WPA state machine data from wpa_sm_init()
    378  * @wpa_ie: Pointer to memory area for the generated WPA/RSN IE
    379  * @wpa_ie_len: Maximum length of the generated WPA/RSN IE
    380  * Returns: Length of the generated WPA/RSN IE or -1 on failure
    381  */
    382 int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len)
    383 {
    384 	if (sm->proto == WPA_PROTO_RSN)
    385 		return wpa_gen_wpa_ie_rsn(wpa_ie, wpa_ie_len,
    386 					  sm->pairwise_cipher,
    387 					  sm->group_cipher,
    388 					  sm->key_mgmt, sm->mgmt_group_cipher,
    389 					  sm);
    390 	else
    391 		return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len,
    392 					  sm->pairwise_cipher,
    393 					  sm->group_cipher,
    394 					  sm->key_mgmt);
    395 }
    396 
    397 
    398 /**
    399  * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
    400  * @pos: Pointer to the IE header
    401  * @end: Pointer to the end of the Key Data buffer
    402  * @ie: Pointer to parsed IE data
    403  * Returns: 0 on success, 1 if end mark is found, -1 on failure
    404  */
    405 static int wpa_parse_generic(const u8 *pos, const u8 *end,
    406 			     struct wpa_eapol_ie_parse *ie)
    407 {
    408 	if (pos[1] == 0)
    409 		return 1;
    410 
    411 	if (pos[1] >= 6 &&
    412 	    RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
    413 	    pos[2 + WPA_SELECTOR_LEN] == 1 &&
    414 	    pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
    415 		ie->wpa_ie = pos;
    416 		ie->wpa_ie_len = pos[1] + 2;
    417 		return 0;
    418 	}
    419 
    420 	if (pos + 1 + RSN_SELECTOR_LEN < end &&
    421 	    pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
    422 	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
    423 		ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
    424 		return 0;
    425 	}
    426 
    427 	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
    428 	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
    429 		ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
    430 		ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
    431 		return 0;
    432 	}
    433 
    434 	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
    435 	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
    436 		ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
    437 		ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
    438 		return 0;
    439 	}
    440 
    441 #ifdef CONFIG_PEERKEY
    442 	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
    443 	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) {
    444 		ie->smk = pos + 2 + RSN_SELECTOR_LEN;
    445 		ie->smk_len = pos[1] - RSN_SELECTOR_LEN;
    446 		return 0;
    447 	}
    448 
    449 	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
    450 	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) {
    451 		ie->nonce = pos + 2 + RSN_SELECTOR_LEN;
    452 		ie->nonce_len = pos[1] - RSN_SELECTOR_LEN;
    453 		return 0;
    454 	}
    455 
    456 	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
    457 	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) {
    458 		ie->lifetime = pos + 2 + RSN_SELECTOR_LEN;
    459 		ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN;
    460 		return 0;
    461 	}
    462 
    463 	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
    464 	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) {
    465 		ie->error = pos + 2 + RSN_SELECTOR_LEN;
    466 		ie->error_len = pos[1] - RSN_SELECTOR_LEN;
    467 		return 0;
    468 	}
    469 #endif /* CONFIG_PEERKEY */
    470 
    471 #ifdef CONFIG_IEEE80211W
    472 	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
    473 	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
    474 		ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
    475 		ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
    476 		return 0;
    477 	}
    478 #endif /* CONFIG_IEEE80211W */
    479 
    480 	return 0;
    481 }
    482 
    483 
    484 /**
    485  * wpa_supplicant_parse_ies - Parse EAPOL-Key Key Data IEs
    486  * @buf: Pointer to the Key Data buffer
    487  * @len: Key Data Length
    488  * @ie: Pointer to parsed IE data
    489  * Returns: 0 on success, -1 on failure
    490  */
    491 int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
    492 			     struct wpa_eapol_ie_parse *ie)
    493 {
    494 	const u8 *pos, *end;
    495 	int ret = 0;
    496 
    497 	os_memset(ie, 0, sizeof(*ie));
    498 	for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) {
    499 		if (pos[0] == 0xdd &&
    500 		    ((pos == buf + len - 1) || pos[1] == 0)) {
    501 			/* Ignore padding */
    502 			break;
    503 		}
    504 		if (pos + 2 + pos[1] > end) {
    505 			wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
    506 				   "underflow (ie=%d len=%d pos=%d)",
    507 				   pos[0], pos[1], (int) (pos - buf));
    508 			wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data",
    509 					buf, len);
    510 			ret = -1;
    511 			break;
    512 		}
    513 		if (*pos == WLAN_EID_RSN) {
    514 			ie->rsn_ie = pos;
    515 			ie->rsn_ie_len = pos[1] + 2;
    516 #ifdef CONFIG_IEEE80211R
    517 		} else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
    518 			ie->mdie = pos;
    519 			ie->mdie_len = pos[1] + 2;
    520 #endif /* CONFIG_IEEE80211R */
    521 		} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
    522 			ret = wpa_parse_generic(pos, end, ie);
    523 			if (ret < 0)
    524 				break;
    525 			if (ret > 0) {
    526 				ret = 0;
    527 				break;
    528 			}
    529 		} else {
    530 			wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
    531 				    "Key Data IE", pos, 2 + pos[1]);
    532 		}
    533 	}
    534 
    535 	return ret;
    536 }
    537