Просмотр исходного кода

Merge branch 'feature/wifi_pmk_caching' into 'master'

wifi: Add PMK caching feature for station WPA2-enterprise

Closes IDF-969

See merge request espressif/esp-idf!6156
Jiang Jiang Jian 6 лет назад
Родитель
Сommit
cb6e2fc858

+ 1 - 0
components/wpa_supplicant/CMakeLists.txt

@@ -45,6 +45,7 @@ set(srcs "port/os_xtensa.c"
     "src/esp_supplicant/esp_wpa_main.c"
     "src/esp_supplicant/esp_wpas_glue.c"
     "src/esp_supplicant/esp_wps.c"
+    "src/rsn_supp/pmksa_cache.c"
     "src/rsn_supp/wpa.c"
     "src/rsn_supp/wpa_ie.c"
     "src/tls/asn1.c"

+ 9 - 0
components/wpa_supplicant/port/include/os.h

@@ -228,6 +228,10 @@ char * ets_strdup(const char *s);
 #ifndef os_memcmp
 #define os_memcmp(s1, s2, n) memcmp((s1), (s2), (n))
 #endif
+#ifndef os_memcmp_const
+#define os_memcmp_const(s1, s2, n) memcmp((s1), (s2), (n))
+#endif
+
 
 #ifndef os_strlen
 #define os_strlen(s) strlen(s)
@@ -274,6 +278,11 @@ char * ets_strdup(const char *s);
 #endif
 #endif
 
+static inline int os_snprintf_error(size_t size, int res)
+{
+        return res < 0 || (unsigned int) res >= size;
+}
+
 /**
  * os_strlcpy - Copy a string with size bound and NUL-termination
  * @dest: Destination

+ 119 - 17
components/wpa_supplicant/src/common/defs.h

@@ -1,15 +1,9 @@
 /*
  * WPA Supplicant - Common definitions
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, 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.
  */
 
 #ifndef DEFS_H
@@ -41,43 +35,95 @@ typedef enum { FALSE = 0, TRUE = 1 } Boolean;
 #define WPA_KEY_MGMT_IEEE8021X_SHA256 BIT(7)
 #define WPA_KEY_MGMT_PSK_SHA256 BIT(8)
 #define WPA_KEY_MGMT_WPS BIT(9)
+#define WPA_KEY_MGMT_SAE BIT(10)
+#define WPA_KEY_MGMT_FT_SAE BIT(11)
+#define WPA_KEY_MGMT_WAPI_PSK BIT(12)
+#define WPA_KEY_MGMT_WAPI_CERT BIT(13)
 #define WPA_KEY_MGMT_CCKM BIT(14)
+#define WPA_KEY_MGMT_OSEN BIT(15)
+#define WPA_KEY_MGMT_IEEE8021X_SUITE_B BIT(16)
+#define WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 BIT(17)
 
 static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
 {
 	return !!(akm & (WPA_KEY_MGMT_IEEE8021X |
 			 WPA_KEY_MGMT_FT_IEEE8021X |
 			 WPA_KEY_MGMT_CCKM |
-			 WPA_KEY_MGMT_IEEE8021X_SHA256));
+			 WPA_KEY_MGMT_OSEN |
+			 WPA_KEY_MGMT_IEEE8021X_SHA256 |
+			 WPA_KEY_MGMT_IEEE8021X_SUITE_B |
+			 WPA_KEY_MGMT_IEEE8021X_SUITE_B_192));
 }
 
 static inline int wpa_key_mgmt_wpa_psk(int akm)
 {
-	return akm == WPA_KEY_MGMT_PSK ||
-		akm == WPA_KEY_MGMT_FT_PSK ||
-		akm == WPA_KEY_MGMT_PSK_SHA256;
+	return !!(akm & (WPA_KEY_MGMT_PSK |
+			 WPA_KEY_MGMT_FT_PSK |
+			 WPA_KEY_MGMT_PSK_SHA256 |
+			 WPA_KEY_MGMT_SAE |
+			 WPA_KEY_MGMT_FT_SAE));
 }
 
 static inline int wpa_key_mgmt_ft(int akm)
 {
-	return akm == WPA_KEY_MGMT_FT_PSK ||
-		akm == WPA_KEY_MGMT_FT_IEEE8021X;
+	return !!(akm & (WPA_KEY_MGMT_FT_PSK |
+			 WPA_KEY_MGMT_FT_IEEE8021X |
+			 WPA_KEY_MGMT_FT_SAE));
+}
+
+static inline int wpa_key_mgmt_sae(int akm)
+{
+	return !!(akm & (WPA_KEY_MGMT_SAE |
+			 WPA_KEY_MGMT_FT_SAE));
 }
 
 static inline int wpa_key_mgmt_sha256(int akm)
 {
-	return akm == WPA_KEY_MGMT_PSK_SHA256 ||
-		akm == WPA_KEY_MGMT_IEEE8021X_SHA256;
+	return !!(akm & (WPA_KEY_MGMT_PSK_SHA256 |
+			 WPA_KEY_MGMT_IEEE8021X_SHA256 |
+			 WPA_KEY_MGMT_OSEN |
+			 WPA_KEY_MGMT_IEEE8021X_SUITE_B));
+}
+
+static inline int wpa_key_mgmt_sha384(int akm)
+{
+	return !!(akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192);
+}
+
+static inline int wpa_key_mgmt_suite_b(int akm)
+{
+	return !!(akm & (WPA_KEY_MGMT_IEEE8021X_SUITE_B |
+			 WPA_KEY_MGMT_IEEE8021X_SUITE_B_192));
+}
+
+static inline int wpa_key_mgmt_wpa(int akm)
+{
+	return wpa_key_mgmt_wpa_ieee8021x(akm) ||
+		wpa_key_mgmt_wpa_psk(akm) ||
+		wpa_key_mgmt_sae(akm);
+}
+
+static inline int wpa_key_mgmt_wpa_any(int akm)
+{
+	return wpa_key_mgmt_wpa(akm) || (akm & WPA_KEY_MGMT_WPA_NONE);
+}
+
+static inline int wpa_key_mgmt_cckm(int akm)
+{
+	return akm == WPA_KEY_MGMT_CCKM;
 }
 
 
 #define WPA_PROTO_WPA BIT(0)
 #define WPA_PROTO_RSN BIT(1)
+#define WPA_PROTO_WAPI BIT(2)
+#define WPA_PROTO_OSEN BIT(3)
 
 #define WPA_AUTH_ALG_OPEN BIT(0)
 #define WPA_AUTH_ALG_SHARED BIT(1)
 #define WPA_AUTH_ALG_LEAP BIT(2)
 #define WPA_AUTH_ALG_FT BIT(3)
