]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - src/rsn_supp/wpa_ie.c
Allow management group cipher to be configured
[thirdparty/hostap.git] / src / rsn_supp / wpa_ie.c
index 84f2811b886199c7a12c0f8e90193bf79af107af..2329033ea0f4004389071ca48b4181d3337ab3cd 100644 (file)
@@ -2,14 +2,8 @@
  * wpa_supplicant - WPA/RSN IE and KDE processing
  * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "includes.h"
 #include "common.h"
 #include "wpa.h"
 #include "pmksa_cache.h"
-#include "ieee802_11_defs.h"
+#include "common/ieee802_11_defs.h"
 #include "wpa_i.h"
 #include "wpa_ie.h"
 
 
-static int wpa_selector_to_bitfield(const u8 *s)
-{
-       if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE)
-               return WPA_CIPHER_NONE;
-       if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP40)
-               return WPA_CIPHER_WEP40;
-       if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP)
-               return WPA_CIPHER_TKIP;
-       if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP)
-               return WPA_CIPHER_CCMP;
-       if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP104)
-               return WPA_CIPHER_WEP104;
-       return 0;
-}
-
-
-static int wpa_key_mgmt_to_bitfield(const u8 *s)
-{
-       if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_UNSPEC_802_1X)
-               return WPA_KEY_MGMT_IEEE8021X;
-       if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X)
-               return WPA_KEY_MGMT_PSK;
-       if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_NONE)
-               return WPA_KEY_MGMT_WPA_NONE;
-       return 0;
-}
-
-
-static int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
-                               struct wpa_ie_data *data)
-{
-       const struct wpa_ie_hdr *hdr;
-       const u8 *pos;
-       int left;
-       int i, count;
-
-       os_memset(data, 0, sizeof(*data));
-       data->proto = WPA_PROTO_WPA;
-       data->pairwise_cipher = WPA_CIPHER_TKIP;
-       data->group_cipher = WPA_CIPHER_TKIP;
-       data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
-       data->capabilities = 0;
-       data->pmkid = NULL;
-       data->num_pmkid = 0;
-       data->mgmt_group_cipher = 0;
-
-       if (wpa_ie_len == 0) {
-               /* No WPA IE - fail silently */
-               return -1;
-       }
-
-       if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) {
-               wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
-                          __func__, (unsigned long) wpa_ie_len);
-               return -1;
-       }
-
-       hdr = (const struct wpa_ie_hdr *) wpa_ie;
-
-       if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC ||
-           hdr->len != wpa_ie_len - 2 ||
-           RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE ||
-           WPA_GET_LE16(hdr->version) != WPA_VERSION) {
-               wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
-                          __func__);
-               return -1;
-       }
-
-       pos = (const u8 *) (hdr + 1);
-       left = wpa_ie_len - sizeof(*hdr);
-
-       if (left >= WPA_SELECTOR_LEN) {
-               data->group_cipher = wpa_selector_to_bitfield(pos);
-               pos += WPA_SELECTOR_LEN;
-               left -= WPA_SELECTOR_LEN;
-       } else if (left > 0) {
-               wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
-                          __func__, left);
-               return -1;
-       }
-
-       if (left >= 2) {
-               data->pairwise_cipher = 0;
-               count = WPA_GET_LE16(pos);
-               pos += 2;
-               left -= 2;
-               if (count == 0 || left < count * WPA_SELECTOR_LEN) {
-                       wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
-                                  "count %u left %u", __func__, count, left);
-                       return -1;
-               }
-               for (i = 0; i < count; i++) {
-                       data->pairwise_cipher |= wpa_selector_to_bitfield(pos);
-                       pos += WPA_SELECTOR_LEN;
-                       left -= WPA_SELECTOR_LEN;
-               }
-       } else if (left == 1) {
-               wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
-                          __func__);
-               return -1;
-       }
-
-       if (left >= 2) {
-               data->key_mgmt = 0;
-               count = WPA_GET_LE16(pos);
-               pos += 2;
-               left -= 2;
-               if (count == 0 || left < count * WPA_SELECTOR_LEN) {
-                       wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
-                                  "count %u left %u", __func__, count, left);
-                       return -1;
-               }
-               for (i = 0; i < count; i++) {
-                       data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos);
-                       pos += WPA_SELECTOR_LEN;
-                       left -= WPA_SELECTOR_LEN;
-               }
-       } else if (left == 1) {
-               wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
-                          __func__);
-               return -1;
-       }
-
-       if (left >= 2) {
-               data->capabilities = WPA_GET_LE16(pos);
-               pos += 2;
-               left -= 2;
-       }
-
-       if (left > 0) {
-               wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored",
-                          __func__, left);
-       }
-
-       return 0;
-}
-
-
 /**
  * wpa_parse_wpa_ie - Parse WPA/RSN IE
  * @wpa_ie: Pointer to WPA or RSN IE
@@ -185,6 +41,7 @@ static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
 {
        u8 *pos;
        struct wpa_ie_hdr *hdr;
+       u32 suite;
 
        if (wpa_ie_len < sizeof(*hdr) + WPA_SELECTOR_LEN +
            2 + WPA_SELECTOR_LEN + 2 + WPA_SELECTOR_LEN)
@@ -196,34 +53,26 @@ static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
        WPA_PUT_LE16(hdr->version, WPA_VERSION);
        pos = (u8 *) (hdr + 1);
 
-       if (group_cipher == WPA_CIPHER_CCMP) {
-               RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
-       } else if (group_cipher == WPA_CIPHER_TKIP) {
-               RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
-       } else if (group_cipher == WPA_CIPHER_WEP104) {
-               RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP104);
-       } else if (group_cipher == WPA_CIPHER_WEP40) {
-               RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP40);
-       } else {
+       suite = wpa_cipher_to_suite(WPA_PROTO_WPA, group_cipher);
+       if (suite == 0) {
                wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
                           group_cipher);
                return -1;
        }
+       RSN_SELECTOR_PUT(pos, suite);
        pos += WPA_SELECTOR_LEN;
 
        *pos++ = 1;
        *pos++ = 0;
-       if (pairwise_cipher == WPA_CIPHER_CCMP) {
-               RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
-       } else if (pairwise_cipher == WPA_CIPHER_TKIP) {
-               RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
-       } else if (pairwise_cipher == WPA_CIPHER_NONE) {
-               RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE);
-       } else {
+       suite = wpa_cipher_to_suite(WPA_PROTO_WPA, pairwise_cipher);
+       if (suite == 0 ||
+           (!wpa_cipher_valid_pairwise(pairwise_cipher) &&
+            pairwise_cipher != WPA_CIPHER_NONE)) {
                wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
                           pairwise_cipher);
                return -1;
        }
+       RSN_SELECTOR_PUT(pos, suite);
        pos += WPA_SELECTOR_LEN;
 
        *pos++ = 1;
@@ -234,6 +83,8 @@ static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
                RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X);
        } else if (key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
                RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_NONE);
+       } else if (key_mgmt == WPA_KEY_MGMT_CCKM) {
+               RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_CCKM);
        } else {
                wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
                           key_mgmt);
@@ -256,10 +107,10 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
                              int key_mgmt, int mgmt_group_cipher,
                              struct wpa_sm *sm)
 {
-#ifndef CONFIG_NO_WPA2
        u8 *pos;
        struct rsn_ie_hdr *hdr;
        u16 capab;
+       u32 suite;
 
        if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN +
            2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 +
@@ -274,34 +125,26 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
        WPA_PUT_LE16(hdr->version, RSN_VERSION);
        pos = (u8 *) (hdr + 1);
 
-       if (group_cipher == WPA_CIPHER_CCMP) {
-               RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
-       } else if (group_cipher == WPA_CIPHER_TKIP) {
-               RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
-       } else if (group_cipher == WPA_CIPHER_WEP104) {
-               RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP104);
-       } else if (group_cipher == WPA_CIPHER_WEP40) {
-               RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP40);
-       } else {
+       suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher);
+       if (suite == 0) {
                wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
                           group_cipher);
                return -1;
        }
+       RSN_SELECTOR_PUT(pos, suite);
        pos += RSN_SELECTOR_LEN;
 
        *pos++ = 1;
        *pos++ = 0;
-       if (pairwise_cipher == WPA_CIPHER_CCMP) {
-               RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
-       } else if (pairwise_cipher == WPA_CIPHER_TKIP) {
-               RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
-       } else if (pairwise_cipher == WPA_CIPHER_NONE) {
-               RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE);
-       } else {
+       suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher);
+       if (suite == 0 ||
+           (!wpa_cipher_valid_pairwise(pairwise_cipher) &&
+            pairwise_cipher != WPA_CIPHER_NONE)) {
                wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
                           pairwise_cipher);
                return -1;
        }
+       RSN_SELECTOR_PUT(pos, suite);
        pos += RSN_SELECTOR_LEN;
 
        *pos++ = 1;
@@ -310,6 +153,8 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
                RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X);
        } else if (key_mgmt == WPA_KEY_MGMT_PSK) {
                RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X);
+       } else if (key_mgmt == WPA_KEY_MGMT_CCKM) {
+               RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_CCKM);
 #ifdef CONFIG_IEEE80211R
        } else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
                RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
@@ -322,6 +167,12 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
        } else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) {
                RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
 #endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+       } else if (key_mgmt == WPA_KEY_MGMT_SAE) {
+               RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
+       } else if (key_mgmt == WPA_KEY_MGMT_FT_SAE) {
+               RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
+#endif /* CONFIG_SAE */
        } else {
                wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
                           key_mgmt);
