qcacld-3.0: Changes to support FILS authentication

Add changes to add support of sending and parsing
authentication packets based on 80211ai specifications.

Change-Id: I684dbc89945ba3aef3186c872e5e1f7564d7e44c
CRs-Fixed: 2028113
diff --git a/Kbuild b/Kbuild
index 16831f5..be748a8 100644
--- a/Kbuild
+++ b/Kbuild
@@ -109,6 +109,8 @@
 	#Flag to enable Fast Transition (11r) feature
 	CONFIG_QCOM_VOWIFI_11R := y
 
+	#Flag to enable FILS Feature (11ai)
+	CONFIG_WLAN_FEATURE_FILS := y
 	ifneq ($(CONFIG_QCA_CLD_WLAN),)
 		ifeq (y,$(findstring y,$(CONFIG_CNSS) $(CONFIG_CNSS2) $(CONFIG_ICNSS)))
 		#Flag to enable Protected Managment Frames (11w) feature
@@ -596,6 +598,10 @@
 MAC_LIM_OBJS += $(MAC_SRC_DIR)/pe/lim/lim_process_tdls.o
 endif
 
+ifeq ($(CONFIG_WLAN_FEATURE_FILS),y)
+MAC_LIM_OBJS += $(MAC_SRC_DIR)/pe/lim/lim_process_fils.o
+endif
+
 ifeq ($(CONFIG_WLAN_FEATURE_NAN_DATAPATH), y)
 MAC_NDP_OBJS += $(MAC_SRC_DIR)/pe/nan/nan_datapath.o
 endif
@@ -792,6 +798,7 @@
 		$(QDF_OBJ_DIR)/qdf_mem.o \
 		$(QDF_OBJ_DIR)/qdf_nbuf.o \
 		$(QDF_OBJ_DIR)/qdf_threads.o \
+		$(QDF_OBJ_DIR)/qdf_crypto.o \
 		$(QDF_OBJ_DIR)/qdf_trace.o
 
 ifeq ($(CONFIG_WLAN_DEBUGFS), y)
@@ -1624,6 +1631,10 @@
 CDEFINES += -DWLAN_LOGGING_SOCK_SVC_ENABLE
 endif
 
+ifeq ($(CONFIG_WLAN_FEATURE_FILS),y)
+CDEFINES += -DWLAN_FEATURE_FILS_SK
+endif
+
 ifeq ($(CONFIG_CNSS), y)
 ifeq ($(CONFIG_CNSS_SDIO), y)
 CDEFINES += -DCONFIG_PLD_SDIO_CNSS
diff --git a/core/cds/inc/cds_config.h b/core/cds/inc/cds_config.h
index 8e4f47f..a52158f 100644
--- a/core/cds/inc/cds_config.h
+++ b/core/cds/inc/cds_config.h
@@ -164,4 +164,27 @@
 	bool auto_power_save_fail_mode;
 	uint8_t ito_repeat_count;
 };
+
+#ifdef WLAN_FEATURE_FILS_SK
+#define MAX_PMK_LEN 48
+#define FILS_MAX_KEYNAME_NAI_LENGTH 255
+#define FILS_MAX_REALM_LEN 255
+#define FILS_MAX_RRK_LENGTH 64
+
+struct cds_fils_connection_info {
+	bool is_fils_connection;
+	uint8_t keyname_nai[FILS_MAX_KEYNAME_NAI_LENGTH];
+	uint32_t key_nai_length;
+	uint16_t sequence_number;
+	uint8_t r_rk[FILS_MAX_RRK_LENGTH];
+	uint32_t r_rk_length;
+	uint8_t realm[FILS_MAX_REALM_LEN];
+	uint32_t realm_len;
+	uint8_t akm_type;
+	uint8_t auth_type;
+	uint8_t pmk[MAX_PMK_LEN];
+	uint8_t pmk_len;
+	uint8_t pmkid[16];
+};
+#endif
 #endif /* !defined( __CDS_CONFIG_H ) */
diff --git a/core/cds/inc/cds_utils.h b/core/cds/inc/cds_utils.h
index cb3f6f4..fe9ba8c 100644
--- a/core/cds/inc/cds_utils.h
+++ b/core/cds/inc/cds_utils.h
@@ -126,6 +126,15 @@
 uint32_t cds_chan_to_freq(uint8_t chan);
 uint8_t cds_freq_to_chan(uint32_t freq);
 enum cds_band_type cds_chan_to_band(uint32_t chan);
+
+/**
+ * cds_upper_to_lower: API to convert upper case string into lower case
+ * @txt: input text
+ * @length: length of input string
+ *
+ * Return: None
+ */
+void cds_upper_to_lower(uint8_t *txt, uint32_t length);
 #ifdef WLAN_FEATURE_11W
 bool cds_is_mmie_valid(uint8_t *key, uint8_t *ipn,
 		       uint8_t *frm, uint8_t *efrm);
diff --git a/core/cds/src/cds_utils.c b/core/cds/src/cds_utils.c
index 8eaa2f5..3350a31 100644
--- a/core/cds/src/cds_utils.c
+++ b/core/cds/src/cds_utils.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -597,6 +597,16 @@
 	return chan;
 }
 
+void cds_upper_to_lower(uint8_t *txt, uint32_t length)
+{
+	int i;
+
+	for (i = 0; i < length; i++) {
+		if (txt[i] >= 'A' && txt[i] <= 'Z')
+			txt[i] = txt[i] + 32;
+	}
+}
+
 enum cds_band_type cds_chan_to_band(uint32_t chan)
 {
 	if (chan <= CDS_24_GHZ_CHANNEL_14)
diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h
index caca6e4..ad5cbb2 100644
--- a/core/hdd/inc/wlan_hdd_main.h
+++ b/core/hdd/inc/wlan_hdd_main.h
@@ -2637,4 +2637,17 @@
 int hdd_get_rssi_snr_by_bssid(hdd_adapter_t *adapter, const uint8_t *bssid,
 			      int8_t *rssi, int8_t *snr);
 
+#if defined(WLAN_FEATURE_FILS_SK) && defined(CFG80211_FILS_SK_OFFLOAD_SUPPORT)
+/**
+ * hdd_clear_fils_connection_info: API to clear fils info from roam profile and
+ * free allocated memory
+ * @adapter: pointer to hdd adapter
+ *
+ * Return: None
+ */
+void hdd_clear_fils_connection_info(hdd_adapter_t *adapter);
+#else
+static inline void hdd_clear_fils_connection_info(hdd_adapter_t *adapter)
+{ }
+#endif
 #endif /* end #if !defined(WLAN_HDD_MAIN_H) */
diff --git a/core/hdd/src/wlan_hdd_assoc.c b/core/hdd/src/wlan_hdd_assoc.c
index 26c85c8..b2ba1ae 100644
--- a/core/hdd/src/wlan_hdd_assoc.c
+++ b/core/hdd/src/wlan_hdd_assoc.c
@@ -2485,6 +2485,23 @@
 	pHddStaCtx->roam_info.deferKeyComplete = false;
 }
 
+#if defined(WLAN_FEATURE_FILS_SK) && defined(CFG80211_FILS_SK_OFFLOAD_SUPPORT)
+void hdd_clear_fils_connection_info(hdd_adapter_t *adapter)
+{
+	hdd_wext_state_t *wext_state;
+
+	if ((adapter->device_mode == QDF_SAP_MODE) ||
+	    (adapter->device_mode == QDF_P2P_GO_MODE))
+		return;
+
+	wext_state = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
+	if (wext_state->roamProfile.fils_con_info) {
+		qdf_mem_free(wext_state->roamProfile.fils_con_info);
+		wext_state->roamProfile.fils_con_info = NULL;
+	}
+}
+#endif
+
 /**
  * hdd_association_completion_handler() - association completion handler
  * @pAdapter: pointer to adapter
@@ -5426,6 +5443,28 @@
 	return cipher_type;
 }
 
+#ifdef WLAN_FEATURE_FILS_SK
+/*
+ * hdd_is_fils_connection: API to determine if connection is FILS
+ * @adapter: hdd adapter
+ *
+ * Return: true if fils connection else false
+ */
+static inline bool hdd_is_fils_connection(hdd_adapter_t *adapter)
+{
+	hdd_wext_state_t *wext_state = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
+
+	if (wext_state->roamProfile.fils_con_info)
+		return wext_state->roamProfile.
+			fils_con_info->is_fils_connection;
+}
+#else
+static inline bool hdd_is_fils_connection(hdd_adapter_t *adapter)
+{
+	return false;
+}
+#endif
+
 /**
  * hdd_process_genie() - process gen ie
  * @pAdapter: pointer to adapter
@@ -5617,23 +5656,33 @@
 
 #ifdef WLAN_FEATURE_FILS_SK
 /**
- * hdd_is_rsn_is_fils() - This API checks whether a give auth type is FILS
+ * hdd_check_fils_rsn_n_set_auth_type() - This API checks whether a give
+ * auth type is fils if yes, sets it in profile.
  * @rsn_auth_type: auth type
  *
  * Return: true if FILS auth else false
  */
-static bool hdd_is_rsn_is_fils(eCsrAuthType rsn_auth_type)
+static bool hdd_check_fils_rsn_n_set_auth_type(tCsrRoamProfile *roam_profile,
+			    eCsrAuthType rsn_auth_type)
 {
+	bool is_fils_rsn = false;
+
+	if (!roam_profile->fils_con_info)
+		return false;
+
 	if ((rsn_auth_type == eCSR_AUTH_TYPE_FILS_SHA256) ||
 	   (rsn_auth_type == eCSR_AUTH_TYPE_FILS_SHA384) ||
 	   (rsn_auth_type == eCSR_AUTH_TYPE_FT_FILS_SHA256) ||
 	   (rsn_auth_type == eCSR_AUTH_TYPE_FT_FILS_SHA384))
-		return true;
+		is_fils_rsn = true;
+	if (is_fils_rsn)
+		roam_profile->fils_con_info->akm_type = rsn_auth_type;
 
-	return false;
+	return is_fils_rsn;
 }
 #else
-static inline bool hdd_is_rsn_is_fils(eCsrAuthType rsn_auth_type)
+static bool hdd_check_fils_rsn_n_set_auth_type(tCsrRoamProfile *roam_profile,
+			    eCsrAuthType rsn_auth_type)
 {
 	return false;
 }
@@ -5736,10 +5785,13 @@
 					eCSR_AUTH_TYPE_RSN_8021X_SHA256;
 			} else
 #endif
