|
@@ -28,103 +28,120 @@
|
|
|
#include "wl1271_scan.h"
|
|
|
#include "wl1271_acx.h"
|
|
|
|
|
|
-int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
|
|
|
- struct cfg80211_scan_request *req, u8 active_scan,
|
|
|
- u8 high_prio, u8 band, u8 probe_requests)
|
|
|
+static int wl1271_get_scan_channels(struct wl1271 *wl,
|
|
|
+ struct cfg80211_scan_request *req,
|
|
|
+ struct basic_scan_channel_params *channels,
|
|
|
+ enum ieee80211_band band, bool passive)
|
|
|
{
|
|
|
+ int i, j;
|
|
|
+ u32 flags;
|
|
|
|
|
|
- struct wl1271_cmd_trigger_scan_to *trigger = NULL;
|
|
|
- struct wl1271_cmd_scan *params = NULL;
|
|
|
- struct ieee80211_channel *channels;
|
|
|
- u32 rate;
|
|
|
- int i, j, n_ch, ret;
|
|
|
- u16 scan_options = 0;
|
|
|
- u8 ieee_band;
|
|
|
-
|
|
|
- if (band == WL1271_SCAN_BAND_2_4_GHZ) {
|
|
|
- ieee_band = IEEE80211_BAND_2GHZ;
|
|
|
- rate = wl->conf.tx.basic_rate;
|
|
|
- } else if (band == WL1271_SCAN_BAND_DUAL && wl1271_11a_enabled()) {
|
|
|
- ieee_band = IEEE80211_BAND_2GHZ;
|
|
|
- rate = wl->conf.tx.basic_rate;
|
|
|
- } else if (band == WL1271_SCAN_BAND_5_GHZ && wl1271_11a_enabled()) {
|
|
|
- ieee_band = IEEE80211_BAND_5GHZ;
|
|
|
- rate = wl->conf.tx.basic_rate_5;
|
|
|
- } else
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- if (wl->hw->wiphy->bands[ieee_band]->channels == NULL)
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- channels = wl->hw->wiphy->bands[ieee_band]->channels;
|
|
|
- n_ch = wl->hw->wiphy->bands[ieee_band]->n_channels;
|
|
|
-
|
|
|
- if (test_bit(WL1271_FLAG_SCANNING, &wl->flags))
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- params = kzalloc(sizeof(*params), GFP_KERNEL);
|
|
|
- if (!params)
|
|
|
- return -ENOMEM;
|
|
|
-
|
|
|
- params->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD);
|
|
|
- params->params.rx_filter_options =
|
|
|
- cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN);
|
|
|
+ for (i = 0, j = 0;
|
|
|
+ i < req->n_channels && j < WL1271_SCAN_MAX_CHANNELS;
|
|
|
+ i++) {
|
|
|
|
|
|
- if (!active_scan)
|
|
|
- scan_options |= WL1271_SCAN_OPT_PASSIVE;
|
|
|
- if (high_prio)
|
|
|
- scan_options |= WL1271_SCAN_OPT_PRIORITY_HIGH;
|
|
|
- params->params.scan_options = cpu_to_le16(scan_options);
|
|
|
+ flags = req->channels[i]->flags;
|
|
|
|
|
|
- params->params.num_probe_requests = probe_requests;
|
|
|
- params->params.tx_rate = cpu_to_le32(rate);
|
|
|
- params->params.tid_trigger = 0;
|
|
|
- params->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;
|
|
|
+ if (!wl->scan.scanned_ch[i] &&
|
|
|
+ !(flags & IEEE80211_CHAN_DISABLED) &&
|
|
|
+ ((!!(flags & IEEE80211_CHAN_PASSIVE_SCAN)) == passive) &&
|
|
|
+ (req->channels[i]->band == band)) {
|
|
|
|
|
|
- if (band == WL1271_SCAN_BAND_DUAL)
|
|
|
- params->params.band = WL1271_SCAN_BAND_2_4_GHZ;
|
|
|
- else
|
|
|
- params->params.band = band;
|
|
|
+ wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ",
|
|
|
+ req->channels[i]->band,
|
|
|
+ req->channels[i]->center_freq);
|
|
|
+ wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X",
|
|
|
+ req->channels[i]->hw_value,
|
|
|
+ req->channels[i]->flags);
|
|
|
+ wl1271_debug(DEBUG_SCAN,
|
|
|
+ "max_antenna_gain %d, max_power %d",
|
|
|
+ req->channels[i]->max_antenna_gain,
|
|
|
+ req->channels[i]->max_power);
|
|
|
+ wl1271_debug(DEBUG_SCAN, "beacon_found %d",
|
|
|
+ req->channels[i]->beacon_found);
|
|
|
|
|
|
- for (i = 0, j = 0; i < n_ch && i < WL1271_SCAN_MAX_CHANNELS; i++) {
|
|
|
- if (!(channels[i].flags & IEEE80211_CHAN_DISABLED)) {
|
|
|
- params->channels[j].min_duration =
|
|
|
+ channels[j].min_duration =
|
|
|
cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION);
|
|
|
- params->channels[j].max_duration =
|
|
|
+ channels[j].max_duration =
|
|
|
cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION);
|
|
|
- memset(¶ms->channels[j].bssid_lsb, 0xff, 4);
|
|
|
- memset(¶ms->channels[j].bssid_msb, 0xff, 2);
|
|
|
- params->channels[j].early_termination = 0;
|
|
|
- params->channels[j].tx_power_att =
|
|
|
- WL1271_SCAN_CURRENT_TX_PWR;
|
|
|
- params->channels[j].channel = channels[i].hw_value;
|
|
|
+ channels[j].early_termination = 0;
|
|
|
+ channels[j].tx_power_att = WL1271_SCAN_CURRENT_TX_PWR;
|
|
|
+ channels[j].channel = req->channels[i]->hw_value;
|
|
|
+
|
|
|
+ memset(&channels[j].bssid_lsb, 0xff, 4);
|
|
|
+ memset(&channels[j].bssid_msb, 0xff, 2);
|
|
|
+
|
|
|
+ /* Mark the channels we already used */
|
|
|
+ wl->scan.scanned_ch[i] = true;
|
|
|
+
|
|
|
j++;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- params->params.num_channels = j;
|
|
|
+ return j;
|
|
|
+}
|
|
|
|
|
|
- if (ssid_len && ssid) {
|
|
|
- params->params.ssid_len = ssid_len;
|
|
|
- memcpy(params->params.ssid, ssid, ssid_len);
|
|
|
+#define WL1271_NOTHING_TO_SCAN 1
|
|
|
+
|
|
|
+static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
|
|
|
+ bool passive, u32 basic_rate)
|
|
|
+{
|
|
|
+ struct wl1271_cmd_scan *cmd;
|
|
|
+ struct wl1271_cmd_trigger_scan_to *trigger;
|
|
|
+ int ret;
|
|
|
+ u16 scan_options = 0;
|
|
|
+
|
|
|
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
|
|
+ trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
|
|
|
+ if (!cmd || !trigger) {
|
|
|
+ ret = -ENOMEM;
|
|
|
+ goto out;
|
|
|
}
|
|
|
|
|
|
- ret = wl1271_cmd_build_probe_req(wl, ssid, ssid_len,
|
|
|
- req->ie, req->ie_len, ieee_band);
|
|
|
- if (ret < 0) {
|
|
|
- wl1271_error("PROBE request template failed");
|
|
|
+ /* We always use high priority scans */
|
|
|
+ scan_options = WL1271_SCAN_OPT_PRIORITY_HIGH;
|
|
|
+ if(passive)
|
|
|
+ scan_options |= WL1271_SCAN_OPT_PASSIVE;
|
|
|
+ cmd->params.scan_options = cpu_to_le16(scan_options);
|
|
|
+
|
|
|
+ cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req,
|
|
|
+ cmd->channels,
|
|
|
+ band, passive);
|
|
|
+ if (cmd->params.n_ch == 0) {
|
|
|
+ ret = WL1271_NOTHING_TO_SCAN;
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
|
|
|
- if (!trigger) {
|
|
|
- ret = -ENOMEM;
|
|
|
+ cmd->params.tx_rate = cpu_to_le32(basic_rate);
|
|
|
+ cmd->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD);
|
|
|
+ cmd->params.rx_filter_options =
|
|
|
+ cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN);
|
|
|
+
|
|
|
+ cmd->params.n_probe_reqs = WL1271_SCAN_PROBE_REQS;
|
|
|
+ cmd->params.tx_rate = cpu_to_le32(basic_rate);
|
|
|
+ cmd->params.tid_trigger = 0;
|
|
|
+ cmd->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;
|
|
|
+
|
|
|
+ if (band == IEEE80211_BAND_2GHZ)
|
|
|
+ cmd->params.band = WL1271_SCAN_BAND_2_4_GHZ;
|
|
|
+ else
|
|
|
+ cmd->params.band = WL1271_SCAN_BAND_5_GHZ;
|
|
|
+
|
|
|
+ if (wl->scan.ssid_len && wl->scan.ssid) {
|
|
|
+ cmd->params.ssid_len = wl->scan.ssid_len;
|
|
|
+ memcpy(cmd->params.ssid, wl->scan.ssid, wl->scan.ssid_len);
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = wl1271_cmd_build_probe_req(wl, wl->scan.ssid, wl->scan.ssid_len,
|
|
|
+ wl->scan.req->ie, wl->scan.req->ie_len,
|
|
|
+ band);
|
|
|
+ if (ret < 0) {
|
|
|
+ wl1271_error("PROBE request template failed");
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
/* disable the timeout */
|
|
|
trigger->timeout = 0;
|
|
|
-
|
|
|
ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger,
|
|
|
sizeof(*trigger), 0);
|
|
|
if (ret < 0) {
|
|
@@ -132,60 +149,109 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- wl1271_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params));
|
|
|
-
|
|
|
- set_bit(WL1271_FLAG_SCANNING, &wl->flags);
|
|
|
- if (wl1271_11a_enabled()) {
|
|
|
- wl->scan.state = band;
|
|
|
- if (band == WL1271_SCAN_BAND_DUAL) {
|
|
|
- wl->scan.active = active_scan;
|
|
|
- wl->scan.high_prio = high_prio;
|
|
|
- wl->scan.probe_requests = probe_requests;
|
|
|
- if (ssid_len && ssid) {
|
|
|
- wl->scan.ssid_len = ssid_len;
|
|
|
- memcpy(wl->scan.ssid, ssid, ssid_len);
|
|
|
- } else
|
|
|
- wl->scan.ssid_len = 0;
|
|
|
- wl->scan.req = req;
|
|
|
- } else
|
|
|
- wl->scan.req = NULL;
|
|
|
- }
|
|
|
+ wl1271_dump(DEBUG_SCAN, "SCAN: ", cmd, sizeof(*cmd));
|
|
|
|
|
|
- ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params), 0);
|
|
|
+ ret = wl1271_cmd_send(wl, CMD_SCAN, cmd, sizeof(*cmd), 0);
|
|
|
if (ret < 0) {
|
|
|
wl1271_error("SCAN failed");
|
|
|
- clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
out:
|
|
|
- kfree(params);
|
|
|
+ kfree(cmd);
|
|
|
kfree(trigger);
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-int wl1271_scan_complete(struct wl1271 *wl)
|
|
|
+void wl1271_scan_stm(struct wl1271 *wl)
|
|
|
{
|
|
|
- if (test_bit(WL1271_FLAG_SCANNING, &wl->flags)) {
|
|
|
- if (wl->scan.state == WL1271_SCAN_BAND_DUAL) {
|
|
|
- /* 2.4 GHz band scanned, scan 5 GHz band, pretend to
|
|
|
- * the wl1271_scan function that we are not scanning
|
|
|
- * as it checks that.
|
|
|
- */
|
|
|
- clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
|
|
|
- /* FIXME: ie missing! */
|
|
|
- wl1271_scan(wl, wl->scan.ssid, wl->scan.ssid_len,
|
|
|
- wl->scan.req,
|
|
|
- wl->scan.active,
|
|
|
- wl->scan.high_prio,
|
|
|
- WL1271_SCAN_BAND_5_GHZ,
|
|
|
- wl->scan.probe_requests);
|
|
|
- } else {
|
|
|
- mutex_unlock(&wl->mutex);
|
|
|
- ieee80211_scan_completed(wl->hw, false);
|
|
|
- mutex_lock(&wl->mutex);
|
|
|
- clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ switch (wl->scan.state) {
|
|
|
+ case WL1271_SCAN_STATE_IDLE:
|
|
|
+ break;
|
|
|
+
|
|
|
+ case WL1271_SCAN_STATE_2GHZ_ACTIVE:
|
|
|
+ ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, false,
|
|
|
+ wl->conf.tx.basic_rate);
|
|
|
+ if (ret == WL1271_NOTHING_TO_SCAN) {
|
|
|
+ wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE;
|
|
|
+ wl1271_scan_stm(wl);
|
|
|
+ }
|
|
|
+
|
|
|
+ break;
|
|
|
+
|
|
|
+ case WL1271_SCAN_STATE_2GHZ_PASSIVE:
|
|
|
+ ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, true,
|
|
|
+ wl->conf.tx.basic_rate);
|
|
|
+ if (ret == WL1271_NOTHING_TO_SCAN) {
|
|
|
+ if (wl1271_11a_enabled())
|
|
|
+ wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE;
|
|
|
+ else
|
|
|
+ wl->scan.state = WL1271_SCAN_STATE_DONE;
|
|
|
+ wl1271_scan_stm(wl);
|
|
|
}
|
|
|
+
|
|
|
+ break;
|
|
|
+
|
|
|
+ case WL1271_SCAN_STATE_5GHZ_ACTIVE:
|
|
|
+ ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, false,
|
|
|
+ wl->conf.tx.basic_rate_5);
|
|
|
+ if (ret == WL1271_NOTHING_TO_SCAN) {
|
|
|
+ wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE;
|
|
|
+ wl1271_scan_stm(wl);
|
|
|
+ }
|
|
|
+
|
|
|
+ break;
|
|
|
+
|
|
|
+ case WL1271_SCAN_STATE_5GHZ_PASSIVE:
|
|
|
+ ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, true,
|
|
|
+ wl->conf.tx.basic_rate_5);
|
|
|
+ if (ret == WL1271_NOTHING_TO_SCAN) {
|
|
|
+ wl->scan.state = WL1271_SCAN_STATE_DONE;
|
|
|
+ wl1271_scan_stm(wl);
|
|
|
+ }
|
|
|
+
|
|
|
+ break;
|
|
|
+
|
|
|
+ case WL1271_SCAN_STATE_DONE:
|
|
|
+ mutex_unlock(&wl->mutex);
|
|
|
+ ieee80211_scan_completed(wl->hw, false);
|
|
|
+ mutex_lock(&wl->mutex);
|
|
|
+
|
|
|
+ kfree(wl->scan.scanned_ch);
|
|
|
+ wl->scan.scanned_ch = NULL;
|
|
|
+
|
|
|
+ wl->scan.state = WL1271_SCAN_STATE_IDLE;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ wl1271_error("invalid scan state");
|
|
|
+ break;
|
|
|
}
|
|
|
+}
|
|
|
+
|
|
|
+int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
|
|
|
+ struct cfg80211_scan_request *req)
|
|
|
+{
|
|
|
+ if (wl->scan.state != WL1271_SCAN_STATE_IDLE)
|
|
|
+ return -EBUSY;
|
|
|
+
|
|
|
+ wl->scan.state = WL1271_SCAN_STATE_2GHZ_ACTIVE;
|
|
|
+
|
|
|
+ if (ssid_len && ssid) {
|
|
|
+ wl->scan.ssid_len = ssid_len;
|
|
|
+ memcpy(wl->scan.ssid, ssid, ssid_len);
|
|
|
+ } else {
|
|
|
+ wl->scan.ssid_len = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ wl->scan.req = req;
|
|
|
+
|
|
|
+ wl->scan.scanned_ch = kzalloc(req->n_channels *
|
|
|
+ sizeof(*wl->scan.scanned_ch),
|
|
|
+ GFP_KERNEL);
|
|
|
+ wl1271_scan_stm(wl);
|
|
|
+
|
|
|
return 0;
|
|
|
}
|