diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index f683f7f..e0a8e53 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -20,7 +20,8 @@
 #include "p2p_hostapd.h"
 #include "hs20.h"
 #include "ap_drv_ops.h"
-
+#include "ap/wpa_auth.h"
+#include "ap/wpa_auth_i.h"
 
 u32 hostapd_sta_flags_to_drv(u32 flags)
 {
@@ -341,11 +342,34 @@ int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr,
 		     u16 seq, u16 status, const u8 *ie, size_t len)
 {
 	struct wpa_driver_sta_auth_params params;
+	struct sta_info *sta;
+	struct wpa_state_machine *sm;
 
 	if (hapd->driver == NULL || hapd->driver->sta_auth == NULL)
 		return 0;
 
+	sta = ap_get_sta(hapd, addr);
+	if (sta == NULL) {
+		wpa_printf(MSG_DEBUG, "Station " MACSTR
+				" not found for STA AUTH message",
+				MAC2STR(addr));
+		return 0;
+	}
+
 	os_memset(&params, 0, sizeof(params));
+	if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
+		sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
+		sta->auth_alg == WLAN_AUTH_FILS_PK) {
+		sm = sta->wpa_sm;
+		os_memcpy(params.fils_ANonce, sm->ANonce, WPA_NONCE_LEN);
+		os_memcpy(params.fils_SNonce, sm->SNonce, WPA_NONCE_LEN);
+		os_memcpy(params.fils_kek, sm->PTK.kek, WPA_KEK_MAX_LEN);
+		params.fils_keklen = sm->PTK.kek_len;
+		params.fils_auth = 1;
+		wpa_hexdump(MSG_DEBUG, "FILS: SNonce", sm->ANonce, FILS_NONCE_LEN);
+		wpa_hexdump(MSG_DEBUG, "FILS: SNonce", sm->SNonce, FILS_NONCE_LEN);
+		wpa_hexdump(MSG_DEBUG, "FILS: KEK", sm->PTK.kek, sm->PTK.kek_len);
+    }
 
 	params.own_addr = hapd->own_addr;
 	params.addr = addr;
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index d339742..3ae73e0 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -35,7 +35,7 @@
 #include "dfs.h"
 #include "beacon.h"
 #include "mbo_ap.h"
-
+#include "pmksa_cache_auth.h"
 
 int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
 			const u8 *req_ies, size_t req_ies_len, int reassoc)
@@ -381,15 +381,51 @@ skip_wpa_check:
 	p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf),
 					sta->auth_alg, req_ies, req_ies_len);
 
-	hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
+#endif
+
+#ifdef CONFIG_FILS
+	if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
+		sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
+		sta->auth_alg == WLAN_AUTH_FILS_PK) {
+
+		if(!req_ies) {
+			wpa_printf(MSG_DEBUG,"FILS: Invalid IE BUF\n");
+			return WLAN_STATUS_UNSPECIFIED_FAILURE;
+		}
+
+		if (wpa_fils_validate_filssession(sta->wpa_sm, req_ies,
+						req_ies_len, sta->fils_session)) {
+			wpa_printf(MSG_DEBUG,"FILS: Session Validation Failed\n");
+			return WLAN_STATUS_UNSPECIFIED_FAILURE;
+		}
 
-	if (sta->auth_alg == WLAN_AUTH_FT)
+		if (wpa_fils_validate_keyconfirm(sta->wpa_sm, req_ies, req_ies_len)) {
+			wpa_printf(MSG_DEBUG,"FILS: Key Confirm Validation Failed\n");
+			return WLAN_STATUS_UNSPECIFIED_FAILURE;
+		}
+
+		if(!elems.fils_session) {
+			wpa_printf(MSG_DEBUG, "fils_session element not found \n");
+			return WLAN_STATUS_UNSPECIFIED_FAILURE;
+		}
+
+		p = hostapd_eid_assoc_fils_session(hapd, sta->wpa_sm, p, elems.fils_session);
+		wpa_hexdump(MSG_DEBUG, "FILS Assoc Resp BUF (IEs)", buf, p - buf);
+	}
+#endif /* CONFIG_FILS */
+
+#if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_FILS)
+	hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
+	if (sta->auth_alg == WLAN_AUTH_FT ||
+		sta->auth_alg == WLAN_AUTH_FILS_SK ||
+		sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
+		sta->auth_alg == WLAN_AUTH_FILS_PK)
 		ap_sta_set_authorized(hapd, sta, 1);
-#else /* CONFIG_IEEE80211R_AP */
+#else /* CONFIG_IEEE80211R_AP || CONFIG_FILS */
 	/* Keep compiler silent about unused variables */
 	if (status) {
 	}
-#endif /* CONFIG_IEEE80211R_AP */
+#endif /* CONFIG_IEEE80211R_AP || CONFIG_FILS */
 
 	new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
 	sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
@@ -399,6 +435,10 @@ skip_wpa_check:
 
 	if (reassoc && (sta->auth_alg == WLAN_AUTH_FT))
 		wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
+	else if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
+			 sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
+			 sta->auth_alg == WLAN_AUTH_FILS_PK)
+		wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FILS);
 	else
 		wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
 
@@ -424,7 +464,6 @@ fail:
 	return -1;
 }
 
