diff options
author | Jérôme Pouiller <jerome.pouiller@silabs.com> | 2019-12-17 16:15:37 +0000 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2019-12-18 15:56:31 +0100 |
commit | 3827e33d371ed2f4024fd42a4409e1b7af8e0938 (patch) | |
tree | 32f88a8504c8cea69a4e033d1689384b5de242b6 /drivers/staging/wfx/scan.c | |
parent | d1c015b4ef6f2ab74b19c216cfff07742b7665cf (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.c | 47 |
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; } |