qcacld-3.0: Add Support for FILS Association

Adds the following  support:
1) Add FILS IE's to assoc request.
2) AEAD encrypt/decrypt the assoc request/response frames for FILS
3) Process/Verify the Assoc response for the FILS params
4) Plumb the Auth keys to firmware after successful FILS assoc
5) Update the user space with Auth key details

Change-Id: I57f6319cecdf10e08047b510321b885c3cd711b5
CRs-Fixed: 2030038
diff --git a/core/hdd/src/wlan_hdd_assoc.c b/core/hdd/src/wlan_hdd_assoc.c
index 6817691..790808d 100644
--- a/core/hdd/src/wlan_hdd_assoc.c
+++ b/core/hdd/src/wlan_hdd_assoc.c
@@ -3139,7 +3139,7 @@
 				if (pRoamInfo)
 					hdd_connect_result(dev,
 						pRoamInfo->bssid.bytes,
-						NULL, NULL, 0, NULL, 0,
+						pRoamInfo, NULL, 0, NULL, 0,
 						WLAN_STATUS_ASSOC_DENIED_UNSPEC,
 						GFP_KERNEL,
 						connect_timeout,
@@ -3156,7 +3156,7 @@
 				if (pRoamInfo)
 					hdd_connect_result(dev,
 						pRoamInfo->bssid.bytes,
-						NULL, NULL, 0, NULL, 0,
+						pRoamInfo, NULL, 0, NULL, 0,
 						pRoamInfo->reasonCode ?
 						pRoamInfo->reasonCode :
 						WLAN_STATUS_UNSPECIFIED_FAILURE,
diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c
index 62a6c51..c0c5921 100644
--- a/core/hdd/src/wlan_hdd_main.c
+++ b/core/hdd/src/wlan_hdd_main.c
@@ -4749,6 +4749,175 @@
 }
 #endif
 
+#ifdef WLAN_FEATURE_FILS_SK
+#ifdef CFG80211_CONNECT_DONE
+#ifdef CFG80211_FILS_SK_OFFLOAD_SUPPORT
+/**
+ * hdd_populate_fils_params() - Populate FILS keys to connect response
+ * @fils_params: connect response to supplicant
+ * @fils_kek: FILS kek
+ * @fils_kek_len: FILS kek length
+ * @pmk: FILS PMK
+ * @pmk_len: FILS PMK length
+ * @pmkid: PMKID
+ * @fils_seq_num: FILS Seq number
+ *
+ * Return: None
+ */
+static void hdd_populate_fils_params(struct cfg80211_connect_resp_params
+				     *fils_params, const uint8_t *fils_kek,
+				     size_t fils_kek_len, const uint8_t *pmk,
+				     size_t pmk_len, const uint8_t *pmkid,
+				     uint16_t fils_seq_num)
+{
+	/* Increament seq number to be used for next FILS */
+	fils_params->fils_erp_next_seq_num = fils_seq_num + 1;
+	fils_params->update_erp_next_seq_num = true;
+	fils_params->fils_kek = fils_kek;
+	fils_params->fils_kek_len = fils_kek_len;
+	fils_params->pmk = pmk;
+	fils_params->pmk_len = pmk_len;
+	fils_params->pmkid = pmkid;
+}
+#else
+static inline void hdd_populate_fils_params(struct cfg80211_connect_resp_params
+					    *fils_params, const uint8_t
+					    *fils_kek, size_t fils_kek_len,
+					    const uint8_t *pmk, size_t pmk_len,
+					    const uint8_t *pmkid,
+					    uint16_t fils_seq_num)
+{ }
+#endif
+
+/**
+ * hdd_connect_done() - Wrapper API to call cfg80211_connect_done
+ * @dev: network device
+ * @bssid: bssid to which we want to associate
+ * @bss: cfg80211 bss info
+ * @roam_info: information about connected bss
+ * @req_ie: Request Information Element
+ * @req_ie_len: len of the req IE
+ * @resp_ie: Response IE
+ * @resp_ie_len: len of ht response IE
+ * @status: status
+ * @gfp: allocation flags
+ * @connect_timeout: If timed out waiting for Auth/Assoc/Probe resp
+ * @timeout_reason: reason for connect timeout
+ * @roam_fils_params: FILS join response params
+ *
+ * This API is used as wrapper to send FILS key/sequence number
+ * params etc. to supplicant in case of FILS connection
+ *
+ * Return: None
+ */
+static void hdd_connect_done(struct net_device *dev, const u8 *bssid,
+			     struct cfg80211_bss *bss, tCsrRoamInfo *roam_info,
+			     const u8 *req_ie, size_t req_ie_len,
+			     const u8 *resp_ie, size_t resp_ie_len, u16 status,
+			     gfp_t gfp, bool connect_timeout, tSirResultCodes
+			     timeout_reason, struct fils_join_rsp_params
+			     *roam_fils_params)
+{
+	struct cfg80211_connect_resp_params fils_params;
+	qdf_mem_zero(&fils_params, sizeof(fils_params));
+
+	if (!roam_fils_params) {
+		fils_params.status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+	} else {
+		fils_params.status = status;
+		fils_params.bssid = bssid;
+		fils_params.timeout_reason = timeout_reason;
+		fils_params.req_ie = req_ie;
+		fils_params.req_ie_len = req_ie_len;
+		fils_params.resp_ie = resp_ie;
+		fils_params.resp_ie_len = resp_ie_len;
+		fils_params.bss = bss;
+		hdd_populate_fils_params(&fils_params, roam_fils_params->kek,
+					 roam_fils_params->kek_len,
+					 roam_fils_params->fils_pmk,
+					 roam_fils_params->fils_pmk_len,
+					 roam_fils_params->fils_pmkid,
+					 roam_info->fils_seq_num);
+	}
+	hdd_debug("FILS indicate connect status %d seq no %d",
+		  fils_params.status,
+		  fils_params.fils_erp_next_seq_num);
+
+	cfg80211_connect_done(dev, &fils_params, gfp);
+
+	/* Clear all the FILS key info */
+	if (roam_fils_params && roam_fils_params->fils_pmk)
+		qdf_mem_free(roam_fils_params->fils_pmk);
+	if (roam_fils_params)
+		qdf_mem_free(roam_fils_params);
+	roam_info->fils_join_rsp = NULL;
+}
+#else
+static inline void hdd_connect_done(struct net_device *dev, const u8 *bssid,
+				    struct cfg80211_bss *bss, tCsrRoamInfo
+				    *roam_info, const u8 *req_ie,
+				    size_t req_ie_len, const u8 *resp_ie,
+				    size_t resp_ie_len, u16 status, gfp_t gfp,
+				    bool connect_timeout, tSirResultCodes
+				    timeout_reason, struct fils_join_rsp_params
+				    *roam_fils_params)
+{ }
+#endif
+#endif
+
+#if defined(CFG80211_CONNECT_DONE) && defined(WLAN_FEATURE_FILS_SK)
+/**
+ * hdd_fils_update_connect_results() - API to send fils connection status to
+ * supplicant.
+ * @dev: network device
+ * @bssid: bssid to which we want to associate
+ * @bss: cfg80211 bss info
+ * @roam_info: information about connected bss
+ * @req_ie: Request Information Element
+ * @req_ie_len: len of the req IE
+ * @resp_ie: Response IE
+ * @resp_ie_len: len of ht response IE
+ * @status: status
+ * @gfp: allocation flags
+ * @connect_timeout: If timed out waiting for Auth/Assoc/Probe resp
+ * @timeout_reason: reason for connect timeout
+ *
+ * The API is a wrapper to send connection status to supplicant
+ *
+ * Return: 0 if success else failure
+ */
+static int hdd_fils_update_connect_results(struct net_device *dev,
+			const u8 *bssid,
+			struct cfg80211_bss *bss,
+			tCsrRoamInfo *roam_info, const u8 *req_ie,
+			size_t req_ie_len, const u8 *resp_ie,
+			size_t resp_ie_len, u16 status, gfp_t gfp,
+			bool connect_timeout,
+			tSirResultCodes timeout_reason)
+{
+	ENTER();
+	if (!roam_info || !roam_info->is_fils_connection)
+		return -EINVAL;
+
+	hdd_connect_done(dev, bssid, bss, roam_info, req_ie, req_ie_len,
+			 resp_ie, resp_ie_len, status, gfp, connect_timeout,
+			 timeout_reason, roam_info->fils_join_rsp);
+	return 0;
+}
+#else
+static inline int hdd_fils_update_connect_results(struct net_device *dev,
+			const u8 *bssid,
+			struct cfg80211_bss *bss,
+			tCsrRoamInfo *roam_info, const u8 *req_ie,
+			size_t req_ie_len, const u8 *resp_ie,
+			size_t resp_ie_len, u16 status, gfp_t gfp,
+			bool connect_timeout,
+			tSirResultCodes timeout_reason)
+{
+	return -EINVAL;
+}
+#endif
+
 /**
  * hdd_connect_result() - API to send connection status to supplicant
  * @dev: network device
@@ -4796,9 +4965,14 @@
 			roam_info->u.pConnectedProfile->SSID.length);
 	}
 
-	hdd_connect_bss(dev, bssid, bss, req_ie,
-		req_ie_len, resp_ie, resp_ie_len,
-		status, gfp, connect_timeout, timeout_reason);
+	if (hdd_fils_update_connect_results(dev, bssid, bss,
+			roam_info, req_ie, req_ie_len, resp_ie,
+			resp_ie_len, status, gfp, connect_timeout,
+			timeout_reason) != 0) {
+		hdd_connect_bss(dev, bssid, bss, req_ie,
+			req_ie_len, resp_ie, resp_ie_len,
+			status, gfp, connect_timeout, timeout_reason);
+	}
 
 	qdf_runtime_pm_allow_suspend(&padapter->connect_rpm_ctx.connect);
 	hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_CONNECT);
diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h
index 548d95e..840cec0 100644
--- a/core/mac/inc/sir_api.h
+++ b/core/mac/inc/sir_api.h
@@ -329,6 +329,20 @@
 	eSIR_DONOT_USE_RESULT_CODE = SIR_MAX_ENUM_SIZE
 } tSirResultCodes;
 
+#ifdef WLAN_FEATURE_FILS_SK
+struct fils_join_rsp_params {
+	uint8_t *fils_pmk;
+	uint8_t fils_pmk_len;
+	uint8_t fils_pmkid[PMKID_LEN];
+	uint8_t kek[MAX_KEK_LEN];
+	uint8_t kek_len;
+	uint8_t tk[MAX_TK_LEN];
+	uint8_t tk_len;
+	uint8_t gtk_len;
+	uint8_t gtk[MAX_GTK_LEN];
+};
+#endif
+
 #define RMENABLEDCAP_MAX_LEN 5
 
 struct rrm_config_param {
@@ -1295,6 +1309,11 @@
 	tDot11fIEHTInfo ht_operation;
 	tDot11fIEVHTOperation vht_operation;
 	tDot11fIEhs20vendor_ie hs20vendor_ie;
+	bool is_fils_connection;
+#ifdef WLAN_FEATURE_FILS_SK
+	uint16_t fils_seq_num;
+	struct fils_join_rsp_params *fils_join_rsp;
+#endif
 	uint8_t frames[1];
 } tSirSmeJoinRsp, *tpSirSmeJoinRsp;
 
diff --git a/core/mac/src/include/parser_api.h b/core/mac/src/include/parser_api.h
index 25f9200..70e548a 100644
--- a/core/mac/src/include/parser_api.h
+++ b/core/mac/src/include/parser_api.h
@@ -414,6 +414,11 @@
 	tSirQCNIE QCN_IE;
 	tDot11fIEvendor_he_cap vendor_he_cap;
 	tDot11fIEvendor_he_op vendor_he_op;
+#ifdef WLAN_FEATURE_FILS_SK
+	tDot11fIEfils_session fils_session;
+	tDot11fIEfils_key_confirmation fils_key_auth;
+	tDot11fIEfils_kde fils_kde;
+#endif
 } tSirAssocRsp, *tpSirAssocRsp;
 
 #ifdef FEATURE_WLAN_ESE
@@ -579,6 +584,7 @@
 
 tSirRetStatus
 sir_convert_assoc_resp_frame2_struct(struct sAniSirGlobal *pMac,
+				tpPESession session_entry,
 				uint8_t *frame, uint32_t len,
 				tpSirAssocRsp assoc);
 
@@ -1065,6 +1071,27 @@
 
 void populate_dot11f_qcn_ie(tDot11fIEQCN_IE *pDot11f);
 
+#ifdef WLAN_FEATURE_FILS_SK
+/**
+ * populate_dot11f_fils_params() - Populate FILS IE to frame
+ * @mac_ctx: global mac context
+ * @frm: Assoc request frame
+ * @pe_session: PE session
+ *
+ * This API is used to populate FILS IE to Association request
+ *
+ * Return: None
+ */
+void populate_dot11f_fils_params(tpAniSirGlobal mac_ctx,
+				 tDot11fAssocRequest * frm,
+				 tpPESession pe_session);
+#else
+static inline void populate_dot11f_fils_params(tpAniSirGlobal mac_ctx,
+				 tDot11fAssocRequest *frm,
+				 tpPESession pe_session)
+{ }
+#endif
+
 tSirRetStatus
 populate_dot11f_operating_mode(tpAniSirGlobal pMac,
 			tDot11fIEOperatingMode *pDot11f,
diff --git a/core/mac/src/pe/include/lim_fils_defs.h b/core/mac/src/pe/include/lim_fils_defs.h
index c3619cb..7e0286d 100644
--- a/core/mac/src/pe/include/lim_fils_defs.h
+++ b/core/mac/src/pe/include/lim_fils_defs.h
@@ -34,6 +34,9 @@
 #define MAX_KEY_AUTH_DATA_LEN 48
 #define MAX_GTK_LEN 255
 #define MAX_IGTK_LEN 255
+#define SIR_FILS_SESSION_IE_LEN 11
+#define FILS_KEY_RSC_LEN 8
+#define FILS_MAX_KEY_AUTH_LEN (MAX_ICK_LEN + MAX_KEK_LEN + MAX_TK_LEN)
 
 #define IPN_LEN 6
 #define FILS_SESSION_LENGTH 8
@@ -90,6 +93,18 @@
 #define SIR_FILS_EAP_TLV_CRYPTO_LIST 5
 #define SIR_FILS_EAP_TLV_AUTH_INDICATION 6
 
+#define DATA_TYPE_GTK 1
+#define DATA_TYPE_IGTK 9
+#define KEY_RSC_LEN 8
+#define KDE_IE_DATA_OFFSET 4
+#define KDE_DATA_TYPE_OFFSET 3
+#define GTK_OFFSET 2
+#define IPN_OFFSET 2
+#define IGTK_OFFSET 8
+
+#define KDE_OUI_TYPE   "\x00\x0F\xAC"
+#define KDE_OUI_TYPE_SIZE  3
+
 /*
  * struct eap_auth_reserved: this structure defines flags format in eap packets
  * as defined in RFC 6696 5.3.1
diff --git a/core/mac/src/pe/include/lim_process_fils.h b/core/mac/src/pe/include/lim_process_fils.h
index 5070bb2..a214f92 100644
--- a/core/mac/src/pe/include/lim_process_fils.h
+++ b/core/mac/src/pe/include/lim_process_fils.h
@@ -99,6 +99,84 @@
 		session_entry->fils_info->sequence_number++;
 }
 
+/**
+ * populate_fils_connect_params() - Populate FILS connect params to join rsp
+ * @mac_ctx: Mac context
+ * @session: PE session
+ * @sme_join_rsp: SME join rsp
+ *
+ * This API copies the FILS connect params from PE session to SME join rsp
+ *
+ * Return: None
+ */
+void populate_fils_connect_params(tpAniSirGlobal mac_ctx,
+				  tpPESession session,
+				  tpSirSmeJoinRsp sme_join_rsp);
+
+/**
+ * aead_encrypt_assoc_req() - Encrypt FILS IE's in assoc request
+ * @mac_ctx: mac context
+ * @pe_session: PE session
+ * @frame: packed frame buffer
+ * @payload: length of @frame
+ *
+ * This API is used to encrypt the all the IE present after FILS session IE
+ * in Association request frame
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS aead_encrypt_assoc_req(tpAniSirGlobal mac_ctx,
+				  tpPESession pe_session,
+				  uint8_t *frame, uint32_t *payload);
+
+/**
+ * aead_decrypt_assoc_rsp() - API for AEAD decryption in FILS connection
+ * @mac_ctx: MAC context
+ * @session: PE session
+ * @ar: Assoc response frame structure
+ * @p_frame: frame buffer received
+ * @n_frame: length of @p_frame
+ *
+ * This API is used to decrypt the AEAD encrypted part of FILS assoc response
+ * and populate the decrypted FILS IE's to Assoc response frame structure(ar)
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS aead_decrypt_assoc_rsp(tpAniSirGlobal mac_ctx,
+				  tpPESession session,
+				  tDot11fAssocResponse *ar,
+				  uint8_t *p_frame, uint32_t *n_frame);
+/**
+ * lim_is_fils_connection() - Check if it is FILS connection
+ * @pe_session: PE session
+ *
+ * This API is used to check if current PE session is FILS connection
+ *
+ * Return: True if FILS connection, false if not
+ */
+static inline bool lim_is_fils_connection(tpPESession pe_session)
+{
+	if (pe_session->fils_info->is_fils_connection)
+		return true;
+	return false;
+}
+
+/**
+ * lim_verify_fils_params_assoc_rsp() - Verify FILS params in assoc rsp
+ * @mac_ctx: Mac context
+ * @session_entry: PE session
+ * @assoc_rsp: Assoc response received
+ * @assoc_cnf: Assoc cnf msg to be sent to MLME
+ *
+ * This API is used to match FILS params received in Assoc response
+ * with Assoc params received/derived at the Authentication stage
+ *
+ * Return: True, if successfully matches. False, otherwise
+ */
+bool lim_verify_fils_params_assoc_rsp(tpAniSirGlobal mac_ctx,
+				      tpPESession session_entry,
+				      tpSirAssocRsp assoc_rsp,
+				      tLimMlmAssocCnf * assoc_cnf);
 #else
 static inline bool lim_process_fils_auth_frame2(tpAniSirGlobal mac_ctx,
 		tpPESession pe_session, tSirMacAuthFrameBody *rx_auth_frm_body)
@@ -130,4 +208,39 @@
 {
 	return 0;
 }
+
+static inline bool lim_is_fils_connection(tpPESession pe_session)
+{
+	return false;
+}
+
+static inline void populate_fils_connect_params(tpAniSirGlobal mac_ctx,
+						tpPESession session,
+						tpSirSmeJoinRsp sme_join_rsp)
+{ }
+
+static inline QDF_STATUS aead_encrypt_assoc_req(tpAniSirGlobal mac_ctx,
+						tpPESession pe_session,
+						uint8_t *frame,
+						uint32_t *payload)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline QDF_STATUS aead_decrypt_assoc_rsp(tpAniSirGlobal mac_ctx,
+				  tpPESession session,
+				  tDot11fAssocResponse *ar,
+				  uint8_t *p_frame, uint32_t *n_frame)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline bool lim_verify_fils_params_assoc_rsp(tpAniSirGlobal mac_ctx,
+			tpPESession session_entry,
+			tpSirAssocRsp assoc_rsp,
+			tLimMlmAssocCnf *assoc_cnf)
+
+{
+	return true;
+}
 #endif
diff --git a/core/mac/src/pe/include/lim_session.h b/core/mac/src/pe/include/lim_session.h
index cb0de7b..54cbe04 100644
--- a/core/mac/src/pe/include/lim_session.h
+++ b/core/mac/src/pe/include/lim_session.h
@@ -646,4 +646,13 @@
 tpPESession pe_find_session_by_sme_session_id(tpAniSirGlobal mac_ctx,
 					      uint8_t sme_session_id);
 uint8_t pe_get_active_session_count(tpAniSirGlobal mac_ctx);
+#ifdef WLAN_FEATURE_FILS_SK
+/**
+ * pe_delete_fils_info: API to delete fils session info
+ * @session: pe session
+ *
+ * Return: void
+ */
+void pe_delete_fils_info(tpPESession session);
+#endif
 #endif /* #if !defined( __LIM_SESSION_H ) */
diff --git a/core/mac/src/pe/lim/lim_assoc_utils.c b/core/mac/src/pe/lim/lim_assoc_utils.c
index f33dd7b..4b58c22 100644
--- a/core/mac/src/pe/lim/lim_assoc_utils.c
+++ b/core/mac/src/pe/lim/lim_assoc_utils.c
@@ -767,16 +767,15 @@
 				mlmStaContext.protStatusCode,
 				psessionEntry->peSessionId);
 
-			if (mlmStaContext.resultCode != eSIR_SME_SUCCESS) {
-				pe_delete_session(pMac, psessionEntry);
-				psessionEntry = NULL;
-			}
-
 			lim_send_sme_join_reassoc_rsp(pMac, eWNI_SME_REASSOC_RSP,
 						      mlmStaContext.resultCode,
 						      mlmStaContext.protStatusCode,
 						      psessionEntry, smesessionId,
 						      smetransactionId);
+			if (mlmStaContext.resultCode != eSIR_SME_SUCCESS) {
+				pe_delete_session(pMac, psessionEntry);
+				psessionEntry = NULL;
+			}
 		} else {
 			qdf_mem_free(psessionEntry->pLimJoinReq);
 			psessionEntry->pLimJoinReq = NULL;
@@ -788,16 +787,16 @@
 				mlmStaContext.protStatusCode,
 				psessionEntry->peSessionId);
 