-
 void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
 {
 	struct sta_info *sta;
@@ -712,6 +751,38 @@ static void hostapd_notify_auth_ft_finish(void *ctx, const u8 *dst,
 }
 #endif /* CONFIG_IEEE80211R_AP */
 
+#ifdef CONFIG_FILS
+static void hostapd_notify_auth_fils_finish(struct hostapd_data *hapd,
+					  struct sta_info *sta, u16 resp,
+					  struct rsn_pmksa_cache_entry *pmksa,
+					  struct wpabuf *erp_resp, const u8 *msk, size_t msk_len,
+					  u16 auth_transaction)
+{
+	struct wpabuf *data = NULL;
+
+	data = prepare_auth_resp_fils(hapd, sta, &resp, pmksa, erp_resp, msk, msk_len);
+	if(data == NULL) {
+		wpa_printf(MSG_DEBUG,"%s prepare_auth_resp returned Failure\n",__func__);
+	}
+
+	if(resp == WLAN_STATUS_SUCCESS) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+					   HOSTAPD_LEVEL_DEBUG, "authentication OK (FILS)");
+		sta->flags |= WLAN_STA_AUTH;
+		wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
+		sta->auth_alg = WLAN_AUTH_FILS_SK;
+		mlme_authenticate_indication(hapd, sta);
+	} else {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+		HOSTAPD_LEVEL_DEBUG, "authentication Failed (FILS)");
+	}
+
+	hostapd_sta_auth(hapd, sta->addr, auth_transaction, resp,
+					 data ? wpabuf_head(data) : NULL,
+					 data ? wpabuf_len(data) : 0);
+	wpabuf_free(data);
+}
+#endif /* CONFIG_FILS */
 
 static void hostapd_notif_auth(struct hostapd_data *hapd,
 			       struct auth_info *rx_auth)
@@ -750,6 +821,17 @@ static void hostapd_notif_auth(struct hostapd_data *hapd,
 		return;
 	}
 #endif /* CONFIG_IEEE80211R_AP */
+
+#ifdef CONFIG_FILS
+	if (rx_auth->auth_type == WLAN_AUTH_FILS_SK) {
+		sta->auth_alg = WLAN_AUTH_FILS_SK;
+		handle_auth_fils(hapd, sta, rx_auth->ies, rx_auth->ies_len,
+						 rx_auth->auth_transaction, rx_auth->status_code,
+						 hostapd_notify_auth_fils_finish);
+		return;
+    }
+#endif /* CONFIG_FILS */
+
 fail:
 	hostapd_sta_auth(hapd, rx_auth->peer, rx_auth->auth_transaction + 1,
 			 status, resp_ies, resp_ies_len);
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 1ed3b41..076a992 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -47,7 +47,6 @@
 #include "taxonomy.h"
 #include "fils_hlp.h"
 
-
 u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
 {
 	u8 *pos = eid;
@@ -1011,14 +1010,17 @@ static void handle_auth_fils_finish(struct hostapd_data *hapd,
 				    struct sta_info *sta, u16 resp,
 				    struct rsn_pmksa_cache_entry *pmksa,
 				    struct wpabuf *erp_resp,
-				    const u8 *msk, size_t msk_len);
-
-static void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
-			    const struct ieee80211_mgmt *mgmt, size_t len,
-			    u16 auth_transaction, u16 status_code)
+				    const u8 *msk, size_t msk_len, u16 auth_transaction);
+
+void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
+					  const u8 *pos, size_t len, u16 auth_transaction,
+					  u16 status_code, void (*cb)(struct hostapd_data *hapd,
+                      struct sta_info *sta, u16 resp,
+                      struct rsn_pmksa_cache_entry *pmksa, struct wpabuf *erp_resp,
+                      const u8 *msk, size_t msk_len, u16 auth_transaction))
 {
 	u16 resp = WLAN_STATUS_SUCCESS;
-	const u8 *pos, *end;
+	const u8 *end;
 	struct ieee802_11_elems elems;
 	int res;
 	struct wpa_ie_data rsn;
@@ -1027,8 +1029,7 @@ static void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
 	if (auth_transaction != 1 || status_code != WLAN_STATUS_SUCCESS)
 		return;
 
-	pos = mgmt->u.auth.variable;
-	end = ((const u8 *) mgmt) + len;
+	end = pos + len;
 
 	wpa_hexdump(MSG_DEBUG, "FILS: Authentication frame fields",
 		    pos, end - pos);
@@ -1143,6 +1144,9 @@ static void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
 			ieee802_1x_encapsulate_radius(
 				hapd, sta, elems.fils_wrapped_data,
 				elems.fils_wrapped_data_len);
+			wpa_printf(MSG_DEBUG, "Appending pending cb & auth_transaction \n");
+			sta->fils_pending_cb = cb;
+			sta->fils_pending_auth_transaction = auth_transaction;
 			wpa_printf(MSG_DEBUG,
 				   "FILS: Will send Authentication frame once the response from authentication server is available");
 			sta->flags |= WLAN_STA_PENDING_FILS_ERP;
@@ -1155,12 +1159,14 @@ static void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
 	}
 
 fail:
