aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-07-06 21:56:11 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-07-10 15:02:32 -0400
commit667503ddcb96f3b10211f997fe55907fa7509841 (patch)
tree5e2559e94a716bb81bfc7566e3e3a05267810c31
parent4f5dadcebb55fccef34722bbbf6401d39124c8a4 (diff)
cfg80211: fix locking
Over time, a lot of locking issues have crept into the smarts of cfg80211, so e.g. scan completion can race against a new scan, IBSS join can race against leaving an IBSS, etc. Introduce a new per-interface lock that protects most of the per-interface data that we need to keep track of, and sprinkle assertions about that lock everywhere. Some things now need to be offloaded to work structs so that we don't require being able to sleep in functions the drivers call. The exception to that are the MLME callbacks (rx_auth etc.) that currently only mac80211 calls because it was easier to do that there instead of in cfg80211, and future drivers implementing those calls will, if they ever exist, probably need to use a similar scheme like mac80211 anyway... In order to be able to handle _deauth and _disassoc properly, introduce a cookie passed to it that will determine locking requirements. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--include/net/cfg80211.h24
-rw-r--r--net/mac80211/cfg.c12
-rw-r--r--net/mac80211/ieee80211_i.h6
-rw-r--r--net/mac80211/mlme.c25
-rw-r--r--net/wireless/core.c92
-rw-r--r--net/wireless/core.h100
-rw-r--r--net/wireless/ibss.c133
-rw-r--r--net/wireless/mlme.c214
-rw-r--r--net/wireless/nl80211.c8
-rw-r--r--net/wireless/nl80211.h2
-rw-r--r--net/wireless/scan.c30
-rw-r--r--net/wireless/sme.c252
-rw-r--r--net/wireless/wext-sme.c125
13 files changed, 823 insertions, 200 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 60c1f11da45f..83c2c727d71e 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -555,6 +555,7 @@ struct cfg80211_scan_request {
555 /* internal */ 555 /* internal */
556 struct wiphy *wiphy; 556 struct wiphy *wiphy;
557 int ifidx; 557 int ifidx;
558 bool aborted;
558}; 559};
559 560
560/** 561/**
@@ -998,9 +999,11 @@ struct cfg80211_ops {
998 int (*assoc)(struct wiphy *wiphy, struct net_device *dev, 999 int (*assoc)(struct wiphy *wiphy, struct net_device *dev,
999 struct cfg80211_assoc_request *req); 1000 struct cfg80211_assoc_request *req);
1000 int (*deauth)(struct wiphy *wiphy, struct net_device *dev, 1001 int (*deauth)(struct wiphy *wiphy, struct net_device *dev,
1001 struct cfg80211_deauth_request *req); 1002 struct cfg80211_deauth_request *req,
1003 void *cookie);
1002 int (*disassoc)(struct wiphy *wiphy, struct net_device *dev, 1004 int (*disassoc)(struct wiphy *wiphy, struct net_device *dev,
1003 struct cfg80211_disassoc_request *req); 1005 struct cfg80211_disassoc_request *req,
1006 void *cookie);
1004 1007
1005 int (*connect)(struct wiphy *wiphy, struct net_device *dev, 1008 int (*connect)(struct wiphy *wiphy, struct net_device *dev,
1006 struct cfg80211_connect_params *sme); 1009 struct cfg80211_connect_params *sme);
@@ -1249,10 +1252,12 @@ struct wireless_dev {
1249 struct wiphy *wiphy; 1252 struct wiphy *wiphy;
1250 enum nl80211_iftype iftype; 1253 enum nl80211_iftype iftype;
1251 1254
1252 /* private to the generic wireless code */ 1255 /* the remainder of this struct should be private to cfg80211 */
1253 struct list_head list; 1256 struct list_head list;
1254 struct net_device *netdev; 1257 struct net_device *netdev;
1255 1258
1259 struct mutex mtx;
1260
1256 /* currently used for IBSS and SME - might be rearranged later */ 1261 /* currently used for IBSS and SME - might be rearranged later */
1257 u8 ssid[IEEE80211_MAX_SSID_LEN]; 1262 u8 ssid[IEEE80211_MAX_SSID_LEN];
1258 u8 ssid_len; 1263 u8 ssid_len;
@@ -1263,6 +1268,9 @@ struct wireless_dev {
1263 } sme_state; 1268 } sme_state;
1264 struct cfg80211_conn *conn; 1269 struct cfg80211_conn *conn;
1265 1270
1271 struct list_head event_list;
1272 spinlock_t event_lock;
1273
1266 struct cfg80211_internal_bss *authtry_bsses[MAX_AUTH_BSSES]; 1274 struct cfg80211_internal_bss *authtry_bsses[MAX_AUTH_BSSES];
1267 struct cfg80211_internal_bss *auth_bsses[MAX_AUTH_BSSES]; 1275 struct cfg80211_internal_bss *auth_bsses[MAX_AUTH_BSSES];
1268 struct cfg80211_internal_bss *current_bss; /* associated / joined */ 1276 struct cfg80211_internal_bss *current_bss; /* associated / joined */
@@ -1765,24 +1773,30 @@ void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr);
1765 * @dev: network device 1773 * @dev: network device
1766 * @buf: deauthentication frame (header + body) 1774 * @buf: deauthentication frame (header + body)
1767 * @len: length of the frame data 1775 * @len: length of the frame data
1776 * @cookie: cookie from ->deauth if called within that callback,
1777 * %NULL otherwise
1768 * 1778 *
1769 * This function is called whenever deauthentication has been processed in 1779 * This function is called whenever deauthentication has been processed in
1770 * station mode. This includes both received deauthentication frames and 1780 * station mode. This includes both received deauthentication frames and
1771 * locally generated ones. This function may sleep. 1781 * locally generated ones. This function may sleep.
1772 */ 1782 */
1773void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len); 1783void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len,
1784 void *cookie);
1774 1785
1775/** 1786/**
1776 * cfg80211_send_disassoc - notification of processed disassociation 1787 * cfg80211_send_disassoc - notification of processed disassociation
1777 * @dev: network device 1788 * @dev: network device
1778 * @buf: disassociation response frame (header + body) 1789 * @buf: disassociation response frame (header + body)
1779 * @len: length of the frame data 1790 * @len: length of the frame data
1791 * @cookie: cookie from ->disassoc if called within that callback,
1792 * %NULL otherwise
1780 * 1793 *
1781 * This function is called whenever disassociation has been processed in 1794 * This function is called whenever disassociation has been processed in
1782 * station mode. This includes both received disassociation frames and locally 1795 * station mode. This includes both received disassociation frames and locally
1783 * generated ones. This function may sleep. 1796 * generated ones. This function may sleep.
1784 */ 1797 */
1785void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len); 1798void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len,
1799 void *cookie);
1786 1800
1787/** 1801/**
1788 * cfg80211_michael_mic_failure - notification of Michael MIC failure (TKIP) 1802 * cfg80211_michael_mic_failure - notification of Michael MIC failure (TKIP)
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 7cfc14e4ca07..36f8f245fa4c 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1182,15 +1182,19 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev,
1182} 1182}
1183 1183
1184static int ieee80211_deauth(struct wiphy *wiphy, struct net_device *dev, 1184static int ieee80211_deauth(struct wiphy *wiphy, struct net_device *dev,
1185 struct cfg80211_deauth_request *req) 1185 struct cfg80211_deauth_request *req,
1186 void *cookie)
1186{ 1187{
1187 return ieee80211_mgd_deauth(IEEE80211_DEV_TO_SUB_IF(dev), req); 1188 return ieee80211_mgd_deauth(IEEE80211_DEV_TO_SUB_IF(dev),
1189 req, cookie);
1188} 1190}
1189 1191
1190static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev, 1192static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev,
1191 struct cfg80211_disassoc_request *req) 1193 struct cfg80211_disassoc_request *req,
1194 void *cookie)
1192{ 1195{
1193 return ieee80211_mgd_disassoc(IEEE80211_DEV_TO_SUB_IF(dev), req); 1196 return ieee80211_mgd_disassoc(IEEE80211_DEV_TO_SUB_IF(dev),
1197 req, cookie);
1194} 1198}
1195 1199
1196static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, 1200static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 2e92bbd9b2d0..327aabc07abe 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -918,9 +918,11 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
918int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, 918int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
919 struct cfg80211_assoc_request *req); 919 struct cfg80211_assoc_request *req);
920int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, 920int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
921 struct cfg80211_deauth_request *req); 921 struct cfg80211_deauth_request *req,
922 void *cookie);
922int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, 923int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
923 struct cfg80211_disassoc_request *req); 924 struct cfg80211_disassoc_request *req,
925 void *cookie);
924ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, 926ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata,
925 struct sk_buff *skb); 927 struct sk_buff *skb);
926void ieee80211_send_pspoll(struct ieee80211_local *local, 928void ieee80211_send_pspoll(struct ieee80211_local *local,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 15dbb57ab55e..c9db9646025b 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -386,7 +386,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
386 386
387 387
388static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, 388static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
389 const u8 *bssid, u16 stype, u16 reason) 389 const u8 *bssid, u16 stype, u16 reason,
390 void *cookie)
390{ 391{
391 struct ieee80211_local *local = sdata->local; 392 struct ieee80211_local *local = sdata->local;
392 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 393 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -412,9 +413,9 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
412 mgmt->u.deauth.reason_code = cpu_to_le16(reason); 413 mgmt->u.deauth.reason_code = cpu_to_le16(reason);
413 414
414 if (stype == IEEE80211_STYPE_DEAUTH) 415 if (stype == IEEE80211_STYPE_DEAUTH)
415 cfg80211_send_deauth(sdata->dev, (u8 *) mgmt, skb->len); 416 cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len, cookie);
416 else 417 else
417 cfg80211_send_disassoc(sdata->dev, (u8 *) mgmt, skb->len); 418 cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len, cookie);
418 ieee80211_tx_skb(sdata, skb, ifmgd->flags & IEEE80211_STA_MFP_ENABLED); 419 ieee80211_tx_skb(sdata, skb, ifmgd->flags & IEEE80211_STA_MFP_ENABLED);
419} 420}
420 421
@@ -1837,10 +1838,12 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
1837 /* no action */ 1838 /* no action */
1838 break; 1839 break;
1839 case RX_MGMT_CFG80211_DEAUTH: 1840 case RX_MGMT_CFG80211_DEAUTH:
1840 cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); 1841 cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len,
1842 NULL);
1841 break; 1843 break;
1842 case RX_MGMT_CFG80211_DISASSOC: 1844 case RX_MGMT_CFG80211_DISASSOC:
1843 cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len); 1845 cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len,
1846 NULL);
1844 break; 1847 break;
1845 default: 1848 default:
1846 WARN(1, "unexpected: %d", rma); 1849 WARN(1, "unexpected: %d", rma);
@@ -2273,7 +2276,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
2273} 2276}
2274 2277
2275int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, 2278int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
2276 struct cfg80211_deauth_request *req) 2279 struct cfg80211_deauth_request *req,
2280 void *cookie)
2277{ 2281{
2278 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 2282 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
2279 struct ieee80211_mgd_work *wk; 2283 struct ieee80211_mgd_work *wk;
@@ -2305,13 +2309,15 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
2305 mutex_unlock(&ifmgd->mtx); 2309 mutex_unlock(&ifmgd->mtx);
2306 2310
2307 ieee80211_send_deauth_disassoc(sdata, bssid, 2311 ieee80211_send_deauth_disassoc(sdata, bssid,
2308 IEEE80211_STYPE_DEAUTH, req->reason_code); 2312 IEEE80211_STYPE_DEAUTH, req->reason_code,
2313 cookie);
2309 2314
2310 return 0; 2315 return 0;
2311} 2316}
2312 2317
2313int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, 2318int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
2314 struct cfg80211_disassoc_request *req) 2319 struct cfg80211_disassoc_request *req,
2320 void *cookie)
2315{ 2321{
2316 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 2322 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
2317 2323
@@ -2331,6 +2337,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
2331 mutex_unlock(&ifmgd->mtx); 2337 mutex_unlock(&ifmgd->mtx);
2332 2338
2333 ieee80211_send_deauth_disassoc(sdata, req->bss->bssid, 2339 ieee80211_send_deauth_disassoc(sdata, req->bss->bssid,
2334 IEEE80211_STYPE_DISASSOC, req->reason_code); 2340 IEEE80211_STYPE_DISASSOC, req->reason_code,
2341 cookie);
2335 return 0; 2342 return 0;
2336} 2343}
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
260static 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
305static 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
262struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) 327struct 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);
170extern struct cfg80211_registered_device * 172extern struct cfg80211_registered_device *
171cfg80211_get_dev_from_ifindex(int ifindex); 173cfg80211_get_dev_from_ifindex(int ifindex);
172 174
175static inline void cfg80211_lock_rdev(struct cfg80211_registered_device *drv)
176{
177 mutex_lock(&drv->mtx);
178}
179
173static inline void cfg80211_unlock_rdev(struct cfg80211_registered_device *drv) 180static 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
186static inline void wdev_lock(struct wireless_dev *wdev)
187 __acquires(wdev)
188{
189 mutex_lock(&wdev->mtx);
190 __acquire(wdev->mtx);
191}
192
193static 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
203enum cfg80211_event_type {
204 EVENT_CONNECT_RESULT,
205 EVENT_ROAMED,
206 EVENT_DISCONNECTED,
207 EVENT_IBSS_JOINED,
208};
209
210struct 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 */
180extern void cfg80211_dev_free(struct cfg80211_registered_device *drv); 243extern 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 */
257int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
258 struct net_device *dev,
259 struct cfg80211_ibss_params *params);
194int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, 260int 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);
197void cfg80211_clear_ibss(struct net_device *dev, bool nowext); 263void cfg80211_clear_ibss(struct net_device *dev, bool nowext);
198int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, 264int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
199 struct net_device *dev, bool nowext); 265 struct net_device *dev, bool nowext);
266void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid);
200 267
201/* MLME */ 268/* MLME */
269int __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);
202int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, 276int 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);
281int __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);
207int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, 288int 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);
294int __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);
213int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, 297int 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);
219void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, 303void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
220 struct net_device *dev); 304 struct net_device *dev);
305void __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 */
311int __cfg80211_connect(struct cfg80211_registered_device *rdev,
312 struct net_device *dev,
313 struct cfg80211_connect_params *connect);
223int cfg80211_connect(struct cfg80211_registered_device *rdev, 314int 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);
317int __cfg80211_disconnect(struct cfg80211_registered_device *rdev,
318 struct net_device *dev, u16 reason,
319 bool wextev);
226int cfg80211_disconnect(struct cfg80211_registered_device *rdev, 320int 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);
323void __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
230void cfg80211_conn_work(struct work_struct *work); 327void cfg80211_conn_work(struct work_struct *work);
231 328
232/* internal helpers */ 329/* internal helpers */
233int cfg80211_validate_key_settings(struct key_params *params, int key_idx, 330int cfg80211_validate_key_settings(struct key_params *params, int key_idx,
234 const u8 *mac_addr); 331 const u8 *mac_addr);
235void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, u8 *ie, 332void __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);
237void cfg80211_sme_scan_done(struct net_device *dev); 334void cfg80211_sme_scan_done(struct net_device *dev);
238void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); 335void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len);
239void cfg80211_sme_disassoc(struct net_device *dev, int idx); 336void cfg80211_sme_disassoc(struct net_device *dev, int idx);
337void __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
13void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp) 13void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid)
14{ 14{
15 struct wireless_dev *wdev = dev->ieee80211_ptr; 15 struct wireless_dev *wdev = dev->ieee80211_ptr;
16 struct cfg80211_bss *bss; 16 struct cfg80211_bss *bss;
@@ -39,22 +39,45 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp)
39 cfg80211_hold_bss(bss_from_pub(bss)); 39 cfg80211_hold_bss(bss_from_pub(bss));
40 wdev->current_bss = bss_from_pub(bss); 40 wdev->current_bss = bss_from_pub(bss);
41 41
42 nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid, gfp); 42 nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid,
43 GFP_KERNEL);
43#ifdef CONFIG_WIRELESS_EXT 44#ifdef CONFIG_WIRELESS_EXT
44 memset(&wrqu, 0, sizeof(wrqu)); 45 memset(&wrqu, 0, sizeof(wrqu));
45 memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); 46 memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
46 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); 47 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
47#endif 48#endif
48} 49}
50
51void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid, gfp_t gfp)
52{
53 struct wireless_dev *wdev = dev->ieee80211_ptr;
54 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
55 struct cfg80211_event *ev;
56 unsigned long flags;
57
58 ev = kzalloc(sizeof(*ev), gfp);
59 if (!ev)
60 return;
61
62 ev->type = EVENT_IBSS_JOINED;
63 memcpy(ev->cr.bssid, bssid, ETH_ALEN);
64
65 spin_lock_irqsave(&wdev->event_lock, flags);
66 list_add_tail(&ev->list, &wdev->event_list);
67 spin_unlock_irqrestore(&wdev->event_lock, flags);
68 schedule_work(&rdev->event_work);
69}
49EXPORT_SYMBOL(cfg80211_ibss_joined); 70EXPORT_SYMBOL(cfg80211_ibss_joined);
50 71
51int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, 72int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
52 struct net_device *dev, 73 struct net_device *dev,
53 struct cfg80211_ibss_params *params) 74 struct cfg80211_ibss_params *params)
54{ 75{
55 struct wireless_dev *wdev = dev->ieee80211_ptr; 76 struct wireless_dev *wdev = dev->ieee80211_ptr;
56 int err; 77 int err;
57 78
79 ASSERT_WDEV_LOCK(wdev);
80
58 if (wdev->ssid_len) 81 if (wdev->ssid_len)
59 return -EALREADY; 82 return -EALREADY;
60 83
@@ -72,10 +95,26 @@ int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
72 return 0; 95 return 0;
73} 96}
74 97
75void cfg80211_clear_ibss(struct net_device *dev, bool nowext) 98int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
99 struct net_device *dev,
100 struct cfg80211_ibss_params *params)
101{
102 struct wireless_dev *wdev = dev->ieee80211_ptr;
103 int err;
104
105 wdev_lock(wdev);
106 err = __cfg80211_join_ibss(rdev, dev, params);
107 wdev_unlock(wdev);
108
109 return err;
110}
111
112static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
76{ 113{
77 struct wireless_dev *wdev = dev->ieee80211_ptr; 114 struct wireless_dev *wdev = dev->ieee80211_ptr;
78 115
116 ASSERT_WDEV_LOCK(wdev);
117
79 if (wdev->current_bss) { 118 if (wdev->current_bss) {
80 cfg80211_unhold_bss(wdev->current_bss); 119 cfg80211_unhold_bss(wdev->current_bss);
81 cfg80211_put_bss(&wdev->current_bss->pub); 120 cfg80211_put_bss(&wdev->current_bss->pub);
@@ -89,12 +128,23 @@ void cfg80211_clear_ibss(struct net_device *dev, bool nowext)
89#endif 128#endif
90} 129}
91 130
92int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, 131void cfg80211_clear_ibss(struct net_device *dev, bool nowext)
93 struct net_device *dev, bool nowext) 132{
133 struct wireless_dev *wdev = dev->ieee80211_ptr;
134
135 wdev_lock(wdev);
136 __cfg80211_clear_ibss(dev, nowext);
137 wdev_unlock(wdev);
138}
139
140static int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
141 struct net_device *dev, bool nowext)
94{ 142{
95 struct wireless_dev *wdev = dev->ieee80211_ptr; 143 struct wireless_dev *wdev = dev->ieee80211_ptr;
96 int err; 144 int err;
97 145
146 ASSERT_WDEV_LOCK(wdev);
147
98 if (!wdev->ssid_len) 148 if (!wdev->ssid_len)
99 return -ENOLINK; 149 return -ENOLINK;
100 150
@@ -103,11 +153,24 @@ int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
103 if (err) 153 if (err)
104 return err; 154 return err;
105 155
106 cfg80211_clear_ibss(dev, nowext); 156 __cfg80211_clear_ibss(dev, nowext);
107 157
108 return 0; 158 return 0;
109} 159}
110 160
161int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
162 struct net_device *dev, bool nowext)
163{
164 struct wireless_dev *wdev = dev->ieee80211_ptr;
165 int err;
166
167 wdev_lock(wdev);
168 err = __cfg80211_leave_ibss(rdev, dev, nowext);
169 wdev_unlock(wdev);
170
171 return err;
172}
173
111#ifdef CONFIG_WIRELESS_EXT 174#ifdef CONFIG_WIRELESS_EXT
112static int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, 175static int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
113 struct wireless_dev *wdev) 176 struct wireless_dev *wdev)
@@ -184,12 +247,15 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
184 if (wdev->wext.ibss.channel == chan) 247 if (wdev->wext.ibss.channel == chan)
185 return 0; 248 return 0;
186 249
187 if (wdev->ssid_len) { 250 wdev_lock(wdev);
188 err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), 251 err = 0;
189 dev, true); 252 if (wdev->ssid_len)
190 if (err) 253 err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy),
191 return err; 254 dev, true);
192 } 255 wdev_unlock(wdev);
256
257 if (err)
258 return err;
193 259
194 if (chan) { 260 if (chan) {
195 wdev->wext.ibss.channel = chan; 261 wdev->wext.ibss.channel = chan;
@@ -215,10 +281,12 @@ int cfg80211_ibss_wext_giwfreq(struct net_device *dev,
215 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) 281 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
216 return -EINVAL; 282 return -EINVAL;
217 283
284 wdev_lock(wdev);
218 if (wdev->current_bss) 285 if (wdev->current_bss)
219 chan = wdev->current_bss->pub.channel; 286 chan = wdev->current_bss->pub.channel;
220 else if (wdev->wext.ibss.channel) 287 else if (wdev->wext.ibss.channel)
221 chan = wdev->wext.ibss.channel; 288 chan = wdev->wext.ibss.channel;
289 wdev_unlock(wdev);
222 290
223 if (chan) { 291 if (chan) {
224 freq->m = chan->center_freq; 292 freq->m = chan->center_freq;
@@ -247,12 +315,15 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev,
247 if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss) 315 if (!wiphy_to_dev(wdev->wiphy)->ops->join_ibss)
248 return -EOPNOTSUPP; 316 return -EOPNOTSUPP;
249 317
250 if (wdev->ssid_len) { 318 wdev_lock(wdev);
251 err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), 319 err = 0;
252 dev, true); 320 if (wdev->ssid_len)
253 if (err) 321 err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy),
254 return err; 322 dev, true);
255 } 323 wdev_unlock(wdev);
324
325 if (err)
326 return err;
256 327
257 /* iwconfig uses nul termination in SSID.. */ 328 /* iwconfig uses nul termination in SSID.. */
258 if (len > 0 && ssid[len - 1] == '\0') 329 if (len > 0 && ssid[len - 1] == '\0')
@@ -279,6 +350,7 @@ int cfg80211_ibss_wext_giwessid(struct net_device *dev,
279 350
280 data->flags = 0; 351 data->flags = 0;
281 352
353 wdev_lock(wdev);
282 if (wdev->ssid_len) { 354 if (wdev->ssid_len) {
283 data->flags = 1; 355 data->flags = 1;
284 data->length = wdev->ssid_len; 356 data->length = wdev->ssid_len;
@@ -288,6 +360,7 @@ int cfg80211_ibss_wext_giwessid(struct net_device *dev,
288 data->length = wdev->wext.ibss.ssid_len; 360 data->length = wdev->wext.ibss.ssid_len;
289 memcpy(ssid, wdev->wext.ibss.ssid, data->length); 361 memcpy(ssid, wdev->wext.ibss.ssid, data->length);
290 } 362 }
363 wdev_unlock(wdev);
291 364
292 return 0; 365 return 0;
293} 366}
@@ -325,12 +398,15 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev,
325 compare_ether_addr(bssid, wdev->wext.ibss.bssid) == 0) 398 compare_ether_addr(bssid, wdev->wext.ibss.bssid) == 0)
326 return 0; 399 return 0;
327 400
328 if (wdev->ssid_len) { 401 wdev_lock(wdev);
329 err = cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy), 402 err = 0;
330 dev, true); 403 if (wdev->ssid_len)
331 if (err) 404 err = __cfg80211_leave_ibss(wiphy_to_dev(wdev->wiphy),
332 return err; 405 dev, true);
333 } 406 wdev_unlock(wdev);
407
408 if (err)
409 return err;
334 410
335 if (bssid) { 411 if (bssid) {
336 memcpy(wdev->wext.bssid, bssid, ETH_ALEN); 412 memcpy(wdev->wext.bssid, bssid, ETH_ALEN);
@@ -355,10 +431,13 @@ int cfg80211_ibss_wext_giwap(struct net_device *dev,
355 431
356 ap_addr->sa_family = ARPHRD_ETHER; 432 ap_addr->sa_family = ARPHRD_ETHER;
357 433
434 wdev_lock(wdev);
358 if (wdev->current_bss) 435 if (wdev->current_bss)
359 memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN); 436 memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN);
360 else 437 else
361 memcpy(ap_addr->sa_data, wdev->wext.ibss.bssid, ETH_ALEN); 438 memcpy(ap_addr->sa_data, wdev->wext.ibss.bssid, ETH_ALEN);
439 wdev_unlock(wdev);
440
362 return 0; 441 return 0;
363} 442}
364/* temporary symbol - mark GPL - in the future the handler won't be */ 443/* temporary symbol - mark GPL - in the future the handler won't be */
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}
49EXPORT_SYMBOL(cfg80211_send_rx_auth); 51EXPORT_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}
85EXPORT_SYMBOL(cfg80211_send_rx_assoc); 90EXPORT_SYMBOL(cfg80211_send_rx_assoc);
86 91
87void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len) 92static 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
150void 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}
143EXPORT_SYMBOL(cfg80211_send_deauth); 166EXPORT_SYMBOL(cfg80211_send_deauth);
144 167
145void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len) 168static 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
212void 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}
186EXPORT_SYMBOL(cfg80211_send_disassoc); 228EXPORT_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}
218EXPORT_SYMBOL(cfg80211_send_auth_timeout); 262EXPORT_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}
250EXPORT_SYMBOL(cfg80211_send_assoc_timeout); 296EXPORT_SYMBOL(cfg80211_send_assoc_timeout);
251 297
@@ -276,17 +322,21 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
276EXPORT_SYMBOL(cfg80211_michael_mic_failure); 322EXPORT_SYMBOL(cfg80211_michael_mic_failure);
277 323
278/* some MLME handling for userspace SME */ 324/* some MLME handling for userspace SME */
279int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, 325int __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
345int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, 395int 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
411int __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
393int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, 462int 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
481int __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
427int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, 517int 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
531static 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
552int 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
446void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, 566void 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
4392void nl80211_send_disconnected(struct cfg80211_registered_device *rdev, 4394void 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);
43void nl80211_send_disconnected(struct cfg80211_registered_device *rdev, 43void 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
47void 47void
48nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, 48nl80211_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
20void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) 20void __cfg80211_scan_done(struct work_struct *wk)
21{ 21{
22 struct cfg80211_registered_device *rdev;
23 struct cfg80211_scan_request *request;
22 struct net_device *dev; 24 struct net_device *dev;
23#ifdef CONFIG_WIRELESS_EXT 25#ifdef CONFIG_WIRELESS_EXT
24 union iwreq_data wrqu; 26 union iwreq_data wrqu;
25#endif 27#endif
26 28
29 rdev = container_of(wk, struct cfg80211_registered_device,
30 scan_done_wk);
31
32 mutex_lock(&rdev->mtx);
33 request = rdev->scan_req;
34
27 dev = dev_get_by_index(&init_net, request->ifidx); 35 dev = dev_get_by_index(&init_net, request->ifidx);
28 if (!dev) 36 if (!dev)
29 goto out; 37 goto out;
@@ -35,7 +43,7 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
35 */ 43 */
36 cfg80211_sme_scan_done(dev); 44 cfg80211_sme_scan_done(dev);
37 45
38 if (aborted) 46 if (request->aborted)
39 nl80211_send_scan_aborted(wiphy_to_dev(request->wiphy), dev); 47 nl80211_send_scan_aborted(wiphy_to_dev(request->wiphy), dev);
40 else 48 else
41 nl80211_send_scan_done(wiphy_to_dev(request->wiphy), dev); 49 nl80211_send_scan_done(wiphy_to_dev(request->wiphy), dev);
@@ -43,7 +51,7 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
43 wiphy_to_dev(request->wiphy)->scan_req = NULL; 51 wiphy_to_dev(request->wiphy)->scan_req = NULL;
44 52
45#ifdef CONFIG_WIRELESS_EXT 53#ifdef CONFIG_WIRELESS_EXT
46 if (!aborted) { 54 if (!request->aborted) {
47 memset(&wrqu, 0, sizeof(wrqu)); 55 memset(&wrqu, 0, sizeof(wrqu));
48 56
49 wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); 57 wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
@@ -53,8 +61,24 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
53 dev_put(dev); 61 dev_put(dev);
54 62
55 out: 63 out:
64 cfg80211_unlock_rdev(rdev);
56 kfree(request); 65 kfree(request);
57} 66}
67
68void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
69{
70 struct net_device *dev = dev_get_by_index(&init_net, request->ifidx);
71 if (WARN_ON(!dev)) {
72 kfree(request);
73 return;
74 }
75
76 WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req);
77
78 request->aborted = aborted;
79 schedule_work(&wiphy_to_dev(request->wiphy)->scan_done_wk);
80 dev_put(dev);
81}
58EXPORT_SYMBOL(cfg80211_scan_done); 82EXPORT_SYMBOL(cfg80211_scan_done);
59 83
60static void bss_release(struct kref *ref) 84static void bss_release(struct kref *ref)
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, &params->crypto); 142 params->ie, params->ie_len,
143 false, &params->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
201void cfg80211_sme_scan_done(struct net_device *dev) 218static 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
229void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len) 249void 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
258void 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
276static void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, 308void __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}
368EXPORT_SYMBOL(cfg80211_connect_result); 423EXPORT_SYMBOL(cfg80211_connect_result);
369 424
370void cfg80211_roamed(struct net_device *dev, const u8 *bssid, 425void __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
487void 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}
427EXPORT_SYMBOL(cfg80211_roamed); 514EXPORT_SYMBOL(cfg80211_roamed);
428 515
429void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, u8 *ie, 516void __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,
468void cfg80211_disconnected(struct net_device *dev, u16 reason, 557void 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}
473EXPORT_SYMBOL(cfg80211_disconnected); 580EXPORT_SYMBOL(cfg80211_disconnected);
474 581
475int cfg80211_connect(struct cfg80211_registered_device *rdev, 582int __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
575int cfg80211_disconnect(struct cfg80211_registered_device *rdev, 684int 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
697int __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
749int 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
624void cfg80211_sme_disassoc(struct net_device *dev, int idx) 762void 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 */
82EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwfreq); 95EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwfreq);
@@ -92,10 +105,12 @@ int cfg80211_mgd_wext_giwfreq(struct net_device *dev,
92 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) 105 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
93 return -EINVAL; 106 return -EINVAL;
94 107
108 wdev_lock(wdev);
95 if (wdev->current_bss) 109 if (wdev->current_bss)
96 chan = wdev->current_bss->pub.channel; 110 chan = wdev->current_bss->pub.channel;
97 else if (wdev->wext.connect.channel) 111 else if (wdev->wext.connect.channel)
98 chan = wdev->wext.connect.channel; 112 chan = wdev->wext.connect.channel;
113 wdev_unlock(wdev);
99 114
100 if (chan) { 115 if (chan) {
101 freq->m = chan->center_freq; 116 freq->m = chan->center_freq;
@@ -128,21 +143,26 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,
128 if (len > 0 && ssid[len - 1] == '\0') 143 if (len > 0 && ssid[len - 1] == '\0')
129 len--; 144 len--;
130 145
146 cfg80211_lock_rdev(wiphy_to_dev(wdev->wiphy));
147 wdev_lock(wdev);
148
149 err = 0;
150
131 if (wdev->wext.connect.ssid && len && 151 if (wdev->wext.connect.ssid && len &&
132 len == wdev->wext.connect.ssid_len && 152 len == wdev->wext.connect.ssid_len &&
133 memcmp(wdev->wext.connect.ssid, ssid, len)) 153 memcmp(wdev->wext.connect.ssid, ssid, len))
134 return 0; 154 goto out;
135 155
136 if (wdev->sme_state != CFG80211_SME_IDLE) { 156 if (wdev->sme_state != CFG80211_SME_IDLE) {
137 bool event = true; 157 bool event = true;
138 /* if SSID set now, we'll try to connect, avoid event */ 158 /* if SSID set now, we'll try to connect, avoid event */
139 if (len) 159 if (len)
140 event = false; 160 event = false;
141 err = cfg80211_disconnect(wiphy_to_dev(wdev->wiphy), 161 err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy),
142 dev, WLAN_REASON_DEAUTH_LEAVING, 162 dev, WLAN_REASON_DEAUTH_LEAVING,
143 event); 163 event);
144 if (err) 164 if (err)
145 return err; 165 goto out;
146 } 166 }
147 167
148 wdev->wext.connect.ssid = wdev->wext.ssid; 168 wdev->wext.connect.ssid = wdev->wext.ssid;
@@ -151,7 +171,11 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,
151 171
152 wdev->wext.connect.crypto.control_port = false; 172 wdev->wext.connect.crypto.control_port = false;
153 173
154 return cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev); 174 err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev);
175 out:
176 wdev_unlock(wdev);
177 cfg80211_unlock_rdev(wiphy_to_dev(wdev->wiphy));
178 return err;
155} 179}
156/* temporary symbol - mark GPL - in the future the handler won't be */ 180/* temporary symbol - mark GPL - in the future the handler won't be */
157EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwessid); 181EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwessid);
@@ -168,6 +192,7 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev,
168 192
169 data->flags = 0; 193 data->flags = 0;
170 194
195 wdev_lock(wdev);
171 if (wdev->ssid_len) { 196 if (wdev->ssid_len) {
172 data->flags = 1; 197 data->flags = 1;
173 data->length = wdev->ssid_len; 198 data->length = wdev->ssid_len;
@@ -178,6 +203,7 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev,
178 memcpy(ssid, wdev->wext.connect.ssid, data->length); 203 memcpy(ssid, wdev->wext.connect.ssid, data->length);
179 } else 204 } else
180 data->flags = 0; 205 data->flags = 0;
206 wdev_unlock(wdev);
181 207
182 return 0; 208 return 0;
183} 209}
@@ -203,21 +229,25 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev,
203 if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid)) 229 if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid))
204 bssid = NULL; 230 bssid = NULL;
205 231
232 cfg80211_lock_rdev(wiphy_to_dev(wdev->wiphy));
233 wdev_lock(wdev);
234
235 err = 0;
206 /* both automatic */ 236 /* both automatic */
207 if (!bssid && !wdev->wext.connect.bssid) 237 if (!bssid && !wdev->wext.connect.bssid)
208 return 0; 238 goto out;
209 239
210 /* fixed already - and no change */ 240 /* fixed already - and no change */
211 if (wdev->wext.connect.bssid && bssid && 241 if (wdev->wext.connect.bssid && bssid &&
212 compare_ether_addr(bssid, wdev->wext.connect.bssid) == 0) 242 compare_ether_addr(bssid, wdev->wext.connect.bssid) == 0)
213 return 0; 243 goto out;
214 244
215 if (wdev->sme_state != CFG80211_SME_IDLE) { 245 if (wdev->sme_state != CFG80211_SME_IDLE) {
216 err = cfg80211_disconnect(wiphy_to_dev(wdev->wiphy), 246 err = __cfg80211_disconnect(wiphy_to_dev(wdev->wiphy),
217 dev, WLAN_REASON_DEAUTH_LEAVING, 247 dev, WLAN_REASON_DEAUTH_LEAVING,
218 false); 248 false);
219 if (err) 249 if (err)
220 return err; 250 goto out;
221 } 251 }
222 252
223 if (bssid) { 253 if (bssid) {
@@ -226,7 +256,11 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev,
226 } else 256 } else
227 wdev->wext.connect.bssid = NULL; 257 wdev->wext.connect.bssid = NULL;
228 258
229 return cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev); 259 err = cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev);
260 out:
261 wdev_unlock(wdev);
262 cfg80211_unlock_rdev(wiphy_to_dev(wdev->wiphy));
263 return err;
230} 264}
231/* temporary symbol - mark GPL - in the future the handler won't be */ 265/* temporary symbol - mark GPL - in the future the handler won't be */
232EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwap); 266EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwap);
@@ -243,12 +277,14 @@ int cfg80211_mgd_wext_giwap(struct net_device *dev,
243 277
244 ap_addr->sa_family = ARPHRD_ETHER; 278 ap_addr->sa_family = ARPHRD_ETHER;
245 279
280 wdev_lock(wdev);
246 if (wdev->current_bss) 281 if (wdev->current_bss)
247 memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN); 282 memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN);
248 else if (wdev->wext.connect.bssid) 283 else if (wdev->wext.connect.bssid)
249 memcpy(ap_addr->sa_data, wdev->wext.connect.bssid, ETH_ALEN); 284 memcpy(ap_addr->sa_data, wdev->wext.connect.bssid, ETH_ALEN);
250 else 285 else
251 memset(ap_addr->sa_data, 0, ETH_ALEN); 286 memset(ap_addr->sa_data, 0, ETH_ALEN);
287 wdev_unlock(wdev);
252 288
253 return 0; 289 return 0;
254} 290}
@@ -270,15 +306,20 @@ int cfg80211_wext_siwgenie(struct net_device *dev,
270 if (!ie_len) 306 if (!ie_len)
271 ie = NULL; 307 ie = NULL;
272 308
309 wdev_lock(wdev);
310
273 /* no change */ 311 /* no change */
312 err = 0;
274 if (wdev->wext.ie_len == ie_len && 313 if (wdev->wext.ie_len == ie_len &&
275 memcmp(wdev->wext.ie, ie, ie_len) == 0) 314 memcmp(wdev->wext.ie, ie, ie_len) == 0)
276 return 0; 315 goto out;
277 316
278 if (ie_len) { 317 if (ie_len) {
279 ie = kmemdup(extra, ie_len, GFP_KERNEL); 318 ie = kmemdup(extra, ie_len, GFP_KERNEL);
280 if (!ie) 319 if (!ie) {
281 return -ENOMEM; 320 err = -ENOMEM;
321 goto out;
322 }
282 } else 323 } else
283 ie = NULL; 324 ie = NULL;
284 325
@@ -287,14 +328,17 @@ int cfg80211_wext_siwgenie(struct net_device *dev,
287 wdev->wext.ie_len = ie_len; 328 wdev->wext.ie_len = ie_len;
288 329
289 if (wdev->sme_state != CFG80211_SME_IDLE) { 330 if (wdev->sme_state != CFG80211_SME_IDLE) {
290 err = cfg80211_disconnect(rdev, dev, 331 err = __cfg80211_disconnect(rdev, dev,
291 WLAN_REASON_DEAUTH_LEAVING, false); 332 WLAN_REASON_DEAUTH_LEAVING, false);
292 if (err) 333 if (err)
293 return err; 334 goto out;
294 } 335 }
295 336
296 /* userspace better not think we'll reconnect */ 337 /* userspace better not think we'll reconnect */
297 return 0; 338 err = 0;
339 out:
340 wdev_unlock(wdev);
341 return err;
298} 342}
299EXPORT_SYMBOL_GPL(cfg80211_wext_siwgenie); 343EXPORT_SYMBOL_GPL(cfg80211_wext_siwgenie);
300 344
@@ -305,6 +349,7 @@ int cfg80211_wext_siwmlme(struct net_device *dev,
305 struct wireless_dev *wdev = dev->ieee80211_ptr; 349 struct wireless_dev *wdev = dev->ieee80211_ptr;
306 struct iw_mlme *mlme = (struct iw_mlme *)extra; 350 struct iw_mlme *mlme = (struct iw_mlme *)extra;
307 struct cfg80211_registered_device *rdev; 351 struct cfg80211_registered_device *rdev;
352 int err;
308 353
309 if (!wdev) 354 if (!wdev)
310 return -EOPNOTSUPP; 355 return -EOPNOTSUPP;
@@ -317,13 +362,19 @@ int cfg80211_wext_siwmlme(struct net_device *dev,
317 if (mlme->addr.sa_family != ARPHRD_ETHER) 362 if (mlme->addr.sa_family != ARPHRD_ETHER)
318 return -EINVAL; 363 return -EINVAL;
319 364
365 wdev_lock(wdev);
320 switch (mlme->cmd) { 366 switch (mlme->cmd) {
321 case IW_MLME_DEAUTH: 367 case IW_MLME_DEAUTH:
322 case IW_MLME_DISASSOC: 368 case IW_MLME_DISASSOC:
323 return cfg80211_disconnect(rdev, dev, mlme->reason_code, 369 err = __cfg80211_disconnect(rdev, dev, mlme->reason_code,
324 true); 370 true);
371 break;
325 default: 372 default:
326 return -EOPNOTSUPP; 373 err = -EOPNOTSUPP;
374 break;
327 } 375 }
376 wdev_unlock(wdev);
377
378 return err;
328} 379}
329EXPORT_SYMBOL_GPL(cfg80211_wext_siwmlme); 380EXPORT_SYMBOL_GPL(cfg80211_wext_siwmlme);