diff options
author | Zhu Yi <yi.zhu@intel.com> | 2007-11-21 21:53:21 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 17:55:27 -0500 |
commit | ece8edddf067d21c4e5abfe3f1205da1588edbb2 (patch) | |
tree | 25450d1aedc630a538ca2f13aa0fa47100256182 /net/mac80211/ieee80211_sta.c | |
parent | f68635e627f9b21db05102e2d8fcd2894493d6bc (diff) |
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 <mohamed.abbas@intel.com>
Cc: Ben Cahill <ben.m.cahill@intel.com>
Signed-off-by: Zhu Yi <yi.zhu@intel.com>
Acked-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/mac80211/ieee80211_sta.c')
-rw-r--r-- | net/mac80211/ieee80211_sta.c | 66 |
1 files changed, 44 insertions, 22 deletions
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 4f9be2fb2bfc..231a663ad914 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, | |||
1483 | u32 supp_rates, prev_rates; | 1483 | u32 supp_rates, prev_rates; |
1484 | int i, j; | 1484 | int i, j; |
1485 | 1485 | ||
1486 | mode = local->sta_scanning ? | 1486 | mode = local->sta_sw_scanning ? |
1487 | local->scan_hw_mode : local->oper_hw_mode; | 1487 | local->scan_hw_mode : local->oper_hw_mode; |
1488 | |||
1489 | if (local->sta_hw_scanning) { | ||
1490 | /* search for the correct mode matches the beacon */ | ||
1491 | list_for_each_entry(mode, &local->modes_list, list) | ||
1492 | if (mode->mode == rx_status->phymode) | ||
1493 | break; | ||
1494 | |||
1495 | if (mode == NULL) | ||
1496 | mode = local->oper_hw_mode; | ||
1497 | } | ||
1488 | rates = mode->rates; | 1498 | rates = mode->rates; |
1489 | num_rates = mode->num_rates; | 1499 | num_rates = mode->num_rates; |
1490 | 1500 | ||
@@ -1867,31 +1877,39 @@ static void ieee80211_sta_rx_queued_mgmt(struct net_device *dev, | |||
1867 | } | 1877 | } |
1868 | 1878 | ||
1869 | 1879 | ||
1870 | void ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb, | 1880 | ieee80211_txrx_result |
1871 | struct ieee80211_rx_status *rx_status) | 1881 | ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb, |
1882 | struct ieee80211_rx_status *rx_status) | ||
1872 | { | 1883 | { |
1873 | struct ieee80211_mgmt *mgmt; | 1884 | struct ieee80211_mgmt *mgmt; |
1874 | u16 fc; | 1885 | u16 fc; |
1875 | 1886 | ||
1876 | if (skb->len < 24) { | 1887 | if (skb->len < 2) |
1877 | dev_kfree_skb(skb); | 1888 | return TXRX_DROP; |
1878 | return; | ||
1879 | } | ||
1880 | 1889 | ||
1881 | mgmt = (struct ieee80211_mgmt *) skb->data; | 1890 | mgmt = (struct ieee80211_mgmt *) skb->data; |
1882 | fc = le16_to_cpu(mgmt->frame_control); | 1891 | fc = le16_to_cpu(mgmt->frame_control); |
1883 | 1892 | ||
1893 | if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) | ||
1894 | return TXRX_CONTINUE; | ||
1895 | |||
1896 | if (skb->len < 24) | ||
1897 | return TXRX_DROP; | ||
1898 | |||
1884 | if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { | 1899 | if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { |
1885 | if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP) { | 1900 | if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP) { |
1886 | ieee80211_rx_mgmt_probe_resp(dev, mgmt, | 1901 | ieee80211_rx_mgmt_probe_resp(dev, mgmt, |
1887 | skb->len, rx_status); | 1902 | skb->len, rx_status); |
1903 | dev_kfree_skb(skb); | ||
1904 | return TXRX_QUEUED; | ||
1888 | } else if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) { | 1905 | } else if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) { |
1889 | ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len, | 1906 | ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len, |
1890 | rx_status); | 1907 | rx_status); |
1908 | dev_kfree_skb(skb); | ||
1909 | return TXRX_QUEUED; | ||
1891 | } | 1910 | } |
1892 | } | 1911 | } |
1893 | 1912 | return TXRX_CONTINUE; | |
1894 | dev_kfree_skb(skb); | ||
1895 | } | 1913 | } |
1896 | 1914 | ||
1897 | 1915 | ||
@@ -1981,7 +1999,7 @@ void ieee80211_sta_work(struct work_struct *work) | |||
1981 | if (!netif_running(dev)) | 1999 | if (!netif_running(dev)) |
1982 | return; | 2000 | return; |
1983 | 2001 | ||
1984 | if (local->sta_scanning) | 2002 | if (local->sta_sw_scanning || local->sta_hw_scanning) |
1985 | return; | 2003 | return; |
1986 | 2004 | ||
1987 | if (sdata->type != IEEE80211_IF_TYPE_STA && | 2005 | if (sdata->type != IEEE80211_IF_TYPE_STA && |
@@ -2639,9 +2657,15 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) | |||
2639 | union iwreq_data wrqu; | 2657 | union iwreq_data wrqu; |
2640 | 2658 | ||
2641 | local->last_scan_completed = jiffies; | 2659 | local->last_scan_completed = jiffies; |
2642 | wmb(); | 2660 | memset(&wrqu, 0, sizeof(wrqu)); |
2643 | local->sta_scanning = 0; | 2661 | wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); |
2644 | 2662 | ||
2663 | if (local->sta_hw_scanning) { | ||
2664 | local->sta_hw_scanning = 0; | ||
2665 | goto done; | ||
2666 | } | ||
2667 | |||
2668 | local->sta_sw_scanning = 0; | ||
2645 | if (ieee80211_hw_config(local)) | 2669 | if (ieee80211_hw_config(local)) |
2646 | printk(KERN_DEBUG "%s: failed to restore operational " | 2670 | printk(KERN_DEBUG "%s: failed to restore operational " |
2647 | "channel after scan\n", dev->name); | 2671 | "channel after scan\n", dev->name); |
@@ -2657,9 +2681,6 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) | |||
2657 | 2681 | ||
2658 | netif_tx_unlock_bh(local->mdev); | 2682 | netif_tx_unlock_bh(local->mdev); |
2659 | 2683 | ||
2660 | memset(&wrqu, 0, sizeof(wrqu)); | ||
2661 | wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); | ||
2662 | |||
2663 | rcu_read_lock(); | 2684 | rcu_read_lock(); |
2664 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | 2685 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
2665 | 2686 | ||
@@ -2677,6 +2698,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) | |||
2677 | } | 2698 | } |
2678 | rcu_read_unlock(); | 2699 | rcu_read_unlock(); |
2679 | 2700 | ||
2701 | done: | ||
2680 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 2702 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
2681 | if (sdata->type == IEEE80211_IF_TYPE_IBSS) { | 2703 | if (sdata->type == IEEE80211_IF_TYPE_IBSS) { |
2682 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 2704 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; |
@@ -2699,7 +2721,7 @@ void ieee80211_sta_scan_work(struct work_struct *work) | |||
2699 | int skip; | 2721 | int skip; |
2700 | unsigned long next_delay = 0; | 2722 | unsigned long next_delay = 0; |
2701 | 2723 | ||
2702 | if (!local->sta_scanning) | 2724 | if (!local->sta_sw_scanning) |
2703 | return; | 2725 | return; |
2704 | 2726 | ||
2705 | switch (local->scan_state) { | 2727 | switch (local->scan_state) { |
@@ -2762,7 +2784,7 @@ void ieee80211_sta_scan_work(struct work_struct *work) | |||
2762 | break; | 2784 | break; |
2763 | } | 2785 | } |
2764 | 2786 | ||
2765 | if (local->sta_scanning) | 2787 | if (local->sta_sw_scanning) |
2766 | queue_delayed_work(local->hw.workqueue, &local->scan_work, | 2788 | queue_delayed_work(local->hw.workqueue, &local->scan_work, |
2767 | next_delay); | 2789 | next_delay); |
2768 | } | 2790 | } |
@@ -2794,7 +2816,7 @@ static int ieee80211_sta_start_scan(struct net_device *dev, | |||
2794 | * ResultCode: SUCCESS, INVALID_PARAMETERS | 2816 | * ResultCode: SUCCESS, INVALID_PARAMETERS |
2795 | */ | 2817 | */ |
2796 | 2818 | ||
2797 | if (local->sta_scanning) { | 2819 | if (local->sta_sw_scanning || local->sta_hw_scanning) { |
2798 | if (local->scan_dev == dev) | 2820 | if (local->scan_dev == dev) |
2799 | return 0; | 2821 | return 0; |
2800 | return -EBUSY; | 2822 | return -EBUSY; |
@@ -2802,15 +2824,15 @@ static int ieee80211_sta_start_scan(struct net_device *dev, | |||
2802 | 2824 | ||
2803 | if (local->ops->hw_scan) { | 2825 | if (local->ops->hw_scan) { |
2804 | int rc = local->ops->hw_scan(local_to_hw(local), | 2826 | int rc = local->ops->hw_scan(local_to_hw(local), |
2805 | ssid, ssid_len); | 2827 | ssid, ssid_len); |
2806 | if (!rc) { | 2828 | if (!rc) { |
2807 | local->sta_scanning = 1; | 2829 | local->sta_hw_scanning = 1; |
2808 | local->scan_dev = dev; | 2830 | local->scan_dev = dev; |
2809 | } | 2831 | } |
2810 | return rc; | 2832 | return rc; |
2811 | } | 2833 | } |
2812 | 2834 | ||
2813 | local->sta_scanning = 1; | 2835 | local->sta_sw_scanning = 1; |
2814 | 2836 | ||
2815 | rcu_read_lock(); | 2837 | rcu_read_lock(); |
2816 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | 2838 | 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) | |||
2865 | if (sdata->type != IEEE80211_IF_TYPE_STA) | 2887 | if (sdata->type != IEEE80211_IF_TYPE_STA) |
2866 | return ieee80211_sta_start_scan(dev, ssid, ssid_len); | 2888 | return ieee80211_sta_start_scan(dev, ssid, ssid_len); |
2867 | 2889 | ||
2868 | if (local->sta_scanning) { | 2890 | if (local->sta_sw_scanning || local->sta_hw_scanning) { |
2869 | if (local->scan_dev == dev) | 2891 | if (local->scan_dev == dev) |
2870 | return 0; | 2892 | return 0; |
2871 | return -EBUSY; | 2893 | return -EBUSY; |