aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/ibss.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/ibss.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/ibss.c')
-rw-r--r--net/wireless/ibss.c133
1 files changed, 106 insertions, 27 deletions
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index a5330c5a5477..99ef9364b7e8 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -10,7 +10,7 @@
10#include "nl80211.h" 10#include "nl80211.h"
11 11
12 12
13void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp) 13void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid)
14{ 14{
15 struct wireless_dev *wdev = dev->ieee80211_ptr; 15 struct wireless_dev *wdev = dev->ieee80211_ptr;
16 struct cfg80211_bss *bss; 16 struct cfg80211_bss *bss;
@@ -39,22 +39,45 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp)
39 cfg80211_hold_bss(bss_from_pub(bss)); 39 cfg80211_hold_bss(bss_from_pub(bss));
40 wdev->current_bss = bss_from_pub(bss); 40 wdev->current_bss = bss_from_pub(bss);
41 41
42 nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid, gfp); 42 nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid,
43 GFP_KERNEL);
43#ifdef CONFIG_WIRELESS_EXT 44#ifdef CONFIG_WIRELESS_EXT
44 memset(&wrqu, 0, sizeof(wrqu)); 45 memset(&wrqu, 0, sizeof(wrqu));
45 memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); 46 memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
46 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); 47 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
47#endif 48#endif
48} 49}
50
51void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp)
52{
53 struct wireless_dev *wdev = dev->ieee80211_ptr;
54 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
55 struct cfg80211_event *ev;
56 unsigned long flags;
57
58 ev = kzalloc(sizeof(*ev), gfp);
59 if (!ev)
60 return;
61
62 ev->type = EVENT_IBSS_JOINED;
63 memcpy(ev->cr.bssid, bssid, ETH_ALEN);
64
65 spin_lock_irqsave(&wdev->event_lock, flags);
66 list_add_tail(&ev->list, &wdev->event_list);
67 spin_unlock_irqrestore(&wdev->event_lock, flags);
68 schedule_work(&rdev->event_work);
69}
49EXPORT_SYMBOL(cfg80211_ibss_joined); 70EXPORT_SYMBOL(cfg80211_ibss_joined);
50 71
51int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, 72int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
52 struct net_device *dev, 73 struct net_device *dev,
53 struct cfg80211_ibss_params *params) 74 struct cfg80211_ibss_params *params)
54{ 75{
55 struct wireless_dev *wdev = dev->ieee80211_ptr; 76 struct wireless_dev *wdev = dev->ieee80211_ptr;
56 int err; 77 int err;
57 78
79 ASSERT_WDEV_LOCK(wdev);
80
58 if (wdev->ssid_len) 81 if (wdev->ssid_len)
59 return -EALREADY; 82 return -EALREADY;
60 83
@@ -72,10 +95,26 @@ int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
72 return 0; 95 return 0;
73} 96}
74 97
75void cfg80211_clear_ibss(struct net_device *dev, bool nowext) 98int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
99 struct net_device *dev,
100 struct cfg80211_ibss_params *params)
101{
102 struct wireless_dev *wdev = dev->ieee80211_ptr;
103 int err;
104
105 wdev_lock(wdev);
106 err = __cfg80211_join_ibss(rdev, dev, params);
107 wdev_unlock(wdev);
108
109 return err;
110}
111
112static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
76{ 113{
77 struct wireless_dev *wdev = dev->ieee80211_ptr; 114 struct wireless_dev *wdev = dev->ieee80211_ptr;
78 115
116 ASSERT_WDEV_LOCK(wdev);
117
79 if (wdev->current_bss) { 118 if (wdev->current_bss) {
80 cfg80211_unhold_bss(wdev->current_bss); 119 cfg80211_unhold_bss(wdev->current_bss);
81 cfg80211_put_bss(&wdev->current_bss->pub); 120 cfg80211_put_bss(&wdev->current_bss->pub);
@@ -89,12 +128,23 @@ void cfg80211_clear_ibss(struct net_device *dev, bool nowext)
89#endif 128#endif
90} 129}
91 130
92int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, 131void cfg80211_clear_ibss(struct net_device *dev, bool nowext)
93 struct net_device *dev, bool nowext) 132{
133 struct wireless_dev *wdev = dev->ieee80211_ptr;
134
135 wdev_lock(wdev);
136 __cfg80211_clear_ibss(dev, nowext);
137 wdev_unlock(wdev);
138}
139
140static int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
141 struct net_device *dev, bool nowext)
94{ 142{
95 struct wireless_dev *wdev = dev->ieee80211_ptr; 143 struct wireless_dev *wdev = dev->ieee80211_ptr;
96 int err; 144 int err;
97 145
146 ASSERT_WDEV_LOCK(wdev);
147
98 if (!wdev->ssid_len) 148 if (!wdev->ssid_len)
99 return -ENOLINK; 149 return -ENOLINK;
100 150
@@ -103,11 +153,24 @@ int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
103 if (err) 153 if (err)
104 return err; 154 return err;
105 155
106 cfg80211_clear_ibss(dev, nowext); 156 __cfg80211_clear_ibss(dev, nowext);
107 157
108 return 0; 158 return 0;
109} 159}
110 160
161int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
162 struct net_device *dev, bool nowext)
163{
164 struct wireless_dev *wdev = dev->ieee80211_ptr;
165 int err;
166
167 wdev_lock(wdev);
168 err = __cfg80211_leave_ibss(rdev, dev, nowext);
169 wdev_unlock(wdev);
170
171 return err;
172}
173
111#ifdef CONFIG_WIRELESS_EXT 174#ifdef CONFIG_WIRELESS_EXT
112static int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, 175static int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
113 struct wireless_dev *wdev) 176 struct wireless_dev *wdev)
@@ -184,12 +247,15 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
184 if (wdev->wext.ibss.channel == chan) 247 if (wdev->wext.ibss.channel == chan)
185 return 0; 248 return 0;
186 249
187 if (wdev->ssid_len) { 250 wdev_lock(wdev);
188 err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), 251 err = 0;
189 dev, true); 252 if (wdev->ssid_len)
190 if (err) 253 err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy),
191 return err; 254 dev, true);
192 } 255 wdev_unlock(wdev);
256
257 if (err)
258 return err;
193 259
194 if (chan) { 260 if (chan) {
195 wdev->wext.ibss.channel = chan; 261 wdev->wext.ibss.channel = chan;
@@ -215,10 +281,12 @@ int cfg80211_ibss_wext_giwfreq(struct net_device *dev,
215 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) 281 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
216 return -EINVAL; 282 return -EINVAL;
217 283
284 wdev_lock(wdev);
218 if (wdev->current_bss) 285 if (wdev->current_bss)
219 chan = wdev->current_bss->pub.channel; 286 chan = wdev->current_bss->pub.channel;
220 else if (wdev->wext.ibss.channel) 287 else if (wdev->wext.ibss.channel)
221 chan = wdev->wext.ibss.channel; 288 chan = wdev->wext.ibss.channel;
289 wdev_unlock(wdev);
222 290
223 if (chan) { 291 if (chan) {
224 freq->m = chan->center_freq; 292 freq->m = chan->center_freq;
@@ -247,12 +315,15 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev,
247 if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss) 315 if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss)
248 return -EOPNOTSUPP; 316 return -EOPNOTSUPP;
249 317
250 if (wdev->ssid_len) { 318 wdev_lock(wdev);
251 err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), 319 err = 0;
252 dev, true); 320 if (wdev->ssid_len)
253 if (err) 321 err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy),
254 return err; 322 dev, true);
255 } 323 wdev_unlock(wdev);
324
325 if (err)
326 return err;
256 327
257 /* iwconfig uses nul termination in SSID.. */ 328 /* iwconfig uses nul termination in SSID.. */
258 if (len > 0 && ssid[len - 1] == '\0') 329 if (len > 0 && ssid[len - 1] == '\0')
@@ -279,6 +350,7 @@ int cfg80211_ibss_wext_giwessid(struct net_device *dev,
279 350
280 data->flags = 0; 351 data->flags = 0;
281 352
353 wdev_lock(wdev);
282 if (wdev->ssid_len) { 354 if (wdev->ssid_len) {
283 data->flags = 1; 355 data->flags = 1;
284 data->length = wdev->ssid_len; 356 data->length = wdev->ssid_len;
@@ -288,6 +360,7 @@ int cfg80211_ibss_wext_giwessid(struct net_device *dev,
288 data->length = wdev->wext.ibss.ssid_len; 360 data->length = wdev->wext.ibss.ssid_len;
289 memcpy(ssid, wdev->wext.ibss.ssid, data->length); 361 memcpy(ssid, wdev->wext.ibss.ssid, data->length);
290 } 362 }
363 wdev_unlock(wdev);
291 364
292 return 0; 365 return 0;
293} 366}
@@ -325,12 +398,15 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev,
325 compare_ether_addr(bssid, wdev->wext.ibss.bssid) == 0) 398 compare_ether_addr(bssid, wdev->wext.ibss.bssid) == 0)
326 return 0; 399 return 0;
327 400
328 if (wdev->ssid_len) { 401 wdev_lock(wdev);
329 err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), 402 err = 0;
330 dev, true); 403 if (wdev->ssid_len)
331 if (err) 404 err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy),
332 return err; 405 dev, true);
333 } 406 wdev_unlock(wdev);
407
408 if (err)
409 return err;
334 410
335 if (bssid) { 411 if (bssid) {
336 memcpy(wdev->wext.bssid, bssid, ETH_ALEN); 412 memcpy(wdev->wext.bssid, bssid, ETH_ALEN);
@@ -355,10 +431,13 @@ int cfg80211_ibss_wext_giwap(struct net_device *dev,
355 431
356 ap_addr->sa_family = ARPHRD_ETHER; 432 ap_addr->sa_family = ARPHRD_ETHER;
357 433
434 wdev_lock(wdev);
358 if (wdev->current_bss) 435 if (wdev->current_bss)
359 memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN); 436 memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN);
360 else 437 else
361 memcpy(ap_addr->sa_data, wdev->wext.ibss.bssid, ETH_ALEN); 438 memcpy(ap_addr->sa_data, wdev->wext.ibss.bssid, ETH_ALEN);
439 wdev_unlock(wdev);
440
362 return 0; 441 return 0;
363} 442}
364/* temporary symbol - mark GPL - in the future the handler won't be */ 443/* temporary symbol - mark GPL - in the future the handler won't be */