Merge git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
[firefly-linux-kernel-4.4.55.git] / net / mac80211 / scan.c
index c70e176771359b5e9371df1da486b29a157084f7..169da0742c817507e09a0119f1d1105077784231 100644 (file)
 #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;