]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - src/ap/wpa_auth.c
Allow RSNE in EAPOL-Key msg 3/4 to be replaced for testing purposes
[thirdparty/hostap.git] / src / ap / wpa_auth.c
index 34969e79e46ff6aa61b207a61d85f3d9e58875ce..ab20705f0f3b0bb71723d25844944c5f9844043d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * IEEE 802.11 RSN / WPA Authenticator
- * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -13,6 +13,7 @@
 #include "utils/state_machine.h"
 #include "utils/bitfield.h"
 #include "common/ieee802_11_defs.h"
+#include "common/ocv.h"
 #include "crypto/aes.h"
 #include "crypto/aes_wrap.h"
 #include "crypto/aes_siv.h"
@@ -22,6 +23,7 @@
 #include "crypto/sha384.h"
 #include "crypto/random.h"
 #include "eapol_auth/eapol_auth_sm.h"
+#include "drivers/driver.h"
 #include "ap_config.h"
 #include "ieee802_11.h"
 #include "wpa_auth.h"
@@ -54,13 +56,14 @@ 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, unsigned int pmk_len,
-                         struct wpa_ptk *ptk);
+                         struct wpa_ptk *ptk, int force_sha256);
 static void wpa_group_free(struct wpa_authenticator *wpa_auth,
                           struct wpa_group *group);
 static void wpa_group_get(struct wpa_authenticator *wpa_auth,
                          struct wpa_group *group);
 static void wpa_group_put(struct wpa_authenticator *wpa_auth,
                          struct wpa_group *group);
+static int ieee80211w_kde_len(struct wpa_state_machine *sm);
 static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos);
 
 static const u32 eapol_key_timeout_first = 100; /* ms */
@@ -112,12 +115,13 @@ 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 *p2p_dev_addr,
-                                         const u8 *prev_psk, size_t *psk_len)
+                                         const u8 *prev_psk, size_t *psk_len,
+                                         int *vlan_id)
 {
        if (wpa_auth->cb->get_psk == NULL)
                return NULL;
        return wpa_auth->cb->get_psk(wpa_auth->cb_ctx, addr, p2p_dev_addr,
-                                    prev_psk, psk_len);
+                                    prev_psk, psk_len, vlan_id);
 }
 
 
@@ -133,21 +137,46 @@ static inline int wpa_auth_get_msk(struct wpa_authenticator *wpa_auth,
 static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
                                   int vlan_id,
                                   enum wpa_alg alg, const u8 *addr, int idx,
-                                  u8 *key, size_t key_len)
+                                  u8 *key, size_t key_len,
+                                  enum key_flag key_flag)
 {
        if (wpa_auth->cb->set_key == NULL)
                return -1;
        return wpa_auth->cb->set_key(wpa_auth->cb_ctx, vlan_id, alg, addr, idx,
-                                    key, key_len);
+                                    key, key_len, key_flag);
 }
 
 
 static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,
                                      const u8 *addr, int idx, u8 *seq)
 {
+       int res;
+
        if (wpa_auth->cb->get_seqnum == NULL)
                return -1;
-       return wpa_auth->cb->get_seqnum(wpa_auth->cb_ctx, addr, idx, seq);
+       res = wpa_auth->cb->get_seqnum(wpa_auth->cb_ctx, addr, idx, seq);
+#ifdef CONFIG_TESTING_OPTIONS
+       if (!addr && idx < 4 && wpa_auth->conf.gtk_rsc_override_set) {
+               wpa_printf(MSG_DEBUG,
+                          "TESTING: Override GTK RSC %016llx --> %016llx",
+                          (long long unsigned) WPA_GET_LE64(seq),
+                          (long long unsigned)
+                          WPA_GET_LE64(wpa_auth->conf.gtk_rsc_override));
+               os_memcpy(seq, wpa_auth->conf.gtk_rsc_override,
+                         WPA_KEY_RSC_LEN);
+       }
+       if (!addr && idx >= 4 && idx <= 5 &&
+           wpa_auth->conf.igtk_rsc_override_set) {
+               wpa_printf(MSG_DEBUG,
+                          "TESTING: Override IGTK RSC %016llx --> %016llx",
+                          (long long unsigned) WPA_GET_LE64(seq),
+                          (long long unsigned)
+                          WPA_GET_LE64(wpa_auth->conf.igtk_rsc_override));
+               os_memcpy(seq, wpa_auth->conf.igtk_rsc_override,
+                         WPA_KEY_RSC_LEN);
+       }
+#endif /* CONFIG_TESTING_OPTIONS */
+       return res;
 }
 
 
@@ -238,6 +267,26 @@ static void wpa_sta_disconnect(struct wpa_authenticator *wpa_auth,
 }
 
 
+#ifdef CONFIG_OCV
+static int wpa_channel_info(struct wpa_authenticator *wpa_auth,
+                           struct wpa_channel_info *ci)
+{
+       if (!wpa_auth->cb->channel_info)
+               return -1;
+       return wpa_auth->cb->channel_info(wpa_auth->cb_ctx, ci);
+}
+#endif /* CONFIG_OCV */
+
+
+static int wpa_auth_update_vlan(struct wpa_authenticator *wpa_auth,
+                               const u8 *addr, int vlan_id)
+{
+       if (!wpa_auth->cb->update_vlan)
+               return -1;
+       return wpa_auth->cb->update_vlan(wpa_auth->cb_ctx, addr, vlan_id);
+}
+
+
 static void wpa_rekey_gmk(void *eloop_ctx, void *timeout_ctx)
 {
        struct wpa_authenticator *wpa_auth = eloop_ctx;
@@ -297,6 +346,19 @@ static void wpa_rekey_ptk(void *eloop_ctx, void *timeout_ctx)
 }
 
 
+void wpa_auth_set_ptk_rekey_timer(struct wpa_state_machine *sm)
+{
+       if (sm && sm->wpa_auth->conf.wpa_ptk_rekey) {
+               wpa_printf(MSG_DEBUG, "WPA: Start PTK rekeying timer for "
+                          MACSTR " (%d seconds)", MAC2STR(sm->addr),
+                          sm->wpa_auth->conf.wpa_ptk_rekey);
+               eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
+               eloop_register_timeout(sm->wpa_auth->conf.wpa_ptk_rekey, 0,
+                                      wpa_rekey_ptk, sm->wpa_auth, sm);
+       }
+}
+
+
 static int wpa_auth_pmksa_clear_cb(struct wpa_state_machine *sm, void *ctx)
 {
        if (sm->pmksa == ctx)
@@ -332,6 +394,10 @@ static int wpa_group_init_gmk_and_counter(struct wpa_authenticator *wpa_auth,
        wpa_get_ntp_timestamp(buf + ETH_ALEN);
        ptr = (unsigned long) group;
        os_memcpy(buf + ETH_ALEN + 8, &ptr, sizeof(ptr));
+#ifdef TEST_FUZZ
+       os_memset(buf + ETH_ALEN, 0xab, 8);
+       os_memset(buf + ETH_ALEN + 8, 0xcd, sizeof(ptr));
+#endif /* TEST_FUZZ */
        if (random_get_bytes(rkey, sizeof(rkey)) < 0)
                return -1;
 
@@ -668,8 +734,12 @@ static void wpa_free_sta_sm(struct wpa_state_machine *sm)
 #endif /* CONFIG_IEEE80211R_AP */
        os_free(sm->last_rx_eapol_key);
        os_free(sm->wpa_ie);
+       os_free(sm->rsnxe);
        wpa_group_put(sm->wpa_auth, sm->group);
-       os_free(sm);
+#ifdef CONFIG_DPP2
+       wpabuf_clear_free(sm->dpp_z);
+#endif /* CONFIG_DPP2 */
+       bin_clear_free(sm, sizeof(*sm));
 }
 
 
@@ -711,8 +781,18 @@ static void wpa_request_new_ptk(struct wpa_state_machine *sm)
        if (sm == NULL)
                return;
 
-       sm->PTKRequest = TRUE;
-       sm->PTK_valid = 0;
+       if (sm->wpa_auth->conf.wpa_deny_ptk0_rekey) {
+               wpa_printf(MSG_INFO,
+                          "WPA: PTK0 rekey not allowed, disconnect " MACSTR,
+                          MAC2STR(sm->addr));
+               sm->Disconnect = TRUE;
+               /* Try to encourage the STA to reconnect */
+               sm->disconnect_reason =
+                       WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA;
+       } else {
+               sm->PTKRequest = TRUE;
+               sm->PTK_valid = 0;
+       }
 }
 
 