-			if (hdd_is_rsn_is_fils(RSNAuthType)) {
-				hdd_info("updated fils auth");
+			if (hdd_check_fils_rsn_n_set_auth_type(pRoamProfile,
+				RSNAuthType)) {
 				pRoamProfile->AuthType.authType[0] =
 					RSNAuthType;
+				hdd_info("updated profile authtype as %d",
+					RSNAuthType);
+
 			} else if ((pWextState->
 			     authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X)
 			    == IW_AUTH_KEY_MGMT_802_1X) {
diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c
index f63ab78..3ef2861 100644
--- a/core/hdd/src/wlan_hdd_cfg80211.c
+++ b/core/hdd/src/wlan_hdd_cfg80211.c
@@ -1759,7 +1759,7 @@
 		if (icv->flags & IEEE80211_CHAN_PASSIVE)
 			icv->flagext |= IEEE80211_CHAN_DFS;
 
-		hdd_info("freq %d flags %d flagext %d ieee %d maxreg %d maxpw %d minpw %d regClass %d antenna %d seg0 %d seg1 %d",
+		hdd_debug("freq %d flags %d flagext %d ieee %d maxreg %d maxpw %d minpw %d regClass %d antenna %d seg0 %d seg1 %d",
 			icv->freq, icv->flags,
 			icv->flagext, icv->ieee_chan_number,
 			icv->max_reg_power, icv->max_radio_power,
@@ -11688,6 +11688,17 @@
 #endif
 
 #define WLAN_HDD_MAX_NUM_CSA_COUNTERS 2
+#if defined(WLAN_FEATURE_FILS_SK) && defined(CFG80211_FILS_SK_OFFLOAD_SUPPORT)
+static void wlan_hdd_cfg80211_set_wiphy_fils_feature(struct wiphy *wiphy)
+{
+	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_SK_OFFLOAD);
+}
+#else
+static void wlan_hdd_cfg80211_set_wiphy_fils_feature(struct wiphy *wiphy)
+{
+}
+#endif
+
 /*
  * FUNCTION: wlan_hdd_cfg80211_init
  * This function is called by hdd_wlan_startup()
@@ -11741,6 +11752,7 @@
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0))
 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS);
 #endif
+	wlan_hdd_cfg80211_set_wiphy_fils_feature(wiphy);
 
 	hdd_config_sched_scan_plans_to_wiphy(wiphy, pCfg);
 
@@ -14978,7 +14990,12 @@
 		pHddStaCtx->conn_info.authType = eCSR_AUTH_TYPE_CCKM_WPA;
 		break;
 #endif
-
+#if defined(WLAN_FEATURE_FILS_SK) && defined(CFG80211_FILS_SK_OFFLOAD_SUPPORT)
+	case NL80211_AUTHTYPE_FILS_SK:
+		hdd_notice("set authentication type to FILS SHARED");
+		pHddStaCtx->conn_info.authType = eCSR_AUTH_TYPE_OPEN_SYSTEM;
+		break;
+#endif
 	default:
 		hdd_err("Unsupported authentication type: %d", auth_type);
 		pHddStaCtx->conn_info.authType = eCSR_AUTH_TYPE_UNKNOWN;
@@ -14990,6 +15007,36 @@
 	return 0;
 }
 
+#if defined(WLAN_FEATURE_FILS_SK) && defined(CFG80211_FILS_SK_OFFLOAD_SUPPORT)
+/**
+ * hdd_validate_fils_info_ptr() - check fils info for FILS AKMs
+ * @wext_state:     wext state pointer
+ * @fils_akm_check: boolean to update whether
+ *                  fils info is present or not
+ *
+ * Return: None
+ */
+static void hdd_validate_fils_info_ptr(hdd_wext_state_t *wext_state,
+				       bool *fils_akm_check)
+{
+	struct cds_fils_connection_info *fils_con_info;
+
+	fils_con_info = wext_state->roamProfile.fils_con_info;
+	if (!fils_con_info) {
+		hdd_debug("No valid Roam profile");
+		*fils_akm_check = false;
+	}
+
+	*fils_akm_check = true;
+}
+#else
+static void hdd_validate_fils_info_ptr(hdd_wext_state_t *wext_state,
+				       bool *fils_akm_check)
+{
+	*fils_akm_check = true;
+}
+#endif
+
 /**
  * wlan_hdd_set_akm_suite() - set key management type
  * @pAdapter: Pointer to adapter
@@ -15002,6 +15049,11 @@
 static int wlan_hdd_set_akm_suite(hdd_adapter_t *pAdapter, u32 key_mgmt)
 {
 	hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
+	tCsrRoamProfile *roam_profile;
+	bool fils_akm_check;
+
+	roam_profile = &pWextState->roamProfile;
+	hdd_validate_fils_info_ptr(pWextState, &fils_akm_check);
 
 #ifndef WLAN_AKM_SUITE_8021X_SHA256
 #define WLAN_AKM_SUITE_8021X_SHA256 0x000FAC05
@@ -15041,10 +15093,39 @@
 		break;
 #ifdef WLAN_FEATURE_FILS_SK
 	case WLAN_AKM_SUITE_FILS_SHA256:
-	case WLAN_AKM_SUITE_FILS_SHA384:
-	case WLAN_AKM_SUITE_FT_FILS_SHA256:
-	case WLAN_AKM_SUITE_FT_FILS_SHA384:
+		if (!fils_akm_check)
+			return -EINVAL;
+
+		hdd_debug("setting key mgmt type to FILS SHA256");
 		pWextState->authKeyMgmt |= IW_AUTH_KEY_MGMT_802_1X;
+		roam_profile->fils_con_info->akm_type =
+			eCSR_AUTH_TYPE_FILS_SHA256;
+		break;
+
+	case WLAN_AKM_SUITE_FILS_SHA384:
+		if (!fils_akm_check)
+			return -EINVAL;
+		hdd_debug("setting key mgmt type to FILS SH384");
+		pWextState->authKeyMgmt |= IW_AUTH_KEY_MGMT_802_1X;
+		roam_profile->fils_con_info->akm_type =
+			eCSR_AUTH_TYPE_FILS_SHA384;
+		break;
+
+	case WLAN_AKM_SUITE_FT_FILS_SHA256:
+		if (!fils_akm_check)
+			return -EINVAL;
+		hdd_debug("setting key mgmt type to FILS FT SH256");
+		pWextState->authKeyMgmt |= IW_AUTH_KEY_MGMT_802_1X;
+		roam_profile->fils_con_info->akm_type =
+			eCSR_AUTH_TYPE_FT_FILS_SHA256;
+		break;
+
+	case WLAN_AKM_SUITE_FT_FILS_SHA384:
+		if (!fils_akm_check)
+			return -EINVAL;
+		pWextState->authKeyMgmt |= IW_AUTH_KEY_MGMT_802_1X;
+		roam_profile->fils_con_info->akm_type =
+			eCSR_AUTH_TYPE_FT_FILS_SHA384;
 		break;
 #endif
 	default:
@@ -15520,6 +15601,115 @@
 	return false;
 }
 
+#if defined(WLAN_FEATURE_FILS_SK) && defined(CFG80211_FILS_SK_OFFLOAD_SUPPORT)
+/**
+ * wlan_hdd_get_fils_auth_type() - API to get FILS auth type
+ * @auth: enum of auth type
+ *
+ * This API converts nl80211 FILS auth type to driver specific
+ * auth type enum
+ *
+ * Return: FILS auth type
+ */
+static int wlan_hdd_get_fils_auth_type(enum nl80211_auth_type auth)
+{
+	switch (auth) {
+	case NL80211_AUTHTYPE_FILS_SK:
+		return eSIR_FILS_SK_WITHOUT_PFS;
+	case NL80211_AUTHTYPE_FILS_SK_PFS:
+		return eSIR_FILS_SK_WITH_PFS;
+	case NL80211_AUTHTYPE_FILS_PK:
+		return eSIR_FILS_PK_AUTH;
+	default:
+		return -EINVAL;
+	}
+}
+
+/**
+ * wlan_hdd_cfg80211_set_fils_config() - set fils config params during connect
+ * @adapter: Pointer to adapter
+ * @req: Pointer to fils parameters
+ *
+ * Return: 0 for success, non-zero for failure
+ */
+static int wlan_hdd_cfg80211_set_fils_config(hdd_adapter_t *adapter,
+					 struct cfg80211_connect_params *req)
+{
+	hdd_wext_state_t *wext_state;
+	tCsrRoamProfile *roam_profile;
+	int auth_type;
+	uint8_t *buf;
+
+	wext_state = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
+	roam_profile = &wext_state->roamProfile;
+
+	hdd_clear_fils_connection_info(adapter);
+	roam_profile->fils_con_info =
+		qdf_mem_malloc(sizeof(struct cds_fils_connection_info));
+
+	if (!roam_profile->fils_con_info) {
+		hdd_err("failed to allocate memory");
+		return -EINVAL;
+	}
+
+	if (req->auth_type != NL80211_AUTHTYPE_FILS_SK) {
+		roam_profile->fils_con_info->is_fils_connection = false;
+		return 0;
+	}
+
+	roam_profile->fils_con_info->is_fils_connection = true;
+	roam_profile->fils_con_info->sequence_number =
+		req->fils_erp_next_seq_num;
+	auth_type = wlan_hdd_get_fils_auth_type(req->auth_type);
+	if (auth_type < 0) {
+		hdd_err("invalid auth type for fils %d", req->auth_type);
+		return -EINVAL;
+	}
+	roam_profile->fils_con_info->auth_type = auth_type;
+
+	roam_profile->fils_con_info->r_rk_length =
+			req->fils_erp_rrk_len;
+	if (req->fils_erp_rrk_len)
+		qdf_mem_copy(roam_profile->fils_con_info->r_rk,
+			req->fils_erp_rrk,
+			roam_profile->fils_con_info->r_rk_length);
+
+	roam_profile->fils_con_info->realm_len = req->fils_erp_realm_len;
+	if (req->fils_erp_realm_len)
+		qdf_mem_copy(roam_profile->fils_con_info->realm,
+			req->fils_erp_realm,
+			roam_profile->fils_con_info->realm_len);
+
+	roam_profile->fils_con_info->key_nai_length =
+		req->fils_erp_username_len + sizeof(char) +
+				req->fils_erp_realm_len;
+	if (req->fils_erp_username_len) {
+		buf = roam_profile->fils_con_info->keyname_nai;
+		qdf_mem_copy(buf,
+			req->fils_erp_username,
+			req->fils_erp_username_len);
+		buf += req->fils_erp_username_len;
+		qdf_mem_copy(buf, "@", sizeof(char));
+		buf += sizeof(char);
+		qdf_mem_copy(buf, req->fils_erp_realm,
+			req->fils_erp_realm_len);
+	}
+	hdd_debug("fils connection seq=%d auth=%d user_len=%zu rrk_len=%zu realm_len=%zu keyname nai len %d\n",
+		req->fils_erp_next_seq_num, req->auth_type,
+		req->fils_erp_username_len, req->fils_erp_rrk_len,
+		req->fils_erp_realm_len,
+		roam_profile->fils_con_info->key_nai_length);
+
+	return 0;
+}
+#else
+static int wlan_hdd_cfg80211_set_fils_config(hdd_adapter_t *adapter,
+					 struct cfg80211_connect_params *req)
+{
+	return 0;
+}
+#endif
+
 /**
  * wlan_hdd_cfg80211_set_privacy() - set security parameters during connection
  * @pAdapter: Pointer to adapter
@@ -15550,6 +15740,9 @@
 	/*set authentication type */
 	status = wlan_hdd_cfg80211_set_auth_type(pAdapter, req->auth_type);
 
+	/* Parase extra info from connect request */
+	status = wlan_hdd_cfg80211_set_fils_config(pAdapter, req);
+
 	if (0 > status) {
 		hdd_err("Failed to set authentication type");
 		return status;
@@ -17309,7 +17502,7 @@
 		qdf_mem_copy(pmk_cache->pmk, pmksa->pmk, pmksa->pmk_len);
 		pmk_cache->pmk_len = pmksa->pmk_len;
 	} else
-		hdd_info("pmk len is %zu", pmksa->pmk_len);
+		hdd_debug("pmk len is %zu", pmksa->pmk_len);
 }
 #else
 /*
diff --git a/core/hdd/src/wlan_hdd_cfg80211.h b/core/hdd/src/wlan_hdd_cfg80211.h
index 3a656db..4610744 100644
--- a/core/hdd/src/wlan_hdd_cfg80211.h
+++ b/core/hdd/src/wlan_hdd_cfg80211.h
@@ -89,6 +89,28 @@
 #define BASIC_RATE_MASK   0x80
 #define RATE_MASK         0x7f
 
+#ifndef NL80211_AUTHTYPE_FILS_SK
+#define NL80211_AUTHTYPE_FILS_SK 5
+#endif
+#ifndef NL80211_AUTHTYPE_FILS_SK_PFS
+#define NL80211_AUTHTYPE_FILS_SK_PFS 6
+#endif
+#ifndef NL80211_AUTHTYPE_FILS_PK
+#define NL80211_AUTHTYPE_FILS_PK 7
+#endif
+#ifndef WLAN_AKM_SUITE_FILS_SHA256
+#define WLAN_AKM_SUITE_FILS_SHA256 0x000FAC0E
+#endif
+#ifndef WLAN_AKM_SUITE_FILS_SHA384
+#define WLAN_AKM_SUITE_FILS_SHA384 0x000FAC0F
+#endif
+#ifndef WLAN_AKM_SUITE_FT_FILS_SHA256
+#define WLAN_AKM_SUITE_FT_FILS_SHA256 0x000FAC10
+#endif
+#ifndef WLAN_AKM_SUITE_FT_FILS_SHA384
+#define WLAN_AKM_SUITE_FT_FILS_SHA384 0x000FAC11
+#endif
+
 #ifdef FEATURE_WLAN_TDLS
 #define WLAN_IS_TDLS_SETUP_ACTION(action) \
 	((SIR_MAC_TDLS_SETUP_REQ <= action) && \
diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c
index e32b203..7d5d683 100644
--- a/core/hdd/src/wlan_hdd_main.c
+++ b/core/hdd/src/wlan_hdd_main.c
@@ -4277,6 +4277,7 @@
 			wlan_hdd_scan_abort(adapter);
 
 		wlan_hdd_cleanup_remain_on_channel_ctx(adapter);
+		hdd_clear_fils_connection_info(adapter);
 
 #ifdef WLAN_OPEN_SOURCE
 		cancel_work_sync(&adapter->ipv4NotifierWorkQueue);
@@ -4496,6 +4497,7 @@
 			clear_bit(WMM_INIT_DONE, &adapter->event_flags);
 		}
 
+		hdd_clear_fils_connection_info(adapter);
 		if (adapter->device_mode == QDF_SAP_MODE) {
 			/*
 			 * If adapter is SAP, set session ID to invalid
diff --git a/core/hdd/src/wlan_hdd_wext.c b/core/hdd/src/wlan_hdd_wext.c
index e4b17ad..07e59f5 100644
--- a/core/hdd/src/wlan_hdd_wext.c
+++ b/core/hdd/src/wlan_hdd_wext.c
@@ -14248,6 +14248,16 @@
 
 }
 
+#ifdef WLAN_FEATURE_FILS_SK
+static void hdd_initialize_fils_info(hdd_wext_state_t *pwextBuf)
+{
+	pwextBuf->roamProfile.fils_con_info = NULL;
+}
+#else
+static void hdd_initialize_fils_info(hdd_wext_state_t *pwextBuf)
+{ }
+#endif
+
 /**
  * hdd_register_wext() - register wext context
  * @dev: net device handle
@@ -14285,6 +14295,7 @@
 		return QDF_STATUS_E_FAILURE;
 	}
 
+	hdd_initialize_fils_info(pwextBuf);
 	/* Register as a wireless device */
 	dev->wireless_handlers = (struct iw_handler_def *)&we_handler_def;
 
diff --git a/core/mac/inc/ani_system_defs.h b/core/mac/inc/ani_system_defs.h
index 7cc076f..99fd5ee 100644
--- a/core/mac/inc/ani_system_defs.h
+++ b/core/mac/inc/ani_system_defs.h
@@ -72,6 +72,9 @@
 	eSIR_LEAP_AUTH = 0x80,
 #endif
 	eSIR_AUTO_SWITCH,
+	eSIR_FILS_SK_WITHOUT_PFS = 4,
+	eSIR_FILS_SK_WITH_PFS = 5,
+	eSIR_FILS_PK_AUTH = 6,
 	eSIR_DONOT_USE_AUTH_TYPE = SIR_MAX_ENUM_SIZE
 } tAniAuthType;
 
diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h
index 763e1c9..548d95e 100644
--- a/core/mac/inc/sir_api.h
+++ b/core/mac/inc/sir_api.h
@@ -67,6 +67,8 @@
 #define SIR_MDIE_ELEMENT_ID         54
 #define SIR_MDIE_SIZE               3   /* MD ID(2 bytes), Capability(1 byte) */
 
+#define SIR_MAX_ELEMENT_ID         255
+
 /* Increase dwell time for P2P search in ms */
 #define P2P_SEARCH_DWELL_TIME_INCREASE   20
 #define P2P_SOCIAL_CHANNELS              3
@@ -1226,6 +1228,10 @@
 	tSirMacPowerCapInfo powerCap;
 	tSirSupChnl supportedChannels;
 	bool enable_bcast_probe_rsp;
+#ifdef WLAN_FEATURE_FILS_SK
+	struct cds_fils_connection_info fils_con_info;
+#endif
+	/* Pls make this as last variable in struct */
 	tSirBssDescription bssDescription;
 	/*
 	 * WARNING: Pls make bssDescription as last variable in struct
diff --git a/core/mac/inc/sir_mac_prot_def.h b/core/mac/inc/sir_mac_prot_def.h
index 6436de3..50ecb79 100644
--- a/core/mac/inc/sir_mac_prot_def.h
+++ b/core/mac/inc/sir_mac_prot_def.h
@@ -39,6 +39,7 @@
 #include "cds_api.h"
 #include "sir_types.h"
 #include "wni_cfg.h"
+#include <lim_fils_defs.h>
 
 /* /Capability information related */
 #define CAPABILITY_INFO_DELAYED_BA_BIT 14
@@ -1955,6 +1956,14 @@
 	uint8_t type;           /* = SIR_MAC_CHALLENGE_TEXT_EID */
 	uint8_t length;         /* = SIR_MAC_AUTH_CHALLENGE_LENGTH */
 	uint8_t challengeText[SIR_MAC_AUTH_CHALLENGE_LENGTH];
+#ifdef WLAN_FEATURE_FILS_SK
+	tSirMacRsnInfo rsn_ie;
+	uint8_t assoc_delay_info;
+	uint8_t session[SIR_FILS_SESSION_LENGTH];
+	uint8_t wrapped_data_len;
+	uint8_t wrapped_data[SIR_FILS_WRAPPED_DATA_MAX_SIZE];
+	uint8_t nonce[SIR_FILS_NONCE_LENGTH];
+#endif
 } qdf_packed tSirMacAuthFrameBody, *tpSirMacAuthFrameBody;
 
 typedef struct sSirMacAuthenticationFrame {
diff --git a/core/mac/src/include/parser_api.h b/core/mac/src/include/parser_api.h
index a5762b4..25f9200 100644
--- a/core/mac/src/include/parser_api.h
+++ b/core/mac/src/include/parser_api.h
@@ -115,7 +115,7 @@
 #define SIR_HESSID_LEN 6
 #define SIR_MAX_KEY_CNT 7
 #define SIR_MAX_KEY_LEN 48
-
+#define SIR_FILS_IND_ELEM_OFFSET 2
 /*
  * struct public_key_identifier: structure for public key identifier
  * present in fils indication element
diff --git a/core/mac/src/pe/include/lim_fils_defs.h b/core/mac/src/pe/include/lim_fils_defs.h
new file mode 100644
index 0000000..c3619cb
--- /dev/null
+++ b/core/mac/src/pe/include/lim_fils_defs.h
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define FILS_EAP_TLV_MAX_DATA_LEN 255
+#define FILS_SHA256_128_AUTH_TAG 16
+#define FILS_SHA256_256_AUTH_TAG 32
+
+#define FILS_SHA256_CRYPTO_TYPE "hmac(sha256)"
+#define FILS_SHA384_CRYPTO_TYPE "hmac(sha384)"
+
+/* RFC 6696 */
+#define RMSK_LABEL "Re-authentication Master Session Key@ietf.org"
+
+/* 12.12.2.5.3 80211-ai draft */
+#define PTK_KEY_LABEL "FILS PTK Derivation"
+#define MAX_ICK_LEN 48
+#define MAX_KEK_LEN 64
+#define MAX_TK_LEN 32
+#define MAX_KEY_AUTH_DATA_LEN 48
+#define MAX_GTK_LEN 255
+#define MAX_IGTK_LEN 255
+
+#define IPN_LEN 6
+#define FILS_SESSION_LENGTH 8
+#define FILS_MAX_KDE_LIST_LEN 255
+
+/* 12.12.2.5.3 80211-ai draft */
+#define FILS_SHA384_KEK_LEN 64
+#define FILS_SHA256_KEK_LEN 32
+
+/* 12.12.2.5.3 80211-ai draft */
+#define FILS_SHA256_ICK_LEN 32
+#define FILS_SHA384_ICK_LEN 48
+
+#define TK_LEN_TKIP 32
+#define TK_LEN_CCMP 16
+#define TK_LEN_AES_128_CMAC 32
+
+#define FILS_SHA256_PKM_LEN 32
+#define FILS_SHA384_PKM_LEN 48
+
+#define PMKID_LEN 16
+
+#define MAX_PRF_INTERATIONS_COUNT 255
+
+/* 9.4.2.180 FILS Session element */
+#define SIR_FILS_SESSION_LENGTH    8
+#define SIR_FILS_SESSION_EXT_EID   4
+
+/* 9.4.2.190 FILS Nonce element */
+#define SIR_FILS_NONCE_LENGTH      16
+#define SIR_FILS_NONCE_EXT_EID   13
+
+/*9.4.2.188 FILS Wrapped Data element */
+#define SIR_FILS_WRAPPED_DATA_MAX_SIZE 255
+#define SIR_FILS_WRAPPED_DATA_EXT_EID   8
+
+#define MAX_IE_LENGTH 255
+
+/* RFC 6696 5.3.1: EAP-Initiate/Re-auth-Start Packet */
+#define SIR_FILS_EAP_REAUTH_PACKET_TYPE 1
+#define SIR_FILS_EAP_INIT_PACKET_TYPE 2
+
+#define FILS_AUTH_TAG_MAX_LENGTH 32
+
+#define SIR_FILS_OPTIONAL_DATA_LEN 3
+/* RFC 6696 4.3: RiK deriavtion */
+#define SIR_FILS_RIK_LABEL "Re-authentication Integrity Key@ietf.org"
+
+/* RFC 6696 5.3.1: EAP-Initiate/Re-auth-Start Packet */
+#define SIR_FILS_EAP_TLV_KEYNAME_NAI 1
+#define SIR_FILS_EAP_TLV_R_RK_LIFETIME 2
+#define SIR_FILS_EAP_TLV_R_MSK_LIFETIME 3
+#define SIR_FILS_EAP_TLV_DOMAIN_NAME 4
+#define SIR_FILS_EAP_TLV_CRYPTO_LIST 5
+#define SIR_FILS_EAP_TLV_AUTH_INDICATION 6
+
+/*
+ * struct eap_auth_reserved: this structure defines flags format in eap packets
+ * as defined in RFC 6696 5.3.1
+ * flag_r:
+ * flag_b:
+ * flag_l:
+ */
+struct eap_auth_reserved {
+	uint8_t flag_r:1;
+	uint8_t flag_b:1;
+	uint8_t flag_l:1;
+	uint8_t reverved:5;
+};
+
+/*
+ * enum fils_erp_cryptosuite: this enum defines the cryptosuites used
+ * to calculate auth tag and auth tag length as defined by RFC 6696 5.3.1
+ * @HMAC_SHA256_64: sha256 with auth tag len as 64 bits
+ * @HMAC_SHA256_128: sha256 with auth tag len as 128 bits
+ * @HMAC_SHA256_256: sha256 with auth tag len as 256 bits
+ */
+enum fils_erp_cryptosuite {
+	INVALID_CRYPTO = 0, /* reserved */
+	HMAC_SHA256_64,
+	HMAC_SHA256_128,
+	HMAC_SHA256_256,
+};
+
+/*
+ * struct fils_eap_tlv: this structure defines the eap header
+ * for eap packet present in warpped data element IE
+ * @type: type of packet
+ * @length: length of packet
+ * @data: pointer to eap data
+ */
+struct fils_eap_tlv {
+	uint8_t type;
+	uint8_t length;
+	uint8_t data[FILS_EAP_TLV_MAX_DATA_LEN];
+};
+
+/* struct fils_auth_rsp_info: this structure saves the info from
+ * fils auth response.
+ * @keyname: pointer to keyname nai
+ * @keylength: keyname nai length
+ * @domain_name: pointer to domain name
+ * @domain_len: domain length
+ * @r_rk_lifetime: rRk lifetime
+ * @r_msk_lifetime: RMSK lifetime
+ * @sequence: sequence number to be validated
+ * @fils_nonce: anonce
+ * @assoc_delay: time in ms, DUT needs to wait after association req
+ */
+struct fils_auth_rsp_info {
+	uint8_t *keyname;
+	uint8_t keylength;
+	uint8_t *domain_name;
+	uint8_t domain_len;
+	uint32_t r_rk_lifetime;
+	uint32_t r_msk_lifetime;
+	uint16_t sequence;
+	uint8_t fils_nonce[SIR_FILS_NONCE_LENGTH];
+	uint8_t assoc_delay;
+};
+
+/*
+ * struct pe_fils_session: fils session info used in PE session
+ * @is_fils_connection: whether connection is fils or not
+ * @keyname_nai_data: keyname nai data
+ * @keyname_nai_length: keyname nai length
+ * @akm: akm type will be used
+ * @auth: authentication type
+ * @cipher: cipher type
+ * @fils_erp_reauth_pkt: pointer to fils reauth packet data
+ * @fils_erp_reauth_pkt_len: reauth packet length
+ * @fils_r_rk: pointer to fils rRk
+ * @fils_r_rk_len: fils rRk length
+ * @fils_r_ik: pointer to fils rIk
+ * @fils_r_ik_len: fils rIk length
+ * @sequence_number: sequence number needs to be used in eap packet
+ * @fils_session: fils session IE element
+ * @fils_nonce: fils snonce
+ * @rsn_ie: rsn ie used in auth request
+ * @rsn_ie_len: rsn ie length
+ * @fils_eap_finish_pkt: pointer to eap finish packet
+ * @fils_eap_finish_pkt_len: eap finish packet length
+ * @fils_rmsk: rmsk data pointer
+ * @fils_rmsk_len: rmsk data length
+ * @fils_pmk: pointer to pmk data
+ * @fils_pmk_len: pmk length
+ * @fils_pmkid: pointer to pmkid derived
+ * @auth_info: data obtained from auth response
+ * @ick: pointer to ick
+ * @ick_len: ick length
+ * @kek: pointer to kek
+ * @kek_len: kek length
+ * @tk: pointer to tk
+ * @tk_len: tk length
+ * @key_auth: data needs to be sent in assoc req, will be validated by AP
+ * @key_auth_len: key auth data length
+ * @ap_key_auth_data: data needs to be validated in assoc rsp
+ * @ap_key_auth_len:  ap key data length
+ * @gtk_len: gtk key length
+ * @gtk: pointer to gtk data
+ * @rsc: rsc value
+ * @igtk_len: igtk length
+ * @igtk: igtk data pointer
+ * @ipn: pointer to ipn data
+ */
+struct pe_fils_session {
+	bool is_fils_connection;
+	uint8_t *keyname_nai_data;
+	uint8_t keyname_nai_length;
+	uint8_t akm;
+	uint8_t auth;
+	uint8_t cipher;
+	uint8_t *fils_erp_reauth_pkt;
+	uint32_t fils_erp_reauth_pkt_len;
+	uint8_t *fils_r_rk;
+	uint8_t fils_r_rk_len;
+	uint8_t *fils_r_ik;
+	uint32_t fils_r_ik_len;
+	uint16_t sequence_number;
+	uint8_t fils_session[SIR_FILS_SESSION_LENGTH];
+	uint8_t fils_nonce[SIR_FILS_NONCE_LENGTH];
+	uint8_t rsn_ie[MAX_IE_LENGTH];
+	uint8_t rsn_ie_len;
+	uint8_t *fils_eap_finish_pkt;
+	uint8_t fils_eap_finish_pkt_len;
+	uint8_t *fils_rmsk;
+	uint8_t fils_rmsk_len;
+	uint8_t *fils_pmk;
+	uint8_t fils_pmk_len;
+	uint8_t fils_pmkid[PMKID_LEN];
+	struct fils_auth_rsp_info auth_info;
+	uint8_t ick[MAX_ICK_LEN];
+	uint8_t ick_len;
+	uint8_t kek[MAX_KEK_LEN];
+	uint8_t kek_len;
+	uint8_t tk[MAX_TK_LEN];
+	uint8_t tk_len;
+	uint8_t key_auth[MAX_KEY_AUTH_DATA_LEN];
+	uint8_t key_auth_len;
+	uint8_t ap_key_auth_data[MAX_KEY_AUTH_DATA_LEN];
+	uint8_t ap_key_auth_len;
+	uint8_t gtk_len;
+	uint8_t gtk[MAX_GTK_LEN];
+	uint8_t rsc;
+	uint8_t igtk_len;
+	uint8_t igtk[MAX_IGTK_LEN];
+	uint8_t ipn[IPN_LEN];
+};
diff --git a/core/mac/src/pe/include/lim_process_fils.h b/core/mac/src/pe/include/lim_process_fils.h
new file mode 100644
index 0000000..5070bb2
--- /dev/null
+++ b/core/mac/src/pe/include/lim_process_fils.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <cds_api.h>
+#include <lim_global.h>
+#include <ani_global.h>
+#include <lim_ser_des_utils.h>
+
+#ifdef WLAN_FEATURE_FILS_SK
+
+/**
+ * lim_process_fils_auth_frame2()- This API processes fils data from auth resp
+ * @mac_ctx: mac context
+ * @session: PE session
+ * @rx_auth_frm_body: pointer to auth frame
+ *
+ * Return: true if fils data needs to be processed else false
+ */
+bool lim_process_fils_auth_frame2(tpAniSirGlobal mac_ctx,
+				tpPESession pe_session,
+				tSirMacAuthFrameBody * rx_auth_frm_body);
+
+/**
+ * lim_add_fils_data_to_auth_frame()- This API adds fils data to auth frame.
+ * Following will be added in this.
+ *     1. RSNIE
+ *     2. SNonce
+ *     3. Session
+ *     4. Wrapped data
+ * @session: PE session
+ * @body: pointer to auth frame where data needs to be added
+ *
+ * Return: None
+ */
+void lim_add_fils_data_to_auth_frame(tpPESession session, uint8_t *body);
+
+/**
+ * lim_is_valid_fils_auth_frame()- This API checks whether auth frame is a
+ * valid frame.
+ * @mac_ctx: mac context
+ * @pe_session: pe session pointer
+ * @rx_auth_frm_body: pointer to autherntication frame
+ *
+ * Return: true if frame is valid or fils is disable, false otherwise
+ */
+bool lim_is_valid_fils_auth_frame(tpAniSirGlobal mac_ctx,
+	tpPESession pe_session, tSirMacAuthFrameBody *rx_auth_frm_body);
+
+/**
+ * lim_update_fils_config()- This API updates fils session info to csr config
+ * from join request.
+ * @session: PE session
+ * @sme_join_req: pointer to join request
+ *
+ * Return: None
+ */
+void lim_update_fils_config(tpPESession session, tpSirSmeJoinReq sme_join_req);
+
+/**
+ * lim_create_fils_auth_data()- This API creates the fils auth data
+ * which needs to be sent in auth req.
+ * @mac_ctx: mac context
+ * @auth_frame: pointer to auth frame
+ * @session: PE session
+ *
+ * Return: length of fils data
+ */
+uint32_t lim_create_fils_auth_data(tpAniSirGlobal mac_ctx,
+		tpSirMacAuthFrameBody auth_frame, tpPESession session);
+
+/**
+ * lim_increase_fils_sequence_number: this API increases fils sequence number in
+ * the event of resending auth packet
+ * @session_entry: pointer to PE session
+ *
+ * Return: None
+ */
+static inline void lim_increase_fils_sequence_number(tpPESession session_entry)
+{
+	if (!session_entry->fils_info)
+		return;
+
+	if (session_entry->fils_info->is_fils_connection)
+		session_entry->fils_info->sequence_number++;
+}
+
+#else
+static inline bool lim_process_fils_auth_frame2(tpAniSirGlobal mac_ctx,
+		tpPESession pe_session, tSirMacAuthFrameBody *rx_auth_frm_body)
+{
+	return false;
+}
+
+static inline void
+lim_increase_fils_sequence_number(tpPESession session_entry)
+{ }
+
+static inline void
+lim_add_fils_data_to_auth_frame(tpPESession session, uint8_t *body)
+{
+}
+
+static inline bool lim_is_valid_fils_auth_frame(tpAniSirGlobal mac_ctx,
+	tpPESession pe_session, tSirMacAuthFrameBody *rx_auth_frm_body)
+{
+	return true;
+}
+
+static inline void
+lim_update_fils_config(tpPESession session, tpSirSmeJoinReq sme_join_req)
+{ }
+
+static inline uint32_t lim_create_fils_auth_data(tpAniSirGlobal mac_ctx,
+		tpSirMacAuthFrameBody auth_frame, tpPESession session)
+{
+	return 0;
+}
+#endif
diff --git a/core/mac/src/pe/include/lim_session.h b/core/mac/src/pe/include/lim_session.h
index cd8d835..cb0de7b 100644
--- a/core/mac/src/pe/include/lim_session.h
+++ b/core/mac/src/pe/include/lim_session.h
@@ -519,6 +519,9 @@
 	bool enable_bcast_probe_rsp;
 	uint8_t ht_client_cnt;
 	bool ch_switch_in_progress;
+#ifdef WLAN_FEATURE_FILS_SK
+	struct pe_fils_session *fils_info;
+#endif
 } tPESession, *tpPESession;
 
 /*-------------------------------------------------------------------------
diff --git a/core/mac/src/pe/lim/lim_process_auth_frame.c b/core/mac/src/pe/lim/lim_process_auth_frame.c
index a1f5ec9..a2a6b4d 100644
--- a/core/mac/src/pe/lim/lim_process_auth_frame.c
+++ b/core/mac/src/pe/lim/lim_process_auth_frame.c
@@ -51,6 +51,7 @@
 #include "lim_ft.h"
 #include "cds_utils.h"
 #include "lim_send_messages.h"
+#include "lim_process_fils.h"
 
 /**
  * is_auth_valid
@@ -618,6 +619,13 @@
 		return;
 	}
 
+	if (lim_process_fils_auth_frame2(mac_ctx, pe_session,
+					 rx_auth_frm_body)) {
+		lim_restore_from_auth_state(mac_ctx, eSIR_SME_SUCCESS,
+				rx_auth_frm_body->authStatusCode, pe_session);
+		return;
+	}
+
 	if (rx_auth_frm_body->authAlgoNumber == eSIR_OPEN_SYSTEM) {
 		pe_session->limCurrentAuthType = eSIR_OPEN_SYSTEM;
 		auth_node = lim_acquire_free_pre_auth_node(mac_ctx,
@@ -1090,7 +1098,7 @@
 	uint8_t decrypt_result;
 	uint16_t frame_len, curr_seq_num = 0;
 	uint32_t val, key_length = 8;
-	tSirMacAuthFrameBody *rx_auth_frm_body, rx_auth_frame, auth_frame;
+	tSirMacAuthFrameBody *rx_auth_frm_body, *rx_auth_frame, *auth_frame;
 	tpSirMacMgmtHdr mac_hdr;
 	struct tLimPreAuthNode *auth_node;
 
@@ -1131,6 +1139,19 @@
 		cfg_set_int(mac_ctx, WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT,
 				pe_session->defaultAuthFailureTimeout);
 	}
+
+	rx_auth_frame = qdf_mem_malloc(sizeof(tSirMacAuthFrameBody));
+	if (!rx_auth_frame) {
+		pe_err("failed to allocate memory");
+		return;
+	}
+
+	auth_frame = qdf_mem_malloc(sizeof(tSirMacAuthFrameBody));
+	if (!auth_frame) {
+		pe_err("failed to allocate memory");
+		goto free;
+	}
+
 	/*
 	 * Determine if WEP bit is set in the FC or received MAC header
 	 * Note: WEP bit is set in FC of MAC header.
@@ -1147,7 +1168,7 @@
 			lim_send_deauth_mgmt_frame(mac_ctx,
 					eSIR_MAC_MIC_FAILURE_REASON,
 					mac_hdr->sa, pe_session, false);
-			return;
+			goto free;
 		}
 		/* Extract key ID from IV (most 2 bits of 4th byte of IV) */
 		key_id = (*(body_ptr + 3)) >> 6;