-	handle_auth_fils_finish(hapd, sta, resp, pmksa, NULL, NULL, 0);
+	if(cb != NULL) {
+		cb(hapd, sta, resp, pmksa, NULL, NULL, 0, auth_transaction + 1);
+	}
 }
 
 
-static void handle_auth_fils_finish(struct hostapd_data *hapd,
-				    struct sta_info *sta, u16 resp,
+struct wpabuf *prepare_auth_resp_fils(struct hostapd_data *hapd,
+				    struct sta_info *sta, u16 *resp,
 				    struct rsn_pmksa_cache_entry *pmksa,
 				    struct wpabuf *erp_resp,
 				    const u8 *msk, size_t msk_len)
@@ -1174,31 +1180,34 @@ static void handle_auth_fils_finish(struct hostapd_data *hapd,
 	size_t pmk_len = 0;
 	u8 pmk_buf[PMK_LEN_MAX];
 
-	if (resp != WLAN_STATUS_SUCCESS)
-		goto fail;
+	if (*resp != WLAN_STATUS_SUCCESS) {
+		return NULL;
+    }
 
 	ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen);
 	if (!ie) {
-		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
-		goto fail;
+		*resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+		return NULL;
 	}
+
 	if (pmksa) {
 		/* Add PMKID of the selected PMKSA into RSNE */
 		ie_buf = os_malloc(ielen + 2 + 2 + PMKID_LEN);
 		if (!ie_buf) {
-			resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
-			goto fail;
+			*resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+			return NULL;
 		}
+
 		os_memcpy(ie_buf, ie, ielen);
 		if (wpa_insert_pmkid(ie_buf, &ielen, pmksa->pmkid) < 0) {
-			resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+			*resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
 			goto fail;
 		}
 		ie = ie_buf;
 	}
 
 	if (random_get_bytes(fils_nonce, FILS_NONCE_LEN) < 0) {
-		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+		*resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
 		goto fail;
 	}
 	wpa_hexdump(MSG_DEBUG, "RSN: Generated FILS Nonce",
@@ -1206,7 +1215,7 @@ static void handle_auth_fils_finish(struct hostapd_data *hapd,
 
 	data = wpabuf_alloc(1000 + ielen);
 	if (!data) {
-		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+		*resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
 		goto fail;
 	}
 
@@ -1245,7 +1254,7 @@ static void handle_auth_fils_finish(struct hostapd_data *hapd,
 				     msk, msk_len, sta->fils_snonce, fils_nonce,
 				     NULL, 0, pmk_buf, &pmk_len)) {
 			wpa_printf(MSG_DEBUG, "FILS: Failed to derive PMK");
-			resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+			*resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
 			wpabuf_free(data);
 			data = NULL;
 			goto fail;
@@ -1258,7 +1267,7 @@ static void handle_auth_fils_finish(struct hostapd_data *hapd,
 
 	if (!pmk) {
 		wpa_printf(MSG_DEBUG, "FILS: No PMK available");
-		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+		*resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
 		wpabuf_free(data);
 		data = NULL;
 		goto fail;
@@ -1266,13 +1275,29 @@ static void handle_auth_fils_finish(struct hostapd_data *hapd,
 
 	if (fils_auth_pmk_to_ptk(sta->wpa_sm, pmk, pmk_len,
 				 sta->fils_snonce, fils_nonce) < 0) {
-		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+		*resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
 		wpabuf_free(data);
 		data = NULL;
 		goto fail;
 	}
 
 fail:
+	os_free(ie_buf);
+	return data;
+}
+
+static void handle_auth_fils_finish(struct hostapd_data *hapd,
+				    struct sta_info *sta, u16 resp,
+				    struct rsn_pmksa_cache_entry *pmksa,
+				    struct wpabuf *erp_resp,
+				    const u8 *msk, size_t msk_len, u16 auth_transaction)
+{
+	struct wpabuf *data = NULL;
+
+	data = prepare_auth_resp_fils(hapd, sta, &resp, pmksa, erp_resp, msk, msk_len);
+	if(!data)
+		wpa_printf(MSG_DEBUG,"%s prepare_auth_resp returned Failure\n",__func__);
+
 	send_auth_reply(hapd, sta->addr, hapd->own_addr, WLAN_AUTH_FILS_SK, 2,
 			resp,
 			data ? wpabuf_head(data) : (u8 *) "",
@@ -1281,15 +1306,13 @@ fail:
 
 	if (resp == WLAN_STATUS_SUCCESS) {
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
-			       HOSTAPD_LEVEL_DEBUG,
-			       "authentication OK (FILS)");
+					HOSTAPD_LEVEL_DEBUG,
+					"authentication OK (FILS)");
 		sta->flags |= WLAN_STA_AUTH;
 		wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
 		sta->auth_alg = WLAN_AUTH_FILS_SK;
 		mlme_authenticate_indication(hapd, sta);
 	}
-
-	os_free(ie_buf);
 }
 
 
@@ -1299,9 +1322,12 @@ void ieee802_11_finish_fils_auth(struct hostapd_data *hapd,
 				 const u8 *msk, size_t msk_len)
 {
 	sta->flags &= ~WLAN_STA_PENDING_FILS_ERP;
-	handle_auth_fils_finish(hapd, sta, success ? WLAN_STATUS_SUCCESS :
-				WLAN_STATUS_UNSPECIFIED_FAILURE, NULL,
-				erp_resp, msk, msk_len);
+
+	if(sta->fils_pending_cb != NULL) {
+		sta->fils_pending_cb(hapd, sta, success ? WLAN_STATUS_SUCCESS :
+							 WLAN_STATUS_UNSPECIFIED_FAILURE, NULL,
+							 erp_resp, msk, msk_len, sta->fils_pending_auth_transaction + 1);
+    }
 }
 
 #endif /* CONFIG_FILS */
@@ -1738,8 +1764,9 @@ static void handle_auth(struct hostapd_data *hapd,
 #endif /* CONFIG_SAE */
 #ifdef CONFIG_FILS
 	case WLAN_AUTH_FILS_SK:
-		handle_auth_fils(hapd, sta, mgmt, len, auth_transaction,
-				 status_code);
+		handle_auth_fils(hapd, sta, mgmt->u.auth.variable,
+						 (len - IEEE80211_HDRLEN - sizeof(mgmt->u.auth)),
+						 auth_transaction, status_code, handle_auth_fils_finish);
 		return;
 #endif /* CONFIG_FILS */
 	}
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 74ed690..e74ea44 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -143,4 +143,9 @@ void ieee802_11_finish_fils_auth(struct hostapd_data *hapd,
 void fils_hlp_timeout(void *eloop_ctx, void *eloop_data);
 void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta);
 
+struct wpabuf *prepare_auth_resp_fils(struct hostapd_data *hapd,
+                    struct sta_info *sta, u16 *resp,
+                    struct rsn_pmksa_cache_entry *pmksa,
+                    struct wpabuf *erp_resp,
+                    const u8 *msk, size_t msk_len);
 #endif /* IEEE802_11_H */
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 6f55403..a604ded 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -48,6 +48,7 @@
  * Supported Rates IEs). */
 #define WLAN_SUPP_RATES_MAX 32
 
+struct rsn_pmksa_cache_entry;
 
 struct mbo_non_pref_chan_info {
 	struct mbo_non_pref_chan_info *next;
@@ -231,6 +232,11 @@ struct sta_info {
 	unsigned int fils_dhcp_rapid_commit_proxy:1;
 	struct wpabuf *fils_hlp_resp;
 	struct wpabuf *hlp_dhcp_discover;
+	u8 fils_pending_auth_transaction;
+	void (*fils_pending_cb)(struct hostapd_data *hapd, struct sta_info *sta,
+							u16 resp, struct rsn_pmksa_cache_entry *pmksa,
+							struct wpabuf *erp_resp, const u8 *msk,
+							size_t msk_len, u16 auth_transaction);
 #endif /* CONFIG_FILS */
 };
 
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index e4ba325..22eb926 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -1514,6 +1514,10 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
 		const u8 *aad[1];
 		size_t aad_len[1];
 
+		if (!kde) {
+			wpa_printf(MSG_DEBUG, "WPA: AES-SIV KDE NULL");
+			return;
+		}
 		WPA_PUT_BE16(key_mic, AES_BLOCK_SIZE + kde_len);
 		wpa_hexdump_key(MSG_DEBUG, "Plaintext EAPOL-Key Key Data",
 				kde, kde_len);
@@ -1753,6 +1757,15 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
 #else /* CONFIG_IEEE80211R_AP */
 		break;
 #endif /* CONFIG_IEEE80211R_AP */
+	case WPA_ASSOC_FILS:
+#ifdef CONFIG_FILS
+		wpa_printf(MSG_DEBUG, "FILS: TK configuration after association");
+		fils_set_tk(sm);
+		sm->fils_completed = 1;
+		return 0;
+#else /* CONFIG_FILS */
+		break;
+#endif /* CONFIG_FILS */
 	}
 
 #ifdef CONFIG_IEEE80211R_AP
@@ -2141,6 +2154,118 @@ static int wpa_aead_decrypt(struct wpa_state_machine *sm, struct wpa_ptk *ptk,
 	return 0;
 }
 
+u8 * hostapd_eid_assoc_fils_session(struct hostapd_data *hapd,
+                                    struct wpa_state_machine *sm, u8 *buf,
+                                    const u8 *fils_session)
+{
+	struct wpabuf *plain = NULL;
+	u8 *pos = buf;
+
+	/* FILS SESSION */
+	*pos++ = WLAN_EID_EXTENSION;  /* Element ID */
+	*pos++ = 1 + FILS_SESSION_LEN; /* Length */
+	*pos++ = WLAN_EID_EXT_FILS_SESSION; /* Element ID Extension */
+	os_memcpy(pos, fils_session, FILS_SESSION_LEN);
+	pos += FILS_SESSION_LEN;
+
+	plain = fils_prepare_plainbuf(sm, NULL);
+	if(!plain) {
+		wpa_printf(MSG_DEBUG,"FILS: Plain Buffer prep failed\n");
+		return NULL;
+	}
+
+	os_memcpy(pos, wpabuf_head(plain), wpabuf_len(plain));
+	pos += wpabuf_len(plain);
+
+	wpa_printf(MSG_DEBUG, "%s plain buf_len :%d\n",__func__, wpabuf_len(plain));
+	wpabuf_free(plain);
+	sm->fils_completed = 1;
+	return pos;
+}
+
+int wpa_fils_validate_filssession(struct wpa_state_machine *sm, const u8 *ies,
+                            size_t ies_len, const u8 *fils_session)
+{
+	const u8 *ie = NULL, *end = NULL;
+	const u8 *session = NULL;
+
+	if (!wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
+        wpa_printf(MSG_DEBUG, "FILS: Not a FILS AKM - reject association");
+        return -1;
+	}
+
+	/* Verify Session Element */
+	ie = ies;
+	end = ((const u8 *) ie) + ies_len;
+	while (ie + 1 < end) {
+		if (ie + 2 + ie[1] > end)
+				break;
+			if (ie[0] == WLAN_EID_EXTENSION &&
+				ie[1] >= 1 + FILS_SESSION_LEN &&
+				ie[2] == WLAN_EID_EXT_FILS_SESSION) {
+				session = ie;
+				break;
+			}
+			ie += 2 + ie[1];
+	}
+
+	if (!session) {
+		wpa_printf(MSG_DEBUG,
+			"%s FILS: Could not find FILS Session element in Assoc Req - reject", __func__);
+		return -1;
+	}
+
+	if (!fils_session) {
+		wpa_printf(MSG_DEBUG,
+			"%s FILS: Could not find FILS Session element in STA entry - reject", __func__);
+		return -1;
+	}
+
+	if (os_memcmp(fils_session, session + 3, FILS_SESSION_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "FILS: Session mismatch");
+		wpa_hexdump(MSG_DEBUG, "FILS: Expected FILS Session",
+				fils_session, FILS_SESSION_LEN);
+		wpa_hexdump(MSG_DEBUG, "FILS: Received FILS Session",
+				session + 3, FILS_SESSION_LEN);
+		return -1;
+	}
+	return 0;
+}
+
+int wpa_fils_validate_keyconfirm(struct wpa_state_machine *sm, const u8 *ies,
+								 size_t ies_len)
+{
+	struct ieee802_11_elems elems;
+
+	if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
+		wpa_printf(MSG_DEBUG, "FILS: Failed to parse decrypted elements");
+		return -1;
+	}
+
+	if (!elems.fils_key_confirm) {
+		wpa_printf(MSG_DEBUG, "FILS: No FILS Key Confirm element");
+		return -1;
+	}
+
+	if (elems.fils_key_confirm_len != sm->fils_key_auth_len) {
+		wpa_printf(MSG_DEBUG,
+			"FILS: Unexpected Key-Auth length %d (expected %d)",
+			elems.fils_key_confirm_len,
+			(int) sm->fils_key_auth_len);
+		return -1;
+	}
+
+	if (os_memcmp(elems.fils_key_confirm, sm->fils_key_auth_sta,
+				  sm->fils_key_auth_len) != 0) {
+		wpa_printf(MSG_DEBUG, "FILS: Key-Auth mismatch");
+		wpa_hexdump(MSG_DEBUG, "FILS: Received Key-Auth",
+					elems.fils_key_confirm, elems.fils_key_confirm_len);
+		wpa_hexdump(MSG_DEBUG, "FILS: Expected Key-Auth",
+					sm->fils_key_auth_sta, sm->fils_key_auth_len);
+		return -1;
+	}
+	return 0;
+}
 
 int fils_decrypt_assoc(struct wpa_state_machine *sm, const u8 *fils_session,
 		       const struct ieee80211_mgmt *mgmt, size_t frame_len,
@@ -2151,6 +2276,7 @@ int fils_decrypt_assoc(struct wpa_state_machine *sm, const u8 *fils_session,
 	struct ieee802_11_elems elems;
 	const u8 *aad[5];
 	size_t aad_len[5];
+	u16 status = 0;
 
 	if (!sm || !sm->PTK_valid) {
 		wpa_printf(MSG_DEBUG,
@@ -2173,6 +2299,12 @@ int fils_decrypt_assoc(struct wpa_state_machine *sm, const u8 *fils_session,
 		ie_start = mgmt->u.assoc_req.variable;
 	ie = ie_start;
 
+	status = wpa_fils_validate_filssession(sm, ie, left, fils_session);
+	if(status < 0) {
+		wpa_printf(MSG_DEBUG,"FILS: Session Validation Failed\n");
+		return -1;
+	}
+
 	/*
 	 * Find FILS Session element which is the last unencrypted element in
 	 * the frame.
@@ -2195,14 +2327,6 @@ int fils_decrypt_assoc(struct wpa_state_machine *sm, const u8 *fils_session,
 			   "FILS: Could not find FILS Session element in Association Request frame - reject");
 		return -1;
 	}
-	if (os_memcmp(fils_session, session + 3, FILS_SESSION_LEN) != 0) {
-		wpa_printf(MSG_DEBUG, "FILS: Session mismatch");
-		wpa_hexdump(MSG_DEBUG, "FILS: Expected FILS Session",
-			    fils_session, FILS_SESSION_LEN);
-		wpa_hexdump(MSG_DEBUG, "FILS: Received FILS Session",
-			    session + 3, FILS_SESSION_LEN);
-		return -1;
-	}
 	crypt = session + 2 + session[1];
 
 	if (end - crypt < AES_BLOCK_SIZE) {
@@ -2241,31 +2365,9 @@ int fils_decrypt_assoc(struct wpa_state_machine *sm, const u8 *fils_session,
 	wpa_hexdump(MSG_DEBUG, "FILS: Decrypted Association Request elements",
 		    pos, left - AES_BLOCK_SIZE);
 
-	if (ieee802_11_parse_elems(pos, left - AES_BLOCK_SIZE, &elems, 1) ==
-	    ParseFailed) {
-		wpa_printf(MSG_DEBUG,
-			   "FILS: Failed to parse decrypted elements");
-		return -1;
-	}
-	if (!elems.fils_key_confirm) {
-		wpa_printf(MSG_DEBUG, "FILS: No FILS Key Confirm element");
-		return -1;
-	}
-	if (elems.fils_key_confirm_len != sm->fils_key_auth_len) {
-		wpa_printf(MSG_DEBUG,
-			   "FILS: Unexpected Key-Auth length %d (expected %d)",
-			   elems.fils_key_confirm_len,
-			   (int) sm->fils_key_auth_len);
-		return -1;
-	}
-	if (os_memcmp(elems.fils_key_confirm, sm->fils_key_auth_sta,
-		      sm->fils_key_auth_len) != 0) {
-		wpa_printf(MSG_DEBUG, "FILS: Key-Auth mismatch");
-		wpa_hexdump(MSG_DEBUG, "FILS: Received Key-Auth",
-			    elems.fils_key_confirm,
-			    elems.fils_key_confirm_len);
-		wpa_hexdump(MSG_DEBUG, "FILS: Expected Key-Auth",
-			    sm->fils_key_auth_sta, sm->fils_key_auth_len);
+	status = wpa_fils_validate_keyconfirm(sm, pos, (left - AES_BLOCK_SIZE));
+	if(status < 0) {
+		wpa_printf(MSG_DEBUG,"FILS: Keyconfirm Validation Failed\n");
 		return -1;
 	}
 
@@ -2321,10 +2423,52 @@ int fils_encrypt_assoc(struct wpa_state_machine *sm, u8 *buf,
 	aad_len[4] = pos - aad[4];
 
 	/* The following elements will be encrypted with AES-SIV */
+	plain = fils_prepare_plainbuf(sm, hlp);
+	if(!plain) {
+		wpa_printf(MSG_DEBUG,"FILS: Plain Buffer prep failed\n");
+		return -1;
+	}
+
+	if (pos + wpabuf_len(plain) + AES_BLOCK_SIZE > end) {
+		wpa_printf(MSG_DEBUG,
+				   "FILS: Not enough room for FILS elements");
+        wpabuf_free(plain);
+        return -1;
+    }
+
+	wpa_hexdump_buf_key(MSG_DEBUG, "FILS: Association Response plaintext",
+			    plain);
+
+	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);
+		return -1;
+	}
+
+	wpa_hexdump(MSG_DEBUG,
+		    "FILS: Encrypted Association Response elements",
+		    pos, AES_BLOCK_SIZE + wpabuf_len(plain));
+	current_len += wpabuf_len(plain) + AES_BLOCK_SIZE;
+	wpabuf_free(plain);
+
+	sm->fils_completed = 1;
+
+	return current_len;
+}
+
+struct wpabuf *fils_prepare_plainbuf(struct wpa_state_machine *sm, const struct wpabuf *hlp)
+{
+	struct wpabuf *plain;
+	u8 *gtk, dummy_gtk[32];
+	size_t gtk_len;
+	struct wpa_group *gsm;
+	u8 *len, *tmp, *tmp2;
+	u8 hdr[2];
 
 	plain = wpabuf_alloc(1000);
 	if (!plain)
-		return -1;
+		return NULL;
 
 	/* TODO: FILS Public Key */
 
@@ -2358,7 +2502,7 @@ int fils_encrypt_assoc(struct wpa_state_machine *sm, u8 *buf,
 		 */
 		if (random_get_bytes(dummy_gtk, gtk_len) < 0) {
 			wpabuf_free(plain);
-			return -1;
+			return NULL;
 		}
 		gtk = dummy_gtk;
 	}
@@ -2375,36 +2519,9 @@ int fils_encrypt_assoc(struct wpa_state_machine *sm, u8 *buf,
 	wpabuf_put(plain, tmp2 - tmp);
 
 	*len = (u8 *) wpabuf_put(plain, 0) - len - 1;
-
-	if (pos + wpabuf_len(plain) + AES_BLOCK_SIZE > end) {
-		wpa_printf(MSG_DEBUG,
-			   "FILS: Not enough room for FILS elements");
-		wpabuf_free(plain);
-		return -1;
-	}
-
-	wpa_hexdump_buf_key(MSG_DEBUG, "FILS: Association Response plaintext",
-			    plain);
-
-	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);
-		return -1;
-	}
-
-	wpa_hexdump(MSG_DEBUG,
-		    "FILS: Encrypted Association Response elements",
-		    pos, AES_BLOCK_SIZE + wpabuf_len(plain));
-	current_len += wpabuf_len(plain) + AES_BLOCK_SIZE;
-	wpabuf_free(plain);
-
-	sm->fils_completed = 1;
-
-	return current_len;
+	return plain;
 }
 
-
 int fils_set_tk(struct wpa_state_machine *sm)
 {
 	enum wpa_alg alg;
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 90ea82d..192696e 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -273,7 +273,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
 		 u8 *data, size_t data_len);
 enum wpa_event {
 	WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH,
-	WPA_REAUTH_EAPOL, WPA_ASSOC_FT, WPA_DRV_STA_REMOVED
+	WPA_REAUTH_EAPOL, WPA_ASSOC_FT, WPA_ASSOC_FILS, WPA_DRV_STA_REMOVED
 };
 void wpa_remove_ptk(struct wpa_state_machine *sm);
 int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event);
@@ -364,6 +364,19 @@ int fils_decrypt_assoc(struct wpa_state_machine *sm, const u8 *fils_session,
 int fils_encrypt_assoc(struct wpa_state_machine *sm, u8 *buf,
 		       size_t current_len, size_t max_len,
 		       const struct wpabuf *hlp);
+struct wpabuf *fils_prepare_plainbuf(struct wpa_state_machine *sm, const struct wpabuf *hlp);
 int fils_set_tk(struct wpa_state_machine *sm);
+u8 *hostapd_eid_assoc_fils_session(struct hostapd_data *hapd,
+                                   struct wpa_state_machine *sm, u8 *eid, const u8 *fils_session);
+int wpa_fils_validate_filssession(struct wpa_state_machine *sm, const u8 *ies,
+								  size_t ies_len, const u8 *fils_session);
+int wpa_fils_validate_keyconfirm(struct wpa_state_machine *sm, const u8 *ies,
+								 size_t ies_len);
+void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
+			    const u8 *pos, size_t len, u16 auth_transaction, u16 status_code,
+			    void (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
+			    u16 resp, struct rsn_pmksa_cache_entry *pmksa,
+			    struct wpabuf *erp_resp, const u8 *msk, size_t msk_len,
+				u16 auth_transaction));
 
 #endif /* WPA_AUTH_H */
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index f223d78..3052f61 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -25,6 +25,7 @@
 #include "pae/ieee802_1x_kay.h"
 #endif /* CONFIG_MACSEC */
 #include "utils/list.h"
+#include "common/wpa_common.h"
 
 #define HOSTAPD_CHAN_DISABLED 0x00000001
 #define HOSTAPD_CHAN_NO_IR 0x00000002
@@ -629,6 +630,31 @@ struct wpa_driver_sta_auth_params {
 	 * len - ie buffer length
 	 */
 	size_t len;
+
+	/**
+	 * fils_auth - indicates if FILS AUTH is being performed
+	 */
+	u8 fils_auth;
+
+	/**
+	 * fils_ANonce - AP Nonce : required for FILS
+	 */
+	u8 fils_ANonce[WPA_NONCE_LEN];
+
+	/**
+	 * fils_SNonce - STA Nonce : required for FILS
+	*/
+	u8 fils_SNonce[WPA_NONCE_LEN];
+
+	/**
+	 * fils_kek - key for encryption - Required for FILS
+	 */
+	u8 fils_kek[WPA_KEK_MAX_LEN];
+
+	/**
+	 * fils_keklen - Length of the key(kek) - Required for FILS
+	 */
+	size_t fils_keklen;
 };
 
 /**
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index a43fd0d..e287e1b 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -20,6 +20,10 @@
 #include "p2p/p2p.h"
 
 #include "common.h"
+
+#include "utils/state_machine.h"
+#include "common/ieee802_11_defs.h"
+
 #ifndef _BYTE_ORDER
 #ifdef WORDS_BIGENDIAN
 #define _BYTE_ORDER _BIG_ENDIAN
@@ -55,7 +59,7 @@
 #include "netlink.h"
 #include "linux_ioctl.h"
 
-#if defined(CONFIG_IEEE80211W) || defined(CONFIG_IEEE80211R) || defined(CONFIG_HS20) || defined(CONFIG_WNM) || defined(CONFIG_WPS)
+#if defined(CONFIG_IEEE80211W) || defined(CONFIG_IEEE80211R) || defined(CONFIG_HS20) || defined(CONFIG_WNM) || defined(CONFIG_WPS) || defined(CONFIG_FILS)
 #define ATHEROS_USE_RAW_RECEIVE
 #endif
 
@@ -950,11 +954,11 @@ static int atheros_receive_pkt(struct atheros_driver_data *drv)
 #ifdef CONFIG_WPS
 	filt.app_filterype |= IEEE80211_FILTER_TYPE_PROBE_REQ;
 #endif /* CONFIG_WPS */
-#if defined(CONFIG_IEEE80211W) || defined(CONFIG_IEEE80211R)
+#if defined(CONFIG_IEEE80211W) || defined(CONFIG_IEEE80211R) || defined(CONFIG_FILS)
 	filt.app_filterype |= (IEEE80211_FILTER_TYPE_ASSOC_REQ |
 			       IEEE80211_FILTER_TYPE_AUTH |
 			       IEEE80211_FILTER_TYPE_ACTION);
-#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
+#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W || CONFIG_FILS */
 #ifdef CONFIG_WNM
 	filt.app_filterype |= IEEE80211_FILTER_TYPE_ACTION;
 #endif /* CONFIG_WNM */
@@ -968,12 +972,12 @@ static int atheros_receive_pkt(struct atheros_driver_data *drv)
 			return ret;
 	}
 
-#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R)
+#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) || defined(CONFIG_FILS)
 	drv->sock_raw = l2_packet_init(drv->iface, NULL, ETH_P_80211_RAW,
 				       atheros_raw_receive, drv, 1);
 	if (drv->sock_raw == NULL)
 		return -1;
-#endif /* CONFIG_WPS || CONFIG_IEEE80211R */
+#endif /* CONFIG_WPS || CONFIG_IEEE80211R || CONFIG_FILS */
 	return ret;
 }
 