-			if (mlmStaContext.resultCode != eSIR_SME_SUCCESS) {
-				pe_delete_session(pMac, psessionEntry);
-				psessionEntry = NULL;
-			}
-
 			lim_send_sme_join_reassoc_rsp(pMac, eWNI_SME_JOIN_RSP,
 						      mlmStaContext.resultCode,
 						      mlmStaContext.protStatusCode,
 						      psessionEntry, smesessionId,
 						      smetransactionId);
+
+			if (mlmStaContext.resultCode != eSIR_SME_SUCCESS) {
+				pe_delete_session(pMac, psessionEntry);
+				psessionEntry = NULL;
+			}
 		}
 
 	} else if (mlmStaContext.cleanupTrigger == eLIM_DUPLICATE_ENTRY) {
diff --git a/core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c b/core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c
index f9d6fe6..2bdcea0 100644
--- a/core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c
+++ b/core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c
@@ -51,7 +51,7 @@
 #include "lim_ser_des_utils.h"
 #include "lim_sta_hash_api.h"
 #include "lim_send_messages.h"
-
+#include "lim_process_fils.h"
 
 extern tSirRetStatus sch_beacon_edca_process(tpAniSirGlobal pMac,
 	tSirMacEdcaParamSetIE *edca, tpPESession psessionEntry);
@@ -626,7 +626,7 @@
 	else
 		body = WMA_GET_RX_MPDU_DATA(rx_pkt_info);
 	/* parse Re/Association Response frame. */
-	if (sir_convert_assoc_resp_frame2_struct(mac_ctx, body,
+	if (sir_convert_assoc_resp_frame2_struct(mac_ctx, session_entry, body,
 		frame_len, assoc_rsp) == eSIR_FAILURE) {
 		qdf_mem_free(assoc_rsp);
 		pe_err("Parse error Assoc resp subtype: %d" "length: %d",
@@ -759,6 +759,23 @@
 			hdr->sa, session_entry, false);
 		goto assocReject;
 	}
+
+	/*
+	 * If it is FILS connection, check is FILS params are matching
+	 * with Authentication stage.
+	 */
+	if (!lim_verify_fils_params_assoc_rsp(mac_ctx, session_entry,
+						assoc_rsp, &assoc_cnf)) {
+		pe_err("FILS params doesnot match");
+		assoc_cnf.resultCode = eSIR_SME_INVALID_ASSOC_RSP_RXED;
+		assoc_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS;
+		/* Send advisory Disassociation frame to AP */
+		lim_send_disassoc_mgmt_frame(mac_ctx,
+			eSIR_MAC_UNSPEC_FAILURE_REASON,
+			hdr->sa, session_entry, false);
+		goto assocReject;
+	}
+
 	/*
 	 * Association Response received with success code
 	 * Set the link state to POSTASSOC now that we have received
diff --git a/core/mac/src/pe/lim/lim_process_fils.c b/core/mac/src/pe/lim/lim_process_fils.c
index 79e8df3..01b49fb 100644
--- a/core/mac/src/pe/lim/lim_process_fils.c
+++ b/core/mac/src/pe/lim/lim_process_fils.c
@@ -1235,4 +1235,555 @@
 	}
 	return frame_len;
 }
+
+void populate_fils_connect_params(tpAniSirGlobal mac_ctx,
+				  tpPESession session,
+				  tpSirSmeJoinRsp sme_join_rsp)
+{
+	struct fils_join_rsp_params *fils_join_rsp;
+	struct pe_fils_session *fils_info = session->fils_info;
+
+	if (!lim_is_fils_connection(session))
+		return;
+
+	if (!fils_info->fils_pmk_len ||
+			!fils_info->tk_len || !fils_info->gtk_len ||
+			!fils_info->fils_pmk || !fils_info->kek_len) {
+		pe_err("Invalid FILS info pmk len %d kek len %d tk len %d gtk len %d",
+			fils_info->fils_pmk_len,
+			fils_info->kek_len,
+			fils_info->tk_len,
+			fils_info->gtk_len);
+		return;
+	}
+
+	sme_join_rsp->fils_join_rsp = qdf_mem_malloc(sizeof(*fils_join_rsp));
+	if (!sme_join_rsp->fils_join_rsp) {
+		pe_err("fils_join_rsp malloc fails!");
+		pe_delete_fils_info(session);
+		return;
+	}
+
+	fils_join_rsp = sme_join_rsp->fils_join_rsp;
+	fils_join_rsp->fils_pmk = qdf_mem_malloc(fils_info->fils_pmk_len);
+	if (!fils_join_rsp->fils_pmk) {
+		pe_err("fils_pmk malloc fails!");
+		qdf_mem_free(fils_join_rsp);
+		pe_delete_fils_info(session);
+		return;
+	}
+
+	fils_join_rsp->fils_pmk_len = fils_info->fils_pmk_len;
+	qdf_mem_copy(fils_join_rsp->fils_pmk, fils_info->fils_pmk,
+			fils_info->fils_pmk_len);
+
+	qdf_mem_copy(fils_join_rsp->fils_pmkid, fils_info->fils_pmkid,
+			IEEE80211_PMKID_LEN);
+
+	fils_join_rsp->kek_len = fils_info->kek_len;
+	qdf_mem_copy(fils_join_rsp->kek, fils_info->kek, fils_info->kek_len);
+
+	fils_join_rsp->tk_len = fils_info->tk_len;
+	qdf_mem_copy(fils_join_rsp->tk, fils_info->tk, fils_info->tk_len);
+
+	fils_join_rsp->gtk_len = fils_info->gtk_len;
+	qdf_mem_copy(fils_join_rsp->gtk, fils_info->gtk, fils_info->gtk_len);
+
+	pe_debug("FILS connect params copied lim");
+	pe_delete_fils_info(session);
+}
+
+/**
+ * lim_parse_kde_elements() - Parse Key Delivery Elements
+ * @mac_ctx: mac context
+ * @fils_info: FILS info
+ * @kde_list: KDE list buffer
+ * @kde_list_len: Length of @kde_list
+ *
+ * This API is used to parse the Key Delivery Elements from buffer
+ * and populate them in PE FILS session struct i.e @fils_info
+ *
+ *             Key Delivery Element[KDE] format
+ * +----------+--------+-----------+------------+----------+
+ * | ID(0xDD) | length |  KDE OUI  |  data type |  IE data |
+ * |----------|--------|-----------|------------|----------|
+ * |  1 byte  | 1 byte |  3 bytes  |   1 byte   | variable |
+ * +----------+--------+-----------+------------+----------+
+ *
+ * there can be multiple KDE present inside KDE list.
+ * the IE data could be GTK, IGTK etc based on the data type
+ *
+ * Return: QDF_STATUS_SUCCESS if we parse GTK successfully,
+ *         QDF_STATUS_E_FAILURE otherwise
+ */
+static QDF_STATUS lim_parse_kde_elements(tpAniSirGlobal mac_ctx,
+					 struct pe_fils_session *fils_info,
+					 uint8_t *kde_list,
+					 uint8_t kde_list_len)
+{
+	uint8_t rem_len = kde_list_len;
+	uint8_t *temp_ie = kde_list;
+	uint8_t elem_id, data_type, data_len, *ie_data = NULL, *current_ie;
+	uint16_t elem_len;
+
+	if (!kde_list_len || !kde_list) {
+		pe_err("kde_list NULL or kde_list_len %d", kde_list_len);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	while (rem_len >= 2) {
+		current_ie = temp_ie;
+		elem_id = *temp_ie++;
+		elem_len = *temp_ie++;
+		rem_len -= 2;
+
+		if (lim_check_if_vendor_oui_match(mac_ctx, KDE_OUI_TYPE,
+				KDE_OUI_TYPE_SIZE, current_ie, elem_len)) {
+
+			data_type = *(temp_ie + KDE_DATA_TYPE_OFFSET);
+			ie_data = (temp_ie + KDE_IE_DATA_OFFSET);
+			data_len = (elem_len - KDE_IE_DATA_OFFSET);
+
+			switch (data_type) {
+			case DATA_TYPE_GTK:
+				qdf_mem_copy(fils_info->gtk, (ie_data +
+					     GTK_OFFSET), (data_len -
+					     GTK_OFFSET));
+				fils_info->gtk_len = (data_len - GTK_OFFSET);
+				lim_fils_data_dump("GTK: ", fils_info->gtk,
+						   fils_info->gtk_len);
+				break;
+
+			case DATA_TYPE_IGTK:
+				fils_info->igtk_len = (data_len - IGTK_OFFSET);
+				qdf_mem_copy(fils_info->igtk, (ie_data +
+					     IGTK_OFFSET), (data_len -
+					     IGTK_OFFSET));
+				qdf_mem_copy(fils_info->ipn, (ie_data +
+					     IPN_OFFSET), IPN_LEN);
+				lim_fils_data_dump("IGTK: ", fils_info->igtk,
+						   fils_info->igtk_len);
+			break;
+			default:
+				pe_err("Unknown KDE data type %x", data_type);
+			break;
+			}
+		}
+
+		temp_ie += elem_len;
+		rem_len -= elem_len;
+		ie_data = NULL;
+	}
+
+	/* Expecting GTK in KDE */
+	if (!fils_info->gtk_len) {
+		pe_err("GTK not found in KDE");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
+bool lim_verify_fils_params_assoc_rsp(tpAniSirGlobal mac_ctx,
+				      tpPESession session_entry,
+				      tpSirAssocRsp assoc_rsp,
+				      tLimMlmAssocCnf *assoc_cnf)
+{
+	struct pe_fils_session *fils_info = session_entry->fils_info;
+	tDot11fIEfils_session fils_session = assoc_rsp->fils_session;
+	tDot11fIEfils_key_confirmation fils_key_auth = assoc_rsp->fils_key_auth;
+	tDot11fIEfils_kde fils_kde = assoc_rsp->fils_kde;
+	QDF_STATUS status;
+
+	if (!lim_is_fils_connection(session_entry))
+		return true;
+
+	if (!assoc_rsp->fils_session.present) {
+		pe_err("FILS IE not present");
+		goto verify_fils_params_fails;
+	}
+
+	/* Compare FILS session */
+	if (qdf_mem_cmp(fils_info->fils_session,
+			fils_session.session, DOT11F_IE_FILS_SESSION_MAX_LEN)) {
+		pe_err("FILS session mismatch");
+		goto verify_fils_params_fails;
+	}
+
+	/* Compare FILS key auth */
+	if ((fils_key_auth.num_key_auth != fils_info->key_auth_len) ||
+		qdf_mem_cmp(fils_info->ap_key_auth_data, fils_key_auth.key_auth,
+					 fils_info->ap_key_auth_len)) {
+		lim_fils_data_dump("session keyauth",
+				   fils_info->ap_key_auth_data,
+				   fils_info->ap_key_auth_len);
+		lim_fils_data_dump("Pkt keyauth",
+				   fils_key_auth.key_auth,
+				   fils_key_auth.num_key_auth);
+		goto verify_fils_params_fails;
+	}
+
+	/* Verify the Key Delivery Element presence */
+	if (!fils_kde.num_kde_list) {
+		pe_err("FILS KDE list absent");
+		goto verify_fils_params_fails;
+	}
+
+	/* Derive KDE elements */
+	status = lim_parse_kde_elements(mac_ctx, fils_info, fils_kde.kde_list,
+					fils_kde.num_kde_list);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		pe_err("KDE parsing fails");
+		goto verify_fils_params_fails;
+	}
+	return true;
+
+verify_fils_params_fails:
+	assoc_cnf->resultCode = eSIR_SME_ASSOC_REFUSED;
+	assoc_cnf->protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS;
+	return false;
+}
+
+/**
+ * find_ie_data_after_fils_session_ie() - Find IE pointer after FILS Session IE
+ * @mac_ctx: MAC context
+ * @buf: IE buffer
+ * @buf_len: Length of @buf
+ * @ie: Pointer to update the found IE pointer after FILS session IE
+ * @ie_len: length of the IE data after FILS session IE
+ *
+ * This API is used to find the IE data ptr and length after FILS session IE
+ *
+ * Return: QDF_STATUS_SUCCESS if found, else QDF_STATUS_E_FAILURE
+ */
+static QDF_STATUS find_ie_data_after_fils_session_ie(tpAniSirGlobal mac_ctx,
+						     uint8_t *buf,
+						     uint32_t buf_len,
+						     uint8_t **ie,
+						     uint32_t *ie_len)
+{
+	uint32_t left = buf_len;
+	uint8_t *ptr = buf;
+	uint8_t elem_id, elem_len;
+
+	if (NULL == buf || 0 == buf_len)
+		return QDF_STATUS_E_FAILURE;
+
+	while (left >= 2) {
+		elem_id = ptr[0];
+		elem_len = ptr[1];
+		left -= 2;
+		if (elem_len > left)
+			return QDF_STATUS_E_FAILURE;
+
+		if (elem_id == SIR_MAC_REQUEST_EID_MAX &&
+			ptr[2] == SIR_FILS_SESSION_EXT_EID) {
+			(*ie) = ((&ptr[1]) + ptr[1] + 1);
+			(*ie_len) = (left - elem_len);
+			return QDF_STATUS_SUCCESS;
+		}
+		left -= elem_len;
+		ptr += (elem_len + 2);
+	}
+	return QDF_STATUS_E_FAILURE;
+}
+
+/**
+ * fils_aead_encrypt() - API to do FILS AEAD encryption
+ *
+ * @kek: Pointer to KEK
+ * @kek_len: KEK length
+ * @own_mac: Pointer to own MAC address
+ * @bssid: Bssid
+ * @snonce: Supplicant Nonce
+ * @anonce: Authenticator Nonce
+ * @data: Pointer to data after MAC header
+ * @data_len: length of @data
+ * @plain_text: Pointer to data after FILS Session IE
+ * @plain_text_len: length of @plain_text
+ * @out: Pointer to the encrypted data
+ *
+ * length of AEAD encryption @out is @plain_text_len + AES_BLOCK_SIZE[16 bytes]
+ *
+ * Return: zero on success, error otherwise
+ */
+static int fils_aead_encrypt(const u8 *kek, unsigned int kek_len,
+			     const u8 *own_mac, const u8 *bssid,
+			     const u8 *snonce, const u8 *anonce,
+			     const u8 *data, size_t data_len, u8 *plain_text,
+			     size_t plain_text_len, u8 *out)
+{
+	u8 v[AES_BLOCK_SIZE];
+	const u8 *aad[6];
+	size_t aad_len[6];
+	u8 *buf;
+	int ret;
+
+	/* SIV Encrypt/Decrypt takes input key of length 256, 384 or 512 bits */
+	if (kek_len != 32 && kek_len != 48 && kek_len != 64) {
+		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
+			  FL("Invalid key length: %u"), kek_len);
+		return -EINVAL;
+	}
+
+	if (own_mac == NULL || bssid == NULL || snonce == NULL ||
+	    anonce == NULL || data_len == 0 || plain_text_len == 0 ||
+	    out == NULL) {
+		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
+			  FL("Error missing params mac:%p bssid:%p snonce:%p anonce:%p data_len:%lu plain_text_len:%lu out:%p"),
+			  own_mac, bssid, snonce, anonce, data_len,
+			  plain_text_len, out);
+		return -EINVAL;
+	}
+
+	if (plain_text == out) {
+		buf = qdf_mem_malloc(plain_text_len);
+		if (buf == NULL) {
+			QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
+				  FL("Failed to allocate memory"));
+			return -ENOMEM;
+		}
+		qdf_mem_copy(buf, plain_text, plain_text_len);
+	} else {
+		buf = plain_text;
+	}
+
+	aad[0] = own_mac;
+	aad_len[0] = QDF_MAC_ADDR_SIZE;
+	aad[1] = bssid;
+	aad_len[1] = QDF_MAC_ADDR_SIZE;
+	aad[2] = snonce;
+	aad_len[2] = SIR_FILS_NONCE_LENGTH;
+	aad[3] = anonce;
+	aad_len[3] = SIR_FILS_NONCE_LENGTH;
+	aad[4] = data;
+	aad_len[4] = data_len;
+	/* Plain text, P, is Sn in AES-SIV */
+	aad[5] = buf;
+	aad_len[5] = plain_text_len;
+
+	/* AES-SIV S2V */
+	/* K1 = leftmost(K, len(K)/2) */
+	ret = qdf_aes_s2v(kek, kek_len/2, aad, aad_len, 6, v);
+	if (ret)
+		goto error;
+
+	/* out = SIV || C (Synthetic Initialization Vector || Ciphered text) */
+	qdf_mem_copy(out, v, AES_BLOCK_SIZE);
+
+	/* AES-SIV CTR */
+	/* K2 = rightmost(K, len(K)/2) */
+	/* Clear 31st and 63rd bits in counter synthetic iv */
+	v[12] &= 0x7F;
+	v[8] &= 0x7F;
+
+	ret = qdf_aes_ctr(kek + kek_len/2, kek_len/2, v, buf, plain_text_len,
+		      out + AES_BLOCK_SIZE, true);
+
+error:
+	if (plain_text == out)
+		qdf_mem_free(buf);
+	return ret;
+}
+
+QDF_STATUS aead_encrypt_assoc_req(tpAniSirGlobal mac_ctx,
+				  tpPESession pe_session,
+				  uint8_t *frm, uint32_t *frm_len)
+{
+	uint8_t *plain_text = NULL, *data;
+	uint32_t plain_text_len = 0, data_len;
+	QDF_STATUS status;
+	struct pe_fils_session *fils_info = pe_session->fils_info;
+
+	/*
+	 * data is the packet data after MAC header till
+	 * FILS session IE(inclusive)
+	 */
+	data = frm + sizeof(tSirMacMgmtHdr);
+
+	/*
+	 * plain_text is the packet data after FILS session IE
+	 * which needs to be encrypted. Get plain_text ptr and
+	 * plain_text_len values using find_ptr_aft_fils_session_ie()
+	 */
+	status = find_ie_data_after_fils_session_ie(mac_ctx, data +
+					      FIXED_PARAM_OFFSET_ASSOC_REQ,
+					      (*frm_len -
+					      FIXED_PARAM_OFFSET_ASSOC_REQ),
+					      &plain_text, &plain_text_len);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		pe_err("Could not find FILS session IE");
+		return QDF_STATUS_E_FAILURE;
+	}
+	data_len = ((*frm_len) - plain_text_len);
+
+	lim_fils_data_dump("Plain text: ", plain_text, plain_text_len);
+
+	/* Overwrite the AEAD encrypted output @ plain_text */
+	if (fils_aead_encrypt(fils_info->kek, fils_info->kek_len,
+			      pe_session->selfMacAddr, pe_session->bssId,
+			      fils_info->fils_nonce,
+			      fils_info->auth_info.fils_nonce,
+			      data, data_len, plain_text, plain_text_len,
+			      plain_text)) {
+		pe_err("AEAD Encryption fails!");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	/*
+	 * AEAD encrypted output(cipher_text) will have length equals to
+	 * plain_text_len + AES_BLOCK_SIZE(AEAD encryption header info).
+	 * Add this to frm_len
+	 */
+	(*frm_len) += (AES_BLOCK_SIZE);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * fils_aead_decrypt() - API to do AEAD decryption
+ *
+ * @kek: Pointer to KEK
+ * @kek_len: KEK length
+ * @own_mac: Pointer to own MAC address
+ * @bssid: Bssid
+ * @snonce: Supplicant Nonce
+ * @anonce: Authenticator Nonce
+ * @data: Pointer to data after MAC header
+ * @data_len: length of @data
+ * @plain_text: Pointer to data after FILS Session IE
+ * @plain_text_len: length of @plain_text
+ * @out: Pointer to the encrypted data
+ *
+ * Return: zero on success, error otherwise
+ */
+static int fils_aead_decrypt(const u8 *kek, unsigned int kek_len,
+			     const u8 *own_mac, const u8 *bssid,
+			     const u8 *snonce, const u8 *anonce,
+			     const u8 *data, size_t data_len, u8 *ciphered_text,
+			     size_t ciphered_text_len, u8 *plain_text)
+{
+	const u8 *aad[6];
+	size_t aad_len[6];
+	u8 *buf;
+	size_t buf_len;
+	u8 v[AES_BLOCK_SIZE];
+	u8 siv[AES_BLOCK_SIZE];
+	int ret;
+
+	/* SIV Encrypt/Decrypt takes input key of length 256, 384 or 512 bits */
+	if (kek_len != 32 && kek_len != 48 && kek_len != 64) {
+		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
+			  FL("Invalid key length: %u"), kek_len);
+		return -EINVAL;
+	}
+
+	if (own_mac == NULL || bssid == NULL || snonce == NULL ||
+	    anonce == NULL || data_len == 0 || ciphered_text_len == 0 ||
+	    plain_text == NULL) {
+		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
+			  FL("Error missing params mac:%p bssid:%p snonce:%p anonce:%p data_len:%lu ciphered_text_len:%lu plain_text:%p"),
+			  own_mac, bssid, snonce, anonce, data_len,
+			  ciphered_text_len, plain_text);
+		return -EINVAL;
+	}
+
+	qdf_mem_copy(v, ciphered_text, AES_BLOCK_SIZE);
+	qdf_mem_copy(siv, ciphered_text, AES_BLOCK_SIZE);
+	v[12] &= 0x7F;
+	v[8] &= 0x7F;
+
+	buf_len = ciphered_text_len - AES_BLOCK_SIZE;
+	if (ciphered_text == plain_text) {
+		/* in place decryption */
+		buf = qdf_mem_malloc(buf_len);
+		if (buf == NULL) {
+			QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
+				  FL("Failed to allocate memory"));
+			return -ENOMEM;
+		}
+		qdf_mem_copy(buf, ciphered_text + AES_BLOCK_SIZE, buf_len);
+	} else {
+		buf = ciphered_text + AES_BLOCK_SIZE;
+	}
+
+	/* AES-SIV CTR */
+	/* K2 = rightmost(K, len(K)/2) */
+	ret = qdf_aes_ctr(kek + kek_len/2, kek_len/2, v, buf, buf_len,
+			  plain_text, false);
+	if (ret)
+		goto error;
+
+	aad[0] = bssid;
+	aad_len[0] = QDF_MAC_ADDR_SIZE;
+	aad[1] = own_mac;
+	aad_len[1] = QDF_MAC_ADDR_SIZE;
+	aad[2] = anonce;
+	aad_len[2] = SIR_FILS_NONCE_LENGTH;
+	aad[3] = snonce;
+	aad_len[3] = SIR_FILS_NONCE_LENGTH;
+	aad[4] = data;
+	aad_len[4] = data_len;
+	aad[5] = plain_text;
+	aad_len[5] = buf_len;
+
+	/* AES-SIV S2V */
+	/* K1 = leftmost(K, len(K)/2) */
+	ret = qdf_aes_s2v(kek, kek_len/2, aad, aad_len, 6, v);
+	if (ret)
+		goto error;
+
+	/* compare the iv generated against the one sent by AP */
+	if (memcmp(v, siv, AES_BLOCK_SIZE) != 0) {
+		QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
+			  FL("siv not same as frame siv"));
+		ret = -EINVAL;
+	}
+
+error:
+	if (ciphered_text == plain_text)
+		qdf_mem_free(buf);
+	return ret;
+}
+
+QDF_STATUS aead_decrypt_assoc_rsp(tpAniSirGlobal mac_ctx,
+				  tpPESession session,
+				  tDot11fAssocResponse *ar,
+				  uint8_t *p_frame, uint32_t *n_frame)
+{
+	QDF_STATUS status;
+	uint32_t data_len, fils_ies_len;
+	uint8_t *fils_ies;
+	struct pe_fils_session *fils_info = session->fils_info;
+
+	lim_fils_data_dump("Assoc Rsp :", p_frame, *n_frame);
+	status = find_ie_data_after_fils_session_ie(mac_ctx, p_frame +
+					      FIXED_PARAM_OFFSET_ASSOC_RSP,
+					      ((*n_frame) -
+					      FIXED_PARAM_OFFSET_ASSOC_RSP),
+					      &fils_ies, &fils_ies_len);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		pe_err("FILS session IE not present");
+		return status;
+	}
+
+	data_len = (*n_frame) - fils_ies_len;
+
+	if (fils_aead_decrypt(fils_info->kek, fils_info->kek_len,
+			      session->selfMacAddr, session->bssId,
+			      fils_info->fils_nonce,
+			      fils_info->auth_info.fils_nonce,
+			      p_frame, data_len,
+			      fils_ies, fils_ies_len, fils_ies)){
+		pe_err("AEAD decryption fails");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	/* Dump the output of AEAD decrypt */
+	lim_fils_data_dump("Plain text: ", fils_ies,
+			   fils_ies_len - AES_BLOCK_SIZE);
+
+	(*n_frame) -= AES_BLOCK_SIZE;
+	return status;
+}
 #endif
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 274c3d9..361d787 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
@@ -1289,7 +1289,7 @@
 	lim_send_sme_join_reassoc_rsp(mac, eWNI_SME_JOIN_RSP,
 				      link_state_params->result_code,
 				      link_state_params->prot_status_code,
-				      NULL, sme_session_id, sme_trans_id);
+				      session, sme_session_id, sme_trans_id);
 	pe_delete_session(mac, session);
 	qdf_mem_free(link_state_params);
 }
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 f9cbf7a..889a561 100644
--- a/core/mac/src/pe/lim/lim_send_management_frames.c
+++ b/core/mac/src/pe/lim/lim_send_management_frames.c
@@ -59,6 +59,7 @@
 #include "cds_utils.h"
 #include "sme_trace.h"
 #include "rrm_api.h"
