]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - src/ap/wpa_auth.c
WPA auth: Disconnect STA if MSK cannot be fetched
[thirdparty/hostap.git] / src / ap / wpa_auth.c
index 18ae86c8bdc3bdf2bab22259327eb99ad416beeb..668cb429dd245915afaf443544a5dc700c3228e1 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * IEEE 802.11 RSN / WPA Authenticator
- * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -11,6 +11,7 @@
 #include "utils/common.h"
 #include "utils/eloop.h"
 #include "utils/state_machine.h"
+#include "utils/bitfield.h"
 #include "common/ieee802_11_defs.h"
 #include "crypto/aes_wrap.h"
 #include "crypto/crypto.h"
@@ -32,7 +33,8 @@
 
 static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx);
 static int wpa_sm_step(struct wpa_state_machine *sm);
-static int wpa_verify_key_mic(struct wpa_ptk *PTK, u8 *data, size_t data_len);
+static int wpa_verify_key_mic(int akmp, struct wpa_ptk *PTK, u8 *data,
+                             size_t data_len);
 static void wpa_sm_call_step(void *eloop_ctx, void *timeout_ctx);
 static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,
                              struct wpa_group *group);
@@ -41,6 +43,8 @@ static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
                          struct wpa_group *group);
 static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
                                       struct wpa_group *group);
+static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
+                         const u8 *pmk, struct wpa_ptk *ptk);
 
 static const u32 dot11RSNAConfigGroupUpdateCount = 4;
 static const u32 dot11RSNAConfigPairwiseUpdateCount = 4;
@@ -82,11 +86,14 @@ static inline int wpa_auth_get_eapol(struct wpa_authenticator *wpa_auth,
 
 
 static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth,
-                                         const u8 *addr, const u8 *prev_psk)
+                                         const u8 *addr,
+                                         const u8 *p2p_dev_addr,
+                                         const u8 *prev_psk)
 {
        if (wpa_auth->cb.get_psk == NULL)
                return NULL;
-       return wpa_auth->cb.get_psk(wpa_auth->cb.ctx, addr, prev_psk);
+       return wpa_auth->cb.get_psk(wpa_auth->cb.ctx, addr, p2p_dev_addr,
+                                   prev_psk);
 }
 
 
@@ -131,6 +138,17 @@ wpa_auth_send_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr,
 }
 
 
+#ifdef CONFIG_MESH
+static inline int wpa_auth_start_ampe(struct wpa_authenticator *wpa_auth,
+                                     const u8 *addr)
+{
+       if (wpa_auth->cb.start_ampe == NULL)
+               return -1;
+       return wpa_auth->cb.start_ampe(wpa_auth->cb.ctx, addr);
+}
+#endif /* CONFIG_MESH */
+
+
 int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth,
                          int (*cb)(struct wpa_state_machine *sm, void *ctx),
                          void *cb_ctx)
@@ -207,6 +225,8 @@ static int wpa_use_aes_cmac(struct wpa_state_machine *sm)
        if (wpa_key_mgmt_sha256(sm->wpa_key_mgmt))
                ret = 1;
 #endif /* CONFIG_IEEE80211W */
+       if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN)
+               ret = 1;
        return ret;
 }
 
@@ -395,6 +415,7 @@ struct wpa_authenticator * wpa_init(const u8 *addr,
                                                wpa_auth);
        if (wpa_auth->pmksa == NULL) {
                wpa_printf(MSG_ERROR, "PMKSA cache initialization failed.");
+               os_free(wpa_auth->group);
                os_free(wpa_auth->wpa_ie);
                os_free(wpa_auth);
                return NULL;
@@ -404,6 +425,7 @@ struct wpa_authenticator * wpa_init(const u8 *addr,
        wpa_auth->ft_pmk_cache = wpa_ft_pmk_cache_init();
        if (wpa_auth->ft_pmk_cache == NULL) {
                wpa_printf(MSG_ERROR, "FT PMK cache initialization failed.");
+               os_free(wpa_auth->group);
                os_free(wpa_auth->wpa_ie);
                pmksa_cache_auth_deinit(wpa_auth->pmksa);
                os_free(wpa_auth);
@@ -421,6 +443,17 @@ struct wpa_authenticator * wpa_init(const u8 *addr,
                                       wpa_rekey_gtk, wpa_auth, NULL);
        }
 
+#ifdef CONFIG_P2P
+       if (WPA_GET_BE32(conf->ip_addr_start)) {
+               int count = WPA_GET_BE32(conf->ip_addr_end) -
+                       WPA_GET_BE32(conf->ip_addr_start) + 1;
+               if (count > 1000)
+                       count = 1000;
+               if (count > 0)
+                       wpa_auth->ip_pool = bitfield_alloc(count);
+       }
+#endif /* CONFIG_P2P */
+
        return wpa_auth;
 }
 
@@ -434,6 +467,8 @@ int wpa_init_keys(struct wpa_authenticator *wpa_auth)
        wpa_group_sm_step(wpa_auth, group);
        group->GInit = FALSE;
        wpa_group_sm_step(wpa_auth, group);
+       if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE)
+               return -1;
        return 0;
 }
 
@@ -461,6 +496,11 @@ void wpa_deinit(struct wpa_authenticator *wpa_auth)
        wpa_auth->ft_pmk_cache = NULL;
 #endif /* CONFIG_IEEE80211R */
 
+#ifdef CONFIG_P2P
+       bitfield_free(wpa_auth->ip_pool);
+#endif /* CONFIG_P2P */
+
+
        os_free(wpa_auth->wpa_ie);
 
        group = wpa_auth->group;
@@ -508,14 +548,20 @@ int wpa_reconfig(struct wpa_authenticator *wpa_auth,
 
 
 struct wpa_state_machine *
-wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr)
+wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr,
+                 const u8 *p2p_dev_addr)
 {
        struct wpa_state_machine *sm;
 
+       if (wpa_auth->group->wpa_group_state == WPA_GROUP_FATAL_FAILURE)
+               return NULL;
+
        sm = os_zalloc(sizeof(struct wpa_state_machine));
        if (sm == NULL)
                return NULL;
        os_memcpy(sm->addr, addr, ETH_ALEN);
+       if (p2p_dev_addr)
+               os_memcpy(sm->p2p_dev_addr, p2p_dev_addr, ETH_ALEN);
 
        sm->wpa_auth = wpa_auth;
        sm->group = wpa_auth->group;
@@ -535,6 +581,8 @@ int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth,
                wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
                                "FT authentication already completed - do not "
                                "start 4-way handshake");
