aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/wext-sme.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/wext-sme.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/wext-sme.c')
-rw-r--r--net/wireless/wext-sme.c125
1 files changed, 88 insertions, 37 deletions
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c
index fe1987acb891..6f75aaa7f795 100644
--- a/net/wireless/wext-sme.c
+++ b/net/wireless/wext-sme.c
@@ -15,6 +15,9 @@ static int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
15{ 15{
16 int err; 16 int err;
17 17
18 ASSERT_RDEV_LOCK(rdev);
19 ASSERT_WDEV_LOCK(wdev);
20
18 if (!netif_running(wdev->netdev)) 21 if (!netif_running(wdev->netdev))
19 return 0; 22 return 0;
20 23
@@ -24,8 +27,8 @@ static int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
24 27
25 err = 0; 28 err = 0;
26 if (wdev->wext.connect.ssid_len != 0) 29 if (wdev->wext.connect.ssid_len != 0)
27 err = cfg80211_connect(rdev, wdev->netdev, 30 err = __cfg80211_connect(rdev, wdev->netdev,
28 &wdev->wext.connect); 31 &wdev->wext.connect);
29 32
30 return err; 33 return err;
31} 34}
@@ -50,33 +53,43 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
50 if (chan && (chan->flags & IEEE80211_CHAN_DISABLED)) 53 if (chan && (chan->flags & IEEE80211_CHAN_DISABLED))
51 return -EINVAL; 54 return -EINVAL;
52 55
53 if (wdev->wext.connect.channel == chan) 56 cfg80211_lock_rdev(rdev);
54 return 0; 57 wdev_lock(wdev);
58
59 if (wdev->wext.connect.channel == chan) {
60 err = 0;
61 goto out;
62 }
55 63
56 if (wdev->sme_state != CFG80211_SME_IDLE) { 64 if (wdev->sme_state != CFG80211_SME_IDLE) {
57 bool event = true; 65 bool event = true;
58 /* if SSID set, we'll try right again, avoid event */ 66 /* if SSID set, we'll try right again, avoid event */
59 if (wdev->wext.connect.ssid_len) 67 if (wdev->wext.connect.ssid_len)
60 event = false; 68 event = false;
61 err = cfg80211_disconnect(wiphy_to_dev(wdev->wiphy), 69 err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy),
62 dev, WLAN_REASON_DEAUTH_LEAVING, 70 dev, WLAN_REASON_DEAUTH_LEAVING,
63 event); 71 event);
64 if (err) 72 if (err)
65 return err; 73 goto out;
66 } 74 }
67 75
76
68 wdev->wext.connect.channel = chan; 77 wdev->wext.connect.channel = chan;
69 78
70 /* SSID is not set, we just want to switch channel */ 79 /* SSID is not set, we just want to switch channel */
71 if (wdev->wext.connect.ssid_len && chan) { 80 if (wdev->wext.connect.ssid_len && chan) {
72 if (!rdev->ops->set_channel) 81 err = -EOPNOTSUPP;
73 return -EOPNOTSUPP; 82 if (rdev->ops->set_channel)
74 83 err = rdev->ops->set_channel(wdev->wiphy, chan,
75 return rdev->ops->set_channel(wdev->wiphy, chan, 84 NL80211_CHAN_NO_HT);
76 NL80211_CHAN_NO_HT); 85 goto out;
77 } 86 }
78 87
79 return cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev); 88 err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev);
89 out:
90 wdev_unlock(wdev);
91 cfg80211_unlock_rdev(rdev);
92 return err;
80} 93}
81/* temporary symbol - mark GPL - in the future the handler won't be */ 94/* temporary symbol - mark GPL - in the future the handler won't be */
82EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwfreq); 95EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwfreq);
@@ -92,10 +105,12 @@ int cfg80211_mgd_wext_giwfreq(struct net_device *dev,
92 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) 105 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
93 return -EINVAL; 106 return -EINVAL;
94 107
108 wdev_lock(wdev);
95 if (wdev->current_bss) 109 if (wdev->current_bss)
96 chan = wdev->current_bss->pub.channel; 110 chan = wdev->current_bss->pub.channel;
97 else if (wdev->wext.connect.channel) 111 else if (wdev->wext.connect.channel)
98 chan = wdev->wext.connect.channel; 112 chan = wdev->wext.connect.channel;
113 wdev_unlock(wdev);
99 114
100 if (chan) { 115 if (chan) {
101 freq->m = chan->center_freq; 116 freq->m = chan->center_freq;
@@ -128,21 +143,26 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,
128 if (len > 0 && ssid[len - 1] == '\0') 143 if (len > 0 && ssid[len - 1] == '\0')
129 len--; 144 len--;
130 145
146 cfg80211_lock_rdev(wiphy_to_dev(wdev->wiphy));
147 wdev_lock(wdev);
148
149 err = 0;
150
131 if (wdev->wext.connect.ssid && len && 151 if (wdev->wext.connect.ssid && len &&
132 len == wdev->wext.connect.ssid_len && 152 len == wdev->wext.connect.ssid_len &&
133 memcmp(wdev->wext.connect.ssid, ssid, len)) 153 memcmp(wdev->wext.connect.ssid, ssid, len))
134 return 0; 154 goto out;
135 155
136 if (wdev->sme_state != CFG80211_SME_IDLE) { 156 if (wdev->sme_state != CFG80211_SME_IDLE) {
137 bool event = true; 157 bool event = true;
138 /* if SSID set now, we'll try to connect, avoid event */ 158 /* if SSID set now, we'll try to connect, avoid event */
139 if (len) 159 if (len)
140 event = false; 160 event = false;
141 err = cfg80211_disconnect(wiphy_to_dev(wdev->wiphy), 161 err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy),
142 dev, WLAN_REASON_DEAUTH_LEAVING, 162 dev, WLAN_REASON_DEAUTH_LEAVING,
143 event); 163 event);
144 if (err) 164 if (err)
145 return err; 165 goto out;
146 } 166 }
147 167
148 wdev->wext.connect.ssid = wdev->wext.ssid; 168 wdev->wext.connect.ssid = wdev->wext.ssid;
@@ -151,7 +171,11 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,
151 171
152 wdev->wext.connect.crypto.control_port = false; 172 wdev->wext.connect.crypto.control_port = false;
153 173
154 return cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev); 174 err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev);
175 out:
176 wdev_unlock(wdev);
177 cfg80211_unlock_rdev(wiphy_to_dev(wdev->wiphy));
178 return err;
155} 179}
156/* temporary symbol - mark GPL - in the future the handler won't be */ 180/* temporary symbol - mark GPL - in the future the handler won't be */
157EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwessid); 181EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwessid);
@@ -168,6 +192,7 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev,
168 192
169 data->flags = 0; 193 data->flags = 0;
170 194
195 wdev_lock(wdev);
171 if (wdev->ssid_len) { 196 if (wdev->ssid_len) {
172 data->flags = 1; 197 data->flags = 1;
173 data->length = wdev->ssid_len; 198 data->length = wdev->ssid_len;
@@ -178,6 +203,7 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev,
178 memcpy(ssid, wdev->wext.connect.ssid, data->length); 203 memcpy(ssid, wdev->wext.connect.ssid, data->length);
179 } else 204 } else
180 data->flags = 0; 205 data->flags = 0;
206 wdev_unlock(wdev);
181 207
182 return 0; 208 return 0;
183} 209}
@@ -203,21 +229,25 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev,
203 if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid)) 229 if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid))
204 bssid = NULL; 230 bssid = NULL;
205 231
232 cfg80211_lock_rdev(wiphy_to_dev(wdev->wiphy));
233 wdev_lock(wdev);
234
235 err = 0;
206 /* both automatic */ 236 /* both automatic */
207 if (!bssid && !wdev->wext.connect.bssid) 237 if (!bssid && !wdev->wext.connect.bssid)
208 return 0; 238 goto out;
209 239
210 /* fixed already - and no change */ 240 /* fixed already - and no change */
211 if (wdev->wext.connect.bssid && bssid && 241 if (wdev->wext.connect.bssid && bssid &&
212 compare_ether_addr(bssid, wdev->wext.connect.bssid) == 0) 242 compare_ether_addr(bssid, wdev->wext.connect.bssid) == 0)
213 return 0; 243 goto out;
214 244
215 if (wdev->sme_state != CFG80211_SME_IDLE) { 245 if (wdev->sme_state != CFG80211_SME_IDLE) {
216 err = cfg80211_disconnect(wiphy_to_dev(wdev->wiphy), 246 err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy),
217 dev, WLAN_REASON_DEAUTH_LEAVING, 247 dev, WLAN_REASON_DEAUTH_LEAVING,
218 false); 248 false);
219 if (err) 249 if (err)
220 return err; 250 goto out;
221 } 251 }
222 252
223 if (bssid) { 253 if (bssid) {
@@ -226,7 +256,11 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev,
226 } else 256 } else
227 wdev->wext.connect.bssid = NULL; 257 wdev->wext.connect.bssid = NULL;
228 258
229 return cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev); 259 err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev);
260 out:
261 wdev_unlock(wdev);
262 cfg80211_unlock_rdev(wiphy_to_dev(wdev->wiphy));
263 return err;
230} 264}
231/* temporary symbol - mark GPL - in the future the handler won't be */ 265/* temporary symbol - mark GPL - in the future the handler won't be */
232EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwap); 266EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwap);
@@ -243,12 +277,14 @@ int cfg80211_mgd_wext_giwap(struct net_device *dev,
243 277
244 ap_addr->sa_family = ARPHRD_ETHER; 278 ap_addr->sa_family = ARPHRD_ETHER;
245 279
280 wdev_lock(wdev);
246 if (wdev->current_bss) 281 if (wdev->current_bss)
247 memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN); 282 memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN);
248 else if (wdev->wext.connect.bssid) 283 else if (wdev->wext.connect.bssid)
249 memcpy(ap_addr->sa_data, wdev->wext.connect.bssid, ETH_ALEN); 284 memcpy(ap_addr->sa_data, wdev->wext.connect.bssid, ETH_ALEN);
250 else 285 else
251 memset(ap_addr->sa_data, 0, ETH_ALEN); 286 memset(ap_addr->sa_data, 0, ETH_ALEN);
287 wdev_unlock(wdev);
252 288
253 return 0; 289 return 0;
254} 290}
@@ -270,15 +306,20 @@ int cfg80211_wext_siwgenie(struct net_device *dev,
270 if (!ie_len) 306 if (!ie_len)
271 ie = NULL; 307 ie = NULL;
272 308
309 wdev_lock(wdev);
310
273 /* no change */ 311 /* no change */
312 err = 0;
274 if (wdev->wext.ie_len == ie_len && 313 if (wdev->wext.ie_len == ie_len &&
275 memcmp(wdev->wext.ie, ie, ie_len) == 0) 314 memcmp(wdev->wext.ie, ie, ie_len) == 0)
276 return 0; 315 goto out;
277 316
278 if (ie_len) { 317 if (ie_len) {
279 ie = kmemdup(extra, ie_len, GFP_KERNEL); 318 ie = kmemdup(extra, ie_len, GFP_KERNEL);
280 if (!ie) 319 if (!ie) {
281 return -ENOMEM; 320 err = -ENOMEM;
321 goto out;
322 }
282 } else 323 } else
283 ie = NULL; 324 ie = NULL;
284 325
@@ -287,14 +328,17 @@ int cfg80211_wext_siwgenie(struct net_device *dev,
287 wdev->wext.ie_len = ie_len; 328 wdev->wext.ie_len = ie_len;
288 329
289 if (wdev->sme_state != CFG80211_SME_IDLE) { 330 if (wdev->sme_state != CFG80211_SME_IDLE) {
290 err = cfg80211_disconnect(rdev, dev, 331 err = __cfg80211_disconnect(rdev, dev,
291 WLAN_REASON_DEAUTH_LEAVING, false); 332 WLAN_REASON_DEAUTH_LEAVING, false);
292 if (err) 333 if (err)
293 return err; 334 goto out;
294 } 335 }
295 336
296 /* userspace better not think we'll reconnect */ 337 /* userspace better not think we'll reconnect */
297 return 0; 338 err = 0;
339 out:
340 wdev_unlock(wdev);
341 return err;
298} 342}
299EXPORT_SYMBOL_GPL(cfg80211_wext_siwgenie); 343EXPORT_SYMBOL_GPL(cfg80211_wext_siwgenie);
300 344
@@ -305,6 +349,7 @@ int cfg80211_wext_siwmlme(struct net_device *dev,
305 struct wireless_dev *wdev = dev->ieee80211_ptr; 349 struct wireless_dev *wdev = dev->ieee80211_ptr;
306 struct iw_mlme *mlme = (struct iw_mlme *)extra; 350 struct iw_mlme *mlme = (struct iw_mlme *)extra;
307 struct cfg80211_registered_device *rdev; 351 struct cfg80211_registered_device *rdev;
352 int err;
308 353
309 if (!wdev) 354 if (!wdev)
310 return -EOPNOTSUPP; 355 return -EOPNOTSUPP;
@@ -317,13 +362,19 @@ int cfg80211_wext_siwmlme(struct net_device *dev,
317 if (mlme->addr.sa_family != ARPHRD_ETHER) 362 if (mlme->addr.sa_family != ARPHRD_ETHER)
318 return -EINVAL; 363 return -EINVAL;
319 364
365 wdev_lock(wdev);
320 switch (mlme->cmd) { 366 switch (mlme->cmd) {
321 case IW_MLME_DEAUTH: 367 case IW_MLME_DEAUTH:
322 case IW_MLME_DISASSOC: 368 case IW_MLME_DISASSOC:
323 return cfg80211_disconnect(rdev, dev, mlme->reason_code, 369 err = __cfg80211_disconnect(rdev, dev, mlme->reason_code,
324 true); 370 true);
371 break;
325 default: 372 default:
326 return -EOPNOTSUPP; 373 err = -EOPNOTSUPP;
374 break;
327 } 375 }
376 wdev_unlock(wdev);
377
378 return err;
328} 379}
329EXPORT_SYMBOL_GPL(cfg80211_wext_siwmlme); 380EXPORT_SYMBOL_GPL(cfg80211_wext_siwmlme);