+#include "qdf_crypto.h"
 
 #include "wma_types.h"
 #include <cdp_txrx_cmn.h>
@@ -1637,6 +1638,7 @@
 	tDot11fIEExtCap bcn_ext_cap;
 	uint8_t *bcn_ie = NULL;
 	uint32_t bcn_ie_len = 0;
+	uint32_t aes_block_size_len = 0;
 
 	if (NULL == pe_session) {
 		pe_err("pe_session is NULL");
@@ -1921,6 +1923,20 @@
 			add_ie, &add_ie_len, &frm->SuppOperatingClasses))
 		pe_debug("Unable to Stripoff supp op classes IE from Assoc Req");
 
+	if (lim_is_fils_connection(pe_session)) {
+		populate_dot11f_fils_params(mac_ctx, frm, pe_session);
+		aes_block_size_len = AES_BLOCK_SIZE;
+	}
+
+	/*
+	 * Do unpack to populate the add_ie buffer to frm structure
+	 * before packing the frm structure. In this way, the IE ordering
+	 * which the latest 802.11 spec mandates is maintained.
+	 */
+	if (add_ie_len)
+		dot11f_unpack_assoc_request(mac_ctx, add_ie,
+					    add_ie_len, frm, true);
+
 	status = dot11f_get_packed_assoc_request_size(mac_ctx, frm, &payload);
 	if (DOT11F_FAILED(status)) {
 		pe_err("Association Request packet size failure(0x%08x)",
@@ -1932,7 +1948,8 @@
 			status);
 	}
 
