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
This commit is contained in:
Liangwei Dong 2021-01-14 14:01:53 +08:00 • committed by snandini
commit 0b3b7b36d5
3 changed files with 50 additions and 24 deletions

View file

@ -3459,10 +3459,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,

View file

@ -4400,6 +4400,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)
@ -4428,12 +4430,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))

View file

@ -822,28 +822,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");
@ -912,11 +902,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;
}
@ -1773,7 +1767,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,