+               /* Go to PTKINITDONE state to allow GTK rekeying */
+               sm->wpa_ptk_state = WPA_PTK_PTKINITDONE;
                return 0;
        }
 #endif /* CONFIG_IEEE80211R */
@@ -572,12 +620,26 @@ void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm)
 
 static void wpa_free_sta_sm(struct wpa_state_machine *sm)
 {
+#ifdef CONFIG_P2P
+       if (WPA_GET_BE32(sm->ip_addr)) {
+               u32 start;
+               wpa_printf(MSG_DEBUG, "P2P: Free assigned IP "
+                          "address %u.%u.%u.%u from " MACSTR,
+                          sm->ip_addr[0], sm->ip_addr[1],
+                          sm->ip_addr[2], sm->ip_addr[3],
+                          MAC2STR(sm->addr));
+               start = WPA_GET_BE32(sm->wpa_auth->conf.ip_addr_start);
+               bitfield_clear(sm->wpa_auth->ip_pool,
+                              WPA_GET_BE32(sm->ip_addr) - start);
+       }
+#endif /* CONFIG_P2P */
        if (sm->GUpdateStationKeys) {
                sm->group->GKeyDoneStations--;
                sm->GUpdateStationKeys = FALSE;
        }
 #ifdef CONFIG_IEEE80211R
        os_free(sm->assoc_resp_ftie);
+       wpabuf_free(sm->ft_pending_req_ies);
 #endif /* CONFIG_IEEE80211R */
        os_free(sm->last_rx_eapol_key);
        os_free(sm->wpa_ie);
@@ -736,40 +798,96 @@ static int wpa_receive_error_report(struct wpa_authenticator *wpa_auth,
 }
 
 
+static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
+                             size_t data_len)
+{
+       struct wpa_ptk PTK;
+       int ok = 0;
+       const u8 *pmk = NULL;
+
+       for (;;) {
+               if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
+                       pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
+                                              sm->p2p_dev_addr, pmk);
+                       if (pmk == NULL)
+                               break;
+               } else
+                       pmk = sm->PMK;
+
+               wpa_derive_ptk(sm, sm->alt_SNonce, pmk, &PTK);
+
+               if (wpa_verify_key_mic(sm->wpa_key_mgmt, &PTK, data, data_len)
+                   == 0) {
+                       ok = 1;
+                       break;
+               }
+
+               if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt))
+                       break;
+       }
+
+       if (!ok) {
+               wpa_printf(MSG_DEBUG,
+                          "WPA: Earlier SNonce did not result in matching MIC");
+               return -1;
+       }
+
+       wpa_printf(MSG_DEBUG,
+                  "WPA: Earlier SNonce resulted in matching MIC");
+       sm->alt_snonce_valid = 0;
+       os_memcpy(sm->SNonce, sm->alt_SNonce, WPA_NONCE_LEN);
+       os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
+       sm->PTK_valid = TRUE;
+
+       return 0;
+}
+
+
 void wpa_receive(struct wpa_authenticator *wpa_auth,
                 struct wpa_state_machine *sm,
                 u8 *data, size_t data_len)
 {
        struct ieee802_1x_hdr *hdr;
        struct wpa_eapol_key *key;
+       struct wpa_eapol_key_192 *key192;
        u16 key_info, key_data_length;
        enum { PAIRWISE_2, PAIRWISE_4, GROUP_2, REQUEST,
               SMK_M1, SMK_M3, SMK_ERROR } msg;
        char *msgtxt;
        struct wpa_eapol_ie_parse kde;
        int ft;
-       const u8 *eapol_key_ie;
-       size_t eapol_key_ie_len;
+       const u8 *eapol_key_ie, *key_data;
+       size_t eapol_key_ie_len, keyhdrlen, mic_len;
 
        if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL)
                return;
 
-       if (data_len < sizeof(*hdr) + sizeof(*key))
+       mic_len = wpa_mic_len(sm->wpa_key_mgmt);
+       keyhdrlen = mic_len == 24 ? sizeof(*key192) : sizeof(*key);
+
+       if (data_len < sizeof(*hdr) + keyhdrlen)
                return;
 
        hdr = (struct ieee802_1x_hdr *) data;
        key = (struct wpa_eapol_key *) (hdr + 1);
+       key192 = (struct wpa_eapol_key_192 *) (hdr + 1);
        key_info = WPA_GET_BE16(key->key_info);
-       key_data_length = WPA_GET_BE16(key->key_data_length);
+       if (mic_len == 24) {
+               key_data = (const u8 *) (key192 + 1);
+               key_data_length = WPA_GET_BE16(key192->key_data_length);
+       } else {
+               key_data = (const u8 *) (key + 1);
+               key_data_length = WPA_GET_BE16(key->key_data_length);
+       }
        wpa_printf(MSG_DEBUG, "WPA: Received EAPOL-Key from " MACSTR
                   " key_info=0x%x type=%u key_data_length=%u",
                   MAC2STR(sm->addr), key_info, key->type, key_data_length);
-       if (key_data_length > data_len - sizeof(*hdr) - sizeof(*key)) {
+       if (key_data_length > data_len - sizeof(*hdr) - keyhdrlen) {
                wpa_printf(MSG_INFO, "WPA: Invalid EAPOL-Key frame - "
                           "key_data overflow (%d > %lu)",
                           key_data_length,
                           (unsigned long) (data_len - sizeof(*hdr) -
-                                           sizeof(*key)));
+                                           keyhdrlen));
                return;
        }
 
@@ -837,6 +955,8 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
                if (sm->pairwise == WPA_CIPHER_CCMP ||
                    sm->pairwise == WPA_CIPHER_GCMP) {
                        if (wpa_use_aes_cmac(sm) &&
+                           sm->wpa_key_mgmt != WPA_KEY_MGMT_OSEN &&
+                           !wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) &&
                            ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
                                wpa_auth_logger(wpa_auth, sm->addr,
                                                LOGGER_WARNING,
@@ -855,6 +975,13 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
                                return;
                        }
                }
