mac80211: remove bogus code
[safe/jmp/linux-2.6] / net / mac80211 / scan.c
index d56b9da..c46ac01 100644 (file)
  * published by the Free Software Foundation.
  */
 
-/* TODO: figure out how to avoid that the "current BSS" expires */
-
 #include <linux/wireless.h>
 #include <linux/if_arp.h>
 #include <linux/rtnetlink.h>
 #include <net/mac80211.h>
-#include <net/iw_handler.h>
 
 #include "ieee80211_i.h"
 #include "driver-ops.h"
@@ -91,8 +88,8 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
                bss->dtim_period = tim_ie->dtim_period;
        }
 
-       /* set default value for buggy APs */
-       if (!elems->tim || bss->dtim_period == 0)
+       /* set default value for buggy AP/no TIM element */
+       if (bss->dtim_period == 0)
                bss->dtim_period = 1;
 
        bss->supp_rates_len = 0;
@@ -190,6 +187,39 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
        return RX_QUEUED;
 }
 
+/* return false if no more work */
+static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
+{
+       struct cfg80211_scan_request *req = local->scan_req;
+       enum ieee80211_band band;
+       int i, ielen, n_chans;
+
+       do {
+               if (local->hw_scan_band == IEEE80211_NUM_BANDS)
+                       return false;
+
+               band = local->hw_scan_band;
+               n_chans = 0;
+               for (i = 0; i < req->n_channels; i++) {
+                       if (req->channels[i]->band == band) {
+                               local->hw_scan_req->channels[n_chans] =
+                                                       req->channels[i];
+                               n_chans++;
+                       }
+               }
+
+               local->hw_scan_band++;
+       } while (!n_chans);
+
+       local->hw_scan_req->n_channels = n_chans;
+
+       ielen = ieee80211_build_preq_ies(local, (u8 *)local->hw_scan_req->ie,
+                                        req->ie, req->ie_len, band);
+       local->hw_scan_req->ie_len = ielen;
+
+       return true;
+}
+
 /*
  * inform AP that we will go to sleep so that it will buffer the frames
  * while we scan
@@ -250,13 +280,6 @@ static void ieee80211_scan_ps_disable(struct ieee80211_sub_if_data *sdata)
        }
 }
 
-static void ieee80211_restore_scan_ies(struct ieee80211_local *local)
-{
-       kfree(local->scan_req->ie);
-       local->scan_req->ie = local->orig_ies;
-       local->scan_req->ie_len = local->orig_ies_len;
-}
-
 void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
 {
        struct ieee80211_local *local = hw_to_local(hw);
@@ -275,14 +298,22 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
                return;
        }
 
-       if (test_bit(SCAN_HW_SCANNING, &local->scanning))
-               ieee80211_restore_scan_ies(local);
+       was_hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning);
+       if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) {
+               ieee80211_queue_delayed_work(&local->hw,
+                                            &local->scan_work, 0);
+               mutex_unlock(&local->scan_mtx);
+               return;
+       }
 
-       if (local->scan_req != &local->int_scan_req)
+       kfree(local->hw_scan_req);
+       local->hw_scan_req = NULL;
+
+       if (local->scan_req != local->int_scan_req)
                cfg80211_scan_done(local->scan_req, aborted);
        local->scan_req = NULL;
+       local->scan_sdata = NULL;
 
-       was_hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning);
        local->scanning = 0;
        local->scan_channel = NULL;
 
@@ -293,13 +324,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
        if (was_hw_scan)
                goto done;
 
-       spin_lock_bh(&local->filter_lock);
-       local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC;
-       drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC,
-                            &local->filter_flags,
-                            local->mc_count,
-                            local->mc_list);
-       spin_unlock_bh(&local->filter_lock);
+       ieee80211_configure_filter(local);
 
        drv_sw_scan_complete(local);
 
@@ -312,10 +337,10 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
                if (sdata->vif.type == NL80211_IFTYPE_STATION) {
                        if (sdata->u.mgd.associated) {
                                ieee80211_scan_ps_disable(sdata);
-                               netif_tx_wake_all_queues(sdata->dev);
+                               netif_wake_queue(sdata->dev);
                        }
                } else
-                       netif_tx_wake_all_queues(sdata->dev);
+                       netif_wake_queue(sdata->dev);
 
                /* re-enable beaconing */
                if (sdata->vif.type == NL80211_IFTYPE_AP ||
@@ -370,24 +395,19 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
                 * are handled in the scan state machine
                 */
                if (sdata->vif.type != NL80211_IFTYPE_STATION)
-                       netif_tx_stop_all_queues(sdata->dev);
+                       netif_stop_queue(sdata->dev);
        }
        mutex_unlock(&local->iflist_mtx);
 
