Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=ece8edddf067d21c4e5abfe3f1205da1588edbb2
Commit:     ece8edddf067d21c4e5abfe3f1205da1588edbb2
Parent:     f68635e627f9b21db05102e2d8fcd2894493d6bc
Author:     Zhu Yi <[EMAIL PROTECTED]>
AuthorDate: Thu Nov 22 10:53:21 2007 +0800
Committer:  David S. Miller <[EMAIL PROTECTED]>
CommitDate: Mon Jan 28 14:55:27 2008 -0800

    mac80211: hardware scan rework
    
    The scan code in mac80211 makes the software scan assumption in various
    places. For example, we stop the Tx queue during a software scan so that
    all the Tx packets will be queued by the stack. We also drop frames not
    related to scan in the software scan process. But these are not true for
    hardware scan.
    
    Some wireless hardwares (for example iwl3945/4965) has the ability to
    perform the whole scan process by hardware and/or firmware. The hardware
    scan is relative powerful in that it tries to maintain normal network
    traffic while doing a scan in the background. Some drivers (i.e iwlwifi)
    do provide a way to tune the hardware scan parameters (for example if the
    STA is associated, what's the max time could the STA leave from the
    associated channel, how long the scans get suspended after returning to
    the service channel, etc). But basically this is transparent to the
    stack. mac80211 should not stop Tx queues or drop Rx packets during a
    hardware scan.
    
    This patch resolves the above problem by spliting the current scan
    indicator local->sta_scanning into local->sta_sw_scanning and
    local->sta_hw_scanning. It then changes the scan related code to be aware
    of hardware scan or software scan in various places. With this patch,
    iwlwifi performs much better in the scan-while-associated condition and
    disable_hw_scan=1 should never be required.
    
    Cc: Mohamed Abbas <[EMAIL PROTECTED]>
    Cc: Ben Cahill <[EMAIL PROTECTED]>
    Signed-off-by: Zhu Yi <[EMAIL PROTECTED]>
    Acked-by: Johannes Berg <[EMAIL PROTECTED]>
    Signed-off-by: John W. Linville <[EMAIL PROTECTED]>
    Signed-off-by: David S. Miller <[EMAIL PROTECTED]>
---
 net/mac80211/ieee80211.c       |   13 +++++---
 net/mac80211/ieee80211_i.h     |    6 ++-
 net/mac80211/ieee80211_ioctl.c |    6 ++-
 net/mac80211/ieee80211_sta.c   |   66 ++++++++++++++++++++++++++-------------
 net/mac80211/rx.c              |   12 +++++--
 net/mac80211/tx.c              |    2 +-
 6 files changed, 70 insertions(+), 35 deletions(-)

diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c
index 6378850..4f8b665 100644
--- a/net/mac80211/ieee80211.c
+++ b/net/mac80211/ieee80211.c
@@ -350,11 +350,14 @@ static int ieee80211_stop(struct net_device *dev)
                synchronize_rcu();
                skb_queue_purge(&sdata->u.sta.skb_queue);
 