+#define WPA_AUTH_ALG_SAE BIT(4)
 
 
 enum wifi_key_alg {
@@ -147,6 +193,15 @@ enum wpa_states {
 	 */
 	WPA_DISCONNECTED,
 
+	/**
+	 * WPA_INTERFACE_DISABLED - Interface disabled
+	 *
+	 * This state is entered if the network interface is disabled, e.g.,
+	 * due to rfkill. wpa_supplicant refuses any new operations that would
+	 * use the radio until the interface has been enabled.
+	 */
+	WPA_INTERFACE_DISABLED,
+
 	/**
 	 * WPA_INACTIVE - Inactive state (wpa_supplicant disabled)
 	 *
@@ -249,6 +304,17 @@ enum wpa_states {
 #define MLME_SETPROTECTION_KEY_TYPE_GROUP 0
 #define MLME_SETPROTECTION_KEY_TYPE_PAIRWISE 1
 
+
+/**
+ * enum mfp_options - Management frame protection (IEEE 802.11w) options
+ */
+enum mfp_options {
+	NO_MGMT_FRAME_PROTECTION = 0,
+	MGMT_FRAME_PROTECTION_OPTIONAL = 1,
+	MGMT_FRAME_PROTECTION_REQUIRED = 2,
+};
+#define MGMT_FRAME_PROTECTION_DEFAULT 3
+
 /**
  * enum hostapd_hw_mode - Hardware mode
  */
@@ -257,7 +323,43 @@ enum hostapd_hw_mode {
 	HOSTAPD_MODE_IEEE80211G,
 	HOSTAPD_MODE_IEEE80211A,
 	HOSTAPD_MODE_IEEE80211AD,
+	HOSTAPD_MODE_IEEE80211ANY,
 	NUM_HOSTAPD_MODES
 };
 
+/**
+ * enum wpa_ctrl_req_type - Control interface request types
+ */
+enum wpa_ctrl_req_type {
+	WPA_CTRL_REQ_UNKNOWN,
+	WPA_CTRL_REQ_EAP_IDENTITY,
+	WPA_CTRL_REQ_EAP_PASSWORD,
+	WPA_CTRL_REQ_EAP_NEW_PASSWORD,
+	WPA_CTRL_REQ_EAP_PIN,
+	WPA_CTRL_REQ_EAP_OTP,
+	WPA_CTRL_REQ_EAP_PASSPHRASE,
+	WPA_CTRL_REQ_SIM,
+	WPA_CTRL_REQ_PSK_PASSPHRASE,
+	NUM_WPA_CTRL_REQS
+};
+
+/* Maximum number of EAP methods to store for EAP server user information */
+#define EAP_MAX_METHODS 8
+
+enum mesh_plink_state {
+	PLINK_LISTEN = 1,
+	PLINK_OPEN_SENT,
+	PLINK_OPEN_RCVD,
+	PLINK_CNF_RCVD,
+	PLINK_ESTAB,
+	PLINK_HOLDING,
+	PLINK_BLOCKED,
+};
+
+enum set_band {
+	WPA_SETBAND_AUTO,
+	WPA_SETBAND_5G,
+	WPA_SETBAND_2G
+};
+
 #endif /* DEFS_H */

+ 1 - 1
components/wpa_supplicant/src/esp_supplicant/esp_wifi_driver.h

@@ -105,7 +105,7 @@ typedef struct {
 } wifi_wpa_ie_t;
 
 struct wpa_funcs {
-    void (*wpa_sta_init)(void);
+    bool (*wpa_sta_init)(void);
     bool (*wpa_sta_deinit)(void);
     void (*wpa_sta_connect)(uint8_t *bssid);
     int (*wpa_sta_rx_eapol)(u8 *src_addr, u8 *buf, u32 len);

+ 6 - 1
components/wpa_supplicant/src/esp_supplicant/esp_wpa2.c

@@ -559,7 +559,7 @@ static int wpa2_ent_rx_eapol(u8 *src_addr, u8 *buf, u32 len, uint8_t *bssid)
 		    ret = eap_sm_rx_eapol(src_addr, buf, len, bssid);
 		    break;
 	    case IEEE802_1X_TYPE_EAPOL_KEY:
-		    ret = wpa_sm_rx_eapol(src_addr, buf, len);
+            ret = wpa_sm_rx_eapol(src_addr, buf, len);
 		    break;
 	    default:
 		wpa_printf(MSG_ERROR, "Unknown EAPOL packet type - %d\n", hdr->type);
@@ -696,6 +696,11 @@ static int wpa2_start_eapol_internal(void)
     if (!sm) {
         return ESP_FAIL;
     }
+    if (wpa_sta_is_cur_pmksa_set()) {
+        wpa_printf(MSG_DEBUG,
+                "RSN: PMKSA caching - do not send EAPOL-Start");
+        return ESP_FAIL;
+    }
 
     ret = esp_wifi_get_assoc_bssid_internal(bssid);
     if (ret != 0) {

+ 9 - 11
components/wpa_supplicant/src/esp_supplicant/esp_wpa_main.c

@@ -106,18 +106,15 @@ void  wpa_neg_complete(void)
     esp_wifi_auth_done_internal();
 }
 
-void  wpa_attach(void)
+bool  wpa_attach(void)
 {
-#ifndef IOT_SIP_MODE
-    wpa_register(NULL, wpa_sendto_wrapper,
+    bool ret = true; 
+    ret = wpa_sm_init(NULL, wpa_sendto_wrapper,
                  wpa_config_assoc_ie, wpa_install_key, wpa_get_key, wpa_deauthenticate, wpa_neg_complete);
-#else
-    u8 *payload = (u8 *)os_malloc(WPA_TX_MSG_BUFF_MAXLEN);
-    wpa_register(payload, wpa_sendto_wrapper,
-                 wpa_config_assoc_ie, wpa_install_key, wpa_get_key, wpa_deauthenticate, wpa_neg_complete);
-#endif
-
-    esp_wifi_register_tx_cb_internal(eapol_txcb, WIFI_TXCB_EAPOL_ID);
+    if(ret) {   
+        ret = (esp_wifi_register_tx_cb_internal(eapol_txcb, WIFI_TXCB_EAPOL_ID) == ESP_OK);
+    }
+    return ret;
 }
 
 uint8_t  *wpa_ap_get_wpa_ie(uint8_t *ie_len)
@@ -148,6 +145,7 @@ bool  wpa_ap_rx_eapol(void *hapd_data, void *sm_data, u8 *data, size_t data_len)
 
 bool  wpa_deattach(void)
 {
+    wpa_sm_deinit();
     return true;
 }
 
@@ -224,7 +222,7 @@ int esp_supplicant_init(void)
 
     wpa_cb->wpa_config_parse_string  = wpa_config_parse_string;
     wpa_cb->wpa_parse_wpa_ie  = wpa_parse_wpa_ie_wrapper;
-    wpa_cb->wpa_config_bss = wpa_config_bss;
+    wpa_cb->wpa_config_bss = NULL;//wpa_config_bss;
     wpa_cb->wpa_michael_mic_failure = wpa_michael_mic_failure;
 
     esp_wifi_register_wpa_cb_internal(wpa_cb);

+ 2 - 0
components/wpa_supplicant/src/esp_supplicant/esp_wpas_glue.c

@@ -18,6 +18,7 @@
 #include "utils/common.h"
 #include "common/eapol_common.h"
 #include "rsn_supp/wpa.h"
+#include "rsn_supp/pmksa_cache.h"
 
 u8   *wpa_sm_alloc_eapol(struct wpa_sm *sm, u8 type,
                          const void *data, u16 data_len,
@@ -65,6 +66,7 @@ void  wpa_sm_deauthenticate(struct wpa_sm *sm, u8 reason_code)
 
     /*only need send deauth frame when associated*/
     if (WPA_SM_STATE(sm) >= WPA_ASSOCIATED) {
+        pmksa_cache_clear_current(sm);
         sm->wpa_deauthenticate(reason_code);
     }
 }

+ 518 - 0
components/wpa_supplicant/src/rsn_supp/pmksa_cache.c

@@ -0,0 +1,518 @@
+/*
+ * WPA Supplicant - RSN PMKSA cache
+ * Copyright (c) 2004-2009, 2011-2015, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "rsn_supp/wpa.h"
+#include "rsn_supp/wpa_i.h"
+#include "common/eapol_common.h"
+#include "common/ieee802_11_defs.h"
+#include "pmksa_cache.h"
+#include "esp_timer.h"
+
+#ifdef IEEE8021X_EAPOL
+
+static const int pmksa_cache_max_entries = 10;
+static const int dot11RSNAConfigPMKLifetime = 43200;
+static const int dot11RSNAConfigPMKReauthThreshold = 70;
+
+struct rsn_pmksa_cache {
+    struct rsn_pmksa_cache_entry *pmksa; /* PMKSA cache */
+    int pmksa_count; /* number of entries in PMKSA cache */
+    struct wpa_sm *sm; /* TODO: get rid of this reference(?) */
+    esp_timer_handle_t cache_timeout_timer;
+
+    void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx,
+            enum pmksa_free_reason reason);
+    void *ctx;
+};
+
+
+static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa);
+
+
+static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
+{
+    wpa_bin_clear_free(entry, sizeof(*entry));
+}
+
+
+static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
+        struct rsn_pmksa_cache_entry *entry,
+        enum pmksa_free_reason reason)
+{
+    pmksa->pmksa_count--;
+    pmksa->free_cb(entry, pmksa->ctx, reason);
+    _pmksa_cache_free_entry(entry);
+}
+
+
+static void pmksa_cache_expire(void *eloop_ctx)
+{
+    struct rsn_pmksa_cache *pmksa = eloop_ctx;
+    int64_t now_sec = esp_timer_get_time() / 1e6;
+
+    while (pmksa->pmksa && pmksa->pmksa->expiration <= now_sec) {
+        struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
+        pmksa->pmksa = entry->next;
+        wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
+                MACSTR, MAC2STR(entry->aa));
+        pmksa_cache_free_entry(pmksa, entry, PMKSA_EXPIRE);
+    }
+
+    pmksa_cache_set_expiration(pmksa);
+}
+
+static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
+{
+    int sec;
+    int64_t now_sec = esp_timer_get_time() / 1e6;
+
+    esp_timer_stop(pmksa->cache_timeout_timer);
+    if (pmksa->pmksa == NULL)
+        return;
+    sec = pmksa->pmksa->expiration - now_sec;
+    if (sec < 0)
+        sec = 0;
+
+    esp_timer_start_once(pmksa->cache_timeout_timer, (sec + 1) * 1e6);
+}
+
+/**
+ * pmksa_cache_add - Add a PMKSA cache entry
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
+ * @pmk: The new pairwise master key
+ * @pmk_len: PMK length in bytes, usually PMK_LEN (32)
+ * @kck: Key confirmation key or %NULL if not yet derived
+ * @kck_len: KCK length in bytes
+ * @aa: Authenticator address
+ * @spa: Supplicant address
+ * @network_ctx: Network configuration context for this PMK
+ * @akmp: WPA_KEY_MGMT_* used in key derivation
+ * Returns: Pointer to the added PMKSA cache entry or %NULL on error
+ *
+ * This function create a PMKSA entry for a new PMK and adds it to the PMKSA
+ * cache. If an old entry is already in the cache for the same Authenticator,
+ * this entry will be replaced with the new entry. PMKID will be calculated
+ * based on the PMK and the driver interface is notified of the new PMKID.
+ */
+struct rsn_pmksa_cache_entry *
+pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
+        const u8 *kck, size_t kck_len,
+        const u8 *aa, const u8 *spa, void *network_ctx, int akmp)
+{
+    struct rsn_pmksa_cache_entry *entry, *pos, *prev;
+    int64_t now_sec = esp_timer_get_time() / 1e6;
+
+    if (pmk_len > PMK_LEN)
+        return NULL;
+
+    if (wpa_key_mgmt_suite_b(akmp) && !kck)
+        return NULL;
+
+    entry = os_zalloc(sizeof(*entry));
+    if (entry == NULL)
+        return NULL;
+    os_memcpy(entry->pmk, pmk, pmk_len);
+    entry->pmk_len = pmk_len;
+    rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
+            wpa_key_mgmt_sha256(akmp));
+    entry->expiration = now_sec + dot11RSNAConfigPMKLifetime;
+    entry->reauth_time = now_sec + dot11RSNAConfigPMKLifetime *
+        dot11RSNAConfigPMKReauthThreshold / 100;
+    entry->akmp = akmp;
+    os_memcpy(entry->aa, aa, ETH_ALEN);
+    entry->network_ctx = network_ctx;
+
+    /* Replace an old entry for the same Authenticator (if found) with the
+     * new entry */
+    pos = pmksa->pmksa;
+    prev = NULL;
+    while (pos) {
+        if (os_memcmp(aa, pos->aa, ETH_ALEN) == 0) {
+            if (pos->pmk_len == pmk_len &&
+                    os_memcmp_const(pos->pmk, pmk, pmk_len) == 0 &&
+                    os_memcmp_const(pos->pmkid, entry->pmkid,
+                        PMKID_LEN) == 0) {
+                wpa_printf(MSG_DEBUG, "WPA: reusing previous "
+                        "PMKSA entry");
+                os_free(entry);
+                return pos;
+            }
+            if (prev == NULL)
+                pmksa->pmksa = pos->next;
+            else
+                prev->next = pos->next;
+
+            /*
+             * If OKC is used, there may be other PMKSA cache
+             * entries based on the same PMK. These needs to be
+             * flushed so that a new entry can be created based on
+             * the new PMK. Only clear other entries if they have a
+             * matching PMK and this PMK has been used successfully
+             * with the current AP, i.e., if opportunistic flag has
+             * been cleared in wpa_supplicant_key_neg_complete().
+             */
+            wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for "
+                    "the current AP and any PMKSA cache entry "
+                    "that was based on the old PMK");
+            if (!pos->opportunistic)
+                pmksa_cache_flush(pmksa, network_ctx, pos->pmk,
+                        pos->pmk_len);
+            pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE);
+            break;
+        }
+        prev = pos;
+        pos = pos->next;
+    }
+
+    if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) {
+        /* Remove the oldest entry to make room for the new entry */
+        pos = pmksa->pmksa;
+
+        if (pos == pmksa->sm->cur_pmksa) {
+            /*
+             * Never remove the current PMKSA cache entry, since
+             * it's in use, and removing it triggers a needless
+             * deauthentication.
+             */
+            pos = pos->next;
+            pmksa->pmksa->next = pos ? pos->next : NULL;
+        } else
+            pmksa->pmksa = pos->next;
+
+        if (pos) {
+            wpa_printf(MSG_DEBUG, "RSN: removed the oldest idle "
+                    "PMKSA cache entry (for " MACSTR ") to "
+                    "make room for new one",
+                    MAC2STR(pos->aa));
+            pmksa_cache_free_entry(pmksa, pos, PMKSA_FREE);
+        }
+    }
+
+    /* Add the new entry; order by expiration time */
+    pos = pmksa->pmksa;
+    prev = NULL;
+    while (pos) {
+        if (pos->expiration > entry->expiration)
+            break;
+        prev = pos;
+        pos = pos->next;
+    }
+    if (prev == NULL) {
+        entry->next = pmksa->pmksa;
+        pmksa->pmksa = entry;
+        pmksa_cache_set_expiration(pmksa);
+    } else {
+        entry->next = prev->next;
+        prev->next = entry;
+    }
+    pmksa->pmksa_count++;
+    wpa_printf(MSG_DEBUG, "RSN: Added PMKSA cache entry for " MACSTR
+            " network_ctx=%p", MAC2STR(entry->aa), network_ctx);
+
+    return entry;
+}
+
+
+/**
+ * pmksa_cache_flush - Flush PMKSA cache entries for a specific network
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
+ * @network_ctx: Network configuration context or %NULL to flush all entries
+ * @pmk: PMK to match for or %NYLL to match all PMKs
+ * @pmk_len: PMK length
+ */
+void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx,
+        const u8 *pmk, size_t pmk_len)
+{
+    struct rsn_pmksa_cache_entry *entry, *prev = NULL, *tmp;
+    int removed = 0;
+
+    entry = pmksa->pmksa;
+    while (entry) {
+        if ((entry->network_ctx == network_ctx ||
+                    network_ctx == NULL) &&
+                (pmk == NULL ||
+                 (pmk_len == entry->pmk_len &&
+                  os_memcmp(pmk, entry->pmk, pmk_len) == 0))) {
+            wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry "
+                    "for " MACSTR, MAC2STR(entry->aa));
+            if (prev)
+                prev->next = entry->next;
+            else
+                pmksa->pmksa = entry->next;
+            tmp = entry;
+            entry = entry->next;
+            pmksa_cache_free_entry(pmksa, tmp, PMKSA_FREE);
+            removed++;
+        } else {
+            prev = entry;
+            entry = entry->next;
+        }
+    }
+    /*if (removed)
+      pmksa_cache_set_expiration(pmksa);*/
+}
+
+
+/**
+ * pmksa_cache_deinit - Free all entries in PMKSA cache
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
+ */
+void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa)
+{
+    struct rsn_pmksa_cache_entry *entry, *prev;
+
+    if (pmksa == NULL)
+        return;
+
+    entry = pmksa->pmksa;
+    pmksa->pmksa = NULL;
+    while (entry) {
+        prev = entry;
+        entry = entry->next;
+        os_free(prev);
+    }
+    pmksa_cache_set_expiration(pmksa);
+    os_free(pmksa);
+    esp_timer_stop(pmksa->cache_timeout_timer);
+}
+
+
+/**
+ * pmksa_cache_get - Fetch a PMKSA cache entry
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
+ * @aa: Authenticator address or %NULL to match any
+ * @pmkid: PMKID or %NULL to match any
+ * @network_ctx: Network context or %NULL to match any
+ * Returns: Pointer to PMKSA cache entry or %NULL if no match was found
+ */
+struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
+        const u8 *aa, const u8 *pmkid,
+        const void *network_ctx)
+{
+    struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
+    while (entry) {
+        if ((aa == NULL || os_memcmp(entry->aa, aa, ETH_ALEN) == 0) &&
+                (pmkid == NULL ||
+                 os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0) &&
+                (network_ctx == NULL || network_ctx == entry->network_ctx))
+            return entry;
+        entry = entry->next;
+    }
+    return NULL;
+}
+
+
+static struct rsn_pmksa_cache_entry *
+pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa,
+        const struct rsn_pmksa_cache_entry *old_entry,
+        const u8 *aa)
+{
+    struct rsn_pmksa_cache_entry *new_entry;
+
+    new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len,
+            NULL, 0,
+            aa, pmksa->sm->own_addr,
+            old_entry->network_ctx, old_entry->akmp);
+    if (new_entry == NULL)
+        return NULL;
+
+    /* TODO: reorder entries based on expiration time? */
+    new_entry->expiration = old_entry->expiration;
+    new_entry->opportunistic = 1;
+
+    return new_entry;
+}
+
+
+/**
+ * pmksa_cache_get_opportunistic - Try to get an opportunistic PMKSA entry
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
+ * @network_ctx: Network configuration context
+ * @aa: Authenticator address for the new AP
+ * Returns: Pointer to a new PMKSA cache entry or %NULL if not available
+ *
+ * Try to create a new PMKSA cache entry opportunistically by guessing that the
+ * new AP is sharing the same PMK as another AP that has the same SSID and has
+ * already an entry in PMKSA cache.
+ */
+struct rsn_pmksa_cache_entry *
+pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx,
+        const u8 *aa)
+{
+    struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
+
+    wpa_printf(MSG_DEBUG, "RSN: Consider " MACSTR " for OKC", MAC2STR(aa));
+    if (network_ctx == NULL)
+        return NULL;
+    while (entry) {
+        if (entry->network_ctx == network_ctx) {
+            entry = pmksa_cache_clone_entry(pmksa, entry, aa);
+            if (entry) {
+                wpa_printf(MSG_DEBUG, "RSN: added "
+                        "opportunistic PMKSA cache entry "
+                        "for " MACSTR, MAC2STR(aa));
+            }
+            return entry;
+        }
+        entry = entry->next;
+    }
+    return NULL;
+}
+
+
+/**
+ * pmksa_cache_get_current - Get the current used PMKSA entry
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * Returns: Pointer to the current PMKSA cache entry or %NULL if not available
+ */
+struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm)
+{
+    if (sm == NULL)
+        return NULL;
+    return sm->cur_pmksa;
+}
+
+
+/**
+ * pmksa_cache_clear_current - Clear the current PMKSA entry selection
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ */
+void pmksa_cache_clear_current(struct wpa_sm *sm)
+{
+    if (sm == NULL)
+        return;
+    sm->cur_pmksa = NULL;
+}
+
+
+/**
+ * pmksa_cache_set_current - Set the current PMKSA entry selection
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @pmkid: PMKID for selecting PMKSA or %NULL if not used
+ * @bssid: BSSID for PMKSA or %NULL if not used
+ * @network_ctx: Network configuration context
+ * @try_opportunistic: Whether to allow opportunistic PMKSA caching
+ * Returns: 0 if PMKSA was found or -1 if no matching entry was found
+ */
+int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
+        const u8 *bssid, void *network_ctx,
+        int try_opportunistic)
+{
+    struct rsn_pmksa_cache *pmksa = sm->pmksa;
+    wpa_printf(MSG_DEBUG, "RSN: PMKSA cache search - network_ctx=%p "
+            "try_opportunistic=%d", network_ctx, try_opportunistic);
+    if (pmkid)
+        wpa_hexdump(MSG_DEBUG, "RSN: Search for PMKID",
+                pmkid, PMKID_LEN);
+    if (bssid)
+        wpa_printf(MSG_DEBUG, "RSN: Search for BSSID " MACSTR,
+                MAC2STR(bssid));
+
+    sm->cur_pmksa = NULL;
+    if (pmkid)
+        sm->cur_pmksa = pmksa_cache_get(pmksa, NULL, pmkid,
+                network_ctx);
+    if (sm->cur_pmksa == NULL && bssid)
+        sm->cur_pmksa = pmksa_cache_get(pmksa, bssid, NULL,
+                network_ctx);
+    if (sm->cur_pmksa == NULL && try_opportunistic && bssid)
+        sm->cur_pmksa = pmksa_cache_get_opportunistic(pmksa,
+                network_ctx,
+                bssid);
+    if (sm->cur_pmksa) {
+        wpa_hexdump(MSG_DEBUG, "RSN: PMKSA cache entry found - PMKID",
+                sm->cur_pmksa->pmkid, PMKID_LEN);
+        return 0;
+    }
+    wpa_printf(MSG_DEBUG, "RSN: No PMKSA cache entry found");
+    return -1;
+}
+
+
+/**
+ * pmksa_cache_list - Dump text list of entries in PMKSA cache
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
+ * @buf: Buffer for the list
+ * @len: Length of the buffer
+ * Returns: number of bytes written to buffer
+ *
+ * This function is used to generate a text format representation of the
+ * current PMKSA cache contents for the ctrl_iface PMKSA command.
+ */
+int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len)
+{
+    int i, ret;
+    char *pos = buf;
+    struct rsn_pmksa_cache_entry *entry;
+    int64_t now_sec = esp_timer_get_time() / 1e6;
+    ret = os_snprintf(pos, buf + len - pos,
+            "Index / AA / PMKID / expiration (in seconds) / "
+            "opportunistic\n");
+    if (os_snprintf_error(buf + len - pos, ret))
+        return pos - buf;
+    pos += ret;
+    i = 0;
+    entry = pmksa->pmksa;
+    while (entry) {
+        i++;
+        ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ",
+                i, MAC2STR(entry->aa));
+        if (os_snprintf_error(buf + len - pos, ret))
+            return pos - buf;
+        pos += ret;
+        pos += wpa_snprintf_hex(pos, buf + len - pos, entry->pmkid,
+                PMKID_LEN);
+        ret = os_snprintf(pos, buf + len - pos, " %d %d\n",
+                (int) (entry->expiration - now_sec),
+                entry->opportunistic);
+        if (os_snprintf_error(buf + len - pos, ret))
+            return pos - buf;
+        pos += ret;
+        entry = entry->next;
+    }
+    return pos - buf;
+}
+
+
+/**
+ * pmksa_cache_init - Initialize PMKSA cache
+ * @free_cb: Callback function to be called when a PMKSA cache entry is freed
+ * @ctx: Context pointer for free_cb function
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * Returns: Pointer to PMKSA cache data or %NULL on failure
+ */
+struct rsn_pmksa_cache *
+pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
+            void *ctx, enum pmksa_free_reason reason),
+        void *ctx, struct wpa_sm *sm)
+{
+    struct rsn_pmksa_cache *pmksa;
+
+    pmksa = os_zalloc(sizeof(*pmksa));
+    if (pmksa) {
+        pmksa->free_cb = free_cb;
+        pmksa->ctx = ctx;
+        pmksa->sm = sm;
+        pmksa->pmksa_count = 0;
+        pmksa->pmksa = NULL;
+
+        esp_timer_create_args_t pmksa_cache_timeout_timer_create = {
+            .callback = &pmksa_cache_expire,
+            .arg = pmksa,
+            .dispatch_method = ESP_TIMER_TASK,
+            .name = "pmksa_timeout_timer"
+        };
+        esp_timer_create(&pmksa_cache_timeout_timer_create, &(pmksa->cache_timeout_timer));
+    }
+
+    return pmksa;
+}
+
+#endif /* IEEE8021X_EAPOL */