+
+               if (wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) &&
+                   ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) {
+                       wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING,
+                                       "did not use EAPOL-Key descriptor version 0 as required for AKM-defined cases");
+                       return;
+               }
        }
 
        if (key_info & WPA_KEY_INFO_REQUEST) {
@@ -890,8 +1017,25 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
                                         "based on retransmitted EAPOL-Key "
                                         "1/4");
                        sm->update_snonce = 1;
-                       wpa_replay_counter_mark_invalid(sm->prev_key_replay,
-                                                       key->replay_counter);
+                       os_memcpy(sm->alt_SNonce, sm->SNonce, WPA_NONCE_LEN);
+                       sm->alt_snonce_valid = TRUE;
+                       os_memcpy(sm->alt_replay_counter,
+                                 sm->key_replay[0].counter,
+                                 WPA_REPLAY_COUNTER_LEN);
+                       goto continue_processing;
+               }
+
+               if (msg == PAIRWISE_4 && sm->alt_snonce_valid &&
+                   sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING &&
+                   os_memcmp(key->replay_counter, sm->alt_replay_counter,
+                             WPA_REPLAY_COUNTER_LEN) == 0) {
+                       /*
+                        * Supplicant may still be using the old SNonce since
+                        * there was two EAPOL-Key 2/4 messages and they had
+                        * different SNonce values.
+                        */
+                       wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+                                        "Try to process received EAPOL-Key 4/4 based on old Replay Counter and SNonce from an earlier EAPOL-Key 1/4");
                        goto continue_processing;
                }
 
@@ -950,8 +1094,7 @@ continue_processing:
                        wpa_sta_disconnect(wpa_auth, sm->addr);
                        return;
                }
