aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorZhu Yi <yi.zhu@intel.com>2007-11-21 21:53:21 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 17:55:27 -0500
commitece8edddf067d21c4e5abfe3f1205da1588edbb2 (patch)
tree25450d1aedc630a538ca2f13aa0fa47100256182 /net/mac80211
parentf68635e627f9b21db05102e2d8fcd2894493d6bc (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')
-rw-r--r--net/mac80211/ieee80211.c13
-rw-r--r--net/mac80211/ieee80211_i.h6
-rw-r--r--net/mac80211/ieee80211_ioctl.c6
-rw-r--r--net/mac80211/ieee80211_sta.c66
-rw-r--r--net/mac80211/rx.c12
-rw-r--r--net/mac80211/tx.c2
6 files changed, 70 insertions, 35 deletions
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c
index 6378850d8580..4f8b6653e364 100644
--- a/net/mac80211/ieee80211.c
+++ b/net/mac80211/ieee80211.c
@@ -350,11 +350,14 @@ static int ieee80211_stop(struct net_device *dev)
350 synchronize_rcu(); 350 synchronize_rcu();
351 skb_queue_purge(&sdata->u.sta.skb_queue); 351 skb_queue_purge(&sdata->u.sta.skb_queue);
352 352
353 if (!local->ops->hw_scan && 353 if (local->scan_dev == sdata->dev) {
354 local->scan_dev == sdata->dev) { 354 if (!local->ops->hw_scan) {
355 local->sta_scanning = 0; 355 local->sta_sw_scanning = 0;
356 cancel_delayed_work(&local->scan_work); 356 cancel_delayed_work(&local->scan_work);
357 } else
358 local->sta_hw_scanning = 0;
357 } 359 }
360
358 flush_workqueue(local->hw.workqueue); 361 flush_workqueue(local->hw.workqueue);
359 362
360 sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED; 363 sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED;
@@ -526,7 +529,7 @@ int ieee80211_hw_config(struct ieee80211_local *local)
526 struct ieee80211_channel *chan; 529 struct ieee80211_channel *chan;
527 int ret = 0; 530 int ret = 0;
528 531
529 if (local->sta_scanning) { 532 if (local->sta_sw_scanning) {
530 chan = local->scan_channel; 533 chan = local->scan_channel;
531 mode = local->scan_hw_mode; 534 mode = local->scan_hw_mode;
532 } else { 535 } else {
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 2be7fcebac48..e9109443cb10 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -470,7 +470,8 @@ struct ieee80211_local {
470 470
471 struct list_head interfaces; 471 struct list_head interfaces;
472 472
473 int sta_scanning; 473 bool sta_sw_scanning;
474 bool sta_hw_scanning;
474 int scan_channel_idx; 475 int scan_channel_idx;
475 enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state; 476 enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state;
476 unsigned long last_scan_completed; 477 unsigned long last_scan_completed;
@@ -745,7 +746,8 @@ int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len);
745void ieee80211_sta_req_auth(struct net_device *dev, 746void ieee80211_sta_req_auth(struct net_device *dev,
746 struct ieee80211_if_sta *ifsta); 747 struct ieee80211_if_sta *ifsta);
747int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len); 748int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len);
748void ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb, 749ieee80211_txrx_result ieee80211_sta_rx_scan(struct net_device *dev,
750 struct sk_buff *skb,
749 struct ieee80211_rx_status *rx_status); 751 struct ieee80211_rx_status *rx_status);
750void ieee80211_rx_bss_list_init(struct net_device *dev); 752void ieee80211_rx_bss_list_init(struct net_device *dev);
751void ieee80211_rx_bss_list_deinit(struct net_device *dev); 753void ieee80211_rx_bss_list_deinit(struct net_device *dev);
diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c
index bbd9bc572a54..dc03bd796fee 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)
315 } 315 }
316 316
317 if (set) { 317 if (set) {
318 if (local->sta_scanning) 318 if (local->sta_sw_scanning)
319 ret = 0; 319 ret = 0;
320 else 320 else
321 ret = ieee80211_hw_config(local); 321 ret = ieee80211_hw_config(local);
@@ -545,8 +545,10 @@ static int ieee80211_ioctl_giwscan(struct net_device *dev,
545{ 545{
546 int res; 546 int res;
547 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); 547 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
548 if (local->sta_scanning) 548
549 if (local->sta_sw_scanning || local->sta_hw_scanning)
549 return -EAGAIN; 550 return -EAGAIN;
551
550 res = ieee80211_sta_scan_results(dev, extra, data->length); 552 res = ieee80211_sta_scan_results(dev, extra, data->length);
551 if (res >= 0) { 553 if (res >= 0) {
552 data->length = res; 554 data->length = res;
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
1870void ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb, 1880ieee80211_txrx_result
1871 struct ieee80211_rx_status *rx_status) 1881ieee80211_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
2701done:
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;
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index a7263fc476bd..a26aa7f50495 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)
338 struct ieee80211_local *local = rx->local; 338 struct ieee80211_local *local = rx->local;
339 struct sk_buff *skb = rx->skb; 339 struct sk_buff *skb = rx->skb;
340 340
341 if (unlikely(local->sta_scanning != 0)) { 341 if (unlikely(local->sta_hw_scanning))
342 ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status); 342 return ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status);
343
344 if (unlikely(local->sta_sw_scanning)) {
345 /* drop all the other packets during a software scan anyway */
346 if (ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status)
347 != TXRX_QUEUED)
348 dev_kfree_skb(skb);
343 return TXRX_QUEUED; 349 return TXRX_QUEUED;
344 } 350 }
345 351
@@ -1499,7 +1505,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
1499 goto end; 1505 goto end;
1500 } 1506 }
1501 1507
1502 if (unlikely(local->sta_scanning)) 1508 if (unlikely(local->sta_sw_scanning || local->sta_hw_scanning))
1503 rx.flags |= IEEE80211_TXRXD_RXIN_SCAN; 1509 rx.flags |= IEEE80211_TXRXD_RXIN_SCAN;
1504 1510
1505 if (__ieee80211_invoke_rx_handlers(local, local->rx_pre_handlers, &rx, 1511 if (__ieee80211_invoke_rx_handlers(local, local->rx_pre_handlers, &rx,
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 9ccf4b5a9aad..50ab4b2de1e9 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)
225 if (unlikely(tx->flags & IEEE80211_TXRXD_TX_INJECTED)) 225 if (unlikely(tx->flags & IEEE80211_TXRXD_TX_INJECTED))
226 return TXRX_CONTINUE; 226 return TXRX_CONTINUE;
227 227
228 if (unlikely(tx->local->sta_scanning != 0) && 228 if (unlikely(tx->local->sta_sw_scanning) &&
229 ((tx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || 229 ((tx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
230 (tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ)) 230 (tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ))
231 return TXRX_DROP; 231 return TXRX_DROP;