+ 134 - 0
components/wpa_supplicant/src/rsn_supp/pmksa_cache.h

@@ -0,0 +1,134 @@
+/*
+ * wpa_supplicant - WPA2/RSN PMKSA cache functions
+ * Copyright (c) 2003-2009, 2011-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef PMKSA_CACHE_H
+#define PMKSA_CACHE_H
+
+/**
+ * struct rsn_pmksa_cache_entry - PMKSA cache entry
+ */
+struct rsn_pmksa_cache_entry {
+    struct rsn_pmksa_cache_entry *next;
+    u8 pmkid[PMKID_LEN];
+    u8 pmk[PMK_LEN];
+    size_t pmk_len;
+    os_time_t expiration;
+    int akmp; /* WPA_KEY_MGMT_* */
+    u8 aa[ETH_ALEN];
+
+    os_time_t reauth_time;
+
+    /**
+     * network_ctx - Network configuration context
+     *
+     * This field is only used to match PMKSA cache entries to a specific
+     * network configuration (e.g., a specific SSID and security policy).
+     * This can be a pointer to the configuration entry, but PMKSA caching
+     * code does not dereference the value and this could be any kind of
+     * identifier.
+     */
+    void *network_ctx;
+    int opportunistic;
+};
+
+struct rsn_pmksa_cache;
+
+enum pmksa_free_reason {
+    PMKSA_FREE,
+    PMKSA_REPLACE,
+    PMKSA_EXPIRE,
+};
+
+#ifdef IEEE8021X_EAPOL
+
+struct rsn_pmksa_cache *
+pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
+            void *ctx, enum pmksa_free_reason reason),
+        void *ctx, struct wpa_sm *sm);
+void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa);
+struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
+        const u8 *aa, const u8 *pmkid,
+        const void *network_ctx);
+int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len);
+struct rsn_pmksa_cache_entry *
+pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
+        const u8 *kck, size_t kck_len,
+        const u8 *aa, const u8 *spa, void *network_ctx, int akmp);
+struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm);
+void pmksa_cache_clear_current(struct wpa_sm *sm);
+int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
+        const u8 *bssid, void *network_ctx,
+        int try_opportunistic);
+struct rsn_pmksa_cache_entry *
+pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa,
+        void *network_ctx, const u8 *aa);
+void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx,
+        const u8 *pmk, size_t pmk_len);
+
+#else /* IEEE8021X_EAPOL */
+
+    static inline struct rsn_pmksa_cache *
+pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
+            void *ctx, enum pmksa_free_reason reason),
+        void *ctx, struct wpa_sm *sm)
+{
+    return (void *) -1;
+}
+
+static inline void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa)
+{
+}
+
+    static inline struct rsn_pmksa_cache_entry *
+pmksa_cache_get(struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *pmkid,
+        const void *network_ctx)
+{
+    return NULL;
+}
+
+    static inline struct rsn_pmksa_cache_entry *
+pmksa_cache_get_current(struct wpa_sm *sm)
+{
+    return NULL;
+}
+
+static inline int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf,
+        size_t len)
+{
+    return -1;
+}
+
+    static inline struct rsn_pmksa_cache_entry *
+pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
+        const u8 *kck, size_t kck_len,
+        const u8 *aa, const u8 *spa, void *network_ctx, int akmp)
+{
+    return NULL;
+}
+
+static inline void pmksa_cache_clear_current(struct wpa_sm *sm)
+{
+}
+
+static inline int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
+        const u8 *bssid,
+        void *network_ctx,
+        int try_opportunistic)
+{
+    return -1;
+}
+
+static inline void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa,
+        void *network_ctx,
+        const u8 *pmk, size_t pmk_len)
+{
+}
+
+#endif /* IEEE8021X_EAPOL */
+
+#endif /* PMKSA_CACHE_H */