-               if (wpa_parse_kde_ies((u8 *) (key + 1), key_data_length,
-                                     &kde) < 0) {
+               if (wpa_parse_kde_ies(key_data, key_data_length, &kde) < 0) {
                        wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
                                         "received EAPOL-Key msg 2/4 with "
                                         "invalid Key Data contents");
@@ -960,6 +1103,9 @@ continue_processing:
                if (kde.rsn_ie) {
                        eapol_key_ie = kde.rsn_ie;
                        eapol_key_ie_len = kde.rsn_ie_len;
+               } else if (kde.osen) {
+                       eapol_key_ie = kde.osen;
+                       eapol_key_ie_len = kde.osen_len;
                } else {
                        eapol_key_ie = kde.wpa_ie;
                        eapol_key_ie_len = kde.wpa_ie_len;
@@ -989,6 +1135,26 @@ continue_processing:
                        return;
                }
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_P2P
+               if (kde.ip_addr_req && kde.ip_addr_req[0] &&
+                   wpa_auth->ip_pool && WPA_GET_BE32(sm->ip_addr) == 0) {
+                       int idx;
+                       wpa_printf(MSG_DEBUG, "P2P: IP address requested in "
+                                  "EAPOL-Key exchange");
+                       idx = bitfield_get_first_zero(wpa_auth->ip_pool);
+                       if (idx >= 0) {
+                               u32 start = WPA_GET_BE32(wpa_auth->conf.
+                                                        ip_addr_start);
+                               bitfield_set(wpa_auth->ip_pool, idx);
+                               WPA_PUT_BE32(sm->ip_addr, start + idx);
+                               wpa_printf(MSG_DEBUG, "P2P: Assigned IP "
+                                          "address %u.%u.%u.%u to " MACSTR,
+                                          sm->ip_addr[0], sm->ip_addr[1],
+                                          sm->ip_addr[2], sm->ip_addr[3],
+                                          MAC2STR(sm->addr));
+                       }
+               }
+#endif /* CONFIG_P2P */
                break;
        case PAIRWISE_4:
                if (sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING ||
@@ -1053,7 +1219,10 @@ continue_processing:
 
        sm->MICVerified = FALSE;
        if (sm->PTK_valid && !sm->update_snonce) {
-               if (wpa_verify_key_mic(&sm->PTK, data, data_len)) {
+               if (wpa_verify_key_mic(sm->wpa_key_mgmt, &sm->PTK, data,
+                                      data_len) &&
+                   (msg != PAIRWISE_4 || !sm->alt_snonce_valid ||
+                    wpa_try_alt_snonce(sm, data, data_len))) {
                        wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
                                        "received EAPOL-Key with invalid MIC");
                        return;
@@ -1082,7 +1251,7 @@ continue_processing:
                 */
                if (msg == SMK_ERROR) {
 #ifdef CONFIG_PEERKEY
-                       wpa_smk_error(wpa_auth, sm, key);
+                       wpa_smk_error(wpa_auth, sm, key_data, key_data_length);
 #endif /* CONFIG_PEERKEY */
                        return;
                } else if (key_info & WPA_KEY_INFO_ERROR) {
@@ -1097,11 +1266,12 @@ continue_processing:
                        wpa_request_new_ptk(sm);
 #ifdef CONFIG_PEERKEY
                } else if (msg == SMK_M1) {
-                       wpa_smk_m1(wpa_auth, sm, key);
+                       wpa_smk_m1(wpa_auth, sm, key, key_data,
+                                  key_data_length);
 #endif /* CONFIG_PEERKEY */
                } else if (key_data_length > 0 &&
-                          wpa_parse_kde_ies((const u8 *) (key + 1),
-                                            key_data_length, &kde) == 0 &&
+                          wpa_parse_kde_ies(key_data, key_data_length,
+                                            &kde) == 0 &&
                           kde.mac_addr) {
                } else {
                        wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
@@ -1139,7 +1309,7 @@ continue_processing:
 
 #ifdef CONFIG_PEERKEY
        if (msg == SMK_M3) {
-               wpa_smk_m3(wpa_auth, sm, key);
+               wpa_smk_m3(wpa_auth, sm, key, key_data, key_data_length);
                return;
        }
 #endif /* CONFIG_PEERKEY */
@@ -1214,17 +1384,25 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
 {
        struct ieee802_1x_hdr *hdr;
        struct wpa_eapol_key *key;
-       size_t len;
+       struct wpa_eapol_key_192 *key192;
+       size_t len, mic_len, keyhdrlen;
        int alg;
        int key_data_len, pad_len = 0;
        u8 *buf, *pos;
        int version, pairwise;
        int i;
+       u8 *key_data;
+
+       mic_len = wpa_mic_len(sm->wpa_key_mgmt);
+       keyhdrlen = mic_len == 24 ? sizeof(*key192) : sizeof(*key);
 
-       len = sizeof(struct ieee802_1x_hdr) + sizeof(struct wpa_eapol_key);
+       len = sizeof(struct ieee802_1x_hdr) + keyhdrlen;
 
        if (force_version)
                version = force_version;
+       else if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN ||
+                wpa_key_mgmt_suite_b(sm->wpa_key_mgmt))
+               version = WPA_KEY_INFO_TYPE_AKM_DEFINED;
        else if (wpa_use_aes_cmac(sm))
                version = WPA_KEY_INFO_TYPE_AES_128_CMAC;
        else if (sm->pairwise != WPA_CIPHER_TKIP)
@@ -1247,6 +1425,8 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
        key_data_len = kde_len;
 
        if ((version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
+            sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN ||
+            wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) ||
             version == WPA_KEY_INFO_TYPE_AES_128_CMAC) && encr) {
                pad_len = key_data_len % 8;
                if (pad_len)
@@ -1263,6 +1443,8 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
        hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
        hdr->length = host_to_be16(len  - sizeof(*hdr));
        key = (struct wpa_eapol_key *) (hdr + 1);
+       key192 = (struct wpa_eapol_key_192 *) (hdr + 1);
+       key_data = ((u8 *) (hdr + 1)) + keyhdrlen;
 
        key->type = sm->wpa == WPA_VERSION_WPA2 ?
                EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
@@ -1288,6 +1470,8 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
        inc_byte_array(sm->key_replay[0].counter, WPA_REPLAY_COUNTER_LEN);
        os_memcpy(key->replay_counter, sm->key_replay[0].counter,
                  WPA_REPLAY_COUNTER_LEN);
+       wpa_hexdump(MSG_DEBUG, "WPA: Replay Counter",
+                   key->replay_counter, WPA_REPLAY_COUNTER_LEN);
        sm->key_replay[0].valid = TRUE;
 
        if (nonce)
@@ -1297,8 +1481,11 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
                os_memcpy(key->key_rsc, key_rsc, WPA_KEY_RSC_LEN);
 
        if (kde && !encr) {
-               os_memcpy(key + 1, kde, kde_len);
-               WPA_PUT_BE16(key->key_data_length, kde_len);
+               os_memcpy(key_data, kde, kde_len);
+               if (mic_len == 24)
+                       WPA_PUT_BE16(key192->key_data_length, kde_len);
+               else
+                       WPA_PUT_BE16(key->key_data_length, kde_len);
        } else if (encr && kde) {
                buf = os_zalloc(key_data_len);
                if (buf == NULL) {
@@ -1315,29 +1502,47 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
                wpa_hexdump_key(MSG_DEBUG, "Plaintext EAPOL-Key Key Data",
                                buf, key_data_len);
                if (version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
+                   sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN ||
+                   wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) ||
                    version == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
-                       if (aes_wrap(sm->PTK.kek, (key_data_len - 8) / 8, buf,
-                                    (u8 *) (key + 1))) {
+                       if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len,
+                                    (key_data_len - 8) / 8, buf, key_data)) {
                                os_free(hdr);
                                os_free(buf);
                                return;
                        }
-                       WPA_PUT_BE16(key->key_data_length, key_data_len);
-               } else {
+                       if (mic_len == 24)
+                               WPA_PUT_BE16(key192->key_data_length,
+                                            key_data_len);
+                       else
+                               WPA_PUT_BE16(key->key_data_length,
+                                            key_data_len);
+               } else if (sm->PTK.kek_len == 16) {
                        u8 ek[32];
                        os_memcpy(key->key_iv,
                                  sm->group->Counter + WPA_NONCE_LEN - 16, 16);
                        inc_byte_array(sm->group->Counter, WPA_NONCE_LEN);
                        os_memcpy(ek, key->key_iv, 16);
-                       os_memcpy(ek + 16, sm->PTK.kek, 16);
-                       os_memcpy(key + 1, buf, key_data_len);
-                       rc4_skip(ek, 32, 256, (u8 *) (key + 1), key_data_len);
-                       WPA_PUT_BE16(key->key_data_length, key_data_len);
+                       os_memcpy(ek + 16, sm->PTK.kek, sm->PTK.kek_len);
+                       os_memcpy(key_data, buf, key_data_len);
+                       rc4_skip(ek, 32, 256, key_data, key_data_len);
+                       if (mic_len == 24)
+                               WPA_PUT_BE16(key192->key_data_length,
+                                            key_data_len);
+                       else
+                               WPA_PUT_BE16(key->key_data_length,
+                                            key_data_len);
+               } else {
+                       os_free(hdr);
+                       os_free(buf);
+                       return;
                }
                os_free(buf);
        }
 
        if (key_info & WPA_KEY_INFO_MIC) {
+               u8 *key_mic;
+
                if (!sm->PTK_valid) {
                        wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
                                        "PTK not valid when sending EAPOL-Key "
@@ -1345,16 +1550,19 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
                        os_free(hdr);
                        return;
                }
-               wpa_eapol_key_mic(sm->PTK.kck, version, (u8 *) hdr, len,
-                                 key->key_mic);
+
+               key_mic = key192->key_mic; /* same offset for key and key192 */
+               wpa_eapol_key_mic(sm->PTK.kck, sm->PTK.kck_len,
+                                 sm->wpa_key_mgmt, version,
+                                 (u8 *) hdr, len, key_mic);
 #ifdef CONFIG_TESTING_OPTIONS
                if (!pairwise &&
-                   wpa_auth->conf.corrupt_gtk_rekey_mic_probability > 0.0d &&
+                   wpa_auth->conf.corrupt_gtk_rekey_mic_probability > 0.0 &&
                    drand48() <
                    wpa_auth->conf.corrupt_gtk_rekey_mic_probability) {
                        wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
                                        "Corrupting group EAPOL-Key Key MIC");
-                       key->key_mic[0]++;
+                       key_mic[0]++;
                }
 #endif /* CONFIG_TESTING_OPTIONS */
        }
@@ -1398,27 +1606,32 @@ static void wpa_send_eapol(struct wpa_authenticator *wpa_auth,
 }
 
 
-static int wpa_verify_key_mic(struct wpa_ptk *PTK, u8 *data, size_t data_len)
+static int wpa_verify_key_mic(int akmp, struct wpa_ptk *PTK, u8 *data,
+                             size_t data_len)
 {
        struct ieee802_1x_hdr *hdr;
        struct wpa_eapol_key *key;
+       struct wpa_eapol_key_192 *key192;
        u16 key_info;
        int ret = 0;
-       u8 mic[16];
+       u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
+       size_t mic_len = wpa_mic_len(akmp);
 
        if (data_len < sizeof(*hdr) + sizeof(*key))
                return -1;
 
        hdr = (struct ieee802_1x_hdr *) data;
        key = (struct wpa_eapol_key *) (hdr + 1);
+       key192 = (struct wpa_eapol_key_192 *) (hdr + 1);
        key_info = WPA_GET_BE16(key->key_info);
-       os_memcpy(mic, key->key_mic, 16);
-       os_memset(key->key_mic, 0, 16);
-       if (wpa_eapol_key_mic(PTK->kck, key_info & WPA_KEY_INFO_TYPE_MASK,
-                             data, data_len, key->key_mic) ||
-           os_memcmp(mic, key->key_mic, 16) != 0)
+       os_memcpy(mic, key192->key_mic, mic_len);
+       os_memset(key192->key_mic, 0, mic_len);
+       if (wpa_eapol_key_mic(PTK->kck, PTK->kck_len, akmp,
+                             key_info & WPA_KEY_INFO_TYPE_MASK,
+                             data, data_len, key192->key_mic) ||
+           os_memcmp_const(mic, key192->key_mic, mic_len) != 0)
                ret = -1;
-       os_memcpy(key->key_mic, mic, 16);
+       os_memcpy(key192->key_mic, mic, mic_len);
        return ret;
 }
 
@@ -1445,6 +1658,14 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event)
 
        switch (event) {
        case WPA_AUTH:
+#ifdef CONFIG_MESH
+               /* PTKs are derived through AMPE */
+               if (wpa_auth_start_ampe(sm->wpa_auth, sm->addr)) {
+                       /* not mesh */
+                       break;
+               }
+               return 0;
+#endif /* CONFIG_MESH */
        case WPA_ASSOC:
                break;
        case WPA_DEAUTH:
@@ -1658,8 +1879,12 @@ SM_STATE(WPA_PTK, INITPMK)
                }
 #endif /* CONFIG_IEEE80211R */
        } else {
-               wpa_printf(MSG_DEBUG, "WPA: Could not get PMK");
+               wpa_printf(MSG_DEBUG, "WPA: Could not get PMK, get_msk: %p",
+                          sm->wpa_auth->cb.get_msk);
+               sm->Disconnect = TRUE;
+               return;
        }
+       os_memset(msk, 0, sizeof(msk));
 
        sm->req_replay_counter_used = 0;
        /* IEEE 802.11i does not set keyRun to FALSE, but not doing this
@@ -1678,7 +1903,7 @@ SM_STATE(WPA_PTK, INITPSK)
 {
        const u8 *psk;
        SM_ENTRY_MA(WPA_PTK, INITPSK, wpa_ptk);
-       psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, NULL);
+       psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr, NULL);
        if (psk) {
                os_memcpy(sm->PMK, psk, PMK_LEN);
 #ifdef CONFIG_IEEE80211R
@@ -1698,6 +1923,7 @@ SM_STATE(WPA_PTK, PTKSTART)
        SM_ENTRY_MA(WPA_PTK, PTKSTART, wpa_ptk);
        sm->PTKRequest = FALSE;
        sm->TimeoutEvt = FALSE;
+       sm->alt_snonce_valid = FALSE;
 
        sm->TimeoutCtr++;
        if (sm->TimeoutCtr > (int) dot11RSNAConfigPairwiseUpdateCount) {
@@ -1713,16 +1939,20 @@ SM_STATE(WPA_PTK, PTKSTART)
         * one possible PSK for this STA.
         */
        if (sm->wpa == WPA_VERSION_WPA2 &&
-           wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt)) {
+           wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) &&
+           sm->wpa_key_mgmt != WPA_KEY_MGMT_OSEN) {
                pmkid = buf;
                pmkid_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN;
                pmkid[0] = WLAN_EID_VENDOR_SPECIFIC;
                pmkid[1] = RSN_SELECTOR_LEN + PMKID_LEN;
                RSN_SELECTOR_PUT(&pmkid[2], RSN_KEY_DATA_PMKID);
-               if (sm->pmksa)
+               if (sm->pmksa) {
                        os_memcpy(&pmkid[2 + RSN_SELECTOR_LEN],
                                  sm->pmksa->pmkid, PMKID_LEN);
-               else {
+               } else if (wpa_key_mgmt_suite_b(sm->wpa_key_mgmt)) {
+                       /* No KCK available to derive PMKID */
+                       pmkid = NULL;
+               } else {
                        /*
                         * Calculate PMKID since no PMKSA cache entry was
                         * available with pre-calculated PMKID.
@@ -1738,21 +1968,17 @@ SM_STATE(WPA_PTK, PTKSTART)
 }
 
 
-static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *pmk,
-                         struct wpa_ptk *ptk)
+static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
+                         const u8 *pmk, struct wpa_ptk *ptk)
 {
-       size_t ptk_len = sm->pairwise != WPA_CIPHER_TKIP ? 48 : 64;
 #ifdef CONFIG_IEEE80211R
        if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
-               return wpa_auth_derive_ptk_ft(sm, pmk, ptk, ptk_len);
+               return wpa_auth_derive_ptk_ft(sm, pmk, ptk);
 #endif /* CONFIG_IEEE80211R */
 
-       wpa_pmk_to_ptk(pmk, PMK_LEN, "Pairwise key expansion",
-                      sm->wpa_auth->addr, sm->addr, sm->ANonce, sm->SNonce,
-                      (u8 *) ptk, ptk_len,
-                      wpa_key_mgmt_sha256(sm->wpa_key_mgmt));
-
-       return 0;
+       return wpa_pmk_to_ptk(pmk, PMK_LEN, "Pairwise key expansion",
+                             sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce,
+                             ptk, sm->wpa_key_mgmt, sm->pairwise);
 }
 
 
@@ -1771,15 +1997,17 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
         * the packet */
        for (;;) {
                if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
-                       pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, pmk);
+                       pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
+                                              sm->p2p_dev_addr, pmk);
                        if (pmk == NULL)
                                break;
                } else
                        pmk = sm->PMK;
 