@@ -1054,7 +1058,7 @@ atheros_set_ap_wps_ie(void *priv, const struct wpabuf *beacon,
 #define atheros_set_ap_wps_ie NULL
 #endif /* CONFIG_WPS */
 
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
+#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS)
 static int
 atheros_sta_auth(void *priv, struct wpa_driver_sta_auth_params *params)
 {
@@ -1065,7 +1069,24 @@ atheros_sta_auth(void *priv, struct wpa_driver_sta_auth_params *params)
 	wpa_printf(MSG_DEBUG, "%s: addr=%s status_code=%d",
 		   __func__, ether_sprintf(params->addr), params->status);
 
-	mlme.im_op = IEEE80211_MLME_AUTH;
+	/* Copy FILS AAD params if driver support FILS */
+	if(params->fils_auth && drv->fils_en) {
+		wpa_printf(MSG_DEBUG,"%s: im_op IEEE80211_MLME_AUTH_FILS \n", __func__);
+		os_memcpy(mlme.fils_aad.ANonce, params->fils_ANonce,
+                  IEEE80211_FILS_NONCE_LEN);
+		os_memcpy(mlme.fils_aad.SNonce, params->fils_SNonce,
+                  IEEE80211_FILS_NONCE_LEN);
+		os_memcpy(mlme.fils_aad.kek, params->fils_kek,
+                  IEEE80211_MAX_WPA_KEK_LEN);
+		mlme.fils_aad.kek_len = params->fils_keklen;
+		mlme.im_op = IEEE80211_MLME_AUTH_FILS;
+		wpa_hexdump(MSG_DEBUG, "FILS: SNonce", mlme.fils_aad.ANonce, FILS_NONCE_LEN);
+		wpa_hexdump(MSG_DEBUG, "FILS: SNonce", mlme.fils_aad.SNonce, FILS_NONCE_LEN);
+		wpa_hexdump(MSG_DEBUG, "FILS: KEK", mlme.fils_aad.kek, mlme.fils_aad.kek_len);
+	} else {
+		mlme.im_op = IEEE80211_MLME_AUTH;
+	}
+
 	mlme.im_reason = params->status;
 	mlme.im_seq = params->seq;
 	os_memcpy(mlme.im_macaddr, params->addr, IEEE80211_ADDR_LEN);
@@ -1082,6 +1103,7 @@ atheros_sta_auth(void *priv, struct wpa_driver_sta_auth_params *params)
 			return -1;
 		}
 	}