+ 271 - 8
components/wpa_supplicant/src/rsn_supp/wpa.c

@@ -16,6 +16,7 @@
 
 #include "utils/common.h"
 #include "rsn_supp/wpa.h"
+#include "rsn_supp/pmksa_cache.h"
 #include "rsn_supp/wpa_i.h"
 #include "common/eapol_common.h"
 #include "common/ieee802_11_defs.h"
@@ -45,7 +46,7 @@
 /* fix buf for tx for now */
 #define WPA_TX_MSG_BUFF_MAXLEN 200
 
-#define ASSOC_IE_LEN 24
+#define ASSOC_IE_LEN 24 + 2 + PMKID_LEN
 u8 assoc_ie_buf[ASSOC_IE_LEN+2]; 
 
 void set_assoc_ie(u8 * assoc_buf);
@@ -60,6 +61,7 @@ int wpa_sm_get_key(uint8_t *ifx, int *alg, u8 *addr, int *key_idx, u8 *key, size
 
 void wpa_set_passphrase(char * passphrase, u8 *ssid, size_t ssid_len);
 
+void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm);
 static inline enum wpa_states   wpa_sm_get_state(struct wpa_sm *sm)
 {
     return sm->wpa_state;;
@@ -226,7 +228,7 @@ void   wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
                reply->key_mic : NULL);
     wpa_sm_free_eapol(rbuf);
 }