@@ -835,13 +915,15 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
        int ok = 0;
        const u8 *pmk = NULL;
        size_t pmk_len;
+       int vlan_id = 0;
 
        os_memset(&PTK, 0, sizeof(PTK));
        for (;;) {
                if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
                    !wpa_key_mgmt_sae(sm->wpa_key_mgmt)) {
                        pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
-                                              sm->p2p_dev_addr, pmk, &pmk_len);
+                                              sm->p2p_dev_addr, pmk, &pmk_len,
+                                              &vlan_id);
                        if (pmk == NULL)
                                break;
 #ifdef CONFIG_IEEE80211R_AP
@@ -855,11 +937,16 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
                        pmk_len = sm->pmk_len;
                }
 
-               if (wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK) < 0)
+               if (wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK, 0) <
+                   0)
                        break;
 
                if (wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK,
                                       data, data_len) == 0) {
+                       if (sm->PMK != pmk) {
+                               os_memcpy(sm->PMK, pmk, pmk_len);
+                               sm->pmk_len = pmk_len;
+                       }
                        ok = 1;
                        break;
                }
@@ -878,8 +965,14 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
        wpa_printf(MSG_DEBUG,
                   "WPA: Earlier SNonce resulted in matching MIC");
        sm->alt_snonce_valid = 0;
+
+       if (vlan_id && wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
+           wpa_auth_update_vlan(sm->wpa_auth, sm->addr, vlan_id) < 0)
+               return -1;
+
        os_memcpy(sm->SNonce, sm->alt_SNonce, WPA_NONCE_LEN);
        os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
+       forced_memzero(&PTK, sizeof(PTK));
        sm->PTK_valid = TRUE;
 
        return 0;
@@ -1202,6 +1295,11 @@ continue_processing:
                     wpa_try_alt_snonce(sm, data, data_len))) {
                        wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
                                        "received EAPOL-Key with invalid MIC");
+#ifdef TEST_FUZZ
+                       wpa_printf(MSG_INFO,
+                                  "TEST: Ignore Key MIC failure for fuzz testing");
+                       goto continue_fuzz;
+#endif /* TEST_FUZZ */
                        return;
                }
 #ifdef CONFIG_FILS
@@ -1210,9 +1308,17 @@ continue_processing:
                                     &key_data_length) < 0) {
                        wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
                                        "received EAPOL-Key with invalid MIC");
+#ifdef TEST_FUZZ
+                       wpa_printf(MSG_INFO,
+                                  "TEST: Ignore Key MIC failure for fuzz testing");
+                       goto continue_fuzz;
+#endif /* TEST_FUZZ */
                        return;
                }
 #endif /* CONFIG_FILS */
+#ifdef TEST_FUZZ
+       continue_fuzz:
+#endif /* TEST_FUZZ */
                sm->MICVerified = TRUE;
                eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
                sm->pending_1_of_4_timeout = 0;
@@ -1317,6 +1423,9 @@ static int wpa_gmk_to_gtk(const u8 *gmk, const char *label, const u8 *addr,
        os_memcpy(data + ETH_ALEN, gnonce, WPA_NONCE_LEN);
        pos = data + ETH_ALEN + WPA_NONCE_LEN;
        wpa_get_ntp_timestamp(pos);
+#ifdef TEST_FUZZ
+       os_memset(pos, 0xef, 8);
+#endif /* TEST_FUZZ */
        pos += 8;
        if (random_get_bytes(pos, gtk_len) < 0)
                ret = -1;
@@ -1337,6 +1446,8 @@ static int wpa_gmk_to_gtk(const u8 *gmk, const char *label, const u8 *addr,
 #endif /* CONFIG_SHA256 */
 #endif /* CONFIG_SHA384 */
 
+       forced_memzero(data, sizeof(data));
+
        return ret;
 }
 
@@ -1596,6 +1707,9 @@ static void wpa_send_eapol(struct wpa_authenticator *wpa_auth,
                timeout_ms = eapol_key_timeout_no_retrans;
        if (pairwise && ctr == 1 && !(key_info & WPA_KEY_INFO_MIC))
                sm->pending_1_of_4_timeout = 1;
+#ifdef TEST_FUZZ
+       timeout_ms = 1;
+#endif /* TEST_FUZZ */
        wpa_printf(MSG_DEBUG, "WPA: Use EAPOL-Key timeout of %u ms (retry "
                   "counter %u)", timeout_ms, ctr);
        eloop_register_timeout(timeout_ms / 1000, (timeout_ms % 1000) * 1000,
@@ -1637,7 +1751,7 @@ void wpa_remove_ptk(struct wpa_state_machine *sm)
        sm->PTK_valid = FALSE;
        os_memset(&sm->PTK, 0, sizeof(sm->PTK));
        if (wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 0, NULL,
-                            0))
+                            0, KEY_FLAG_PAIRWISE))
                wpa_printf(MSG_DEBUG,
                           "RSN: PTK removal from the driver failed");
        sm->pairwise_set = FALSE;
@@ -1670,6 +1784,14 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
        case WPA_DEAUTH:
        case WPA_DISASSOC:
                sm->DeauthenticationRequest = TRUE;
+#ifdef CONFIG_IEEE80211R_AP
+               os_memset(sm->PMK, 0, sizeof(sm->PMK));
+               sm->pmk_len = 0;
+               os_memset(sm->xxkey, 0, sizeof(sm->xxkey));
+               sm->xxkey_len = 0;
+               os_memset(sm->pmk_r1, 0, sizeof(sm->pmk_r1));
+               sm->pmk_r1_len = 0;
+#endif /* CONFIG_IEEE80211R_AP */
                break;
        case WPA_REAUTH:
        case WPA_REAUTH_EAPOL:
@@ -1690,6 +1812,15 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
                        sm->Init = FALSE;
                        sm->AuthenticationRequest = TRUE;
                        break;
+               } else if (sm->wpa_auth->conf.wpa_deny_ptk0_rekey) {
+                       wpa_printf(MSG_INFO,
+                                  "WPA: PTK0 rekey not allowed, disconnect "
+                                  MACSTR, MAC2STR(sm->addr));
+                       sm->Disconnect = TRUE;
+                       /* Try to encourage the STA reconnect */
+                       sm->disconnect_reason =
+                               WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA;
+                       break;
                }
                if (sm->GUpdateStationKeys) {
                        /*
@@ -1710,6 +1841,7 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
 
                /* Using FT protocol, not WPA auth state machine */
                sm->ft_completed = 1;
+               wpa_auth_set_ptk_rekey_timer(sm);
                return 0;
 #else /* CONFIG_IEEE80211R_AP */
                break;
@@ -1733,10 +1865,8 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
        sm->ft_completed = 0;
 #endif /* CONFIG_IEEE80211R_AP */
 
-#ifdef CONFIG_IEEE80211W
        if (sm->mgmt_frame_prot && event == WPA_AUTH)
                remove_ptk = 0;
-#endif /* CONFIG_IEEE80211W */
 #ifdef CONFIG_FILS
        if (wpa_key_mgmt_fils(sm->wpa_key_mgmt) &&
            (event == WPA_AUTH || event == WPA_ASSOC))
@@ -1964,7 +2094,7 @@ SM_STATE(WPA_PTK, INITPMK)
                sm->Disconnect = TRUE;
                return;
        }