-       local->scan_state = SCAN_DECISION;
+       local->next_scan_state = SCAN_DECISION;
        local->scan_channel_idx = 0;
 
-       spin_lock_bh(&local->filter_lock);
-       local->filter_flags |= FIF_BCN_PRBRESP_PROMISC;
-       drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC,
-                            &local->filter_flags,
-                            local->mc_count,
-                            local->mc_list);
-       spin_unlock_bh(&local->filter_lock);
+       ieee80211_configure_filter(local);
 
        /* TODO: start scan as soon as all nullfunc frames are ACKed */
-       queue_delayed_work(local->hw.workqueue, &local->scan_work,
-                          IEEE80211_CHANNEL_TIME);
+       ieee80211_queue_delayed_work(&local->hw,
+                                    &local->scan_work,
+                                    IEEE80211_CHANNEL_TIME);
 
        return 0;
 }
@@ -405,25 +425,29 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
 
        if (local->ops->hw_scan) {
                u8 *ies;
-               int ielen;
 
-               ies = kmalloc(2 + IEEE80211_MAX_SSID_LEN +
-                             local->scan_ies_len + req->ie_len, GFP_KERNEL);
-               if (!ies)
+               local->hw_scan_req = kmalloc(
+                               sizeof(*local->hw_scan_req) +
+                               req->n_channels * sizeof(req->channels[0]) +
+                               2 + IEEE80211_MAX_SSID_LEN + local->scan_ies_len +
+                               req->ie_len, GFP_KERNEL);
+               if (!local->hw_scan_req)
                        return -ENOMEM;
 
-               ielen = ieee80211_build_preq_ies(local, ies,
-                                                req->ie, req->ie_len);
-               local->orig_ies = req->ie;
-               local->orig_ies_len = req->ie_len;
-               req->ie = ies;
-               req->ie_len = ielen;
+               local->hw_scan_req->ssids = req->ssids;
+               local->hw_scan_req->n_ssids = req->n_ssids;
+               ies = (u8 *)local->hw_scan_req +
+                       sizeof(*local->hw_scan_req) +
+                       req->n_channels * sizeof(req->channels[0]);
+               local->hw_scan_req->ie = ies;
+
+               local->hw_scan_band = 0;
        }
 
        local->scan_req = req;
        local->scan_sdata = sdata;
 
-       if (req != &local->int_scan_req &&
+       if (req != local->int_scan_req &&
            sdata->vif.type == NL80211_IFTYPE_STATION &&
            !list_empty(&ifmgd->work_list)) {
                /* actually wait for the work it's doing to finish/time out */
@@ -449,16 +473,17 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
        ieee80211_recalc_idle(local);
        mutex_unlock(&local->scan_mtx);
 
-       if (local->ops->hw_scan)
-               rc = drv_hw_scan(local, local->scan_req);
-       else
+       if (local->ops->hw_scan) {
+               WARN_ON(!ieee80211_prep_hw_scan(local));
+               rc = drv_hw_scan(local, local->hw_scan_req);
+       } else
                rc = ieee80211_start_sw_scan(local);
 
        mutex_lock(&local->scan_mtx);
 
        if (rc) {
-               if (local->ops->hw_scan)
-                       ieee80211_restore_scan_ies(local);
+               kfree(local->hw_scan_req);
+               local->hw_scan_req = NULL;
                local->scanning = 0;
 
                ieee80211_recalc_idle(local);
@@ -505,15 +530,15 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local,
                 * next channel
                 */
                if (associated)
-                       local->scan_state = SCAN_ENTER_OPER_CHANNEL;
+                       local->next_scan_state = SCAN_ENTER_OPER_CHANNEL;
                else
-                       local->scan_state = SCAN_SET_CHANNEL;
+                       local->next_scan_state = SCAN_SET_CHANNEL;
        } else {
                /*
                 * we're on the operating channel currently, let's
                 * leave that channel now to scan another one
                 */
-               local->scan_state = SCAN_LEAVE_OPER_CHANNEL;
+               local->next_scan_state = SCAN_LEAVE_OPER_CHANNEL;
        }
 
        *next_delay = 0;
@@ -534,7 +559,7 @@ static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *loca
                        continue;
 
                if (sdata->vif.type == NL80211_IFTYPE_STATION) {
-                       netif_tx_stop_all_queues(sdata->dev);
+                       netif_stop_queue(sdata->dev);
                        if (sdata->u.mgd.associated)
                                ieee80211_scan_ps_enable(sdata);
                }
@@ -545,7 +570,7 @@ static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *loca
 
        /* advance to the next channel to be scanned */
        *next_delay = HZ / 10;
-       local->scan_state = SCAN_SET_CHANNEL;
+       local->next_scan_state = SCAN_SET_CHANNEL;
 }
 
 static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *local,
@@ -569,7 +594,7 @@ static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *loca
                if (sdata->vif.type == NL80211_IFTYPE_STATION) {
                        if (sdata->u.mgd.associated)
                                ieee80211_scan_ps_disable(sdata);
-                       netif_tx_wake_all_queues(sdata->dev);
+                       netif_wake_queue(sdata->dev);
                }
        }
        mutex_unlock(&local->iflist_mtx);