-
+/*
 int   wpa_supplicant_get_pmk(struct wpa_sm *sm)
 {   
        if(sm->pmk_len >0) {
@@ -235,6 +237,178 @@ int   wpa_supplicant_get_pmk(struct wpa_sm *sm)
            return 1;
     }     
 }
+*/
+
+
+static void wpa_sm_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry,
+        void *ctx, enum pmksa_free_reason reason)
+{
+    struct wpa_sm *sm = ctx;
+    int deauth = 0;
+
+    wpa_printf( MSG_DEBUG, "RSN: PMKSA cache entry free_cb: "
+            MACSTR " reason=%d", MAC2STR(entry->aa), reason);
+
+    if (sm->cur_pmksa == entry) {
+        wpa_printf( MSG_DEBUG,
+                "RSN: %s current PMKSA entry",
+                reason == PMKSA_REPLACE ? "replaced" : "removed");
+        pmksa_cache_clear_current(sm);
+
+        /*
+         * If an entry is simply being replaced, there's no need to
+         * deauthenticate because it will be immediately re-added.
+         * This happens when EAP authentication is completed again
+         * (reauth or failed PMKSA caching attempt).
+         * */
+        if (reason != PMKSA_REPLACE)
+            deauth = 1;
+    }
+
+    if (reason == PMKSA_EXPIRE &&
+            (sm->pmk_len == entry->pmk_len &&
+             os_memcmp(sm->pmk, entry->pmk, sm->pmk_len) == 0)) {
+        wpa_printf( MSG_DEBUG,
+                "RSN: deauthenticating due to expired PMK");
+        pmksa_cache_clear_current(sm);
+        deauth = 1;
+    }
+
+    if (deauth) {
+        os_memset(sm->pmk, 0, sizeof(sm->pmk));
+        wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
+    }
+}
+
+
+
+
+
+static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
+        const unsigned char *src_addr,
+        const u8 *pmkid)
+{
+    int abort_cached = 0;
+
+    if (pmkid && !sm->cur_pmksa) {
+        /* When using drivers that generate RSN IE, wpa_supplicant may
+         * not have enough time to get the association information
+         * event before receiving this 1/4 message, so try to find a
+         * matching PMKSA cache entry here. */
+        sm->cur_pmksa = pmksa_cache_get(sm->pmksa, src_addr, pmkid,
+                NULL);
+        if (sm->cur_pmksa) {
+            wpa_printf(MSG_DEBUG,
+                    "RSN: found matching PMKID from PMKSA cache");
+        } else {
+            wpa_printf( MSG_DEBUG,
+                    "RSN: no matching PMKID found");
+            abort_cached = 1;
+        }
+    }
+
+    if (pmkid && sm->cur_pmksa &&
+            os_memcmp_const(pmkid, sm->cur_pmksa->pmkid, PMKID_LEN) == 0) {
+
+        wpa_hexdump(MSG_DEBUG, "RSN: matched PMKID", pmkid, PMKID_LEN);
+        wpa_sm_set_pmk_from_pmksa(sm);
+        wpa_hexdump_key(MSG_DEBUG, "RSN: PMK from PMKSA cache",
+                sm->pmk, sm->pmk_len);
+        //eapol_sm_notify_cached(sm->eapol);
+#ifdef CONFIG_IEEE80211R
+        sm->xxkey_len = 0;
+#endif /* CONFIG_IEEE80211R */
+    } else if (wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt)) {
+        int res = 0, pmk_len;
+        pmk_len = PMK_LEN;
+        /* For ESP_SUPPLICANT this is already set using wpa_set_pmk*/
+        //res = eapol_sm_get_key(sm->eapol, sm->pmk, PMK_LEN);
+
+        if(!sm->pmk_len) {
+            res = -1; 
+        }
+
+        if (res == 0) {
+            struct rsn_pmksa_cache_entry *sa = NULL;
+            wpa_hexdump_key(MSG_DEBUG, "WPA: PMK from EAPOL state "
+                    "machines", sm->pmk, pmk_len);
+            sm->pmk_len = pmk_len;
+            //wpa_supplicant_key_mgmt_set_pmk(sm);
+            if (sm->proto == WPA_PROTO_RSN &&
+                    !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
+                    !wpa_key_mgmt_ft(sm->key_mgmt)) {
+                sa = pmksa_cache_add(sm->pmksa,
+                        sm->pmk, pmk_len,
+                        NULL, 0,
+						     src_addr, sm->own_addr,
+						     sm->network_ctx,
+						     sm->key_mgmt);
+			}
+			if (!sm->cur_pmksa && pmkid &&
+			    pmksa_cache_get(sm->pmksa, src_addr, pmkid, NULL))
+			{
+				wpa_printf( MSG_DEBUG,
+					"RSN: the new PMK matches with the "
+					"PMKID");
+				abort_cached = 0;
+			} else if (sa && !sm->cur_pmksa && pmkid) {
+				/*
+				 * It looks like the authentication server
+				 * derived mismatching MSK. This should not
+				 * really happen, but bugs happen.. There is not
+				 * much we can do here without knowing what
+				 * exactly caused the server to misbehave.
+				 */
+				wpa_printf( MSG_INFO,
+					"RSN: PMKID mismatch - authentication server may have derived different MSK?!");
+				return -1;
+			}
+
+			if (!sm->cur_pmksa)
+				sm->cur_pmksa = sa;
+		} else {
+			wpa_printf( MSG_WARNING,
+				"WPA: Failed to get master session key from "
+				"EAPOL state machines - key handshake "
+				"aborted");
+			if (sm->cur_pmksa) {
+				wpa_printf( MSG_DEBUG,
+					"RSN: Cancelled PMKSA caching "
+					"attempt");
+				sm->cur_pmksa = NULL;
+				abort_cached = 1;
+			} else if (!abort_cached) {
+				return -1;
+			}
+		}
+	}
+
+	if (abort_cached && wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) &&
+	    !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
+	    !wpa_key_mgmt_ft(sm->key_mgmt) && sm->key_mgmt != WPA_KEY_MGMT_OSEN)
+	{
+		/* Send EAPOL-Start to trigger full EAP authentication. */
+		u8 *buf;
+		size_t buflen;
+
+		wpa_printf( MSG_DEBUG,
+			"RSN: no PMKSA entry found - trigger "
+			"full EAP authentication");
+		buf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_START,
+					 NULL, 0, &buflen, NULL);
+		if (buf) {
+			wpa_sm_ether_send(sm, sm->bssid, ETH_P_EAPOL,
+					  buf, buflen);
+			os_free(buf);
+			return -2;
+		}
+
+		return -1;
+	}
+
+	return 0;
+}
+
 
 /**
  * wpa_supplicant_send_2_of_4 - Send message 2 of WPA/RSN 4-Way Handshake
@@ -342,9 +516,9 @@ void   wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
         }
     }
 #endif /* CONFIG_NO_WPA2 */
-
-       res = wpa_supplicant_get_pmk(sm);
-       if (res == -2) {
+    res = wpa_supplicant_get_pmk(sm, src_addr, ie.pmkid);
+       
+    if (res == -2) {
           #ifdef DEBUG_PRINT    
          wpa_printf(MSG_DEBUG, "RSN: Do not reply to msg 1/4 - "
                "requesting full EAP authentication");
@@ -354,6 +528,8 @@ void   wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
     if (res)
         goto failed;
 
+    pmksa_cache_set_current(sm, NULL, sm->bssid, 0, 0);
+
     if (sm->renew_snonce) {
         if (os_get_random(sm->snonce, WPA_NONCE_LEN)) {
          #ifdef DEBUG_PRINT            
@@ -1699,8 +1875,65 @@ void wpa_sm_set_state(enum wpa_states state)
     sm->wpa_state= state;
 }
 
+
+/**
+ * wpa_sm_set_pmk - Set PMK
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @pmk: The new PMK
+ * @pmk_len: The length of the new PMK in bytes
+ * @bssid: AA to add into PMKSA cache or %NULL to not cache the PMK
+ *
+ * Configure the PMK for WPA state machine.
+ */
+void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
+		    const u8 *bssid)
+{
+	if (sm == NULL)
+		return;
+
+	sm->pmk_len = pmk_len;
+	os_memcpy(sm->pmk, pmk, pmk_len);
+
+#ifdef CONFIG_IEEE80211R
+	/* Set XXKey to be PSK for FT key derivation */
+	sm->xxkey_len = pmk_len;
+	os_memcpy(sm->xxkey, pmk, pmk_len);
+#endif /* CONFIG_IEEE80211R */
+
+	if (bssid) {
+		pmksa_cache_add(sm->pmksa, pmk, pmk_len, NULL, 0,
+				bssid, sm->own_addr,
+				sm->network_ctx, sm->key_mgmt);
+	}
+}
+
+
+/**
+ * wpa_sm_set_pmk_from_pmksa - Set PMK based on the current PMKSA
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ *
+ * Take the PMK from the current PMKSA into use. If no PMKSA is active, the PMK
+ * will be cleared.
+ */
+void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm)
+{
+	if (sm == NULL)
+		return;
+
+	if (sm->cur_pmksa) {
+		sm->pmk_len = sm->cur_pmksa->pmk_len;
+		os_memcpy(sm->pmk, sm->cur_pmksa->pmk, sm->pmk_len);
+	} else {
+		sm->pmk_len = PMK_LEN;
+		os_memset(sm->pmk, 0, PMK_LEN);
+	}
+}
+
+
+
+
 #ifdef ESP_SUPPLICANT
-void   wpa_register(char * payload, WPA_SEND_FUNC snd_func,
+bool wpa_sm_init(char * payload, WPA_SEND_FUNC snd_func,
                    WPA_SET_ASSOC_IE set_assoc_ie_func, WPA_INSTALL_KEY ppinstallkey, WPA_GET_KEY ppgetkey, WPA_DEAUTH_FUNC wpa_deauth,
                    WPA_NEG_COMPLETE wpa_neg_complete)
 {
@@ -1716,8 +1949,26 @@ void   wpa_register(char * payload, WPA_SEND_FUNC snd_func,
     sm->key_entry_valid = 0;
     sm->key_install = false;
     wpa_sm_set_state(WPA_INACTIVE);
+    
+    sm->pmksa = pmksa_cache_init(wpa_sm_pmksa_free_cb, sm, sm);
+    if (sm->pmksa == NULL) {
+        wpa_printf(MSG_ERROR,
+                "RSN: PMKSA cache initialization failed");
+        return false;
+    }
+    return true;
 }
 
+/** 
+ *  * wpa_sm_deinit - Deinitialize WPA state machine
+ *    */ 
+void wpa_sm_deinit(void)
+{
+    struct wpa_sm *sm = &gWpaSm;
+    pmksa_cache_deinit(sm->pmksa);
+}
+
+
 void wpa_set_profile(u32 wpa_proto, u8 auth_mode)
 {
     struct wpa_sm *sm = &gWpaSm;
@@ -1751,8 +2002,15 @@ wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher, cha
     memcpy(sm->own_addr, macddr, ETH_ALEN);
     memcpy(sm->bssid, bssid, ETH_ALEN);
     sm->ap_notify_completed_rsne = esp_wifi_sta_is_ap_notify_completed_rsne_internal();
-    
+        
+    if (esp_wifi_sta_prof_is_wpa2_internal() 
+            && esp_wifi_sta_get_prof_authmode_internal() == WPA2_AUTH_ENT) {
+        pmksa_cache_set_current(sm, NULL, (const u8*) bssid, 0, 0);
+        wpa_sm_set_pmk_from_pmksa(sm);
+    }
+
     set_assoc_ie(assoc_ie_buf); /* use static buffer */
+
     wpa_gen_wpa_ie(sm, sm->assoc_wpa_ie, sm->assoc_wpa_ie_len); //TODO: NEED TO DEBUG!!
     wpa_set_passphrase(passphrase, ssid, ssid_len);
 }
@@ -1790,8 +2048,8 @@ wpa_set_passphrase(char * passphrase, u8 *ssid, size_t ssid_len)
     /* TODO nothing */
     } else {
         memcpy(sm->pmk, esp_wifi_sta_get_ap_info_prof_pmk_internal(), PMK_LEN);
+        sm->pmk_len = PMK_LEN;
     }
-    sm->pmk_len = PMK_LEN;
 }
 
   void  
@@ -1971,5 +2229,10 @@ bool wpa_sta_in_4way_handshake(void)
     return false;
 }
 
+
+bool wpa_sta_is_cur_pmksa_set(void) {
+    struct wpa_sm *sm = &gWpaSm;
+    return (pmksa_cache_get_current(sm) != NULL);
+}
 #endif // ESP_SUPPLICANT
 

+ 1 - 0
components/wpa_supplicant/src/rsn_supp/wpa.h

@@ -34,6 +34,7 @@
 struct wpa_sm;
 
 int wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len);
+bool wpa_sta_is_cur_pmksa_set(void);
 bool wpa_sta_in_4way_handshake(void);
 
 #define WPA_ASSERT  assert

+ 11 - 6
components/wpa_supplicant/src/rsn_supp/wpa_i.h

