Parcourir la source

qcacld-3.0: Add FILS roaming support

Add FILS roaming support changes as follows:
- Update ERP info in RSO Start
- Update HLP info in a new command WMI_PDEV_UPDATE_FILS_HLP_PKT_CMDID
- Set/Delete PMK cache info with WMI_PDEV_UPDATE_PMK_CACHE_CMDID
- Process FILS TLV in Roam Synch Indication and update the FILS info
  [seq number,PMK, KEK, realm] to Supplicant.

Change-Id: I78c3bdde080701deb8d2bdb92d8d57d18cceb864
CRs-Fixed: 2081252
Vignesh Viswanathan il y a 7 ans
Parent
commit
c6d1e1cc13

+ 2 - 0
core/cds/inc/cds_config.h

@@ -173,9 +173,11 @@ struct cds_config_info {
 
 #ifdef WLAN_FEATURE_FILS_SK
 #define MAX_PMK_LEN 48
+#define MAX_PMKID_LEN 16
 #define FILS_MAX_KEYNAME_NAI_LENGTH 255
 #define FILS_MAX_REALM_LEN 255
 #define FILS_MAX_RRK_LENGTH 64
+#define FILS_MAX_RIK_LENGTH FILS_MAX_RRK_LENGTH
 
 struct cds_fils_connection_info {
 	bool is_fils_connection;

+ 15 - 0
core/hdd/inc/wlan_hdd_main.h

@@ -2763,9 +2763,24 @@ int hdd_reset_limit_off_chan(struct hdd_adapter *adapter);
  * Return: None
  */
 void hdd_clear_fils_connection_info(struct hdd_adapter *adapter);
+
+/**
+ * hdd_update_hlp_info() - Update HLP packet received in FILS (re)assoc rsp
+ * @dev: net device
+ * @roam_fils_params: Fils join rsp params
+ *
+ * This API is used to send the received HLP packet in Assoc rsp(FILS AKM)
+ * to the network layer.
+ *
+ * Return: None
+ */
+void hdd_update_hlp_info(struct net_device *dev, tCsrRoamInfo *roam_info);
 #else
 static inline void hdd_clear_fils_connection_info(struct hdd_adapter *adapter)
 { }
+static inline void hdd_update_hlp_info(struct net_device *dev,
+				       tCsrRoamInfo *roam_info)
+{}
 #endif
 
 #undef nla_parse

+ 15 - 0
core/hdd/src/wlan_hdd_assoc.c

@@ -2187,6 +2187,11 @@ static void hdd_send_re_assoc_event(struct net_device *dev,
 		(u8 *)pCsrRoamInfo->pbFrames + pCsrRoamInfo->nBeaconLength,
 		pCsrRoamInfo->nAssocReqLength);
 
+	wlan_hdd_save_gtk_offload_params(adapter, NULL,
+			pCsrRoamInfo->kek,
+			pCsrRoamInfo->kek_len,
+			pCsrRoamInfo->replay_ctr, true);
+
 	hdd_debug("ReAssoc Req IE dump");
 	QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG,
 		assoc_req_ies, pCsrRoamInfo->nAssocReqLength);
@@ -2195,6 +2200,10 @@ static void hdd_send_re_assoc_event(struct net_device *dev,
 			assoc_req_ies, pCsrRoamInfo->nAssocReqLength,
 			rspRsnIe, rspRsnLength,
 			pCsrRoamInfo);
+	hdd_debug("Kek len %d", pCsrRoamInfo->kek_len);
+
+	hdd_update_hlp_info(dev, pCsrRoamInfo);
+
 done:
 	sme_roam_free_connect_profile(&roam_profile);
 	if (final_req_ie)
@@ -2494,6 +2503,12 @@ void hdd_clear_fils_connection_info(struct hdd_adapter *adapter)
 		qdf_mem_free(wext_state->roamProfile.fils_con_info);
 		wext_state->roamProfile.fils_con_info = NULL;
 	}
+
+	if (wext_state->roamProfile.hlp_ie) {
+		qdf_mem_free(wext_state->roamProfile.hlp_ie);
+		wext_state->roamProfile.hlp_ie = NULL;
+		wext_state->roamProfile.hlp_ie_len = 0;
+	}
 }
 #endif
 

+ 410 - 13
core/hdd/src/wlan_hdd_cfg80211.c

@@ -5349,6 +5349,102 @@ wlan_hdd_cfg80211_get_logger_supp_feature(struct wiphy *wiphy,
 	return ret;
 }
 
+#ifdef WLAN_FEATURE_GTK_OFFLOAD
+void wlan_hdd_save_gtk_offload_params(struct hdd_adapter *adapter,
+				      uint8_t *kck_ptr, uint8_t *kek_ptr,
+				      uint32_t kek_len, uint8_t *replay_ctr,
+				      bool big_endian)
+{
+	struct hdd_station_ctx *hdd_sta_ctx;
+	uint8_t *buf;
+	int i;
+	struct pmo_gtk_req *gtk_req = NULL;
+	QDF_STATUS status = QDF_STATUS_E_FAILURE;
+
+	gtk_req = qdf_mem_malloc(sizeof(*gtk_req));
+	if (!gtk_req) {
+		hdd_err("cannot allocate gtk_req");
+		return;
+	}
+
+	hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
+	if (kck_ptr)
+		qdf_mem_copy(gtk_req->kck, kck_ptr, NL80211_KCK_LEN);
+
+	if (kek_ptr)
+		qdf_mem_copy(gtk_req->kek, kek_ptr, kek_len);
+
+	qdf_copy_macaddr(&gtk_req->bssid, &hdd_sta_ctx->conn_info.bssId);
+
+	gtk_req->kek_len = kek_len;
+
+	/* convert big to little endian since driver work on little endian */
+	buf = (uint8_t *)&gtk_req->replay_counter;
+	for (i = 0; i < 8; i++)
+		buf[7 - i] = replay_ctr[i];
+
+	status = pmo_ucfg_cache_gtk_offload_req(adapter->hdd_vdev, gtk_req);
+	if (status != QDF_STATUS_SUCCESS)
+		hdd_err("Failed to cache GTK Offload");
+
+	qdf_mem_free(gtk_req);
+}
+#else
+void wlan_hdd_save_gtk_offload_params(struct hdd_adapter *adapter,
+					     uint8_t *kck_ptr,
+					     uint8_t *kek_ptr,
+					     uint32_t kek_len,
+					     uint8_t *replay_ctr,
+					     bool big_endian)
+{
+}
+#endif
+
+#ifdef WLAN_FEATURE_FILS_SK
+/**
+ * wlan_hdd_add_fils_params_roam_auth_event() - Adds FILS params in roam auth
+ * @skb: SK buffer
+ * @roam_info: Roam info
+ *
+ * API adds fils params[pmk, pmkid, next sequence number] to roam auth event
+ *
+ * Return: zero on success, error code on failure
+ */
+static int wlan_hdd_add_fils_params_roam_auth_event(struct sk_buff *skb,
+						    tCsrRoamInfo *roam_info)
+{
+	if (roam_info->pmk_len &&
+	    nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PMK,
+		    roam_info->pmk_len, roam_info->pmk)) {
+		hdd_err("pmk send fail");
+		return -EINVAL;
+	}
+
+	if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PMKID,
+		    SIR_PMKID_LEN, roam_info->pmkid)) {
+		hdd_err("pmkid send fail");
+		return -EINVAL;
+	}
+
+	if (roam_info->update_erp_next_seq_num &&
+	    nla_put_u16(skb,
+			QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_FILS_ERP_NEXT_SEQ_NUM,
+			roam_info->next_erp_seq_num)) {
+		hdd_err("ERP seq num send fail");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+#else
+static inline int wlan_hdd_add_fils_params_roam_auth_event(struct sk_buff *skb,
+							   tCsrRoamInfo
+							   *roam_info)
+{
+	return 0;
+}
+#endif
+
 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
 /**
  * wlan_hdd_send_roam_auth_event() - Send the roamed and authorized event
@@ -5384,6 +5480,8 @@ int wlan_hdd_send_roam_auth_event(struct hdd_adapter *adapter, uint8_t *bssid,
 	struct hdd_context *hdd_ctx_ptr = WLAN_HDD_GET_CTX(adapter);
 	struct sk_buff *skb = NULL;
 	eCsrAuthType auth_type;
+	uint32_t fils_params_len;
+	int status;
 
 	ENTER();
 
@@ -5394,12 +5492,23 @@ int wlan_hdd_send_roam_auth_event(struct hdd_adapter *adapter, uint8_t *bssid,
 			!roam_info_ptr->roamSynchInProgress)
 		return 0;
 
+	/*
+	 * PMK is sent from FW in Roam Synch Event for FILS Roaming.
+	 * In that case, add three more NL attributes.ie. PMK, PMKID
+	 * and ERP next sequence number. Add corresponding lengths
+	 * with 3 extra NL message headers for each of the
+	 * aforementioned params.
+	 */
+	fils_params_len = roam_info_ptr->pmk_len + SIR_PMKID_LEN +
+			  sizeof(uint16_t) + (3 * NLMSG_HDRLEN);
+
 	skb = cfg80211_vendor_event_alloc(hdd_ctx_ptr->wiphy,
 			&(adapter->wdev),
 			ETH_ALEN + req_rsn_len + rsp_rsn_len +
 			sizeof(uint8_t) + SIR_REPLAY_CTR_LEN +
-			SIR_KCK_KEY_LEN + SIR_KCK_KEY_LEN +
-			sizeof(uint8_t) + (8 * NLMSG_HDRLEN),
+			SIR_KCK_KEY_LEN + roam_info_ptr->kek_len +
+			sizeof(uint8_t) + (8 * NLMSG_HDRLEN) +
+			fils_params_len,
 			QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH_INDEX,
 			GFP_KERNEL);
 
@@ -5444,10 +5553,29 @@ int wlan_hdd_send_roam_auth_event(struct hdd_adapter *adapter, uint8_t *bssid,
 			SIR_KCK_KEY_LEN, roam_info_ptr->kck) ||
 		    nla_put(skb,
 			QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KEK,
-			SIR_KEK_KEY_LEN, roam_info_ptr->kek)) {
+			roam_info_ptr->kek_len, roam_info_ptr->kek)) {
 			hdd_err("nla put fail");
 			goto nla_put_failure;
 		}