-               wpa_derive_ptk(sm, pmk, &PTK);
+               wpa_derive_ptk(sm, sm->SNonce, pmk, &PTK);
 
-               if (wpa_verify_key_mic(&PTK, sm->last_rx_eapol_key,
+               if (wpa_verify_key_mic(sm->wpa_key_mgmt, &PTK,
+                                      sm->last_rx_eapol_key,
                                       sm->last_rx_eapol_key_len) == 0) {
                        ok = 1;
                        break;
@@ -1801,8 +2029,8 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
                 * Verify that PMKR1Name from EAPOL-Key message 2/4 matches
                 * with the value we derived.
                 */
-               if (os_memcmp(sm->sup_pmk_r1_name, sm->pmk_r1_name,
-                             WPA_PMK_NAME_LEN) != 0) {
+               if (os_memcmp_const(sm->sup_pmk_r1_name, sm->pmk_r1_name,
+                                   WPA_PMK_NAME_LEN) != 0) {
                        wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
                                        "PMKR1Name mismatch in FT 4-way "
                                        "handshake");
@@ -1845,7 +2073,9 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING2)
 static int ieee80211w_kde_len(struct wpa_state_machine *sm)
 {
        if (sm->mgmt_frame_prot) {
-               return 2 + RSN_SELECTOR_LEN + sizeof(struct wpa_igtk_kde);
+               size_t len;
+               len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+               return 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN + len;
        }
 
        return 0;
@@ -1856,6 +2086,8 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
 {
        struct wpa_igtk_kde igtk;
        struct wpa_group *gsm = sm->group;
+       u8 rsc[WPA_KEY_RSC_LEN];
+       size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
 
        if (!sm->mgmt_frame_prot)
                return pos;
@@ -1863,19 +2095,22 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
        igtk.keyid[0] = gsm->GN_igtk;
        igtk.keyid[1] = 0;
        if (gsm->wpa_group_state != WPA_GROUP_SETKEYSDONE ||
-           wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, igtk.pn) < 0)
+           wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, rsc) < 0)
                os_memset(igtk.pn, 0, sizeof(igtk.pn));
-       os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN);
+       else
+               os_memcpy(igtk.pn, rsc, sizeof(igtk.pn));
+       os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], len);
        if (sm->wpa_auth->conf.disable_gtk) {
                /*
                 * Provide unique random IGTK to each STA to prevent use of
                 * IGTK in the BSS.
                 */
-               if (random_get_bytes(igtk.igtk, WPA_IGTK_LEN) < 0)
+               if (random_get_bytes(igtk.igtk, len) < 0)
                        return pos;
        }
        pos = wpa_add_kde(pos, RSN_KEY_DATA_IGTK,
-                         (const u8 *) &igtk, sizeof(igtk), NULL, 0);
+                         (const u8 *) &igtk, WPA_IGTK_KDE_PREFIX_LEN + len,
+                         NULL, 0);
 
        return pos;
 }