@@ -41,11 +41,14 @@ struct wpa_sm {
     u8 rx_replay_counter[WPA_REPLAY_COUNTER_LEN];
     int rx_replay_counter_set;
     u8 request_counter[WPA_REPLAY_COUNTER_LEN];
+    struct rsn_pmksa_cache *pmksa; /* PMKSA cache */
+    struct rsn_pmksa_cache_entry *cur_pmksa; /* current PMKSA entry */
 
     unsigned int pairwise_cipher;
     unsigned int group_cipher;
     unsigned int key_mgmt;
     unsigned int mgmt_group_cipher;
+    void *network_ctx;
 
     int rsn_enabled; /* Whether RSN is enabled in configuration */
 
@@ -147,12 +150,14 @@ typedef void (*WPA_DEAUTH_FUNC)(u8 reason_code);
 
 typedef void (*WPA_NEG_COMPLETE)(void);
 
-void wpa_register(char * payload, WPA_SEND_FUNC snd_func, \
-                                                      WPA_SET_ASSOC_IE set_assoc_ie_func, \
-                                                      WPA_INSTALL_KEY ppinstallkey, \
-                                                      WPA_GET_KEY ppgetkey, \
-                                                      WPA_DEAUTH_FUNC wpa_deauth, \
-                                                      WPA_NEG_COMPLETE wpa_neg_complete);
+bool wpa_sm_init(char * payload, WPA_SEND_FUNC snd_func, \
+        WPA_SET_ASSOC_IE set_assoc_ie_func, \
+        WPA_INSTALL_KEY ppinstallkey, \
+        WPA_GET_KEY ppgetkey, \
+        WPA_DEAUTH_FUNC wpa_deauth, \
+        WPA_NEG_COMPLETE wpa_neg_complete);
+
+void wpa_sm_deinit(void);
 
 void eapol_txcb(void *eb);
 

+ 127 - 107
components/wpa_supplicant/src/rsn_supp/wpa_ie.c

@@ -19,6 +19,7 @@
 #include "rsn_supp/wpa.h"
 #include "common/ieee802_11_defs.h"
 #include "rsn_supp/wpa_ie.h"
+#include "rsn_supp/pmksa_cache.h"
 
 /**
  * wpa_parse_wpa_ie - Parse WPA/RSN IE
@@ -38,113 +39,6 @@ int  wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len,
 		return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data);
 }
 
-/**
- * wpa_parse_generic - Parse EAPOL-Key Key Data Generic 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_generic(const u8 *pos, const u8 *end,
-			     struct wpa_eapol_ie_parse *ie)
-{
-	if (pos[1] == 0)
-		return 1;
-
-	if (pos[1] >= 6 &&
-	    RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
-	    pos[2 + WPA_SELECTOR_LEN] == 1 &&
-	    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;
-	}
-
-	if (pos + 1 + RSN_SELECTOR_LEN < 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;
-	}
-
-	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
-	    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(MSG_DEBUG, "WPA: GTK in EAPOL-Key",
-				pos, pos[1] + 2);
-		return 0;
-	}
-
-	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
-	    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;
-	}
-	return 0;
-}
-
-
-/**
- * wpa_supplicant_parse_ies - Parse EAPOL-Key Key Data IEs
- * @buf: Pointer to the Key Data buffer
- * @len: Key Data Length
- * @ie: Pointer to parsed IE data
- * Returns: 0 on success, -1 on failure
- */
-int  wpa_supplicant_parse_ies(const u8 *buf, size_t len,
-			     struct wpa_eapol_ie_parse *ie)
-{
-	const u8 *pos, *end;
-	int ret = 0;
-
-	memset(ie, 0, sizeof(*ie));
-	for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) {
-		if (pos[0] == 0xdd &&
-		    ((pos == buf + len - 1) || pos[1] == 0)) {
-			/* Ignore padding */
-			break;
-		}
-		if (pos + 2 + pos[1] > end) {
-		    #ifdef DEBUG_PRINT	
-			wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
-				   "underflow (ie=%d len=%d pos=%d)",
-				   pos[0], pos[1], (int) (pos - buf));
-		    #endif	
-			wpa_hexdump(MSG_DEBUG, "WPA: Key Data",
-					buf, len);
-			ret = -1;
-			break;
-		}
-		if (*pos == WLAN_EID_RSN) {
-			ie->rsn_ie = pos;
-			ie->rsn_ie_len = pos[1] + 2;
-			wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key",
-				    ie->rsn_ie, ie->rsn_ie_len);
-		} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
-			ret = wpa_parse_generic(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]);
-		}
-	}
-
-	return ret;
-}
-
 
 static int  wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
                   int pairwise_cipher, int group_cipher,
@@ -229,6 +123,13 @@ static int  wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
     u16 capab;
     u8 min_len = 0;
 
+    if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN +
+            2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 +
+            (sm->cur_pmksa ? 2 + PMKID_LEN : 0)) {
+        wpa_printf(MSG_DEBUG, "RSN: Too short IE buffer (%lu bytes)",
+                (unsigned long) rsn_ie_len);
+        return -1;
+    }
 
     /* For WPA2-PSK, if the RSNE in AP beacon/probe response doesn't specify the 
      * pairwise cipher or AKM suite, the RSNE IE in association request
@@ -321,6 +222,15 @@ static int  wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
     WPA_PUT_LE16(pos, capab);
     pos += 2;
 
+    if (sm->cur_pmksa) {
+        /* PMKID Count (2 octets, little endian) */
+        *pos++ = 1;
+        *pos++ = 0;
+        /* PMKID */
+        os_memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN);
+        pos += PMKID_LEN;
+    }
+
 #ifdef CONFIG_IEEE80211W
     if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
         if (!sm->cur_pmksa) {
@@ -367,5 +277,115 @@ int  wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len)
                       sm->group_cipher,
                       sm->key_mgmt);
 }
+
+
+/**
+ * wpa_parse_generic - Parse EAPOL-Key Key Data Generic 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_generic(const u8 *pos, const u8 *end,
+			     struct wpa_eapol_ie_parse *ie)
+{
+	if (pos[1] == 0)
+		return 1;
+
+	if (pos[1] >= 6 &&
+	    RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
+	    pos[2 + WPA_SELECTOR_LEN] == 1 &&
+	    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;
+	}
+
+	if (pos + 1 + RSN_SELECTOR_LEN < 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;
+	}
+
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    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(MSG_DEBUG, "WPA: GTK in EAPOL-Key",
+				pos, pos[1] + 2);
+		return 0;
+	}
+
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    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;
+	}
+	return 0;
+}
+
+
+/**
+ * wpa_supplicant_parse_ies - Parse EAPOL-Key Key Data IEs
+ * @buf: Pointer to the Key Data buffer
+ * @len: Key Data Length
+ * @ie: Pointer to parsed IE data
+ * Returns: 0 on success, -1 on failure
+ */
+int  wpa_supplicant_parse_ies(const u8 *buf, size_t len,
+			     struct wpa_eapol_ie_parse *ie)
+{
+	const u8 *pos, *end;
+	int ret = 0;
+
+	memset(ie, 0, sizeof(*ie));
+	for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) {
+		if (pos[0] == 0xdd &&
+		    ((pos == buf + len - 1) || pos[1] == 0)) {
+			/* Ignore padding */
+			break;
+		}
+		if (pos + 2 + pos[1] > end) {
+		    #ifdef DEBUG_PRINT	
+			wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
+				   "underflow (ie=%d len=%d pos=%d)",
+				   pos[0], pos[1], (int) (pos - buf));
+		    #endif	
+			wpa_hexdump(MSG_DEBUG, "WPA: Key Data",
+					buf, len);
+			ret = -1;
+			break;
+		}
+		if (*pos == WLAN_EID_RSN) {
+			ie->rsn_ie = pos;
+			ie->rsn_ie_len = pos[1] + 2;
+			wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key",
+				    ie->rsn_ie, ie->rsn_ie_len);
+		} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
+			ret = wpa_parse_generic(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]);
+		}
+	}
+
+	return ret;
+}
+
+
 #endif // ESP_SUPPLICANT
 

+ 235 - 46
components/wpa_supplicant/src/utils/common.c

@@ -2,14 +2,8 @@
  * wpa_supplicant/hostapd / common helper functions, etc.
  * Copyright (c) 2002-2007, 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 "utils/includes.h"
@@ -99,68 +93,263 @@ void wpa_get_ntp_timestamp(u8 *buf)
 	usec = now.usec;
 	usec = 4295 * usec - (usec >> 5) - (usec >> 9);
 	tmp = host_to_be32(sec);
-	memcpy(buf, (u8 *) &tmp, 4);
+	os_memcpy(buf, (u8 *) &tmp, 4);
 	tmp = host_to_be32(usec);
-	memcpy(buf + 4, (u8 *) &tmp, 4);
+	os_memcpy(buf + 4, (u8 *) &tmp, 4);
+}
+void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len)
+{
+	char *end = txt + maxlen;
+	size_t i;
+
+	for (i = 0; i < len; i++) {
+		if (txt + 4 >= end)
+			break;
+
+		switch (data[i]) {
+		case '\"':
+			*txt++ = '\\';
+			*txt++ = '\"';
+			break;
+		case '\\':
+			*txt++ = '\\';
+			*txt++ = '\\';
+			break;
+		case '\033':
+			*txt++ = '\\';
+			*txt++ = 'e';
+			break;
+		case '\n':
+			*txt++ = '\\';
+			*txt++ = 'n';
+			break;
+		case '\r':
+			*txt++ = '\\';
+			*txt++ = 'r';
+			break;
+		case '\t':
+			*txt++ = '\\';
+			*txt++ = 't';
+			break;
+		default:
+			if (data[i] >= 32 && data[i] <= 127) {
+				*txt++ = data[i];
+			} else {
+				txt += os_snprintf(txt, end - txt, "\\x%02x",
+						   data[i]);
+			}
+			break;
+		}
+	}
+
+	*txt = '\0';
 }
 