-       os_memset(msk, 0, sizeof(msk));
+       forced_memzero(msk, sizeof(msk));
 
        sm->req_replay_counter_used = 0;
        /* IEEE 802.11i does not set keyRun to FALSE, but not doing this
@@ -1986,7 +2116,7 @@ SM_STATE(WPA_PTK, INITPSK)
 
        SM_ENTRY_MA(WPA_PTK, INITPSK, wpa_ptk);
        psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr, NULL,
-                              &psk_len);
+                              &psk_len, NULL);
        if (psk) {
                os_memcpy(sm->PMK, psk, psk_len);
                sm->pmk_len = psk_len;
@@ -2000,6 +2130,10 @@ SM_STATE(WPA_PTK, INITPSK)
                wpa_printf(MSG_DEBUG, "SAE: PMK from PMKSA cache");
                os_memcpy(sm->PMK, sm->pmksa->pmk, sm->pmksa->pmk_len);
                sm->pmk_len = sm->pmksa->pmk_len;
+#ifdef CONFIG_IEEE80211R_AP
+               os_memcpy(sm->xxkey, sm->pmksa->pmk, sm->pmksa->pmk_len);
+               sm->xxkey_len = sm->pmksa->pmk_len;
+#endif /* CONFIG_IEEE80211R_AP */
        }
 #endif /* CONFIG_SAE */
        sm->req_replay_counter_used = 0;
@@ -2060,6 +2194,28 @@ SM_STATE(WPA_PTK, PTKSTART)
                        wpa_printf(MSG_DEBUG,
                                   "RSN: No KCK available to derive PMKID for message 1/4");
                        pmkid = NULL;
+#ifdef CONFIG_FILS
+               } else if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
+                       if (sm->pmkid_set) {
+                               wpa_hexdump(MSG_DEBUG,
+                                           "RSN: Message 1/4 PMKID from FILS/ERP",
+                                           sm->pmkid, PMKID_LEN);
+                               os_memcpy(&pmkid[2 + RSN_SELECTOR_LEN],
+                                         sm->pmkid, PMKID_LEN);
+                       } else {
+                               /* No PMKID available */
+                               wpa_printf(MSG_DEBUG,
+                                          "RSN: No FILS/ERP PMKID available for message 1/4");
+                               pmkid = NULL;
+                       }
+#endif /* CONFIG_FILS */
+#ifdef CONFIG_IEEE80211R_AP
+               } else if (wpa_key_mgmt_ft(sm->wpa_key_mgmt) &&
+                          sm->ft_completed) {
+                       wpa_printf(MSG_DEBUG,
+                                  "FT: No PMKID in message 1/4 when using FT protocol");
+                       pmkid = NULL;
+#endif /* CONFIG_IEEE80211R_AP */
 #ifdef CONFIG_SAE
                } else if (wpa_key_mgmt_sae(sm->wpa_key_mgmt)) {
                        if (sm->pmkid_set) {
@@ -2088,6 +2244,8 @@ SM_STATE(WPA_PTK, PTKSTART)
                                    &pmkid[2 + RSN_SELECTOR_LEN], PMKID_LEN);
                }
        }
+       if (!pmkid)
+               pmkid_len = 0;
        wpa_send_eapol(sm->wpa_auth, sm,
                       WPA_KEY_INFO_ACK | WPA_KEY_INFO_KEY_TYPE, NULL,
                       sm->ANonce, pmkid, pmkid_len, 0, 0);
@@ -2096,16 +2254,42 @@ SM_STATE(WPA_PTK, PTKSTART)
 
 static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
                          const u8 *pmk, unsigned int pmk_len,
-                         struct wpa_ptk *ptk)
+                         struct wpa_ptk *ptk, int force_sha256)
 {
+       const u8 *z = NULL;
+       size_t z_len = 0;
+       int akmp;
+
 #ifdef CONFIG_IEEE80211R_AP
-       if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
-               return wpa_auth_derive_ptk_ft(sm, pmk, ptk);
+       if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
+               if (sm->ft_completed) {
+                       u8 ptk_name[WPA_PMK_NAME_LEN];
+
+                       return wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->pmk_r1_len,
+                                                sm->SNonce, sm->ANonce,
+                                                sm->addr, sm->wpa_auth->addr,
+                                                sm->pmk_r1_name,
+                                                ptk, ptk_name,
+                                                sm->wpa_key_mgmt,
+                                                sm->pairwise);
+               }
+               return wpa_auth_derive_ptk_ft(sm, ptk);
+       }
 #endif /* CONFIG_IEEE80211R_AP */
 
+#ifdef CONFIG_DPP2
+       if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP && sm->dpp_z) {
+               z = wpabuf_head(sm->dpp_z);
+               z_len = wpabuf_len(sm->dpp_z);
+       }
+#endif /* CONFIG_DPP2 */
+
+       akmp = sm->wpa_key_mgmt;
+       if (force_sha256)
+               akmp |= WPA_KEY_MGMT_PSK_SHA256;
        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);
+                             ptk, akmp, sm->pairwise, z, z_len);
 }
 
 
@@ -2154,7 +2338,17 @@ int fils_auth_pmk_to_ptk(struct wpa_state_machine *sm, const u8 *pmk,
                wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR0Name",
                            pmk_r0_name, WPA_PMK_NAME_LEN);
                wpa_ft_store_pmk_fils(sm, pmk_r0, pmk_r0_name);
-               os_memset(fils_ft, 0, sizeof(fils_ft));
+               forced_memzero(fils_ft, sizeof(fils_ft));
+
+               res = wpa_derive_pmk_r1_name(pmk_r0_name, conf->r1_key_holder,
+                                            sm->addr, sm->pmk_r1_name,
+                                            use_sha384);
+               forced_memzero(pmk_r0, PMK_LEN_MAX);
+               if (res < 0)
+                       return -1;
+               wpa_hexdump(MSG_DEBUG, "FILS+FT: PMKR1Name", sm->pmk_r1_name,
+                           WPA_PMK_NAME_LEN);
+               sm->pmk_r1_name_valid = 1;
        }
 #endif /* CONFIG_IEEE80211R_AP */
 
@@ -2167,7 +2361,7 @@ int fils_auth_pmk_to_ptk(struct wpa_state_machine *sm, const u8 *pmk,
                               sm->wpa_key_mgmt, sm->fils_key_auth_sta,
                               sm->fils_key_auth_ap,
                               &sm->fils_key_auth_len);
-       os_memset(ick, 0, sizeof(ick));
+       forced_memzero(ick, sizeof(ick));
 
        /* Store nonces for (Re)Association Request/Response frame processing */
        os_memcpy(sm->SNonce, snonce, FILS_NONCE_LEN);
