aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/scan.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/scan.c')
-rw-r--r--net/mac80211/scan.c140
1 files changed, 98 insertions, 42 deletions
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index c70e17677135..169da0742c81 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -29,20 +29,6 @@
#define IEEE80211_CHANNEL_TIME (HZ / 33)
#define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 8)
-struct ieee80211_bss *
-ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq,
- u8 *ssid, u8 ssid_len)
-{
- struct cfg80211_bss *cbss;
-
- cbss = cfg80211_get_bss(local->hw.wiphy,
- ieee80211_get_channel(local->hw.wiphy, freq),
- bssid, ssid, ssid_len, 0, 0);
- if (!cbss)
- return NULL;
- return (void *)cbss->priv;
-}
-
static void ieee80211_rx_bss_free(struct cfg80211_bss *cbss)
{
struct ieee80211_bss *bss = (void *)cbss->priv;
@@ -208,7 +194,7 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
presp = ieee80211_is_probe_resp(fc);
if (presp) {
/* ignore ProbeResp to foreign address */
- if (compare_ether_addr(mgmt->da, sdata->vif.addr))
+ if (!ether_addr_equal(mgmt->da, sdata->vif.addr))
return RX_DROP_MONITOR;
presp = true;
@@ -387,6 +373,57 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
return 0;
}
+static bool ieee80211_can_scan(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata)
+{
+ if (!list_empty(&local->work_list))
+ return false;
+
+ if (sdata->vif.type == NL80211_IFTYPE_STATION &&
+ sdata->u.mgd.flags & (IEEE80211_STA_BEACON_POLL |
+ IEEE80211_STA_CONNECTION_POLL))
+ return false;
+
+ return true;
+}
+
+void ieee80211_run_deferred_scan(struct ieee80211_local *local)
+{
+ lockdep_assert_held(&local->mtx);
+
+ if (!local->scan_req || local->scanning)
+ return;
+
+ if (!ieee80211_can_scan(local, local->scan_sdata))
+ return;
+
+ ieee80211_queue_delayed_work(&local->hw, &local->scan_work,
+ round_jiffies_relative(0));
+}
+
+static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
+ unsigned long *next_delay)
+{
+ int i;
+ struct ieee80211_sub_if_data *sdata = local->scan_sdata;
+ enum ieee80211_band band = local->hw.conf.channel->band;
+
+ for (i = 0; i < local->scan_req->n_ssids; i++)
+ ieee80211_send_probe_req(
+ sdata, NULL,
+ local->scan_req->ssids[i].ssid,
+ local->scan_req->ssids[i].ssid_len,
+ local->scan_req->ie, local->scan_req->ie_len,
+ local->scan_req->rates[band], false,
+ local->scan_req->no_cck);
+
+ /*
+ * After sending probe requests, wait for probe responses
+ * on the channel.
+ */
+ *next_delay = IEEE80211_CHANNEL_TIME;
+ local->next_scan_state = SCAN_DECISION;
+}
static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
struct cfg80211_scan_request *req)
@@ -399,7 +436,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
if (local->scan_req)
return -EBUSY;
- if (!list_empty(&local->work_list)) {
+ if (!ieee80211_can_scan(local, sdata)) {
/* wait for the work to finish/time out */
local->scan_req = req;
local->scan_sdata = sdata;
@@ -438,10 +475,47 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
local->scan_req = req;
local->scan_sdata = sdata;
- if (local->ops->hw_scan)
+ if (local->ops->hw_scan) {
__set_bit(SCAN_HW_SCANNING, &local->scanning);
- else
+ } else if ((req->n_channels == 1) &&
+ (req->channels[0]->center_freq ==
+ local->hw.conf.channel->center_freq)) {
+
+ /* If we are scanning only on the current channel, then
+ * we do not need to stop normal activities
+ */
+ unsigned long next_delay;
+
+ __set_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning);
+
+ ieee80211_recalc_idle(local);
+
+ /* Notify driver scan is starting, keep order of operations
+ * same as normal software scan, in case that matters. */
+ drv_sw_scan_start(local);
+
+ ieee80211_configure_filter(local); /* accept probe-responses */
+
+ /* We need to ensure power level is at max for scanning. */
+ ieee80211_hw_config(local, 0);
+
+ if ((req->channels[0]->flags &
+ IEEE80211_CHAN_PASSIVE_SCAN) ||
+ !local->scan_req->n_ssids) {
+ next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
+ } else {
+ ieee80211_scan_state_send_probe(local, &next_delay);
+ next_delay = IEEE80211_CHANNEL_TIME;
+ }
+
+ /* Now, just wait a bit and we are all done! */
+ ieee80211_queue_delayed_work(&local->hw, &local->scan_work,
+ next_delay);
+ return 0;
+ } else {
+ /* Do normal software scan */
__set_bit(SCAN_SW_SCANNING, &local->scanning);
+ }
ieee80211_recalc_idle(local);
@@ -598,30 +672,6 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
local->next_scan_state = SCAN_SEND_PROBE;
}
-static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
- unsigned long *next_delay)
-{
- int i;
- struct ieee80211_sub_if_data *sdata = local->scan_sdata;
- enum ieee80211_band band = local->hw.conf.channel->band;
-
- for (i = 0; i < local->scan_req->n_ssids; i++)
- ieee80211_send_probe_req(
- sdata, NULL,
- local->scan_req->ssids[i].ssid,
- local->scan_req->ssids[i].ssid_len,
- local->scan_req->ie, local->scan_req->ie_len,
- local->scan_req->rates[band], false,
- local->scan_req->no_cck);
-
- /*
- * After sending probe requests, wait for probe responses
- * on the channel.
- */
- *next_delay = IEEE80211_CHANNEL_TIME;
- local->next_scan_state = SCAN_DECISION;
-}
-
static void ieee80211_scan_state_suspend(struct ieee80211_local *local,
unsigned long *next_delay)
{
@@ -672,6 +722,12 @@ void ieee80211_scan_work(struct work_struct *work)
sdata = local->scan_sdata;
+ /* When scanning on-channel, the first-callback means completed. */
+ if (test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning)) {
+ aborted = test_and_clear_bit(SCAN_ABORTED, &local->scanning);
+ goto out_complete;
+ }
+
if (test_and_clear_bit(SCAN_COMPLETED, &local->scanning)) {
aborted = test_and_clear_bit(SCAN_ABORTED, &local->scanning);
goto out_complete;