+
+size_t printf_decode(u8 *buf, size_t maxlen, const char *str)
+{
+	const char *pos = str;
+	size_t len = 0;
+	int val;
+
+	while (*pos) {
+		if (len + 1 >= maxlen)
+			break;
+		switch (*pos) {
+		case '\\':
+			pos++;
+			switch (*pos) {
+			case '\\':
+				buf[len++] = '\\';
+				pos++;
+				break;
+			case '"':
+				buf[len++] = '"';
+				pos++;
+				break;
+			case 'n':
+				buf[len++] = '\n';
+				pos++;
+				break;
+			case 'r':
+				buf[len++] = '\r';
+				pos++;
+				break;
+			case 't':
+				buf[len++] = '\t';
+				pos++;
+				break;
+			case 'e':
+				buf[len++] = '\033';
+				pos++;
+				break;
+			case 'x':
+				pos++;
+				val = hex2byte(pos);
+				if (val < 0) {
+					val = hex2num(*pos);
+					if (val < 0)
+						break;
+					buf[len++] = val;
+					pos++;
+				} else {
+					buf[len++] = val;
+					pos += 2;
+				}
+				break;
+			case '0':
+			case '1':
+			case '2':
+			case '3':
+			case '4':
+			case '5':
+			case '6':
+			case '7':
+				val = *pos++ - '0';
+				if (*pos >= '0' && *pos <= '7')
+					val = val * 8 + (*pos++ - '0');
+				if (*pos >= '0' && *pos <= '7')
+					val = val * 8 + (*pos++ - '0');
+				buf[len++] = val;
+				break;
+			default:
+				break;
+			}
+			break;
+		default:
+			buf[len++] = *pos++;
+			break;
+		}
+	}
+	if (maxlen > len)
+		buf[len] = '\0';
+
+	return len;
+}
+
+
+
 char * wpa_config_parse_string(const char *value, size_t *len)
 {
-	if (*value == '"' && (strlen(value) == 7 || strlen(value) == 15)) {
+	if (*value == '"') {
 		const char *pos;
 		char *str;
 		value++;
-		pos = (char *)strrchr(value, '"');
-		if (pos == NULL)
+		pos = os_strrchr(value, '"');
+		if (pos == NULL || pos[1] != '\0')
 			return NULL;
 		*len = pos - value;
-		str = (char *)os_malloc(*len + 1);
+		str = dup_binstr(value, *len);
 		if (str == NULL)
 			return NULL;
-		memcpy(str, value, *len);
-		str[*len] = '\0';
+		return str;
+	} else if (*value == 'P' && value[1] == '"') {
+		const char *pos;
+		char *tstr, *str;
+		size_t tlen;
+		value += 2;
+		pos = os_strrchr(value, '"');
+		if (pos == NULL || pos[1] != '\0')
+			return NULL;
+		tlen = pos - value;
+		tstr = dup_binstr(value, tlen);
+		if (tstr == NULL)
+			return NULL;
+
+		str = os_malloc(tlen + 1);
+		if (str == NULL) {
+			os_free(tstr);
+			return NULL;
+		}
+
+		*len = printf_decode((u8 *) str, tlen + 1, tstr);
+		os_free(tstr);
+
 		return str;
 	} else {
 		u8 *str;
-		size_t tlen, hlen = strlen(value);
-		if (hlen == 5 || hlen == 13) {
-			*len = hlen;
-			str = (u8 *)os_malloc(*len + 1);
-			if (str == NULL) {
-				return NULL;
-			}
-			memcpy(str, value, *len);
-			str[*len] = '\0';
-		} else if (hlen == 10 || hlen == 26) {
-			tlen = hlen / 2;
-			str = (u8 *)os_malloc(tlen + 1);
-			if (str == NULL)
-				return NULL;
-			if (hexstr2bin(value, str, tlen)) {
-				os_free(str);
-				return NULL;
-			}
-			str[tlen] = '\0';
-			*len = tlen;
-		} else {
+		size_t tlen, hlen = os_strlen(value);
+		if (hlen & 1)
+			return NULL;
+		tlen = hlen / 2;
+		str = os_malloc(tlen + 1);
+		if (str == NULL)
+			return NULL;
+		if (hexstr2bin(value, str, tlen)) {
+			os_free(str);
 			return NULL;
 		}
+		str[tlen] = '\0';
+		*len = tlen;
 		return (char *) str;
 	}
 }
 
+
+int wpa_is_hex(const u8 *data, size_t len)
+{
+	size_t i;
+
+	for (i = 0; i < len; i++) {
+		if (data[i] < 32 || data[i] >= 127)
+			return 1;
+	}
+	return 0;
+}
+
+
+size_t wpa_merge_byte_arrays(u8 *res, size_t res_len,
+			 const u8 *src1, size_t src1_len,
+			 const u8 *src2, size_t src2_len)
+{
+	size_t len = 0;
+
+	os_memset(res, 0, res_len);
+
+	if (src1) {
+		if (src1_len >= res_len) {
+			os_memcpy(res, src1, res_len);
+			return res_len;
+		}
+
+		os_memcpy(res, src1, src1_len);
+		len += src1_len;
+	}
+
+	if (src2) {
+		if (len + src2_len >= res_len) {
+			os_memcpy(res + len, src2, res_len - len);
+			return res_len;
+		}
+
+		os_memcpy(res + len, src2, src2_len);
+		len += src2_len;
+	}
+
+	return len;
+}
+
+
 char * dup_binstr(const void *src, size_t len)
 {
-        char *res;
+	char *res;
 
-        if (src == NULL)
-                return NULL;
-        res = os_malloc(len + 1);
-        if (res == NULL)
-                return NULL;
-        memcpy(res, src, len);
-        res[len] = '\0';
+	if (src == NULL)
+		return NULL;
+	res = os_malloc(len + 1);
+	if (res == NULL)
+		return NULL;
+	os_memcpy(res, src, len);
+	res[len] = '\0';
 
-        return res;
+	return res;
 }
+void wpa_bin_clear_free(void *bin, size_t len)
+{
+	if (bin) {
+		os_memset(bin, 0, len);
+		os_free(bin);
+	}
+}
+
 

+ 198 - 79
components/wpa_supplicant/include/utils/common.h → components/wpa_supplicant/src/utils/common.h

@@ -2,14 +2,8 @@
  * wpa_supplicant/hostapd / common helper functions, etc.
  * Copyright (c) 2002-2007, 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.
  */
 
 #ifndef COMMON_H
@@ -65,6 +59,7 @@ static inline unsigned int wpa_swap_32(unsigned int v)
 #define be_to_host16(n) wpa_swap_16(n)
 #define host_to_be16(n) wpa_swap_16(n)
 #define le_to_host32(n) (n)
+#define host_to_le32(n) (n)
 #define be_to_host32(n) wpa_swap_32(n)
 #define host_to_be32(n) wpa_swap_32(n)
 
@@ -125,80 +120,122 @@ static inline unsigned int wpa_swap_32(unsigned int v)
 
 /* Macros for handling unaligned memory accesses */
 
-#define WPA_GET_BE16(a) ((u16) (((a)[0] << 8) | (a)[1]))
-#define WPA_PUT_BE16(a, val)			\
-	do {					\
-		(a)[0] = ((u16) (val)) >> 8;	\
-		(a)[1] = ((u16) (val)) & 0xff;	\
-	} while (0)
-
-#define WPA_GET_LE16(a) ((u16) (((a)[1] << 8) | (a)[0]))
-#define WPA_PUT_LE16(a, val)			\
-	do {					\
-		(a)[1] = ((u16) (val)) >> 8;	\
-		(a)[0] = ((u16) (val)) & 0xff;	\
-	} while (0)
-
-#define WPA_GET_BE24(a) ((((u32) (a)[0]) << 16) | (((u32) (a)[1]) << 8) | \
-			 ((u32) (a)[2]))
-#define WPA_PUT_BE24(a, val)					\
-	do {							\
-		(a)[0] = (u8) ((((u32) (val)) >> 16) & 0xff);	\
-		(a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff);	\
-		(a)[2] = (u8) (((u32) (val)) & 0xff);		\
-	} while (0)
-
-#define WPA_GET_BE32(a) ((((u32) (a)[0]) << 24) | (((u32) (a)[1]) << 16) | \
-			 (((u32) (a)[2]) << 8) | ((u32) (a)[3]))
-#define WPA_PUT_BE32(a, val)					\
-	do {							\
-		(a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff);	\
-		(a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff);	\
-		(a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff);	\
-		(a)[3] = (u8) (((u32) (val)) & 0xff);		\
-	} while (0)
-
-#define WPA_GET_LE32(a) ((((u32) (a)[3]) << 24) | (((u32) (a)[2]) << 16) | \
-			 (((u32) (a)[1]) << 8) | ((u32) (a)[0]))
-#define WPA_PUT_LE32(a, val)					\
-	do {							\
-		(a)[3] = (u8) ((((u32) (val)) >> 24) & 0xff);	\
-		(a)[2] = (u8) ((((u32) (val)) >> 16) & 0xff);	\
-		(a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff);	\
-		(a)[0] = (u8) (((u32) (val)) & 0xff);		\
-	} while (0)
-
-#define WPA_GET_BE64(a) ((((u64) (a)[0]) << 56) | (((u64) (a)[1]) << 48) | \
-			 (((u64) (a)[2]) << 40) | (((u64) (a)[3]) << 32) | \
-			 (((u64) (a)[4]) << 24) | (((u64) (a)[5]) << 16) | \
-			 (((u64) (a)[6]) << 8) | ((u64) (a)[7]))
-#define WPA_PUT_BE64(a, val)				\
-	do {						\
-		(a)[0] = (u8) (((u64) (val)) >> 56);	\
-		(a)[1] = (u8) (((u64) (val)) >> 48);	\
-		(a)[2] = (u8) (((u64) (val)) >> 40);	\
-		(a)[3] = (u8) (((u64) (val)) >> 32);	\
-		(a)[4] = (u8) (((u64) (val)) >> 24);	\
-		(a)[5] = (u8) (((u64) (val)) >> 16);	\
-		(a)[6] = (u8) (((u64) (val)) >> 8);	\
-		(a)[7] = (u8) (((u64) (val)) & 0xff);	\
-	} while (0)
-
-#define WPA_GET_LE64(a) ((((u64) (a)[7]) << 56) | (((u64) (a)[6]) << 48) | \
-			 (((u64) (a)[5]) << 40) | (((u64) (a)[4]) << 32) | \
-			 (((u64) (a)[3]) << 24) | (((u64) (a)[2]) << 16) | \
-			 (((u64) (a)[1]) << 8) | ((u64) (a)[0]))
+static inline u16 WPA_GET_BE16(const u8 *a)
+{
+	return (a[0] << 8) | a[1];
+}
+
+static inline void WPA_PUT_BE16(u8 *a, u16 val)
+{
+	a[0] = val >> 8;
+	a[1] = val & 0xff;
+}
+
+static inline u16 WPA_GET_LE16(const u8 *a)
+{
+	return (a[1] << 8) | a[0];
+}
+
+static inline void WPA_PUT_LE16(u8 *a, u16 val)
+{
+	a[1] = val >> 8;
+	a[0] = val & 0xff;
+}
+
+static inline u32 WPA_GET_BE24(const u8 *a)
+{
+	return (a[0] << 16) | (a[1] << 8) | a[2];
+}
+
+static inline void WPA_PUT_BE24(u8 *a, u32 val)
+{
+	a[0] = (val >> 16) & 0xff;
+	a[1] = (val >> 8) & 0xff;
+	a[2] = val & 0xff;
+}
+
+static inline u32 WPA_GET_BE32(const u8 *a)
+{
+	return ((u32) a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3];
+}
+
+static inline void WPA_PUT_BE32(u8 *a, u32 val)
+{
+	a[0] = (val >> 24) & 0xff;
+	a[1] = (val >> 16) & 0xff;
+	a[2] = (val >> 8) & 0xff;
+	a[3] = val & 0xff;
+}
+
+static inline u32 WPA_GET_LE32(const u8 *a)
+{
+	return ((u32) a[3] << 24) | (a[2] << 16) | (a[1] << 8) | a[0];
+}
+
+static inline void WPA_PUT_LE32(u8 *a, u32 val)
+{
+	a[3] = (val >> 24) & 0xff;
+	a[2] = (val >> 16) & 0xff;
+	a[1] = (val >> 8) & 0xff;
+	a[0] = val & 0xff;
+}
+
+static inline u64 WPA_GET_BE64(const u8 *a)
+{
+	return (((u64) a[0]) << 56) | (((u64) a[1]) << 48) |
+		(((u64) a[2]) << 40) | (((u64) a[3]) << 32) |
+		(((u64) a[4]) << 24) | (((u64) a[5]) << 16) |
+		(((u64) a[6]) << 8) | ((u64) a[7]);
+}
+
+static inline void WPA_PUT_BE64(u8 *a, u64 val)
+{
+	a[0] = val >> 56;
+	a[1] = val >> 48;
+	a[2] = val >> 40;
+	a[3] = val >> 32;
+	a[4] = val >> 24;
+	a[5] = val >> 16;
+	a[6] = val >> 8;
+	a[7] = val & 0xff;
+}
+
+static inline u64 WPA_GET_LE64(const u8 *a)
+{
+	return (((u64) a[7]) << 56) | (((u64) a[6]) << 48) |
+		(((u64) a[5]) << 40) | (((u64) a[4]) << 32) |
+		(((u64) a[3]) << 24) | (((u64) a[2]) << 16) |
+		(((u64) a[1]) << 8) | ((u64) a[0]);
+}
+
+static inline void WPA_PUT_LE64(u8 *a, u64 val)
+{
+	a[7] = val >> 56;
+	a[6] = val >> 48;
+	a[5] = val >> 40;
+	a[4] = val >> 32;
+	a[3] = val >> 24;
+	a[2] = val >> 16;
+	a[1] = val >> 8;
+	a[0] = val & 0xff;
+}
 
 
 #ifndef ETH_ALEN
 #define ETH_ALEN 6
 #endif
