summaryrefslogtreecommitdiff
path: root/drivers/staging/wfx/scan.c
diff options
context:
space:
mode:
authorJérôme Pouiller <jerome.pouiller@silabs.com>2019-12-17 16:15:37 +0000
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2019-12-18 15:56:31 +0100
commit3827e33d371ed2f4024fd42a4409e1b7af8e0938 (patch)
tree32f88a8504c8cea69a4e033d1689384b5de242b6 /drivers/staging/wfx/scan.c
parentd1c015b4ef6f2ab74b19c216cfff07742b7665cf (diff)
staging: wfx: workaround bug with "iw scan"
mac80211 specification does not forbid hw_scan() to call ieee80211_scan_completed(). However, from userspace point of view, not all applications support this behavior. In particular, the code of iw contains a big fat warning: /* * This code has a bug, which requires creating a separate * nl80211 socket to fix: * It is possible for a NL80211_CMD_NEW_SCAN_RESULTS or * NL80211_CMD_SCAN_ABORTED message to be sent by the kernel * before (!) we listen to it, because we only start listening * after we send our scan request. [...] * Alas, the kernel doesn't do that (yet). */ So, we have to avoid to call ieee80211_scan_completed() from hw_scan() (it's a kind of unwritten rule). This patch relocates the hw_scan() process to a work_struct to fix the problem. Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com> Link: https://lore.kernel.org/r/20191217161318.31402-52-Jerome.Pouiller@silabs.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/staging/wfx/scan.c')
-rw-r--r--drivers/staging/wfx/scan.c47
1 files changed, 30 insertions, 17 deletions
diff --git a/drivers/staging/wfx/scan.c b/drivers/staging/wfx/scan.c
index b73e61e8da46..540009b72240 100644
--- a/drivers/staging/wfx/scan.c
+++ b/drivers/staging/wfx/scan.c
@@ -71,23 +71,19 @@ static int send_scan_req(struct wfx_vif *wvif,
return i - start_idx;
}
-int wfx_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_scan_request *hw_req)
+/*
+ * It is not really necessary to run scan request asynchronously. However,
+ * there is a bug in "iw scan" when ieee80211_scan_completed() is called before
+ * wfx_hw_scan() return
+ */
+void wfx_hw_scan_work(struct work_struct *work)
{
- struct wfx_dev *wdev = hw->priv;
- struct wfx_vif *wvif = (struct wfx_vif *) vif->drv_priv;
+ struct wfx_vif *wvif = container_of(work, struct wfx_vif, scan_work);
+ struct ieee80211_scan_request *hw_req = wvif->scan_req;
int chan_cur, ret;
- WARN_ON(hw_req->req.n_channels > HIF_API_MAX_NB_CHANNELS);
-
- if (vif->type == NL80211_IFTYPE_AP)
- return -EOPNOTSUPP;
-
- if (wvif->state == WFX_STATE_PRE_STA)
- return -EBUSY;
-
mutex_lock(&wvif->scan_lock);
- mutex_lock(&wdev->conf_mutex);
+ mutex_lock(&wvif->wdev->conf_mutex);
update_probe_tmpl(wvif, &hw_req->req);
wfx_fwd_probe_req(wvif, true);
chan_cur = 0;
@@ -96,18 +92,35 @@ int wfx_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
if (ret > 0)
chan_cur += ret;
} while (ret > 0 && chan_cur < hw_req->req.n_channels);
- __ieee80211_scan_completed_compat(hw, ret < 0);
- mutex_unlock(&wdev->conf_mutex);
+ mutex_unlock(&wvif->wdev->conf_mutex);
mutex_unlock(&wvif->scan_lock);
+ __ieee80211_scan_completed_compat(wvif->wdev->hw, ret < 0);
if (wvif->delayed_unjoin) {
wvif->delayed_unjoin = false;
- wfx_tx_lock(wdev);
+ wfx_tx_lock(wvif->wdev);
if (!schedule_work(&wvif->unjoin_work))
- wfx_tx_unlock(wdev);
+ wfx_tx_unlock(wvif->wdev);
} else if (wvif->delayed_link_loss) {
wvif->delayed_link_loss = false;
wfx_cqm_bssloss_sm(wvif, 1, 0, 0);
}
+}
+
+int wfx_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_scan_request *hw_req)
+{
+ struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
+
+ WARN_ON(hw_req->req.n_channels > HIF_API_MAX_NB_CHANNELS);
+
+ if (vif->type == NL80211_IFTYPE_AP)
+ return -EOPNOTSUPP;
+
+ if (wvif->state == WFX_STATE_PRE_STA)
+ return -EBUSY;
+
+ wvif->scan_req = hw_req;
+ schedule_work(&wvif->scan_work);
return 0;
}