@@ -1161,18 +1182,18 @@
 		 * Out-of-sequence-Authentication-Frame status code.
 		 */
 		if (LIM_IS_STA_ROLE(pe_session)) {
-			auth_frame.authAlgoNumber = eSIR_SHARED_KEY;
-			auth_frame.authTransactionSeqNumber =
+			auth_frame->authAlgoNumber = eSIR_SHARED_KEY;
+			auth_frame->authTransactionSeqNumber =
 				SIR_MAC_AUTH_FRAME_4;
-			auth_frame.authStatusCode =
+			auth_frame->authStatusCode =
 				eSIR_MAC_CHALLENGE_FAILURE_STATUS;
 			/* Log error */
 			pe_err("rx Auth frm with wep bit set role: %d %pM",
 				GET_LIM_SYSTEM_ROLE(pe_session), mac_hdr->sa);
-			lim_send_auth_mgmt_frame(mac_ctx, &auth_frame,
+			lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
 				mac_hdr->sa, LIM_NO_WEP_IN_FC,
 				pe_session, false);
-			return;
+			goto free;
 		}
 
 		if (frame_len < LIM_ENCR_AUTH_BODY_LEN) {
@@ -1180,7 +1201,7 @@
 			pe_err("Not enough size: %d to decry rx Auth frm",
 				frame_len);
 			lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOGE);
-			return;
+			goto free;
 		}
 		if (LIM_IS_AP_ROLE(pe_session)) {
 			val = pe_session->privacy;
@@ -1207,15 +1228,15 @@
 			 * another strange thing in the spec. Status code
 			 * should have been 'unsupported algorithm' status code.
 			 */
-			auth_frame.authAlgoNumber = eSIR_SHARED_KEY;
-			auth_frame.authTransactionSeqNumber =
+			auth_frame->authAlgoNumber = eSIR_SHARED_KEY;
+			auth_frame->authTransactionSeqNumber =
 				SIR_MAC_AUTH_FRAME_4;
-			auth_frame.authStatusCode =
+			auth_frame->authStatusCode =
 				eSIR_MAC_CHALLENGE_FAILURE_STATUS;
-			lim_send_auth_mgmt_frame(mac_ctx, &auth_frame,
+			lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
 				mac_hdr->sa, LIM_NO_WEP_IN_FC,
 				pe_session, false);
-			return;
+			goto free;
 		}
 
 		/*
@@ -1234,15 +1255,15 @@
 			 * bit set. Send Auth frame4 with
 			 * 'out of sequence' status code.
 			 */
-			auth_frame.authAlgoNumber = eSIR_SHARED_KEY;
-			auth_frame.authTransactionSeqNumber =
+			auth_frame->authAlgoNumber = eSIR_SHARED_KEY;
+			auth_frame->authTransactionSeqNumber =
 				SIR_MAC_AUTH_FRAME_4;
-			auth_frame.authStatusCode =
+			auth_frame->authStatusCode =
 				eSIR_MAC_AUTH_FRAME_OUT_OF_SEQ_STATUS;
-			lim_send_auth_mgmt_frame(mac_ctx, &auth_frame,
+			lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
 				mac_hdr->sa, LIM_NO_WEP_IN_FC,
 				pe_session, false);
-			return;
+			goto free;
 		}
 		/* Change the auth-response timeout */
 		lim_deactivate_and_change_per_sta_id_timer(mac_ctx,
@@ -1262,16 +1283,16 @@
 			 * Reject by sending Authenticaton frame with
 			 * out of sequence Auth frame status code.
 			 */
-			auth_frame.authAlgoNumber = eSIR_SHARED_KEY;
-			auth_frame.authTransactionSeqNumber =
+			auth_frame->authAlgoNumber = eSIR_SHARED_KEY;
+			auth_frame->authTransactionSeqNumber =
 				SIR_MAC_AUTH_FRAME_4;
-			auth_frame.authStatusCode =
+			auth_frame->authStatusCode =
 				eSIR_MAC_AUTH_FRAME_OUT_OF_SEQ_STATUS;
 
-			lim_send_auth_mgmt_frame(mac_ctx, &auth_frame,
+			lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
 				mac_hdr->sa, LIM_NO_WEP_IN_FC,
 				pe_session, false);
-			return;
+			goto free;
 		}
 
 		val = SIR_MAC_KEY_LENGTH;