@@ -1925,8 +2160,10 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
        if (sm->wpa == WPA_VERSION_WPA &&
            (sm->wpa_auth->conf.wpa & WPA_PROTO_RSN) &&
            wpa_ie_len > wpa_ie[1] + 2 && wpa_ie[0] == WLAN_EID_RSN) {
-               /* WPA-only STA, remove RSN IE */
+               /* WPA-only STA, remove RSN IE and possible MDIE */
                wpa_ie = wpa_ie + wpa_ie[1] + 2;
+               if (wpa_ie[0] == WLAN_EID_MOBILITY_DOMAIN)
+                       wpa_ie = wpa_ie + wpa_ie[1] + 2;
                wpa_ie_len = wpa_ie[1] + 2;
        }
        wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
@@ -1980,6 +2217,10 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
                kde_len += 300; /* FTIE + 2 * TIE */
        }
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_P2P
+       if (WPA_GET_BE32(sm->ip_addr) > 0)
+               kde_len += 2 + RSN_SELECTOR_LEN + 3 * 4;
+#endif /* CONFIG_P2P */
        kde = os_malloc(kde_len);
        if (kde == NULL)
                return;
@@ -2041,6 +2282,16 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
                pos += 4;
        }
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_P2P
+       if (WPA_GET_BE32(sm->ip_addr) > 0) {
+               u8 addr[3 * 4];
+               os_memcpy(addr, sm->ip_addr, 4);
+               os_memcpy(addr + 4, sm->wpa_auth->conf.ip_addr_mask, 4);
+               os_memcpy(addr + 8, sm->wpa_auth->conf.ip_addr_go, 4);
+               pos = wpa_add_kde(pos, WFA_KEY_DATA_IP_ADDR_ALLOC,
+                                 addr, sizeof(addr), NULL, 0);
+       }
+#endif /* CONFIG_P2P */
 
        wpa_send_eapol(sm->wpa_auth, sm,
                       (secure ? WPA_KEY_INFO_SECURE : 0) | WPA_KEY_INFO_MIC |
@@ -2059,7 +2310,7 @@ SM_STATE(WPA_PTK, PTKINITDONE)
                enum wpa_alg alg = wpa_cipher_to_alg(sm->pairwise);
                int klen = wpa_cipher_key_len(sm->pairwise);
                if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
-                                    sm->PTK.tk1, klen)) {
+                                    sm->PTK.tk, klen)) {
                        wpa_sta_disconnect(sm->wpa_auth, sm->addr);
                        return;
                }
@@ -2158,7 +2409,8 @@ SM_STEP(WPA_PTK)
                }
                break;
        case WPA_PTK_INITPSK:
