Bläddra i källkod

qcacld-3.0: Validate STA channel switch notify

Add validation for STA CSA channel change notify event:
1. acquire the wdev->mtx lock before invoke kernel API -
cfg80211_ch_switch_notify. Kernel will access wdev->current_bss
in the API, it maybe changed in other thread.
2. if the bssid is not connected in vdev, don't invoke kernel API -
cfg80211_ch_switch_notify since wdev->current_bss maybe unlinked from
kernel bss list. cfg80211_ch_switch_notify make assumption
current_bss existing on the bss list.

Change-Id: I0dd415a5576d29e3a7729768c8482205677ca3e7
CRs-Fixed: 2855494
Liangwei Dong 4 år sedan
förälder
incheckning
b4f5f936a7
3 ändrade filer med 50 tillägg och 24 borttagningar
  1. 15 1
      core/hdd/inc/wlan_hdd_main.h
  2. 24 6
      core/hdd/src/wlan_hdd_assoc.c
  3. 11 17
      core/hdd/src/wlan_hdd_hostapd.c

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

@@ -3554,10 +3554,24 @@ int hdd_update_config(struct hdd_context *hdd_ctx);
  */
 int hdd_update_components_config(struct hdd_context *hdd_ctx);
 
+/**
+ * hdd_chan_change_notify() - Function to notify hostapd about channel change
+ * @hostapd_adapter:	hostapd adapter
+ * @dev:		Net device structure
+ * @chan_change:	New channel change parameters
+ * @legacy_phymode:	is the phymode legacy
+ * @lock_wdev:  need wdev lock or not
+ *
+ * This function is used to notify hostapd about the channel change
+ *
+ * Return: Success on intimating userspace
+ *
+ */
 QDF_STATUS hdd_chan_change_notify(struct hdd_adapter *adapter,
 		struct net_device *dev,
 		struct hdd_chan_change_params chan_change,
-		bool legacy_phymode);
+		bool legacy_phymode,
+		bool lock_wdev);
 int wlan_hdd_set_channel(struct wiphy *wiphy,
 		struct net_device *dev,
 		struct cfg80211_chan_def *chandef,

+ 24 - 6
core/hdd/src/wlan_hdd_assoc.c

@@ -4079,6 +4079,8 @@ static void hdd_roam_channel_switch_handler(struct hdd_adapter *adapter,
 	struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
 	mac_handle_t mac_handle = hdd_adapter_get_mac_handle(adapter);
 	struct hdd_station_ctx *sta_ctx;
+	uint8_t connected_vdev;
+	bool notify = true;
 
 	/* Enable Roaming on STA interface which was disabled before CSA */
 	if (adapter->device_mode == QDF_STA_MODE)
@@ -4107,12 +4109,28 @@ static void hdd_roam_channel_switch_handler(struct hdd_adapter *adapter,
 		hdd_err("%s: unable to create BSS entry", adapter->dev->name);
 	else
 		cfg80211_put_bss(wiphy, bss);
-
-	status = hdd_chan_change_notify(adapter, adapter->dev, chan_change,
-				roam_info->mode == SIR_SME_PHY_MODE_LEGACY);
-	if (QDF_IS_STATUS_ERROR(status))
-		hdd_err("channel change notification failed");
-
+	if ((adapter->device_mode == QDF_STA_MODE ||
+	     adapter->device_mode == QDF_P2P_CLIENT_MODE)) {
+		if (!wlan_get_connected_vdev_by_bssid(
+				hdd_ctx->pdev, sta_ctx->conn_info.bssid.bytes,
+				&connected_vdev))
+			notify = false;
+		else if (adapter->vdev_id != connected_vdev)
+			notify = false;
+	}
+	if (notify) {
+		status = hdd_chan_change_notify(adapter, adapter->dev,
+						chan_change,
+						roam_info->mode ==
+						SIR_SME_PHY_MODE_LEGACY,
+						true);
+		if (QDF_IS_STATUS_ERROR(status))
+			hdd_err("channel change notification failed");
+	} else {
+		hdd_err("BSS "QDF_MAC_ADDR_FMT" no connected with vdev %d (%d)",
+			QDF_MAC_ADDR_REF(sta_ctx->conn_info.bssid.bytes),
+			adapter->vdev_id, connected_vdev);
+	}
 	status = policy_mgr_set_hw_mode_on_channel_switch(hdd_ctx->psoc,
 		adapter->vdev_id);
 	if (QDF_IS_STATUS_ERROR(status))

+ 11 - 17
core/hdd/src/wlan_hdd_hostapd.c

@@ -821,28 +821,18 @@ static int hdd_stop_bss_link(struct hdd_adapter *adapter)
 	return errno;
 }
 
-/**
- * hdd_chan_change_notify() - Function to notify hostapd about channel change
- * @hostapd_adapter:	hostapd adapter
- * @dev:		Net device structure
- * @chan_change:	New channel change parameters
- * @legacy_phymode:	is the phymode legacy
- *
- * This function is used to notify hostapd about the channel change
- *
- * Return: Success on intimating userspace
- *
- */
 QDF_STATUS hdd_chan_change_notify(struct hdd_adapter *adapter,
 		struct net_device *dev,
 		struct hdd_chan_change_params chan_change,
-		bool legacy_phymode)
+		bool legacy_phymode,
+		bool lock_wdev)
 {
 	struct ieee80211_channel *chan;
 	struct cfg80211_chan_def chandef;
 	enum nl80211_channel_type channel_type;
 	uint32_t freq;
 	mac_handle_t mac_handle = adapter->hdd_ctx->mac_handle;
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
 
 	if (!mac_handle) {
 		hdd_err("mac_handle is NULL");
@@ -911,11 +901,15 @@ QDF_STATUS hdd_chan_change_notify(struct hdd_adapter *adapter,
 				chan_change.chan_params.mhz_freq_seg0;
 	}
 
-	hdd_debug("notify: chan:%d width:%d freq1:%d freq2:%d",
-		chandef.chan->center_freq, chandef.width, chandef.center_freq1,
-		chandef.center_freq2);
+	hdd_debug("notify: chan:%d width:%d freq1:%d freq2:%d locked %d",
+		  chandef.chan->center_freq, chandef.width,
+		  chandef.center_freq1, chandef.center_freq2, lock_wdev);
+	if (lock_wdev)
+		mutex_lock(&wdev->mtx);
 
 	cfg80211_ch_switch_notify(dev, &chandef);
+	if (lock_wdev)
+		mutex_unlock(&wdev->mtx);
 
 	return QDF_STATUS_SUCCESS;
 }
@@ -1805,7 +1799,7 @@ static QDF_STATUS hdd_hostapd_chan_change(struct hdd_adapter *adapter,
 			sap_chan_selected->vht_seg1_center_ch_freq;
 
 	return hdd_chan_change_notify(adapter, adapter->dev,
-				      chan_change, legacy_phymode);
+				      chan_change, legacy_phymode, false);
 }
 
 QDF_STATUS hdd_hostapd_sap_event_cb(struct sap_event *sap_event,