@@ -1291,15 +1312,15 @@
 			 * Send Authentication frame
 			 * with challenge failure status code
 			 */
-			auth_frame.authAlgoNumber = eSIR_SHARED_KEY;
-			auth_frame.authTransactionSeqNumber =
+			auth_frame->authAlgoNumber = eSIR_SHARED_KEY;
+			auth_frame->authTransactionSeqNumber =
 				SIR_MAC_AUTH_FRAME_4;
-			auth_frame.authStatusCode =
+			auth_frame->authStatusCode =
 				eSIR_MAC_CHALLENGE_FAILURE_STATUS;
-			lim_send_auth_mgmt_frame(mac_ctx, &auth_frame,
+			lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
 				mac_hdr->sa, LIM_NO_WEP_IN_FC,
 				pe_session, false);
-			return;
+			goto free;
 		}
 
 		key_length = val;
@@ -1313,33 +1334,33 @@
 				MAC_ADDR_ARRAY(mac_hdr->sa));
 			/* ICV failure */
 			lim_delete_pre_auth_node(mac_ctx, mac_hdr->sa);
-			auth_frame.authAlgoNumber = eSIR_SHARED_KEY;
-			auth_frame.authTransactionSeqNumber =
+			auth_frame->authAlgoNumber = eSIR_SHARED_KEY;
+			auth_frame->authTransactionSeqNumber =
 				SIR_MAC_AUTH_FRAME_4;
-			auth_frame.authStatusCode =
+			auth_frame->authStatusCode =
 				eSIR_MAC_CHALLENGE_FAILURE_STATUS;
 
-			lim_send_auth_mgmt_frame(mac_ctx, &auth_frame,
+			lim_send_auth_mgmt_frame(mac_ctx, auth_frame,
 				mac_hdr->sa, LIM_NO_WEP_IN_FC,
 				pe_session, false);
-			return;
+			goto free;
 		}
 		if ((sir_convert_auth_frame2_struct(mac_ctx, plainbody,
-				frame_len - 8, &rx_auth_frame) != eSIR_SUCCESS)
-				|| (!is_auth_valid(mac_ctx, &rx_auth_frame,
+				frame_len - 8, rx_auth_frame) != eSIR_SUCCESS)
+				|| (!is_auth_valid(mac_ctx, rx_auth_frame,
 							pe_session))) {
 			pe_err("failed to convert Auth Frame to structure or Auth is not valid");
-			return;
+			goto free;
 		}
 	} else if ((sir_convert_auth_frame2_struct(mac_ctx, body_ptr,
-				frame_len, &rx_auth_frame) != eSIR_SUCCESS)
-				|| (!is_auth_valid(mac_ctx, &rx_auth_frame,
+				frame_len, rx_auth_frame) != eSIR_SUCCESS)
+				|| (!is_auth_valid(mac_ctx, rx_auth_frame,
 						pe_session))) {
 			pe_err("failed to convert Auth Frame to structure or Auth is not valid");
-			return;
+			goto free;
 	}
 
-	rx_auth_frm_body = &rx_auth_frame;
+	rx_auth_frm_body = rx_auth_frame;
 
 	pe_debug("Received Auth frame with type: %d seqnum: %d status: %d %d",
 		(uint32_t) rx_auth_frm_body->authAlgoNumber,
@@ -1347,6 +1368,12 @@
 		(uint32_t) rx_auth_frm_body->authStatusCode,
 		(uint32_t) mac_ctx->lim.gLimNumPreAuthContexts);
 
