lkml.org 
[lkml]   [2019]   [Dec]   [16]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 51/55] staging: wfx: workaround bug with "iw scan"
    Date
    From: Jérôme Pouiller <jerome.pouiller@silabs.com>

    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>
    ---
    drivers/staging/wfx/scan.c | 47 ++++++++++++++++++++++++--------------
    drivers/staging/wfx/scan.h | 1 +
    drivers/staging/wfx/sta.c | 1 +
    drivers/staging/wfx/wfx.h | 2 ++
    4 files changed, 34 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;
    }

    diff --git a/drivers/staging/wfx/scan.h b/drivers/staging/wfx/scan.h
    index 03bc6c7e562d..b547f1927d72 100644
    --- a/drivers/staging/wfx/scan.h
    +++ b/drivers/staging/wfx/scan.h
    @@ -15,6 +15,7 @@
    struct wfx_dev;
    struct wfx_vif;

    +void wfx_hw_scan_work(struct work_struct *work);
    int wfx_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
    struct ieee80211_scan_request *req);
    void wfx_scan_complete(struct wfx_vif *wvif,
    diff --git a/drivers/staging/wfx/sta.c b/drivers/staging/wfx/sta.c
    index 16f5db873275..4354bb8081c5 100644
    --- a/drivers/staging/wfx/sta.c
    +++ b/drivers/staging/wfx/sta.c
    @@ -1427,6 +1427,7 @@ int wfx_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)

    mutex_init(&wvif->scan_lock);
    init_completion(&wvif->scan_complete);
    + INIT_WORK(&wvif->scan_work, wfx_hw_scan_work);

    mutex_unlock(&wdev->conf_mutex);

    diff --git a/drivers/staging/wfx/wfx.h b/drivers/staging/wfx/wfx.h
    index 3356d0cbf7af..b5f763c3fac7 100644
    --- a/drivers/staging/wfx/wfx.h
    +++ b/drivers/staging/wfx/wfx.h
    @@ -127,7 +127,9 @@ struct wfx_vif {

    /* avoid some operations in parallel with scan */
    struct mutex scan_lock;
    + struct work_struct scan_work;
    struct completion scan_complete;
    + struct ieee80211_scan_request *scan_req;

    struct completion set_pm_mode_complete;

    --
    2.20.1
    \
     
     \ /
      Last update: 2019-12-16 18:07    [W:4.679 / U:0.024 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site