aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/scan.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/scan.c')
-rw-r--r--net/wireless/scan.c159
1 files changed, 105 insertions, 54 deletions
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 7e595ce24eeb..4c210c2debc6 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -14,29 +14,41 @@
14#include <net/iw_handler.h> 14#include <net/iw_handler.h>
15#include "core.h" 15#include "core.h"
16#include "nl80211.h" 16#include "nl80211.h"
17#include "wext-compat.h"
17 18
18#define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ) 19#define IEEE80211_SCAN_RESULT_EXPIRE (15 * HZ)
19 20
20void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) 21void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
21{ 22{
23 struct cfg80211_scan_request *request;
22 struct net_device *dev; 24 struct net_device *dev;
23#ifdef CONFIG_WIRELESS_EXT 25#ifdef CONFIG_WIRELESS_EXT
24 union iwreq_data wrqu; 26 union iwreq_data wrqu;
25#endif 27#endif
26 28
27 dev = dev_get_by_index(&init_net, request->ifidx); 29 ASSERT_RDEV_LOCK(rdev);
28 if (!dev)
29 goto out;
30 30
31 WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); 31 request = rdev->scan_req;
32
33 if (!request)
34 return;
35
36 dev = request->dev;
37
38 /*
39 * This must be before sending the other events!
40 * Otherwise, wpa_supplicant gets completely confused with
41 * wext events.
42 */
43 cfg80211_sme_scan_done(dev);
32 44
33 if (aborted) 45 if (request->aborted)
34 nl80211_send_scan_aborted(wiphy_to_dev(request->wiphy), dev); 46 nl80211_send_scan_aborted(rdev, dev);
35 else 47 else
36 nl80211_send_scan_done(wiphy_to_dev(request->wiphy), dev); 48 nl80211_send_scan_done(rdev, dev);
37 49
38#ifdef CONFIG_WIRELESS_EXT 50#ifdef CONFIG_WIRELESS_EXT
39 if (!aborted) { 51 if (!request->aborted) {
40 memset(&wrqu, 0, sizeof(wrqu)); 52 memset(&wrqu, 0, sizeof(wrqu));
41 53
42 wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); 54 wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
@@ -45,9 +57,38 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
45 57
46 dev_put(dev); 58 dev_put(dev);
47 59
48 out: 60 rdev->scan_req = NULL;
49 wiphy_to_dev(request->wiphy)->scan_req = NULL; 61
50 kfree(request); 62 /*
63 * OK. If this is invoked with "leak" then we can't
64 * free this ... but we've cleaned it up anyway. The
65 * driver failed to call the scan_done callback, so
66 * all bets are off, it might still be trying to use
67 * the scan request or not ... if it accesses the dev
68 * in there (it shouldn't anyway) then it may crash.
69 */
70 if (!leak)
71 kfree(request);
72}
73
74void __cfg80211_scan_done(struct work_struct *wk)
75{
76 struct cfg80211_registered_device *rdev;
77
78 rdev = container_of(wk, struct cfg80211_registered_device,
79 scan_done_wk);
80
81 cfg80211_lock_rdev(rdev);
82 ___cfg80211_scan_done(rdev, false);
83 cfg80211_unlock_rdev(rdev);
84}
85
86void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
87{
88 WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req);
89
90 request->aborted = aborted;
91 schedule_work(&wiphy_to_dev(request->wiphy)->scan_done_wk);
51} 92}
52EXPORT_SYMBOL(cfg80211_scan_done); 93EXPORT_SYMBOL(cfg80211_scan_done);
53 94
@@ -62,6 +103,8 @@ static void bss_release(struct kref *ref)
62 if (bss->ies_allocated) 103 if (bss->ies_allocated)
63 kfree(bss->pub.information_elements); 104 kfree(bss->pub.information_elements);
64 105
106 BUG_ON(atomic_read(&bss->hold));
107
65 kfree(bss); 108 kfree(bss);
66} 109}
67 110
@@ -84,8 +127,9 @@ void cfg80211_bss_expire(struct cfg80211_registered_device *dev)
84 bool expired = false; 127 bool expired = false;
85 128
86 list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) { 129 list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) {
87 if (bss->hold || 130 if (atomic_read(&bss->hold))
88 !time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE)) 131 continue;
132 if (!time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE))
89 continue; 133 continue;
90 list_del(&bss->list); 134 list_del(&bss->list);
91 rb_erase(&bss->rbn, &dev->bss_tree); 135 rb_erase(&bss->rbn, &dev->bss_tree);
@@ -97,7 +141,7 @@ void cfg80211_bss_expire(struct cfg80211_registered_device *dev)
97 dev->bss_generation++; 141 dev->bss_generation++;
98} 142}
99 143
100static u8 *find_ie(u8 num, u8 *ies, size_t len) 144static u8 *find_ie(u8 num, u8 *ies, int len)
101{ 145{
102 while (len > 2 && ies[0] != num) { 146 while (len > 2 && ies[0] != num) {
103 len -= ies[1] + 2; 147 len -= ies[1] + 2;
@@ -539,6 +583,7 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
539 spin_lock_bh(&dev->bss_lock); 583 spin_lock_bh(&dev->bss_lock);
540 584
541 list_del(&bss->list); 585 list_del(&bss->list);
586 dev->bss_generation++;
542 rb_erase(&bss->rbn, &dev->bss_tree); 587 rb_erase(&bss->rbn, &dev->bss_tree);
543 588
544 spin_unlock_bh(&dev->bss_lock); 589 spin_unlock_bh(&dev->bss_lock);
@@ -547,30 +592,6 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
547} 592}
548EXPORT_SYMBOL(cfg80211_unlink_bss); 593EXPORT_SYMBOL(cfg80211_unlink_bss);
549 594
550void cfg80211_hold_bss(struct cfg80211_bss *pub)
551{
552 struct cfg80211_internal_bss *bss;
553
554 if (!pub)
555 return;
556
557 bss = container_of(pub, struct cfg80211_internal_bss, pub);
558 bss->hold = true;
559}
560EXPORT_SYMBOL(cfg80211_hold_bss);
561
562void cfg80211_unhold_bss(struct cfg80211_bss *pub)
563{
564 struct cfg80211_internal_bss *bss;
565
566 if (!pub)
567 return;
568
569 bss = container_of(pub, struct cfg80211_internal_bss, pub);
570 bss->hold = false;
571}
572EXPORT_SYMBOL(cfg80211_unhold_bss);
573
574#ifdef CONFIG_WIRELESS_EXT 595#ifdef CONFIG_WIRELESS_EXT
575int cfg80211_wext_siwscan(struct net_device *dev, 596int cfg80211_wext_siwscan(struct net_device *dev,
576 struct iw_request_info *info, 597 struct iw_request_info *info,
@@ -586,7 +607,10 @@ int cfg80211_wext_siwscan(struct net_device *dev,
586 if (!netif_running(dev)) 607 if (!netif_running(dev))
587 return -ENETDOWN; 608 return -ENETDOWN;
588 609
589 rdev = cfg80211_get_dev_from_ifindex(dev->ifindex); 610 if (wrqu->data.length == sizeof(struct iw_scan_req))
611 wreq = (struct iw_scan_req *)extra;
612
613 rdev = cfg80211_get_dev_from_ifindex(dev_net(dev), dev->ifindex);
590 614
591 if (IS_ERR(rdev)) 615 if (IS_ERR(rdev))
592 return PTR_ERR(rdev); 616 return PTR_ERR(rdev);
@@ -598,9 +622,14 @@ int cfg80211_wext_siwscan(struct net_device *dev,
598 622
599 wiphy = &rdev->wiphy; 623 wiphy = &rdev->wiphy;
600 624
601 for (band = 0; band < IEEE80211_NUM_BANDS; band++) 625 /* Determine number of channels, needed to allocate creq */
602 if (wiphy->bands[band]) 626 if (wreq && wreq->num_channels)
603 n_channels += wiphy->bands[band]->n_channels; 627 n_channels = wreq->num_channels;
628 else {
629 for (band = 0; band < IEEE80211_NUM_BANDS; band++)
630 if (wiphy->bands[band])
631 n_channels += wiphy->bands[band]->n_channels;
632 }
604 633
605 creq = kzalloc(sizeof(*creq) + sizeof(struct cfg80211_ssid) + 634 creq = kzalloc(sizeof(*creq) + sizeof(struct cfg80211_ssid) +
606 n_channels * sizeof(void *), 635 n_channels * sizeof(void *),
@@ -611,28 +640,47 @@ int cfg80211_wext_siwscan(struct net_device *dev,
611 } 640 }
612 641
613 creq->wiphy = wiphy; 642 creq->wiphy = wiphy;
614 creq->ifidx = dev->ifindex; 643 creq->dev = dev;
615 creq->ssids = (void *)(creq + 1); 644 /* SSIDs come after channels */
616 creq->channels = (void *)(creq->ssids + 1); 645 creq->ssids = (void *)&creq->channels[n_channels];
617 creq->n_channels = n_channels; 646 creq->n_channels = n_channels;
618 creq->n_ssids = 1; 647 creq->n_ssids = 1;
619 648
620 /* all channels */ 649 /* translate "Scan on frequencies" request */
621 i = 0; 650 i = 0;
622 for (band = 0; band < IEEE80211_NUM_BANDS; band++) { 651 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
623 int j; 652 int j;
624 if (!wiphy->bands[band]) 653 if (!wiphy->bands[band])
625 continue; 654 continue;
626 for (j = 0; j < wiphy->bands[band]->n_channels; j++) { 655 for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
656
657 /* If we have a wireless request structure and the
658 * wireless request specifies frequencies, then search
659 * for the matching hardware channel.
660 */
661 if (wreq && wreq->num_channels) {
662 int k;
663 int wiphy_freq = wiphy->bands[band]->channels[j].center_freq;
664 for (k = 0; k < wreq->num_channels; k++) {
665 int wext_freq = wreq->channel_list[k].m / 100000;
666 if (wext_freq == wiphy_freq)
667 goto wext_freq_found;
668 }
669 goto wext_freq_not_found;
670 }
671
672 wext_freq_found:
627 creq->channels[i] = &wiphy->bands[band]->channels[j]; 673 creq->channels[i] = &wiphy->bands[band]->channels[j];
628 i++; 674 i++;
675 wext_freq_not_found: ;
629 } 676 }
630 } 677 }
631 678
632 /* translate scan request */ 679 /* Set real number of channels specified in creq->channels[] */
633 if (wrqu->data.length == sizeof(struct iw_scan_req)) { 680 creq->n_channels = i;
634 wreq = (struct iw_scan_req *)extra;
635 681
682 /* translate "Scan for SSID" request */
683 if (wreq) {
636 if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { 684 if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
637 if (wreq->essid_len > IEEE80211_MAX_SSID_LEN) 685 if (wreq->essid_len > IEEE80211_MAX_SSID_LEN)
638 return -EINVAL; 686 return -EINVAL;
@@ -648,9 +696,12 @@ int cfg80211_wext_siwscan(struct net_device *dev,
648 if (err) { 696 if (err) {
649 rdev->scan_req = NULL; 697 rdev->scan_req = NULL;
650 kfree(creq); 698 kfree(creq);
699 } else {
700 nl80211_send_scan_start(rdev, dev);
701 dev_hold(dev);
651 } 702 }
652 out: 703 out:
653 cfg80211_put_dev(rdev); 704 cfg80211_unlock_rdev(rdev);
654 return err; 705 return err;
655} 706}
656EXPORT_SYMBOL_GPL(cfg80211_wext_siwscan); 707EXPORT_SYMBOL_GPL(cfg80211_wext_siwscan);
@@ -941,7 +992,7 @@ int cfg80211_wext_giwscan(struct net_device *dev,
941 if (!netif_running(dev)) 992 if (!netif_running(dev))
942 return -ENETDOWN; 993 return -ENETDOWN;
943 994
944 rdev = cfg80211_get_dev_from_ifindex(dev->ifindex); 995 rdev = cfg80211_get_dev_from_ifindex(dev_net(dev), dev->ifindex);
945 996
946 if (IS_ERR(rdev)) 997 if (IS_ERR(rdev))
947 return PTR_ERR(rdev); 998 return PTR_ERR(rdev);
@@ -959,7 +1010,7 @@ int cfg80211_wext_giwscan(struct net_device *dev,
959 } 1010 }
960 1011
961 out: 1012 out:
962 cfg80211_put_dev(rdev); 1013 cfg80211_unlock_rdev(rdev);
963 return res; 1014 return res;
964} 1015}
965EXPORT_SYMBOL_GPL(cfg80211_wext_giwscan); 1016EXPORT_SYMBOL_GPL(cfg80211_wext_giwscan);