@@ -577,7 +602,7 @@ static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *loca
        __clear_bit(SCAN_OFF_CHANNEL, &local->scanning);
 
        *next_delay = HZ / 5;
-       local->scan_state = SCAN_DECISION;
+       local->next_scan_state = SCAN_DECISION;
 }
 
 static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
@@ -605,8 +630,11 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
        /* advance state machine to next channel/band */
        local->scan_channel_idx++;
 
-       if (skip)
+       if (skip) {
+               /* if we skip this channel return to the decision state */
+               local->next_scan_state = SCAN_DECISION;
                return;
+       }
 
        /*
         * Probe delay is used to update the NAV, cf. 11.1.3.2.2
@@ -621,13 +649,13 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
        if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN ||
            !local->scan_req->n_ssids) {
                *next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
-               local->scan_state = SCAN_DECISION;
+               local->next_scan_state = SCAN_DECISION;
                return;
        }
 
        /* active scan, send probes */
        *next_delay = IEEE80211_PROBE_DELAY;
-       local->scan_state = SCAN_SEND_PROBE;
+       local->next_scan_state = SCAN_SEND_PROBE;
 }
 
 static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
@@ -648,7 +676,7 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
         * on the channel.
         */
        *next_delay = IEEE80211_CHANNEL_TIME;
-       local->scan_state = SCAN_DECISION;
+       local->next_scan_state = SCAN_DECISION;
 }
 
 void ieee80211_scan_work(struct work_struct *work)
@@ -664,11 +692,20 @@ void ieee80211_scan_work(struct work_struct *work)
                return;
        }
 
+       if (local->hw_scan_req) {
+               int rc = drv_hw_scan(local, local->hw_scan_req);
+               mutex_unlock(&local->scan_mtx);
+               if (rc)
+                       ieee80211_scan_completed(&local->hw, true);
+               return;
+       }
+
        if (local->scan_req && !local->scanning) {
                struct cfg80211_scan_request *req = local->scan_req;
                int rc;
 
                local->scan_req = NULL;
+               local->scan_sdata = NULL;
 
                rc = __ieee80211_start_scan(sdata, req);
                mutex_unlock(&local->scan_mtx);
@@ -693,7 +730,7 @@ void ieee80211_scan_work(struct work_struct *work)
         * without scheduling a new work
         */
        do {
-               switch (local->scan_state) {
+               switch (local->next_scan_state) {
                case SCAN_DECISION:
                        if (ieee80211_scan_state_decision(local, &next_delay))
                                return;
@@ -713,8 +750,7 @@ void ieee80211_scan_work(struct work_struct *work)
                }
        } while (next_delay == 0);
 
-       queue_delayed_work(local->hw.workqueue, &local->scan_work,
-                          next_delay);
+       ieee80211_queue_delayed_work(&local->hw, &local->scan_work, next_delay);
 }
 
 int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
@@ -741,10 +777,10 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
        if (local->scan_req)
                goto unlock;
 
-       memcpy(local->int_scan_req.ssids[0].ssid, ssid, IEEE80211_MAX_SSID_LEN);
-       local->int_scan_req.ssids[0].ssid_len = ssid_len;
+       memcpy(local->int_scan_req->ssids[0].ssid, ssid, IEEE80211_MAX_SSID_LEN);
+       local->int_scan_req->ssids[0].ssid_len = ssid_len;
 
-       ret = __ieee80211_start_scan(sdata, &sdata->local->int_scan_req);
+       ret = __ieee80211_start_scan(sdata, sdata->local->int_scan_req);
  unlock:
        mutex_unlock(&local->scan_mtx);
        return ret;
@@ -752,7 +788,7 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
 
 void ieee80211_scan_cancel(struct ieee80211_local *local)
 {
-       bool swscan;
+       bool abortscan;
 
        cancel_delayed_work_sync(&local->scan_work);
 
@@ -761,9 +797,10 @@ void ieee80211_scan_cancel(struct ieee80211_local *local)
         * queued -- mostly at suspend under RTNL.
         */
        mutex_lock(&local->scan_mtx);
-       swscan = test_bit(SCAN_SW_SCANNING, &local->scanning);
+       abortscan = test_bit(SCAN_SW_SCANNING, &local->scanning) ||
+                   (!local->scanning && local->scan_req);
        mutex_unlock(&local->scan_mtx);
 
-       if (swscan)
+       if (abortscan)
                ieee80211_scan_completed(&local->hw, true);
 }