-	bytes = payload + sizeof(tSirMacMgmtHdr) + add_ie_len;
+	bytes = payload + sizeof(tSirMacMgmtHdr) +
+			aes_block_size_len;
 
 	qdf_status = cds_packet_alloc((uint16_t) bytes, (void **)&frame,
 				(void **)&packet);
@@ -1974,17 +1991,20 @@
 		pe_warn("Assoc request pack warning (0x%08x)", status);
 	}
 
-	pe_debug("Sending Association Request length %d to ", bytes);
 	if (pe_session->assocReq != NULL) {
 		qdf_mem_free(pe_session->assocReq);
 		pe_session->assocReq = NULL;
 		pe_session->assocReqLen = 0;
 	}
 
-	if (add_ie_len) {
-		qdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) + payload,
-			     add_ie, add_ie_len);
-		payload += add_ie_len;
+	if (lim_is_fils_connection(pe_session)) {
+		qdf_status = aead_encrypt_assoc_req(mac_ctx, pe_session,
+						    frame, &payload);
+		if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
+			cds_packet_free((void *)packet);
+			qdf_mem_free(frm);
+			return;
+		}
 	}
 
 	pe_session->assocReq = qdf_mem_malloc(payload);
@@ -2017,6 +2037,8 @@
 	mac_hdr = (tpSirMacMgmtHdr) frame;
 	MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT,
 			 pe_session->peSessionId, mac_hdr->fc.subType));