-               if (!local->ops->hw_scan &&
-                   local->scan_dev == sdata->dev) {
-                       local->sta_scanning = 0;
-                       cancel_delayed_work(&local->scan_work);
+               if (local->scan_dev == sdata->dev) {
+                       if (!local->ops->hw_scan) {
+                               local->sta_sw_scanning = 0;
+                               cancel_delayed_work(&local->scan_work);
+                       } else
+                               local->sta_hw_scanning = 0;
                }
+
                flush_workqueue(local->hw.workqueue);
 
                sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED;
@@ -526,7 +529,7 @@ int ieee80211_hw_config(struct ieee80211_local *local)
        struct ieee80211_channel *chan;
        int ret = 0;
 
-       if (local->sta_scanning) {
+       if (local->sta_sw_scanning) {
                chan = local->scan_channel;
                mode = local->scan_hw_mode;
        } else {
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 2be7fce..e910944 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -470,7 +470,8 @@ struct ieee80211_local {
 
        struct list_head interfaces;
 
-       int sta_scanning;
+       bool sta_sw_scanning;
+       bool sta_hw_scanning;
        int scan_channel_idx;
        enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state;
        unsigned long last_scan_completed;
@@ -745,7 +746,8 @@ int ieee80211_sta_req_scan(struct net_device *dev, u8 
*ssid, size_t ssid_len);
 void ieee80211_sta_req_auth(struct net_device *dev,
                            struct ieee80211_if_sta *ifsta);
 int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len);
-void ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb,
+ieee80211_txrx_result ieee80211_sta_rx_scan(struct net_device *dev,
+                                           struct sk_buff *skb,
                           struct ieee80211_rx_status *rx_status);
 void ieee80211_rx_bss_list_init(struct net_device *dev);
 void ieee80211_rx_bss_list_deinit(struct net_device *dev);
diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c
index bbd9bc5..dc03bd7 100644
--- a/net/mac80211/ieee80211_ioctl.c
+++ b/net/mac80211/ieee80211_ioctl.c
@@ -315,7 +315,7 @@ int ieee80211_set_channel(struct ieee80211_local *local, 
int channel, int freq)
        }
 
        if (set) {
-               if (local->sta_scanning)
+               if (local->sta_sw_scanning)
                        ret = 0;
                else
                        ret = ieee80211_hw_config(local);
@@ -545,8 +545,10 @@ static int ieee80211_ioctl_giwscan(struct net_device *dev,
 {
        int res;
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       if (local->sta_scanning)
+
+       if (local->sta_sw_scanning || local->sta_hw_scanning)
                return -EAGAIN;
+
        res = ieee80211_sta_scan_results(dev, extra, data->length);
        if (res >= 0) {
                data->length = res;
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
index 4f9be2f..231a663 100644
--- a/net/mac80211/ieee80211_sta.c
+++ b/net/mac80211/ieee80211_sta.c
@@ -1483,8 +1483,18 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
                u32 supp_rates, prev_rates;
                int i, j;
 
-               mode = local->sta_scanning ?
+               mode = local->sta_sw_scanning ?
                       local->scan_hw_mode : local->oper_hw_mode;
+
+               if (local->sta_hw_scanning) {
+                       /* search for the correct mode matches the beacon */
+                       list_for_each_entry(mode, &local->modes_list, list)
+                               if (mode->mode == rx_status->phymode)
+                                       break;
+
+                       if (mode == NULL)
+                               mode = local->oper_hw_mode;
+               }
                rates = mode->rates;
                num_rates = mode->num_rates;
 
@@ -1867,31 +1877,39 @@ static void ieee80211_sta_rx_queued_mgmt(struct 
net_device *dev,
 }
 
 
-void ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb,
-                          struct ieee80211_rx_status *rx_status)
+ieee80211_txrx_result
+ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb,
+                     struct ieee80211_rx_status *rx_status)
 {
        struct ieee80211_mgmt *mgmt;
        u16 fc;
 
-       if (skb->len < 24) {
-               dev_kfree_skb(skb);
-               return;
-       }
+       if (skb->len < 2)
+               return TXRX_DROP;
 
        mgmt = (struct ieee80211_mgmt *) skb->data;
        fc = le16_to_cpu(mgmt->frame_control);
 
+       if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL)
+               return TXRX_CONTINUE;
+
+       if (skb->len < 24)
+               return TXRX_DROP;
+
        if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
                if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP) {
                        ieee80211_rx_mgmt_probe_resp(dev, mgmt,
                                                     skb->len, rx_status);
+                       dev_kfree_skb(skb);
+                       return TXRX_QUEUED;
                } else if ((fc & IEEE80211_FCTL_STYPE) == 
IEEE80211_STYPE_BEACON) {
                        ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len,
                                                 rx_status);
+                       dev_kfree_skb(skb);
+                       return TXRX_QUEUED;
                }
        }
-
-       dev_kfree_skb(skb);
+       return TXRX_CONTINUE;
 }
 
 
@@ -1981,7 +1999,7 @@ void ieee80211_sta_work(struct work_struct *work)
        if (!netif_running(dev))
                return;
 
-       if (local->sta_scanning)
+       if (local->sta_sw_scanning || local->sta_hw_scanning)
                return;
 
        if (sdata->type != IEEE80211_IF_TYPE_STA &&
@@ -2639,9 +2657,15 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw)
        union iwreq_data wrqu;
 
        local->last_scan_completed = jiffies;
-       wmb();
-       local->sta_scanning = 0;
+       memset(&wrqu, 0, sizeof(wrqu));
+       wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
 