+	if (!lim_is_valid_fils_auth_frame(mac_ctx, pe_session,
+			rx_auth_frm_body)) {
+		pe_err("Received invalid FILS auth packet");
+		goto free;
+	}
+
 	/*
 	 * IOT Workaround: with invalid WEP key, some APs reply
 	 * AuthFrame 4 with invalid seqNumber. This AuthFrame
@@ -1372,16 +1399,16 @@
 	case SIR_MAC_AUTH_FRAME_1:
 		lim_process_auth_frame_type1(mac_ctx,
 			mac_hdr, rx_auth_frm_body, rx_pkt_info,
-			curr_seq_num, &auth_frame, pe_session);
+			curr_seq_num, auth_frame, pe_session);
 		break;
 	case SIR_MAC_AUTH_FRAME_2:
 		lim_process_auth_frame_type2(mac_ctx,
-			mac_hdr, rx_auth_frm_body, &auth_frame, plainbody,
+			mac_hdr, rx_auth_frm_body, auth_frame, plainbody,
 			body_ptr, frame_len, pe_session);
 		break;
 	case SIR_MAC_AUTH_FRAME_3:
 		lim_process_auth_frame_type3(mac_ctx,
-			mac_hdr, rx_auth_frm_body, &auth_frame, pe_session);
+			mac_hdr, rx_auth_frm_body, auth_frame, pe_session);
 		break;
 	case SIR_MAC_AUTH_FRAME_4:
 		lim_process_auth_frame_type4(mac_ctx,
@@ -1394,6 +1421,11 @@
 			mac_hdr->sa);
 		break;
 	}
+free:
+	if (auth_frame)
+		qdf_mem_free(auth_frame);
+	if (rx_auth_frame)
+		qdf_mem_free(rx_auth_frame);
 }
 
 /*----------------------------------------------------------------------
diff --git a/core/mac/src/pe/lim/lim_process_fils.c b/core/mac/src/pe/lim/lim_process_fils.c
new file mode 100644
index 0000000..79e8df3
--- /dev/null
+++ b/core/mac/src/pe/lim/lim_process_fils.c
@@ -0,0 +1,1238 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "lim_process_fils.h"
+#include <lim_send_messages.h>
+#include <lim_types.h>
+#include <lim_utils.h>
+#include <lim_prop_exts_utils.h>
+#include <lim_assoc_utils.h>
+#include <lim_session.h>
+#include <cds_ieee80211_defines.h>
+#include <qdf_crypto.h>
+
+#ifdef WLAN_FEATURE_FILS_SK
+
+#define WLAN_FILS_DEBUG
+#ifdef WLAN_FILS_DEBUG
+/**
+ * lim_fils_data_dump()- dump fils data
+ * @type: Data name
+ * @data: pointer to data buffer
+ * @len: data len
+ *
+ * Return: None
+ */
+static void lim_fils_data_dump(char *type, uint8_t *data, uint32_t len)
+{
+
+	QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO,
+		 ("%s : length %d"), type, len);
+	qdf_trace_hex_dump(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, data, len);
+}
+#else
+static void lim_fils_data_dump(char *type, uint8_t *data, uint32_t len)
+{ }
+#endif
+
+/**
+ * lim_get_crypto_digest_len()- Returns hash length based on crypto type
+ * @type: Crypto type
+ *
+ * Return: hash length
+ */
+static int lim_get_crypto_digest_len(uint8_t *type)
+{
+	if (!strcmp(type, HMAC_SHA386_CRYPTO_TYPE))
+		return SHA384_DIGEST_SIZE;
+	else if (!strcmp(type, HMAC_SHA256_CRYPTO_TYPE))
+		return SHA256_DIGEST_SIZE;
+	return -EINVAL;
+}
+
+/**
+ * lim_get_auth_tag_len()- This API returns auth tag len based on crypto suit
+ * used to encrypt erp packet.
+ * @crypto_suite: Crtpto suit
+ *
+ * Return: tag length
+ */
+static uint8_t lim_get_auth_tag_len(enum fils_erp_cryptosuite crypto_suite)
+{
+	switch (crypto_suite) {
+	case HMAC_SHA256_64:
+		return -EINVAL;
+	case HMAC_SHA256_128:
+		return FILS_SHA256_128_AUTH_TAG;
+	case HMAC_SHA256_256:
+		return FILS_SHA256_256_AUTH_TAG;
+	default:
+		return -EINVAL;
+	}
+}
+
+
+/**
+ * lim_get_crypto_type()- This API returns crypto type based on akm suite used
+ * @akm: akm used for authentication
+ *
+ * Return: Crypto type
+ */
+static uint8_t *lim_get_crypto_type(uint8_t akm)
+{
+	switch (akm) {
+	case eCSR_AUTH_TYPE_FILS_SHA384:
+	case eCSR_AUTH_TYPE_FT_FILS_SHA384:
+		return FILS_SHA384_CRYPTO_TYPE;
+	case eCSR_AUTH_TYPE_FILS_SHA256:
+	case eCSR_AUTH_TYPE_FT_FILS_SHA256:
+	default:
+		return FILS_SHA256_CRYPTO_TYPE;
+	}
+}
+
+/**
+ * lim_get_pmk_length()- This API returns pmk length based on akm used
+ * @akm: akm used for authentication
+ *
+ * Return: PMK length
+ */
+static uint8_t lim_get_pmk_length(int akm_type)
+{
+	switch (akm_type) {
+	case eCSR_AUTH_TYPE_FILS_SHA256:
+	case eCSR_AUTH_TYPE_FT_FILS_SHA256:
+		return FILS_SHA256_PKM_LEN;
+	case eCSR_AUTH_TYPE_FILS_SHA384:
+	case eCSR_AUTH_TYPE_FT_FILS_SHA384:
+		return FILS_SHA384_PKM_LEN;
+	default:
+		return FILS_SHA256_PKM_LEN;
+	}
+}
+
+/**
+ * lim_get_kek_len()- This API returns kek length based on akm used
+ * @akm: akm used for authentication
+ *
+ * Return: KEK length
+ */
+static uint8_t lim_get_kek_len(uint8_t akm)
+{
+	switch (akm) {
+	case eCSR_AUTH_TYPE_FILS_SHA384:
+	case eCSR_AUTH_TYPE_FT_FILS_SHA384:
+		return FILS_SHA384_KEK_LEN;
+	case eCSR_AUTH_TYPE_FILS_SHA256:
+	case eCSR_AUTH_TYPE_FT_FILS_SHA256:
+		return FILS_SHA256_KEK_LEN;
+	default:
+		return FILS_SHA256_KEK_LEN;
+	}
+}
+
+/**
+ * lim_get_tk_len()- This API returns tk length based on cypher used
+ * @akm: cypher used
+ *
+ * Return: TK length
+ */
+static uint8_t lim_get_tk_len(int cypher_suite)
+{
+	switch (cypher_suite) {
+	case eSIR_ED_TKIP:
+		return TK_LEN_TKIP;
+	case eSIR_ED_CCMP:
+		return TK_LEN_CCMP;
+	case eSIR_ED_AES_128_CMAC:
+		return TK_LEN_AES_128_CMAC;
+	default:
+		return 0;
+	}
+}
+
+/**
+ * lim_get_ick_len()- This API returns ick length based on akm used
+ * @akm: akm used for authentication
+ *
+ * Return: ICK length
+ */
+static int lim_get_ick_len(uint8_t akm)
+{
+	switch (akm) {
+	case eCSR_AUTH_TYPE_FILS_SHA384:
+	case eCSR_AUTH_TYPE_FT_FILS_SHA384:
+		return FILS_SHA384_ICK_LEN;
+	case eCSR_AUTH_TYPE_FILS_SHA256:
+	case eCSR_AUTH_TYPE_FT_FILS_SHA256:
+	default:
+		return FILS_SHA256_ICK_LEN;
+	}
+}
+
+/**
+ * lim_get_key_from_prf()- This API returns key data using PRF-X as defined in
+ * 11.6.1.7.2 ieee-80211-2012.
+ * @type: crypto type needs to be used
+ * @secret: key which needs to be used in crypto
+ * @secret_len: key_len of secret
+ * @label: PRF label
+ * @optional_data: Data used for hash
+ * @optional_data_len: data length
+ * @key: key data output
+ * @keylen: key data length
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS lim_get_key_from_prf(uint8_t *type, uint8_t *secret,
+		uint32_t secret_len, uint8_t *label, uint8_t *optional_data,
+		uint32_t optional_data_len, uint8_t *key, uint32_t keylen)
+{
+	uint8_t count[2];
+	uint8_t *addr[4];
+	uint32_t len[4];
+	uint16_t key_bit_length = keylen * 8;
+	uint8_t key_length[2];
+	uint32_t i = 0, remain_len;
+	uint16_t interation;
+	uint8_t crypto_digest_len = lim_get_crypto_digest_len(type);
+	uint8_t tmp_hash[SHA384_DIGEST_SIZE] = {0};
+
+	addr[0] = count;
+	len[0] = sizeof(count);
+
+	addr[1] = label;
+	len[1] = strlen(label);
+
+	addr[2] = optional_data;
+	len[2] = optional_data_len;
+
+	qdf_mem_copy(key_length, &key_bit_length, sizeof(key_bit_length));
+	addr[3] = key_length;
+	len[3] = sizeof(key_length);
+
+	for (interation = 1; i < keylen; interation++) {
+		remain_len = keylen - i;
+		qdf_mem_copy(count, &interation, sizeof(interation));
+
+		if (remain_len >= crypto_digest_len)
+			remain_len = crypto_digest_len;
+
+		if (qdf_get_hmac_hash(type, secret, secret_len, 4,
+				addr, len, tmp_hash) < 0) {
+			pe_err("qdf_get_hmac_hash failed");
+			return QDF_STATUS_E_FAILURE;
+		}
+		qdf_mem_copy(&key[i], tmp_hash, remain_len);
+		i += crypto_digest_len;
+	}
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * lim_default_hmac_sha256_kdf()- This API calculates key data using default kdf
+ * defined in RFC4306.
+ * @secret: key which needs to be used in crypto
+ * @secret_len: key_len of secret
+ * @label: PRF label
+ * @optional_data: Data used for hash
+ * @optional_data_len: data length
+ * @key: key data output
+ * @keylen: key data length
+ *
+ * This API creates default KDF as defined in RFC4306
+ * PRF+ (K,S) = T1 | T2 | T3 | T4 | ...
+ * T1 = PRF (K, S | 0x01)
+ * T2 = PRF (K, T1 | S | 0x02)
+ * T3 = PRF (K, T2 | S | 0x03)
+ * T4 = PRF (K, T3 | S | 0x04)
+ *
+ * for every iteration its creates 32 bit of hash
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS
+lim_default_hmac_sha256_kdf(uint8_t *secret, uint32_t secret_len,
+		uint8_t *label, uint8_t *optional_data,
+		uint32_t optional_data_len, uint8_t *key, uint32_t keylen)
+{
+	uint8_t tmp_hash[SHA256_DIGEST_SIZE] = {0};
+	uint8_t count = 1;
+	uint8_t *addr[4];
+	uint32_t len[4];
+	uint32_t current_position = 0, remaining_data = SHA256_DIGEST_SIZE;
+
+	addr[0] = tmp_hash;
+	len[0] = SHA256_DIGEST_SIZE;
+	addr[1] = label;
+	len[1] = strlen(label) + 1;
+	addr[2] = optional_data;
+	len[2] = optional_data_len;
+	addr[3] = &count;
+	len[3] = 1;
+
+	if (keylen == 0 ||
+	   (keylen > (MAX_PRF_INTERATIONS_COUNT * SHA256_DIGEST_SIZE))) {
+		pe_err("invalid key length %d", keylen);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	/* Create T1 */
+	if (qdf_get_hmac_hash(FILS_SHA256_CRYPTO_TYPE, secret, secret_len, 3,
+			&addr[1], &len[1], tmp_hash) < 0) {
+		pe_err("failed to get hmac hash");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	/* Update hash from tmp_hash */
+	qdf_mem_copy(key + current_position, tmp_hash, remaining_data);
+	current_position += remaining_data;
+
+	for (count = 2; current_position < keylen; count++) {
+		remaining_data = keylen - current_position;
+		if (remaining_data > SHA256_DIGEST_SIZE)
+			remaining_data = SHA256_DIGEST_SIZE;
+
+		/* Create T-n */
+		if (qdf_get_hmac_hash(FILS_SHA256_CRYPTO_TYPE, secret,
+				secret_len, 4, addr, len, tmp_hash) < 0) {
+			pe_err("failed to get hmac hash");
+			return QDF_STATUS_E_FAILURE;
+		}
+		/* Update hash from tmp_hash */
+		qdf_mem_copy(key + current_position, tmp_hash, remaining_data);
+		current_position += remaining_data;
+	}
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * lim_process_fils_eap_tlv()- This API process eap tlv available in auth resp
+ * and returns remaining length.
+ * @pe_session: PE session
+ * @wrapped_data: wrapped data
+ * @data_len: length of tlv
+ *
+ * Return: remaining length
+ */
+static uint32_t lim_process_fils_eap_tlv(tpPESession pe_session,
+				uint8_t *wrapped_data, uint32_t data_len)
+{
+	struct fils_eap_tlv *tlv;
+	struct fils_auth_rsp_info *auth_info;
+	uint8_t auth_tag_len;
+
+	auth_info = &pe_session->fils_info->auth_info;
+	/* Minimum */
+	auth_tag_len = lim_get_auth_tag_len(HMAC_SHA256_128);
+
+	while (data_len > (auth_tag_len + 1)) {
+		tlv = (struct fils_eap_tlv *) wrapped_data;
+
+		pe_debug("tlv type %x len %u total %u",
+			tlv->type, tlv->length, data_len);
+		switch (tlv->type) {
+		case SIR_FILS_EAP_TLV_KEYNAME_NAI:
+			auth_info->keyname = qdf_mem_malloc(tlv->length);
+			if (!auth_info->keyname) {
+				pe_err("failed to alloc memory");
+				return 0;
+			}
+			qdf_mem_copy(auth_info->keyname,
+				     tlv->data, tlv->length);
+			auth_info->keylength = tlv->length;
+			data_len -= (tlv->length + 2);
+			wrapped_data += (tlv->length + 2);
+			break;
+		case SIR_FILS_EAP_TLV_R_RK_LIFETIME:
+			/* TODO check this */
+			auth_info->r_rk_lifetime = lim_get_u32(tlv->data);
+			data_len -= (tlv->length + 2);
+			wrapped_data += (tlv->length + 2);
+			break;
+		case SIR_FILS_EAP_TLV_R_MSK_LIFETIME:
+			/* TODO check this */
+			auth_info->r_msk_lifetime = lim_get_u32(tlv->data);
+			data_len -= (tlv->length + 2);
+			wrapped_data += (tlv->length + 2);
+			break;
+		case SIR_FILS_EAP_TLV_DOMAIN_NAME:
+			auth_info->domain_name = qdf_mem_malloc(tlv->length);
+			if (!auth_info->domain_name) {
+				pe_err("failed to alloc memory");
+				return 0;
+			}
+			qdf_mem_copy(auth_info->domain_name,
+				     tlv->data, tlv->length);
+			auth_info->domain_len = tlv->length;
+			data_len -= (tlv->length + 2);
+			wrapped_data += (tlv->length + 2);
+			break;
+			/* TODO process these now */
+		case SIR_FILS_EAP_TLV_CRYPTO_LIST:
+		case SIR_FILS_EAP_TLV_AUTH_INDICATION:
+			data_len -= (tlv->length + 2);
+			wrapped_data += (tlv->length + 2);
+			break;
+		default:
+			pe_debug("Unknown type");
+			return data_len;
+		}
+	}
+	return data_len;
+}
+
+/**
+ * lim_generate_key_data()- This API generates key data using prf
+ * FILS-Key-Data = KDF-X(PMK, "FILS PTK Derivation", SPA||AA||SNonce||ANonce)
+ * @fils_info: fils session info
+ * @key_label: label used
+ * @data: data buffer
+ * @data_len: data buffer len
+ * @key_data: hash data needs to be generated
+ * @key_data_len: hash data len
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS lim_generate_key_data(struct pe_fils_session *fils_info,
+			uint8_t *key_label, uint8_t *data, uint32_t data_len,
+			uint8_t *key_data, uint32_t key_data_len)
+{
+	QDF_STATUS status;
+
+	if (!fils_info)
+		return QDF_STATUS_E_FAILURE;
+
+	status = lim_get_key_from_prf(lim_get_crypto_type(fils_info->akm),
+			fils_info->fils_pmk,
+			fils_info->fils_pmk_len,
+			key_label, data, data_len, key_data, key_data_len);
+	if (status != QDF_STATUS_SUCCESS)
+		pe_err("failed to generate keydata");
+	return status;
+}
+
+/**
+ * lim_generate_ap_key_auth()- This API generates ap auth data which needs to be
+ * verified in assoc response.
+ * @pe_session: pe session pointer
+ *
+ * Return: None
+ */
+static void lim_generate_ap_key_auth(tpPESession pe_session)
+{
+	uint8_t *buf, *addr[1];
+	uint32_t len;
+	struct pe_fils_session *fils_info = pe_session->fils_info;
+	uint8_t data[SIR_FILS_NONCE_LENGTH + SIR_FILS_NONCE_LENGTH
+			+ QDF_MAC_ADDR_SIZE + QDF_MAC_ADDR_SIZE] = {0};
+
+	if (!fils_info)
+		return;
+
+	len = SIR_FILS_NONCE_LENGTH + SIR_FILS_NONCE_LENGTH +
+			QDF_MAC_ADDR_SIZE +  QDF_MAC_ADDR_SIZE;
+	addr[0] = data;
+	buf = data;
+	qdf_mem_copy(buf, fils_info->auth_info.fils_nonce,
+			SIR_FILS_NONCE_LENGTH);
+	buf += SIR_FILS_NONCE_LENGTH;
+	qdf_mem_copy(buf, fils_info->fils_nonce, SIR_FILS_NONCE_LENGTH);
+	buf += SIR_FILS_NONCE_LENGTH;
+	qdf_mem_copy(buf, pe_session->bssId, QDF_MAC_ADDR_SIZE);
+	buf += QDF_MAC_ADDR_SIZE;
+	qdf_mem_copy(buf, pe_session->selfMacAddr, QDF_MAC_ADDR_SIZE);
+	buf += QDF_MAC_ADDR_SIZE;
+
+	if (qdf_get_hmac_hash(lim_get_crypto_type(fils_info->akm),
+				fils_info->ick, fils_info->ick_len, 1, &addr[0],
+				&len, fils_info->ap_key_auth_data) < 0)
+		pe_err("failed to generate PMK id");
+	fils_info->ap_key_auth_len = lim_get_crypto_digest_len(
+					lim_get_crypto_type(fils_info->akm));
+	lim_fils_data_dump("AP Key Auth", fils_info->ap_key_auth_data,
+		fils_info->ap_key_auth_len);
+}
+
+/**
+ * lim_generate_key_auth()- This API generates sta auth data which needs to be
+ * send to AP in assoc request, AP will generate the same the verify it.
+ * @pe_session: pe session pointer
+ *
+ * Return: None
+ */
+static void lim_generate_key_auth(tpPESession pe_session)
+{
+	uint8_t *buf, *addr[1];
+	uint32_t len;
+	struct pe_fils_session *fils_info = pe_session->fils_info;
+	uint8_t data[SIR_FILS_NONCE_LENGTH + SIR_FILS_NONCE_LENGTH
+			+ QDF_MAC_ADDR_SIZE + QDF_MAC_ADDR_SIZE] = {0};
+
+	if (!fils_info)
+		return;
+
+	len = SIR_FILS_NONCE_LENGTH + SIR_FILS_NONCE_LENGTH +
+			QDF_MAC_ADDR_SIZE +  QDF_MAC_ADDR_SIZE;
+
+	addr[0] = data;
+	buf = data;
+	qdf_mem_copy(buf, fils_info->fils_nonce, SIR_FILS_NONCE_LENGTH);
+	buf += SIR_FILS_NONCE_LENGTH;
+	qdf_mem_copy(buf, fils_info->auth_info.fils_nonce,
+			SIR_FILS_NONCE_LENGTH);
+	buf += SIR_FILS_NONCE_LENGTH;
+	qdf_mem_copy(buf, pe_session->selfMacAddr, QDF_MAC_ADDR_SIZE);
+	buf += QDF_MAC_ADDR_SIZE;
+	qdf_mem_copy(buf, pe_session->bssId, QDF_MAC_ADDR_SIZE);
+	buf += QDF_MAC_ADDR_SIZE;
+
+	if (qdf_get_hmac_hash(lim_get_crypto_type(fils_info->akm),
+				fils_info->ick, fils_info->ick_len, 1,
+				&addr[0], &len, fils_info->key_auth) < 0)
+		pe_err("failed to generate key auth");
+	fils_info->key_auth_len = lim_get_crypto_digest_len(
+				lim_get_crypto_type(fils_info->akm));
+	lim_fils_data_dump("STA Key Auth",
+			fils_info->key_auth, fils_info->key_auth_len);
+}
+
+/**
+ * lim_get_keys()- This API generates keys keydata which is generated after
+ * parsing of auth response.
+ * KCK = L(FILS-Key-Data, 0, KCK_bits)
+ * KEK = L(FILS-Key-Data, KCK_bits, KEK_bits)
+ * TK = L(FILS-Key-Data, KCK_bits + KEK_bits, TK_bits)
+ * FILS-FT = L(FILS-Key-Data, KCK_bits + KEK_bits + TK_bits, FILS-FT_bits)
+ * @pe_session: pe session pointer
+ *
+ * Return: None
+ */
+static void lim_get_keys(tpPESession pe_session)
+{
+	uint8_t key_label[] = PTK_KEY_LABEL;
+	uint8_t *data;
+	uint8_t data_len;
+	struct pe_fils_session *fils_info = pe_session->fils_info;
+	uint8_t key_data[MAX_ICK_LEN + MAX_KEK_LEN + MAX_TK_LEN] = {0};
+	uint8_t key_data_len;
+	uint8_t ick_len = lim_get_ick_len(fils_info->akm);
+	uint8_t kek_len = lim_get_kek_len(fils_info->akm);
+	uint8_t tk_len = lim_get_tk_len(pe_session->encryptType);
+	uint8_t *buf;
+
+	if (!fils_info)
+		return;
+
+	key_data_len = ick_len + kek_len + tk_len;
+
+	data_len = 2 * SIR_FILS_NONCE_LENGTH + 2 * QDF_MAC_ADDR_SIZE;
+	data = qdf_mem_malloc(data_len);
+	if (!data) {
+		pe_err("failed to alloc memory");
+		return;
+	}
+
+	/* Update data */
+	buf = data;
+	qdf_mem_copy(buf, pe_session->selfMacAddr, QDF_MAC_ADDR_SIZE);
+	buf += QDF_MAC_ADDR_SIZE;
+	qdf_mem_copy(buf, pe_session->bssId, QDF_MAC_ADDR_SIZE);
+	buf += QDF_MAC_ADDR_SIZE;
+	qdf_mem_copy(buf, fils_info->fils_nonce, SIR_FILS_NONCE_LENGTH);
+	buf += SIR_FILS_NONCE_LENGTH;
+	qdf_mem_copy(buf, fils_info->auth_info.fils_nonce,
+			SIR_FILS_NONCE_LENGTH);
+	lim_generate_key_data(fils_info, key_label, data, data_len,
+				key_data, key_data_len);
+	buf = key_data;
+	qdf_mem_copy(fils_info->ick, buf, ick_len);
+	fils_info->ick_len = ick_len;
+	buf += ick_len;
+	qdf_mem_copy(fils_info->kek, buf, kek_len);
+	fils_info->kek_len = kek_len;
+	buf += kek_len;
+	qdf_mem_copy(fils_info->tk, buf, tk_len);
+	fils_info->tk_len = tk_len;
+	lim_fils_data_dump("Key Data", key_data, key_data_len);
+	lim_fils_data_dump("ICK", fils_info->ick, ick_len);
+	lim_fils_data_dump("KEK", fils_info->kek, kek_len);
+	lim_fils_data_dump("TK", fils_info->tk, tk_len);
+	qdf_mem_free(data);
+}
+
+/**
+ * lim_generate_pmkid()- This API generates PMKID using hash of erp auth packet
+ * parsing of auth response.
+ * PMKID = Truncate-128(Hash(EAP-Initiate/Reauth))
+ * @pe_session: pe session pointer
+ *
+ * Return: None
+ */
+static void lim_generate_pmkid(tpPESession pe_session)
+{
+	uint8_t hash[SHA384_DIGEST_SIZE];
+	struct pe_fils_session *fils_info = pe_session->fils_info;
+
+	if (!fils_info)
+		return;
+
+	qdf_get_hash(lim_get_crypto_type(fils_info->akm), 1,
+		&fils_info->fils_erp_reauth_pkt,
+		&fils_info->fils_erp_reauth_pkt_len, hash);
+	qdf_mem_copy(fils_info->fils_pmkid, hash, PMKID_LEN);
+	lim_fils_data_dump("PMKID", fils_info->fils_pmkid, PMKID_LEN);
+}
+
+/**
+ * lim_generate_pmk()- This API generates PMK using hmac hash of rmsk data
+ * anonce, snonce will be used as key for this
+ * PMK = HMAC-Hash(SNonce || ANonce, rMSK [ || DHss ])
+ * @pe_session: pe session pointer
+ *
+ * Return: None
+ */
+static void lim_generate_pmk(tpPESession pe_session)
+{
+	uint8_t nounce[2 * SIR_FILS_NONCE_LENGTH] = {0};
+	uint8_t nounce_len = 2 * SIR_FILS_NONCE_LENGTH;
+	uint8_t *addr[1];
+	uint32_t len[1];
+	struct pe_fils_session *fils_info = pe_session->fils_info;
+
+	if (!fils_info)
+		return;
+
+	/* Snounce */
+	qdf_mem_copy(nounce, pe_session->fils_info->fils_nonce,
+			SIR_FILS_NONCE_LENGTH);
+	/* anounce */
+	qdf_mem_copy(nounce + SIR_FILS_NONCE_LENGTH,
+			pe_session->fils_info->auth_info.fils_nonce,
+			SIR_FILS_NONCE_LENGTH);
+	fils_info->fils_pmk_len = lim_get_pmk_length(fils_info->akm);
+
+	if (fils_info->fils_pmk)
+		qdf_mem_free(fils_info->fils_pmk);
+
+	fils_info->fils_pmk = qdf_mem_malloc(fils_info->fils_pmk_len);
+	if (!fils_info->fils_pmk) {
+		pe_err("failed to alloc memory");
+		return;
+	}
+
+	addr[0] = fils_info->fils_rmsk;
+	len[0] = fils_info->fils_rmsk_len;
+	lim_fils_data_dump("Nonce", nounce, nounce_len);
+	if (qdf_get_hmac_hash(lim_get_crypto_type(fils_info->akm), nounce,
+				nounce_len, 1,
+				&addr[0], &len[0], fils_info->fils_pmk) < 0)
+		pe_err("failed to generate PMK");
+	lim_fils_data_dump("PMK", fils_info->fils_pmk, fils_info->fils_pmk_len);
+}
+
+/**
+ * lim_generate_rmsk_data()- This API generates RMSK data using
+ * default kdf as defined in RFC4306.
+ * @pe_session: pe session pointer
+ *
+ * Return: None
+ */
+static void lim_generate_rmsk_data(tpPESession pe_session)
+{
+	uint8_t optional_data[4] = {0};
+	uint8_t rmsk_label[] = RMSK_LABEL;
+	struct pe_fils_session *fils_info = pe_session->fils_info;
+	struct fils_auth_rsp_info *auth_info;
+
+	if (!fils_info)
+		return;
+
+	auth_info = &(pe_session->fils_info->auth_info);
+	fils_info->fils_rmsk_len = fils_info->fils_r_rk_len;
+	fils_info->fils_rmsk = qdf_mem_malloc(fils_info->fils_r_rk_len);
+	if (!fils_info->fils_rmsk) {
+		pe_err("failed to alloc memory");
+		return;
+	}
+
+	/*
+	 * Sequence number sent in EAP-INIT packet,
+	 * it should be in network byte order
+	 */
+	lim_copy_u16_be(&optional_data[0], fils_info->sequence_number);
+	lim_copy_u16_be(&optional_data[2], fils_info->fils_r_rk_len);
+	lim_default_hmac_sha256_kdf(fils_info->fils_r_rk,
+			fils_info->fils_r_rk_len, rmsk_label,
+			optional_data, sizeof(optional_data),
+			fils_info->fils_rmsk, fils_info->fils_rmsk_len);
+	lim_fils_data_dump("RMSK", fils_info->fils_rmsk,
+				fils_info->fils_rmsk_len);
+}
+
+/**
+ * lim_process_auth_wrapped_data()- This API process wrapped data element
+ * of auth response.
+ * @pe_session: pe session pointer
+ * @wrapped_data: wrapped data pointer
+ * @data_len: wrapped data len
+ *
+ * Return: None
+ */
+static QDF_STATUS lim_process_auth_wrapped_data(tpPESession pe_session,
+			uint8_t *wrapped_data, uint32_t data_len)
+{
+	uint8_t code;
+	uint8_t identifier;
+	uint16_t length;
+	uint8_t type;
+	unsigned long flags;
+	struct pe_fils_session *fils_info;
+	uint8_t hash[32], crypto;
+	uint32_t remaining_len = data_len, new_len;
+	uint8_t *input_data[1];
+	uint32_t input_len[1];
+	uint8_t auth_tag_len;
+
+	fils_info = pe_session->fils_info;
+	input_data[0] = wrapped_data;
+	input_len[0] = data_len;
+
+	if (!fils_info)
+		return QDF_STATUS_E_FAILURE;
+
+	pe_debug("trying to process the wrappped data");
+
+	code = *wrapped_data;
+	wrapped_data++;
+	remaining_len--;
+	identifier = *wrapped_data;
+	wrapped_data++;
+	remaining_len--;
+
+	length = lim_get_u16(wrapped_data);
+	wrapped_data += sizeof(uint16_t);
+	remaining_len -= sizeof(uint16_t);
+
+	type = *wrapped_data; /* val should be 2 here */
+	wrapped_data++;
+	remaining_len--;
+
+	flags = *wrapped_data;
+	if (test_bit(7, &flags)) {
+		pe_err("R bit is set in flag, error");
+		return QDF_STATUS_E_FAILURE;
+	}
+	wrapped_data++;
+	remaining_len--;
+
+	fils_info->auth_info.sequence = lim_get_u16_be(wrapped_data);
+	wrapped_data += sizeof(uint16_t);
+	remaining_len -= sizeof(uint16_t);
+	/* Validate Auth sequence number */
+	if (fils_info->auth_info.sequence < fils_info->sequence_number) {
+		pe_err("sequence EAP-finish:%d is less than EAP-init:%d",
+			fils_info->auth_info.sequence,
+			fils_info->sequence_number);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	/* Parse attached TLVs */
+	new_len = lim_process_fils_eap_tlv(pe_session,
+				wrapped_data, remaining_len);
+
+	wrapped_data += remaining_len - new_len;
+	remaining_len = new_len;
+	/* Remove cryptosuite */
+	crypto = *wrapped_data;
+	wrapped_data++;
+	remaining_len--;
+
+	auth_tag_len = lim_get_auth_tag_len(crypto);
+	input_len[0] -= auth_tag_len;
+	/* if we have auth tag remaining */
+	if (remaining_len == auth_tag_len) {
+		qdf_get_hmac_hash(FILS_SHA256_CRYPTO_TYPE, fils_info->fils_r_ik,
+				fils_info->fils_r_ik_len, 1,
+				input_data, input_len, hash);
+	} else {
+		pe_err("invalid remaining len %d",
+			remaining_len);
+	}
+	if (qdf_mem_cmp(wrapped_data, hash, auth_tag_len)) {
+		pe_err("integratity check failed for auth, crypto %d",
+			crypto);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	lim_generate_rmsk_data(pe_session);
+	lim_generate_pmk(pe_session);
+	lim_generate_pmkid(pe_session);
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * lim_is_valid_fils_auth_frame()- This API check whether auth frame is a
+ * valid frame.
+ * @mac_ctx: mac context
+ * @pe_session: pe session pointer
+ * @rx_auth_frm_body: pointer to autherntication frame
+ *
+ * Return: true if frame is valid or fils is disable, false otherwise
+ */
+bool lim_is_valid_fils_auth_frame(tpAniSirGlobal mac_ctx,
+		tpPESession pe_session,
+		tSirMacAuthFrameBody *rx_auth_frm_body)
+{
+	if (!pe_session->fils_info)
+		return true;
+
+	if (pe_session->fils_info->is_fils_connection == false)
+		return true;
+
+	if (qdf_mem_cmp(rx_auth_frm_body->session,
+				pe_session->fils_info->fils_session,
+				SIR_FILS_SESSION_LENGTH)) {
+		lim_fils_data_dump("Current FILS session",
+				pe_session->fils_info->fils_session,
+				SIR_FILS_SESSION_LENGTH);
+		lim_fils_data_dump("FILS Session in pkt",
+				rx_auth_frm_body->session,
+				SIR_FILS_SESSION_LENGTH);
+		return false;
+	}
+	qdf_mem_copy(pe_session->fils_info->auth_info.fils_nonce,
+			rx_auth_frm_body->nonce, SIR_FILS_NONCE_LENGTH);
+	pe_session->fils_info->auth_info.assoc_delay =
+			rx_auth_frm_body->assoc_delay_info;
+	return true;
+}
+
+/**
+ * lim_create_fils_r_ik()- This API create rik using rrk coming from
+ * supplicant.
+ * rIK = KDF (K, S), where
+ * K = rRK and
+ * S = rIK Label + "\0" + cryptosuite + length
+ * The rIK Label is the 8-bit ASCII string:
+ * Re-authentication Integrity Key@ietf.org
+ * @fils_info: fils session info
+ *
+ * Return: None
+ */
+static QDF_STATUS lim_create_fils_r_ik(struct pe_fils_session *fils_info)
+{
+	uint8_t optional_data[SIR_FILS_OPTIONAL_DATA_LEN];
+	uint8_t label[] = SIR_FILS_RIK_LABEL;
+
+	if (!fils_info)
+		return QDF_STATUS_E_FAILURE;
+
+	optional_data[0] = HMAC_SHA256_128;
+	/* basic validation */
+	if (fils_info->fils_r_rk_len <= 0) {
+		pe_err("invalid r_rk length %d", fils_info->fils_r_rk_len);
+		return QDF_STATUS_E_FAILURE;
+	}
+	lim_copy_u16_be(&optional_data[1], fils_info->fils_r_rk_len);
+	fils_info->fils_r_ik = qdf_mem_malloc(fils_info->fils_r_rk_len);
+	if (!fils_info->fils_r_ik) {
+		pe_err("failed to alloc memory");
+		return QDF_STATUS_E_FAILURE;
+	}
+	if (lim_default_hmac_sha256_kdf(fils_info->fils_r_rk,
+				fils_info->fils_r_rk_len, label,
+				optional_data, sizeof(optional_data),
+				fils_info->fils_r_ik, fils_info->fils_r_rk_len)
+			!= QDF_STATUS_SUCCESS) {
+		pe_err("failed to create r_ik");
+		return QDF_STATUS_E_FAILURE;
+	}
+	fils_info->fils_r_ik_len = fils_info->fils_r_rk_len;
+	lim_fils_data_dump("rRk", fils_info->fils_r_rk,
+				fils_info->fils_r_rk_len);
+	lim_fils_data_dump("rIk", fils_info->fils_r_ik,
+				fils_info->fils_r_rk_len);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * lim_create_fils_wrapper_data()- This API create warpped data which will be
+ * sent in auth request.
+ * @fils_info: fils session info
+ *
+ * Return: 0 if success else error code
+ */
+static int lim_create_fils_wrapper_data(struct pe_fils_session *fils_info)
+{
+	uint8_t *buf;
+	uint8_t auth_tag[FILS_AUTH_TAG_MAX_LENGTH] = {0};
+	uint32_t length = 0;
+	int buf_len =
+		/* code + identifier */
+		sizeof(uint8_t) * 2 +
+		/* length */
+		sizeof(uint16_t) +
+		/* type + flags */
+		sizeof(uint8_t) * 2 +
+		/* sequence */
+		sizeof(uint16_t) +
+		/* tlv : type, length, data */
+		sizeof(uint8_t) * 2 + fils_info->keyname_nai_length +
+		/* cryptosuite + auth_tag */
+		sizeof(uint8_t) + lim_get_auth_tag_len(HMAC_SHA256_128);
+
+	if (!fils_info)
+		return 0;
+
+	fils_info->fils_erp_reauth_pkt = qdf_mem_malloc(buf_len);
+	if (!fils_info->fils_erp_reauth_pkt) {
+		pe_err("failed to allocate memory");
+		return -EINVAL;
+	}
+	buf = fils_info->fils_erp_reauth_pkt;
+	*buf = 5;
+	buf++;
+	/* Identifier */
+	*buf = 0;
+	buf++;
+	/* Length */
+	lim_copy_u16_be(buf, buf_len);
+	buf += sizeof(uint16_t);
+	/* type */
+	*buf = SIR_FILS_EAP_INIT_PACKET_TYPE;
+	buf++;
+
+	/**
+	 *  flag
+	 *  0 1 2  <-- 5 -->
+	 * ----------------
+	 * |R|B|L| Reserved|
+	 * -----------------
+	 */
+	*buf = 0x20; /* l=1, b=0, r=0 */
+	buf++;
+	/* sequence */
+	lim_copy_u16_be(buf, fils_info->sequence_number);
+	buf += sizeof(uint16_t);
+
+	/* tlv */
+	/* Type */
+	*buf = SIR_FILS_EAP_TLV_KEYNAME_NAI;
+	buf++;
+	/* NAI Length */
+	*buf = fils_info->keyname_nai_length;
+	buf++;
+	/* NAI Data */
+	qdf_mem_copy(buf, fils_info->keyname_nai_data,
+			fils_info->keyname_nai_length);
+	buf += fils_info->keyname_nai_length;
+
+	/* cryptosuite */
+	*buf = HMAC_SHA256_128;
+	buf++;
+
+	/*
+	 * This should be moved to just after sending probe to save time
+	 * lim_process_switch_channel_join_req ??
+	 */
+	lim_create_fils_r_ik(fils_info);
+	fils_info->fils_erp_reauth_pkt_len = buf_len;
+	length = fils_info->fils_erp_reauth_pkt_len -
+			lim_get_auth_tag_len(HMAC_SHA256_128);
+	qdf_get_hmac_hash(FILS_SHA256_CRYPTO_TYPE,
+			fils_info->fils_r_ik, fils_info->fils_r_ik_len, 1,
+			&fils_info->fils_erp_reauth_pkt, &length, auth_tag);
+
+	lim_fils_data_dump("Auth tag", auth_tag,
+			lim_get_auth_tag_len(HMAC_SHA256_128));
+	lim_fils_data_dump("EAP init pkt", fils_info->fils_erp_reauth_pkt,
+			fils_info->fils_erp_reauth_pkt_len);
+
+	qdf_mem_copy(buf, auth_tag, lim_get_auth_tag_len(HMAC_SHA256_128));
+	buf += lim_get_auth_tag_len(HMAC_SHA256_128);
+
+	return buf_len;
+}
+
+/**
+ * lim_add_fils_data_to_auth_frame()- This API add fils data to auth frame.
+ * Following will be added in this.
+ * RSNIE
+ * SNonce
+ * Session
+ * Wrapped data
+ * @session: PE session
+ * @body: pointer to auth frame where data needs to be added
+ *
+ * Return: None
+ */
+void lim_add_fils_data_to_auth_frame(tpPESession session,
+		uint8_t *body)
+{
+	struct pe_fils_session *fils_info;
+
+	fils_info = session->fils_info;
+
+	if (!fils_info)
+		return;
+
+	/* RSN IE */
+	qdf_mem_copy(body, fils_info->rsn_ie, fils_info->rsn_ie_len);
+	body += fils_info->rsn_ie_len;
+	lim_fils_data_dump("FILS RSN", fils_info->rsn_ie,
+			fils_info->rsn_ie_len);
+
+	/* ***Nounce*** */
+	/* Add element id */
+	*body = SIR_MAX_ELEMENT_ID;
+	body++;
+	/* Add nounce length + 1 for ext element id */
+	*body = SIR_FILS_NONCE_LENGTH + 1;
+	body++;
+	/* Add ext element */
+	*body = SIR_FILS_NONCE_EXT_EID;
+	body++;
+	/* Add data */
+	cds_rand_get_bytes(0, fils_info->fils_nonce, SIR_FILS_NONCE_LENGTH);
+	qdf_mem_copy(body, fils_info->fils_nonce, SIR_FILS_NONCE_LENGTH);
+	body = body + SIR_FILS_NONCE_LENGTH;
+	/* Dump data */
+	lim_fils_data_dump("fils anonce", fils_info->fils_nonce,
+			SIR_FILS_NONCE_LENGTH);
+
+	/*   *** Session ***  */
+	/* Add element id */
+	*body = SIR_MAX_ELEMENT_ID;
+	body++;
+	/* Add nounce length + 1 for ext element id */
+	*body = SIR_FILS_SESSION_LENGTH + 1;
+	body++;
+	/* Add ext element */
+	*body = SIR_FILS_SESSION_EXT_EID;
+	body++;
+	/* Add data */
+	cds_rand_get_bytes(0, fils_info->fils_session, SIR_FILS_SESSION_LENGTH);
+	qdf_mem_copy(body, fils_info->fils_session, SIR_FILS_SESSION_LENGTH);
+	body = body + SIR_FILS_SESSION_LENGTH;
+	/* dump data */
+	lim_fils_data_dump("Fils Session",
+		fils_info->fils_session, SIR_FILS_SESSION_LENGTH);
+
+	/*  ERP Packet  */
+	/* Add element id */
+	*body = SIR_MAX_ELEMENT_ID;
+	body++;
+	/* Add packet length + 1 for ext element id */
+	*body = fils_info->fils_erp_reauth_pkt_len + 1;
+	body++;
+	/* Add ext element */
+	*body = SIR_FILS_WRAPPED_DATA_EXT_EID;
+	body++;
+	/* Copy data */
+	qdf_mem_copy(body, fils_info->fils_erp_reauth_pkt,
+			fils_info->fils_erp_reauth_pkt_len);
+	lim_fils_data_dump("Fils ERP reauth Pkt",
+			fils_info->fils_erp_reauth_pkt,
+			fils_info->fils_erp_reauth_pkt_len);
+	body = body + fils_info->fils_erp_reauth_pkt_len;
+}
+
+/**
+ * lim_process_fils_auth_frame2()- This API process fils data from auth response
+ * @mac_ctx: mac context
+ * @session: PE session
+ * @rx_auth_frm_body: pointer to auth frame
+ *
+ * Return: true if fils data needs to be processed else false
+ */
+bool lim_process_fils_auth_frame2(tpAniSirGlobal mac_ctx,
+		tpPESession pe_session,
+		tSirMacAuthFrameBody *rx_auth_frm_body)
+{
+	bool pmkid_found = false;
+	int i;
+	tDot11fIERSN dot11f_ie_rsn = {0};
+
+	if (!pe_session->fils_info)
+		return false;
+
+	if (rx_auth_frm_body->authAlgoNumber != eSIR_FILS_SK_WITHOUT_PFS)
+		return false;
+
+	dot11f_unpack_ie_rsn(mac_ctx,
+				&rx_auth_frm_body->rsn_ie.info[0],
+				rx_auth_frm_body->rsn_ie.length,
+				&dot11f_ie_rsn, 0);
+
+	for (i = 0; i < dot11f_ie_rsn.pmkid_count; i++) {
+		if (qdf_mem_cmp(dot11f_ie_rsn.pmkid[i],
+		    pe_session->fils_info->fils_pmkid,
+		    PMKID_LEN) == 0) {
+			pmkid_found = true;
+			pe_debug("pmkid match in rsn ie total_count %d",
+				dot11f_ie_rsn.pmkid_count);
+			break;
+		}
+	}
+	if (!pmkid_found) {
+		if (QDF_STATUS_SUCCESS !=
+		    lim_process_auth_wrapped_data(pe_session,
+			rx_auth_frm_body->wrapped_data,
+			rx_auth_frm_body->wrapped_data_len))
+			return false;
+	} else {
+		lim_fils_data_dump("PMK",
+			pe_session->fils_info->fils_pmk,
+			pe_session->fils_info->fils_pmk_len);
+	}
+	lim_get_keys(pe_session);
+	lim_generate_key_auth(pe_session);
+	lim_generate_ap_key_auth(pe_session);
+	return true;
+}
+
+/**
+ * lim_update_fils_config()- This API update fils session info to csr config
+ * from join request.
+ * @session: PE session
+ * @sme_join_req: pointer to join request
+ *
+ * Return: None
+ */
+void lim_update_fils_config(tpPESession session,
+		tpSirSmeJoinReq sme_join_req)
+{
+	struct pe_fils_session *csr_fils_info;
+	struct cds_fils_connection_info *fils_config_info;
+
+	fils_config_info = &sme_join_req->fils_con_info;
+	csr_fils_info = session->fils_info;
+
+	if (!csr_fils_info)
+		return;
+
+	if (fils_config_info->is_fils_connection == false)
+		return;
+
+	csr_fils_info->is_fils_connection =
+		fils_config_info->is_fils_connection;
+	csr_fils_info->keyname_nai_length =
+		fils_config_info->key_nai_length;
+	csr_fils_info->fils_r_rk_len =
+		fils_config_info->r_rk_length;
+	csr_fils_info->akm = fils_config_info->akm_type;
+	csr_fils_info->auth = fils_config_info->auth_type;
+	csr_fils_info->sequence_number = fils_config_info->sequence_number;
+	csr_fils_info->keyname_nai_data =
+		qdf_mem_malloc(fils_config_info->key_nai_length);
+	if (!csr_fils_info->keyname_nai_data) {
+		pe_err("failed to alloc memory");
+		return;
+	}
+	qdf_mem_copy(csr_fils_info->keyname_nai_data,
+			fils_config_info->keyname_nai,
+			fils_config_info->key_nai_length);
+	csr_fils_info->fils_r_rk =
+		qdf_mem_malloc(fils_config_info->r_rk_length);
+	if (!csr_fils_info->fils_r_rk) {
+		pe_err("failed to alloc memory");
+		qdf_mem_free(csr_fils_info->keyname_nai_data);
+		return;
+	}
+	qdf_mem_copy(csr_fils_info->fils_r_rk,
+			fils_config_info->r_rk,
+			fils_config_info->r_rk_length);
+
+	qdf_mem_copy(csr_fils_info->fils_pmkid,
+			fils_config_info->pmkid, PMKID_LEN);
+	csr_fils_info->rsn_ie_len = sme_join_req->rsnIE.length;
+	qdf_mem_copy(csr_fils_info->rsn_ie,
+			sme_join_req->rsnIE.rsnIEdata,
+			sme_join_req->rsnIE.length);
+
+	csr_fils_info->fils_pmk_len = fils_config_info->pmk_len;
+	if (fils_config_info->pmk_len) {
+		csr_fils_info->fils_pmk =
+			qdf_mem_malloc(fils_config_info->pmk_len);
+		if (!csr_fils_info->fils_pmk) {
+			qdf_mem_free(csr_fils_info->keyname_nai_data);
+			qdf_mem_free(csr_fils_info->fils_r_rk);
+			pe_err("failed to alloc memory");
+			return;
+		}
+		qdf_mem_copy(csr_fils_info->fils_pmk, fils_config_info->pmk,
+			fils_config_info->pmk_len);
+	}
+	pe_debug("fils=%d nai-len=%d rrk_len=%d akm=%d auth=%d pmk_len=%d",
+		fils_config_info->is_fils_connection,
+		fils_config_info->key_nai_length,
+		fils_config_info->r_rk_length,
+		fils_config_info->akm_type,
+		fils_config_info->auth_type,
+		fils_config_info->pmk_len);
+}
+
+#define EXTENDED_IE_HEADER_LEN 3
+/**
+ * lim_create_fils_auth_data()- This API creates the fils auth data
+ * which needs to be sent in auth req.
+ * @mac_ctx: mac context
+ * @auth_frame: pointer to auth frame
+ * @session: PE session
+ *
+ * Return: length of fils data
+ */
+uint32_t lim_create_fils_auth_data(tpAniSirGlobal mac_ctx,
+		tpSirMacAuthFrameBody auth_frame,
+		tpPESession session)
+{
+	uint32_t frame_len = 0;
+	uint32_t wrapped_data_len;
+
+	if (!session->fils_info)
+		return 0;
+
+	/* These memory may already been allocated if auth retry */
+	if (session->fils_info->fils_r_ik) {
+		qdf_mem_free(session->fils_info->fils_r_ik);
+		session->fils_info->fils_r_ik = NULL;
+	}
+	if  (session->fils_info->fils_erp_reauth_pkt) {
+		qdf_mem_free(session->fils_info->fils_erp_reauth_pkt);
+		session->fils_info->fils_erp_reauth_pkt = NULL;
+	}
+	if (auth_frame->authAlgoNumber == eSIR_FILS_SK_WITHOUT_PFS) {
+		frame_len += session->fils_info->rsn_ie_len;
+		/* FILS nounce */
+		frame_len += SIR_FILS_NONCE_LENGTH + EXTENDED_IE_HEADER_LEN;
+		/* FILS Session */
+		frame_len += SIR_FILS_SESSION_LENGTH + EXTENDED_IE_HEADER_LEN;
+		/* Calculate data/length for FILS Wrapped Data */
+		wrapped_data_len =
+			lim_create_fils_wrapper_data(session->fils_info);
+		if (wrapped_data_len < 0) {
+			pe_err("failed to create warpped data");
+			return 0;
+		}
+		frame_len += wrapped_data_len + EXTENDED_IE_HEADER_LEN;
+	}
+	return frame_len;
+}
+#endif
diff --git a/core/mac/src/pe/lim/lim_process_mlm_req_messages.c b/core/mac/src/pe/lim/lim_process_mlm_req_messages.c
index 2f39e45..c290d09 100644
--- a/core/mac/src/pe/lim/lim_process_mlm_req_messages.c
+++ b/core/mac/src/pe/lim/lim_process_mlm_req_messages.c
@@ -47,6 +47,7 @@
 #endif
 #include "wma_if.h"
 #include "wlan_reg_services_api.h"
+#include "lim_process_fils.h"
 
 static void lim_process_mlm_start_req(tpAniSirGlobal, uint32_t *);
 static void lim_process_mlm_join_req(tpAniSirGlobal, uint32_t *);
@@ -2296,6 +2297,7 @@
 			auth_frame.authStatusCode = 0;
 			pe_warn("Retry Auth");
 			mac_ctx->auth_ack_status = LIM_AUTH_ACK_NOT_RCD;
+			lim_increase_fils_sequence_number(session_entry);
 			lim_send_auth_mgmt_frame(mac_ctx,
 				&auth_frame,
 				mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr,
diff --git a/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c b/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c
index 73d1b54..274c3d9 100644
--- a/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c
+++ b/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c
@@ -2243,6 +2243,29 @@
 	}
 }
 
+#ifdef WLAN_FEATURE_FILS_SK
+/*
+ * lim_update_fils_auth_mode: API to update Auth mode in case of fils session
+ * @session_entry: pe session entry
+ * @auth_mode: auth mode needs to be updated
+ *
+ * Return: None
+ */
+static void lim_update_fils_auth_mode(tpPESession session_entry,
+			tAniAuthType *auth_mode)
+{
+	if (!session_entry->fils_info)
+		return;
+
+	if (session_entry->fils_info->is_fils_connection)
+		*auth_mode = session_entry->fils_info->auth;
+}
+#else
+static void lim_update_fils_auth_mode(tpPESession session_entry,
+			tAniAuthType *auth_mode)
+{ }
+#endif
+
 /**
  * csr_neighbor_roam_handoff_req_hdlr - Processes handoff request
  * @mac_ctx:  Pointer to mac context
@@ -2295,6 +2318,7 @@
 		else
 			authMode = cfgAuthType;
 
+		lim_update_fils_auth_mode(session_entry, &authMode);
 		/* Trigger MAC based Authentication */
 		pMlmAuthReq = qdf_mem_malloc(sizeof(tLimMlmAuthReq));
 		if (NULL == pMlmAuthReq) {
diff --git a/core/mac/src/pe/lim/lim_process_sme_req_messages.c b/core/mac/src/pe/lim/lim_process_sme_req_messages.c
index b74f7c3..ac831c2 100644
--- a/core/mac/src/pe/lim/lim_process_sme_req_messages.c
+++ b/core/mac/src/pe/lim/lim_process_sme_req_messages.c
@@ -64,6 +64,7 @@
 
 #include <lim_ft.h>
 #include "cds_regdomain.h"
+#include "lim_process_fils.h"
 
 /*
  * This overhead is time for sending NOA start to host in case of GO/sending
@@ -1786,6 +1787,7 @@
 		session->txLdpcIniFeatureEnabled =
 			sme_join_req->txLdpcIniFeatureEnabled;
 
+		lim_update_fils_config(session, sme_join_req);
 		if (session->bssType == eSIR_INFRASTRUCTURE_MODE) {
 			session->limSystemRole = eLIM_STA_ROLE;
 		} else {
diff --git a/core/mac/src/pe/lim/lim_security_utils.c b/core/mac/src/pe/lim/lim_security_utils.c
index e6d6afb..18f883e 100644
--- a/core/mac/src/pe/lim/lim_security_utils.c
+++ b/core/mac/src/pe/lim/lim_security_utils.c
@@ -487,6 +487,29 @@
 	lim_post_sme_message(pMac, LIM_MLM_AUTH_CNF, (uint32_t *) &mlmAuthCnf);
 } /*** end lim_restore_from_auth_state() ***/
 
+#ifdef WLAN_FEATURE_FILS_SK
+/*
+ * lim_get_fils_auth_data_len: This API will return
+ * extra auth data len in case of fils session
+ *
+ * Return: fils data len in auth packet
+ */
+static int lim_get_fils_auth_data_len(void)
+{
+	int len = sizeof(tSirMacRsnInfo) +
+			sizeof(uint8_t) + /* assoc_delay_info */
+			SIR_FILS_SESSION_LENGTH +
+			sizeof(uint8_t) + /* wrapped_data_len */
+			SIR_FILS_WRAPPED_DATA_MAX_SIZE + SIR_FILS_NONCE_LENGTH;
+	return len;
+}
+#else
+static inline int lim_get_fils_auth_data_len(void)
+{
+	return 0;
+}
+#endif
+
 /**
  * lim_encrypt_auth_frame()
  *
@@ -519,8 +542,7 @@
 	uint8_t seed[LIM_SEED_LENGTH], icv[SIR_MAC_WEP_ICV_LENGTH];
 	uint16_t frame_len;
 
-	frame_len = ((tpSirMacAuthFrameBody)pPlainText)->length +
-		     SIR_MAC_AUTH_FRAME_INFO_LEN + SIR_MAC_CHALLENGE_ID_LEN;
+	frame_len = sizeof(tSirMacAuthFrameBody) - lim_get_fils_auth_data_len();
 	keyLength += 3;
 
 	/* Bytes 3-7 of seed is key */
diff --git a/core/mac/src/pe/lim/lim_send_management_frames.c b/core/mac/src/pe/lim/lim_send_management_frames.c
index a038d01..f9cbf7a 100644
--- a/core/mac/src/pe/lim/lim_send_management_frames.c
+++ b/core/mac/src/pe/lim/lim_send_management_frames.c
@@ -63,6 +63,7 @@
 #include "wma_types.h"
 #include <cdp_txrx_cmn.h>
 #include <cdp_txrx_peer_ops.h>
+#include "lim_process_fils.h"
 
 /**
  *
@@ -2083,7 +2084,6 @@
  *
  * Return: void
  */
-
 void
 lim_send_auth_mgmt_frame(tpAniSirGlobal mac_ctx,
 			 tpSirMacAuthFrameBody auth_frame,
@@ -2147,6 +2147,8 @@
 		body_len = SIR_MAC_AUTH_FRAME_INFO_LEN;
 		frame_len = sizeof(tSirMacMgmtHdr) + body_len;
 
+		frame_len += lim_create_fils_auth_data(mac_ctx,
+						auth_frame, session);
 		if (auth_frame->authAlgoNumber == eSIR_FT_AUTH) {
 			if (NULL != session->ftPEContext.pFTPreAuthReq &&
 			    0 != session->ftPEContext.pFTPreAuthReq->
@@ -2329,6 +2331,11 @@
 						pbssDescription->mdie[0],
 					SIR_MDIE_SIZE);
 			}
+		} else if (auth_frame->authAlgoNumber ==
+				eSIR_FILS_SK_WITHOUT_PFS) {
+			/* TODO MDIE */
+			pe_debug("appending fils Auth data");
+			lim_add_fils_data_to_auth_frame(session, body);
 		}
 
 		pe_debug("*** Sending Auth seq# %d status %d (%d) to "
diff --git a/core/mac/src/pe/lim/lim_ser_des_utils.h b/core/mac/src/pe/lim/lim_ser_des_utils.h
index 82b9c48..e2b5208 100644
--- a/core/mac/src/pe/lim/lim_ser_des_utils.h
+++ b/core/mac/src/pe/lim/lim_ser_des_utils.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2015,2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2015, 2016-2017 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -95,6 +95,31 @@
 #endif
 }
 
+/**
+ * lim_copy_u16_be()- This API copies a u16 value in buffer
+ * to network byte order
+ * @ptr: pointer to buffer
+ * @u16_val: value needs to be copied
+ *
+ * Return: None
+ */
+static inline void lim_copy_u16_be(uint8_t *ptr, uint16_t u16_val)
+{
+	ptr[0] = u16_val >> 8;
+	ptr[1] = u16_val & 0xff;
+}
+
+/**
+ * lim_copy_u16_be()- This API reads u16 value from network byte order buffer
+ * @ptr: pointer to buffer
+ *
+ * Return: 16bit value
+ */
+static inline uint16_t lim_get_u16_be(uint8_t *buf)
+{
+	return (buf[0] << 8) | buf[1];
+}
+
 tSirRetStatus lim_send_disassoc_frm_req_ser_des(tpAniSirGlobal mac_ctx,
 		struct sme_send_disassoc_frm_req *disassoc_frm_req,
 		uint8_t *buf);
diff --git a/core/mac/src/pe/lim/lim_session.c b/core/mac/src/pe/lim/lim_session.c
index 957e871..747981c 100644
--- a/core/mac/src/pe/lim/lim_session.c
+++ b/core/mac/src/pe/lim/lim_session.c
@@ -267,6 +267,86 @@
 }
 #endif
 
+#ifdef WLAN_FEATURE_FILS_SK
+/**
+ * pe_delete_fils_info: API to delete fils session info
+ * @session: pe session
+ *
+ * Return: void
+ */
+static void pe_delete_fils_info(tpPESession session)
+{
+	struct pe_fils_session *fils_info;
+
+	if (!session || (session && !session->valid)) {
+		QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG,
+			  FL("session is not valid"));
+		return;
+	}
+	fils_info = session->fils_info;
+	if (!fils_info) {
+		QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG,
+			  FL("fils info not found"));
+		return;
+	}
+	if (fils_info->keyname_nai_data)
+		qdf_mem_free(fils_info->keyname_nai_data);
+	if (fils_info->fils_erp_reauth_pkt)
+		qdf_mem_free(fils_info->fils_erp_reauth_pkt);
+	if (fils_info->fils_r_rk)
+		qdf_mem_free(fils_info->fils_r_rk);
+	if (fils_info->fils_r_ik)
+		qdf_mem_free(fils_info->fils_r_ik);
+	if (fils_info->fils_eap_finish_pkt)
+		qdf_mem_free(fils_info->fils_eap_finish_pkt);
+	if (fils_info->fils_rmsk)
+		qdf_mem_free(fils_info->fils_rmsk);
+	if (fils_info->fils_pmk)
+		qdf_mem_free(fils_info->fils_pmk);
+	if (fils_info->auth_info.keyname)
+		qdf_mem_free(fils_info->auth_info.keyname);
+	if (fils_info->auth_info.domain_name)
+		qdf_mem_free(fils_info->auth_info.domain_name);
+	qdf_mem_free(fils_info);
+	session->fils_info = NULL;
+}
+/**
+ * pe_init_fils_info: API to initialize fils session info elements to null
+ * @session: pe session
+ *
+ * Return: void
+ */
+static void pe_init_fils_info(tpPESession session)
+{
+	struct pe_fils_session *fils_info;
+
+	if (!session || (session && !session->valid)) {
+		QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG,
+			  FL("session is not valid"));
+		return;
+	}
+	session->fils_info = qdf_mem_malloc(sizeof(struct pe_fils_session));
+	fils_info = session->fils_info;
+	if (!fils_info) {
+		QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG,
+			  FL("fils info not found"));
+		return;
+	}
+	fils_info->keyname_nai_data = NULL;
+	fils_info->fils_erp_reauth_pkt = NULL;
+	fils_info->fils_r_rk = NULL;
+	fils_info->fils_r_ik = NULL;
+	fils_info->fils_eap_finish_pkt = NULL;
+	fils_info->fils_rmsk = NULL;
+	fils_info->fils_pmk = NULL;
+	fils_info->auth_info.keyname = NULL;
+	fils_info->auth_info.domain_name = NULL;
+}
+#else
+static void pe_delete_fils_info(tpPESession session) { }
+static void pe_init_fils_info(tpPESession session) { }
+#endif
+
 /**
  * lim_get_peer_idxpool_size: get number of peer idx pool size
  * @num_sta: Max number of STA
@@ -454,6 +534,7 @@
 		if (status != QDF_STATUS_SUCCESS)
 			pe_err("cannot create or start protectionFieldsResetTimer");
 	}
+	pe_init_fils_info(session_ptr);
 	pe_init_pmf_comeback_timer(pMac, session_ptr, *sessionId);
 	session_ptr->ht_client_cnt = 0;
 
@@ -746,6 +827,7 @@
 		qdf_mc_timer_stop(&session->pmfComebackTimer);
 	qdf_mc_timer_destroy(&session->pmfComebackTimer);
 #endif
+	pe_delete_fils_info(session);
 	session->valid = false;
 
 	if (session->access_policy_vendor_ie)
diff --git a/core/mac/src/sys/legacy/src/utils/src/parser_api.c b/core/mac/src/sys/legacy/src/utils/src/parser_api.c
index 00a927e..ae1fea9 100644
--- a/core/mac/src/sys/legacy/src/utils/src/parser_api.c
+++ b/core/mac/src/sys/legacy/src/utils/src/parser_api.c
@@ -4139,6 +4139,51 @@
 
 } /* End sir_convert_beacon_frame2_struct. */
 