@@ -2469,7 +2663,7 @@ int fils_encrypt_assoc(struct wpa_state_machine *sm, u8 *buf,
        if (pos + wpabuf_len(plain) + AES_BLOCK_SIZE > end) {
                wpa_printf(MSG_DEBUG,
                           "FILS: Not enough room for FILS elements");
-               wpabuf_free(plain);
+               wpabuf_clear_free(plain);
                return -1;
        }
 
@@ -2479,7 +2673,7 @@ int fils_encrypt_assoc(struct wpa_state_machine *sm, u8 *buf,
        if (aes_siv_encrypt(sm->PTK.kek, sm->PTK.kek_len,
                            wpabuf_head(plain), wpabuf_len(plain),
                            5, aad, aad_len, pos) < 0) {
-               wpabuf_free(plain);
+               wpabuf_clear_free(plain);
                return -1;
        }
 
@@ -2487,7 +2681,7 @@ int fils_encrypt_assoc(struct wpa_state_machine *sm, u8 *buf,
                    "FILS: Encrypted Association Response elements",
                    pos, AES_BLOCK_SIZE + wpabuf_len(plain));
        current_len += wpabuf_len(plain) + AES_BLOCK_SIZE;
-       wpabuf_free(plain);
+       wpabuf_clear_free(plain);
 
        sm->fils_completed = 1;
 
@@ -2505,7 +2699,7 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
        size_t gtk_len;
        struct wpa_group *gsm;
 
-       plain = wpabuf_alloc(1000);
+       plain = wpabuf_alloc(1000 + ieee80211w_kde_len(sm));
        if (!plain)
                return NULL;
 
@@ -2541,7 +2735,7 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
                 * of GTK in the BSS.
                 */
                if (random_get_bytes(dummy_gtk, gtk_len) < 0) {
-                       wpabuf_free(plain);
+                       wpabuf_clear_free(plain);
                        return NULL;
                }
                gtk = dummy_gtk;
@@ -2553,12 +2747,33 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
                           gtk, gtk_len);
        wpabuf_put(plain, tmp2 - tmp);
 
-       /* IGTK KDE */
+       /* IGTK KDE and BIGTK KDE */
        tmp = wpabuf_put(plain, 0);
        tmp2 = ieee80211w_kde_add(sm, tmp);
        wpabuf_put(plain, tmp2 - tmp);
 
        *len = (u8 *) wpabuf_put(plain, 0) - len - 1;
+
+#ifdef CONFIG_OCV
+       if (wpa_auth_uses_ocv(sm)) {
+               struct wpa_channel_info ci;
+               u8 *pos;
+
+               if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
+                       wpa_printf(MSG_WARNING,
+                                  "FILS: Failed to get channel info for OCI element");
+                       wpabuf_clear_free(plain);
+                       return NULL;
+               }
+
+               pos = wpabuf_put(plain, OCV_OCI_EXTENDED_LEN);
+               if (ocv_insert_extended_oci(&ci, pos) < 0) {
+                       wpabuf_clear_free(plain);
+                       return NULL;
+               }
+       }
+#endif /* CONFIG_OCV */
+
        return plain;
 }
 
@@ -2582,7 +2797,7 @@ int fils_set_tk(struct wpa_state_machine *sm)
 
        wpa_printf(MSG_DEBUG, "FILS: Configure TK to the driver");
        if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
-                            sm->PTK.tk, klen)) {
+                            sm->PTK.tk, klen, KEY_FLAG_PAIRWISE_RX_TX)) {
                wpa_printf(MSG_DEBUG, "FILS: Failed to set TK to the driver");
                return -1;
        }
@@ -2616,7 +2831,7 @@ u8 * hostapd_eid_assoc_fils_session(struct wpa_state_machine *sm, u8 *buf,
 
        wpa_printf(MSG_DEBUG, "%s: plain buf_len: %u", __func__,
                   (unsigned int) wpabuf_len(plain));
-       wpabuf_free(plain);
+       wpabuf_clear_free(plain);
        sm->fils_completed = 1;
        return pos;
 }
@@ -2624,6 +2839,21 @@ u8 * hostapd_eid_assoc_fils_session(struct wpa_state_machine *sm, u8 *buf,
 #endif /* CONFIG_FILS */
 
 
+#ifdef CONFIG_OCV
+int get_sta_tx_parameters(struct wpa_state_machine *sm, int ap_max_chanwidth,
+                         int ap_seg1_idx, int *bandwidth, int *seg1_idx)
+{
+       struct wpa_authenticator *wpa_auth = sm->wpa_auth;
+
+       if (!wpa_auth->cb->get_sta_tx_params)
+               return -1;
+       return wpa_auth->cb->get_sta_tx_params(wpa_auth->cb_ctx, sm->addr,
+                                              ap_max_chanwidth, ap_seg1_idx,
+                                              bandwidth, seg1_idx);
+}
+#endif /* CONFIG_OCV */
+
+
 SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
 {
        struct wpa_authenticator *wpa_auth = sm->wpa_auth;
@@ -2638,6 +2868,8 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
        struct ieee802_1x_hdr *hdr;
        struct wpa_eapol_key *key;
        struct wpa_eapol_ie_parse kde;
+       int vlan_id = 0;
+       int owe_ptk_workaround = !!wpa_auth->conf.owe_ptk_workaround;
 
        SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
        sm->EAPOLKeyReceived = FALSE;
@@ -2653,7 +2885,8 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
                if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
                    !wpa_key_mgmt_sae(sm->wpa_key_mgmt)) {
                        pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
-                                              sm->p2p_dev_addr, pmk, &pmk_len);
+                                              sm->p2p_dev_addr, pmk, &pmk_len,
+                                              &vlan_id);
                        if (pmk == NULL)
                                break;
                        psk_found = 1;
@@ -2668,13 +2901,24 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
                        pmk_len = sm->pmk_len;
                }
 
-               if (wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK) < 0)
+               if ((!pmk || !pmk_len) && sm->pmksa) {
+                       wpa_printf(MSG_DEBUG, "WPA: Use PMK from PMKSA cache");
+                       pmk = sm->pmksa->pmk;
+                       pmk_len = sm->pmksa->pmk_len;
+               }
+
+               if (wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK,
+                                  owe_ptk_workaround == 2) < 0)
                        break;
 
                if (mic_len &&
                    wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK,
                                       sm->last_rx_eapol_key,
                                       sm->last_rx_eapol_key_len) == 0) {
+                       if (sm->PMK != pmk) {
+                               os_memcpy(sm->PMK, pmk, pmk_len);
+                               sm->pmk_len = pmk_len;
+                       }
                        ok = 1;
                        break;
                }
@@ -2688,6 +2932,16 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
                }
 #endif /* CONFIG_FILS */
 
+#ifdef CONFIG_OWE
+               if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE && pmk_len > 32 &&
+                   owe_ptk_workaround == 1) {
+                       wpa_printf(MSG_DEBUG,
+                                  "OWE: Try PTK derivation workaround with SHA256");
+                       owe_ptk_workaround = 2;
+                       continue;
+               }
+#endif /* CONFIG_OWE */
+
                if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
                    wpa_key_mgmt_sae(sm->wpa_key_mgmt))
                        break;
@@ -2746,6 +3000,48 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
                                   WLAN_REASON_PREV_AUTH_NOT_VALID);
                return;
        }
