aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/wireless/core.c76
-rw-r--r--net/wireless/core.h2
2 files changed, 65 insertions, 13 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 69a185ba9ff1..c150071b6f29 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -430,6 +430,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
430 INIT_WORK(&rdev->conn_work, cfg80211_conn_work); 430 INIT_WORK(&rdev->conn_work, cfg80211_conn_work);
431 INIT_WORK(&rdev->event_work, cfg80211_event_work); 431 INIT_WORK(&rdev->event_work, cfg80211_event_work);
432 432
433 init_waitqueue_head(&rdev->dev_wait);
434
433 /* 435 /*
434 * Initialize wiphy parameters to IEEE 802.11 MIB default values. 436 * Initialize wiphy parameters to IEEE 802.11 MIB default values.
435 * Fragmentation and RTS threshold are disabled by default with the 437 * Fragmentation and RTS threshold are disabled by default with the
@@ -574,7 +576,23 @@ void wiphy_unregister(struct wiphy *wiphy)
574 /* protect the device list */ 576 /* protect the device list */
575 mutex_lock(&cfg80211_mutex); 577 mutex_lock(&cfg80211_mutex);
576 578
579 wait_event(rdev->dev_wait, ({
580 int __count;
581 mutex_lock(&rdev->devlist_mtx);
582 __count = rdev->opencount;
583 mutex_unlock(&rdev->devlist_mtx);
584 __count == 0;}));
585
586 mutex_lock(&rdev->devlist_mtx);
577 BUG_ON(!list_empty(&rdev->netdev_list)); 587 BUG_ON(!list_empty(&rdev->netdev_list));
588 mutex_unlock(&rdev->devlist_mtx);
589
590 /*
591 * First remove the hardware from everywhere, this makes
592 * it impossible to find from userspace.
593 */
594 cfg80211_debugfs_rdev_del(rdev);
595 list_del(&rdev->list);
578 596
579 /* 597 /*
580 * Try to grab rdev->mtx. If a command is still in progress, 598 * Try to grab rdev->mtx. If a command is still in progress,
@@ -582,26 +600,18 @@ void wiphy_unregister(struct wiphy *wiphy)
582 * down the device already. We wait for this command to complete 600 * down the device already. We wait for this command to complete
583 * before unlinking the item from the list. 601 * before unlinking the item from the list.
584 * Note: as codified by the BUG_ON above we cannot get here if 602 * Note: as codified by the BUG_ON above we cannot get here if
585 * a virtual interface is still associated. Hence, we can only 603 * a virtual interface is still present. Hence, we can only get
586 * get to lock contention here if userspace issues a command 604 * to lock contention here if userspace issues a command that
587 * that identified the hardware by wiphy index. 605 * identified the hardware by wiphy index.
588 */ 606 */
589 cfg80211_lock_rdev(rdev); 607 cfg80211_lock_rdev(rdev);
590 608 /* nothing */
591 if (WARN_ON(rdev->scan_req)) {
592 rdev->scan_req->aborted = true;
593 ___cfg80211_scan_done(rdev);
594 }
595
596 cfg80211_unlock_rdev(rdev); 609 cfg80211_unlock_rdev(rdev);
597 610
598 cfg80211_debugfs_rdev_del(rdev);
599
600 /* If this device got a regulatory hint tell core its 611 /* If this device got a regulatory hint tell core its
601 * free to listen now to a new shiny device regulatory hint */ 612 * free to listen now to a new shiny device regulatory hint */
602 reg_device_remove(wiphy); 613 reg_device_remove(wiphy);
603 614
604 list_del(&rdev->list);
605 cfg80211_rdev_list_generation++; 615 cfg80211_rdev_list_generation++;
606 device_del(&rdev->wiphy.dev); 616 device_del(&rdev->wiphy.dev);
607 debugfs_remove(rdev->wiphy.debugfsdir); 617 debugfs_remove(rdev->wiphy.debugfsdir);
@@ -640,6 +650,31 @@ void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked)
640} 650}
641EXPORT_SYMBOL(wiphy_rfkill_set_hw_state); 651EXPORT_SYMBOL(wiphy_rfkill_set_hw_state);
642 652
653static void wdev_cleanup_work(struct work_struct *work)
654{
655 struct wireless_dev *wdev;
656 struct cfg80211_registered_device *rdev;
657
658 wdev = container_of(work, struct wireless_dev, cleanup_work);
659 rdev = wiphy_to_dev(wdev->wiphy);
660
661 cfg80211_lock_rdev(rdev);
662
663 if (WARN_ON(rdev->scan_req && rdev->scan_req->dev == wdev->netdev)) {
664 rdev->scan_req->aborted = true;
665 ___cfg80211_scan_done(rdev);
666 }
667
668 cfg80211_unlock_rdev(rdev);
669
670 mutex_lock(&rdev->devlist_mtx);
671 rdev->opencount--;
672 mutex_unlock(&rdev->devlist_mtx);
673 wake_up(&rdev->dev_wait);
674
675 dev_put(wdev->netdev);
676}
677
643static int cfg80211_netdev_notifier_call(struct notifier_block * nb, 678static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
644 unsigned long state, 679 unsigned long state,
645 void *ndev) 680 void *ndev)
@@ -663,6 +698,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
663 * are added with nl80211. 698 * are added with nl80211.
664 */ 699 */
665 mutex_init(&wdev->mtx); 700 mutex_init(&wdev->mtx);
701 INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work);
666 INIT_LIST_HEAD(&wdev->event_list); 702 INIT_LIST_HEAD(&wdev->event_list);
667 spin_lock_init(&wdev->event_lock); 703 spin_lock_init(&wdev->event_lock);
668 mutex_lock(&rdev->devlist_mtx); 704 mutex_lock(&rdev->devlist_mtx);
@@ -717,8 +753,22 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
717 default: 753 default:
718 break; 754 break;
719 } 755 }
756 dev_hold(dev);
757 schedule_work(&wdev->cleanup_work);
720 break; 758 break;
721 case NETDEV_UP: 759 case NETDEV_UP:
760 /*
761 * If we have a really quick DOWN/UP succession we may
762 * have this work still pending ... cancel it and see
763 * if it was pending, in which case we need to account
764 * for some of the work it would have done.
765 */
766 if (cancel_work_sync(&wdev->cleanup_work)) {
767 mutex_lock(&rdev->devlist_mtx);
768 rdev->opencount--;
769 mutex_unlock(&rdev->devlist_mtx);
770 dev_put(dev);
771 }
722#ifdef CONFIG_WIRELESS_EXT 772#ifdef CONFIG_WIRELESS_EXT
723 cfg80211_lock_rdev(rdev); 773 cfg80211_lock_rdev(rdev);
724 mutex_lock(&rdev->devlist_mtx); 774 mutex_lock(&rdev->devlist_mtx);
@@ -734,6 +784,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
734 break; 784 break;
735 } 785 }
736 wdev_unlock(wdev); 786 wdev_unlock(wdev);
787 rdev->opencount++;
737 mutex_unlock(&rdev->devlist_mtx); 788 mutex_unlock(&rdev->devlist_mtx);
738 cfg80211_unlock_rdev(rdev); 789 cfg80211_unlock_rdev(rdev);
739#endif 790#endif
@@ -756,7 +807,6 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
756 sysfs_remove_link(&dev->dev.kobj, "phy80211"); 807 sysfs_remove_link(&dev->dev.kobj, "phy80211");
757 list_del_init(&wdev->list); 808 list_del_init(&wdev->list);
758 rdev->devlist_generation++; 809 rdev->devlist_generation++;
759 mutex_destroy(&wdev->mtx);
760#ifdef CONFIG_WIRELESS_EXT 810#ifdef CONFIG_WIRELESS_EXT
761 kfree(wdev->wext.keys); 811 kfree(wdev->wext.keys);
762#endif 812#endif
diff --git a/net/wireless/core.h b/net/wireless/core.h
index c603f5286326..f565432ae22f 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -50,6 +50,8 @@ struct cfg80211_registered_device {
50 struct mutex devlist_mtx; 50 struct mutex devlist_mtx;
51 struct list_head netdev_list; 51 struct list_head netdev_list;
52 int devlist_generation; 52 int devlist_generation;
53 int opencount; /* also protected by devlist_mtx */
54 wait_queue_head_t dev_wait;
53 55
54 /* BSSes/scanning */ 56 /* BSSes/scanning */
55 spinlock_t bss_lock; 57 spinlock_t bss_lock;