diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2009-07-06 21:56:11 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-07-10 15:02:32 -0400 |
commit | 667503ddcb96f3b10211f997fe55907fa7509841 (patch) | |
tree | 5e2559e94a716bb81bfc7566e3e3a05267810c31 /net/wireless/mlme.c | |
parent | 4f5dadcebb55fccef34722bbbf6401d39124c8a4 (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/mlme.c')
-rw-r--r-- | net/wireless/mlme.c | 214 |
1 files changed, 168 insertions, 46 deletions
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 960bf60e44e5..1b2ca1fea7a1 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -23,7 +23,7 @@ void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len) | |||
23 | u16 status = le16_to_cpu(mgmt->u.auth.status_code); | 23 | u16 status = le16_to_cpu(mgmt->u.auth.status_code); |
24 | bool done = false; | 24 | bool done = false; |
25 | 25 | ||
26 | might_sleep(); | 26 | wdev_lock(wdev); |
27 | 27 | ||
28 | for (i = 0; i < MAX_AUTH_BSSES; i++) { | 28 | for (i = 0; i < MAX_AUTH_BSSES; i++) { |
29 | if (wdev->authtry_bsses[i] && | 29 | if (wdev->authtry_bsses[i] && |
@@ -45,6 +45,8 @@ void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len) | |||
45 | 45 | ||
46 | nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL); | 46 | nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL); |
47 | cfg80211_sme_rx_auth(dev, buf, len); | 47 | cfg80211_sme_rx_auth(dev, buf, len); |
48 | |||
49 | wdev_unlock(wdev); | ||
48 | } | 50 | } |
49 | EXPORT_SYMBOL(cfg80211_send_rx_auth); | 51 | EXPORT_SYMBOL(cfg80211_send_rx_auth); |
50 | 52 | ||
@@ -59,14 +61,15 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) | |||
59 | int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); | 61 | int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); |
60 | bool done; | 62 | bool done; |
61 | 63 | ||
62 | might_sleep(); | 64 | wdev_lock(wdev); |
63 | 65 | ||
64 | status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); | 66 | status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); |
65 | 67 | ||
66 | nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL); | 68 | nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL); |
67 | 69 | ||
68 | cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, | 70 | __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, |
69 | status_code, GFP_KERNEL); | 71 | status_code, |
72 | status_code == WLAN_STATUS_SUCCESS); | ||
70 | 73 | ||
71 | if (status_code == WLAN_STATUS_SUCCESS) { | 74 | if (status_code == WLAN_STATUS_SUCCESS) { |
72 | for (i = 0; wdev->current_bss && i < MAX_AUTH_BSSES; i++) { | 75 | for (i = 0; wdev->current_bss && i < MAX_AUTH_BSSES; i++) { |
@@ -81,10 +84,13 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) | |||
81 | 84 | ||
82 | WARN_ON(!done); | 85 | WARN_ON(!done); |
83 | } | 86 | } |
87 | |||
88 | wdev_unlock(wdev); | ||
84 | } | 89 | } |
85 | EXPORT_SYMBOL(cfg80211_send_rx_assoc); | 90 | EXPORT_SYMBOL(cfg80211_send_rx_assoc); |
86 | 91 | ||
87 | void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len) | 92 | static void __cfg80211_send_deauth(struct net_device *dev, |
93 | const u8 *buf, size_t len) | ||
88 | { | 94 | { |
89 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 95 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
90 | struct wiphy *wiphy = wdev->wiphy; | 96 | struct wiphy *wiphy = wdev->wiphy; |
@@ -94,7 +100,7 @@ void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len) | |||
94 | int i; | 100 | int i; |
95 | bool done = false; | 101 | bool done = false; |
96 | 102 | ||
97 | might_sleep(); | 103 | ASSERT_WDEV_LOCK(wdev); |
98 | 104 | ||
99 | nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL); | 105 | nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL); |
100 | 106 | ||
@@ -132,17 +138,35 @@ void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len) | |||
132 | reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); | 138 | reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); |
133 | 139 | ||
134 | from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0; | 140 | from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0; |
135 | __cfg80211_disconnected(dev, GFP_KERNEL, NULL, 0, | 141 | __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); |
136 | reason_code, from_ap); | ||
137 | } else if (wdev->sme_state == CFG80211_SME_CONNECTING) { | 142 | } else if (wdev->sme_state == CFG80211_SME_CONNECTING) { |
138 | cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, | 143 | __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, |
139 | WLAN_STATUS_UNSPECIFIED_FAILURE, | 144 | WLAN_STATUS_UNSPECIFIED_FAILURE, |
140 | GFP_KERNEL); | 145 | false); |
146 | } | ||
147 | } | ||
148 | |||
149 | |||
150 | void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len, | ||
151 | void *cookie) | ||
152 | { | ||
153 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
154 | |||
155 | BUG_ON(cookie && wdev != cookie); | ||
156 | |||
157 | if (cookie) { | ||
158 | /* called within callback */ | ||
159 | __cfg80211_send_deauth(dev, buf, len); | ||
160 | } else { | ||
161 | wdev_lock(wdev); | ||
162 | __cfg80211_send_deauth(dev, buf, len); | ||
163 | wdev_unlock(wdev); | ||
141 | } | 164 | } |
142 | } | 165 | } |
143 | EXPORT_SYMBOL(cfg80211_send_deauth); | 166 | EXPORT_SYMBOL(cfg80211_send_deauth); |
144 | 167 | ||
145 | void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len) | 168 | static void __cfg80211_send_disassoc(struct net_device *dev, |
169 | const u8 *buf, size_t len) | ||
146 | { | 170 | { |
147 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 171 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
148 | struct wiphy *wiphy = wdev->wiphy; | 172 | struct wiphy *wiphy = wdev->wiphy; |
@@ -154,12 +178,12 @@ void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len) | |||
154 | bool from_ap; | 178 | bool from_ap; |
155 | bool done = false; | 179 | bool done = false; |
156 | 180 | ||
157 | might_sleep(); | 181 | wdev_lock(wdev); |
158 | 182 | ||
159 | nl80211_send_disassoc(rdev, dev, buf, len, GFP_KERNEL); | 183 | nl80211_send_disassoc(rdev, dev, buf, len, GFP_KERNEL); |
160 | 184 | ||
161 | if (!wdev->sme_state == CFG80211_SME_CONNECTED) | 185 | if (!wdev->sme_state == CFG80211_SME_CONNECTED) |
162 | return; | 186 | goto out; |
163 | 187 | ||
164 | if (wdev->current_bss && | 188 | if (wdev->current_bss && |
165 | memcmp(wdev->current_bss, bssid, ETH_ALEN) == 0) { | 189 | memcmp(wdev->current_bss, bssid, ETH_ALEN) == 0) { |
@@ -180,8 +204,26 @@ void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len) | |||
180 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); | 204 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); |
181 | 205 | ||
182 | from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0; | 206 | from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0; |
183 | __cfg80211_disconnected(dev, GFP_KERNEL, NULL, 0, | 207 | __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap); |
184 | reason_code, from_ap); | 208 | out: |
209 | wdev_unlock(wdev); | ||
210 | } | ||
211 | |||
212 | void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len, | ||
213 | void *cookie) | ||
214 | { | ||
215 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
216 | |||
217 | BUG_ON(cookie && wdev != cookie); | ||
218 | |||
219 | if (cookie) { | ||
220 | /* called within callback */ | ||
221 | __cfg80211_send_disassoc(dev, buf, len); | ||
222 | } else { | ||
223 | wdev_lock(wdev); | ||
224 | __cfg80211_send_disassoc(dev, buf, len); | ||
225 | wdev_unlock(wdev); | ||
226 | } | ||
185 | } | 227 | } |
186 | EXPORT_SYMBOL(cfg80211_send_disassoc); | 228 | EXPORT_SYMBOL(cfg80211_send_disassoc); |
187 | 229 | ||
@@ -193,13 +235,13 @@ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) | |||
193 | int i; | 235 | int i; |
194 | bool done = false; | 236 | bool done = false; |
195 | 237 | ||
196 | might_sleep(); | 238 | wdev_lock(wdev); |
197 | 239 | ||
198 | nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL); | 240 | nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL); |
199 | if (wdev->sme_state == CFG80211_SME_CONNECTING) | 241 | if (wdev->sme_state == CFG80211_SME_CONNECTING) |
200 | cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, | 242 | __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, |
201 | WLAN_STATUS_UNSPECIFIED_FAILURE, | 243 | WLAN_STATUS_UNSPECIFIED_FAILURE, |
202 | GFP_KERNEL); | 244 | false); |
203 | 245 | ||
204 | for (i = 0; addr && i < MAX_AUTH_BSSES; i++) { | 246 | for (i = 0; addr && i < MAX_AUTH_BSSES; i++) { |
205 | if (wdev->authtry_bsses[i] && | 247 | if (wdev->authtry_bsses[i] && |
@@ -214,6 +256,8 @@ void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr) | |||
214 | } | 256 | } |
215 | 257 | ||
216 | WARN_ON(!done); | 258 | WARN_ON(!done); |
259 | |||
260 | wdev_unlock(wdev); | ||
217 | } | 261 | } |
218 | EXPORT_SYMBOL(cfg80211_send_auth_timeout); | 262 | EXPORT_SYMBOL(cfg80211_send_auth_timeout); |
219 | 263 | ||
@@ -225,13 +269,13 @@ void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr) | |||
225 | int i; | 269 | int i; |
226 | bool done = false; | 270 | bool done = false; |
227 | 271 | ||
228 | might_sleep(); | 272 | wdev_lock(wdev); |
229 | 273 | ||
230 | nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL); | 274 | nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL); |
231 | if (wdev->sme_state == CFG80211_SME_CONNECTING) | 275 | if (wdev->sme_state == CFG80211_SME_CONNECTING) |
232 | cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, | 276 | __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, |
233 | WLAN_STATUS_UNSPECIFIED_FAILURE, | 277 | WLAN_STATUS_UNSPECIFIED_FAILURE, |
234 | GFP_KERNEL); | 278 | false); |
235 | 279 | ||
236 | for (i = 0; addr && i < MAX_AUTH_BSSES; i++) { | 280 | for (i = 0; addr && i < MAX_AUTH_BSSES; i++) { |
237 | if (wdev->auth_bsses[i] && | 281 | if (wdev->auth_bsses[i] && |
@@ -246,6 +290,8 @@ void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr) | |||
246 | } | 290 | } |
247 | 291 | ||
248 | WARN_ON(!done); | 292 | WARN_ON(!done); |
293 | |||
294 | wdev_unlock(wdev); | ||
249 | } | 295 | } |
250 | EXPORT_SYMBOL(cfg80211_send_assoc_timeout); | 296 | EXPORT_SYMBOL(cfg80211_send_assoc_timeout); |
251 | 297 | ||
@@ -276,17 +322,21 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr, | |||
276 | EXPORT_SYMBOL(cfg80211_michael_mic_failure); | 322 | EXPORT_SYMBOL(cfg80211_michael_mic_failure); |
277 | 323 | ||
278 | /* some MLME handling for userspace SME */ | 324 | /* some MLME handling for userspace SME */ |
279 | int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | 325 | int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, |
280 | struct net_device *dev, struct ieee80211_channel *chan, | 326 | struct net_device *dev, |
281 | enum nl80211_auth_type auth_type, const u8 *bssid, | 327 | struct ieee80211_channel *chan, |
282 | const u8 *ssid, int ssid_len, | 328 | enum nl80211_auth_type auth_type, |
283 | const u8 *ie, int ie_len) | 329 | const u8 *bssid, |
330 | const u8 *ssid, int ssid_len, | ||
331 | const u8 *ie, int ie_len) | ||
284 | { | 332 | { |
285 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 333 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
286 | struct cfg80211_auth_request req; | 334 | struct cfg80211_auth_request req; |
287 | struct cfg80211_internal_bss *bss; | 335 | struct cfg80211_internal_bss *bss; |
288 | int i, err, slot = -1, nfree = 0; | 336 | int i, err, slot = -1, nfree = 0; |
289 | 337 | ||
338 | ASSERT_WDEV_LOCK(wdev); | ||
339 | |||
290 | if (wdev->current_bss && | 340 | if (wdev->current_bss && |
291 | memcmp(bssid, wdev->current_bss->pub.bssid, ETH_ALEN) == 0) | 341 | memcmp(bssid, wdev->current_bss->pub.bssid, ETH_ALEN) == 0) |
292 | return -EALREADY; | 342 | return -EALREADY; |
@@ -342,18 +392,37 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | |||
342 | return err; | 392 | return err; |
343 | } | 393 | } |
344 | 394 | ||
345 | int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | 395 | int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, |
346 | struct net_device *dev, struct ieee80211_channel *chan, | 396 | struct net_device *dev, struct ieee80211_channel *chan, |
347 | const u8 *bssid, const u8 *prev_bssid, | 397 | enum nl80211_auth_type auth_type, const u8 *bssid, |
348 | const u8 *ssid, int ssid_len, | 398 | const u8 *ssid, int ssid_len, |
349 | const u8 *ie, int ie_len, bool use_mfp, | 399 | const u8 *ie, int ie_len) |
350 | struct cfg80211_crypto_settings *crypt) | 400 | { |
401 | int err; | ||
402 | |||
403 | wdev_lock(dev->ieee80211_ptr); | ||
404 | err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, | ||
405 | ssid, ssid_len, ie, ie_len); | ||
406 | wdev_unlock(dev->ieee80211_ptr); | ||
407 | |||
408 | return err; | ||
409 | } | ||
410 | |||
411 | int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | ||
412 | struct net_device *dev, | ||
413 | struct ieee80211_channel *chan, | ||
414 | const u8 *bssid, const u8 *prev_bssid, | ||
415 | const u8 *ssid, int ssid_len, | ||
416 | const u8 *ie, int ie_len, bool use_mfp, | ||
417 | struct cfg80211_crypto_settings *crypt) | ||
351 | { | 418 | { |
352 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 419 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
353 | struct cfg80211_assoc_request req; | 420 | struct cfg80211_assoc_request req; |
354 | struct cfg80211_internal_bss *bss; | 421 | struct cfg80211_internal_bss *bss; |
355 | int i, err, slot = -1; | 422 | int i, err, slot = -1; |
356 | 423 | ||
424 | ASSERT_WDEV_LOCK(wdev); | ||
425 | |||
357 | memset(&req, 0, sizeof(req)); | 426 | memset(&req, 0, sizeof(req)); |
358 | 427 | ||
359 | if (wdev->current_bss) | 428 | if (wdev->current_bss) |
@@ -390,14 +459,35 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
390 | return err; | 459 | return err; |
391 | } | 460 | } |
392 | 461 | ||
393 | int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, | 462 | int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, |
394 | struct net_device *dev, const u8 *bssid, | 463 | struct net_device *dev, |
395 | const u8 *ie, int ie_len, u16 reason) | 464 | struct ieee80211_channel *chan, |
465 | const u8 *bssid, const u8 *prev_bssid, | ||
466 | const u8 *ssid, int ssid_len, | ||
467 | const u8 *ie, int ie_len, bool use_mfp, | ||
468 | struct cfg80211_crypto_settings *crypt) | ||
469 | { | ||
470 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
471 | int err; | ||
472 | |||
473 | wdev_lock(wdev); | ||
474 | err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, | ||
475 | ssid, ssid_len, ie, ie_len, use_mfp, crypt); | ||
476 | wdev_unlock(wdev); | ||
477 | |||
478 | return err; | ||
479 | } | ||
480 | |||
481 | int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, | ||
482 | struct net_device *dev, const u8 *bssid, | ||
483 | const u8 *ie, int ie_len, u16 reason) | ||
396 | { | 484 | { |
397 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 485 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
398 | struct cfg80211_deauth_request req; | 486 | struct cfg80211_deauth_request req; |
399 | int i; | 487 | int i; |
400 | 488 | ||
489 | ASSERT_WDEV_LOCK(wdev); | ||
490 | |||
401 | memset(&req, 0, sizeof(req)); | 491 | memset(&req, 0, sizeof(req)); |
402 | req.reason_code = reason; | 492 | req.reason_code = reason; |
403 | req.ie = ie; | 493 | req.ie = ie; |
@@ -421,16 +511,32 @@ int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, | |||
421 | if (!req.bss) | 511 | if (!req.bss) |
422 | return -ENOTCONN; | 512 | return -ENOTCONN; |
423 | 513 | ||
424 | return rdev->ops->deauth(&rdev->wiphy, dev, &req); | 514 | return rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev); |
425 | } | 515 | } |
426 | 516 | ||
427 | int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, | 517 | int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, |
428 | struct net_device *dev, const u8 *bssid, | 518 | struct net_device *dev, const u8 *bssid, |
429 | const u8 *ie, int ie_len, u16 reason) | 519 | const u8 *ie, int ie_len, u16 reason) |
520 | { | ||
521 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
522 | int err; | ||
523 | |||
524 | wdev_lock(wdev); | ||
525 | err = __cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason); | ||
526 | wdev_unlock(wdev); | ||
527 | |||
528 | return err; | ||
529 | } | ||
530 | |||
531 | static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, | ||
532 | struct net_device *dev, const u8 *bssid, | ||
533 | const u8 *ie, int ie_len, u16 reason) | ||
430 | { | 534 | { |
431 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 535 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
432 | struct cfg80211_disassoc_request req; | 536 | struct cfg80211_disassoc_request req; |
433 | 537 | ||
538 | ASSERT_WDEV_LOCK(wdev); | ||
539 | |||
434 | memset(&req, 0, sizeof(req)); | 540 | memset(&req, 0, sizeof(req)); |
435 | req.reason_code = reason; | 541 | req.reason_code = reason; |
436 | req.ie = ie; | 542 | req.ie = ie; |
@@ -440,7 +546,21 @@ int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, | |||
440 | else | 546 | else |
441 | return -ENOTCONN; | 547 | return -ENOTCONN; |
442 | 548 | ||
443 | return rdev->ops->disassoc(&rdev->wiphy, dev, &req); | 549 | return rdev->ops->disassoc(&rdev->wiphy, dev, &req, wdev); |
550 | } | ||
551 | |||
552 | int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, | ||
553 | struct net_device *dev, const u8 *bssid, | ||
554 | const u8 *ie, int ie_len, u16 reason) | ||
555 | { | ||
556 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
557 | int err; | ||
558 | |||
559 | wdev_lock(wdev); | ||
560 | err = __cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason); | ||
561 | wdev_unlock(wdev); | ||
562 | |||
563 | return err; | ||
444 | } | 564 | } |
445 | 565 | ||
446 | void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, | 566 | void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, |
@@ -450,6 +570,8 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, | |||
450 | struct cfg80211_deauth_request req; | 570 | struct cfg80211_deauth_request req; |
451 | int i; | 571 | int i; |
452 | 572 | ||
573 | ASSERT_WDEV_LOCK(wdev); | ||
574 | |||
453 | if (!rdev->ops->deauth) | 575 | if (!rdev->ops->deauth) |
454 | return; | 576 | return; |
455 | 577 | ||
@@ -460,7 +582,7 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, | |||
460 | 582 | ||
461 | if (wdev->current_bss) { | 583 | if (wdev->current_bss) { |
462 | req.bss = &wdev->current_bss->pub; | 584 | req.bss = &wdev->current_bss->pub; |
463 | rdev->ops->deauth(&rdev->wiphy, dev, &req); | 585 | rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev); |
464 | if (wdev->current_bss) { | 586 | if (wdev->current_bss) { |
465 | cfg80211_unhold_bss(wdev->current_bss); | 587 | cfg80211_unhold_bss(wdev->current_bss); |
466 | cfg80211_put_bss(&wdev->current_bss->pub); | 588 | cfg80211_put_bss(&wdev->current_bss->pub); |
@@ -471,7 +593,7 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, | |||
471 | for (i = 0; i < MAX_AUTH_BSSES; i++) { | 593 | for (i = 0; i < MAX_AUTH_BSSES; i++) { |
472 | if (wdev->auth_bsses[i]) { | 594 | if (wdev->auth_bsses[i]) { |
473 | req.bss = &wdev->auth_bsses[i]->pub; | 595 | req.bss = &wdev->auth_bsses[i]->pub; |
474 | rdev->ops->deauth(&rdev->wiphy, dev, &req); | 596 | rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev); |
475 | if (wdev->auth_bsses[i]) { | 597 | if (wdev->auth_bsses[i]) { |
476 | cfg80211_unhold_bss(wdev->auth_bsses[i]); | 598 | cfg80211_unhold_bss(wdev->auth_bsses[i]); |
477 | cfg80211_put_bss(&wdev->auth_bsses[i]->pub); | 599 | cfg80211_put_bss(&wdev->auth_bsses[i]->pub); |
@@ -480,7 +602,7 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, | |||
480 | } | 602 | } |
481 | if (wdev->authtry_bsses[i]) { | 603 | if (wdev->authtry_bsses[i]) { |
482 | req.bss = &wdev->authtry_bsses[i]->pub; | 604 | req.bss = &wdev->authtry_bsses[i]->pub; |
483 | rdev->ops->deauth(&rdev->wiphy, dev, &req); | 605 | rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev); |
484 | if (wdev->authtry_bsses[i]) { | 606 | if (wdev->authtry_bsses[i]) { |
485 | cfg80211_unhold_bss(wdev->authtry_bsses[i]); | 607 | cfg80211_unhold_bss(wdev->authtry_bsses[i]); |
486 | cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); | 608 | cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); |