+
+		status = wlan_hdd_add_fils_params_roam_auth_event(skb,
+							roam_info_ptr);
+		if (status)
+			goto nla_put_failure;
+
+		/*
+		 * Save the gtk rekey parameters in HDD STA context. They will
+		 * be used next time when host enables GTK offload and goes
+		 * into power save state.
+		 */
+		wlan_hdd_save_gtk_offload_params(adapter, roam_info_ptr->kck,
+						 roam_info_ptr->kek,
+						 roam_info_ptr->kek_len,
+						 roam_info_ptr->replay_ctr,
+						 true);
+		hdd_debug("roam_info_ptr->replay_ctr 0x%llx",
+			*((uint64_t *)roam_info_ptr->replay_ctr));
+
 	} else {
 		hdd_debug("No Auth Params TLV's");
 		if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED,
@@ -15995,6 +16123,56 @@ static int wlan_hdd_add_assoc_ie(struct hdd_wext_state *wext_state,
 	return 0;
 }
 
+#ifdef WLAN_FEATURE_FILS_SK
+/**
+ * wlan_hdd_save_hlp_ie - API to save HLP IE
+ * @roam_profile: Pointer to roam profile
+ * @gen_ie: IE buffer to store
+ * @len: length of the IE buffer @gen_ie
+ * @flush: Flush the older saved HLP if any
+ *
+ * Return: None
+ */
+static void wlan_hdd_save_hlp_ie(tCsrRoamProfile *roam_profile,
+				const uint8_t *gen_ie, uint16_t len,
+				bool flush)
+{
+	uint8_t *hlp_ie = roam_profile->hlp_ie;
+
+	if (flush) {
+		roam_profile->hlp_ie_len = 0;
+		if (hlp_ie) {
+			qdf_mem_free(hlp_ie);
+			roam_profile->hlp_ie = NULL;
+		}
+	}
+
+	if ((roam_profile->hlp_ie_len +
+			len) > FILS_MAX_HLP_DATA_LEN) {
+		hdd_err("HLP len exceeds: hlp_ie_len %d len %d",
+			roam_profile->hlp_ie_len, len);
+		return;
+	}
+
+	if (!roam_profile->hlp_ie) {
+		roam_profile->hlp_ie =
+				qdf_mem_malloc(FILS_MAX_HLP_DATA_LEN);
+		hlp_ie = roam_profile->hlp_ie;
+		if (!hlp_ie) {
+			hdd_err("HLP IE mem alloc fails");
+			return;
+		}
+	}
+
+	qdf_mem_copy(hlp_ie + roam_profile->hlp_ie_len, gen_ie, len);
+	roam_profile->hlp_ie_len += len;
+}
+#else
+static inline void wlan_hdd_save_hlp_ie(tCsrRoamProfile *roam_profile,
+				const uint8_t *gen_ie, uint16_t len,
+				bool flush)
+{}
+#endif
 /**
  * wlan_hdd_cfg80211_set_ie() - set IEs
  * @adapter: Pointer to adapter
@@ -16297,6 +16475,10 @@ static int wlan_hdd_cfg80211_set_ie(struct hdd_adapter *adapter,
 				if (genie[0] == SIR_FILS_HLP_EXT_EID) {
 					hdd_debug("Set HLP EXT IE(len %d)",
 							eLen + 2);
+					wlan_hdd_save_hlp_ie(&pWextState->
+							roamProfile,
+							genie - 2, eLen + 2,
+							true);
 					status = wlan_hdd_add_assoc_ie(
 							pWextState, genie - 2,
 							eLen + 2);
@@ -16310,6 +16492,9 @@ static int wlan_hdd_cfg80211_set_ie(struct hdd_adapter *adapter,
 		case DOT11F_EID_FRAGMENT_IE:
 			{
 				hdd_debug("Set Fragment IE(len %d)", eLen + 2);
+				wlan_hdd_save_hlp_ie(&pWextState->roamProfile,
+							genie - 2, eLen + 2,
+							false);
 				status = wlan_hdd_add_assoc_ie(pWextState,
 							genie - 2, eLen + 2);
 				if (status)
@@ -18274,20 +18459,21 @@ static void hdd_fill_pmksa_info(tPmkidCacheInfo *pmk_cache,
 {
 	if (pmksa->bssid) {
 		hdd_debug("%s PMKSA for " MAC_ADDRESS_STR,
-			is_delete ? "Delete" : "Set",
-			MAC_ADDR_ARRAY(pmksa->bssid));
+			  is_delete ? "Delete" : "Set",
+			  MAC_ADDR_ARRAY(pmksa->bssid));
 		qdf_mem_copy(pmk_cache->BSSID.bytes,
-				pmksa->bssid, QDF_MAC_ADDR_SIZE);
+			     pmksa->bssid, QDF_MAC_ADDR_SIZE);
 	} else {
 		qdf_mem_copy(pmk_cache->ssid, pmksa->ssid,
-				SIR_MAC_MAX_SSID_LENGTH);
-		qdf_mem_copy(pmk_cache->cache_id,
-			pmksa->cache_id, CACHE_ID_LEN);
+			     SIR_MAC_MAX_SSID_LENGTH);
+		qdf_mem_copy(pmk_cache->cache_id, pmksa->cache_id,
+			     CACHE_ID_LEN);
 		pmk_cache->ssid_len = pmksa->ssid_len;
 		hdd_debug("%s PMKSA for ssid %*.*s cache_id %x %x",
-			is_delete ? "Delete" : "Set",
-			pmk_cache->ssid_len, pmk_cache->ssid_len,
-			pmksa->ssid, pmksa->cache_id[0], pmksa->cache_id[1]);
+			  is_delete ? "Delete" : "Set",
+			  pmk_cache->ssid_len, pmk_cache->ssid_len,
+			  pmk_cache->ssid, pmk_cache->cache_id[0],
+			  pmk_cache->cache_id[1]);
 	}
 
 	if (is_delete)
@@ -18408,6 +18594,9 @@ static int __wlan_hdd_cfg80211_set_pmksa(struct wiphy *wiphy,
 			 TRACE_CODE_HDD_CFG80211_SET_PMKSA,
 			 adapter->sessionId, result));
 
+	sme_set_del_pmkid_cache(halHandle, adapter->sessionId,
+					&pmk_cache, true);
+
 	EXIT();
 	return QDF_IS_STATUS_SUCCESS(result) ? 0 : -EINVAL;
 }
@@ -18495,6 +18684,9 @@ static int __wlan_hdd_cfg80211_del_pmksa(struct wiphy *wiphy,
 		       MAC_ADDR_ARRAY(pmksa->bssid));
 		status = -EINVAL;
 	}
+
+	sme_set_del_pmkid_cache(halHandle, adapter->sessionId, &pmk_cache,
+						false);
 	EXIT();
 	return status;
 }
@@ -18709,6 +18901,41 @@ out:
 
 }
 
+/**
+ * wlan_hdd_copy_gtk_kek - Copy the KEK from GTK rekey data to GTK request
+ * @gtk_req: Pointer to GTK request
+ * @data: Pointer to rekey data
+ *
+ * Return: none
+ */
+#ifdef CFG80211_REKEY_DATA_KEK_LEN
+static
+void wlan_hdd_copy_gtk_kek(struct pmo_gtk_req *gtk_req,
+			   struct cfg80211_gtk_rekey_data *data)
+{
+	qdf_mem_copy(gtk_req->kek, data->kek, data->kek_len);
+	gtk_req->kek_len = data->kek_len;
+}
+#else
+static
+void wlan_hdd_copy_gtk_kek(struct pmo_gtk_req *gtk_req,
+			   struct cfg80211_gtk_rekey_data *data)
+{
+	qdf_mem_copy(gtk_req->kek, data->kek, NL80211_KEK_LEN);
+	gtk_req->kek_len = NL80211_KEK_LEN;
+}
+#endif
+
+/**
+ * __wlan_hdd_cfg80211_set_rekey_data() - set rekey data
+ * @wiphy: Pointer to wiphy
+ * @dev: Pointer to network device
+ * @data: Pointer to rekey data
+ *
+ * This function is used to offload GTK rekeying job to the firmware.
+ *
+ * Return: 0 for success, non-zero for failure
+ */
 static
 int __wlan_hdd_cfg80211_set_rekey_data(struct wiphy *wiphy,
 		struct net_device *dev,
@@ -18757,7 +18984,8 @@ int __wlan_hdd_cfg80211_set_rekey_data(struct wiphy *wiphy,
 
 	hdd_debug("current replay counter: %llu in user space",
 		gtk_req->replay_counter);
-	qdf_mem_copy(gtk_req->kek, data->kek, NL80211_KEK_LEN);
+
+	wlan_hdd_copy_gtk_kek(gtk_req, data);
 	qdf_mem_copy(gtk_req->kck, data->kck, NL80211_KCK_LEN);
 	status = pmo_ucfg_cache_gtk_offload_req(adapter->hdd_vdev, gtk_req);
 	if (status != QDF_STATUS_SUCCESS) {
@@ -19524,6 +19752,169 @@ static void hdd_update_chan_info(struct hdd_context *hdd_ctx,
 #undef CNT_DIFF
 #undef MAX_COUNT
 
+#if defined(WLAN_FEATURE_FILS_SK) &&\
+	(defined(CFG80211_UPDATE_CONNECT_PARAMS) ||\
+		(LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)))
+
+#ifndef UPDATE_FILS_ERP_INFO
+#define UPDATE_FILS_ERP_INFO BIT(1)
+#endif
+
+#ifndef UPDATE_FILS_AUTH_TYPE
+#define UPDATE_FILS_AUTH_TYPE BIT(2)
+#endif
+
+/**
+ * __wlan_hdd_cfg80211_update_connect_params - update connect params
+ * @wiphy: Handle to struct wiphy to get handle to module context.
+ * @dev: Pointer to network device
+ * @req: Pointer to connect params
+ * @changed: Bitmap used to indicate the changed params
+ *
+ * Update the connect parameters while connected to a BSS. The updated
+ * parameters can be used by driver/firmware for subsequent BSS selection
+ * (roaming) decisions and to form the Authentication/(Re)Association
+ * Request frames. This call does not request an immediate disassociation
+ * or reassociation with the current BSS, i.e., this impacts only
+ * subsequent (re)associations. The bits in changed are defined in enum
+ * cfg80211_connect_params_changed
+ *
+ * Return: zero for success, non-zero for failure
+ */
+static int __wlan_hdd_cfg80211_update_connect_params(
+			struct wiphy *wiphy, struct net_device *dev,
+			struct cfg80211_connect_params *req, uint32_t changed)
+{
+	struct hdd_wext_state *wext_state;
+	tCsrRoamProfile *roam_profile;
+	uint8_t *buf;
+	int ret, auth_type;
+	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
+	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
+	QDF_STATUS status;
+	struct cds_fils_connection_info *fils_info;
+
+	ENTER_DEV(dev);
+
+	if (wlan_hdd_validate_session_id(adapter->sessionId)) {
+		hdd_err("invalid session id: %d", adapter->sessionId);
+		return -EINVAL;
+	}
+
+	ret = wlan_hdd_validate_context(hdd_ctx);
+	if (ret)
+		return -EINVAL;
+
+	wext_state = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
+	roam_profile = &wext_state->roamProfile;
+	fils_info = roam_profile->fils_con_info;
+
+	if (!fils_info) {
+		hdd_err("No valid FILS conn info");
+		return -EINVAL;
+	}
+
+	if (req->ie_len)
+		wlan_hdd_cfg80211_set_ie(adapter, req->ie, req->ie_len);
+
+	if (changed)
+		fils_info->is_fils_connection = true;
+
+	if (changed & UPDATE_FILS_ERP_INFO) {
+		if ((req->fils_erp_username_len >
+		     FILS_MAX_KEYNAME_NAI_LENGTH) ||
+		    (req->fils_erp_rrk_len > FILS_MAX_RRK_LENGTH) ||
+		    (req->fils_erp_realm_len > FILS_MAX_REALM_LEN)) {
+			hdd_err("Invalid length: username len %zd, rrk len %zd realm len %zd",
+				req->fils_erp_username_len,
+				req->fils_erp_rrk_len,
+				req->fils_erp_realm_len);
+			return -EINVAL;
+		}
+
+		fils_info->key_nai_length = req->fils_erp_username_len +
+					    sizeof(char) +
+					    req->fils_erp_realm_len;
+		if (req->fils_erp_username_len && req->fils_erp_username) {
+			buf = fils_info->keyname_nai;
+			qdf_mem_copy(buf, req->fils_erp_username,
+					req->fils_erp_username_len);
+			buf += req->fils_erp_username_len;
+			*buf++ = '@';
+			qdf_mem_copy(buf, req->fils_erp_realm,
+					req->fils_erp_realm_len);
+		}
+
+		fils_info->sequence_number = req->fils_erp_next_seq_num;
+		fils_info->r_rk_length = req->fils_erp_rrk_len;
+
+		if (req->fils_erp_rrk_len && req->fils_erp_rrk)
+			qdf_mem_copy(fils_info->r_rk, req->fils_erp_rrk,
+						fils_info->r_rk_length);
+
+		fils_info->realm_len = req->fils_erp_realm_len;
+		if (req->fils_erp_realm_len && req->fils_erp_realm)
+			qdf_mem_copy(fils_info->realm, req->fils_erp_realm,
+						fils_info->realm_len);
+	}
+
+	if (changed & UPDATE_FILS_AUTH_TYPE) {
+		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;
+	}
+
+	hdd_debug("fils conn update: changed %x is_fils %d seq=%d auth=%d user_len=%zu rrk_len=%zu realm_len=%zu keyname nai len %d",
+			changed, roam_profile->fils_con_info->
+			is_fils_connection, 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);
+
+	if (!adapter->fast_roaming_allowed) {
+		hdd_debug("LFR3 not enabled on this interface");
+		return 0;
+	}
+
+	status = sme_update_fils_config(hdd_ctx->hHal, adapter->sessionId,
+			roam_profile);
+	if (QDF_IS_STATUS_ERROR(status))
+		hdd_err("Update FILS connect params to Fw failed %d", status);
+
+	return 0;
+}
+
+/**
+ * wlan_hdd_cfg80211_update_connect_params - SSR wrapper for
+ *                __wlan_hdd_cfg80211_update_connect_params
+ * @wiphy: Pointer to wiphy structure
+ * @dev: Pointer to net_device
+ * @req: Pointer to connect params
+ * @changed: flags used to indicate the changed params
+ *
+ * Return: zero for success, non-zero for failure
+ */
+static int wlan_hdd_cfg80211_update_connect_params(struct wiphy *wiphy,
+					    struct net_device *dev,
+					    struct cfg80211_connect_params *req,
+					    uint32_t changed)
+{
+	int ret;
+
+	cds_ssr_protect(__func__);
+	ret = __wlan_hdd_cfg80211_update_connect_params(wiphy, dev,
+							req, changed);
+	cds_ssr_unprotect(__func__);
+
+	return ret;
+}
+#endif
+
 /**
  * wlan_hdd_chan_info_cb() - channel info callback
  * @chan_info: struct scan_chan_info
@@ -19744,6 +20135,7 @@ void hdd_set_rate_bw(struct rate_info *info, enum hdd_rate_info_bw hdd_bw)
  * @set_ap_chanwidth = Set AP channel bandwidth
  * @dump_survey = Dump survey
  * @key_mgmt_set_pmk = Set pmk key management
+ * @update_connect_params = Update connect params
  */
 static struct cfg80211_ops wlan_hdd_cfg80211_ops = {
 	.add_virtual_intf = wlan_hdd_add_virtual_intf,
@@ -19812,4 +20204,9 @@ static struct cfg80211_ops wlan_hdd_cfg80211_ops = {
 	defined(CFG80211_ABORT_SCAN)
 	.abort_scan = wlan_hdd_cfg80211_abort_scan,
 #endif
+#if defined(WLAN_FEATURE_FILS_SK) &&\
+	(defined(CFG80211_UPDATE_CONNECT_PARAMS) ||\
+		(LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)))
+	.update_connect_params = wlan_hdd_cfg80211_update_connect_params,
+#endif
 };

+ 19 - 0
core/hdd/src/wlan_hdd_cfg80211.h

@@ -523,4 +523,23 @@ int wlan_hdd_merge_avoid_freqs(struct ch_avoid_ind_type *destFreqList,
  * Return: none
  */
 void hdd_bt_activity_cb(void *context, uint32_t bt_activity);
+
+/**
+ * wlan_hdd_save_gtk_offload_params() - Save gtk offload parameters in STA
+ *                                      context for offload operations.
+ * @adapter: Adapter context
+ * @kck_ptr: KCK buffer pointer
+ * @kek_ptr: KEK buffer pointer
+ * @kek_len: KEK length
+ * @replay_ctr: Pointer to 64 bit long replay counter
+ * @big_endian: true if replay_ctr is in big endian format
+ *
+ * Return: None
+ */
+void wlan_hdd_save_gtk_offload_params(struct hdd_adapter *adapter,
+					     uint8_t *kck_ptr,
+					     uint8_t *kek_ptr,
+					     uint32_t kek_len,
+					     uint8_t *replay_ctr,
+					     bool big_endian);
 #endif

+ 30 - 26
core/hdd/src/wlan_hdd_main.c

@@ -4888,27 +4888,32 @@ static inline void hdd_populate_fils_params(struct cfg80211_connect_resp_params
 { }
 #endif
 
-/**
- * hdd_update_hlp_info() - Update HLP packet received in FILS assoc rsp
- * @dev: net device
- * @roam_fils_params: Fils join rsp params
- *
- * This API is used to send the received HLP packet in Assoc rsp(FILS AKM)
- * to the network layer.
- *
- * Return: None
- */
-static void hdd_update_hlp_info(struct net_device *dev,
-				struct fils_join_rsp_params *roam_fils_params)
+void hdd_update_hlp_info(struct net_device *dev, tCsrRoamInfo *roam_info)
 {
 	struct sk_buff *skb;
 	uint16_t skb_len;
 	struct llc_snap_hdr_t *llc_hdr;
 	QDF_STATUS status;
-	uint8_t *hlp_data = roam_fils_params->hlp_data;
-	uint16_t hlp_data_len = roam_fils_params->hlp_data_len;
+	uint8_t *hlp_data;
+	uint16_t hlp_data_len;
+	struct fils_join_rsp_params *roam_fils_params
+				= roam_info->fils_join_rsp;
 	struct hdd_adapter *padapter = WLAN_HDD_GET_PRIV_PTR(dev);
 
+	if (!roam_fils_params) {
+		hdd_err("FILS Roam Param NULL");
+		return;
+	}
+
+	if (!roam_fils_params->hlp_data_len || !roam_fils_params->hlp_data) {
+		hdd_err("FILS HLP Data NULL, len %d",
+			roam_fils_params->hlp_data_len);
+		return;
+	}
+
+	hlp_data = roam_fils_params->hlp_data;
+	hlp_data_len = roam_fils_params->hlp_data_len;
+
 	/* Calculate skb length */
 	skb_len = (2 * ETH_ALEN) + hlp_data_len;
 	skb = qdf_nbuf_alloc(NULL, skb_len, 0, 4, false);
@@ -4960,7 +4965,6 @@ static void hdd_update_hlp_info(struct net_device *dev,
  * @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
@@ -4972,10 +4976,12 @@ static void hdd_connect_done(struct net_device *dev, const u8 *bssid,
 			     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)
+			     tSirResultCodes timeout_reason)
 {
 	struct cfg80211_connect_resp_params fils_params;
+	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
+	struct fils_join_rsp_params *roam_fils_params =
+				roam_info->fils_join_rsp;
 
 	qdf_mem_zero(&fils_params, sizeof(fils_params));
 
@@ -4996,6 +5002,10 @@ static void hdd_connect_done(struct net_device *dev, const u8 *bssid,
 					 roam_fils_params->fils_pmk_len,
 					 roam_fils_params->fils_pmkid,
 					 roam_info->fils_seq_num);
+		wlan_hdd_save_gtk_offload_params(adapter, NULL,
+					roam_fils_params->kek,
+					roam_fils_params->kek_len,
+					roam_info->replay_ctr, true);
 	}
 	hdd_debug("FILS indicate connect status %d seq no %d",
 		  fils_params.status,
@@ -5004,7 +5014,7 @@ static void hdd_connect_done(struct net_device *dev, const u8 *bssid,
 	cfg80211_connect_done(dev, &fils_params, gfp);
 
 	if (roam_fils_params && roam_fils_params->hlp_data_len)
-		hdd_update_hlp_info(dev, roam_fils_params);
+		hdd_update_hlp_info(dev, roam_info);
 
 	/* Clear all the FILS key info */
 	if (roam_fils_params && roam_fils_params->fils_pmk)
@@ -5020,13 +5030,7 @@ hdd_connect_done(struct net_device *dev, const u8 *bssid,
 		 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)
-{ }
-
-static inline void hdd_update_hlp_info(struct net_device *dev,
-			struct fils_join_rsp_params *roam_fils_params)
-
+		 tSirResultCodes timeout_reason)
 { }
 #endif
 #endif
@@ -5067,7 +5071,7 @@ static int hdd_fils_update_connect_results(struct net_device *dev,
 
 	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);
+			 timeout_reason);
 	return 0;
 }
 #else

+ 11 - 1
core/hdd/src/wlan_hdd_power.c

@@ -718,7 +718,8 @@ static int hdd_set_grat_arp_keepalive(struct hdd_adapter *adapter)
  * This function performs the work initially trigged by a callback
  * from the IPv4 netdev notifier.  Since this means there has been a
  * change in IPv4 state for the interface, the ARP offload is
- * reconfigured.
+ * reconfigured. Also, Updates the HLP IE info with IP address info
+ * to fw if LFR3 is enabled
  *
  * Return: None
  */
@@ -727,6 +728,9 @@ static void __hdd_ipv4_notifier_work_queue(struct work_struct *work)
 	struct hdd_context *hdd_ctx;
 	struct hdd_adapter *adapter;
 	int errno;
+	struct hdd_wext_state *wext_state;
+	tCsrRoamProfile *roam_profile;
+	struct in_ifaddr *ifa;
 
 	ENTER();
 
@@ -745,6 +749,12 @@ static void __hdd_ipv4_notifier_work_queue(struct work_struct *work)
 	if (hdd_ctx->config->sta_keepalive_method == HDD_STA_KEEPALIVE_GRAT_ARP)
 		hdd_set_grat_arp_keepalive(adapter);
 
+	wext_state = WLAN_HDD_GET_WEXT_STATE_PTR(adapter);
+	roam_profile = &wext_state->roamProfile;
+	ifa = hdd_lookup_ifaddr(adapter);
+	if (ifa)
+		sme_send_hlp_ie_info(hdd_ctx->hHal, adapter->sessionId,
+				     roam_profile, ifa->ifa_local);
 exit:
 	EXIT();
 }

+ 2 - 0
core/hdd/src/wlan_hdd_wext.c

@@ -14594,6 +14594,8 @@ static int hdd_set_wext(struct hdd_adapter *adapter)
 static void hdd_initialize_fils_info(struct hdd_wext_state *pwextBuf)
 {
 	pwextBuf->roamProfile.fils_con_info = NULL;
+	pwextBuf->roamProfile.hlp_ie = NULL;
+	pwextBuf->roamProfile.hlp_ie_len = 0;
 }
 #else
 static void hdd_initialize_fils_info(struct hdd_wext_state *pwextBuf)

+ 18 - 1
core/mac/inc/sir_api.h

@@ -189,7 +189,10 @@ typedef enum {
 #define SIR_BTK_KEY_LEN 32
 #define SIR_KCK_KEY_LEN 16
 #define SIR_KEK_KEY_LEN 16
+#define SIR_KEK_KEY_LEN_FILS 64
 #define SIR_REPLAY_CTR_LEN 8
+#define SIR_PMK_LEN  48
+#define SIR_PMKID_LEN 16
 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
 #define SIR_UAPSD_BITOFFSET_ACVO     0
 #define SIR_UAPSD_BITOFFSET_ACVI     1
@@ -3276,6 +3279,10 @@ typedef struct sSirRoamOffloadScanReq {
 	tSirAddie assoc_ie;
 	struct lca_disallow_config_params lca_config_params;
 	struct scoring_param score_params;
+#ifdef WLAN_FEATURE_FILS_SK
+	bool is_fils_connection;
+	struct roam_fils_params roam_fils_params;
+#endif
 } tSirRoamOffloadScanReq, *tpSirRoamOffloadScanReq;
 
 typedef struct sSirRoamOffloadScanRsp {
@@ -4312,13 +4319,23 @@ typedef struct sSirSmeRoamOffloadSynchInd {
 	uint8_t roamReason;
 	uint32_t chan_freq;
 	uint8_t kck[SIR_KCK_KEY_LEN];
-	uint8_t kek[SIR_KEK_KEY_LEN];
+	uint32_t kek_len;
+	uint8_t kek[SIR_KEK_KEY_LEN_FILS];
+	uint32_t   pmk_len;
+	uint8_t    pmk[SIR_PMK_LEN];
+	uint8_t    pmkid[SIR_PMKID_LEN];
+	bool update_erp_next_seq_num;
+	uint16_t next_erp_seq_num;
 	uint8_t replay_ctr[SIR_REPLAY_CTR_LEN];
 	void *add_bss_params;
 	tpSirSmeJoinRsp join_rsp;
 	uint16_t aid;
 	struct sir_hw_mode_trans_ind hw_mode_trans_ind;
 	uint8_t nss;
+	struct qdf_mac_addr dst_mac;
+	struct qdf_mac_addr src_mac;
+	uint16_t hlp_data_len;
+	uint8_t hlp_data[FILS_MAX_HLP_DATA_LEN];
 } roam_offload_synch_ind;
 
 #ifdef WLAN_FEATURE_ROAM_OFFLOAD

+ 2 - 0
core/mac/src/include/sir_params.h

@@ -656,6 +656,8 @@ typedef struct sSirMbMsgP2p {
 
 #define SIR_HAL_SET_LIMIT_OFF_CHAN          (SIR_HAL_ITC_MSG_TYPES_BEGIN + 390)
 
+#define SIR_HAL_SET_DEL_PMKID_CACHE         (SIR_HAL_ITC_MSG_TYPES_BEGIN + 391)
+#define SIR_HAL_HLP_IE_INFO                 (SIR_HAL_ITC_MSG_TYPES_BEGIN + 392)
 #define SIR_HAL_MSG_TYPES_END               (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF)
 
 /* CFG message types */

+ 10 - 8
core/mac/src/pe/include/lim_fils_defs.h

@@ -109,6 +109,8 @@
 #define KDE_OUI_TYPE   "\x00\x0F\xAC"
 #define KDE_OUI_TYPE_SIZE  3
 
+#define SINGLE_ELEMENT_HASH_CNT 1
+
 /*
  * struct eap_auth_reserved: this structure defines flags format in eap packets
  * as defined in RFC 6696 5.3.1
@@ -184,10 +186,10 @@ struct fils_auth_rsp_info {
  * @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
+ * @fils_rrk: pointer to fils rRk
+ * @fils_rrk_len: fils rRk length
+ * @fils_rik: pointer to fils rIk
+ * @fils_rik_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
@@ -231,10 +233,10 @@ struct pe_fils_session {
 	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;
+	uint8_t *fils_rrk;
+	uint8_t fils_rrk_len;
+	uint8_t *fils_rik;
+	uint32_t fils_rik_len;
 	uint16_t sequence_number;
 	uint8_t fils_session[SIR_FILS_SESSION_LENGTH];
 	uint8_t fils_nonce[SIR_FILS_NONCE_LENGTH];

+ 36 - 0
core/mac/src/pe/include/lim_process_fils.h

@@ -61,6 +61,25 @@ void lim_add_fils_data_to_auth_frame(tpPESession session, uint8_t *body);
 bool lim_is_valid_fils_auth_frame(tpAniSirGlobal mac_ctx,
 	tpPESession pe_session, tSirMacAuthFrameBody *rx_auth_frm_body);
 
+/**
+ * lim_create_fils_rik()- This API create rik using rrk coming from
+ * supplicant.
+ * @rrk: input rrk
+ * @rrk_len: rrk length
+ * @rik: Created rik
+ * @rik_len: rik length to be filled
+ *
+ * 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 [email protected]
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS lim_create_fils_rik(uint8_t *rrk, uint8_t rrk_len,
+			       uint8_t *rik, uint32_t *rik_len);
+
 /**
  * lim_update_fils_config()- This API updates fils session info to csr config
  * from join request.
@@ -177,6 +196,19 @@ bool lim_verify_fils_params_assoc_rsp(tpAniSirGlobal mac_ctx,
 				      tpPESession session_entry,
 				      tpSirAssocRsp assoc_rsp,
 				      tLimMlmAssocCnf * assoc_cnf);
+
+/**
+ * lim_update_fils_rik() - API to update FILS RIK in RSO
+ * @pe_session: PE Session
+ * @req_buffer: Pointer to RSO request
+ *
+ * This API is used to calculate(if required) RIK and fill
+ * the same in RSO request to fw.
+ *
+ * Return: None
+ */
+void lim_update_fils_rik(tpPESession pe_session,
+			 tSirRoamOffloadScanReq *req_buffer);
 #else
 static inline bool lim_process_fils_auth_frame2(tpAniSirGlobal mac_ctx,
 		tpPESession pe_session, tSirMacAuthFrameBody *rx_auth_frm_body)
@@ -243,4 +275,8 @@ static inline bool lim_verify_fils_params_assoc_rsp(tpAniSirGlobal mac_ctx,
 {
 	return true;
 }
+
+static inline void lim_update_fils_rik(tpPESession pe_session,
+				       tSirRoamOffloadScanReq *req_buffer)
+{ }
 #endif

+ 4 - 0
core/mac/src/pe/include/lim_session.h

@@ -521,6 +521,10 @@ typedef struct sPESession       /* Added to Support BT-AMP */
 	bool ch_switch_in_progress;
 #ifdef WLAN_FEATURE_FILS_SK
 	struct pe_fils_session *fils_info;
+	struct qdf_mac_addr dst_mac;
+	struct qdf_mac_addr src_mac;
+	uint16_t hlp_data_len;
+	uint8_t *hlp_data;
 #endif
 	/* previous auth frame's sequence number */
 	uint16_t prev_auth_seq_num;

+ 44 - 0
core/mac/src/pe/lim/lim_api.c

@@ -2051,6 +2051,45 @@ lim_roam_fill_bss_descr(tpAniSirGlobal pMac,
 	qdf_mem_free(parsed_frm_ptr);
 	return QDF_STATUS_SUCCESS;
 }
+
+#if defined(WLAN_FEATURE_FILS_SK)
+/**
+ * lim_copy_and_free_hlp_data_from_session - Copy HLP info
+ * @session_ptr: PE session
+ * @roam_sync_ind_ptr: Roam Synch Indication pointer
+ *
+ * This API is used to copy the parsed HLP info from PE session
+ * to roam synch indication data. THe HLP info is expected to be
+ * parsed/stored in PE session already from assoc IE's received
+ * from fw as part of Roam Synch Indication.
+ *
+ * Return: None
+ */
+static void lim_copy_and_free_hlp_data_from_session(tpPESession session_ptr,
+				    roam_offload_synch_ind *roam_sync_ind_ptr)
+{
+	if (session_ptr->hlp_data && session_ptr->hlp_data_len) {
+		cds_copy_hlp_info(&session_ptr->dst_mac,
+				&session_ptr->src_mac,
+				session_ptr->hlp_data_len,
+				session_ptr->hlp_data,
+				&roam_sync_ind_ptr->dst_mac,
+				&roam_sync_ind_ptr->src_mac,
+				&roam_sync_ind_ptr->hlp_data_len,
+				roam_sync_ind_ptr->hlp_data);
+		qdf_mem_free(session_ptr->hlp_data);
+		session_ptr->hlp_data = NULL;
+		session_ptr->hlp_data_len = 0;
+	}
+}
+#else
+static inline void lim_copy_and_free_hlp_data_from_session(
+					tpPESession session_ptr,
+					roam_offload_synch_ind
+					*roam_sync_ind_ptr)
+{}
+#endif
+
 /**
  * pe_roam_synch_callback() - PE level callback for roam synch propagation
  * @mac_ctx: MAC Context
@@ -2199,8 +2238,13 @@ QDF_STATUS pe_roam_synch_callback(tpAniSirGlobal mac_ctx,
 			mac_ctx->roam.pReassocResp,
 			mac_ctx->roam.reassocRespLen);
 	ft_session_ptr->bRoamSynchInProgress = true;
+
 	lim_process_assoc_rsp_frame(mac_ctx, mac_ctx->roam.pReassocResp,
 			LIM_REASSOC, ft_session_ptr);
+
+	lim_copy_and_free_hlp_data_from_session(ft_session_ptr,
+						roam_sync_ind_ptr);
+
 	roam_sync_ind_ptr->aid = ft_session_ptr->limAID;
 	curr_sta_ds->mlmStaContext.mlmState =
 		eLIM_MLM_LINK_ESTABLISHED_STATE;

+ 103 - 50
core/mac/src/pe/lim/lim_process_fils.c

@@ -667,8 +667,8 @@ static void lim_generate_rmsk_data(tpPESession pe_session)
 		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);
+	fils_info->fils_rmsk_len = fils_info->fils_rrk_len;
+	fils_info->fils_rmsk = qdf_mem_malloc(fils_info->fils_rrk_len);
 	if (!fils_info->fils_rmsk) {
 		pe_err("failed to alloc memory");
 		return;
@@ -679,9 +679,9 @@ static void lim_generate_rmsk_data(tpPESession pe_session)
 	 * 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,
+	lim_copy_u16_be(&optional_data[2], fils_info->fils_rrk_len);
+	lim_default_hmac_sha256_kdf(fils_info->fils_rrk,
+			fils_info->fils_rrk_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,
@@ -770,8 +770,10 @@ static QDF_STATUS lim_process_auth_wrapped_data(tpPESession pe_session,
 	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,
+		qdf_get_hmac_hash(FILS_SHA256_CRYPTO_TYPE,
+				fils_info->fils_rik,
+				fils_info->fils_rik_len,
+				SINGLE_ELEMENT_HASH_CNT,
 				input_data, input_len, hash);
 	} else {
 		pe_err("invalid remaining len %d",
@@ -826,51 +828,34 @@ bool lim_is_valid_fils_auth_frame(tpAniSirGlobal mac_ctx,
 	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 [email protected]
- * @fils_info: fils session info
- *
- * Return: None
- */
-static QDF_STATUS lim_create_fils_r_ik(struct pe_fils_session *fils_info)
+QDF_STATUS lim_create_fils_rik(uint8_t *rrk, uint8_t rrk_len,
+					uint8_t *rik, uint32_t *rik_len)
 {
 	uint8_t optional_data[SIR_FILS_OPTIONAL_DATA_LEN];
 	uint8_t label[] = SIR_FILS_RIK_LABEL;
 
-	if (!fils_info)
+	if (!rrk || !rik) {
+		pe_err("FILS rrk/rik NULL");
 		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");
+	if (rrk_len <= 0) {
+		pe_err("invalid r_rk length %d", rrk_len);
 		return QDF_STATUS_E_FAILURE;
 	}
-	if (lim_default_hmac_sha256_kdf(fils_info->fils_r_rk,
-				fils_info->fils_r_rk_len, label,
+	lim_copy_u16_be(&optional_data[1], rrk_len);
+	if (lim_default_hmac_sha256_kdf(rrk, rrk_len, label,
 				optional_data, sizeof(optional_data),
-				fils_info->fils_r_ik, fils_info->fils_r_rk_len)
+				rik, rrk_len)
 			!= QDF_STATUS_SUCCESS) {
-		pe_err("failed to create r_ik");
+		pe_err("failed to create rik");
 		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);
+	*rik_len = rrk_len;
+	lim_fils_data_dump("rRk", rrk, rrk_len);
+	lim_fils_data_dump("rIk", rik, *rik_len);
 
 	return QDF_STATUS_SUCCESS;
 }
@@ -880,13 +865,14 @@ static QDF_STATUS lim_create_fils_r_ik(struct pe_fils_session *fils_info)
  * sent in auth request.
  * @fils_info: fils session info
  *
- * Return: 0 if success else error code
+ * Return: length of the created wrapped data
  */
 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;
+	QDF_STATUS status;
 	int buf_len =
 		/* code + identifier */
 		sizeof(uint8_t) * 2 +
@@ -955,12 +941,31 @@ static int lim_create_fils_wrapper_data(struct pe_fils_session *fils_info)
 	 * 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_rik = qdf_mem_malloc(fils_info->fils_rrk_len);
+	if (!fils_info->fils_rik) {
+		qdf_mem_free(fils_info->fils_erp_reauth_pkt);
+		fils_info->fils_erp_reauth_pkt = NULL;
+		pe_err("failed to alloc memory");
+		return -EINVAL;
+	}
+	status = lim_create_fils_rik(fils_info->fils_rrk,
+				     fils_info->fils_rrk_len,
+				     fils_info->fils_rik,
+				     &fils_info->fils_rik_len);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		pe_err("RIK create fails");
+		qdf_mem_free(fils_info->fils_erp_reauth_pkt);
+		qdf_mem_free(fils_info->fils_rik);
+		fils_info->fils_erp_reauth_pkt = NULL;
+		fils_info->fils_rik = NULL;
+		return -EINVAL;
+	}
+
 	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_rik, fils_info->fils_rik_len, 1,
 			&fils_info->fils_erp_reauth_pkt, &length, auth_tag);
 
 	lim_fils_data_dump("Auth tag", auth_tag,
@@ -1138,7 +1143,7 @@ void lim_update_fils_config(tpPESession session,
 		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 =
+	csr_fils_info->fils_rrk_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;
@@ -1152,16 +1157,16 @@ void lim_update_fils_config(tpPESession session,
 	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 =
+	csr_fils_info->fils_rrk =
 		qdf_mem_malloc(fils_config_info->r_rk_length);
-	if (!csr_fils_info->fils_r_rk) {
+	if (!csr_fils_info->fils_rrk) {
 		pe_err("failed to alloc memory");
 		qdf_mem_free(csr_fils_info->keyname_nai_data);
 		return;
 	}
 
 	if (fils_config_info->r_rk_length <= FILS_MAX_RRK_LENGTH)
-		qdf_mem_copy(csr_fils_info->fils_r_rk,
+		qdf_mem_copy(csr_fils_info->fils_rrk,
 				fils_config_info->r_rk,
 				fils_config_info->r_rk_length);
 
@@ -1178,7 +1183,7 @@ void lim_update_fils_config(tpPESession session,
 			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);
+			qdf_mem_free(csr_fils_info->fils_rrk);
 			pe_err("failed to alloc memory");
 			return;
 		}
@@ -1215,9 +1220,9 @@ uint32_t lim_create_fils_auth_data(tpAniSirGlobal mac_ctx,
 		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_rik) {
+		qdf_mem_free(session->fils_info->fils_rik);
+		session->fils_info->fils_rik = NULL;
 	}
 	if  (session->fils_info->fils_erp_reauth_pkt) {
 		qdf_mem_free(session->fils_info->fils_erp_reauth_pkt);
@@ -1301,7 +1306,6 @@ void populate_fils_connect_params(tpAniSirGlobal mac_ctx,
 			  fils_join_rsp->hlp_data);
 
 	pe_debug("FILS connect params copied lim");
-	pe_delete_fils_info(session);
 }
 
 /**
@@ -1409,6 +1413,11 @@ bool lim_verify_fils_params_assoc_rsp(tpAniSirGlobal mac_ctx,
 	if (!lim_is_fils_connection(session_entry))
 		return true;
 
+	if (!fils_info) {
+		pe_err("FILS Info not present");
+		goto verify_fils_params_fails;
+	}
+
 	if (!assoc_rsp->fils_session.present) {
 		pe_err("FILS IE not present");
 		goto verify_fils_params_fails;
@@ -1797,4 +1806,48 @@ QDF_STATUS aead_decrypt_assoc_rsp(tpAniSirGlobal mac_ctx,
 	(*n_frame) -= AES_BLOCK_SIZE;
 	return status;
 }
+
+void lim_update_fils_rik(tpPESession pe_session,
+			 tSirRoamOffloadScanReq *req_buffer)
+{
+	struct pe_fils_session *pe_fils_info = pe_session->fils_info;
+	struct roam_fils_params *roam_fils_params =
+		&req_buffer->roam_fils_params;
+
+	/*
+	 * If it is first connection, LIM session entries will not be
+	 * set with FILS. However in RSO, CSR filled the RRK, realm
+	 * info and is_fils_connection to true in req_buffer, RIK
+	 * can be created with RRK and send all the FILS info to fw
+	 */
+	if ((!lim_is_fils_connection(pe_session) ||
+	     !pe_fils_info) && (req_buffer->is_fils_connection)) {
+		if (roam_fils_params->rrk_length > FILS_MAX_RRK_LENGTH) {
+			pe_err("FILS rrk len(%d) max (%d)",
+					roam_fils_params->rrk_length,
+					FILS_MAX_RRK_LENGTH);
+			return;
+		}
+
+		lim_create_fils_rik(roam_fils_params->rrk,
+				    roam_fils_params->rrk_length,
+				    roam_fils_params->rik,
+				    &roam_fils_params->rik_length);
+		pe_debug("Fils created rik len %d",
+					roam_fils_params->rik_length);
+		return;
+	}
+
+	if ((pe_fils_info->fils_rik_len > FILS_MAX_RIK_LENGTH) ||
+	    !pe_fils_info->fils_rik) {
+		pe_err("Fils rik len(%d) max %d", pe_fils_info->fils_rik_len,
+				FILS_MAX_RIK_LENGTH);
+		return;
+	}
+
+	roam_fils_params->rik_length = pe_fils_info->fils_rik_len;
+	qdf_mem_copy(roam_fils_params->rik, pe_fils_info->fils_rik,
+			roam_fils_params->rik_length);
+	pe_debug("fils rik len %d", roam_fils_params->rik_length);
+}
 #endif

+ 3 - 0
core/mac/src/pe/lim/lim_process_sme_req_messages.c

@@ -3997,6 +3997,9 @@ static void __lim_process_roam_scan_offload_req(tpAniSirGlobal mac_ctx,
 	}
 	qdf_mem_free(local_ie_buf);
 
+	if (pe_session)
+		lim_update_fils_rik(pe_session, req_buffer);
+
 	wma_msg.type = WMA_ROAM_SCAN_OFFLOAD_REQ;
 	wma_msg.bodyptr = req_buffer;
 

+ 6 - 6
core/mac/src/pe/lim/lim_session.c

@@ -293,10 +293,10 @@ void pe_delete_fils_info(tpPESession session)
 		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_rrk)
+		qdf_mem_free(fils_info->fils_rrk);
+	if (fils_info->fils_rik)
+		qdf_mem_free(fils_info->fils_rik);
 	if (fils_info->fils_eap_finish_pkt)
 		qdf_mem_free(fils_info->fils_eap_finish_pkt);
 	if (fils_info->fils_rmsk)
@@ -336,8 +336,8 @@ static void pe_init_fils_info(tpPESession session)
 	}
 	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_rrk = NULL;
+	fils_info->fils_rik = NULL;
 	fils_info->fils_eap_finish_pkt = NULL;
 	fils_info->fils_rmsk = NULL;
 	fils_info->fils_pmk = NULL;

+ 9 - 1
core/sme/inc/csr_api.h

@@ -1006,6 +1006,8 @@ typedef struct tagCsrRoamProfile {
 	uint32_t dfs_regdomain;
 #ifdef WLAN_FEATURE_FILS_SK
 	bool fils_connection;
+	uint8_t *hlp_ie;
+	uint32_t hlp_ie_len;
 	struct cds_fils_connection_info *fils_con_info;
 #endif
 } tCsrRoamProfile;
@@ -1453,7 +1455,13 @@ typedef struct tagCsrRoamInfo {
 	uint8_t roamSynchInProgress;
 	uint8_t synchAuthStatus;
 	uint8_t kck[SIR_KCK_KEY_LEN];
-	uint8_t kek[SIR_KEK_KEY_LEN];
+	uint8_t kek[SIR_KEK_KEY_LEN_FILS];
+	uint8_t kek_len;
+	uint32_t pmk_len;
+	uint8_t pmk[SIR_PMK_LEN];
+	uint8_t pmkid[SIR_PMKID_LEN];
+	bool update_erp_next_seq_num;
+	uint16_t next_erp_seq_num;
 	uint8_t replay_ctr[SIR_REPLAY_CTR_LEN];
 	uint8_t subnet_change_status;
 #endif

+ 7 - 1
core/sme/inc/csr_internal.h

@@ -820,7 +820,13 @@ struct csr_roam_offload_synch_params {
 	struct qdf_mac_addr bssid;      /* MAC address of roamed AP */
 	enum csr_roamoffload_authstatus authStatus;   /* auth status */
 	uint8_t kck[SIR_KCK_KEY_LEN];
-	uint8_t kek[SIR_KEK_KEY_LEN];
+	uint8_t kek[SIR_KEK_KEY_LEN_FILS];
+	uint32_t kek_len;
+	uint32_t pmk_len;
+	uint8_t pmk[SIR_PMK_LEN];
+	uint8_t pmkid[SIR_PMKID_LEN];
+	bool update_erp_next_seq_num;
+	uint16_t next_erp_seq_num;
 	uint8_t replay_ctr[SIR_REPLAY_CTR_LEN];
 	tpSirBssDescription  bss_desc_ptr;      /*BSS descriptor*/
 };

+ 17 - 0
core/sme/inc/csr_neighbor_roam.h

@@ -331,6 +331,7 @@ void csr_roam_reset_roam_params(tpAniSirGlobal mac_ptr);
 #define REASON_ROAM_STOP_ALL                        38
 #define REASON_SUPPLICANT_DISABLED_ROAMING          39
 #define REASON_CTX_INIT                             40
+#define REASON_FILS_PARAMS_CHANGED                  41
 
 #if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD)
 QDF_STATUS csr_roam_offload_scan(tpAniSirGlobal pMac, uint8_t sessionId,
@@ -342,6 +343,22 @@ static inline QDF_STATUS csr_roam_offload_scan(tpAniSirGlobal pMac,
 	return QDF_STATUS_E_NOSUPPORT;
 }
 #endif
+
+#if defined(WLAN_FEATURE_FILS_SK)
+/**
+ * csr_update_fils_config - Update FILS config to CSR roam session
+ * @mac: MAC context
+ * @session_id: session id
+ * @src_profile: Source profile having latest FILS config
+ *
+ * API to update FILS config to roam csr session
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS csr_update_fils_config(tpAniSirGlobal mac, uint8_t session_id,
+				  tCsrRoamProfile *src_profile);
+#endif
+
 QDF_STATUS csr_neighbor_roam_handoff_req_hdlr(tpAniSirGlobal pMac, void *pMsg);
 QDF_STATUS csr_neighbor_roam_proceed_with_handoff_req(tpAniSirGlobal pMac,
 		uint8_t sessionId);

+ 62 - 1
core/sme/inc/sme_api.h

@@ -346,7 +346,6 @@ QDF_STATUS sme_roam_set_pmkid_cache(tHalHandle hHal, uint8_t sessionId,
 		tPmkidCacheInfo *pPMKIDCache,
 		uint32_t numItems,
 		bool update_entire_cache);
-
 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
 QDF_STATUS sme_roam_set_psk_pmk(tHalHandle hHal, uint8_t sessionId,
 		uint8_t *pPSK_PMK, size_t pmk_len);
@@ -1795,4 +1794,66 @@ QDF_STATUS sme_send_limit_off_channel_params(tHalHandle hal, uint8_t vdev_id,
  */
 QDF_STATUS sme_set_vc_mode_config(uint32_t vc_bitmap);
 
+/**
+ * sme_set_del_pmkid_cache() - API to update PMKID cache
+ * @hal: HAL handle for device
+ * @session_id: Session id
+ * @pmk_cache_info: Pointer to PMK cache info
+ * @is_add: boolean that implies whether to add or delete PMKID entry
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS sme_set_del_pmkid_cache(tHalHandle hal, uint8_t session_id,
+				   tPmkidCacheInfo *pmk_cache_info,
+				   bool is_add);
+
+/**
+ * sme_send_hlp_ie_info() - API to send HLP IE info to fw
+ * @hal: HAL handle for device
+ * @session_id: Session id
+ * @profile: CSR Roam profile
+ * @if_addr: IP address
+ *
+ * This API is used to send HLP IE info along with IP address
+ * to fw if LFR3 is enabled.
+ *
+ * Return: QDF_STATUS
+ */
+void sme_send_hlp_ie_info(tHalHandle hal, uint8_t session_id,
+			  tCsrRoamProfile *profile, uint32_t if_addr);
+
+#if defined(WLAN_FEATURE_FILS_SK)
+/**
+ * sme_update_fils_config - Update FILS config to CSR roam session
+ * @hal: HAL handle for device
+ * @session_id: session id
+ * @src_profile: Source profile having latest FILS config
+ *
+ * API to update FILS config to roam csr session and update the same
+ * to fw if LFR3 is enabled.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS sme_update_fils_config(tHalHandle hal, uint8_t session_id,
+				tCsrRoamProfile *src_profile);
+
+/**
+ * sme_free_join_rsp_fils_params - free fils params
+ * @roam_info: roam info
+ *
+ * Return: void
+ */
+void sme_free_join_rsp_fils_params(tCsrRoamInfo *roam_info);
+#else
+static inline QDF_STATUS sme_update_fils_config(tHalHandle hal,
+				uint8_t session_id,
+				tCsrRoamProfile *src_profile)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline void sme_free_join_rsp_fils_params(tCsrRoamInfo *roam_info)
+{}
+
+#endif
 #endif /* #if !defined( __SME_API_H ) */

+ 193 - 0
core/sme/src/common/sme_api.c

@@ -7134,6 +7134,144 @@ QDF_STATUS sme_update_roam_rssi_diff(tHalHandle hHal, uint8_t sessionId,
 	return status;
 }
 
+#ifdef WLAN_FEATURE_FILS_SK
+QDF_STATUS sme_update_fils_config(tHalHandle hal, uint8_t session_id,
+				  tCsrRoamProfile *src_profile)
+{
+	tpAniSirGlobal mac = PMAC_STRUCT(hal);
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	tpCsrNeighborRoamControlInfo neighbor_roam_info =
+			&mac->roam.neighborRoamInfo[session_id];
+
+	if (session_id >= CSR_ROAM_SESSION_MAX) {
+		sme_err("Invalid sme session id: %d", session_id);
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (!src_profile) {
+		sme_err("src roam profile NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (!mac->roam.configParam.isFastRoamIniFeatureEnabled ||
+	    (neighbor_roam_info->neighborRoamState !=
+	     eCSR_NEIGHBOR_ROAM_STATE_CONNECTED)) {
+		sme_info("Fast roam is disabled or not connected(%d)",
+				neighbor_roam_info->neighborRoamState);
+		return QDF_STATUS_E_PERM;
+	}
+
+	csr_update_fils_config(mac, session_id, src_profile);
+	if (mac->roam.configParam.isRoamOffloadEnabled) {
+		sme_debug("Updating fils config to fw");
+		csr_roam_offload_scan(mac, session_id,
+				      ROAM_SCAN_OFFLOAD_UPDATE_CFG,
+				      REASON_FILS_PARAMS_CHANGED);
+	} else {
+		sme_info("LFR3 not enabled");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	return status;
+}
+
+void sme_send_hlp_ie_info(tHalHandle hal, uint8_t session_id,
+			  tCsrRoamProfile *profile, uint32_t if_addr)
+{
+	int i;
+	struct scheduler_msg msg;
+	QDF_STATUS status;
+	struct hlp_params *params;
+	tpAniSirGlobal mac = PMAC_STRUCT(hal);
+	struct csr_roam_session *session = CSR_GET_SESSION(mac, session_id);
+	tpCsrNeighborRoamControlInfo neighbor_roam_info =
+				&mac->roam.neighborRoamInfo[session_id];
+
+	if (!session) {
+		sme_err("session NULL");
+		return;
+	}
+
+	if (!mac->roam.configParam.isFastRoamIniFeatureEnabled ||
+	    (neighbor_roam_info->neighborRoamState !=
+	     eCSR_NEIGHBOR_ROAM_STATE_CONNECTED)) {
+		sme_debug("Fast roam is disabled or not connected(%d)",
+				neighbor_roam_info->neighborRoamState);
+		return;
+	}
+
+	params = qdf_mem_malloc(sizeof(*params));
+	if (!params) {
+		sme_err("Mem alloc for HLP IE fails");
+		return;
+	}
+	if ((profile->hlp_ie_len +
+	     SIR_IPV4_ADDR_LEN) > FILS_MAX_HLP_DATA_LEN) {
+		sme_err("HLP IE len exceeds %d",
+				profile->hlp_ie_len);
+		qdf_mem_free(params);
+		return;
+	}
+
+	params->vdev_id = session_id;
+	params->hlp_ie_len = profile->hlp_ie_len + SIR_IPV4_ADDR_LEN;
+
+	for (i = 0; i < SIR_IPV4_ADDR_LEN; i++)
+		params->hlp_ie[i] = (if_addr >> (i * 8)) & 0xFF;
+
+	qdf_mem_copy(params->hlp_ie + SIR_IPV4_ADDR_LEN,
+		     profile->hlp_ie, profile->hlp_ie_len);
+
+	msg.type = SIR_HAL_HLP_IE_INFO;
+	msg.reserved = 0;
+	msg.bodyptr = params;
+	status = sme_acquire_global_lock(&mac->sme);
+	if (status != QDF_STATUS_SUCCESS) {
+		sme_err("sme lock acquire fails");
+		qdf_mem_free(params);
+		return;
+	}
+
+	if (!QDF_IS_STATUS_SUCCESS
+			(scheduler_post_msg(QDF_MODULE_ID_WMA, &msg))) {
+		sme_err("Not able to post WMA_HLP_IE_INFO message to HAL");
+		sme_release_global_lock(&mac->sme);
+		qdf_mem_free(params);
+		return;
+	}
+
+	sme_release_global_lock(&mac->sme);
+}
+
+void sme_free_join_rsp_fils_params(tCsrRoamInfo *roam_info)
+{
+	struct fils_join_rsp_params *roam_fils_params;
+
+	if (!roam_info) {
+		sme_err("FILS Roam Info NULL");
+		return;
+	}
+
+	roam_fils_params = roam_info->fils_join_rsp;
+	if (!roam_fils_params) {
+		sme_err("FILS Roam Param NULL");
+		return;
+	}
+
+	if (roam_fils_params->fils_pmk)
+		qdf_mem_free(roam_fils_params->fils_pmk);
+
+	qdf_mem_free(roam_fils_params);
+
+	roam_info->fils_join_rsp = NULL;
+}
+
+#else
+inline void sme_send_hlp_ie_info(tHalHandle hal, uint8_t session_id,
+			  tCsrRoamProfile *profile, uint32_t if_addr)
+{}
+#endif
+
 /*
  * sme_update_fast_transition_enabled() - enable/disable Fast Transition
  *	support at runtime
@@ -15427,6 +15565,61 @@ QDF_STATUS sme_fast_reassoc(tHalHandle hal, tCsrRoamProfile *profile,
 	return status;
 }
 
+QDF_STATUS sme_set_del_pmkid_cache(tHalHandle hal, uint8_t session_id,
+				   tPmkidCacheInfo *pmk_cache_info,
+				   bool is_add)
+{
+	struct wmi_unified_pmk_cache *pmk_cache;
+	struct scheduler_msg msg;
+
+	pmk_cache = qdf_mem_malloc(sizeof(*pmk_cache));
+	if (!pmk_cache) {
+		sme_err("Memory allocation failure");
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	pmk_cache->session_id = session_id;
+
+	if (!pmk_cache_info->ssid_len) {
+		pmk_cache->cat_flag = WMI_PMK_CACHE_CAT_FLAG_BSSID;
+		WMI_CHAR_ARRAY_TO_MAC_ADDR(pmk_cache_info->BSSID.bytes,
+				&pmk_cache->bssid);
+	} else {
+		pmk_cache->cat_flag = WMI_PMK_CACHE_CAT_FLAG_SSID_CACHE_ID;
+		pmk_cache->ssid.length = pmk_cache_info->ssid_len;
+		qdf_mem_copy(pmk_cache->ssid.mac_ssid,
+			     pmk_cache_info->ssid,
+			     pmk_cache->ssid.length);
+	}
+	pmk_cache->cache_id = (uint32_t) (pmk_cache_info->cache_id[0] << 8 |
+					pmk_cache_info->cache_id[1]);
+
+	if (is_add)
+		pmk_cache->action_flag = WMI_PMK_CACHE_ACTION_FLAG_ADD_ENTRY;
+	else
+		pmk_cache->action_flag = WMI_PMK_CACHE_ACTION_FLAG_DEL_ENTRY;
+
+	pmk_cache->pmkid_len = CSR_RSN_PMKID_SIZE;
+	qdf_mem_copy(pmk_cache->pmkid, pmk_cache_info->PMKID,
+		     CSR_RSN_PMKID_SIZE);
+
+	pmk_cache->pmk_len = pmk_cache_info->pmk_len;
+	qdf_mem_copy(pmk_cache->pmk, pmk_cache_info->pmk,
+		     pmk_cache->pmk_len);
+
+	msg.type = SIR_HAL_SET_DEL_PMKID_CACHE;
+	msg.reserved = 0;
+	msg.bodyptr = pmk_cache;
+	if (QDF_STATUS_SUCCESS !=
+	    scheduler_post_msg(QDF_MODULE_ID_WMA, &msg)) {
+		sme_err("Not able to post message to WDA");
+		qdf_mem_free(pmk_cache);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
 /* ARP DEBUG STATS */
 
 /**

+ 184 - 15
core/sme/src/csr/csr_api_roam.c

@@ -3922,6 +3922,7 @@ QDF_STATUS csr_roam_call_callback(tpAniSirGlobal pMac, uint32_t sessionId,
 				EVENT_WLAN_STATUS_V2);
 	}
 #endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */
+
 	return status;
 }
 
@@ -7548,6 +7549,7 @@ static void csr_roam_process_join_res(tpAniSirGlobal mac_ctx,
 #endif
 		csr_roam_link_up(mac_ctx, conn_profile->bssid);
 	}
+	sme_free_join_rsp_fils_params(&roam_info);
 }
 
 /**
@@ -7735,23 +7737,38 @@ static bool csr_roam_process_results(tpAniSirGlobal mac_ctx, tSmeCmd *cmd,
  *
  * Return: None
  */
-static inline void update_profile_fils_info(tCsrRoamProfile *des_profile,
+static void update_profile_fils_info(tCsrRoamProfile *des_profile,
 					tCsrRoamProfile *src_profile)
 {
-	if (!src_profile->fils_con_info)
+	if (!src_profile || !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));
+	sme_debug("is fils %d", src_profile->fils_con_info->is_fils_connection);
+
+	if (!src_profile->fils_con_info->is_fils_connection)
+		return;
+
+	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));
+
+	des_profile->hlp_ie =
+		qdf_mem_malloc(src_profile->hlp_ie_len);
+	if (!des_profile->hlp_ie) {
+		sme_err("failed to allocate memory for hlp ie");
+		return;
+	}
+
+	qdf_mem_copy(des_profile->hlp_ie, src_profile->hlp_ie,
+		     src_profile->hlp_ie_len);
+	des_profile->hlp_ie_len = src_profile->hlp_ie_len;
 }
 #else
 static inline void update_profile_fils_info(tCsrRoamProfile *des_profile,
@@ -10693,18 +10710,25 @@ 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 *hash;
 	uint8_t *data[1];
 
 	if (!fils_con_info->realm_len)
 		return false;
 
+	hash = qdf_mem_malloc(SHA256_DIGEST_SIZE);
+	if (!hash) {
+		sme_err("malloc fails in fils realm");
+		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);
+	qdf_mem_free(hash);
 	return true;
 }
 
@@ -18393,6 +18417,106 @@ csr_roam_offload_per_scan(tpAniSirGlobal mac_ctx, uint8_t session_id)
 	return QDF_STATUS_SUCCESS;
 }
 
+#if defined(WLAN_FEATURE_FILS_SK)
+QDF_STATUS csr_update_fils_config(tpAniSirGlobal mac, uint8_t session_id,
+				  tCsrRoamProfile *src_profile)
+{
+	struct csr_roam_session *session = CSR_GET_SESSION(mac, session_id);
+	tCsrRoamProfile *dst_profile = NULL;
+
+	if (!session) {
+		sme_err("session NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	dst_profile = session->pCurRoamProfile;
+
+	if (!dst_profile) {
+		sme_err("Current Roam profile of SME session NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+	update_profile_fils_info(dst_profile, src_profile);
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * copy_all_before_char() - API to copy all character before a particular char
+ * @str: Source string
+ * @dst: Destination string
+ * @c: Character before which all characters need to be copied
+ *
+ * Return: length of the copied string, if success. zero otherwise.
+ */
+static uint32_t copy_all_before_char(char *str, char *dst, char c)
+{
+	uint32_t len = 0;
+
+	if (!str)
+		return len;
+
+	while (*str != '\0' && *str != c) {
+		*dst++ = *str++;
+		len++;
+	}
+	return len;
+}
+
+/**
+ * csr_update_fils_params_rso() - API to update FILS params in RSO
+ * @mac: Mac context
+ * @session: CSR Roam Session
+ * @req_buffer: RSO request buffer
+ *
+ * Return: None
+ */
+static void csr_update_fils_params_rso(tpAniSirGlobal mac,
+		struct csr_roam_session *session,
+		tSirRoamOffloadScanReq *req_buffer)
+{
+	struct roam_fils_params *roam_fils_params;
+	struct cds_fils_connection_info *fils_info;
+
+	if (!session->pCurRoamProfile)
+		return;
+
+	fils_info = session->pCurRoamProfile->fils_con_info;
+	if (!fils_info || !req_buffer)
+		return;
+
+	roam_fils_params = &req_buffer->roam_fils_params;
+	if ((fils_info->key_nai_length > FILS_MAX_KEYNAME_NAI_LENGTH) ||
+			(fils_info->r_rk_length > FILS_MAX_RRK_LENGTH)) {
+		sme_err("Fils info len error: keyname nai len(%d) rrk len(%d)",
+			fils_info->key_nai_length, fils_info->r_rk_length);
+		return;
+	}
+
+	req_buffer->is_fils_connection = true;
+	roam_fils_params->username_length =
+			copy_all_before_char(fils_info->keyname_nai,
+				roam_fils_params->username, '@');
+
+	roam_fils_params->next_erp_seq_num =
+			(fils_info->sequence_number + 1);
+
+	roam_fils_params->rrk_length = fils_info->r_rk_length;
+	qdf_mem_copy(roam_fils_params->rrk, fils_info->r_rk,
+			roam_fils_params->rrk_length);
+
+	/* REALM info */
+	roam_fils_params->realm_len = fils_info->key_nai_length
+			- roam_fils_params->username_length - 1;
+	qdf_mem_copy(roam_fils_params->realm, fils_info->keyname_nai
+			+ roam_fils_params->username_length + 1,
+			roam_fils_params->realm_len);
+}
+#else
+static inline void csr_update_fils_params_rso(tpAniSirGlobal mac,
+		struct csr_roam_session *session,
+		tSirRoamOffloadScanReq *req_buffer)
+{}
+#endif
+
 /**
  * csr_update_score_params() - API to update Score params in RSO
  * @mac_ctx: Mac context
@@ -18687,6 +18811,7 @@ csr_roam_offload_scan(tpAniSirGlobal mac_ctx, uint8_t session_id,
 				session->nAddIEAssocLength);
 		csr_update_driver_assoc_ies(mac_ctx, session, req_buf);
 		csr_update_score_params(mac_ctx, req_buf);
+		csr_update_fils_params_rso(mac_ctx, session, req_buf);
 	}
 
 	QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG,
@@ -20515,6 +20640,34 @@ void csr_roam_fill_tdls_info(tpAniSirGlobal mac_ctx, tCsrRoamInfo *roam_info,
 }
 #endif
 
+#if defined(WLAN_FEATURE_FILS_SK)
+static void csr_copy_fils_join_rsp_roam_info(tCsrRoamInfo *roam_info,
+				      roam_offload_synch_ind *roam_synch_data)
+{
+	struct fils_join_rsp_params *roam_fils_info;
+
+	roam_info->fils_join_rsp = qdf_mem_malloc(sizeof(*roam_fils_info));
+	if (!roam_info->fils_join_rsp) {
+		sme_err("fils_join_rsp malloc fails!");
+		return;
+	}
+
+	roam_fils_info = roam_info->fils_join_rsp;
+	cds_copy_hlp_info(&roam_synch_data->dst_mac,
+			&roam_synch_data->src_mac,
+			roam_synch_data->hlp_data_len,
+			roam_synch_data->hlp_data,
+			&roam_fils_info->dst_mac,
+			&roam_fils_info->src_mac,
+			&roam_fils_info->hlp_data_len,
+			roam_fils_info->hlp_data);
+}
+#else
+static inline void csr_copy_fils_join_rsp_roam_info(tCsrRoamInfo *roam_info,
+				      roam_offload_synch_ind *roam_synch_data)
+{}
+#endif
+
 #ifdef WLAN_FEATURE_ROAM_OFFLOAD
 static QDF_STATUS csr_process_roam_sync_callback(tpAniSirGlobal mac_ctx,
 		roam_offload_synch_ind *roam_synch_data,
@@ -20823,14 +20976,29 @@ static QDF_STATUS csr_process_roam_sync_callback(tpAniSirGlobal mac_ctx,
 	}
 	roam_info->roamSynchInProgress = true;
 	roam_info->synchAuthStatus = roam_synch_data->authStatus;
+	roam_info->kek_len = roam_synch_data->kek_len;
+	roam_info->pmk_len = roam_synch_data->pmk_len;
 	qdf_mem_copy(roam_info->kck, roam_synch_data->kck, SIR_KCK_KEY_LEN);
-	qdf_mem_copy(roam_info->kek, roam_synch_data->kek, SIR_KEK_KEY_LEN);
+	qdf_mem_copy(roam_info->kek, roam_synch_data->kek, roam_info->kek_len);
+
+	if (roam_synch_data->pmk_len)
+		qdf_mem_copy(roam_info->pmk, roam_synch_data->pmk,
+			     roam_synch_data->pmk_len);
+
+	qdf_mem_copy(roam_info->pmkid, roam_synch_data->pmkid, SIR_PMKID_LEN);
+	roam_info->update_erp_next_seq_num =
+			roam_synch_data->update_erp_next_seq_num;
+	roam_info->next_erp_seq_num = roam_synch_data->next_erp_seq_num;
 	qdf_mem_copy(roam_info->replay_ctr, roam_synch_data->replay_ctr,
 			SIR_REPLAY_CTR_LEN);
 	QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG,
-		FL("LFR3: Copy KCK, KEK and Replay Ctr"));
+		FL("LFR3: Copy KCK, KEK(len %d) and Replay Ctr"),
+		roam_info->kek_len);
 	roam_info->subnet_change_status =
 		CSR_GET_SUBNET_STATUS(roam_synch_data->roamReason);
+
+	csr_copy_fils_join_rsp_roam_info(roam_info, roam_synch_data);
+
 	csr_roam_call_callback(mac_ctx, session_id, roam_info, 0,
 		eCSR_ROAM_ASSOCIATION_COMPLETION, eCSR_ROAM_RESULT_ASSOCIATED);
 	csr_reset_pmkid_candidate_list(mac_ctx, session_id);
@@ -20847,6 +21015,7 @@ static QDF_STATUS csr_process_roam_sync_callback(tpAniSirGlobal mac_ctx,
 
 	session->fRoaming = false;
 	session->roam_synch_in_progress = false;
+	sme_free_join_rsp_fils_params(roam_info);
 	qdf_mem_free(roam_info->pbFrames);
 	qdf_mem_free(roam_info);
 	qdf_mem_free(ies_local);

+ 6 - 0
core/sme/src/csr/csr_util.c

@@ -6056,6 +6056,12 @@ static inline void csr_free_fils_profile_info(tCsrRoamProfile *profile)
 		qdf_mem_free(profile->fils_con_info);
 		profile->fils_con_info = NULL;
 	}
+
+	if (profile->hlp_ie) {
+		qdf_mem_free(profile->hlp_ie);
+		profile->hlp_ie = NULL;
+		profile->hlp_ie_len = 0;
+	}
 }
 #else
 static inline void csr_free_fils_profile_info(tCsrRoamProfile *profile)

+ 74 - 0
core/wma/src/wma_main.c

@@ -6832,6 +6832,30 @@ static void wma_get_arp_req_stats(WMA_HANDLE handle,
 			 __func__);
 }
 
+/**
+ * wma_set_del_pmkid_cache() - API to set/delete PMKID cache entry in fw
+ * @handle: WMA handle
+ * @pmk_cache: PMK cache entry
+ *
+ * Return: None
+ */
+static void wma_set_del_pmkid_cache(WMA_HANDLE handle,
+				    struct wmi_unified_pmk_cache *pmk_cache)
+{
+	int status;
+	tp_wma_handle wma_handle = (tp_wma_handle) handle;
+
+	if (!wma_handle || !wma_handle->wmi_handle) {
+		WMA_LOGE("WMA is closed, cannot send set del pmkid");
+		return;
+	}
+
+	status = wmi_unified_set_del_pmkid_cache(wma_handle->wmi_handle,
+						 pmk_cache);
+	if (status != EOK)
+		WMA_LOGE("failed to send set/del pmkid cmd to fw");
+}
+
 QDF_STATUS wma_set_rx_reorder_timeout_val(tp_wma_handle wma_handle,
 	struct sir_set_rx_reorder_timeout_val *reorder_timeout)
 {
@@ -6974,6 +6998,46 @@ QDF_STATUS wma_get_chain_rssi(tp_wma_handle wma_handle,
 	return QDF_STATUS_SUCCESS;
 }
 
+#if defined(WLAN_FEATURE_FILS_SK)
+/**
+ * wma_roam_scan_send_hlp() - API to send HLP IE info to fw
+ * @wma_handle: WMA handle
+ * @req: HLP params
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS wma_roam_scan_send_hlp(tp_wma_handle wma_handle,
+					 struct hlp_params *req)
+{
+	struct hlp_params *params;
+	QDF_STATUS status;
+
+	params = qdf_mem_malloc(sizeof(*params));
+	if (!params) {
+		WMA_LOGE("%s : Memory allocation failed", __func__);
+		return QDF_STATUS_E_NOMEM;
+	}
+
+	params->vdev_id = req->vdev_id;
+	params->hlp_ie_len = req->hlp_ie_len;
+	qdf_mem_copy(params->hlp_ie, req->hlp_ie, req->hlp_ie_len);
+	status = wmi_unified_roam_send_hlp_cmd(wma_handle->wmi_handle, params);
+
+	WMA_LOGD("Send HLP status %d vdev id %d", status, params->vdev_id);
+	qdf_trace_hex_dump(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_DEBUG,
+				params->hlp_ie, 10);
+
+	qdf_mem_free(params);
+	return status;
+}
+#else
+static QDF_STATUS wma_roam_scan_send_hlp(tp_wma_handle wma_handle,
+					 struct hlp_params *req)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
 /**
  * wma_process_set_limit_off_chan() - set limit off chanel parameters
  * @wma_handle: pointer to wma handle
@@ -7790,6 +7854,16 @@ static QDF_STATUS wma_mc_process_msg(struct scheduler_msg *msg)
 			(struct get_arp_stats_params *)msg->bodyptr);
 		qdf_mem_free(msg->bodyptr);
 		break;
+	case SIR_HAL_SET_DEL_PMKID_CACHE:
+		wma_set_del_pmkid_cache(wma_handle,
+			(struct wmi_unified_pmk_cache *) msg->bodyptr);
+		qdf_mem_free(msg->bodyptr);
+		break;
+	case SIR_HAL_HLP_IE_INFO:
+		wma_roam_scan_send_hlp(wma_handle,
+			(struct hlp_params *)msg->bodyptr);
+		qdf_mem_free(msg->bodyptr);
+		break;
 	case WMA_SET_LIMIT_OFF_CHAN:
 		wma_process_limit_off_chan(wma_handle, msg->bodyptr);
 		qdf_mem_free(msg->bodyptr);

+ 89 - 0
core/wma/src/wma_scan_roam.c

@@ -771,6 +771,57 @@ QDF_STATUS wma_roam_scan_mawc_params(tp_wma_handle wma_handle,
 
 	return status;
 }
+#ifdef WLAN_FEATURE_FILS_SK
+/**
+ * wma_roam_scan_fill_fils_params() - API to fill FILS params in RSO command
+ * @wma_handle: WMA handle
+ * @params: Pointer to destination RSO params to be filled
+ * @roam_req: Pointer to RSO params from CSR
+ *
+ * Return: None
+ */
+static void wma_roam_scan_fill_fils_params(tp_wma_handle wma_handle,
+					   struct roam_offload_scan_params
+					   *params, tSirRoamOffloadScanReq
+					   *roam_req)
+{
+	struct roam_fils_params *dst_fils_params, *src_fils_params;
+
+	if (!params || !roam_req || !roam_req->is_fils_connection) {
+		WMA_LOGE("wma_roam_scan_fill_fils_params- NULL");
+		return;
+	}
+
+	src_fils_params = &roam_req->roam_fils_params;
+	dst_fils_params = &params->roam_fils_params;
+
+	params->add_fils_tlv = true;
+
+	dst_fils_params->username_length = src_fils_params->username_length;
+	qdf_mem_copy(dst_fils_params->username, src_fils_params->username,
+		     dst_fils_params->username_length);
+
+	dst_fils_params->next_erp_seq_num = src_fils_params->next_erp_seq_num;
+	dst_fils_params->rrk_length = src_fils_params->rrk_length;
+	qdf_mem_copy(dst_fils_params->rrk, src_fils_params->rrk,
+		     dst_fils_params->rrk_length);
+
+	dst_fils_params->rik_length = src_fils_params->rik_length;
+	qdf_mem_copy(dst_fils_params->rik, src_fils_params->rik,
+		     dst_fils_params->rik_length);
+
+	dst_fils_params->realm_len = src_fils_params->realm_len;
+	qdf_mem_copy(dst_fils_params->realm, src_fils_params->realm,
+		     dst_fils_params->realm_len);
+}
+#else
+static inline void wma_roam_scan_fill_fils_params(
+					tp_wma_handle wma_handle,
+					struct roam_offload_scan_params *params,
+					tSirRoamOffloadScanReq *roam_req)
+
+{ }
+#endif
 
 /**
  * wma_roam_scan_offload_mode() - send roam scan mode request to fw
@@ -841,6 +892,8 @@ QDF_STATUS wma_roam_scan_offload_mode(tp_wma_handle wma_handle,
 		params->assoc_ie_length = roam_req->assoc_ie.length;
 		qdf_mem_copy(params->assoc_ie, roam_req->assoc_ie.addIEdata,
 						roam_req->assoc_ie.length);
+
+		wma_roam_scan_fill_fils_params(wma_handle, params, roam_req);
 	}
 
 	WMA_LOGD(FL("qos_caps: %d, qos_enabled: %d, roam_scan_mode: %d"),
@@ -1145,6 +1198,10 @@ A_UINT32 e_csr_auth_type_to_rsn_authmode(eCsrAuthType authtype,
 			return WMI_AUTH_OPEN;
 		}
 		return WMI_AUTH_NONE;
+	case eCSR_AUTH_TYPE_FILS_SHA256:
+		return WMI_AUTH_RSNA_FILS_SHA256;
+	case eCSR_AUTH_TYPE_FILS_SHA384:
+		return WMI_AUTH_RSNA_FILS_SHA384;
 	default:
 		return WMI_AUTH_NONE;
 	}
@@ -2060,6 +2117,7 @@ QDF_STATUS wma_process_roaming_config(tp_wma_handle wma_handle,
 					     roam_req->sessionId);
 		if (qdf_status != QDF_STATUS_SUCCESS)
 			break;
+
 		qdf_status = wma_roam_scan_filter(wma_handle, roam_req);
 		if (qdf_status != QDF_STATUS_SUCCESS) {
 			WMA_LOGE("Sending update for roam scan filter failed");
@@ -2239,6 +2297,7 @@ static int wma_fill_roam_synch_buffer(tp_wma_handle wma,
 	uint8_t *reassoc_req_ptr;
 	wmi_channel *chan;
 	wmi_key_material *key;
+	wmi_roam_fils_synch_tlv_param *fils_info;
 
 	synch_event = param_buf->fixed_param;
 	roam_synch_ind_ptr->roamedVdevId = synch_event->vdev_id;
@@ -2296,6 +2355,7 @@ static int wma_fill_roam_synch_buffer(tp_wma_handle wma,
 	if (key != NULL) {
 		qdf_mem_copy(roam_synch_ind_ptr->kck, key->kck,
 			     SIR_KCK_KEY_LEN);
+		roam_synch_ind_ptr->kek_len = SIR_KEK_KEY_LEN;
 		qdf_mem_copy(roam_synch_ind_ptr->kek, key->kek,
 			     SIR_KEK_KEY_LEN);
 		qdf_mem_copy(roam_synch_ind_ptr->replay_ctr,
@@ -2318,6 +2378,35 @@ static int wma_fill_roam_synch_buffer(tp_wma_handle wma,
 	else
 		WMA_LOGD(FL("hw_mode transition fixed param is NULL"));
 
+	fils_info = (wmi_roam_fils_synch_tlv_param *)
+			(param_buf->roam_fils_synch_info);
+	if (param_buf->roam_fils_synch_info) {
+		roam_synch_ind_ptr->kek_len = fils_info->kek_len;
+		qdf_mem_copy(roam_synch_ind_ptr->kek, fils_info->kek,
+			     fils_info->kek_len);
+
+		roam_synch_ind_ptr->pmk_len = fils_info->pmk_len;
+		qdf_mem_copy(roam_synch_ind_ptr->pmk, fils_info->pmk,
+			     fils_info->pmk_len);
+
+		qdf_mem_copy(roam_synch_ind_ptr->pmkid, fils_info->pmkid,
+			     SIR_PMKID_LEN);
+
+		roam_synch_ind_ptr->update_erp_next_seq_num =
+				fils_info->update_erp_next_seq_num;
+		roam_synch_ind_ptr->next_erp_seq_num =
+				fils_info->next_erp_seq_num;
+
+		WMA_LOGD("%s: KEK dump", __func__);
+		QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_DEBUG,
+				   roam_synch_ind_ptr->kek, fils_info->kek_len);
+		WMA_LOGD("%s: PMK dump", __func__);
+		QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_DEBUG,
+				   roam_synch_ind_ptr->pmk, fils_info->pmk_len);
+		WMA_LOGD("%s: PMKID dump", __func__);
+		QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_DEBUG,
+				   roam_synch_ind_ptr->pmkid, SIR_PMKID_LEN);
+	}
 	return 0;
 }