+       if ((!sm->rsnxe && kde.rsnxe) ||
+           (sm->rsnxe && !kde.rsnxe) ||
+           (sm->rsnxe && kde.rsnxe &&
+            (sm->rsnxe_len != kde.rsnxe_len ||
+             os_memcmp(sm->rsnxe, kde.rsnxe, sm->rsnxe_len) != 0))) {
+               wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+                               "RSNXE from (Re)AssocReq did not match the one in EAPOL-Key msg 2/4");
+               wpa_hexdump(MSG_DEBUG, "RSNXE in AssocReq",
+                           sm->rsnxe, sm->rsnxe_len);
+               wpa_hexdump(MSG_DEBUG, "RSNXE in EAPOL-Key msg 2/4",
+                           kde.rsnxe, kde.rsnxe_len);
+               /* MLME-DEAUTHENTICATE.request */
+               wpa_sta_disconnect(wpa_auth, sm->addr,
+                                  WLAN_REASON_PREV_AUTH_NOT_VALID);
+               return;
+       }
+#ifdef CONFIG_OCV
+       if (wpa_auth_uses_ocv(sm)) {
+               struct wpa_channel_info ci;
+               int tx_chanwidth;
+               int tx_seg1_idx;
+
+               if (wpa_channel_info(wpa_auth, &ci) != 0) {
+                       wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+                                       "Failed to get channel info to validate received OCI in EAPOL-Key 2/4");
+                       return;
+               }
+
+               if (get_sta_tx_parameters(sm,
+                                         channel_width_to_int(ci.chanwidth),
+                                         ci.seg1_idx, &tx_chanwidth,
+                                         &tx_seg1_idx) < 0)
+                       return;
+
+               if (ocv_verify_tx_params(kde.oci, kde.oci_len, &ci,
+                                        tx_chanwidth, tx_seg1_idx) != 0) {
+                       wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+                                       ocv_errorstr);
+                       return;
+               }
+       }
+#endif /* CONFIG_OCV */
 #ifdef CONFIG_IEEE80211R_AP
        if (ft && ft_check_msg_2_of_4(wpa_auth, sm, &kde) < 0) {
                wpa_sta_disconnect(wpa_auth, sm->addr,
@@ -2794,6 +3090,13 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
        }
 #endif /* CONFIG_IEEE80211R_AP */
 
+       if (vlan_id && wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) &&
+           wpa_auth_update_vlan(wpa_auth, sm->addr, vlan_id) < 0) {
+               wpa_sta_disconnect(wpa_auth, sm->addr,
+                                  WLAN_REASON_PREV_AUTH_NOT_VALID);
+               return;
+       }
+
        sm->pending_1_of_4_timeout = 0;
        eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
 
@@ -2808,6 +3111,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
        sm->MICVerified = TRUE;
 
        os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
+       forced_memzero(&PTK, sizeof(PTK));
        sm->PTK_valid = TRUE;
 }
 
@@ -2819,23 +3123,27 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING2)
 }
 
 
-#ifdef CONFIG_IEEE80211W
-
 static int ieee80211w_kde_len(struct wpa_state_machine *sm)
 {
+       size_t len = 0;
+
        if (sm->mgmt_frame_prot) {
-               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;
+               len += 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN;
+               len += wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
+       }
+       if (sm->mgmt_frame_prot && sm->wpa_auth->conf.beacon_prot) {
+               len += 2 + RSN_SELECTOR_LEN + WPA_BIGTK_KDE_PREFIX_LEN;
+               len += wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
        }
 
-       return 0;
+       return len;
 }
 
 
 static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
 {
        struct wpa_igtk_kde igtk;
+       struct wpa_bigtk_kde bigtk;
        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);
@@ -2864,32 +3172,95 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
                          (const u8 *) &igtk, WPA_IGTK_KDE_PREFIX_LEN + len,
                          NULL, 0);
 
+       if (!sm->wpa_auth->conf.beacon_prot)
+               return pos;
+
+       bigtk.keyid[0] = gsm->GN_bigtk;
+       bigtk.keyid[1] = 0;
+       if (gsm->wpa_group_state != WPA_GROUP_SETKEYSDONE ||
+           wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, rsc) < 0)
+               os_memset(bigtk.pn, 0, sizeof(bigtk.pn));
+       else
+               os_memcpy(bigtk.pn, rsc, sizeof(bigtk.pn));
+       os_memcpy(bigtk.bigtk, gsm->BIGTK[gsm->GN_bigtk - 6], len);
+       pos = wpa_add_kde(pos, RSN_KEY_DATA_BIGTK,
+                         (const u8 *) &bigtk, WPA_BIGTK_KDE_PREFIX_LEN + len,
+                         NULL, 0);
+
        return pos;
 }
 
-#else /* CONFIG_IEEE80211W */
 
-static int ieee80211w_kde_len(struct wpa_state_machine *sm)
+static int ocv_oci_len(struct wpa_state_machine *sm)
 {
+#ifdef CONFIG_OCV
+       if (wpa_auth_uses_ocv(sm))
+               return OCV_OCI_KDE_LEN;
+#endif /* CONFIG_OCV */
        return 0;
 }
 
-
-static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
+static int ocv_oci_add(struct wpa_state_machine *sm, u8 **argpos)
 {
-       return pos;
+#ifdef CONFIG_OCV
+       struct wpa_channel_info ci;
+
+       if (!wpa_auth_uses_ocv(sm))
+               return 0;
+
+       if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
+               wpa_printf(MSG_WARNING,
+                          "Failed to get channel info for OCI element");
+               return -1;
+       }
+
+       return ocv_insert_oci_kde(&ci, argpos);
+#else /* CONFIG_OCV */
+       return 0;
+#endif /* CONFIG_OCV */
 }
 
-#endif /* CONFIG_IEEE80211W */
+
+#ifdef CONFIG_TESTING_OPTIONS
+static u8 * replace_ie(const char *name, const u8 *old_buf, size_t *len, u8 eid,
+                      const u8 *ie, size_t ie_len)
+{
+       const u8 *elem;
+       u8 *buf;
+
+       wpa_printf(MSG_DEBUG, "TESTING: %s EAPOL override", name);
+       wpa_hexdump(MSG_DEBUG, "TESTING: wpa_ie before override",
+                   old_buf, *len);
+       buf = os_malloc(*len + ie_len);
+       if (!buf)
+               return NULL;
+       os_memcpy(buf, old_buf, *len);
+       elem = get_ie(buf, *len, eid);
+       if (elem) {
+               u8 elem_len = 2 + elem[1];
+
+               os_memmove((void *) elem, elem + elem_len,
+                          *len - (elem - buf) - elem_len);
+               *len -= elem_len;
+       }
+       os_memcpy(buf + *len, ie, ie_len);
+       *len += ie_len;
+       wpa_hexdump(MSG_DEBUG, "TESTING: wpa_ie after EAPOL override",
+                   buf, *len);
+
+       return buf;
+}
+#endif /* CONFIG_TESTING_OPTIONS */
 
 
 SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
 {
-       u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos, dummy_gtk[32];
-       size_t gtk_len, kde_len;
+       u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde = NULL, *pos, dummy_gtk[32];
+       size_t gtk_len, kde_len, wpa_ie_len;
        struct wpa_group *gsm = sm->group;
        u8 *wpa_ie;
-       int wpa_ie_len, secure, keyidx, encr = 0;
+       int secure, gtkidx, encr = 0;
+       u8 *wpa_ie_buf = NULL, *wpa_ie_buf2 = NULL;
 
        SM_ENTRY_MA(WPA_PTK, PTKINITNEGOTIATING, wpa_ptk);
        sm->TimeoutEvt = FALSE;
@@ -2907,7 +3278,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
        }
 
        /* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE],
-          GTK[GN], IGTK, [FTIE], [TIE * 2])
+          GTK[GN], IGTK, [BIGTK], [FTIE], [TIE * 2])
         */
        os_memset(rsc, 0, WPA_KEY_RSC_LEN);
        wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, rsc);