+
+	pe_debug("Sending Association Request length %d to ", bytes);
 	qdf_status =
 		wma_tx_frame(mac_ctx, packet,
 			   (uint16_t) (sizeof(tSirMacMgmtHdr) + payload),
diff --git a/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c b/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c
index 330974a..67728c6 100644
--- a/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c
+++ b/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c
@@ -64,6 +64,7 @@
 #ifdef CONVERGED_TDLS_ENABLE
 #include "wlan_tdls_tgt_api.h"
 #endif
+#include "lim_process_fils.h"
 
 static void lim_handle_join_rsp_status(tpAniSirGlobal mac_ctx,
 	tpPESession session_entry, tSirResultCodes result_code,
@@ -453,6 +454,18 @@
 		sme_join_rsp->vht_operation = parsed_ies->vht_operation;
 }
 
+#ifdef WLAN_FEATURE_FILS_SK
+static void lim_update_fils_seq_num(tpSirSmeJoinRsp sme_join_rsp,
+				    tpPESession session_entry)
+{
+	sme_join_rsp->fils_seq_num =
+		session_entry->fils_info->sequence_number;
+}
+#else
+static inline void lim_update_fils_seq_num(tpSirSmeJoinRsp sme_join_rsp,
+					   tpPESession session_entry)
+{}
+#endif
 /**
  * lim_send_sme_join_reassoc_rsp() - Send Response to Upper Layers
  * @mac_ctx:            Pointer to Global MAC structure
@@ -516,6 +529,13 @@
 			pe_err("MemAlloc fail - JOIN/REASSOC_RSP");
 			return;
 		}
+
+		if (lim_is_fils_connection(session_entry)) {
+			sme_join_rsp->is_fils_connection = true;
+			lim_update_fils_seq_num(sme_join_rsp,
+						session_entry);
+		}
+
 		if (result_code == eSIR_SME_SUCCESS) {
 			sta_ds = dph_get_hash_entry(mac_ctx,
 				DPH_STA_HASH_INDEX_PEER,
@@ -541,8 +561,13 @@
 				sme_join_rsp->max_rate_flags =
 					lim_get_max_rate_flags(mac_ctx, sta_ds);
 				lim_add_bss_info(sta_ds, sme_join_rsp);
+
+				/* Copy FILS params only for Successful join */
+				populate_fils_connect_params(mac_ctx,
+						session_entry, sme_join_rsp);
 			}
 		}
+
 		sme_join_rsp->beaconLength = 0;
 		sme_join_rsp->assocReqLength = 0;
 		sme_join_rsp->assocRspLength = 0;
diff --git a/core/mac/src/pe/lim/lim_session.c b/core/mac/src/pe/lim/lim_session.c
index 747981c..09d88ed 100644
--- a/core/mac/src/pe/lim/lim_session.c
+++ b/core/mac/src/pe/lim/lim_session.c
@@ -274,7 +274,7 @@
  *
  * Return: void
  */
-static void pe_delete_fils_info(tpPESession session)
+void pe_delete_fils_info(tpPESession session)
 {
 	struct pe_fils_session *fils_info;
 
diff --git a/core/mac/src/pe/lim/lim_utils.c b/core/mac/src/pe/lim/lim_utils.c
index ba38611..79087d7 100644
--- a/core/mac/src/pe/lim/lim_utils.c
+++ b/core/mac/src/pe/lim/lim_utils.c
@@ -7988,3 +7988,22 @@
 
 	return NULL;
 }
+
+bool lim_check_if_vendor_oui_match(tpAniSirGlobal mac_ctx,
+					uint8_t *oui, uint8_t oui_len,
+			       uint8_t *ie, uint8_t ie_len)
+{
+	uint8_t *ptr = ie;
+	uint8_t elem_id = *ie;
+
+	if (NULL == ie || 0 == ie_len) {
+		pe_err("IE Null or ie len zero %d", ie_len);
+		return false;
+	}
+
+	if (elem_id == IE_EID_VENDOR &&
+		!qdf_mem_cmp(&ptr[2], oui, oui_len))
+		return true;
+	else
+		return false;
+}
diff --git a/core/mac/src/pe/lim/lim_utils.h b/core/mac/src/pe/lim/lim_utils.h
index 9736827..d4630b0 100644
--- a/core/mac/src/pe/lim/lim_utils.h
+++ b/core/mac/src/pe/lim/lim_utils.h
@@ -1127,4 +1127,19 @@
  * Return: None
  */
 void lim_decrement_pending_mgmt_count(tpAniSirGlobal mac_ctx);
+
+/**
+ * lim_check_if_vendor_oui_match() - Check if the given OUI match in IE buffer
+ * @mac_ctx: MAC context
+ * @ie: IE buffer
+ * @ie_len: length of @ie
+ *
+ * This API is used to check if given vendor OUI
+ * matches in given IE buffer
+ *
+ * Return: True, if mataches. False otherwise
+ */
+bool lim_check_if_vendor_oui_match(tpAniSirGlobal mac_ctx,
+					uint8_t *oui, uint8_t oui_len,
+			       uint8_t *ie, uint8_t ie_len);
 #endif /* __LIM_UTILS_H */
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 ae1fea9..b376bbe 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
@@ -48,6 +48,8 @@
 #include "rrm_api.h"
 
 #include "cds_regdomain.h"
+#include "qdf_crypto.h"
+#include "lim_process_fils.h"
 
 /* ////////////////////////////////////////////////////////////////////// */
 void swap_bit_field16(uint16_t in, uint16_t *out)
@@ -2269,8 +2271,53 @@
 }
 
 #ifdef WLAN_FEATURE_FILS_SK
+static void populate_dot11f_fils_rsn(tpAniSirGlobal mac_ctx,
+				     tDot11fIERSNOpaque *p_dot11f,
+				     uint8_t *rsn_ie)
+{
+	pe_debug("FILS RSN IE length %d", rsn_ie[1]);
+	if (rsn_ie[1]) {
+		p_dot11f->present = 1;
+		p_dot11f->num_data = rsn_ie[1];
+		qdf_mem_copy(p_dot11f->data, &rsn_ie[2], rsn_ie[1]);
+	}
+}
+
+void populate_dot11f_fils_params(tpAniSirGlobal mac_ctx,
+		tDot11fAssocRequest *frm,
+		tpPESession pe_session)
+{
+	struct pe_fils_session *fils_info = pe_session->fils_info;
+
+	/* Populate RSN IE with FILS AKM */
+	populate_dot11f_fils_rsn(mac_ctx, &frm->RSNOpaque,
+				 fils_info->rsn_ie);
+
+	/* Populate FILS session IE */
+	frm->fils_session.present = true;
+	qdf_mem_copy(frm->fils_session.session,
+		     fils_info->fils_session, FILS_SESSION_LENGTH);
+
+	/* Populate FILS Key confirmation IE */
+	if (fils_info->key_auth_len) {
+		frm->fils_key_confirmation.present = true;
+		frm->fils_key_confirmation.num_key_auth =
+						fils_info->key_auth_len;
+
+		qdf_mem_copy(frm->fils_key_confirmation.key_auth,
+			     fils_info->key_auth, fils_info->key_auth_len);
+	}
+}
+
+/**
+ * update_fils_data: update fils params from beacon/probe response
+ * @fils_ind: pointer to sir_fils_indication
+ * @fils_indication: pointer to tDot11fIEfils_indication
+ *
+ * Return: None
+ */
 void update_fils_data(struct sir_fils_indication *fils_ind,
-				 tDot11fIEfils_indication *fils_indication)
+		      tDot11fIEfils_indication *fils_indication)
 {
 	uint8_t *data;
 
@@ -2787,231 +2834,321 @@
 
 } /* End sir_convert_assoc_req_frame2_struct. */
 
