aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/scan.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-07-06 21:56:11 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-07-10 15:02:32 -0400
commit667503ddcb96f3b10211f997fe55907fa7509841 (patch)
tree5e2559e94a716bb81bfc7566e3e3a05267810c31 /net/wireless/scan.c
parent4f5dadcebb55fccef34722bbbf6401d39124c8a4 (diff)
cfg80211: fix locking
Over time, a lot of locking issues have crept into the smarts of cfg80211, so e.g. scan completion can race against a new scan, IBSS join can race against leaving an IBSS, etc. Introduce a new per-interface lock that protects most of the per-interface data that we need to keep track of, and sprinkle assertions about that lock everywhere. Some things now need to be offloaded to work structs so that we don't require being able to sleep in functions the drivers call. The exception to that are the MLME callbacks (rx_auth etc.) that currently only mac80211 calls because it was easier to do that there instead of in cfg80211, and future drivers implementing those calls will, if they ever exist, probably need to use a similar scheme like mac80211 anyway... In order to be able to handle _deauth and _disassoc properly, introduce a cookie passed to it that will determine locking requirements. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless/scan.c')
-rw-r--r--net/wireless/scan.c30
1 files changed, 27 insertions, 3 deletions
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 1625faf1de57..4f552c3f29a3 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -17,13 +17,21 @@
17 17
18#define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ) 18#define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ)
19 19
20void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) 20void __cfg80211_scan_done(struct work_struct *wk)
21{ 21{
22 struct cfg80211_registered_device *rdev;
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
29 rdev = container_of(wk, struct cfg80211_registered_device,
30 scan_done_wk);
31
32 mutex_lock(&rdev->mtx);
33 request = rdev->scan_req;
34
27 dev = dev_get_by_index(&init_net, request->ifidx); 35 dev = dev_get_by_index(&init_net, request->ifidx);
28 if (!dev) 36 if (!dev)
29 goto out; 37 goto out;
@@ -35,7 +43,7 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
35 */ 43 */
36 cfg80211_sme_scan_done(dev); 44 cfg80211_sme_scan_done(dev);
37 45
38 if (aborted) 46 if (request->aborted)
39 nl80211_send_scan_aborted(wiphy_to_dev(request->wiphy), dev); 47 nl80211_send_scan_aborted(wiphy_to_dev(request->wiphy), dev);
40 else 48 else
41 nl80211_send_scan_done(wiphy_to_dev(request->wiphy), dev); 49 nl80211_send_scan_done(wiphy_to_dev(request->wiphy), dev);
@@ -43,7 +51,7 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
43 wiphy_to_dev(request->wiphy)->scan_req = NULL; 51 wiphy_to_dev(request->wiphy)->scan_req = NULL;
44 52
45#ifdef CONFIG_WIRELESS_EXT 53#ifdef CONFIG_WIRELESS_EXT
46 if (!aborted) { 54 if (!request->aborted) {
47 memset(&wrqu, 0, sizeof(wrqu)); 55 memset(&wrqu, 0, sizeof(wrqu));
48 56
49 wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); 57 wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
@@ -53,8 +61,24 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
53 dev_put(dev); 61 dev_put(dev);
54 62
55 out: 63 out:
64 cfg80211_unlock_rdev(rdev);
56 kfree(request); 65 kfree(request);
57} 66}
67
68void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
69{
70 struct net_device *dev = dev_get_by_index(&init_net, request->ifidx);
71 if (WARN_ON(!dev)) {
72 kfree(request);
73 return;
74 }
75
76 WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req);
77
78 request->aborted = aborted;
79 schedule_work(&wiphy_to_dev(request->wiphy)->scan_done_wk);
80 dev_put(dev);
81}
58EXPORT_SYMBOL(cfg80211_scan_done); 82EXPORT_SYMBOL(cfg80211_scan_done);
59 83
60static void bss_release(struct kref *ref) 84static void bss_release(struct kref *ref)