@@ -2916,13 +3287,33 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
        wpa_ie_len = sm->wpa_auth->wpa_ie_len;
        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_ie_len > wpa_ie[1] + 2U && wpa_ie[0] == WLAN_EID_RSN) {
                /* 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;
        }
+#ifdef CONFIG_TESTING_OPTIONS
+       if (sm->wpa_auth->conf.rsne_override_eapol_set) {
+               wpa_ie_buf2 = replace_ie(
+                       "RSNE", wpa_ie, &wpa_ie_len, WLAN_EID_RSN,
+                       sm->wpa_auth->conf.rsne_override_eapol,
+                       sm->wpa_auth->conf.rsne_override_eapol_len);
+               if (!wpa_ie_buf2)
+                       goto done;
+               wpa_ie = wpa_ie_buf2;
+       }
+       if (sm->wpa_auth->conf.rsnxe_override_eapol_set) {
+               wpa_ie_buf = replace_ie(
+                       "RSNXE", wpa_ie, &wpa_ie_len, WLAN_EID_RSNX,
+                       sm->wpa_auth->conf.rsnxe_override_eapol,
+                       sm->wpa_auth->conf.rsnxe_override_eapol_len);
+               if (!wpa_ie_buf)
+                       goto done;
+               wpa_ie = wpa_ie_buf;
+       }
+#endif /* CONFIG_TESTING_OPTIONS */
        wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
                        "sending 3/4 msg of 4-Way Handshake");
        if (sm->wpa == WPA_VERSION_WPA2) {
@@ -2937,10 +3328,10 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
                         * of GTK in the BSS.
                         */
                        if (random_get_bytes(dummy_gtk, gtk_len) < 0)
-                               return;
+                               goto done;
                        gtk = dummy_gtk;
                }
-               keyidx = gsm->GN;
+               gtkidx = gsm->GN;
                _rsc = rsc;
                encr = 1;
        } else {
@@ -2948,7 +3339,6 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
                secure = 0;
                gtk = NULL;
                gtk_len = 0;
-               keyidx = 0;
                _rsc = NULL;
                if (sm->rx_eapol_key_secure) {
                        /*
@@ -2966,7 +3356,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
                }
        }
 
-       kde_len = wpa_ie_len + ieee80211w_kde_len(sm);
+       kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm);
        if (gtk)
                kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
 #ifdef CONFIG_IEEE80211R_AP
@@ -2981,7 +3371,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
 #endif /* CONFIG_P2P */
        kde = os_malloc(kde_len);
        if (kde == NULL)
-               return;
+               goto done;
 
        pos = kde;
        os_memcpy(pos, wpa_ie, wpa_ie_len);
@@ -2996,8 +3386,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
                if (res < 0) {
                        wpa_printf(MSG_ERROR, "FT: Failed to insert "
                                   "PMKR1Name into RSN IE in EAPOL-Key data");
-                       os_free(kde);
-                       return;
+                       goto done;
                }
                pos -= wpa_ie_len;
                pos += elen;
@@ -3005,12 +3394,14 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
 #endif /* CONFIG_IEEE80211R_AP */
        if (gtk) {
                u8 hdr[2];
-               hdr[0] = keyidx & 0x03;
+               hdr[0] = gtkidx & 0x03;
                hdr[1] = 0;
                pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
                                  gtk, gtk_len);
        }
        pos = ieee80211w_kde_add(sm, pos);
+       if (ocv_oci_add(sm, &pos) < 0)
+               goto done;
 
 #ifdef CONFIG_IEEE80211R_AP
        if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
@@ -3036,8 +3427,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
                if (res < 0) {
                        wpa_printf(MSG_ERROR, "FT: Failed to insert FTIE "
                                   "into EAPOL-Key Key Data");
-                       os_free(kde);
-                       return;
+                       goto done;
                }
                pos += res;
 
@@ -3073,8 +3463,11 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
                        WPA_KEY_INFO_MIC : 0) |
                       WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL |
                       WPA_KEY_INFO_KEY_TYPE,
-                      _rsc, sm->ANonce, kde, pos - kde, keyidx, encr);
+                      _rsc, sm->ANonce, kde, pos - kde, 0, encr);
+done:
        os_free(kde);
+       os_free(wpa_ie_buf);
+       os_free(wpa_ie_buf2);
 }
 
 
@@ -3086,7 +3479,8 @@ 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.tk, klen)) {
+                                    sm->PTK.tk, klen,
+                                    KEY_FLAG_PAIRWISE_RX_TX)) {
                        wpa_sta_disconnect(sm->wpa_auth, sm->addr,
                                           WLAN_REASON_PREV_AUTH_NOT_VALID);
                        return;
@@ -3094,12 +3488,7 @@ SM_STATE(WPA_PTK, PTKINITDONE)
                /* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
                sm->pairwise_set = TRUE;
 
-               if (sm->wpa_auth->conf.wpa_ptk_rekey) {
-                       eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
-                       eloop_register_timeout(sm->wpa_auth->conf.
-                                              wpa_ptk_rekey, 0, wpa_rekey_ptk,
-                                              sm->wpa_auth, sm);
-               }
+               wpa_auth_set_ptk_rekey_timer(sm);
 
                if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) ||
                    sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP ||
@@ -3199,7 +3588,7 @@ SM_STEP(WPA_PTK)
                break;
        case WPA_PTK_INITPSK:
                if (wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr,
-                                    NULL, NULL)) {
+                                    NULL, NULL, NULL)) {
                        SM_ENTER(WPA_PTK, PTKSTART);
 #ifdef CONFIG_SAE
                } else if (wpa_auth_uses_sae(sm) && sm->pmksa) {
@@ -3322,7 +3711,7 @@ 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);
+                       ieee80211w_kde_len(sm) + ocv_oci_len(sm);
                kde_buf = os_malloc(kde_len);
                if (kde_buf == NULL)
                        return;
@@ -3333,6 +3722,10 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
                pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
                                  gtk, gsm->GTK_len);
                pos = ieee80211w_kde_add(sm, pos);
+               if (ocv_oci_add(sm, &pos) < 0) {
+                       os_free(kde_buf);
+                       return;
+               }
                kde_len = pos - kde;
        } else {
                kde = gtk;
@@ -3353,8 +3746,67 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
 
 SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED)
 {
+#ifdef CONFIG_OCV
+       struct wpa_authenticator *wpa_auth = sm->wpa_auth;
+       const u8 *key_data, *mic;
+       struct ieee802_1x_hdr *hdr;
+       struct wpa_eapol_key *key;
+       struct wpa_eapol_ie_parse kde;
+       size_t mic_len;
+       u16 key_data_length;
+#endif /* CONFIG_OCV */
+
        SM_ENTRY_MA(WPA_PTK_GROUP, REKEYESTABLISHED, wpa_ptk_group);
        sm->EAPOLKeyReceived = FALSE;
+
+#ifdef CONFIG_OCV
+       mic_len = wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len);
+
+       /*
+        * Note: last_rx_eapol_key length fields have already been validated in
+        * wpa_receive().
+        */
+       hdr = (struct ieee802_1x_hdr *) sm->last_rx_eapol_key;
+       key = (struct wpa_eapol_key *) (hdr + 1);
+       mic = (u8 *) (key + 1);
+       key_data = mic + mic_len + 2;
+       key_data_length = WPA_GET_BE16(mic + mic_len);
+       if (key_data_length > sm->last_rx_eapol_key_len - sizeof(*hdr) -
+           sizeof(*key) - mic_len - 2)
+               return;
+
+       if (wpa_parse_kde_ies(key_data, key_data_length, &kde) < 0) {
+               wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+                                "received EAPOL-Key group msg 2/2 with invalid Key Data contents");
+               return;
+       }
+
+       if (wpa_auth_uses_ocv(sm)) {
+               struct wpa_channel_info ci;
+               int tx_chanwidth;
+               int tx_seg1_idx;
+
+               if (wpa_channel_info(wpa_auth, &ci) != 0) {
+                       wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+                                       "Failed to get channel info to validate received OCI in EAPOL-Key group 1/2");
+                       return;
+               }
+
+               if (get_sta_tx_parameters(sm,
+                                         channel_width_to_int(ci.chanwidth),
+                                         ci.seg1_idx, &tx_chanwidth,
+                                         &tx_seg1_idx) < 0)
+                       return;
+
+               if (ocv_verify_tx_params(kde.oci, kde.oci_len, &ci,
+                                        tx_chanwidth, tx_seg1_idx) != 0) {
+                       wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+                                       ocv_errorstr);
+                       return;
+               }
+       }
+#endif /* CONFIG_OCV */
+
        if (sm->GUpdateStationKeys)
                sm->group->GKeyDoneStations--;
        sm->GUpdateStationKeys = FALSE;