+       if (local->sta_hw_scanning) {
+               local->sta_hw_scanning = 0;
+               goto done;
+       }
+
+       local->sta_sw_scanning = 0;
        if (ieee80211_hw_config(local))
                printk(KERN_DEBUG "%s: failed to restore operational "
                       "channel after scan\n", dev->name);
@@ -2657,9 +2681,6 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw)
 
        netif_tx_unlock_bh(local->mdev);
 
-       memset(&wrqu, 0, sizeof(wrqu));
-       wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
-
        rcu_read_lock();
        list_for_each_entry_rcu(sdata, &local->interfaces, list) {
 
@@ -2677,6 +2698,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw)
        }
        rcu_read_unlock();
 
+done:
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        if (sdata->type == IEEE80211_IF_TYPE_IBSS) {
                struct ieee80211_if_sta *ifsta = &sdata->u.sta;
@@ -2699,7 +2721,7 @@ void ieee80211_sta_scan_work(struct work_struct *work)
        int skip;
        unsigned long next_delay = 0;
 
-       if (!local->sta_scanning)
+       if (!local->sta_sw_scanning)
                return;
 
        switch (local->scan_state) {
@@ -2762,7 +2784,7 @@ void ieee80211_sta_scan_work(struct work_struct *work)
                break;
        }
 
-       if (local->sta_scanning)
+       if (local->sta_sw_scanning)
                queue_delayed_work(local->hw.workqueue, &local->scan_work,
                                   next_delay);
 }
@@ -2794,7 +2816,7 @@ static int ieee80211_sta_start_scan(struct net_device 
*dev,
          * ResultCode: SUCCESS, INVALID_PARAMETERS
         */
 
-       if (local->sta_scanning) {
+       if (local->sta_sw_scanning || local->sta_hw_scanning) {
                if (local->scan_dev == dev)
                        return 0;
                return -EBUSY;
@@ -2802,15 +2824,15 @@ static int ieee80211_sta_start_scan(struct net_device 
*dev,
 
        if (local->ops->hw_scan) {
                int rc = local->ops->hw_scan(local_to_hw(local),
-                                           ssid, ssid_len);
+                                            ssid, ssid_len);
                if (!rc) {
-                       local->sta_scanning = 1;
+                       local->sta_hw_scanning = 1;
                        local->scan_dev = dev;
                }
                return rc;
        }
 
-       local->sta_scanning = 1;
+       local->sta_sw_scanning = 1;
 
        rcu_read_lock();
        list_for_each_entry_rcu(sdata, &local->interfaces, list) {
@@ -2865,7 +2887,7 @@ int ieee80211_sta_req_scan(struct net_device *dev, u8 
*ssid, size_t ssid_len)
        if (sdata->type != IEEE80211_IF_TYPE_STA)
                return ieee80211_sta_start_scan(dev, ssid, ssid_len);
 
-       if (local->sta_scanning) {
+       if (local->sta_sw_scanning || local->sta_hw_scanning) {
                if (local->scan_dev == dev)
                        return 0;
                return -EBUSY;
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index a7263fc..a26aa7f 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -338,8 +338,14 @@ ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx)
        struct ieee80211_local *local = rx->local;
        struct sk_buff *skb = rx->skb;
 
-       if (unlikely(local->sta_scanning != 0)) {
-               ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status);
+       if (unlikely(local->sta_hw_scanning))
+               return ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status);
+
+       if (unlikely(local->sta_sw_scanning)) {
+               /* drop all the other packets during a software scan anyway */
+               if (ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status)
+                   != TXRX_QUEUED)
+                       dev_kfree_skb(skb);
                return TXRX_QUEUED;
        }
 
@@ -1499,7 +1505,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct 
sk_buff *skb,
                goto end;
        }
 
-       if (unlikely(local->sta_scanning))
+       if (unlikely(local->sta_sw_scanning || local->sta_hw_scanning))
                rx.flags |= IEEE80211_TXRXD_RXIN_SCAN;
 
        if (__ieee80211_invoke_rx_handlers(local, local->rx_pre_handlers, &rx,
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 9ccf4b5..50ab4b2 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -225,7 +225,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx)
        if (unlikely(tx->flags & IEEE80211_TXRXD_TX_INJECTED))
                return TXRX_CONTINUE;
 
-       if (unlikely(tx->local->sta_scanning != 0) &&
+       if (unlikely(tx->local->sta_sw_scanning) &&
            ((tx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
             (tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ))
                return TXRX_DROP;
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to