@@ -332,8 +183,10 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
        /* RSN Capabilities */
        capab = 0;
 #ifdef CONFIG_IEEE80211W
-       if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC)
+       if (sm->mfp)
                capab |= WPA_CAPABILITY_MFPC;
+       if (sm->mfp == 2)
+               capab |= WPA_CAPABILITY_MFPR;
 #endif /* CONFIG_IEEE80211W */
        WPA_PUT_LE16(pos, capab);
        pos += 2;
@@ -348,7 +201,7 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
        }
 
 #ifdef CONFIG_IEEE80211W
-       if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
+       if (wpa_cipher_valid_mgmt_group(mgmt_group_cipher)) {
                if (!sm->cur_pmksa) {
                        /* PMKID Count */
                        WPA_PUT_LE16(pos, 0);
@@ -356,7 +209,8 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
                }
 
                /* Management Group Cipher Suite */
-               RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
+               RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN,
+                                                         mgmt_group_cipher));
                pos += RSN_SELECTOR_LEN;
        }
 #endif /* CONFIG_IEEE80211W */
@@ -366,12 +220,67 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
        WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len);
 
        return pos - rsn_ie;
-#else /* CONFIG_NO_WPA2 */
-       return -1;
-#endif /* CONFIG_NO_WPA2 */
 }
 
 