@@ -3418,6 +3870,7 @@ static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
                          struct wpa_group *group)
 {
        int ret = 0;
+       size_t len;
 
        os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
        inc_byte_array(group->Counter, WPA_NONCE_LEN);
@@ -3428,9 +3881,7 @@ static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
        wpa_hexdump_key(MSG_DEBUG, "GTK",
                        group->GTK[group->GN - 1], group->GTK_len);
 
-#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);
@@ -3441,7 +3892,19 @@ static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
                wpa_hexdump_key(MSG_DEBUG, "IGTK",
                                group->IGTK[group->GN_igtk - 4], len);
        }
-#endif /* CONFIG_IEEE80211W */
+
+       if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION &&
+           wpa_auth->conf.beacon_prot) {
+               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, "BIGTK key expansion",
+                                  wpa_auth->addr, group->GNonce,
+                                  group->BIGTK[group->GN_bigtk - 6], len) < 0)
+                       ret = -1;
+               wpa_hexdump_key(MSG_DEBUG, "BIGTK",
+                               group->BIGTK[group->GN_bigtk - 6], len);
+       }
 
        return ret;
 }
@@ -3459,10 +3922,10 @@ static void wpa_group_gtk_init(struct wpa_authenticator *wpa_auth,
        os_memset(group->GTK, 0, sizeof(group->GTK));
        group->GN = 1;
        group->GM = 2;
-#ifdef CONFIG_IEEE80211W
        group->GN_igtk = 4;
        group->GM_igtk = 5;
-#endif /* CONFIG_IEEE80211W */
+       group->GN_bigtk = 6;
+       group->GM_bigtk = 7;
        /* GTK[GN] = CalcGTK() */
        wpa_gtk_update(wpa_auth, group);
 }
@@ -3551,7 +4014,6 @@ int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos)
 }
 
 
-#ifdef CONFIG_IEEE80211W
 int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)
 {
        struct wpa_group *gsm = sm->group;
@@ -3580,7 +4042,37 @@ int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)
 
        return pos - start;
 }
-#endif /* CONFIG_IEEE80211W */
+
+
+int wpa_wnmsleep_bigtk_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);
+
+       /*
+        * BIGTK subelement:
+        * Sub-elem ID[1] | Length[1] | KeyID[2] | PN[6] | Key[16]
+        */
+       *pos++ = WNM_SLEEP_SUBELEM_BIGTK;
+       *pos++ = 2 + 6 + len;
+       WPA_PUT_LE16(pos, gsm->GN_bigtk);
+       pos += 2;
+       if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, pos) != 0)
+               return 0;
+       pos += 6;
+
+       os_memcpy(pos, gsm->BIGTK[gsm->GN_bigtk - 6], len);
+       pos += len;
+
+       wpa_printf(MSG_DEBUG, "WNM: BIGTK Key ID %u in WNM-Sleep Mode exit",
+                  gsm->GN_bigtk);
+       wpa_hexdump_key(MSG_DEBUG, "WNM: BIGTK in WNM-Sleep Mode exit",
+                       gsm->IGTK[gsm->GN_bigtk - 6], len);
+
+       return pos - start;
+}
+
 #endif /* CONFIG_WNM_AP */
 
 
@@ -3597,11 +4089,12 @@ static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
        tmp = group->GM;
        group->GM = group->GN;
        group->GN = tmp;
-#ifdef CONFIG_IEEE80211W
        tmp = group->GM_igtk;
        group->GM_igtk = group->GN_igtk;
        group->GN_igtk = tmp;
-#endif /* CONFIG_IEEE80211W */
+       tmp = group->GM_bigtk;
+       group->GM_bigtk = group->GN_bigtk;
+       group->GN_bigtk = tmp;
        /* "GKeyDoneStations = GNoStations" is done in more robust way by
         * counting the STAs that are marked with GUpdateStationKeys instead of
         * including all STAs that could be in not-yet-completed state. */
@@ -3627,10 +4120,10 @@ static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
        if (wpa_auth_set_key(wpa_auth, group->vlan_id,
                             wpa_cipher_to_alg(wpa_auth->conf.wpa_group),
                             broadcast_ether_addr, group->GN,
-                            group->GTK[group->GN - 1], group->GTK_len) < 0)
+                            group->GTK[group->GN - 1], group->GTK_len,
+                            KEY_FLAG_GROUP_TX_DEFAULT) < 0)
                ret = -1;
 
-#ifdef CONFIG_IEEE80211W
        if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) {
                enum wpa_alg alg;
                size_t len;
@@ -3641,10 +4134,17 @@ static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
                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)
+                                    group->IGTK[group->GN_igtk - 4], len,
+                                    KEY_FLAG_GROUP_TX_DEFAULT) < 0)
+                       ret = -1;
+
+               if (ret == 0 && wpa_auth->conf.beacon_prot &&
+                   wpa_auth_set_key(wpa_auth, group->vlan_id, alg,
+                                    broadcast_ether_addr, group->GN_bigtk,
+                                    group->BIGTK[group->GN_bigtk - 6], len,
+                                    KEY_FLAG_GROUP_TX_DEFAULT) < 0)
                        ret = -1;
        }
-#endif /* CONFIG_IEEE80211W */
 
        return ret;
 }
@@ -3782,11 +4282,12 @@ void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth)
                tmp = group->GM;
                group->GM = group->GN;
                group->GN = tmp;
-#ifdef CONFIG_IEEE80211W
                tmp = group->GM_igtk;
                group->GM_igtk = group->GN_igtk;
                group->GN_igtk = tmp;
-#endif /* CONFIG_IEEE80211W */
+               tmp = group->GM_bigtk;
+               group->GM_bigtk = group->GN_bigtk;
+               group->GN_bigtk = tmp;
                wpa_gtk_update(wpa_auth, group);
                wpa_group_config_group_keys(wpa_auth, group);
        }
@@ -3932,8 +4433,12 @@ int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen)
 
        /* Private MIB */
        ret = os_snprintf(buf + len, buflen - len,
+                         "wpa=%d\n"
+                         "AKMSuiteSelector=" RSN_SUITE "\n"
                          "hostapdWPAPTKState=%d\n"
                          "hostapdWPAPTKGroupState=%d\n",
+                         sm->wpa,
+                         RSN_SUITE_ARG(wpa_akm_to_suite(sm->wpa_key_mgmt)),
                          sm->wpa_ptk_state,
                          sm->wpa_ptk_group_state);
        if (os_snprintf_error(buflen - len, ret))
@@ -3963,6 +4468,15 @@ int wpa_auth_get_pairwise(struct wpa_state_machine *sm)
 }
 
 
+const u8 * wpa_auth_get_pmk(struct wpa_state_machine *sm, int *len)
+{
+       if (!sm)
+               return NULL;
+       *len = sm->pmk_len;
+       return sm->PMK;
+}
+
+
 int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm)
 {
        if (sm == NULL)
@@ -4036,6 +4550,15 @@ int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
            sm->wpa_auth->conf.disable_pmksa_caching)
                return -1;
 