+
 	ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
 	if (ret < 0) {
 		wpa_printf(MSG_DEBUG, "%s: Failed to auth STA (addr " MACSTR
@@ -1129,7 +1151,7 @@ atheros_sta_assoc(void *priv, const u8 *own_addr, const u8 *addr,
 	}
 	return ret;
 }
-#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
+#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W || CONFIG_FILS */
 
 static void
 atheros_new_sta(struct atheros_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
@@ -1276,7 +1298,7 @@ atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv,
 		atheros_raw_receive(drv, NULL,
 				    (u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
 #endif /* CONFIG_WPS */
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
+#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS)
 	} else if (os_strncmp(custom, "Manage.assoc_req ", 17) == 0) {
 		/* Format: "Manage.assoc_req <frame len>" | zero padding |
 		 * frame */
@@ -1300,7 +1322,7 @@ atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv,
 		}
 		atheros_raw_receive(drv, NULL,
 				    (u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
-#endif /* CONFIG_IEEE80211W || CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211W || CONFIG_IEEE80211R || CONFIG_FILS */
 #ifdef ATHEROS_USE_RAW_RECEIVE
 		} else if (os_strncmp(custom, "Manage.action ", 14) == 0) {
 		/* Format: "Manage.assoc_req <frame len>" | zero padding | frame
@@ -2309,7 +2331,7 @@ const struct wpa_driver_ops wpa_driver_atheros_ops = {
 	.set_ap_wps_ie		= atheros_set_ap_wps_ie,
 	.set_authmode		= atheros_set_authmode,
 	.set_ap			= atheros_set_ap,
-#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
+#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) || defined(CONFIG_FILS)
 	.sta_assoc              = atheros_sta_assoc,
 	.sta_auth               = atheros_sta_auth,
 	.send_mlme       	= atheros_send_mgmt,
