浏览代码

qcacld-3.0: Send RSO update after set key failure

In multiple AKM suite roaming scenario, if the STA is
roaming from WPA3 to WPA2 AKM suite, during the roam sync the
rso config will have the PMK of previous WPA3 connection. The
RSO start for the new connection would plumb the PMK of WPA3 to
the FW. After the RSO is enabled, set_key from userspace will
update the proper PMK of the current WPA2 to the FW via
RSO Update.

Due to a race condition, the set_key from userspace can reach
driver before the RSO start is sent to the FW. In this case,
the RSO update(due to set_key) will fail. Therefore, the FW
will keep the WPA3 PMK(in RSO start) as the final PMK for
the WPA2 connection, leading to roam failures.
To fix this, if the set_key for the connected bssid is
received during Roam sync in progress, then mark the
set_key rejection in vdev and send RSO update to the
FW after RSO gets enabled.

Change-Id: Ibb5a4929212e6c2ccabf39136962d3a8e606ece9
CRs-Fixed: 3212800
Surya Prakash Sivaraj 2 年之前
父节点
当前提交
c01e68f5b4

+ 42 - 0
components/mlme/core/inc/wlan_mlme_main.h

@@ -222,6 +222,7 @@ struct wlan_mlme_roaming_config {
  * @roam_sm: Structure containing roaming state related details
  * @roam_config: Roaming configurations structure
  * @sae_single_pmk: Details for sae roaming using single pmk
+ * @set_pmk_pending: RSO update status of PMK from set_key
  */
 struct wlan_mlme_roam {
 	struct wlan_mlme_roam_state_info roam_sm;
@@ -229,6 +230,7 @@ struct wlan_mlme_roam {
 #if defined(WLAN_SAE_SINGLE_PMK) && defined(WLAN_FEATURE_ROAM_OFFLOAD)
 	struct wlan_mlme_sae_single_pmk sae_single_pmk;
 #endif
+	bool set_pmk_pending;
 };
 
 #ifdef WLAN_FEATURE_MSCS
@@ -1187,4 +1189,44 @@ wlan_get_sap_user_config_freq(struct wlan_objmgr_vdev *vdev);
 QDF_STATUS
 wlan_set_sap_user_config_freq(struct wlan_objmgr_vdev *vdev,
 			      qdf_freq_t freq);
+
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+/**
+ * wlan_mlme_defer_pmk_set_in_roaming() - Set the set_key pending status
+ *
+ * @psoc: pointer to psoc
+ * @vdev_id: vdev id
+ * @set_pmk_pending: set_key pending status
+ *
+ * Return: None
+ */
+void
+wlan_mlme_defer_pmk_set_in_roaming(struct wlan_objmgr_psoc *psoc,
+				   uint8_t vdev_id, bool set_pmk_pending);
+
+/**
+ * wlan_mlme_is_pmk_set_deferred() - Get the set_key pending status
+ *
+ * @psoc: pointer to psoc
+ * @vdev_id: vdev id
+ *
+ * Return : set_key pending status
+ */
+bool
+wlan_mlme_is_pmk_set_deferred(struct wlan_objmgr_psoc *psoc,
+			      uint8_t vdev_id);
+#else
+static inline void
+wlan_mlme_defer_pmk_set_in_roaming(struct wlan_objmgr_psoc *psoc,
+				   uint8_t vdev_id, bool set_pmk_pending)
+{
+}
+
+static inline bool
+wlan_mlme_is_pmk_set_deferred(struct wlan_objmgr_psoc *psoc,
+			      uint8_t vdev_id)
+{
+	return false;
+}
+#endif
 #endif

+ 59 - 0
components/mlme/core/src/wlan_mlme_main.c

@@ -1837,6 +1837,65 @@ static void mlme_init_roam_offload_cfg(struct wlan_objmgr_psoc *psoc,
 	qdf_mem_zero(&lfr->roam_rt_stats, sizeof(lfr->roam_rt_stats));
 }
 
+void
+wlan_mlme_defer_pmk_set_in_roaming(struct wlan_objmgr_psoc *psoc,
+				   uint8_t vdev_id, bool set_pmk_pending)
+{
+	struct wlan_objmgr_vdev *vdev;
+	struct mlme_legacy_priv *mlme_priv;
+
+	if (set_pmk_pending && !MLME_IS_ROAM_SYNCH_IN_PROGRESS(psoc, vdev_id))
+		return;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
+						    WLAN_MLME_OBJMGR_ID);
+
+	if (!vdev) {
+		mlme_err("get vdev failed");
+		return;
+	}
+
+	mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev);
+
+	if (!mlme_priv) {
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID);
+		mlme_legacy_err("vdev legacy private object is NULL");
+		return;
+	}
+
+	mlme_priv->mlme_roam.set_pmk_pending = set_pmk_pending;
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID);
+}
+
+bool
+wlan_mlme_is_pmk_set_deferred(struct wlan_objmgr_psoc *psoc,
+			      uint8_t vdev_id)
+{
+	struct wlan_objmgr_vdev *vdev;
+	struct mlme_legacy_priv *mlme_priv;
+	bool set_pmk_pending;
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
+						    WLAN_MLME_OBJMGR_ID);
+
+	if (!vdev) {
+		mlme_err("get vdev failed");
+		return false;
+	}
+
+	mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev);
+
+	if (!mlme_priv) {
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID);
+		mlme_legacy_err("vdev legacy private object is NULL");
+		return false;
+	}
+
+	set_pmk_pending = mlme_priv->mlme_roam.set_pmk_pending;
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID);
+
+	return set_pmk_pending;
+}
 #else
 static void mlme_init_roam_offload_cfg(struct wlan_objmgr_psoc *psoc,
 				       struct wlan_mlme_lfr_cfg *lfr)

