mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-03 21:45:08 -04:00
wil6210: fix race conditions in p2p listen and search
Fix 2 race conditions found during test runs of P2P discovery: 1. Because wil_p2p_cancel_listen was not protected, user space could start a new P2P listen/search before wmi_stop_discovery completed. This caused a crash in the firmware. 2. In P2P listen, when listen timer expires and user space calls cancel_remain_on_channel at the same time, code could send the cfg80211_remain_on_channel_expired notification twice. Added protections with wil->mutex to several places that call wmi_stop_discovery. Signed-off-by: Lior David <qca_liord@qca.qualcomm.com> Signed-off-by: Maya Erez <qca_merez@qca.qualcomm.com> Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
This commit is contained in:
@@ -387,7 +387,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
|
||||
return rc;
|
||||
}
|
||||
|
||||
wil_p2p_stop_discovery(wil);
|
||||
(void)wil_p2p_stop_discovery(wil);
|
||||
|
||||
wil_dbg_misc(wil, "Start scan_request 0x%p\n", request);
|
||||
wil_dbg_misc(wil, "SSID count: %d", request->n_ssids);
|
||||
@@ -868,6 +868,9 @@ static int wil_cfg80211_set_default_key(struct wiphy *wiphy,
|
||||
u8 key_index, bool unicast,
|
||||
bool multicast)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
|
||||
wil_dbg_misc(wil, "%s: entered\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -903,9 +906,7 @@ static int wil_cancel_remain_on_channel(struct wiphy *wiphy,
|
||||
|
||||
wil_dbg_misc(wil, "%s()\n", __func__);
|
||||
|
||||
wil_p2p_cancel_listen(wil, cookie);
|
||||
|
||||
return 0;
|
||||
return wil_p2p_cancel_listen(wil, cookie);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -984,7 +984,7 @@ int __wil_down(struct wil6210_priv *wil)
|
||||
}
|
||||
wil_enable_irq(wil);
|
||||
|
||||
wil_p2p_stop_discovery(wil);
|
||||
(void)wil_p2p_stop_discovery(wil);
|
||||
|
||||
if (wil->scan_request) {
|
||||
wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
|
||||
|
||||
@@ -156,26 +156,42 @@ int wil_p2p_listen(struct wil6210_priv *wil, unsigned int duration,
|
||||
return rc;
|
||||
}
|
||||
|
||||
void wil_p2p_stop_discovery(struct wil6210_priv *wil)
|
||||
u8 wil_p2p_stop_discovery(struct wil6210_priv *wil)
|
||||
{
|
||||
struct wil_p2p_info *p2p = &wil->p2p;
|
||||
u8 started = p2p->discovery_started;
|
||||
|
||||
if (p2p->discovery_started) {
|
||||
del_timer_sync(&p2p->discovery_timer);
|
||||
p2p->discovery_started = 0;
|
||||
wmi_stop_discovery(wil);
|
||||
}
|
||||
|
||||
return started;
|
||||
}
|
||||
|
||||
void wil_p2p_cancel_listen(struct wil6210_priv *wil, u64 cookie)
|
||||
int wil_p2p_cancel_listen(struct wil6210_priv *wil, u64 cookie)
|
||||
{
|
||||
struct wil_p2p_info *p2p = &wil->p2p;
|
||||
u8 started;
|
||||
|
||||
if (cookie != p2p->cookie)
|
||||
mutex_lock(&wil->mutex);
|
||||
|
||||
if (cookie != p2p->cookie) {
|
||||
wil_info(wil, "%s: Cookie mismatch: 0x%016llx vs. 0x%016llx\n",
|
||||
__func__, p2p->cookie, cookie);
|
||||
mutex_unlock(&wil->mutex);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
wil_p2p_stop_discovery(wil);
|
||||
started = wil_p2p_stop_discovery(wil);
|
||||
|
||||
mutex_unlock(&wil->mutex);
|
||||
|
||||
if (!started) {
|
||||
wil_err(wil, "%s: listen not started\n", __func__);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
mutex_lock(&wil->p2p_wdev_mutex);
|
||||
cfg80211_remain_on_channel_expired(wil->radio_wdev,
|
||||
@@ -184,6 +200,7 @@ void wil_p2p_cancel_listen(struct wil6210_priv *wil, u64 cookie)
|
||||
GFP_KERNEL);
|
||||
wil->radio_wdev = wil->wdev;
|
||||
mutex_unlock(&wil->p2p_wdev_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wil_p2p_listen_expired(struct work_struct *work)
|
||||
@@ -192,18 +209,23 @@ void wil_p2p_listen_expired(struct work_struct *work)
|
||||
struct wil_p2p_info, discovery_expired_work);
|
||||
struct wil6210_priv *wil = container_of(p2p,
|
||||
struct wil6210_priv, p2p);
|
||||
u8 started;
|
||||
|
||||
wil_dbg_misc(wil, "%s()\n", __func__);
|
||||
|
||||
wil_p2p_stop_discovery(wil);
|
||||
mutex_lock(&wil->mutex);
|
||||
started = wil_p2p_stop_discovery(wil);
|
||||
mutex_unlock(&wil->mutex);
|
||||
|
||||
mutex_lock(&wil->p2p_wdev_mutex);
|
||||
cfg80211_remain_on_channel_expired(wil->radio_wdev,
|
||||
p2p->cookie,
|
||||
&p2p->listen_chan,
|
||||
GFP_KERNEL);
|
||||
wil->radio_wdev = wil->wdev;
|
||||
mutex_unlock(&wil->p2p_wdev_mutex);
|
||||
if (started) {
|
||||
mutex_lock(&wil->p2p_wdev_mutex);
|
||||
cfg80211_remain_on_channel_expired(wil->radio_wdev,
|
||||
p2p->cookie,
|
||||
&p2p->listen_chan,
|
||||
GFP_KERNEL);
|
||||
wil->radio_wdev = wil->wdev;
|
||||
mutex_unlock(&wil->p2p_wdev_mutex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -213,14 +235,19 @@ void wil_p2p_search_expired(struct work_struct *work)
|
||||
struct wil_p2p_info, discovery_expired_work);
|
||||
struct wil6210_priv *wil = container_of(p2p,
|
||||
struct wil6210_priv, p2p);
|
||||
u8 started;
|
||||
|
||||
wil_dbg_misc(wil, "%s()\n", __func__);
|
||||
|
||||
wil_p2p_stop_discovery(wil);
|
||||
mutex_lock(&wil->mutex);
|
||||
started = wil_p2p_stop_discovery(wil);
|
||||
mutex_unlock(&wil->mutex);
|
||||
|
||||
mutex_lock(&wil->p2p_wdev_mutex);
|
||||
cfg80211_scan_done(wil->scan_request, 0);
|
||||
wil->scan_request = NULL;
|
||||
wil->radio_wdev = wil->wdev;
|
||||
mutex_unlock(&wil->p2p_wdev_mutex);
|
||||
if (started) {
|
||||
mutex_lock(&wil->p2p_wdev_mutex);
|
||||
cfg80211_scan_done(wil->scan_request, 0);
|
||||
wil->scan_request = NULL;
|
||||
wil->radio_wdev = wil->wdev;
|
||||
mutex_unlock(&wil->p2p_wdev_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -775,8 +775,8 @@ int wil_p2p_search(struct wil6210_priv *wil,
|
||||
struct cfg80211_scan_request *request);
|
||||
int wil_p2p_listen(struct wil6210_priv *wil, unsigned int duration,
|
||||
struct ieee80211_channel *chan, u64 *cookie);
|
||||
void wil_p2p_stop_discovery(struct wil6210_priv *wil);
|
||||
void wil_p2p_cancel_listen(struct wil6210_priv *wil, u64 cookie);
|
||||
u8 wil_p2p_stop_discovery(struct wil6210_priv *wil);
|
||||
int wil_p2p_cancel_listen(struct wil6210_priv *wil, u64 cookie);
|
||||
void wil_p2p_listen_expired(struct work_struct *work);
|
||||
void wil_p2p_search_expired(struct work_struct *work);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user