+#ifdef CONFIG_HS20
+static int wpa_gen_wpa_ie_osen(u8 *wpa_ie, size_t wpa_ie_len,
+                              int pairwise_cipher, int group_cipher,
+                              int key_mgmt)
+{
+       u8 *pos, *len;
+       u32 suite;
+
+       if (wpa_ie_len < 2 + 4 + RSN_SELECTOR_LEN +
+           2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN)
+               return -1;
+
+       pos = wpa_ie;
+       *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+       len = pos++; /* to be filled */
+       WPA_PUT_BE24(pos, OUI_WFA);
+       pos += 3;
+       *pos++ = HS20_OSEN_OUI_TYPE;
+
+       /* Group Data Cipher Suite */
+       suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher);
+       if (suite == 0) {
+               wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
+                          group_cipher);
+               return -1;
+       }
+       RSN_SELECTOR_PUT(pos, suite);
+       pos += RSN_SELECTOR_LEN;
+
+       /* Pairwise Cipher Suite Count and List */
+       WPA_PUT_LE16(pos, 1);
+       pos += 2;
+       suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher);
+       if (suite == 0 ||
+           (!wpa_cipher_valid_pairwise(pairwise_cipher) &&
+            pairwise_cipher != WPA_CIPHER_NONE)) {
+               wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
+                          pairwise_cipher);
+               return -1;
+       }
+       RSN_SELECTOR_PUT(pos, suite);
+       pos += RSN_SELECTOR_LEN;
+
+       /* AKM Suite Count and List */
+       WPA_PUT_LE16(pos, 1);
+       pos += 2;
+       RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN);
+       pos += RSN_SELECTOR_LEN;
+
+       *len = pos - len - 1;
+
+       WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len);
+
+       return pos - wpa_ie;
+}
+#endif /* CONFIG_HS20 */
+
+
 /**
  * wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy
  * @sm: Pointer to WPA state machine data from wpa_sm_init()
@@ -387,6 +296,13 @@ int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len)
                                          sm->group_cipher,
                                          sm->key_mgmt, sm->mgmt_group_cipher,
                                          sm);
+#ifdef CONFIG_HS20
+       else if (sm->proto == WPA_PROTO_OSEN)
+               return wpa_gen_wpa_ie_osen(wpa_ie, wpa_ie_len,
+                                          sm->pairwise_cipher,
+                                          sm->group_cipher,
+                                          sm->key_mgmt);
+#endif /* CONFIG_HS20 */
        else
                return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len,
                                          sm->pairwise_cipher,
@@ -395,6 +311,42 @@ int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len)
 }
 
 
