diff options
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/core.c | 92 | ||||
-rw-r--r-- | net/wireless/core.h | 100 | ||||
-rw-r--r-- | net/wireless/ibss.c | 133 | ||||
-rw-r--r-- | net/wireless/mlme.c | 214 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 8 | ||||
-rw-r--r-- | net/wireless/nl80211.h | 2 | ||||
-rw-r--r-- | net/wireless/scan.c | 30 | ||||
-rw-r--r-- | net/wireless/sme.c | 252 | ||||
-rw-r--r-- | net/wireless/wext-sme.c | 125 |
9 files changed, 776 insertions, 180 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c index c6813beded06..9c73769440a8 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -257,6 +257,71 @@ static void cfg80211_rfkill_sync_work(struct work_struct *work) | |||
257 | cfg80211_rfkill_set_block(drv, rfkill_blocked(drv->rfkill)); | 257 | cfg80211_rfkill_set_block(drv, rfkill_blocked(drv->rfkill)); |
258 | } | 258 | } |
259 | 259 | ||
260 | static void cfg80211_process_events(struct wireless_dev *wdev) | ||
261 | { | ||
262 | struct cfg80211_event *ev; | ||
263 | unsigned long flags; | ||
264 | |||
265 | spin_lock_irqsave(&wdev->event_lock, flags); | ||
266 | while (!list_empty(&wdev->event_list)) { | ||
267 | ev = list_first_entry(&wdev->event_list, | ||
268 | struct cfg80211_event, list); | ||
269 | list_del(&ev->list); | ||
270 | spin_unlock_irqrestore(&wdev->event_lock, flags); | ||
271 | |||
272 | wdev_lock(wdev); | ||
273 | switch (ev->type) { | ||
274 | case EVENT_CONNECT_RESULT: | ||
275 | __cfg80211_connect_result( | ||
276 | wdev->netdev, ev->cr.bssid, | ||
277 | ev->cr.req_ie, ev->cr.req_ie_len, | ||
278 | ev->cr.resp_ie, ev->cr.resp_ie_len, | ||
279 | ev->cr.status, | ||
280 | ev->cr.status == WLAN_STATUS_SUCCESS); | ||
281 | break; | ||
282 | case EVENT_ROAMED: | ||
283 | __cfg80211_roamed(wdev, ev->rm.bssid, | ||
284 | ev->rm.req_ie, ev->rm.req_ie_len, | ||
285 | ev->rm.resp_ie, ev->rm.resp_ie_len); | ||
286 | break; | ||
287 | case EVENT_DISCONNECTED: | ||
288 | __cfg80211_disconnected(wdev->netdev, | ||
289 | ev->dc.ie, ev->dc.ie_len, | ||
290 | ev->dc.reason, true); | ||
291 | break; | ||
292 | case EVENT_IBSS_JOINED: | ||
293 | __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid); | ||
294 | break; | ||
295 | } | ||
296 | wdev_unlock(wdev); | ||
297 | |||
298 | kfree(ev); | ||
299 | |||
300 | spin_lock_irqsave(&wdev->event_lock, flags); | ||
301 | } | ||
302 | spin_unlock_irqrestore(&wdev->event_lock, flags); | ||
303 | } | ||
304 | |||
305 | static void cfg80211_event_work(struct work_struct *work) | ||
306 | { | ||
307 | struct cfg80211_registered_device *rdev; | ||
308 | struct wireless_dev *wdev; | ||
309 | |||
310 | rdev = container_of(work, struct cfg80211_registered_device, | ||
311 | event_work); | ||
312 | |||
313 | rtnl_lock(); | ||
314 | cfg80211_lock_rdev(rdev); | ||
315 | mutex_lock(&rdev->devlist_mtx); | ||
316 | |||
317 | list_for_each_entry(wdev, &rdev->netdev_list, list) | ||
318 | cfg80211_process_events(wdev); | ||
319 | |||
320 | mutex_unlock(&rdev->devlist_mtx); | ||
321 | cfg80211_unlock_rdev(rdev); | ||
322 | rtnl_unlock(); | ||
323 | } | ||
324 | |||
260 | /* exported functions */ | 325 | /* exported functions */ |
261 | 326 | ||
262 | struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | 327 | struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) |
@@ -299,6 +364,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
299 | INIT_LIST_HEAD(&drv->netdev_list); | 364 | INIT_LIST_HEAD(&drv->netdev_list); |
300 | spin_lock_init(&drv->bss_lock); | 365 | spin_lock_init(&drv->bss_lock); |
301 | INIT_LIST_HEAD(&drv->bss_list); | 366 | INIT_LIST_HEAD(&drv->bss_list); |
367 | INIT_WORK(&drv->scan_done_wk, __cfg80211_scan_done); | ||
302 | 368 | ||
303 | device_initialize(&drv->wiphy.dev); | 369 | device_initialize(&drv->wiphy.dev); |
304 | drv->wiphy.dev.class = &ieee80211_class; | 370 | drv->wiphy.dev.class = &ieee80211_class; |
@@ -316,6 +382,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
316 | 382 | ||
317 | INIT_WORK(&drv->rfkill_sync, cfg80211_rfkill_sync_work); | 383 | INIT_WORK(&drv->rfkill_sync, cfg80211_rfkill_sync_work); |
318 | INIT_WORK(&drv->conn_work, cfg80211_conn_work); | 384 | INIT_WORK(&drv->conn_work, cfg80211_conn_work); |
385 | INIT_WORK(&drv->event_work, cfg80211_event_work); | ||
319 | 386 | ||
320 | /* | 387 | /* |
321 | * Initialize wiphy parameters to IEEE 802.11 MIB default values. | 388 | * Initialize wiphy parameters to IEEE 802.11 MIB default values. |
@@ -477,6 +544,9 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
477 | mutex_unlock(&drv->mtx); | 544 | mutex_unlock(&drv->mtx); |
478 | 545 | ||
479 | cancel_work_sync(&drv->conn_work); | 546 | cancel_work_sync(&drv->conn_work); |
547 | cancel_work_sync(&drv->scan_done_wk); | ||
548 | kfree(drv->scan_req); | ||
549 | flush_work(&drv->event_work); | ||
480 | 550 | ||
481 | cfg80211_debugfs_drv_del(drv); | 551 | cfg80211_debugfs_drv_del(drv); |
482 | 552 | ||
@@ -535,6 +605,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
535 | 605 | ||
536 | switch (state) { | 606 | switch (state) { |
537 | case NETDEV_REGISTER: | 607 | case NETDEV_REGISTER: |
608 | mutex_init(&wdev->mtx); | ||
609 | INIT_LIST_HEAD(&wdev->event_list); | ||
610 | spin_lock_init(&wdev->event_lock); | ||
538 | mutex_lock(&rdev->devlist_mtx); | 611 | mutex_lock(&rdev->devlist_mtx); |
539 | list_add(&wdev->list, &rdev->netdev_list); | 612 | list_add(&wdev->list, &rdev->netdev_list); |
540 | if (sysfs_create_link(&dev->dev.kobj, &rdev->wiphy.dev.kobj, | 613 | if (sysfs_create_link(&dev->dev.kobj, &rdev->wiphy.dev.kobj, |
@@ -566,15 +639,17 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
566 | cfg80211_leave_ibss(rdev, dev, true); | 639 | cfg80211_leave_ibss(rdev, dev, true); |
567 | break; | 640 | break; |
568 | case NL80211_IFTYPE_STATION: | 641 | case NL80211_IFTYPE_STATION: |
642 | wdev_lock(wdev); | ||
569 | #ifdef CONFIG_WIRELESS_EXT | 643 | #ifdef CONFIG_WIRELESS_EXT |
570 | kfree(wdev->wext.ie); | 644 | kfree(wdev->wext.ie); |
571 | wdev->wext.ie = NULL; | 645 | wdev->wext.ie = NULL; |
572 | wdev->wext.ie_len = 0; | 646 | wdev->wext.ie_len = 0; |
573 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; | 647 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; |
574 | #endif | 648 | #endif |
575 | cfg80211_disconnect(rdev, dev, | 649 | __cfg80211_disconnect(rdev, dev, |
576 | WLAN_REASON_DEAUTH_LEAVING, true); | 650 | WLAN_REASON_DEAUTH_LEAVING, true); |
577 | cfg80211_mlme_down(rdev, dev); | 651 | cfg80211_mlme_down(rdev, dev); |
652 | wdev_unlock(wdev); | ||
578 | break; | 653 | break; |
579 | default: | 654 | default: |
580 | break; | 655 | break; |
@@ -582,20 +657,24 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
582 | break; | 657 | break; |
583 | case NETDEV_UP: | 658 | case NETDEV_UP: |
584 | #ifdef CONFIG_WIRELESS_EXT | 659 | #ifdef CONFIG_WIRELESS_EXT |
660 | cfg80211_lock_rdev(rdev); | ||
661 | wdev_lock(wdev); | ||
585 | switch (wdev->iftype) { | 662 | switch (wdev->iftype) { |
586 | case NL80211_IFTYPE_ADHOC: | 663 | case NL80211_IFTYPE_ADHOC: |
587 | if (wdev->wext.ibss.ssid_len) | 664 | if (wdev->wext.ibss.ssid_len) |
588 | cfg80211_join_ibss(rdev, dev, | 665 | __cfg80211_join_ibss(rdev, dev, |
589 | &wdev->wext.ibss); | 666 | &wdev->wext.ibss); |
590 | break; | 667 | break; |
591 | case NL80211_IFTYPE_STATION: | 668 | case NL80211_IFTYPE_STATION: |
592 | if (wdev->wext.connect.ssid_len) | 669 | if (wdev->wext.connect.ssid_len) |
593 | cfg80211_connect(rdev, dev, | 670 | __cfg80211_connect(rdev, dev, |
594 | &wdev->wext.connect); | 671 | &wdev->wext.connect); |
595 | break; | 672 | break; |
596 | default: | 673 | default: |
597 | break; | 674 | break; |
598 | } | 675 | } |
676 | wdev_unlock(wdev); | ||
677 | cfg80211_unlock_rdev(rdev); | ||
599 | #endif | 678 | #endif |
600 | break; | 679 | break; |
601 | case NETDEV_UNREGISTER: | 680 | case NETDEV_UNREGISTER: |
@@ -605,6 +684,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
605 | list_del_init(&wdev->list); | 684 | list_del_init(&wdev->list); |
606 | } | 685 | } |
607 | mutex_unlock(&rdev->devlist_mtx); | 686 | mutex_unlock(&rdev->devlist_mtx); |
687 | mutex_destroy(&wdev->mtx); | ||
608 | break; | 688 | break; |
609 | case NETDEV_PRE_UP: | 689 | case NETDEV_PRE_UP: |
610 | if (rfkill_blocked(rdev->rfkill)) | 690 | if (rfkill_blocked(rdev->rfkill)) |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 92da612b3f9e..5ccd642e183b 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -57,12 +57,14 @@ struct cfg80211_registered_device { | |||
57 | u32 bss_generation; | 57 | u32 bss_generation; |
58 | struct cfg80211_scan_request *scan_req; /* protected by RTNL */ | 58 | struct cfg80211_scan_request *scan_req; /* protected by RTNL */ |
59 | unsigned long suspend_at; | 59 | unsigned long suspend_at; |
60 | struct work_struct scan_done_wk; | ||
60 | 61 | ||
61 | #ifdef CONFIG_NL80211_TESTMODE | 62 | #ifdef CONFIG_NL80211_TESTMODE |
62 | struct genl_info *testmode_info; | 63 | struct genl_info *testmode_info; |
63 | #endif | 64 | #endif |
64 | 65 | ||
65 | struct work_struct conn_work; | 66 | struct work_struct conn_work; |
67 | struct work_struct event_work; | ||
66 | 68 | ||
67 | #ifdef CONFIG_CFG80211_DEBUGFS | 69 | #ifdef CONFIG_CFG80211_DEBUGFS |
68 | /* Debugfs entries */ | 70 | /* Debugfs entries */ |
@@ -170,12 +172,73 @@ struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx); | |||
170 | extern struct cfg80211_registered_device * | 172 | extern struct cfg80211_registered_device * |
171 | cfg80211_get_dev_from_ifindex(int ifindex); | 173 | cfg80211_get_dev_from_ifindex(int ifindex); |
172 | 174 | ||
175 | static inline void cfg80211_lock_rdev(struct cfg80211_registered_device *drv) | ||
176 | { | ||
177 | mutex_lock(&drv->mtx); | ||
178 | } | ||
179 | |||
173 | static inline void cfg80211_unlock_rdev(struct cfg80211_registered_device *drv) | 180 | static inline void cfg80211_unlock_rdev(struct cfg80211_registered_device *drv) |
174 | { | 181 | { |
175 | BUG_ON(IS_ERR(drv) || !drv); | 182 | BUG_ON(IS_ERR(drv) || !drv); |
176 | mutex_unlock(&drv->mtx); | 183 | mutex_unlock(&drv->mtx); |
177 | } | 184 | } |
178 | 185 | ||
186 | static inline void wdev_lock(struct wireless_dev *wdev) | ||
187 | __acquires(wdev) | ||
188 | { | ||
189 | mutex_lock(&wdev->mtx); | ||
190 | __acquire(wdev->mtx); | ||
191 | } | ||
192 | |||
193 | static inline void wdev_unlock(struct wireless_dev *wdev) | ||
194 | __releases(wdev) | ||
195 | { | ||
196 | __release(wdev->mtx); | ||
197 | mutex_unlock(&wdev->mtx); | ||
198 | } | ||
199 | |||
200 | #define ASSERT_RDEV_LOCK(rdev) WARN_ON(!mutex_is_locked(&(rdev)->mtx)); | ||
201 | #define ASSERT_WDEV_LOCK(wdev) WARN_ON(!mutex_is_locked(&(wdev)->mtx)); | ||
202 | |||
203 | enum cfg80211_event_type { | ||
204 | EVENT_CONNECT_RESULT, | ||
205 | EVENT_ROAMED, | ||
206 | EVENT_DISCONNECTED, | ||
207 | EVENT_IBSS_JOINED, | ||
208 | }; | ||
209 | |||
210 | struct cfg80211_event { | ||
211 | struct list_head list; | ||
212 | enum cfg80211_event_type type; | ||
213 | |||
214 | union { | ||
215 | struct { | ||
216 | u8 bssid[ETH_ALEN]; | ||
217 | const u8 *req_ie; | ||
218 | const u8 *resp_ie; | ||
219 | size_t req_ie_len; | ||
220 | size_t resp_ie_len; | ||
221 | u16 status; | ||
222 | } cr; | ||
223 | struct { | ||
224 | u8 bssid[ETH_ALEN]; | ||
225 | const u8 *req_ie; | ||
226 | const u8 *resp_ie; | ||
227 | size_t req_ie_len; | ||
228 | size_t resp_ie_len; | ||
229 | } rm; | ||
230 | struct { | ||
231 | const u8 *ie; | ||
232 | size_t ie_len; | ||
233 | u16 reason; | ||
234 | } dc; | ||
235 | struct { | ||
236 | u8 bssid[ETH_ALEN]; | ||
237 | } ij; | ||
238 | }; | ||
239 | }; | ||
240 | |||
241 | |||
179 | /* free object */ | 242 | /* free object */ |
180 | extern void cfg80211_dev_free(struct cfg80211_registered_device *drv); | 243 | extern void cfg80211_dev_free(struct cfg80211_registered_device *drv); |
181 | 244 | ||
@@ -191,25 +254,46 @@ void cfg80211_bss_age(struct cfg80211_registered_device *dev, | |||
191 | unsigned long age_secs); | 254 | unsigned long age_secs); |
192 | 255 | ||
193 | /* IBSS */ | 256 | /* IBSS */ |
257 | int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, | ||
258 | struct net_device *dev, | ||
259 | struct cfg80211_ibss_params *params); | ||
194 | int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, | 260 | int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, |
195 | struct net_device *dev, | 261 | struct net_device *dev, |
196 | struct cfg80211_ibss_params *params); | 262 | struct cfg80211_ibss_params *params); |
197 | void cfg80211_clear_ibss(struct net_device *dev, bool nowext); | 263 | void cfg80211_clear_ibss(struct net_device *dev, bool nowext); |
198 | int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, | 264 | int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, |
199 | struct net_device *dev, bool nowext); | 265 | struct net_device *dev, bool nowext); |
266 | void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid); | ||
200 | 267 | ||
201 | /* MLME */ | 268 | /* MLME */ |
269 | int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | ||
270 | struct net_device *dev, | ||
271 | struct ieee80211_channel *chan, | ||
272 | enum nl80211_auth_type auth_type, | ||
273 | const u8 *bssid, | ||
274 | const u8 *ssid, int ssid_len, | ||
275 | const u8 *ie, int ie_len); | ||
202 | int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | 276 | int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, |
203 | struct net_device *dev, struct ieee80211_channel *chan, | 277 | struct net_device *dev, struct ieee80211_channel *chan, |
204 | enum nl80211_auth_type auth_type, const u8 *bssid, | 278 | enum nl80211_auth_type auth_type, const u8 *bssid, |
205 | const u8 *ssid, int ssid_len, | 279 | const u8 *ssid, int ssid_len, |
206 | const u8 *ie, int ie_len); | 280 | const u8 *ie, int ie_len); |
281 | int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | ||
282 | struct net_device *dev, | ||
283 | struct ieee80211_channel *chan, | ||
284 | const u8 *bssid, const u8 *prev_bssid, | ||
285 | const u8 *ssid, int ssid_len, | ||
286 | const u8 *ie, int ie_len, bool use_mfp, | ||
287 | struct cfg80211_crypto_settings *crypt); | ||
207 | int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | 288 | int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, |
208 | struct net_device *dev, struct ieee80211_channel *chan, | 289 | struct net_device *dev, struct ieee80211_channel *chan, |
209 | const u8 *bssid, const u8 *prev_bssid, | 290 | const u8 *bssid, const u8 *prev_bssid, |
210 | const u8 *ssid, int ssid_len, | 291 | const u8 *ssid, int ssid_len, |
211 | const u8 *ie, int ie_len, bool use_mfp, | 292 | const u8 *ie, int ie_len, bool use_mfp, |
212 | struct cfg80211_crypto_settings *crypt); | 293 | struct cfg80211_crypto_settings *crypt); |
294 | int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, | ||
295 | struct net_device *dev, const u8 *bssid, | ||
296 | const u8 *ie, int ie_len, u16 reason); | ||
213 | int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, | 297 | int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, |
214 | struct net_device *dev, const u8 *bssid, | 298 | struct net_device *dev, const u8 *bssid, |
215 | const u8 *ie, int ie_len, u16 reason); | 299 | const u8 *ie, int ie_len, u16 reason); |
@@ -218,24 +302,38 @@ int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, | |||
218 | const u8 *ie, int ie_len, u16 reason); | 302 | const u8 *ie, int ie_len, u16 reason); |
219 | void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, | 303 | void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, |
220 | struct net_device *dev); | 304 | struct net_device *dev); |
305 | void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | ||
306 | const u8 *req_ie, size_t req_ie_len, | ||
307 | const u8 *resp_ie, size_t resp_ie_len, | ||
308 | u16 status, bool wextev); | ||
221 | 309 | ||
222 | /* SME */ | 310 | /* SME */ |
311 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, | ||
312 | struct net_device *dev, | ||
313 | struct cfg80211_connect_params *connect); | ||
223 | int cfg80211_connect(struct cfg80211_registered_device *rdev, | 314 | int cfg80211_connect(struct cfg80211_registered_device *rdev, |
224 | struct net_device *dev, | 315 | struct net_device *dev, |
225 | struct cfg80211_connect_params *connect); | 316 | struct cfg80211_connect_params *connect); |
317 | int __cfg80211_disconnect(struct cfg80211_registered_device *rdev, | ||
318 | struct net_device *dev, u16 reason, | ||
319 | bool wextev); | ||
226 | int cfg80211_disconnect(struct cfg80211_registered_device *rdev, | 320 | int cfg80211_disconnect(struct cfg80211_registered_device *rdev, |
227 | struct net_device *dev, u16 reason, | 321 | struct net_device *dev, u16 reason, |
228 | bool wextev); | 322 | bool wextev); |
323 | void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid, | ||
324 | const u8 *req_ie, size_t req_ie_len, | ||
325 | const u8 *resp_ie, size_t resp_ie_len); | ||
229 | 326 | ||
230 | void cfg80211_conn_work(struct work_struct *work); | 327 | void cfg80211_conn_work(struct work_struct *work); |
231 | 328 | ||
232 | /* internal helpers */ | 329 | /* internal helpers */ |
233 | int cfg80211_validate_key_settings(struct key_params *params, int key_idx, | 330 | int cfg80211_validate_key_settings(struct key_params *params, int key_idx, |
234 | const u8 *mac_addr); | 331 | const u8 *mac_addr); |
235 | void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, u8 *ie, | 332 | void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, |
236 | size_t ie_len, u16 reason, bool from_ap); | 333 | size_t ie_len, u16 reason, bool from_ap); |
237 | void cfg80211_sme_scan_done(struct net_device *dev); | 334 | void cfg80211_sme_scan_done(struct net_device *dev); |
238 | void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); | 335 | void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); |
239 | void cfg80211_sme_disassoc(struct net_device *dev, int idx); | 336 | void cfg80211_sme_disassoc(struct net_device *dev, int idx); |
337 | void __cfg80211_scan_done(struct work_struct *wk); | ||
240 | 338 | ||
241 | #endif /* __NET_WIRELESS_CORE_H */ | 339 | #endif /* __NET_WIRELESS_CORE_H */ |
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 | ||
13 | void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp) | 13 | void __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 | |||
51 | void 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 | } | ||
49 | EXPORT_SYMBOL(cfg80211_ibss_joined); | 70 | EXPORT_SYMBOL(cfg80211_ibss_joined); |
50 | 71 | ||
51 | int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, | 72 | int __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 | ||
75 | void cfg80211_clear_ibss(struct net_device *dev, bool nowext) | 98 | int 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 | |||
112 | static 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 | ||
92 | int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, | 131 | void 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 | |||
140 | static 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 | ||
161 | int 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 |
112 | static int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, | 175 | static 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 */ |
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); |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 4976eac888a3..cf4ac786b20a 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -4029,6 +4029,8 @@ static int nl80211_add_scan_req(struct sk_buff *msg, | |||
4029 | struct nlattr *nest; | 4029 | struct nlattr *nest; |
4030 | int i; | 4030 | int i; |
4031 | 4031 | ||
4032 | ASSERT_RDEV_LOCK(rdev); | ||
4033 | |||
4032 | if (WARN_ON(!req)) | 4034 | if (WARN_ON(!req)) |
4033 | return 0; | 4035 | return 0; |
4034 | 4036 | ||
@@ -4391,12 +4393,12 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev, | |||
4391 | 4393 | ||
4392 | void nl80211_send_disconnected(struct cfg80211_registered_device *rdev, | 4394 | void nl80211_send_disconnected(struct cfg80211_registered_device *rdev, |
4393 | struct net_device *netdev, u16 reason, | 4395 | struct net_device *netdev, u16 reason, |
4394 | u8 *ie, size_t ie_len, bool from_ap, gfp_t gfp) | 4396 | const u8 *ie, size_t ie_len, bool from_ap) |
4395 | { | 4397 | { |
4396 | struct sk_buff *msg; | 4398 | struct sk_buff *msg; |
4397 | void *hdr; | 4399 | void *hdr; |
4398 | 4400 | ||
4399 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | 4401 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); |
4400 | if (!msg) | 4402 | if (!msg) |
4401 | return; | 4403 | return; |
4402 | 4404 | ||
@@ -4420,7 +4422,7 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev, | |||
4420 | return; | 4422 | return; |
4421 | } | 4423 | } |
4422 | 4424 | ||
4423 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); | 4425 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_KERNEL); |
4424 | return; | 4426 | return; |
4425 | 4427 | ||
4426 | nla_put_failure: | 4428 | nla_put_failure: |
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index cf3708b48c29..44cc2a76a1b0 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h | |||
@@ -42,7 +42,7 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev, | |||
42 | const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp); | 42 | const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp); |
43 | void nl80211_send_disconnected(struct cfg80211_registered_device *rdev, | 43 | void nl80211_send_disconnected(struct cfg80211_registered_device *rdev, |
44 | struct net_device *netdev, u16 reason, | 44 | struct net_device *netdev, u16 reason, |
45 | u8 *ie, size_t ie_len, bool from_ap, gfp_t gfp); | 45 | const u8 *ie, size_t ie_len, bool from_ap); |
46 | 46 | ||
47 | void | 47 | void |
48 | nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, | 48 | nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, |
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 | ||
20 | void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) | 20 | void __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 | |||
68 | void 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 | } | ||
58 | EXPORT_SYMBOL(cfg80211_scan_done); | 82 | EXPORT_SYMBOL(cfg80211_scan_done); |
59 | 83 | ||
60 | static void bss_release(struct kref *ref) | 84 | static void bss_release(struct kref *ref) |
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 066a19ef9d73..472e2412c781 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -38,6 +38,8 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) | |||
38 | int n_channels, err; | 38 | int n_channels, err; |
39 | 39 | ||
40 | ASSERT_RTNL(); | 40 | ASSERT_RTNL(); |
41 | ASSERT_RDEV_LOCK(drv); | ||
42 | ASSERT_WDEV_LOCK(wdev); | ||
41 | 43 | ||
42 | if (drv->scan_req) | 44 | if (drv->scan_req) |
43 | return -EBUSY; | 45 | return -EBUSY; |
@@ -106,6 +108,8 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) | |||
106 | struct cfg80211_connect_params *params; | 108 | struct cfg80211_connect_params *params; |
107 | int err; | 109 | int err; |
108 | 110 | ||
111 | ASSERT_WDEV_LOCK(wdev); | ||
112 | |||
109 | if (!wdev->conn) | 113 | if (!wdev->conn) |
110 | return 0; | 114 | return 0; |
111 | 115 | ||
@@ -117,11 +121,11 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) | |||
117 | case CFG80211_CONN_AUTHENTICATE_NEXT: | 121 | case CFG80211_CONN_AUTHENTICATE_NEXT: |
118 | BUG_ON(!drv->ops->auth); | 122 | BUG_ON(!drv->ops->auth); |
119 | wdev->conn->state = CFG80211_CONN_AUTHENTICATING; | 123 | wdev->conn->state = CFG80211_CONN_AUTHENTICATING; |
120 | return cfg80211_mlme_auth(drv, wdev->netdev, | 124 | return __cfg80211_mlme_auth(drv, wdev->netdev, |
121 | params->channel, params->auth_type, | 125 | params->channel, params->auth_type, |
122 | params->bssid, | 126 | params->bssid, |
123 | params->ssid, params->ssid_len, | 127 | params->ssid, params->ssid_len, |
124 | NULL, 0); | 128 | NULL, 0); |
125 | case CFG80211_CONN_ASSOCIATE_NEXT: | 129 | case CFG80211_CONN_ASSOCIATE_NEXT: |
126 | BUG_ON(!drv->ops->assoc); | 130 | BUG_ON(!drv->ops->assoc); |
127 | wdev->conn->state = CFG80211_CONN_ASSOCIATING; | 131 | wdev->conn->state = CFG80211_CONN_ASSOCIATING; |
@@ -131,14 +135,16 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) | |||
131 | * that some APs don't like that -- so we'd need to retry | 135 | * that some APs don't like that -- so we'd need to retry |
132 | * the association. | 136 | * the association. |
133 | */ | 137 | */ |
134 | err = cfg80211_mlme_assoc(drv, wdev->netdev, | 138 | err = __cfg80211_mlme_assoc(drv, wdev->netdev, |
135 | params->channel, params->bssid, NULL, | 139 | params->channel, params->bssid, |
136 | params->ssid, params->ssid_len, | 140 | NULL, |
137 | params->ie, params->ie_len, | 141 | params->ssid, params->ssid_len, |
138 | false, ¶ms->crypto); | 142 | params->ie, params->ie_len, |
143 | false, ¶ms->crypto); | ||
139 | if (err) | 144 | if (err) |
140 | cfg80211_mlme_deauth(drv, wdev->netdev, params->bssid, | 145 | __cfg80211_mlme_deauth(drv, wdev->netdev, params->bssid, |
141 | NULL, 0, WLAN_REASON_DEAUTH_LEAVING); | 146 | NULL, 0, |
147 | WLAN_REASON_DEAUTH_LEAVING); | ||
142 | return err; | 148 | return err; |
143 | default: | 149 | default: |
144 | return 0; | 150 | return 0; |
@@ -152,22 +158,31 @@ void cfg80211_conn_work(struct work_struct *work) | |||
152 | struct wireless_dev *wdev; | 158 | struct wireless_dev *wdev; |
153 | 159 | ||
154 | rtnl_lock(); | 160 | rtnl_lock(); |
161 | cfg80211_lock_rdev(drv); | ||
155 | mutex_lock(&drv->devlist_mtx); | 162 | mutex_lock(&drv->devlist_mtx); |
156 | 163 | ||
157 | list_for_each_entry(wdev, &drv->netdev_list, list) { | 164 | list_for_each_entry(wdev, &drv->netdev_list, list) { |
158 | if (!netif_running(wdev->netdev)) | 165 | wdev_lock(wdev); |
166 | if (!netif_running(wdev->netdev)) { | ||
167 | wdev_unlock(wdev); | ||
159 | continue; | 168 | continue; |
160 | if (wdev->sme_state != CFG80211_SME_CONNECTING) | 169 | } |
170 | if (wdev->sme_state != CFG80211_SME_CONNECTING) { | ||
171 | wdev_unlock(wdev); | ||
161 | continue; | 172 | continue; |
173 | } | ||
162 | if (cfg80211_conn_do_work(wdev)) | 174 | if (cfg80211_conn_do_work(wdev)) |
163 | cfg80211_connect_result(wdev->netdev, | 175 | __cfg80211_connect_result( |
164 | wdev->conn->params.bssid, | 176 | wdev->netdev, |
165 | NULL, 0, NULL, 0, | 177 | wdev->conn->params.bssid, |
166 | WLAN_STATUS_UNSPECIFIED_FAILURE, | 178 | NULL, 0, NULL, 0, |
167 | GFP_ATOMIC); | 179 | WLAN_STATUS_UNSPECIFIED_FAILURE, |
180 | false); | ||
181 | wdev_unlock(wdev); | ||
168 | } | 182 | } |
169 | 183 | ||
170 | mutex_unlock(&drv->devlist_mtx); | 184 | mutex_unlock(&drv->devlist_mtx); |
185 | cfg80211_unlock_rdev(drv); | ||
171 | rtnl_unlock(); | 186 | rtnl_unlock(); |
172 | } | 187 | } |
173 | 188 | ||
@@ -177,6 +192,8 @@ static bool cfg80211_get_conn_bss(struct wireless_dev *wdev) | |||
177 | struct cfg80211_bss *bss; | 192 | struct cfg80211_bss *bss; |
178 | u16 capa = WLAN_CAPABILITY_ESS; | 193 | u16 capa = WLAN_CAPABILITY_ESS; |
179 | 194 | ||
195 | ASSERT_WDEV_LOCK(wdev); | ||
196 | |||
180 | if (wdev->conn->params.privacy) | 197 | if (wdev->conn->params.privacy) |
181 | capa |= WLAN_CAPABILITY_PRIVACY; | 198 | capa |= WLAN_CAPABILITY_PRIVACY; |
182 | 199 | ||
@@ -198,11 +215,13 @@ static bool cfg80211_get_conn_bss(struct wireless_dev *wdev) | |||
198 | return true; | 215 | return true; |
199 | } | 216 | } |
200 | 217 | ||
201 | void cfg80211_sme_scan_done(struct net_device *dev) | 218 | static void __cfg80211_sme_scan_done(struct net_device *dev) |
202 | { | 219 | { |
203 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 220 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
204 | struct cfg80211_registered_device *drv = wiphy_to_dev(wdev->wiphy); | 221 | struct cfg80211_registered_device *drv = wiphy_to_dev(wdev->wiphy); |
205 | 222 | ||
223 | ASSERT_WDEV_LOCK(wdev); | ||
224 | |||
206 | if (wdev->sme_state != CFG80211_SME_CONNECTING) | 225 | if (wdev->sme_state != CFG80211_SME_CONNECTING) |
207 | return; | 226 | return; |
208 | 227 | ||
@@ -218,15 +237,26 @@ void cfg80211_sme_scan_done(struct net_device *dev) | |||
218 | if (wdev->conn->state == CFG80211_CONN_SCAN_AGAIN) | 237 | if (wdev->conn->state == CFG80211_CONN_SCAN_AGAIN) |
219 | schedule_work(&drv->conn_work); | 238 | schedule_work(&drv->conn_work); |
220 | else | 239 | else |
221 | cfg80211_connect_result(dev, wdev->conn->params.bssid, | 240 | __cfg80211_connect_result( |
222 | NULL, 0, NULL, 0, | 241 | wdev->netdev, |
223 | WLAN_STATUS_UNSPECIFIED_FAILURE, | 242 | wdev->conn->params.bssid, |
224 | GFP_ATOMIC); | 243 | NULL, 0, NULL, 0, |
225 | return; | 244 | WLAN_STATUS_UNSPECIFIED_FAILURE, |
245 | false); | ||
226 | } | 246 | } |
227 | } | 247 | } |
228 | 248 | ||
229 | void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len) | 249 | void cfg80211_sme_scan_done(struct net_device *dev) |
250 | { | ||
251 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
252 | |||
253 | wdev_lock(wdev); | ||
254 | __cfg80211_sme_scan_done(dev); | ||
255 | wdev_unlock(wdev); | ||
256 | } | ||
257 | |||
258 | void cfg80211_sme_rx_auth(struct net_device *dev, | ||
259 | const u8 *buf, size_t len) | ||
230 | { | 260 | { |
231 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 261 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
232 | struct wiphy *wiphy = wdev->wiphy; | 262 | struct wiphy *wiphy = wdev->wiphy; |
@@ -234,6 +264,8 @@ void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len) | |||
234 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; | 264 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; |
235 | u16 status_code = le16_to_cpu(mgmt->u.auth.status_code); | 265 | u16 status_code = le16_to_cpu(mgmt->u.auth.status_code); |
236 | 266 | ||
267 | ASSERT_WDEV_LOCK(wdev); | ||
268 | |||
237 | /* should only RX auth frames when connecting */ | 269 | /* should only RX auth frames when connecting */ |
238 | if (wdev->sme_state != CFG80211_SME_CONNECTING) | 270 | if (wdev->sme_state != CFG80211_SME_CONNECTING) |
239 | return; | 271 | return; |
@@ -273,10 +305,10 @@ void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len) | |||
273 | } | 305 | } |
274 | } | 306 | } |
275 | 307 | ||
276 | static void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | 308 | void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, |
277 | const u8 *req_ie, size_t req_ie_len, | 309 | const u8 *req_ie, size_t req_ie_len, |
278 | const u8 *resp_ie, size_t resp_ie_len, | 310 | const u8 *resp_ie, size_t resp_ie_len, |
279 | u16 status, bool wextev, gfp_t gfp) | 311 | u16 status, bool wextev) |
280 | { | 312 | { |
281 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 313 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
282 | struct cfg80211_bss *bss; | 314 | struct cfg80211_bss *bss; |
@@ -284,18 +316,20 @@ static void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
284 | union iwreq_data wrqu; | 316 | union iwreq_data wrqu; |
285 | #endif | 317 | #endif |
286 | 318 | ||
319 | ASSERT_WDEV_LOCK(wdev); | ||
320 | |||
287 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) | 321 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) |
288 | return; | 322 | return; |
289 | 323 | ||
290 | if (wdev->sme_state == CFG80211_SME_CONNECTED) | 324 | if (wdev->sme_state == CFG80211_SME_CONNECTED) |
291 | nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), dev, | 325 | nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), dev, |
292 | bssid, req_ie, req_ie_len, | 326 | bssid, req_ie, req_ie_len, |
293 | resp_ie, resp_ie_len, gfp); | 327 | resp_ie, resp_ie_len, GFP_KERNEL); |
294 | else | 328 | else |
295 | nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev, | 329 | nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev, |
296 | bssid, req_ie, req_ie_len, | 330 | bssid, req_ie, req_ie_len, |
297 | resp_ie, resp_ie_len, | 331 | resp_ie, resp_ie_len, |
298 | status, gfp); | 332 | status, GFP_KERNEL); |
299 | 333 | ||
300 | #ifdef CONFIG_WIRELESS_EXT | 334 | #ifdef CONFIG_WIRELESS_EXT |
301 | if (wextev) { | 335 | if (wextev) { |
@@ -362,21 +396,43 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
362 | const u8 *resp_ie, size_t resp_ie_len, | 396 | const u8 *resp_ie, size_t resp_ie_len, |
363 | u16 status, gfp_t gfp) | 397 | u16 status, gfp_t gfp) |
364 | { | 398 | { |
365 | bool wextev = status == WLAN_STATUS_SUCCESS; | 399 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
366 | __cfg80211_connect_result(dev, bssid, req_ie, req_ie_len, resp_ie, resp_ie_len, status, wextev, gfp); | 400 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
401 | struct cfg80211_event *ev; | ||
402 | unsigned long flags; | ||
403 | |||
404 | ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp); | ||
405 | if (!ev) | ||
406 | return; | ||
407 | |||
408 | ev->type = EVENT_CONNECT_RESULT; | ||
409 | memcpy(ev->cr.bssid, bssid, ETH_ALEN); | ||
410 | ev->cr.req_ie = ((u8 *)ev) + sizeof(*ev); | ||
411 | ev->cr.req_ie_len = req_ie_len; | ||
412 | memcpy((void *)ev->cr.req_ie, req_ie, req_ie_len); | ||
413 | ev->cr.resp_ie = ((u8 *)ev) + sizeof(*ev) + req_ie_len; | ||
414 | ev->cr.resp_ie_len = resp_ie_len; | ||
415 | memcpy((void *)ev->cr.resp_ie, resp_ie, resp_ie_len); | ||
416 | ev->cr.status = status; | ||
417 | |||
418 | spin_lock_irqsave(&wdev->event_lock, flags); | ||
419 | list_add_tail(&ev->list, &wdev->event_list); | ||
420 | spin_unlock_irqrestore(&wdev->event_lock, flags); | ||
421 | schedule_work(&rdev->event_work); | ||
367 | } | 422 | } |
368 | EXPORT_SYMBOL(cfg80211_connect_result); | 423 | EXPORT_SYMBOL(cfg80211_connect_result); |
369 | 424 | ||
370 | void cfg80211_roamed(struct net_device *dev, const u8 *bssid, | 425 | void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid, |
371 | const u8 *req_ie, size_t req_ie_len, | 426 | const u8 *req_ie, size_t req_ie_len, |
372 | const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp) | 427 | const u8 *resp_ie, size_t resp_ie_len) |
373 | { | 428 | { |
374 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
375 | struct cfg80211_bss *bss; | 429 | struct cfg80211_bss *bss; |
376 | #ifdef CONFIG_WIRELESS_EXT | 430 | #ifdef CONFIG_WIRELESS_EXT |
377 | union iwreq_data wrqu; | 431 | union iwreq_data wrqu; |
378 | #endif | 432 | #endif |
379 | 433 | ||
434 | ASSERT_WDEV_LOCK(wdev); | ||
435 | |||
380 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) | 436 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) |
381 | return; | 437 | return; |
382 | 438 | ||
@@ -402,31 +458,62 @@ void cfg80211_roamed(struct net_device *dev, const u8 *bssid, | |||
402 | cfg80211_hold_bss(bss_from_pub(bss)); | 458 | cfg80211_hold_bss(bss_from_pub(bss)); |
403 | wdev->current_bss = bss_from_pub(bss); | 459 | wdev->current_bss = bss_from_pub(bss); |
404 | 460 | ||
405 | nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), dev, bssid, | 461 | nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), wdev->netdev, bssid, |
406 | req_ie, req_ie_len, resp_ie, resp_ie_len, gfp); | 462 | req_ie, req_ie_len, resp_ie, resp_ie_len, |
463 | GFP_KERNEL); | ||
407 | 464 | ||
408 | #ifdef CONFIG_WIRELESS_EXT | 465 | #ifdef CONFIG_WIRELESS_EXT |
409 | if (req_ie) { | 466 | if (req_ie) { |
410 | memset(&wrqu, 0, sizeof(wrqu)); | 467 | memset(&wrqu, 0, sizeof(wrqu)); |
411 | wrqu.data.length = req_ie_len; | 468 | wrqu.data.length = req_ie_len; |
412 | wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, req_ie); | 469 | wireless_send_event(wdev->netdev, IWEVASSOCRESPIE, |
470 | &wrqu, req_ie); | ||
413 | } | 471 | } |
414 | 472 | ||
415 | if (resp_ie) { | 473 | if (resp_ie) { |
416 | memset(&wrqu, 0, sizeof(wrqu)); | 474 | memset(&wrqu, 0, sizeof(wrqu)); |
417 | wrqu.data.length = resp_ie_len; | 475 | wrqu.data.length = resp_ie_len; |
418 | wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, resp_ie); | 476 | wireless_send_event(wdev->netdev, IWEVASSOCRESPIE, |
477 | &wrqu, resp_ie); | ||
419 | } | 478 | } |
420 | 479 | ||
421 | memset(&wrqu, 0, sizeof(wrqu)); | 480 | memset(&wrqu, 0, sizeof(wrqu)); |
422 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | 481 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; |
423 | memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); | 482 | memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); |
424 | wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); | 483 | wireless_send_event(wdev->netdev, SIOCGIWAP, &wrqu, NULL); |
425 | #endif | 484 | #endif |
426 | } | 485 | } |
486 | |||
487 | void cfg80211_roamed(struct net_device *dev, const u8 *bssid, | ||
488 | const u8 *req_ie, size_t req_ie_len, | ||
489 | const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp) | ||
490 | { | ||
491 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
492 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
493 | struct cfg80211_event *ev; | ||
494 | unsigned long flags; | ||
495 | |||
496 | ev = kzalloc(sizeof(*ev) + req_ie_len + resp_ie_len, gfp); | ||
497 | if (!ev) | ||
498 | return; | ||
499 | |||
500 | ev->type = EVENT_ROAMED; | ||
501 | memcpy(ev->rm.bssid, bssid, ETH_ALEN); | ||
502 | ev->rm.req_ie = ((u8 *)ev) + sizeof(*ev); | ||
503 | ev->rm.req_ie_len = req_ie_len; | ||
504 | memcpy((void *)ev->rm.req_ie, req_ie, req_ie_len); | ||
505 | ev->rm.resp_ie = ((u8 *)ev) + sizeof(*ev) + req_ie_len; | ||
506 | ev->rm.resp_ie_len = resp_ie_len; | ||
507 | memcpy((void *)ev->rm.resp_ie, resp_ie, resp_ie_len); | ||
508 | |||
509 | spin_lock_irqsave(&wdev->event_lock, flags); | ||
510 | list_add_tail(&ev->list, &wdev->event_list); | ||
511 | spin_unlock_irqrestore(&wdev->event_lock, flags); | ||
512 | schedule_work(&rdev->event_work); | ||
513 | } | ||
427 | EXPORT_SYMBOL(cfg80211_roamed); | 514 | EXPORT_SYMBOL(cfg80211_roamed); |
428 | 515 | ||
429 | void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, u8 *ie, | 516 | void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, |
430 | size_t ie_len, u16 reason, bool from_ap) | 517 | size_t ie_len, u16 reason, bool from_ap) |
431 | { | 518 | { |
432 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 519 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
@@ -434,6 +521,8 @@ void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, u8 *ie, | |||
434 | union iwreq_data wrqu; | 521 | union iwreq_data wrqu; |
435 | #endif | 522 | #endif |
436 | 523 | ||
524 | ASSERT_WDEV_LOCK(wdev); | ||
525 | |||
437 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) | 526 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) |
438 | return; | 527 | return; |
439 | 528 | ||
@@ -456,7 +545,7 @@ void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, u8 *ie, | |||
456 | } | 545 | } |
457 | 546 | ||
458 | nl80211_send_disconnected(wiphy_to_dev(wdev->wiphy), dev, | 547 | nl80211_send_disconnected(wiphy_to_dev(wdev->wiphy), dev, |
459 | reason, ie, ie_len, from_ap, gfp); | 548 | reason, ie, ie_len, from_ap); |
460 | 549 | ||
461 | #ifdef CONFIG_WIRELESS_EXT | 550 | #ifdef CONFIG_WIRELESS_EXT |
462 | memset(&wrqu, 0, sizeof(wrqu)); | 551 | memset(&wrqu, 0, sizeof(wrqu)); |
@@ -468,16 +557,36 @@ void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, u8 *ie, | |||
468 | void cfg80211_disconnected(struct net_device *dev, u16 reason, | 557 | void cfg80211_disconnected(struct net_device *dev, u16 reason, |
469 | u8 *ie, size_t ie_len, gfp_t gfp) | 558 | u8 *ie, size_t ie_len, gfp_t gfp) |
470 | { | 559 | { |
471 | __cfg80211_disconnected(dev, gfp, ie, ie_len, reason, true); | 560 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
561 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
562 | struct cfg80211_event *ev; | ||
563 | unsigned long flags; | ||
564 | |||
565 | ev = kzalloc(sizeof(*ev) + ie_len, gfp); | ||
566 | if (!ev) | ||
567 | return; | ||
568 | |||
569 | ev->type = EVENT_DISCONNECTED; | ||
570 | ev->dc.ie = ((u8 *)ev) + sizeof(*ev); | ||
571 | ev->dc.ie_len = ie_len; | ||
572 | memcpy((void *)ev->dc.ie, ie, ie_len); | ||
573 | ev->dc.reason = reason; | ||
574 | |||
575 | spin_lock_irqsave(&wdev->event_lock, flags); | ||
576 | list_add_tail(&ev->list, &wdev->event_list); | ||
577 | spin_unlock_irqrestore(&wdev->event_lock, flags); | ||
578 | schedule_work(&rdev->event_work); | ||
472 | } | 579 | } |
473 | EXPORT_SYMBOL(cfg80211_disconnected); | 580 | EXPORT_SYMBOL(cfg80211_disconnected); |
474 | 581 | ||
475 | int cfg80211_connect(struct cfg80211_registered_device *rdev, | 582 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, |
476 | struct net_device *dev, | 583 | struct net_device *dev, |
477 | struct cfg80211_connect_params *connect) | 584 | struct cfg80211_connect_params *connect) |
478 | { | 585 | { |
479 | int err; | ||
480 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 586 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
587 | int err; | ||
588 | |||
589 | ASSERT_WDEV_LOCK(wdev); | ||
481 | 590 | ||
482 | if (wdev->sme_state != CFG80211_SME_IDLE) | 591 | if (wdev->sme_state != CFG80211_SME_IDLE) |
483 | return -EALREADY; | 592 | return -EALREADY; |
@@ -572,12 +681,27 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
572 | } | 681 | } |
573 | } | 682 | } |
574 | 683 | ||
575 | int cfg80211_disconnect(struct cfg80211_registered_device *rdev, | 684 | int cfg80211_connect(struct cfg80211_registered_device *rdev, |
576 | struct net_device *dev, u16 reason, bool wextev) | 685 | struct net_device *dev, |
686 | struct cfg80211_connect_params *connect) | ||
687 | { | ||
688 | int err; | ||
689 | |||
690 | wdev_lock(dev->ieee80211_ptr); | ||
691 | err = __cfg80211_connect(rdev, dev, connect); | ||
692 | wdev_unlock(dev->ieee80211_ptr); | ||
693 | |||
694 | return err; | ||
695 | } | ||
696 | |||
697 | int __cfg80211_disconnect(struct cfg80211_registered_device *rdev, | ||
698 | struct net_device *dev, u16 reason, bool wextev) | ||
577 | { | 699 | { |
578 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 700 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
579 | int err; | 701 | int err; |
580 | 702 | ||
703 | ASSERT_WDEV_LOCK(wdev); | ||
704 | |||
581 | if (wdev->sme_state == CFG80211_SME_IDLE) | 705 | if (wdev->sme_state == CFG80211_SME_IDLE) |
582 | return -EINVAL; | 706 | return -EINVAL; |
583 | 707 | ||
@@ -601,8 +725,9 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev, | |||
601 | } | 725 | } |
602 | 726 | ||
603 | /* wdev->conn->params.bssid must be set if > SCANNING */ | 727 | /* wdev->conn->params.bssid must be set if > SCANNING */ |
604 | err = cfg80211_mlme_deauth(rdev, dev, wdev->conn->params.bssid, | 728 | err = __cfg80211_mlme_deauth(rdev, dev, |
605 | NULL, 0, reason); | 729 | wdev->conn->params.bssid, |
730 | NULL, 0, reason); | ||
606 | if (err) | 731 | if (err) |
607 | return err; | 732 | return err; |
608 | } else { | 733 | } else { |
@@ -612,21 +737,36 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev, | |||
612 | } | 737 | } |
613 | 738 | ||
614 | if (wdev->sme_state == CFG80211_SME_CONNECTED) | 739 | if (wdev->sme_state == CFG80211_SME_CONNECTED) |
615 | __cfg80211_disconnected(dev, GFP_KERNEL, NULL, 0, 0, false); | 740 | __cfg80211_disconnected(dev, NULL, 0, 0, false); |
616 | else if (wdev->sme_state == CFG80211_SME_CONNECTING) | 741 | else if (wdev->sme_state == CFG80211_SME_CONNECTING) |
617 | __cfg80211_connect_result(dev, NULL, NULL, 0, NULL, 0, | 742 | __cfg80211_connect_result(dev, NULL, NULL, 0, NULL, 0, |
618 | WLAN_STATUS_UNSPECIFIED_FAILURE, | 743 | WLAN_STATUS_UNSPECIFIED_FAILURE, |
619 | wextev, GFP_KERNEL); | 744 | wextev); |
620 | 745 | ||
621 | return 0; | 746 | return 0; |
622 | } | 747 | } |
623 | 748 | ||
749 | int cfg80211_disconnect(struct cfg80211_registered_device *rdev, | ||
750 | struct net_device *dev, | ||
751 | u16 reason, bool wextev) | ||
752 | { | ||
753 | int err; | ||
754 | |||
755 | wdev_lock(dev->ieee80211_ptr); | ||
756 | err = __cfg80211_disconnect(rdev, dev, reason, wextev); | ||
757 | wdev_unlock(dev->ieee80211_ptr); | ||
758 | |||
759 | return err; | ||
760 | } | ||
761 | |||
624 | void cfg80211_sme_disassoc(struct net_device *dev, int idx) | 762 | void cfg80211_sme_disassoc(struct net_device *dev, int idx) |
625 | { | 763 | { |
626 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 764 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
627 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 765 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
628 | u8 bssid[ETH_ALEN]; | 766 | u8 bssid[ETH_ALEN]; |
629 | 767 | ||
768 | ASSERT_WDEV_LOCK(wdev); | ||
769 | |||
630 | if (!wdev->conn) | 770 | if (!wdev->conn) |
631 | return; | 771 | return; |
632 | 772 | ||
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 */ |
82 | EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwfreq); | 95 | EXPORT_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 */ |
157 | EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwessid); | 181 | EXPORT_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 */ |
232 | EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwap); | 266 | EXPORT_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 | } |
299 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwgenie); | 343 | EXPORT_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 | } |
329 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwmlme); | 380 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwmlme); |