+#ifdef CONFIG_IEEE80211R_AP
+       if (pmk_len >= 2 * PMK_LEN && wpa_key_mgmt_ft(sm->wpa_key_mgmt) &&
+           wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) &&
+           !wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) {
+               /* Cache MPMK/XXKey instead of initial part from MSK */
+               pmk = pmk + PMK_LEN;
+               pmk_len = PMK_LEN;
+       } else
+#endif /* CONFIG_IEEE80211R_AP */
        if (wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) {
                if (pmk_len > PMK_LEN_SUITE_B_192)
                        pmk_len = PMK_LEN_SUITE_B_192;
@@ -4043,6 +4566,7 @@ int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
                pmk_len = PMK_LEN;
        }
 
+       wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK", pmk, pmk_len);
        if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, pmk_len, NULL,
                                 sm->PTK.kck, sm->PTK.kck_len,
                                 sm->wpa_auth->addr, sm->addr, session_timeout,
@@ -4061,6 +4585,7 @@ int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
        if (wpa_auth == NULL)
                return -1;
 
+       wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK from preauth", pmk, len);
        if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, len, NULL,
                                 NULL, 0,
                                 wpa_auth->addr,
@@ -4078,6 +4603,7 @@ int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr,
        if (wpa_auth->conf.disable_pmksa_caching)
                return -1;
 
+       wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK from SAE", pmk, PMK_LEN);
        if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, PMK_LEN, pmkid,
                                 NULL, 0,
                                 wpa_auth->addr, addr, 0, NULL,
@@ -4102,6 +4628,7 @@ int wpa_auth_pmksa_add2(struct wpa_authenticator *wpa_auth, const u8 *addr,
        if (wpa_auth->conf.disable_pmksa_caching)
                return -1;
 
+       wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK (2)", pmk, PMK_LEN);
        if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, pmk_len, pmkid,
                                 NULL, 0, wpa_auth->addr, addr, session_timeout,
                                 NULL, akmp))
@@ -4575,9 +5102,37 @@ void wpa_auth_get_fils_aead_params(struct wpa_state_machine *sm,
        *fils_kek_len = sm->PTK.kek_len;
 }
 
+
+void wpa_auth_add_fils_pmk_pmkid(struct wpa_state_machine *sm, const u8 *pmk,
+                                size_t pmk_len, const u8 *pmkid)
+{
+       os_memcpy(sm->PMK, pmk, pmk_len);
+       sm->pmk_len = pmk_len;
+       os_memcpy(sm->pmkid, pmkid, PMKID_LEN);
+       sm->pmkid_set = 1;
+}
+
 #endif /* CONFIG_FILS */
 
 
+void wpa_auth_set_auth_alg(struct wpa_state_machine *sm, u16 auth_alg)
+{
+       if (sm)
+               sm->auth_alg = auth_alg;
+}
+
+
+#ifdef CONFIG_DPP2
+void wpa_auth_set_dpp_z(struct wpa_state_machine *sm, const struct wpabuf *z)
+{
+       if (sm) {
+               wpabuf_clear_free(sm->dpp_z);
+               sm->dpp_z = z ? wpabuf_dup(z) : NULL;
+       }
+}
+#endif /* CONFIG_DPP2 */
+
+
 #ifdef CONFIG_TESTING_OPTIONS
 
 int wpa_auth_resend_m1(struct wpa_state_machine *sm, int change_anonce,
@@ -4607,16 +5162,14 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
                       void *ctx1, void *ctx2)
 {
        u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos;
-#ifdef CONFIG_IEEE80211W
        u8 *opos;
-#endif /* CONFIG_IEEE80211W */
        size_t gtk_len, kde_len;
        struct wpa_group *gsm = sm->group;
        u8 *wpa_ie;
-       int wpa_ie_len, secure, keyidx, encr = 0;
+       int wpa_ie_len, secure, gtkidx, encr = 0;
 
        /* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE],
-          GTK[GN], IGTK, [FTIE], [TIE * 2])
+          GTK[GN], IGTK, [BIGTK], [FTIE], [TIE * 2])
         */
 
        /* Use 0 RSC */
@@ -4640,7 +5193,7 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
                secure = 1;
                gtk = gsm->GTK[gsm->GN - 1];
                gtk_len = gsm->GTK_len;
-               keyidx = gsm->GN;
+               gtkidx = gsm->GN;
                _rsc = rsc;
                encr = 1;
        } else {
@@ -4648,7 +5201,6 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
                secure = 0;
                gtk = NULL;
                gtk_len = 0;
-               keyidx = 0;
                _rsc = NULL;
                if (sm->rx_eapol_key_secure) {
                        /*
@@ -4666,7 +5218,7 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
                }
        }
 
-       kde_len = wpa_ie_len + ieee80211w_kde_len(sm);
+       kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm);
        if (gtk)
                kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
 #ifdef CONFIG_IEEE80211R_AP
@@ -4701,12 +5253,11 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
 #endif /* CONFIG_IEEE80211R_AP */
        if (gtk) {
                u8 hdr[2];
-               hdr[0] = keyidx & 0x03;
+               hdr[0] = gtkidx & 0x03;
                hdr[1] = 0;
                pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
                                  gtk, gtk_len);
        }
-#ifdef CONFIG_IEEE80211W
        opos = pos;
        pos = ieee80211w_kde_add(sm, pos);
        if (pos - opos >= 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN) {
@@ -4714,7 +5265,10 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
                opos += 2 + RSN_SELECTOR_LEN + 2;
                os_memset(opos, 0, 6); /* clear PN */
        }
-#endif /* CONFIG_IEEE80211W */
+       if (ocv_oci_add(sm, &pos) < 0) {
+               os_free(kde);
+               return -1;
+       }
 
 #ifdef CONFIG_IEEE80211R_AP
        if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
@@ -4767,7 +5321,7 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
                        WPA_KEY_INFO_MIC : 0) |
                       WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL |
                       WPA_KEY_INFO_KEY_TYPE,
-                      _rsc, sm->ANonce, kde, pos - kde, keyidx, encr);
+                      _rsc, sm->ANonce, kde, pos - kde, 0, encr);
        os_free(kde);
        return 0;
 }
@@ -4781,9 +5335,7 @@ int wpa_auth_resend_group_m1(struct wpa_state_machine *sm,
        struct wpa_group *gsm = sm->group;
        const u8 *kde;
        u8 *kde_buf = NULL, *pos, hdr[2];
-#ifdef CONFIG_IEEE80211W
        u8 *opos;
-#endif /* CONFIG_IEEE80211W */
        size_t kde_len;
        u8 *gtk;
 
@@ -4796,7 +5348,7 @@ int wpa_auth_resend_group_m1(struct wpa_state_machine *sm,
        gtk = gsm->GTK[gsm->GN - 1];
        if (sm->wpa == WPA_VERSION_WPA2) {
                kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
-                       ieee80211w_kde_len(sm);
+                       ieee80211w_kde_len(sm) + ocv_oci_len(sm);
                kde_buf = os_malloc(kde_len);
                if (kde_buf == NULL)
                        return -1;
@@ -4806,7 +5358,6 @@ int wpa_auth_resend_group_m1(struct wpa_state_machine *sm,
                hdr[1] = 0;
                pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
                                  gtk, gsm->GTK_len);
-#ifdef CONFIG_IEEE80211W
                opos = pos;
                pos = ieee80211w_kde_add(sm, pos);
                if (pos - opos >=
@@ -4815,7 +5366,10 @@ int wpa_auth_resend_group_m1(struct wpa_state_machine *sm,
                        opos += 2 + RSN_SELECTOR_LEN + 2;
                        os_memset(opos, 0, 6); /* clear PN */
                }
-#endif /* CONFIG_IEEE80211W */
+               if (ocv_oci_add(sm, &pos) < 0) {
+                       os_free(kde_buf);
+                       return -1;
+               }
                kde_len = pos - kde;
        } else {
                kde = gtk;