+#ifdef WLAN_FEATURE_FILS_SK
+/* sir_update_auth_frame2_struct_fils_conf: API to update fils info from auth
+ * packet type 2
+ * @auth: auth packet pointer received from AP
+ * @auth_frame: data structure needs to be updated
+ *
+ * Return: None
+ */
+static void sir_update_auth_frame2_struct_fils_conf(tDot11fAuthentication *auth,
+				tpSirMacAuthFrameBody auth_frame)
+{
+	if (auth->AuthAlgo.algo != eSIR_FILS_SK_WITHOUT_PFS)
+		return;
+
+	if (auth->fils_assoc_delay_info.present)
+		auth_frame->assoc_delay_info =
+			auth->fils_assoc_delay_info.assoc_delay_info;
+
+	if (auth->fils_session.present)
+		qdf_mem_copy(auth_frame->session, auth->fils_session.session,
+			SIR_FILS_SESSION_LENGTH);
+
+	if (auth->fils_nonce.present)
+		qdf_mem_copy(auth_frame->nonce, auth->fils_nonce.nonce,
+			SIR_FILS_NONCE_LENGTH);
+
+	if (auth->fils_wrapped_data.present) {
+		qdf_mem_copy(auth_frame->wrapped_data,
+			auth->fils_wrapped_data.wrapped_data,
+			auth->fils_wrapped_data.num_wrapped_data);
+		auth_frame->wrapped_data_len =
+			auth->fils_wrapped_data.num_wrapped_data;
+	}
+	if (auth->RSNOpaque.present) {
+		qdf_mem_copy(auth_frame->rsn_ie.info, auth->RSNOpaque.data,
+			auth->RSNOpaque.num_data);
+		auth_frame->rsn_ie.length = auth->RSNOpaque.num_data;
+	}
+}
+#else
+static void sir_update_auth_frame2_struct_fils_conf(tDot11fAuthentication *auth,
+				tpSirMacAuthFrameBody auth_frame)
+{ }
+#endif
+
 tSirRetStatus
 sir_convert_auth_frame2_struct(tpAniSirGlobal pMac,
 			       uint8_t *pFrame,
@@ -4174,6 +4219,7 @@
 		qdf_mem_copy(pAuth->challengeText, auth.ChallengeText.text,
 			     auth.ChallengeText.num_text);
 	}