-               if (wpa_auth_get_psk(sm->wpa_auth, sm->addr, NULL))
+               if (wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr,
+                                    NULL))
                        SM_ENTER(WPA_PTK, PTKSTART);
                else {
                        wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO,
@@ -2232,7 +2484,8 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
 {
        u8 rsc[WPA_KEY_RSC_LEN];
        struct wpa_group *gsm = sm->group;
-       u8 *kde, *pos, hdr[2];
+       const u8 *kde;
+       u8 *kde_buf = NULL, *pos, hdr[2];
        size_t kde_len;
        u8 *gtk, dummy_gtk[32];
 
@@ -2268,28 +2521,29 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
        if (sm->wpa == WPA_VERSION_WPA2) {
                kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
                        ieee80211w_kde_len(sm);
-               kde = os_malloc(kde_len);
-               if (kde == NULL)
+               kde_buf = os_malloc(kde_len);
+               if (kde_buf == NULL)
                        return;
 
-               pos = kde;
+               kde = pos = kde_buf;
                hdr[0] = gsm->GN & 0x03;
                hdr[1] = 0;
                pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
                                  gtk, gsm->GTK_len);
                pos = ieee80211w_kde_add(sm, pos);
+               kde_len = pos - kde;
        } else {
                kde = gtk;
-               pos = kde + gsm->GTK_len;
+               kde_len = gsm->GTK_len;
        }
 
        wpa_send_eapol(sm->wpa_auth, sm,
                       WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
                       WPA_KEY_INFO_ACK |
                       (!sm->Pair ? WPA_KEY_INFO_INSTALL : 0),
-                      rsc, gsm->GNonce, kde, pos - kde, gsm->GN, 1);
-       if (sm->wpa == WPA_VERSION_WPA2)
-               os_free(kde);
+                      rsc, gsm->GNonce, kde, kde_len, gsm->GN, 1);
+
+       os_free(kde_buf);
 }
 
 
@@ -2366,15 +2620,16 @@ static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
 
 #ifdef CONFIG_IEEE80211W
        if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+               size_t len;
+               len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
                os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
                inc_byte_array(group->Counter, WPA_NONCE_LEN);
                if (wpa_gmk_to_gtk(group->GMK, "IGTK key expansion",
                                   wpa_auth->addr, group->GNonce,
-                                  group->IGTK[group->GN_igtk - 4],
-                                  WPA_IGTK_LEN) < 0)
+                                  group->IGTK[group->GN_igtk - 4], len) < 0)
                        ret = -1;
                wpa_hexdump_key(MSG_DEBUG, "IGTK",
-                               group->IGTK[group->GN_igtk - 4], WPA_IGTK_LEN);
+                               group->IGTK[group->GN_igtk - 4], len);
        }
 #endif /* CONFIG_IEEE80211W */
 
@@ -2441,7 +2696,7 @@ static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
 /* update GTK when exiting WNM-Sleep Mode */
 void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm)
 {
-       if (sm->is_wnmsleep)
+       if (sm == NULL || sm->is_wnmsleep)
                return;
 
        wpa_group_update_sta(sm, NULL);
@@ -2450,7 +2705,8 @@ void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm)
 
 void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag)
 {
-       sm->is_wnmsleep = !!flag;
+       if (sm)
+               sm->is_wnmsleep = !!flag;
 }
 
 
@@ -2490,26 +2746,27 @@ int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)
 {
        struct wpa_group *gsm = sm->group;
        u8 *start = pos;
+       size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
 
        /*
         * IGTK subelement:
         * Sub-elem ID[1] | Length[1] | KeyID[2] | PN[6] | Key[16]
         */
        *pos++ = WNM_SLEEP_SUBELEM_IGTK;
-       *pos++ = 2 + 6 + WPA_IGTK_LEN;
+       *pos++ = 2 + 6 + len;
        WPA_PUT_LE16(pos, gsm->GN_igtk);
        pos += 2;
        if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos) != 0)
                return 0;
        pos += 6;
 
-       os_memcpy(pos, gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN);
-       pos += WPA_IGTK_LEN;
+       os_memcpy(pos, gsm->IGTK[gsm->GN_igtk - 4], len);
+       pos += len;
 
        wpa_printf(MSG_DEBUG, "WNM: IGTK Key ID %u in WNM-Sleep Mode exit",
                   gsm->GN_igtk);
        wpa_hexdump_key(MSG_DEBUG, "WNM: IGTK in WNM-Sleep Mode exit",
-                       gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN);
+                       gsm->IGTK[gsm->GN_igtk - 4], len);
 
        return pos - start;
 }
@@ -2564,18 +2821,48 @@ static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
                ret = -1;
 
 #ifdef CONFIG_IEEE80211W
-       if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION &&
-           wpa_auth_set_key(wpa_auth, group->vlan_id, WPA_ALG_IGTK,
-                            broadcast_ether_addr, group->GN_igtk,
-                            group->IGTK[group->GN_igtk - 4],
-                            WPA_IGTK_LEN) < 0)
-               ret = -1;
+       if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+               enum wpa_alg alg;
+               size_t len;
+
+               alg = wpa_cipher_to_alg(wpa_auth->conf.group_mgmt_cipher);
+               len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher);
+
+               if (ret == 0 &&
+                   wpa_auth_set_key(wpa_auth, group->vlan_id, alg,
+                                    broadcast_ether_addr, group->GN_igtk,
+                                    group->IGTK[group->GN_igtk - 4], len) < 0)
+                       ret = -1;
+       }
 #endif /* CONFIG_IEEE80211W */
 
        return ret;
 }
 
 
