diff options
Diffstat (limited to 'net/wireless/scan.c')
-rw-r--r-- | net/wireless/scan.c | 82 |
1 files changed, 42 insertions, 40 deletions
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 7e595ce24eeb..0ccf3a07dc02 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 | ||
20 | void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) | 21 | void __cfg80211_scan_done(struct work_struct *wk) |
21 | { | 22 | { |
23 | struct cfg80211_registered_device *rdev; | ||
24 | struct cfg80211_scan_request *request; | ||
22 | struct net_device *dev; | 25 | struct net_device *dev; |
23 | #ifdef CONFIG_WIRELESS_EXT | 26 | #ifdef CONFIG_WIRELESS_EXT |
24 | union iwreq_data wrqu; | 27 | union iwreq_data wrqu; |
25 | #endif | 28 | #endif |
26 | 29 | ||
27 | dev = dev_get_by_index(&init_net, request->ifidx); | 30 | rdev = container_of(wk, struct cfg80211_registered_device, |
28 | if (!dev) | 31 | scan_done_wk); |
29 | goto out; | ||
30 | 32 | ||
31 | WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); | 33 | mutex_lock(&rdev->mtx); |
34 | request = rdev->scan_req; | ||
35 | |||
36 | dev = request->dev; | ||
32 | 37 | ||
33 | if (aborted) | 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); | ||
44 | |||
45 | if (request->aborted) | ||
34 | nl80211_send_scan_aborted(wiphy_to_dev(request->wiphy), dev); | 46 | nl80211_send_scan_aborted(wiphy_to_dev(request->wiphy), dev); |
35 | else | 47 | else |
36 | nl80211_send_scan_done(wiphy_to_dev(request->wiphy), dev); | 48 | nl80211_send_scan_done(wiphy_to_dev(request->wiphy), 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,10 +57,18 @@ 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 | cfg80211_unlock_rdev(rdev); |
49 | wiphy_to_dev(request->wiphy)->scan_req = NULL; | 61 | wiphy_to_dev(request->wiphy)->scan_req = NULL; |
50 | kfree(request); | 62 | kfree(request); |
51 | } | 63 | } |
64 | |||
65 | void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) | ||
66 | { | ||
67 | WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); | ||
68 | |||
69 | request->aborted = aborted; | ||
70 | schedule_work(&wiphy_to_dev(request->wiphy)->scan_done_wk); | ||
71 | } | ||
52 | EXPORT_SYMBOL(cfg80211_scan_done); | 72 | EXPORT_SYMBOL(cfg80211_scan_done); |
53 | 73 | ||
54 | static void bss_release(struct kref *ref) | 74 | static void bss_release(struct kref *ref) |
@@ -62,6 +82,8 @@ static void bss_release(struct kref *ref) | |||
62 | if (bss->ies_allocated) | 82 | if (bss->ies_allocated) |
63 | kfree(bss->pub.information_elements); | 83 | kfree(bss->pub.information_elements); |
64 | 84 | ||
85 | BUG_ON(atomic_read(&bss->hold)); | ||
86 | |||
65 | kfree(bss); | 87 | kfree(bss); |
66 | } | 88 | } |
67 | 89 | ||
@@ -84,8 +106,9 @@ void cfg80211_bss_expire(struct cfg80211_registered_device *dev) | |||
84 | bool expired = false; | 106 | bool expired = false; |
85 | 107 | ||
86 | list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) { | 108 | list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) { |
87 | if (bss->hold || | 109 | if (atomic_read(&bss->hold)) |
88 | !time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE)) | 110 | continue; |
111 | if (!time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE)) | ||
89 | continue; | 112 | continue; |
90 | list_del(&bss->list); | 113 | list_del(&bss->list); |
91 | rb_erase(&bss->rbn, &dev->bss_tree); | 114 | rb_erase(&bss->rbn, &dev->bss_tree); |
@@ -547,30 +570,6 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) | |||
547 | } | 570 | } |
548 | EXPORT_SYMBOL(cfg80211_unlink_bss); | 571 | EXPORT_SYMBOL(cfg80211_unlink_bss); |
549 | 572 | ||
550 | void 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 | } | ||
560 | EXPORT_SYMBOL(cfg80211_hold_bss); | ||
561 | |||
562 | void 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 | } | ||
572 | EXPORT_SYMBOL(cfg80211_unhold_bss); | ||
573 | |||
574 | #ifdef CONFIG_WIRELESS_EXT | 573 | #ifdef CONFIG_WIRELESS_EXT |
575 | int cfg80211_wext_siwscan(struct net_device *dev, | 574 | int cfg80211_wext_siwscan(struct net_device *dev, |
576 | struct iw_request_info *info, | 575 | struct iw_request_info *info, |
@@ -586,7 +585,7 @@ int cfg80211_wext_siwscan(struct net_device *dev, | |||
586 | if (!netif_running(dev)) | 585 | if (!netif_running(dev)) |
587 | return -ENETDOWN; | 586 | return -ENETDOWN; |
588 | 587 | ||
589 | rdev = cfg80211_get_dev_from_ifindex(dev->ifindex); | 588 | rdev = cfg80211_get_dev_from_ifindex(dev_net(dev), dev->ifindex); |
590 | 589 | ||
591 | if (IS_ERR(rdev)) | 590 | if (IS_ERR(rdev)) |
592 | return PTR_ERR(rdev); | 591 | return PTR_ERR(rdev); |
@@ -611,7 +610,7 @@ int cfg80211_wext_siwscan(struct net_device *dev, | |||
611 | } | 610 | } |
612 | 611 | ||
613 | creq->wiphy = wiphy; | 612 | creq->wiphy = wiphy; |
614 | creq->ifidx = dev->ifindex; | 613 | creq->dev = dev; |
615 | creq->ssids = (void *)(creq + 1); | 614 | creq->ssids = (void *)(creq + 1); |
616 | creq->channels = (void *)(creq->ssids + 1); | 615 | creq->channels = (void *)(creq->ssids + 1); |
617 | creq->n_channels = n_channels; | 616 | creq->n_channels = n_channels; |
@@ -648,9 +647,12 @@ int cfg80211_wext_siwscan(struct net_device *dev, | |||
648 | if (err) { | 647 | if (err) { |
649 | rdev->scan_req = NULL; | 648 | rdev->scan_req = NULL; |
650 | kfree(creq); | 649 | kfree(creq); |
650 | } else { | ||
651 | nl80211_send_scan_start(rdev, dev); | ||
652 | dev_hold(dev); | ||
651 | } | 653 | } |
652 | out: | 654 | out: |
653 | cfg80211_put_dev(rdev); | 655 | cfg80211_unlock_rdev(rdev); |
654 | return err; | 656 | return err; |
655 | } | 657 | } |
656 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwscan); | 658 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwscan); |
@@ -941,7 +943,7 @@ int cfg80211_wext_giwscan(struct net_device *dev, | |||
941 | if (!netif_running(dev)) | 943 | if (!netif_running(dev)) |
942 | return -ENETDOWN; | 944 | return -ENETDOWN; |
943 | 945 | ||
944 | rdev = cfg80211_get_dev_from_ifindex(dev->ifindex); | 946 | rdev = cfg80211_get_dev_from_ifindex(dev_net(dev), dev->ifindex); |
945 | 947 | ||
946 | if (IS_ERR(rdev)) | 948 | if (IS_ERR(rdev)) |
947 | return PTR_ERR(rdev); | 949 | return PTR_ERR(rdev); |
@@ -959,7 +961,7 @@ int cfg80211_wext_giwscan(struct net_device *dev, | |||
959 | } | 961 | } |
960 | 962 | ||
961 | out: | 963 | out: |
962 | cfg80211_put_dev(rdev); | 964 | cfg80211_unlock_rdev(rdev); |
963 | return res; | 965 | return res; |
964 | } | 966 | } |
965 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwscan); | 967 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwscan); |