+/**
+ * wpa_parse_vendor_specific - Parse Vendor Specific IEs
+ * @pos: Pointer to the IE header
+ * @end: Pointer to the end of the Key Data buffer
+ * @ie: Pointer to parsed IE data
+ * Returns: 0 on success, 1 if end mark is found, -1 on failure
+ */
+static int wpa_parse_vendor_specific(const u8 *pos, const u8 *end,
+                                    struct wpa_eapol_ie_parse *ie)
+{
+       unsigned int oui;
+
+       if (pos[1] < 4) {
+               wpa_printf(MSG_MSGDUMP, "Too short vendor specific IE ignored (len=%u)",
+                          pos[1]);
+               return 1;
+       }
+
+       oui = WPA_GET_BE24(&pos[2]);
+       if (oui == OUI_MICROSOFT && pos[5] == WMM_OUI_TYPE && pos[1] > 4) {
+               if (pos[6] == WMM_OUI_SUBTYPE_INFORMATION_ELEMENT) {
+                       ie->wmm = &pos[2];
+                       ie->wmm_len = pos[1];
+                       wpa_hexdump(MSG_DEBUG, "WPA: WMM IE",
+                                   ie->wmm, ie->wmm_len);
+               } else if (pos[6] == WMM_OUI_SUBTYPE_PARAMETER_ELEMENT) {
+                       ie->wmm = &pos[2];
+                       ie->wmm_len = pos[1];
+                       wpa_hexdump(MSG_DEBUG, "WPA: WMM Parameter Element",
+                                   ie->wmm, ie->wmm_len);
+               }
+       }
+       return 0;
+}
+
+
 /**
  * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
  * @pos: Pointer to the IE header
@@ -414,6 +366,8 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
            pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
                ie->wpa_ie = pos;
                ie->wpa_ie_len = pos[1] + 2;
+               wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key",
+                           ie->wpa_ie, ie->wpa_ie_len);
                return 0;
        }
 
@@ -421,6 +375,8 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
            pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
            RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
                ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
+               wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key",
+                           pos, pos[1] + 2);
                return 0;
        }
 
@@ -428,6 +384,8 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
            RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
                ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
                ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
+               wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key",
+                               pos, pos[1] + 2);
                return 0;
        }
 
@@ -435,6 +393,8 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
            RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
                ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
                ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
+               wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key",
+                           pos, pos[1] + 2);
                return 0;
        }
 
@@ -443,6 +403,8 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
            RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) {
                ie->smk = pos + 2 + RSN_SELECTOR_LEN;
                ie->smk_len = pos[1] - RSN_SELECTOR_LEN;
+               wpa_hexdump_key(MSG_DEBUG, "WPA: SMK in EAPOL-Key",
+                               pos, pos[1] + 2);
                return 0;
        }
 
@@ -450,6 +412,8 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
            RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) {
                ie->nonce = pos + 2 + RSN_SELECTOR_LEN;
                ie->nonce_len = pos[1] - RSN_SELECTOR_LEN;
+               wpa_hexdump(MSG_DEBUG, "WPA: Nonce in EAPOL-Key",
+                           pos, pos[1] + 2);
                return 0;
        }
 
@@ -457,6 +421,8 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
            RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) {
                ie->lifetime = pos + 2 + RSN_SELECTOR_LEN;
                ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN;
+               wpa_hexdump(MSG_DEBUG, "WPA: Lifetime in EAPOL-Key",
+                           pos, pos[1] + 2);
                return 0;
        }
 
@@ -464,6 +430,8 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
            RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) {
                ie->error = pos + 2 + RSN_SELECTOR_LEN;
                ie->error_len = pos[1] - RSN_SELECTOR_LEN;
+               wpa_hexdump(MSG_DEBUG, "WPA: Error in EAPOL-Key",
+                           pos, pos[1] + 2);
                return 0;
        }
 #endif /* CONFIG_PEERKEY */
@@ -473,10 +441,31 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
            RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
                ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
                ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
+               wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK in EAPOL-Key",
+                               pos, pos[1] + 2);
                return 0;
        }
 #endif /* CONFIG_IEEE80211W */
 
+#ifdef CONFIG_P2P
+       if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
+           RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) {
+               ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN;
+               wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key",
+                           ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN);
+               return 0;
+       }
+
+       if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 &&
+           RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) {
+               ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN;
+               wpa_hexdump(MSG_DEBUG,
+                           "WPA: IP Address Allocation in EAPOL-Key",
+                           ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN);
+               return 0;
+       }
+#endif /* CONFIG_P2P */
+
        return 0;
 }
 