+static int wpa_group_disconnect_cb(struct wpa_state_machine *sm, void *ctx)
+{
+       if (sm->group == ctx) {
+               wpa_printf(MSG_DEBUG, "WPA: Mark STA " MACSTR
+                          " for discconnection due to fatal failure",
+                          MAC2STR(sm->addr));
+               sm->Disconnect = TRUE;
+       }
+
+       return 0;
+}
+
+
+static void wpa_group_fatal_failure(struct wpa_authenticator *wpa_auth,
+                                   struct wpa_group *group)
+{
+       wpa_printf(MSG_DEBUG, "WPA: group state machine entering state FATAL_FAILURE");
+       group->changed = TRUE;
+       group->wpa_group_state = WPA_GROUP_FATAL_FAILURE;
+       wpa_auth_for_each_sta(wpa_auth, wpa_group_disconnect_cb, group);
+}
+
+
 static int wpa_group_setkeysdone(struct wpa_authenticator *wpa_auth,
                                 struct wpa_group *group)
 {
@@ -2584,8 +2871,10 @@ static int wpa_group_setkeysdone(struct wpa_authenticator *wpa_auth,
        group->changed = TRUE;
        group->wpa_group_state = WPA_GROUP_SETKEYSDONE;
 
-       if (wpa_group_config_group_keys(wpa_auth, group) < 0)
+       if (wpa_group_config_group_keys(wpa_auth, group) < 0) {
+               wpa_group_fatal_failure(wpa_auth, group);
                return -1;
+       }
 
        return 0;
 }
@@ -2596,6 +2885,8 @@ static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,
 {
        if (group->GInit) {
                wpa_group_gtk_init(wpa_auth, group);
+       } else if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE) {
+               /* Do not allow group operations */
        } else if (group->wpa_group_state == WPA_GROUP_GTK_INIT &&
                   group->GTKAuthenticator) {
                wpa_group_setkeysdone(wpa_auth, group);
@@ -2723,7 +3014,7 @@ int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen)
                          wpa_bool_txt(preauth),
                          wpa_bool_txt(wpa_auth->conf.wpa & WPA_PROTO_RSN),
                          wpa_bool_txt(wpa_auth->conf.rsn_preauth));
-       if (ret < 0 || (size_t) ret >= buflen - len)
+       if (os_snprintf_error(buflen - len, ret))
                return len;
        len += ret;
 
@@ -2773,7 +3064,7 @@ int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen)
                RSN_SUITE_ARG(wpa_auth->dot11RSNAGroupCipherRequested),
                wpa_auth->dot11RSNATKIPCounterMeasuresInvoked,
                wpa_auth->dot11RSNA4WayHandshakeFailures);
-       if (ret < 0 || (size_t) ret >= buflen - len)
+       if (os_snprintf_error(buflen - len, ret))
                return len;
        len += ret;
 
@@ -2783,7 +3074,7 @@ int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen)
        /* Private MIB */
        ret = os_snprintf(buf + len, buflen - len, "hostapdWPAGroupState=%d\n",
                          wpa_auth->group->wpa_group_state);
-       if (ret < 0 || (size_t) ret >= buflen - len)
+       if (os_snprintf_error(buflen - len, ret))
                return len;
        len += ret;
 
@@ -2825,7 +3116,7 @@ int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen)
                RSN_SUITE_ARG(pairwise),
                sm->dot11RSNAStatsTKIPLocalMICFailures,
                sm->dot11RSNAStatsTKIPRemoteMICFailures);
-       if (ret < 0 || (size_t) ret >= buflen - len)
+       if (os_snprintf_error(buflen - len, ret))
                return len;
        len += ret;
 
@@ -2835,7 +3126,7 @@ int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen)
                          "hostapdWPAPTKGroupState=%d\n",
                          sm->wpa_ptk_state,
                          sm->wpa_ptk_group_state);
-       if (ret < 0 || (size_t) ret >= buflen - len)
+       if (os_snprintf_error(buflen - len, ret))
                return len;
        len += ret;
 
@@ -2919,6 +3210,7 @@ int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
                return -1;
 
        if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, PMK_LEN,
+                                sm->PTK.kck, sm->PTK.kck_len,
                                 sm->wpa_auth->addr, sm->addr, session_timeout,
                                 eapol, sm->wpa_key_mgmt))
                return 0;
@@ -2935,7 +3227,9 @@ int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
        if (wpa_auth == NULL)
                return -1;
 
-       if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, len, wpa_auth->addr,
+       if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, len,
+                                NULL, 0,
+                                wpa_auth->addr,
                                 sta_addr, session_timeout, eapol,
                                 WPA_KEY_MGMT_IEEE8021X))
                return 0;
@@ -2944,6 +3238,38 @@ int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
 }
 
 
+int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr,
+                          const u8 *pmk)
+{
+       if (wpa_auth->conf.disable_pmksa_caching)
+               return -1;
+
+       if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, PMK_LEN,
+                                NULL, 0,
+                                wpa_auth->addr, addr, 0, NULL,
+                                WPA_KEY_MGMT_SAE))
+               return 0;
+
+       return -1;
+}
+
+
+void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
+                          const u8 *sta_addr)
+{
+       struct rsn_pmksa_cache_entry *pmksa;
+
+       if (wpa_auth == NULL || wpa_auth->pmksa == NULL)
+               return;
+       pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sta_addr, NULL);
+       if (pmksa) {
+               wpa_printf(MSG_DEBUG, "WPA: Remove PMKSA cache entry for "
+                          MACSTR " based on request", MAC2STR(sta_addr));
+               pmksa_cache_free_entry(wpa_auth->pmksa, pmksa);
+       }
+}
+
+
 static struct wpa_group *
 wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id)
 {
@@ -2988,6 +3314,9 @@ int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id)
        if (sm->group == group)
                return 0;
 
+       if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE)
+               return -1;
+
        wpa_printf(MSG_DEBUG, "WPA: Moving STA " MACSTR " to use group state "
                   "machine for VLAN ID %d", MAC2STR(sm->addr), vlan_id);
 
@@ -3032,3 +3361,29 @@ int wpa_auth_uses_sae(struct wpa_state_machine *sm)
                return 0;
        return wpa_key_mgmt_sae(sm->wpa_key_mgmt);
 }
+
+
+int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm)
+{
+       if (sm == NULL)
+               return 0;
+       return sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_SAE;
+}
+
+
+#ifdef CONFIG_P2P
+int wpa_auth_get_ip_addr(struct wpa_state_machine *sm, u8 *addr)
+{
+       if (sm == NULL || WPA_GET_BE32(sm->ip_addr) == 0)
+               return -1;
+       os_memcpy(addr, sm->ip_addr, 4);
+       return 0;
+}
+#endif /* CONFIG_P2P */
+
+
+int wpa_auth_radius_das_disconnect_pmksa(struct wpa_authenticator *wpa_auth,
+                                        struct radius_das_attrs *attr)
+{
+       return pmksa_cache_auth_radius_das_disconnect(wpa_auth->pmksa, attr);
+}