0001
0002
0003
0004
0005
0006
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
0088
0089
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 }