aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/core.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-07-06 21:56:11 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-07-10 15:02:32 -0400
commit667503ddcb96f3b10211f997fe55907fa7509841 (patch)
tree5e2559e94a716bb81bfc7566e3e3a05267810c31 /net/wireless/core.c
parent4f5dadcebb55fccef34722bbbf6401d39124c8a4 (diff)
cfg80211: fix locking
Over time, a lot of locking issues have crept into the smarts of cfg80211, so e.g. scan completion can race against a new scan, IBSS join can race against leaving an IBSS, etc. Introduce a new per-interface lock that protects most of the per-interface data that we need to keep track of, and sprinkle assertions about that lock everywhere. Some things now need to be offloaded to work structs so that we don't require being able to sleep in functions the drivers call. The exception to that are the MLME callbacks (rx_auth etc.) that currently only mac80211 calls because it was easier to do that there instead of in cfg80211, and future drivers implementing those calls will, if they ever exist, probably need to use a similar scheme like mac80211 anyway... In order to be able to handle _deauth and _disassoc properly, introduce a cookie passed to it that will determine locking requirements. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless/core.c')
-rw-r--r--net/wireless/core.c92
1 files changed, 86 insertions, 6 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c
index c6813beded06..9c73769440a8 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -257,6 +257,71 @@ static void cfg80211_rfkill_sync_work(struct work_struct *work)
257 cfg80211_rfkill_set_block(drv, rfkill_blocked(drv->rfkill)); 257 cfg80211_rfkill_set_block(drv, rfkill_blocked(drv->rfkill));
258} 258}
259 259
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))