+	sir_update_auth_frame2_struct_fils_conf(&auth, pAuth);
 
 	return eSIR_SUCCESS;
 
diff --git a/core/sme/inc/csr_api.h b/core/sme/inc/csr_api.h
index 3a9c577..f361c58 100644
--- a/core/sme/inc/csr_api.h
+++ b/core/sme/inc/csr_api.h
@@ -409,6 +409,10 @@
 	struct sCsrChannel_ pcl_channels;
 	struct qdf_mac_addr bssid_hint;
 	enum tQDF_ADAPTER_MODE csrPersona;
+#ifdef WLAN_FEATURE_FILS_SK
+	bool realm_check;
+	uint8_t fils_realm[2];
+#endif
 } tCsrScanResultFilter;
 
 typedef struct sCsrChnPower_ {
@@ -999,7 +1003,10 @@
 	bool do_not_roam;
 	uint32_t cac_duration_ms;
 	uint32_t dfs_regdomain;
-
+#ifdef WLAN_FEATURE_FILS_SK
+	bool fils_connection;
+	struct cds_fils_connection_info *fils_con_info;
+#endif
 } tCsrRoamProfile;
 
 #ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH
diff --git a/core/sme/inc/csr_internal.h b/core/sme/inc/csr_internal.h
index 4e246cd..ac15f00 100644
--- a/core/sme/inc/csr_internal.h
+++ b/core/sme/inc/csr_internal.h
@@ -968,6 +968,8 @@
 	uint8_t uapsd_mask;
 	struct scan_cmd_info scan_info;
 	qdf_mc_timer_t roaming_offload_timer;