@@ -513,11 +502,73 @@ int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
                if (*pos == WLAN_EID_RSN) {
                        ie->rsn_ie = pos;
                        ie->rsn_ie_len = pos[1] + 2;
-#ifdef CONFIG_IEEE80211R
+                       wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key",
+                                   ie->rsn_ie, ie->rsn_ie_len);
                } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
                        ie->mdie = pos;
                        ie->mdie_len = pos[1] + 2;
-#endif /* CONFIG_IEEE80211R */
+                       wpa_hexdump(MSG_DEBUG, "WPA: MDIE in EAPOL-Key",
+                                   ie->mdie, ie->mdie_len);
+               } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) {
+                       ie->ftie = pos;
+                       ie->ftie_len = pos[1] + 2;
+                       wpa_hexdump(MSG_DEBUG, "WPA: FTIE in EAPOL-Key",
+                                   ie->ftie, ie->ftie_len);
+               } else if (*pos == WLAN_EID_TIMEOUT_INTERVAL && pos[1] >= 5) {
+                       if (pos[2] == WLAN_TIMEOUT_REASSOC_DEADLINE) {
+                               ie->reassoc_deadline = pos;
+                               wpa_hexdump(MSG_DEBUG, "WPA: Reassoc Deadline "
+                                           "in EAPOL-Key",
+                                           ie->reassoc_deadline, pos[1] + 2);
+                       } else if (pos[2] == WLAN_TIMEOUT_KEY_LIFETIME) {
+                               ie->key_lifetime = pos;
+                               wpa_hexdump(MSG_DEBUG, "WPA: KeyLifetime "
+                                           "in EAPOL-Key",
+                                           ie->key_lifetime, pos[1] + 2);
+                       } else {
+                               wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized "
+                                           "EAPOL-Key Key Data IE",
+                                           pos, 2 + pos[1]);
+                       }
+               } else if (*pos == WLAN_EID_LINK_ID) {
+                       if (pos[1] >= 18) {
+                               ie->lnkid = pos;
+                               ie->lnkid_len = pos[1] + 2;
+                       }
+               } else if (*pos == WLAN_EID_EXT_CAPAB) {
+                       ie->ext_capab = pos;
+                       ie->ext_capab_len = pos[1] + 2;
+               } else if (*pos == WLAN_EID_SUPP_RATES) {
+                       ie->supp_rates = pos;
+                       ie->supp_rates_len = pos[1] + 2;
+               } else if (*pos == WLAN_EID_EXT_SUPP_RATES) {
+                       ie->ext_supp_rates = pos;
+                       ie->ext_supp_rates_len = pos[1] + 2;
+               } else if (*pos == WLAN_EID_HT_CAP) {
+                       ie->ht_capabilities = pos + 2;
+                       ie->ht_capabilities_len = pos[1];
+               } else if (*pos == WLAN_EID_VHT_AID) {
+                       if (pos[1] >= 2)
+                               ie->aid = WPA_GET_LE16(pos + 2);
+               } else if (*pos == WLAN_EID_VHT_CAP) {
+                       ie->vht_capabilities = pos + 2;
+                       ie->vht_capabilities_len = pos[1];
+               } else if (*pos == WLAN_EID_QOS && pos[1] >= 1) {
+                       ie->qosinfo = pos[2];
+               } else if (*pos == WLAN_EID_SUPPORTED_CHANNELS) {
+                       ie->supp_channels = pos + 2;
+                       ie->supp_channels_len = pos[1];
+               } else if (*pos == WLAN_EID_SUPPORTED_OPERATING_CLASSES) {
+                       /*
+                        * The value of the Length field of the Supported
+                        * Operating Classes element is between 2 and 253.
+                        * Silently skip invalid elements to avoid interop
+                        * issues when trying to use the value.
+                        */
+                       if (pos[1] >= 2 && pos[1] <= 253) {
+                               ie->supp_oper_classes = pos + 2;
+                               ie->supp_oper_classes_len = pos[1];
+                       }
                } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
                        ret = wpa_parse_generic(pos, end, ie);
                        if (ret < 0)
@@ -526,6 +577,14 @@ int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
                                ret = 0;
                                break;
                        }
+
+                       ret = wpa_parse_vendor_specific(pos, end, ie);
+                       if (ret < 0)
+                               break;
+                       if (ret > 0) {
+                               ret = 0;
+                               break;
+                       }
                } else {
                        wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
                                    "Key Data IE", pos, 2 + pos[1]);