-//#ifndef IFNAMSIZ
-//#define IFNAMSIZ 16
-//#endif
+#ifndef ETH_HLEN
+#define ETH_HLEN 14
+#endif
+#ifndef IFNAMSIZ
+#define IFNAMSIZ 16
+#endif
 #ifndef ETH_P_ALL
 #define ETH_P_ALL 0x0003
 #endif
+#ifndef ETH_P_80211_ENCAP
+#define ETH_P_80211_ENCAP 0x890d /* TDLS comes under this category */
+#endif
 #ifndef ETH_P_PAE
 #define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
 #endif /* ETH_P_PAE */
@@ -221,8 +258,31 @@ static inline unsigned int wpa_swap_32(unsigned int v)
 #define STRUCT_PACKED
 #endif
 
+
 #ifdef CONFIG_ANSI_C_EXTRA
 
+#if !defined(_MSC_VER) || _MSC_VER < 1400
+/* snprintf - used in number of places; sprintf() is _not_ a good replacement
+ * due to possible buffer overflow; see, e.g.,
+ * http://www.ijs.si/software/snprintf/ for portable implementation of
+ * snprintf. */
+int snprintf(char *str, size_t size, const char *format, ...);
+
+/* vsnprintf - only used for wpa_msg() in wpa_supplicant.c */
+int vsnprintf(char *str, size_t size, const char *format, va_list ap);
+#endif /* !defined(_MSC_VER) || _MSC_VER < 1400 */
+
+/* getopt - only used in main.c */
+int getopt(int argc, char *const argv[], const char *optstring);
+extern char *optarg;
+extern int optind;
+
+#ifndef CONFIG_NO_SOCKLEN_T_TYPEDEF
+#ifndef __socklen_t_defined
+typedef int socklen_t;
+#endif
+#endif
+
 /* inline - define as __inline or just define it to be empty, if needed */
 #ifdef CONFIG_NO_INLINE
 #define inline
@@ -258,10 +318,16 @@ void perror(const char *s);
 #ifndef MAC2STR
 #define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
 #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
+
+/*
+ * Compact form for string representation of MAC address
+ * To be used, e.g., for constructing dbus paths for P2P Devices
+ */
+#define COMPACT_MACSTR "%02x%02x%02x%02x%02x%02x"
 #endif
 
 #ifndef BIT
-#define BIT(x) (1 << (x))
+#define BIT(x) (1U << (x))
 #endif
 
 /*
@@ -291,15 +357,31 @@ typedef u64 __bitwise le64;
 #endif /* __GNUC__ */
 #endif /* __must_check */
 
+#ifndef __maybe_unused
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+#define __maybe_unused __attribute__((unused))
+#else
+#define __maybe_unused
+#endif /* __GNUC__ */
+#endif /* __must_check */
+
 int hwaddr_aton(const char *txt, u8 *addr);
+int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable);
+int hwaddr_compact_aton(const char *txt, u8 *addr);
 int hwaddr_aton2(const char *txt, u8 *addr);
+int hex2byte(const char *hex);
 int hexstr2bin(const char *hex, u8 *buf, size_t len);
 void inc_byte_array(u8 *counter, size_t len);
 void wpa_get_ntp_timestamp(u8 *buf);
+int wpa_scnprintf(char *buf, size_t size, const char *fmt, ...);
+int wpa_snprintf_hex_sep(char *buf, size_t buf_size, const u8 *data, size_t len,
+			 char sep);
 int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len);
 int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data,
 			       size_t len);
 
+int hwaddr_mask_txt(char *buf, size_t len, const u8 *addr, const u8 *mask);
+
 #ifdef CONFIG_NATIVE_WINDOWS
 void wpa_unicode2ascii_inplace(TCHAR *str);
 TCHAR * wpa_strdup_tchar(const char *str);
@@ -308,21 +390,51 @@ TCHAR * wpa_strdup_tchar(const char *str);
 #define wpa_strdup_tchar(s) strdup((s))
 #endif /* CONFIG_NATIVE_WINDOWS */
 
+void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len);
+size_t printf_decode(u8 *buf, size_t maxlen, const char *str);
+
 const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len);
+
 char * wpa_config_parse_string(const char *value, size_t *len);
+int wpa_is_hex(const u8 *data, size_t len);
+size_t wpa_merge_byte_arrays(u8 *res, size_t res_len,
+			 const u8 *src1, size_t src1_len,
+			 const u8 *src2, size_t src2_len);
+char * dup_binstr(const void *src, size_t len);
 
 static inline int is_zero_ether_addr(const u8 *a)
 {
 	return !(a[0] | a[1] | a[2] | a[3] | a[4] | a[5]);
 }
 
-extern const struct eth_addr ethbroadcast;
-#define broadcast_ether_addr &ethbroadcast
+static inline int is_broadcast_ether_addr(const u8 *a)
+{
+	return (a[0] & a[1] & a[2] & a[3] & a[4] & a[5]) == 0xff;
+}
+
+static inline int is_multicast_ether_addr(const u8 *a)
+{
+	return a[0] & 0x01;
+}
+
+#define broadcast_ether_addr (const u8 *) "\xff\xff\xff\xff\xff\xff"
+
 
-#include "wpabuf.h"
-#include "wpa_debug.h"
+#include "utils/wpa_debug.h"
 
 
+struct wpa_freq_range_list {
+	struct wpa_freq_range {
+		unsigned int min;
+		unsigned int max;
+	} *range;
+	unsigned int num;
+};
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+void wpa_bin_clear_free(void *bin, size_t len);
+
 /*
  * gcc 4.4 ends up generating strict-aliasing warnings about some very common
  * networking socket uses that do not really result in a real problem and
@@ -335,4 +447,11 @@ extern const struct eth_addr ethbroadcast;
 void * __hide_aliasing_typecast(void *foo);
 #define aliasing_hide_typecast(a,t) (t *) __hide_aliasing_typecast((a))
 
+#ifdef CONFIG_VALGRIND
+#include <valgrind/memcheck.h>
+#define WPA_MEM_DEFINED(ptr, len) VALGRIND_MAKE_MEM_DEFINED((ptr), (len))
+#else /* CONFIG_VALGRIND */
+#define WPA_MEM_DEFINED(ptr, len) do { } while (0)
+#endif /* CONFIG_VALGRIND */
+
 #endif /* COMMON_H */