+	bool is_fils_connection;
+	uint16_t fils_seq_num;
 } tCsrRoamSession;
 
 typedef struct tagCsrRoamStruct {
diff --git a/core/sme/src/csr/csr_api_roam.c b/core/sme/src/csr/csr_api_roam.c
index fa09940..3d8e91c 100644
--- a/core/sme/src/csr/csr_api_roam.c
+++ b/core/sme/src/csr/csr_api_roam.c
@@ -54,6 +54,7 @@
 #include "sme_nan_datapath.h"
 #include "pld_common.h"
 #include "wlan_reg_services_api.h"
+#include "qdf_crypto.h"
 #include <wlan_logging_sock_svc.h>
 #include "wlan_objmgr_psoc_obj.h"
 #include <wlan_scan_ucfg_api.h>
@@ -7493,6 +7494,38 @@
 	return release_cmd;
 }
 
+#ifdef WLAN_FEATURE_FILS_SK
+/*
+ * update_profile_fils_info: API to update FILS info from
+ * source profile to destination profile.
+ * @des_profile: pointer to destination profile
+ * @src_profile: pointer to souce profile
+ *
+ * Return: None
+ */
+static inline void update_profile_fils_info(tCsrRoamProfile *des_profile,
+					tCsrRoamProfile *src_profile)
+{
+	if (!src_profile->fils_con_info)
+		return;
+
+	if (src_profile->fils_con_info->is_fils_connection) {
+		des_profile->fils_con_info =
+			qdf_mem_malloc(sizeof(struct cds_fils_connection_info));
+		if (!des_profile->fils_con_info) {
+			sme_err("failed to allocate memory");
+			return;
+		}
+		qdf_mem_copy(des_profile->fils_con_info,
+			     src_profile->fils_con_info,
+			     sizeof(struct cds_fils_connection_info));
+	}
+}
+#else
+static inline void update_profile_fils_info(tCsrRoamProfile *des_profile,
+					tCsrRoamProfile *src_profile)
+{ }
+#endif
 QDF_STATUS csr_roam_copy_profile(tpAniSirGlobal pMac,
 				 tCsrRoamProfile *pDstProfile,
 				 tCsrRoamProfile *pSrcProfile)
@@ -7664,6 +7697,9 @@
 	}
 	qdf_mem_copy(&pDstProfile->addIeParams, &pSrcProfile->addIeParams,
 			sizeof(tSirAddIeParams));
+
+	update_profile_fils_info(pDstProfile, pSrcProfile);
+
 	if (pSrcProfile->supported_rates.numRates) {
 		qdf_mem_copy(pDstProfile->supported_rates.rate,
 				pSrcProfile->supported_rates.rate,
@@ -7943,6 +7979,27 @@
 	return QDF_STATUS_SUCCESS;
 }
 
+#ifdef WLAN_FEATURE_FILS_SK
+/**
+ * csr_is_fils_connection() - API to check if FILS connection
+ * @profile: CSR Roam Profile
+ *
+ * Return: true, if fils connection, false otherwise
+ */
+static bool csr_is_fils_connection(tCsrRoamProfile *profile)
+{
+	if (!profile->fils_con_info)
+		return false;
+
+	return profile->fils_con_info->is_fils_connection;
+}
+#else
+static bool csr_is_fils_connection(tCsrRoamProfile *pProfile)
+{
+	return false;
+}
+#endif
+
 QDF_STATUS csr_roam_connect(tpAniSirGlobal pMac, uint32_t sessionId,
 		tCsrRoamProfile *pProfile,
 		uint32_t *pRoamId)
@@ -7974,6 +8031,7 @@
 
 	/* Initialize the count before proceeding with the Join requests */
 	pSession->join_bssid_count = 0;
+	pSession->is_fils_connection = csr_is_fils_connection(pProfile);
 	sme_debug(
 		"called  BSSType = %s (%d) authtype = %d  encryType = %d",
 		sme_bss_type_to_string(pProfile->BSSType),
@@ -10346,6 +10404,62 @@
 	return status;
 }
 
+#ifdef WLAN_FEATURE_FILS_SK
+/*
+ * csr_create_fils_realm_hash: API to create hash using realm
+ * @fils_con_info: fils connection info obtained from supplicant
+ * @tmp_hash: pointer to new hash
+ *
+ * Return: None
+ */
+static bool
+csr_create_fils_realm_hash(struct cds_fils_connection_info *fils_con_info,
+			   uint8_t *tmp_hash)
+{
+	uint8_t hash[SHA256_DIGEST_SIZE] = {0};
+	uint8_t *data[1];
+
+	if (!fils_con_info->realm_len)
+		return false;
+
+	data[0] = fils_con_info->realm;
+	qdf_get_hash(SHA256_CRYPTO_TYPE, 1, data,
+			&fils_con_info->realm_len, hash);
+	qdf_trace_hex_dump(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_DEBUG,
+				   hash, SHA256_DIGEST_SIZE);
+	qdf_mem_copy(tmp_hash, hash, 2);
+	return true;
+}
+
+/*
+ * csr_update_fils_scan_filter: update scan filter in case of fils session
+ * @scan_fltr: pointer to scan filer
+ * @profile: csr profile pointer
+ *
+ * Return: None
+ */
+static void csr_update_fils_scan_filter(tCsrScanResultFilter *scan_fltr,
+				tCsrRoamProfile *profile)
+{
+	if (profile->fils_con_info &&
+	    profile->fils_con_info->is_fils_connection) {
+		uint8_t realm_hash[2];
+
+		sme_debug("creating realm based on fils info %d",
+			profile->fils_con_info->is_fils_connection);
+		scan_fltr->realm_check =  csr_create_fils_realm_hash(
+				profile->fils_con_info, realm_hash);
+		memcpy(scan_fltr->fils_realm, realm_hash,
+			sizeof(uint8_t) * 2);
+	}
+
+}
+#else
+static void csr_update_fils_scan_filter(tCsrScanResultFilter *scan_fltr,
+				tCsrRoamProfile *profile)
+{ }
+#endif
+
 /*
  * Prepare a filter base on a profile for parsing the scan results.
  * Upon successful return, caller MUST call csr_free_scan_filter on
@@ -10500,6 +10614,7 @@
 	scan_fltr->MFPCapable = profile->MFPCapable;
 #endif
 	scan_fltr->csrPersona = profile->csrPersona;
+	csr_update_fils_scan_filter(scan_fltr, profile);
 
 free_filter:
 	if (!QDF_IS_STATUS_SUCCESS(status))
@@ -13813,11 +13928,12 @@
 				pmksa->cache_id, CACHE_ID_LEN)))
 			fMatchFound = 1;
 
-		if (fMatchFound)
-			/* Clear this - the matched entry */
+		if (fMatchFound) {
+			/* Clear this - matched entry */
 			qdf_mem_zero(cached_pmksa,
 				     sizeof(tPmkidCacheInfo));
 			break;
+		}
 	}
 
 	if (Index == CSR_MAX_PMKID_ALLOWED && !fMatchFound) {
@@ -14241,6 +14357,34 @@
 }
 #endif
 
+#ifdef WLAN_FEATURE_FILS_SK
+/*
+ * csr_update_fils_connection_info: Copy fils connection info to join request
+ * @profile: pointer to profile
+ * @csr_join_req: csr join request
+ *
+ * Return: None
+ */
+static void csr_update_fils_connection_info(tCsrRoamProfile *profile,
+					tSirSmeJoinReq *csr_join_req)
+{
+	if (!profile->fils_con_info)
+		return;
+
+	if (profile->fils_con_info->is_fils_connection) {
+		qdf_mem_copy(&csr_join_req->fils_con_info,
+			     profile->fils_con_info,
+			     sizeof(struct cds_fils_connection_info));
+	} else {
+		qdf_mem_zero(&csr_join_req->fils_con_info,
+			     sizeof(struct cds_fils_connection_info));
+	}
+}
+#else
+static void csr_update_fils_connection_info(tCsrRoamProfile *profile,
+					tSirSmeJoinReq *csr_join_req)
+{ }
+#endif
 
 /**
  * The communication between HDD and LIM is thru mailbox (MB).
@@ -14912,7 +15056,7 @@
 		qdf_mem_copy(&csr_join_req->bssDescription, pBssDescription,
 				pBssDescription->length +
 				sizeof(pBssDescription->length));
-
+		csr_update_fils_connection_info(pProfile, csr_join_req);
 		/*
 		 * conc_custom_rule1:
 		 * If SAP comes up first and STA comes up later then SAP
diff --git a/core/sme/src/csr/csr_api_scan.c b/core/sme/src/csr/csr_api_scan.c
index 9b1c6c7..bcec9aa 100644
--- a/core/sme/src/csr/csr_api_scan.c
+++ b/core/sme/src/csr/csr_api_scan.c
@@ -5508,6 +5508,12 @@
 			pFilter->ChannelInfo.ChannelList,
 			filter->num_of_channels);
 
+	if (pFilter->realm_check) {
+		filter->fils_scan_filter.realm_check = true;
+		qdf_mem_copy(filter->fils_scan_filter.fils_realm,
+			pFilter->fils_realm, REAM_HASH_LEN);
+	}
+
 	filter->num_of_auth =
 		pFilter->authType.numEntries;
 	if (filter->num_of_auth > WLAN_NUM_OF_SUPPORT_AUTH_TYPE)
@@ -5590,7 +5596,8 @@
 		return;
 
 	dot11f_unpack_ie_fils_indication(mac_ctx,
-				scan_entry->ie_list.fils_indication,
+				scan_entry->ie_list.fils_indication +
+				SIR_FILS_IND_ELEM_OFFSET,
 				*(scan_entry->ie_list.fils_indication + 1),
 				&fils_indication, false);
 
diff --git a/core/sme/src/csr/csr_util.c b/core/sme/src/csr/csr_util.c
index fefec67..7072570 100644
--- a/core/sme/src/csr/csr_util.c
+++ b/core/sme/src/csr/csr_util.c
@@ -3716,6 +3716,73 @@
 	return fRC;
 }
 
+#ifdef WLAN_FEATURE_FILS_SK
+/*
+ * csr_update_pmksa_for_cache_id: update tPmkidCacheInfo to lookup using
+ * ssid and cache id
+ * @bss_desc: bss description
+ * @profile: csr roam profile
+ * @pmkid_cache: pmksa cache
+ *
+ * Return: true if cache identifier present else false
+ */
+static bool csr_update_pmksa_for_cache_id(tSirBssDescription *bss_desc,
+				tCsrRoamProfile *profile,
+				tPmkidCacheInfo *pmkid_cache)
+{
+	if (!bss_desc->fils_info_element.is_cache_id_present)
+		return false;
+
+	pmkid_cache->ssid_len =
+		profile->SSIDs.SSIDList[0].SSID.length;
+	qdf_mem_copy(pmkid_cache->ssid,
+		profile->SSIDs.SSIDList[0].SSID.ssId,
+		profile->SSIDs.SSIDList[0].SSID.length);
+	qdf_mem_copy(pmkid_cache->cache_id,
+		bss_desc->fils_info_element.cache_id,
+		CACHE_ID_LEN);
+	qdf_mem_copy(pmkid_cache->BSSID.bytes,
+		bss_desc->bssId, QDF_MAC_ADDR_SIZE);
+
+	return true;
+
+}
+
+/*
+ * csr_update_pmksa_to_profile: update pmk and pmkid to profile which will be
+ * used in case of fils session
+ * @profile: profile
+ * @pmkid_cache: pmksa cache
+ *
+ * Return: None
+ */
+static inline void csr_update_pmksa_to_profile(tCsrRoamProfile *profile,
+		tPmkidCacheInfo *pmkid_cache)
+{
+	if (!profile->fils_con_info)
+		return;
+
+	profile->fils_con_info->pmk_len = pmkid_cache->pmk_len;
+	qdf_mem_copy(profile->fils_con_info->pmk,
+			pmkid_cache->pmk, pmkid_cache->pmk_len);
+	qdf_mem_copy(profile->fils_con_info->pmkid,
+		pmkid_cache->PMKID, CSR_RSN_PMKID_SIZE);
+
+}
+#else
+static inline bool csr_update_pmksa_for_cache_id(tSirBssDescription *bss_desc,
+				tCsrRoamProfile *profile,
+				tPmkidCacheInfo *pmkid_cache)
+{
+	return false;
+}
+
+static inline void csr_update_pmksa_to_profile(tCsrRoamProfile *profile,
+		tPmkidCacheInfo *pmkid_cache)
+{
+}
+#endif
+
 uint8_t csr_construct_rsn_ie(tHalHandle hHal, uint32_t sessionId,
 			     tCsrRoamProfile *pProfile,
 			     tSirBssDescription *pSirBssDesc,
@@ -3803,7 +3870,9 @@
 		pPMK = (tCsrRSNPMKIe *) (((uint8_t *) (&pAuthSuite->AuthOui[1]))
 				+ sizeof(uint16_t));
 
-		qdf_mem_copy(pmkid_cache.BSSID.bytes,
+		if (!csr_update_pmksa_for_cache_id(pSirBssDesc,
+			pProfile, &pmkid_cache))
+			qdf_mem_copy(pmkid_cache.BSSID.bytes,
 				pSirBssDesc->bssId, QDF_MAC_ADDR_SIZE);
 		/* Don't include the PMK SA IDs for CCKM associations. */
 		if (
@@ -3819,8 +3888,10 @@
 			qdf_mem_copy(pPMK->PMKIDList[0].PMKID,
 				     pmkid_cache.PMKID,
 				     CSR_RSN_PMKID_SIZE);
-		} else
+			csr_update_pmksa_to_profile(pProfile, &pmkid_cache);
+		} else {
 			pPMK->cPMKIDs = 0;
+		}
 
 #ifdef WLAN_FEATURE_11W
 		/* Advertise BIP in group cipher key management only if PMF is
@@ -5448,6 +5519,41 @@
 	return match;
 }
 
+#ifdef WLAN_FEATURE_FILS_SK
+/*
+ * csr_is_fils_realm_match: API to check whether realm in scan filter is
+ * matching with realm in bss info
+ * @bss_descr: bss description
+ * @filter: scan filter
+ *
+ * Return: true if success else false
+ */
+static bool csr_is_fils_realm_match(tSirBssDescription *bss_descr,
+			tCsrScanResultFilter *filter)
+{
+	int i;
+	bool is_match = true;
+
+	if (filter->realm_check) {
+		is_match = false;
+		for (i = 0; i < bss_descr->fils_info_element.realm_cnt; i++) {
+			if (!qdf_mem_cmp(filter->fils_realm,
+				bss_descr->fils_info_element.realm[i],
+				SIR_REALM_LEN)) {
+				return true;
+			}
+		}
+	}
+
+	return is_match;
+}
+#else
+static bool csr_is_fils_realm_match(tSirBssDescription *bss_descr,
+			tCsrScanResultFilter *filter)
+{
+	return true;
+}
+#endif
 /**
  * csr_match_bss() - to compare the bss
  * @hal: pointer to hal context
@@ -5611,6 +5717,8 @@
 		}
 	}
 	rc = true;
+	if (rc)
+		rc = csr_is_fils_realm_match(bss_descr, filter);
 
 end:
 	if (ie_dblptr)
@@ -5936,6 +6044,19 @@
 	return nBest;
 }
 
+#ifdef WLAN_FEATURE_FILS_SK
+static inline void csr_free_fils_profile_info(tCsrRoamProfile *profile)
+{
+	if (profile->fils_con_info) {
+		qdf_mem_free(profile->fils_con_info);
+		profile->fils_con_info = NULL;
+	}
+}
+#else
+static inline void csr_free_fils_profile_info(tCsrRoamProfile *profile)
+{ }
+#endif
+
 void csr_release_profile(tpAniSirGlobal pMac, tCsrRoamProfile *pProfile)
 {
 	if (pProfile) {
@@ -5975,6 +6096,7 @@
 			qdf_mem_free(pProfile->ChannelInfo.ChannelList);
 			pProfile->ChannelInfo.ChannelList = NULL;
 		}
+		csr_free_fils_profile_info(pProfile);
 		qdf_mem_set(pProfile, sizeof(tCsrRoamProfile), 0);
 	}
 }