From 0b3b7b36d5cf429cad60273c8acb71c58b856ec7 Mon Sep 17 00:00:00 2001 From: Liangwei Dong Date: Thu, 14 Jan 2021 14:01:53 +0800 Subject: [PATCH] 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 --- core/hdd/inc/wlan_hdd_main.h | 16 +++++++++++++++- core/hdd/src/wlan_hdd_assoc.c | 30 ++++++++++++++++++++++++------ core/hdd/src/wlan_hdd_hostapd.c | 28 +++++++++++----------------- 3 files changed, 50 insertions(+), 24 deletions(-) diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 938510f869a4..88e0a6a03036 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -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, diff --git a/core/hdd/src/wlan_hdd_assoc.c b/core/hdd/src/wlan_hdd_assoc.c index e44750fa438c..7be1d98fe27b 100644 --- a/core/hdd/src/wlan_hdd_assoc.c +++ b/core/hdd/src/wlan_hdd_assoc.c @@ -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)) diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c index d95789ca1a54..e7474455c070 100644 --- a/core/hdd/src/wlan_hdd_hostapd.c +++ b/core/hdd/src/wlan_hdd_hostapd.c @@ -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,