+/**
+ * dot11f_parse_assoc_response() - API to parse Assoc IE buffer to struct
+ * @mac_ctx: MAC context
+ * @p_buf: Pointer to the assoc IE buffer
+ * @n_buf: length of the @p_buf
+ * @p_frm: Struct to populate the IE buffer after parsing
+ * @append_ie: Boolean to indicate whether to reset @p_frm or not. If @append_ie
+ *             is true, @p_frm struct is not reset to zeros.
+ *
+ * Return: tSirRetStatus
+ */
+static tSirRetStatus dot11f_parse_assoc_response(tpAniSirGlobal mac_ctx,
+						 uint8_t *p_buf, uint32_t n_buf,
+						 tDot11fAssocResponse *p_frm,
+						 bool append_ie)
+{
+	uint32_t status;
+
+	status = dot11f_unpack_assoc_response(mac_ctx, p_buf,
+					      n_buf, p_frm, append_ie);
+	if (DOT11F_FAILED(status)) {
+		pe_err("Failed to parse an Association Response (0x%08x, %d bytes):",
+			status, n_buf);
+		QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR,
+				   p_buf, n_buf);
+		return eSIR_FAILURE;
+	}
+
+	return eSIR_SUCCESS;
+}
+
+#ifdef WLAN_FEATURE_FILS_SK
+/**
+ * fils_convert_assoc_rsp_frame2_struct() - Copy FILS IE's to Assoc rsp struct
+ * @ar: frame parser Assoc response struct
+ * @pAssocRsp: LIM Assoc response
+ *
+ * Return: None
+ */
+static void fils_convert_assoc_rsp_frame2_struct(tDot11fAssocResponse *ar,
+						 tpSirAssocRsp pAssocRsp)
+{
+	if (ar->fils_session.present) {
+		pe_debug("fils session IE present");
+		pAssocRsp->fils_session.present = true;
+		qdf_mem_copy(pAssocRsp->fils_session.session,
+				ar->fils_session.session,
+				DOT11F_IE_FILS_SESSION_MAX_LEN);
+	}
+
+	if (ar->fils_key_confirmation.present) {
+		pe_debug("fils key conf IE present");
+		pAssocRsp->fils_key_auth.num_key_auth =
+			ar->fils_key_confirmation.num_key_auth;
+		qdf_mem_copy(pAssocRsp->fils_key_auth.key_auth,
+				ar->fils_key_confirmation.key_auth,
+				pAssocRsp->fils_key_auth.num_key_auth);
+	}
+
+	if (ar->fils_kde.present) {
+		pe_debug("fils kde IE present %d",
+				ar->fils_kde.num_kde_list);
+		pAssocRsp->fils_kde.num_kde_list =
+			ar->fils_kde.num_kde_list;
+		qdf_mem_copy(pAssocRsp->fils_kde.key_rsc,
+				ar->fils_kde.key_rsc, KEY_RSC_LEN);
+		qdf_mem_copy(&pAssocRsp->fils_kde.kde_list,
+				&ar->fils_kde.kde_list,
+				pAssocRsp->fils_kde.num_kde_list);
+	}
+}
+#else
+static inline void fils_convert_assoc_rsp_frame2_struct(tDot11fAssocResponse
+							*ar, tpSirAssocRsp
+							pAssocRsp)
+{ }
+#endif
+
 tSirRetStatus
 sir_convert_assoc_resp_frame2_struct(tpAniSirGlobal pMac,
-				     uint8_t *pFrame,
-				     uint32_t nFrame, tpSirAssocRsp pAssocRsp)
+		tpPESession session_entry,
+		uint8_t *pFrame, uint32_t nFrame,
+		tpSirAssocRsp pAssocRsp)
 {
-	static tDot11fAssocResponse ar;
+	tDot11fAssocResponse *ar;
 	uint32_t status;
 	uint8_t cnt = 0;
 
-	/* Zero-init our [out] parameter, */
-	qdf_mem_set((uint8_t *) pAssocRsp, sizeof(tSirAssocRsp), 0);
-
-	/* delegate to the framesc-generated code, */
-	status = dot11f_unpack_assoc_response(pMac, pFrame, nFrame, &ar, false);
-	if (DOT11F_FAILED(status)) {
-		pe_err("Failed to parse an Association Response (0x%08x, %d bytes):",
-			status, nFrame);
-		QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR,
-				   pFrame, nFrame);
+	ar = qdf_mem_malloc(sizeof(*ar));
+	if (!ar) {
+		pe_err("Assoc rsp mem alloc fails");
 		return eSIR_FAILURE;
-	} else if (DOT11F_WARNED(status)) {
-		pe_debug("There were warnings while unpacking an Association Response (0x%08x, %d bytes):",
-			status, nFrame);
 	}
-	/* & "transliterate" from a 'tDot11fAssocResponse' a 'tSirAssocRsp'... */
+
+	/* decrypt the cipher text using AEAD decryption */
+	if (lim_is_fils_connection(session_entry)) {
+		status = aead_decrypt_assoc_rsp(pMac, session_entry,
+						ar, pFrame, &nFrame);
+		if (!QDF_IS_STATUS_SUCCESS(status)) {
+			pe_err("FILS assoc rsp AEAD decrypt fails");
+			qdf_mem_free(ar);
+			return eSIR_FAILURE;
+		}
+	}
+
+	status = dot11f_parse_assoc_response(pMac, pFrame, nFrame, ar, false);
+	if (eSIR_SUCCESS != status) {
+		qdf_mem_free(ar);
+		return status;
+	}
+
 
 	/* Capabilities */
-	pAssocRsp->capabilityInfo.ess = ar.Capabilities.ess;
-	pAssocRsp->capabilityInfo.ibss = ar.Capabilities.ibss;
-	pAssocRsp->capabilityInfo.cfPollable = ar.Capabilities.cfPollable;
-	pAssocRsp->capabilityInfo.cfPollReq = ar.Capabilities.cfPollReq;
-	pAssocRsp->capabilityInfo.privacy = ar.Capabilities.privacy;
-	pAssocRsp->capabilityInfo.shortPreamble = ar.Capabilities.shortPreamble;
-	pAssocRsp->capabilityInfo.pbcc = ar.Capabilities.pbcc;
+	pAssocRsp->capabilityInfo.ess = ar->Capabilities.ess;
+	pAssocRsp->capabilityInfo.ibss = ar->Capabilities.ibss;
+	pAssocRsp->capabilityInfo.cfPollable = ar->Capabilities.cfPollable;
+	pAssocRsp->capabilityInfo.cfPollReq = ar->Capabilities.cfPollReq;
+	pAssocRsp->capabilityInfo.privacy = ar->Capabilities.privacy;
+	pAssocRsp->capabilityInfo.shortPreamble =
+		ar->Capabilities.shortPreamble;
+	pAssocRsp->capabilityInfo.pbcc = ar->Capabilities.pbcc;
 	pAssocRsp->capabilityInfo.channelAgility =
-		ar.Capabilities.channelAgility;
-	pAssocRsp->capabilityInfo.spectrumMgt = ar.Capabilities.spectrumMgt;
-	pAssocRsp->capabilityInfo.qos = ar.Capabilities.qos;
-	pAssocRsp->capabilityInfo.shortSlotTime = ar.Capabilities.shortSlotTime;
-	pAssocRsp->capabilityInfo.apsd = ar.Capabilities.apsd;
-	pAssocRsp->capabilityInfo.rrm = ar.Capabilities.rrm;
-	pAssocRsp->capabilityInfo.dsssOfdm = ar.Capabilities.dsssOfdm;
-	pAssocRsp->capabilityInfo.delayedBA = ar.Capabilities.delayedBA;
-	pAssocRsp->capabilityInfo.immediateBA = ar.Capabilities.immediateBA;
+		ar->Capabilities.channelAgility;
+	pAssocRsp->capabilityInfo.spectrumMgt = ar->Capabilities.spectrumMgt;
+	pAssocRsp->capabilityInfo.qos = ar->Capabilities.qos;
+	pAssocRsp->capabilityInfo.shortSlotTime =
+		ar->Capabilities.shortSlotTime;
+	pAssocRsp->capabilityInfo.apsd = ar->Capabilities.apsd;
+	pAssocRsp->capabilityInfo.rrm = ar->Capabilities.rrm;
+	pAssocRsp->capabilityInfo.dsssOfdm = ar->Capabilities.dsssOfdm;
+	pAssocRsp->capabilityInfo.delayedBA = ar->Capabilities.delayedBA;
+	pAssocRsp->capabilityInfo.immediateBA = ar->Capabilities.immediateBA;
 
-	pAssocRsp->statusCode = ar.Status.status;
-	pAssocRsp->aid = ar.AID.associd;
+	pAssocRsp->statusCode = ar->Status.status;
+	pAssocRsp->aid = ar->AID.associd;
 #ifdef WLAN_FEATURE_11W
-	if (ar.TimeoutInterval.present) {
+	if (ar->TimeoutInterval.present) {
 		pAssocRsp->TimeoutInterval.present = 1;
 		pAssocRsp->TimeoutInterval.timeoutType =
-			ar.TimeoutInterval.timeoutType;
+			ar->TimeoutInterval.timeoutType;
 		pAssocRsp->TimeoutInterval.timeoutValue =
-			ar.TimeoutInterval.timeoutValue;
+			ar->TimeoutInterval.timeoutValue;
 	}
 #endif
 
-	if (!ar.SuppRates.present) {
+	if (!ar->SuppRates.present) {
 		pAssocRsp->suppRatesPresent = 0;
 		pe_warn("Mandatory IE Supported Rates not present!");
 	} else {
 		pAssocRsp->suppRatesPresent = 1;
 		convert_supp_rates(pMac, &pAssocRsp->supportedRates,
-				   &ar.SuppRates);
+				&ar->SuppRates);
 	}
 
-	if (ar.ExtSuppRates.present) {
+	if (ar->ExtSuppRates.present) {
 		pAssocRsp->extendedRatesPresent = 1;
 		convert_ext_supp_rates(pMac, &pAssocRsp->extendedRates,
-				       &ar.ExtSuppRates);
+				&ar->ExtSuppRates);
 	}
 
-	if (ar.EDCAParamSet.present) {
+	if (ar->EDCAParamSet.present) {
 		pAssocRsp->edcaPresent = 1;
-		convert_edca_param(pMac, &pAssocRsp->edca, &ar.EDCAParamSet);
+		convert_edca_param(pMac, &pAssocRsp->edca, &ar->EDCAParamSet);
 	}
 
-	if (ar.WMMParams.present) {
+	if (ar->WMMParams.present) {
 		pAssocRsp->wmeEdcaPresent = 1;
-		convert_wmm_params(pMac, &pAssocRsp->edca, &ar.WMMParams);
+		convert_wmm_params(pMac, &pAssocRsp->edca, &ar->WMMParams);
 		pe_debug("Received Assoc Resp with WMM Param");
-		__print_wmm_params(pMac, &ar.WMMParams);
+		__print_wmm_params(pMac, &ar->WMMParams);
 	}
 
-	if (ar.HTCaps.present) {
+	if (ar->HTCaps.present) {
 		pe_debug("Received Assoc Resp with HT Cap");
-		qdf_mem_copy(&pAssocRsp->HTCaps, &ar.HTCaps,
+		qdf_mem_copy(&pAssocRsp->HTCaps, &ar->HTCaps,
 			     sizeof(tDot11fIEHTCaps));
 	}
 
-	if (ar.HTInfo.present) {
+	if (ar->HTInfo.present) {
 		pe_debug("Received Assoc Resp with HT Info");
-		qdf_mem_copy(&pAssocRsp->HTInfo, &ar.HTInfo,
+		qdf_mem_copy(&pAssocRsp->HTInfo, &ar->HTInfo,
 			     sizeof(tDot11fIEHTInfo));
 	}
-	if (ar.MobilityDomain.present) {
+	if (ar->MobilityDomain.present) {
 		/* MobilityDomain */
 		pAssocRsp->mdiePresent = 1;
 		qdf_mem_copy((uint8_t *) &(pAssocRsp->mdie[0]),
-			     (uint8_t *) &(ar.MobilityDomain.MDID),
-			     sizeof(uint16_t));
-		pAssocRsp->mdie[2] =
-			((ar.MobilityDomain.overDSCap << 0) | (ar.MobilityDomain.
-							       resourceReqCap <<
-							       1));
+				(uint8_t *) &(ar->MobilityDomain.MDID),
+				sizeof(uint16_t));
+		pAssocRsp->mdie[2] = ((ar->MobilityDomain.overDSCap << 0) |
+				      (ar->MobilityDomain.resourceReqCap << 1));
 		pe_debug("new mdie=%02x%02x%02x",
 			(unsigned int)pAssocRsp->mdie[0],
 			(unsigned int)pAssocRsp->mdie[1],
 			(unsigned int)pAssocRsp->mdie[2]);
 	}
 
-	if (ar.FTInfo.present) {
+	if (ar->FTInfo.present) {
 		pe_debug("FT Info present %d %d %d",
-			ar.FTInfo.R0KH_ID.num_PMK_R0_ID,
-			ar.FTInfo.R0KH_ID.present, ar.FTInfo.R1KH_ID.present);
+			ar->FTInfo.R0KH_ID.num_PMK_R0_ID,
+			ar->FTInfo.R0KH_ID.present, ar->FTInfo.R1KH_ID.present);
 		pAssocRsp->ftinfoPresent = 1;
-		qdf_mem_copy(&pAssocRsp->FTInfo, &ar.FTInfo,
-			     sizeof(tDot11fIEFTInfo));
+		qdf_mem_copy(&pAssocRsp->FTInfo, &ar->FTInfo,
+				sizeof(tDot11fIEFTInfo));
 	}
 
-	if (ar.num_RICDataDesc && ar.num_RICDataDesc <= 2) {
-		for (cnt = 0; cnt < ar.num_RICDataDesc; cnt++) {
-			if (ar.RICDataDesc[cnt].present) {
+	if (ar->num_RICDataDesc && ar->num_RICDataDesc <= 2) {
+		for (cnt = 0; cnt < ar->num_RICDataDesc; cnt++) {
+			if (ar->RICDataDesc[cnt].present) {
 				qdf_mem_copy(&pAssocRsp->RICData[cnt],
-					     &ar.RICDataDesc[cnt],
-					     sizeof(tDot11fIERICDataDesc));
+						&ar->RICDataDesc[cnt],
+						sizeof(tDot11fIERICDataDesc));
 			}
 		}
-		pAssocRsp->num_RICData = ar.num_RICDataDesc;
+		pAssocRsp->num_RICData = ar->num_RICDataDesc;
 		pAssocRsp->ricPresent = true;
 	}
 
 #ifdef FEATURE_WLAN_ESE
-	if (ar.num_WMMTSPEC) {
-		pAssocRsp->num_tspecs = ar.num_WMMTSPEC;
-		for (cnt = 0; cnt < ar.num_WMMTSPEC; cnt++) {
+	if (ar->num_WMMTSPEC) {
+		pAssocRsp->num_tspecs = ar->num_WMMTSPEC;
+		for (cnt = 0; cnt < ar->num_WMMTSPEC; cnt++) {
 			qdf_mem_copy(&pAssocRsp->TSPECInfo[cnt],
-				     &ar.WMMTSPEC[cnt],
-				     (sizeof(tDot11fIEWMMTSPEC) *
-				      ar.num_WMMTSPEC));
+					&ar->WMMTSPEC[cnt],
+					(sizeof(tDot11fIEWMMTSPEC) *
+					 ar->num_WMMTSPEC));
 		}
 		pAssocRsp->tspecPresent = true;
 	}
 
-	if (ar.ESETrafStrmMet.present) {
+	if (ar->ESETrafStrmMet.present) {
 		pAssocRsp->tsmPresent = 1;
 		qdf_mem_copy(&pAssocRsp->tsmIE.tsid,
-			     &ar.ESETrafStrmMet.tsid, sizeof(tSirMacESETSMIE));
+				&ar->ESETrafStrmMet.tsid,
+				sizeof(tSirMacESETSMIE));
 	}
 #endif
 
-	if (ar.VHTCaps.present) {
-		qdf_mem_copy(&pAssocRsp->VHTCaps, &ar.VHTCaps,
+	if (ar->VHTCaps.present) {
+		qdf_mem_copy(&pAssocRsp->VHTCaps, &ar->VHTCaps,
 			     sizeof(tDot11fIEVHTCaps));
 		pe_debug("Received Assoc Response with VHT Cap");
 		lim_log_vht_cap(pMac, &pAssocRsp->VHTCaps);
 	}
-	if (ar.VHTOperation.present) {
-		qdf_mem_copy(&pAssocRsp->VHTOperation, &ar.VHTOperation,
+	if (ar->VHTOperation.present) {
+		qdf_mem_copy(&pAssocRsp->VHTOperation, &ar->VHTOperation,
 			     sizeof(tDot11fIEVHTOperation));
 		pe_debug("Received Assoc Response with VHT Operation");
 		lim_log_vht_operation(pMac, &pAssocRsp->VHTOperation);
 	}
 
-	if (ar.ExtCap.present) {
+	if (ar->ExtCap.present) {
 		struct s_ext_cap *ext_cap;
-		qdf_mem_copy(&pAssocRsp->ExtCap, &ar.ExtCap,
-			     sizeof(tDot11fIEExtCap));
+		qdf_mem_copy(&pAssocRsp->ExtCap, &ar->ExtCap,
+				sizeof(tDot11fIEExtCap));
 		ext_cap = (struct s_ext_cap *)&pAssocRsp->ExtCap.bytes;
 		pe_debug("timingMeas: %d, finetimingMeas Init: %d, Resp: %d",
 			ext_cap->timing_meas, ext_cap->fine_time_meas_initiator,
 			ext_cap->fine_time_meas_responder);
 	}
 
-	if (ar.QosMapSet.present) {
+	if (ar->QosMapSet.present) {
 		pAssocRsp->QosMapSet.present = 1;
 		convert_qos_mapset_frame(pMac, &pAssocRsp->QosMapSet,
-					 &ar.QosMapSet);
+					 &ar->QosMapSet);
 		pe_debug("Received Assoc Response with Qos Map Set");
 		lim_log_qos_map_set(pMac, &pAssocRsp->QosMapSet);
 	}
 
-	pAssocRsp->vendor_vht_ie.present = ar.vendor_vht_ie.present;
-	if (ar.vendor_vht_ie.present) {
-		pAssocRsp->vendor_vht_ie.type = ar.vendor_vht_ie.type;
-		pAssocRsp->vendor_vht_ie.sub_type = ar.vendor_vht_ie.sub_type;
+	pAssocRsp->vendor_vht_ie.present = ar->vendor_vht_ie.present;
+	if (ar->vendor_vht_ie.present) {
+		pAssocRsp->vendor_vht_ie.type = ar->vendor_vht_ie.type;
+		pAssocRsp->vendor_vht_ie.sub_type = ar->vendor_vht_ie.sub_type;
 	}
-	if (ar.OBSSScanParameters.present) {
+	if (ar->OBSSScanParameters.present) {
 		qdf_mem_copy(&pAssocRsp->obss_scanparams,
-			&ar.OBSSScanParameters,
-			sizeof(struct sDot11fIEOBSSScanParameters));
+				&ar->OBSSScanParameters,
+				sizeof(struct sDot11fIEOBSSScanParameters));
 	}
-	if (ar.vendor_vht_ie.VHTCaps.present) {
+	if (ar->vendor_vht_ie.VHTCaps.present) {
 		qdf_mem_copy(&pAssocRsp->vendor_vht_ie.VHTCaps,
-				&ar.vendor_vht_ie.VHTCaps,
+				&ar->vendor_vht_ie.VHTCaps,
 				sizeof(tDot11fIEVHTCaps));
 		pe_debug("Received Assoc Response with Vendor specific VHT Cap");
 		lim_log_vht_cap(pMac, &pAssocRsp->VHTCaps);
 	}
-	if (ar.vendor_vht_ie.VHTOperation.present) {
+	if (ar->vendor_vht_ie.VHTOperation.present) {
 		qdf_mem_copy(&pAssocRsp->vendor_vht_ie.VHTOperation,
-				&ar.vendor_vht_ie.VHTOperation,
+				&ar->vendor_vht_ie.VHTOperation,
 				sizeof(tDot11fIEVHTOperation));
 		pe_debug("Received Assoc Response with Vendor specific VHT Oper");
 		lim_log_vht_operation(pMac, &pAssocRsp->VHTOperation);
 	}
 
-	if (ar.vendor_he_cap.present) {
+	if (ar->vendor_he_cap.present) {
 		pe_debug("11AX: HE cap IE present");
-		qdf_mem_copy(&pAssocRsp->vendor_he_cap, &ar.vendor_he_cap,
+		qdf_mem_copy(&pAssocRsp->vendor_he_cap, &ar->vendor_he_cap,
 			     sizeof(tDot11fIEvendor_he_cap));
 	}
-	if (ar.vendor_he_op.present) {
+	if (ar->vendor_he_op.present) {
 		pe_debug("11AX: HE Operation IE present");
-		qdf_mem_copy(&pAssocRsp->vendor_he_op, &ar.vendor_he_op,
+		qdf_mem_copy(&pAssocRsp->vendor_he_op, &ar->vendor_he_op,
 			     sizeof(tDot11fIEvendor_he_op));
 	}
 
-	if (ar.MBO_IE.present && ar.MBO_IE.rssi_assoc_rej.present) {
+	if (ar->MBO_IE.present && ar->MBO_IE.rssi_assoc_rej.present) {
 		qdf_mem_copy(&pAssocRsp->rssi_assoc_rej,
-				&ar.MBO_IE.rssi_assoc_rej,
+				&ar->MBO_IE.rssi_assoc_rej,
 				sizeof(tDot11fTLVrssi_assoc_rej));
 		pe_debug("Received Assoc Response with rssi based assoc rej");
 	}
 
+	fils_convert_assoc_rsp_frame2_struct(ar, pAssocRsp);
+
+	qdf_mem_free(ar);
 	return eSIR_SUCCESS;
 
 } /* End sir_convert_assoc_resp_frame2_struct. */
diff --git a/core/sme/inc/csr_api.h b/core/sme/inc/csr_api.h
index f361c58..630db79 100644
--- a/core/sme/inc/csr_api.h
+++ b/core/sme/inc/csr_api.h
@@ -1487,6 +1487,11 @@
 	uint8_t tx_mcs_map;
 	/* Extended capabilities of STA */
 	uint8_t ecsa_capable;
+	bool is_fils_connection;
+#ifdef WLAN_FEATURE_FILS_SK
+	uint16_t fils_seq_num;
+	struct fils_join_rsp_params *fils_join_rsp;
+#endif
 } tCsrRoamInfo;
 
 typedef struct tagCsrFreqScanInfo {
diff --git a/core/sme/src/csr/csr_api_roam.c b/core/sme/src/csr/csr_api_roam.c
index 3d8e91c..112fb00 100644
--- a/core/sme/src/csr/csr_api_roam.c
+++ b/core/sme/src/csr/csr_api_roam.c
@@ -6504,6 +6504,27 @@
 }
 #endif
 
+#if defined(WLAN_FEATURE_FILS_SK)
+/**
+ * csr_update_fils_seq_number() - Copy FILS sequence number to roam info
+ * @session: CSR Roam Session
+ * @roam_info: Roam info
+ *
+ * Return: None
+ */
+static void csr_update_fils_seq_number(tCsrRoamSession *session,
+					 tCsrRoamInfo *roam_info)
+{
+	roam_info->is_fils_connection = true;
+	roam_info->fils_seq_num = session->fils_seq_num;
+	pe_debug("FILS sequence number %x", session->fils_seq_num);
+}
+#else
+static inline void csr_update_fils_seq_number(tCsrRoamSession *session,
+						tCsrRoamInfo *roam_info)
+{}
+#endif
+
 /**
  * csr_roam_process_results_default() - Process the result for start bss
  * @mac_ctx:          Global MAC Context
@@ -6526,7 +6547,8 @@
 	}
 	session = CSR_GET_SESSION(mac_ctx, session_id);
 
-	sme_debug("receives no association indication");
+	sme_debug("receives no association indication; FILS %d",
+		  session->is_fils_connection);
 	sme_debug("Assoc ref count: %d", session->bRefAssocStartCnt);
 	if (CSR_IS_INFRASTRUCTURE(&session->connectedProfile)
 		|| CSR_IS_ROAM_SUBSTATE_STOP_BSS_REQ(mac_ctx, session_id)) {
@@ -6540,6 +6562,11 @@
 		csr_set_default_dot11_mode(mac_ctx);
 	}
 
+	qdf_mem_set(&roam_info, sizeof(tCsrRoamInfo), 0);
+	/* Copy FILS sequence number used to be updated to userspace */
+	if (session->is_fils_connection)
+		csr_update_fils_seq_number(session, &roam_info);
+
 	switch (cmd->u.roamCmd.roamReason) {
 	/*
 	 * If this transition is because of an 802.11 OID, then we
@@ -6552,7 +6579,6 @@
 	case eCsrSmeIssuedDisassocForHandoff:
 		csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_IDLE,
 			session_id);
-		qdf_mem_set(&roam_info, sizeof(tCsrRoamInfo), 0);
 		roam_info.pBssDesc = cmd->u.roamCmd.pLastRoamBss;
 		roam_info.pProfile = &cmd->u.roamCmd.roamProfile;
 		roam_info.statusCode = session->joinFailStatusCode.statusCode;
@@ -6922,6 +6948,154 @@
 
 }
 
+#ifdef WLAN_FEATURE_FILS_SK
+/**
+ * populate_fils_params_join_rsp() - Copy FILS params from JOIN rsp
+ * @mac_ctx: Global MAC Context
+ * @roam_info: CSR Roam Info
+ * @join_rsp: SME Join response
+ *
+ * Copy the FILS params from the join results
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS populate_fils_params_join_rsp(tpAniSirGlobal mac_ctx,
+						tCsrRoamInfo *roam_info,
+						tSirSmeJoinRsp *join_rsp)
+{
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct fils_join_rsp_params *roam_fils_info,
+				    *fils_join_rsp = join_rsp->fils_join_rsp;
+
+	if (!fils_join_rsp->fils_pmk_len ||
+			!fils_join_rsp->fils_pmk || !fils_join_rsp->tk_len ||
+			!fils_join_rsp->kek_len || !fils_join_rsp->gtk_len) {
+		sme_err("fils join rsp err: pmk len %d tk len %d kek len %d gtk len %d",
+			fils_join_rsp->fils_pmk_len,
+			fils_join_rsp->tk_len,
+			fils_join_rsp->kek_len,
+			fils_join_rsp->gtk_len);
+		status = QDF_STATUS_E_FAILURE;
+		goto free_fils_join_rsp;
+	}
+
+	roam_info->fils_join_rsp = qdf_mem_malloc(sizeof(*fils_join_rsp));
+	if (!roam_info->fils_join_rsp) {
+		sme_err("fils_join_rsp malloc fails!");
+		status = QDF_STATUS_E_FAILURE;
+		goto free_fils_join_rsp;
+	}
+
+	roam_fils_info = roam_info->fils_join_rsp;
+	roam_fils_info->fils_pmk = qdf_mem_malloc(fils_join_rsp->fils_pmk_len);
+	if (!roam_fils_info->fils_pmk) {
+		qdf_mem_free(roam_info->fils_join_rsp);
+		roam_info->fils_join_rsp = NULL;
+		sme_err("fils_pmk malloc fails!");
+		status = QDF_STATUS_E_FAILURE;
+		goto free_fils_join_rsp;
+	}
+
+	roam_info->fils_seq_num = join_rsp->fils_seq_num;
+	roam_fils_info->fils_pmk_len = fils_join_rsp->fils_pmk_len;
+	qdf_mem_copy(roam_fils_info->fils_pmk,
+		     fils_join_rsp->fils_pmk, roam_fils_info->fils_pmk_len);
+
+	qdf_mem_copy(roam_fils_info->fils_pmkid,
+		     fils_join_rsp->fils_pmkid, PMKID_LEN);
+
+	roam_fils_info->kek_len = fils_join_rsp->kek_len;
+	qdf_mem_copy(roam_fils_info->kek,
+		     fils_join_rsp->kek, roam_fils_info->kek_len);
+
+	roam_fils_info->tk_len = fils_join_rsp->tk_len;
+	qdf_mem_copy(roam_fils_info->tk,
+		     fils_join_rsp->tk, fils_join_rsp->tk_len);
+
+	roam_fils_info->gtk_len = fils_join_rsp->gtk_len;
+	qdf_mem_copy(roam_fils_info->gtk,
+		     fils_join_rsp->gtk, roam_fils_info->gtk_len);
+
+	sme_debug("FILS connect params copied to CSR!");
+
+free_fils_join_rsp:
+	qdf_mem_free(fils_join_rsp->fils_pmk);
+	qdf_mem_free(fils_join_rsp);
+	return status;
+}
+
+/**
+ * csr_process_fils_join_rsp() - Process join rsp for FILS connection
+ * @mac_ctx: Global MAC Context
+ * @profile: CSR Roam Profile
+ * @session_id: Session ID
+ * @roam_info: CSR Roam Info
+ * @bss_desc: BSS description
+ * @join_rsp: SME Join rsp
+ *
+ * Process SME join response for FILS connection
+ *
+ * Return: None
+ */
+static void csr_process_fils_join_rsp(tpAniSirGlobal mac_ctx,
+					tCsrRoamProfile *profile,
+					uint32_t session_id,
+					tCsrRoamInfo *roam_info,
+					tSirBssDescription *bss_desc,
+					tSirSmeJoinRsp *join_rsp)
+{
+	tSirMacAddr bcast_mac = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+	QDF_STATUS status;
+
+	if (!join_rsp || !join_rsp->fils_join_rsp) {
+		sme_err("Join rsp doesn't have FILS info");
+		goto process_fils_join_rsp_fail;
+	}
+
+	/* Copy FILS params */
+	status = populate_fils_params_join_rsp(mac_ctx, roam_info, join_rsp);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		sme_err("Copy FILS params join rsp fails");
+		goto process_fils_join_rsp_fail;
+	}
+
+	status = csr_roam_issue_set_context_req(mac_ctx, session_id,
+					profile->negotiatedMCEncryptionType,
+					bss_desc, &bcast_mac, true, false,
+					eSIR_RX_ONLY, 2,
+					roam_info->fils_join_rsp->gtk_len,
+					roam_info->fils_join_rsp->gtk, 0);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		sme_err("Set context for bcast fail");
+		goto process_fils_join_rsp_fail;
+	}
+
+	status = csr_roam_issue_set_context_req(mac_ctx, session_id,
+					profile->negotiatedUCEncryptionType,
+					bss_desc, &(bss_desc->bssId), true,
+					true, eSIR_TX_RX, 0,
+					roam_info->fils_join_rsp->tk_len,
+					roam_info->fils_join_rsp->tk, 0);
+	if (!QDF_IS_STATUS_SUCCESS(status)) {
+		sme_err("Set context for unicast fail");
+		goto process_fils_join_rsp_fail;
+	}
+	return;
+
+process_fils_join_rsp_fail:
+	csr_roam_substate_change(mac_ctx, eCSR_ROAM_SUBSTATE_NONE, session_id);
+}
+#else
+
+static inline void csr_process_fils_join_rsp(tpAniSirGlobal mac_ctx,
+						tCsrRoamProfile *profile,
+						uint32_t session_id,
+						tCsrRoamInfo *roam_info,
+						tSirBssDescription *bss_desc,
+						tSirSmeJoinRsp *join_rsp)
+{}
+#endif
+
 /**
  * csr_roam_process_join_res() - Process the Join results
  * @mac_ctx:          Global MAC Context
@@ -7097,6 +7271,11 @@
 				profile->negotiatedMCEncryptionType,
 				bss_desc, &bcast_mac, false, false,
 				eSIR_TX_RX, 0, 0, NULL, 0);
+		} else if (CSR_IS_AUTH_TYPE_FILS(profile->negotiatedAuthType)
+				&& join_rsp->is_fils_connection) {
+			roam_info.is_fils_connection = true;
+			csr_process_fils_join_rsp(mac_ctx, profile, session_id,
+				&roam_info, bss_desc, join_rsp);
 		} else {
 			/* Need to wait for supplicant authtication */
 			roam_info.fAuthRequired = true;
@@ -7468,6 +7647,7 @@
 		break;
 	case eCsrStopBssSuccess:
 		if (CSR_IS_NDI(profile)) {
+			qdf_mem_set(&roam_info, sizeof(roam_info), 0);
 			csr_roam_update_ndp_return_params(mac_ctx, res,
 				&roam_status, &roam_result, &roam_info);
 			csr_roam_call_callback(mac_ctx, session_id, &roam_info,
@@ -7477,6 +7657,7 @@
 		break;
 	case eCsrStopBssFailure:
 		if (CSR_IS_NDI(profile)) {
+			qdf_mem_set(&roam_info, sizeof(roam_info), 0);
 			csr_roam_update_ndp_return_params(mac_ctx, res,
 				&roam_status, &roam_result, &roam_info);
 			csr_roam_call_callback(mac_ctx, session_id, &roam_info,
@@ -8873,6 +9054,11 @@
 	if (pEntry)
 		pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link);
 
+	sme_debug("is_fils_connection %d", pSmeJoinRsp->is_fils_connection);
+	/* Copy Sequence Number last used for FILS assoc failure case */
+	if (session_ptr->is_fils_connection)
+		session_ptr->fils_seq_num = pSmeJoinRsp->fils_seq_num;
+
 	if (eSIR_SME_SUCCESS == pSmeJoinRsp->statusCode) {
 		if (pCommand
 		    && eCsrSmeIssuedAssocToSimilarAP ==
diff --git a/core/sme/src/csr/csr_inside_api.h b/core/sme/src/csr/csr_inside_api.h
index 3090375..afc2427 100644
--- a/core/sme/src/csr/csr_inside_api.h
+++ b/core/sme/src/csr/csr_inside_api.h
@@ -181,6 +181,12 @@
 #define CSR_IS_ENC_TYPE_STATIC(encType) ((eCSR_ENCRYPT_TYPE_NONE == (encType)) || \
 					    (eCSR_ENCRYPT_TYPE_WEP40_STATICKEY == (encType)) || \
 					    (eCSR_ENCRYPT_TYPE_WEP104_STATICKEY == (encType)))
+
+#define CSR_IS_AUTH_TYPE_FILS(auth_type) \
+		((eCSR_AUTH_TYPE_FILS_SHA256 == auth_type) || \
+		(eCSR_AUTH_TYPE_FILS_SHA384 == auth_type) || \
+		(eCSR_AUTH_TYPE_FT_FILS_SHA256 == auth_type) || \
+		(eCSR_AUTH_TYPE_FT_FILS_SHA384 == auth_type))
 #define CSR_IS_WAIT_FOR_KEY(pMac, sessionId) \
 		 (CSR_IS_ROAM_JOINED(pMac, sessionId) && \
 		  CSR_IS_ROAM_SUBSTATE_WAITFORKEY(pMac, sessionId))