Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Scan related functions.
0004  *
0005  * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
0006  * Copyright (c) 2010, ST-Ericsson
0007  */
0008 #include <net/mac80211.h>
0009 
0010 #include "scan.h"
0011 #include "wfx.h"
0012 #include "sta.h"
0013 #include "hif_tx_mib.h"
0014 
0015 static void wfx_ieee80211_scan_completed_compat(struct ieee80211_hw *hw, bool aborted)
0016 {
0017     struct cfg80211_scan_info info = {
0018         .aborted = aborted,
0019     };
0020 
0021     ieee80211_scan_completed(hw, &info);
0022 }
0023 
0024 static int update_probe_tmpl(struct wfx_vif *wvif, struct cfg80211_scan_request *req)
0025 {
0026     struct ieee80211_vif *vif = wvif_to_vif(wvif);
0027     struct sk_buff *skb;
0028 
0029     skb = ieee80211_probereq_get(wvif->wdev->hw, vif->addr, NULL, 0,
0030                      req->ie_len);
0031     if (!skb)
0032         return -ENOMEM;
0033 
0034     skb_put_data(skb, req->ie, req->ie_len);
0035     wfx_hif_set_template_frame(wvif, skb, HIF_TMPLT_PRBREQ, 0);
0036     dev_kfree_skb(skb);
0037     return 0;
0038 }
0039 
0040 static int send_scan_req(struct wfx_vif *wvif, struct cfg80211_scan_request *req, int start_idx)
0041 {
0042     struct ieee80211_vif *vif = wvif_to_vif(wvif);
0043     struct ieee80211_channel *ch_start, *ch_cur;
0044     int i, ret;
0045 
0046     for (i = start_idx; i < req->n_channels; i++) {
0047         ch_start = req->channels[start_idx];
0048         ch_cur = req->channels[i];
0049         WARN(ch_cur->band != NL80211_BAND_2GHZ, "band not supported");
0050         if (ch_cur->max_power != ch_start->max_power)
0051             break;
0052         if ((ch_cur->flags ^ ch_start->flags) & IEEE80211_CHAN_NO_IR)
0053             break;
0054     }
0055     wfx_tx_lock_flush(wvif->wdev);
0056     wvif->scan_abort = false;
0057     reinit_completion(&wvif->scan_complete);
0058     ret = wfx_hif_scan(wvif, req, start_idx, i - start_idx);
0059     if (ret) {
0060         wfx_tx_unlock(wvif->wdev);
0061         return -EIO;
0062     }
0063     ret = wait_for_completion_timeout(&wvif->scan_complete, 1 * HZ);
0064     if (!ret) {
0065         wfx_hif_stop_scan(wvif);
0066         ret = wait_for_completion_timeout(&wvif->scan_complete, 1 * HZ);
0067         dev_dbg(wvif->wdev->dev, "scan timeout (%d channels done)\n",
0068             wvif->scan_nb_chan_done);
0069     }
0070     if (!ret) {
0071         dev_err(wvif->wdev->dev, "scan didn't stop\n");
0072         ret = -ETIMEDOUT;
0073     } else if (wvif->scan_abort) {
0074         dev_notice(wvif->wdev->dev, "scan abort\n");
0075         ret = -ECONNABORTED;
0076     } else if (wvif->scan_nb_chan_done > i - start_idx) {
0077         ret = -EIO;
0078     } else {
0079         ret = wvif->scan_nb_chan_done;
0080     }
0081     if (req->channels[start_idx]->max_power != vif->bss_conf.txpower)
0082         wfx_hif_set_output_power(wvif, vif->bss_conf.txpower);
0083     wfx_tx_unlock(wvif->wdev);
0084     return ret;
0085 }
0086 
0087 /* It is not really necessary to run scan request asynchronously. However,
0088  * there is a bug in "iw scan" when ieee80211_scan_completed() is called before
0089  * wfx_hw_scan() return
0090  */
0091 void wfx_hw_scan_work(struct work_struct *work)
0092 {
0093     struct wfx_vif *wvif = container_of(work, struct wfx_vif, scan_work);
0094     struct ieee80211_scan_request *hw_req = wvif->scan_req;
0095     int chan_cur, ret, err;
0096 
0097     mutex_lock(&wvif->wdev->conf_mutex);
0098     mutex_lock(&wvif->scan_lock);
0099     if (wvif->join_in_progress) {
0100         dev_info(wvif->wdev->dev, "abort in-progress REQ_JOIN");
0101         wfx_reset(wvif);
0102     }
0103     update_probe_tmpl(wvif, &hw_req->req);
0104     chan_cur = 0;
0105     err = 0;
0106     do {
0107         ret = send_scan_req(wvif, &hw_req->req, chan_cur);
0108         if (ret > 0) {
0109             chan_cur += ret;
0110             err = 0;
0111         }
0112         if (!ret)
0113             err++;
0114         if (err > 2) {
0115             dev_err(wvif->wdev->dev, "scan has not been able to start\n");
0116             ret = -ETIMEDOUT;
0117         }
0118     } while (ret >= 0 && chan_cur < hw_req->req.n_channels);
0119     mutex_unlock(&wvif->scan_lock);
0120     mutex_unlock(&wvif->wdev->conf_mutex);
0121     wfx_ieee80211_scan_completed_compat(wvif->wdev->hw, ret < 0);
0122 }
0123 
0124 int wfx_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
0125         struct ieee80211_scan_request *hw_req)
0126 {
0127     struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
0128 
0129     WARN_ON(hw_req->req.n_channels > HIF_API_MAX_NB_CHANNELS);
0130     wvif->scan_req = hw_req;
0131     schedule_work(&wvif->scan_work);
0132     return 0;
0133 }
0134 
0135 void wfx_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
0136 {
0137     struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
0138 
0139     wvif->scan_abort = true;
0140     wfx_hif_stop_scan(wvif);
0141 }
0142 
0143 void wfx_scan_complete(struct wfx_vif *wvif, int nb_chan_done)
0144 {
0145     wvif->scan_nb_chan_done = nb_chan_done;
0146     complete(&wvif->scan_complete);
0147 }