+ 15 - 0
components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.c

@@ -3265,6 +3265,8 @@ cm_roam_stop_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id,
 		goto rel_vdev_ref;
 	}
 
+	wlan_mlme_defer_pmk_set_in_roaming(psoc, vdev_id, false);
+
 	cm_roam_scan_filter(psoc, pdev, vdev_id, ROAM_SCAN_OFFLOAD_STOP,
 			    reason, &stop_req->scan_filter_params);
 	cm_roam_scan_offload_fill_rso_configs(psoc, vdev, rso_cfg,
@@ -4102,6 +4104,19 @@ cm_roam_switch_to_rso_enable(struct wlan_objmgr_pdev *pdev,
 	}
 	mlme_set_roam_state(psoc, vdev_id, WLAN_ROAM_RSO_ENABLED);
 
+	/* If the set_key for the connected bssid was received during Roam sync
+	 * in progress, then the RSO update to the FW will be rejected. The RSO
+	 * start which might be in progress during set_key could send stale pmk
+	 * to the FW. Therefore, once RSO is enabled, send the RSO update with
+	 * the PMK received from the __wlan_hdd_cfg80211_keymgmt_set_key.
+	 */
+	if (wlan_mlme_is_pmk_set_deferred(psoc, vdev_id)) {
+		cm_roam_send_rso_cmd(psoc, vdev_id,
+				     ROAM_SCAN_OFFLOAD_UPDATE_CFG,
+				     REASON_ROAM_PSK_PMK_CHANGED);
+		wlan_mlme_defer_pmk_set_in_roaming(psoc, vdev_id, false);
+	}
+
 	/*
 	 * If supplicant disabled roaming, driver does not send
 	 * RSO cmd to fw. This causes roam invoke to fail in FW

+ 8 - 3
core/sme/src/csr/csr_api_roam.c

@@ -4868,6 +4868,7 @@ QDF_STATUS csr_roam_set_psk_pmk(struct mac_context *mac,
 {
 	struct wlan_objmgr_vdev *vdev;
 	struct qdf_mac_addr connected_bssid = {0};
+	QDF_STATUS status;
 
 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac->psoc, vdev_id,
 						    WLAN_LEGACY_SME_ID);
@@ -4898,9 +4899,13 @@ QDF_STATUS csr_roam_set_psk_pmk(struct mac_context *mac,
 	wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID);
 
 	wlan_cm_set_psk_pmk(mac->pdev, vdev_id, pmksa->pmk, pmksa->pmk_len);
-	if (update_to_fw)
-		wlan_roam_update_cfg(mac->psoc, vdev_id,
-				     REASON_ROAM_PSK_PMK_CHANGED);
+	if (update_to_fw) {
+		status = wlan_roam_update_cfg(mac->psoc, vdev_id,
+					      REASON_ROAM_PSK_PMK_CHANGED);
+		if (status == QDF_STATUS_E_INVAL)
+			wlan_mlme_defer_pmk_set_in_roaming(mac->psoc, vdev_id,
+							   true);
+	}
 
 	return QDF_STATUS_SUCCESS;
 }