diff options
Diffstat (limited to 'net/wireless/core.c')
-rw-r--r-- | net/wireless/core.c | 224 |
1 files changed, 46 insertions, 178 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c index 01e41191f1bf..e4df77490229 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -34,13 +34,12 @@ | |||
34 | MODULE_AUTHOR("Johannes Berg"); | 34 | MODULE_AUTHOR("Johannes Berg"); |
35 | MODULE_LICENSE("GPL"); | 35 | MODULE_LICENSE("GPL"); |
36 | MODULE_DESCRIPTION("wireless configuration support"); | 36 | MODULE_DESCRIPTION("wireless configuration support"); |
37 | MODULE_ALIAS_GENL_FAMILY(NL80211_GENL_NAME); | ||
37 | 38 | ||
38 | /* RCU-protected (and cfg80211_mutex for writers) */ | 39 | /* RCU-protected (and RTNL for writers) */ |
39 | LIST_HEAD(cfg80211_rdev_list); | 40 | LIST_HEAD(cfg80211_rdev_list); |
40 | int cfg80211_rdev_list_generation; | 41 | int cfg80211_rdev_list_generation; |
41 | 42 | ||
42 | DEFINE_MUTEX(cfg80211_mutex); | ||
43 | |||
44 | /* for debugfs */ | 43 | /* for debugfs */ |
45 | static struct dentry *ieee80211_debugfs_dir; | 44 | static struct dentry *ieee80211_debugfs_dir; |
46 | 45 | ||
@@ -52,12 +51,11 @@ module_param(cfg80211_disable_40mhz_24ghz, bool, 0644); | |||
52 | MODULE_PARM_DESC(cfg80211_disable_40mhz_24ghz, | 51 | MODULE_PARM_DESC(cfg80211_disable_40mhz_24ghz, |
53 | "Disable 40MHz support in the 2.4GHz band"); | 52 | "Disable 40MHz support in the 2.4GHz band"); |
54 | 53 | ||
55 | /* requires cfg80211_mutex to be held! */ | ||
56 | struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx) | 54 | struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx) |
57 | { | 55 | { |
58 | struct cfg80211_registered_device *result = NULL, *rdev; | 56 | struct cfg80211_registered_device *result = NULL, *rdev; |
59 | 57 | ||
60 | assert_cfg80211_lock(); | 58 | ASSERT_RTNL(); |
61 | 59 | ||
62 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | 60 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { |
63 | if (rdev->wiphy_idx == wiphy_idx) { | 61 | if (rdev->wiphy_idx == wiphy_idx) { |
@@ -76,12 +74,11 @@ int get_wiphy_idx(struct wiphy *wiphy) | |||
76 | return rdev->wiphy_idx; | 74 | return rdev->wiphy_idx; |
77 | } | 75 | } |
78 | 76 | ||
79 | /* requires cfg80211_rdev_mutex to be held! */ | ||
80 | struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx) | 77 | struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx) |
81 | { | 78 | { |
82 | struct cfg80211_registered_device *rdev; | 79 | struct cfg80211_registered_device *rdev; |
83 | 80 | ||
84 | assert_cfg80211_lock(); | 81 | ASSERT_RTNL(); |
85 | 82 | ||
86 | rdev = cfg80211_rdev_by_wiphy_idx(wiphy_idx); | 83 | rdev = cfg80211_rdev_by_wiphy_idx(wiphy_idx); |
87 | if (!rdev) | 84 | if (!rdev) |
@@ -89,35 +86,13 @@ struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx) | |||
89 | return &rdev->wiphy; | 86 | return &rdev->wiphy; |
90 | } | 87 | } |
91 | 88 | ||
92 | struct cfg80211_registered_device * | ||
93 | cfg80211_get_dev_from_ifindex(struct net *net, int ifindex) | ||
94 | { | ||
95 | struct cfg80211_registered_device *rdev = ERR_PTR(-ENODEV); | ||
96 | struct net_device *dev; | ||
97 | |||
98 | mutex_lock(&cfg80211_mutex); | ||
99 | dev = dev_get_by_index(net, ifindex); | ||
100 | if (!dev) | ||
101 | goto out; | ||
102 | if (dev->ieee80211_ptr) { | ||
103 | rdev = wiphy_to_dev(dev->ieee80211_ptr->wiphy); | ||
104 | mutex_lock(&rdev->mtx); | ||
105 | } else | ||
106 | rdev = ERR_PTR(-ENODEV); | ||
107 | dev_put(dev); | ||
108 | out: | ||
109 | mutex_unlock(&cfg80211_mutex); | ||
110 | return rdev; | ||
111 | } | ||
112 | |||
113 | /* requires cfg80211_mutex to be held */ | ||
114 | int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, | 89 | int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, |
115 | char *newname) | 90 | char *newname) |
116 | { | 91 | { |
117 | struct cfg80211_registered_device *rdev2; | 92 | struct cfg80211_registered_device *rdev2; |
118 | int wiphy_idx, taken = -1, result, digits; | 93 | int wiphy_idx, taken = -1, result, digits; |
119 | 94 | ||
120 | assert_cfg80211_lock(); | 95 | ASSERT_RTNL(); |
121 | 96 | ||
122 | /* prohibit calling the thing phy%d when %d is not its number */ | 97 | /* prohibit calling the thing phy%d when %d is not its number */ |
123 | sscanf(newname, PHY_NAME "%d%n", &wiphy_idx, &taken); | 98 | sscanf(newname, PHY_NAME "%d%n", &wiphy_idx, &taken); |
@@ -215,8 +190,7 @@ static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data) | |||
215 | void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev, | 190 | void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev, |
216 | struct wireless_dev *wdev) | 191 | struct wireless_dev *wdev) |
217 | { | 192 | { |
218 | lockdep_assert_held(&rdev->devlist_mtx); | 193 | ASSERT_RTNL(); |
219 | lockdep_assert_held(&rdev->sched_scan_mtx); | ||
220 | 194 | ||
221 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)) | 195 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_P2P_DEVICE)) |
222 | return; | 196 | return; |
@@ -230,18 +204,15 @@ void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev, | |||
230 | rdev->opencount--; | 204 | rdev->opencount--; |
231 | 205 | ||
232 | if (rdev->scan_req && rdev->scan_req->wdev == wdev) { | 206 | if (rdev->scan_req && rdev->scan_req->wdev == wdev) { |
233 | bool busy = work_busy(&rdev->scan_done_wk); | ||
234 | |||
235 | /* | 207 | /* |
236 | * If the work isn't pending or running (in which case it would | 208 | * If the scan request wasn't notified as done, set it |
237 | * be waiting for the lock we hold) the driver didn't properly | 209 | * to aborted and leak it after a warning. The driver |
238 | * cancel the scan when the interface was removed. In this case | 210 | * should have notified us that it ended at the latest |
239 | * warn and leak the scan request object to not crash later. | 211 | * during rdev_stop_p2p_device(). |
240 | */ | 212 | */ |
241 | WARN_ON(!busy); | 213 | if (WARN_ON(!rdev->scan_req->notified)) |
242 | 214 | rdev->scan_req->aborted = true; | |
243 | rdev->scan_req->aborted = true; | 215 | ___cfg80211_scan_done(rdev, !rdev->scan_req->notified); |
244 | ___cfg80211_scan_done(rdev, !busy); | ||
245 | } | 216 | } |
246 | } | 217 | } |
247 | 218 | ||
@@ -255,8 +226,6 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked) | |||
255 | 226 | ||
256 | rtnl_lock(); | 227 | rtnl_lock(); |
257 | 228 | ||
258 | /* read-only iteration need not hold the devlist_mtx */ | ||
259 | |||
260 | list_for_each_entry(wdev, &rdev->wdev_list, list) { | 229 | list_for_each_entry(wdev, &rdev->wdev_list, list) { |
261 | if (wdev->netdev) { | 230 | if (wdev->netdev) { |
262 | dev_close(wdev->netdev); | 231 | dev_close(wdev->netdev); |
@@ -265,12 +234,7 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked) | |||
265 | /* otherwise, check iftype */ | 234 | /* otherwise, check iftype */ |
266 | switch (wdev->iftype) { | 235 | switch (wdev->iftype) { |
267 | case NL80211_IFTYPE_P2P_DEVICE: | 236 | case NL80211_IFTYPE_P2P_DEVICE: |
268 | /* but this requires it */ | ||
269 | mutex_lock(&rdev->devlist_mtx); | ||
270 | mutex_lock(&rdev->sched_scan_mtx); | ||
271 | cfg80211_stop_p2p_device(rdev, wdev); | 237 | cfg80211_stop_p2p_device(rdev, wdev); |
272 | mutex_unlock(&rdev->sched_scan_mtx); | ||
273 | mutex_unlock(&rdev->devlist_mtx); | ||
274 | break; | 238 | break; |
275 | default: | 239 | default: |
276 | break; | 240 | break; |
@@ -298,10 +262,7 @@ static void cfg80211_event_work(struct work_struct *work) | |||
298 | event_work); | 262 | event_work); |
299 | 263 | ||
300 | rtnl_lock(); | 264 | rtnl_lock(); |
301 | cfg80211_lock_rdev(rdev); | ||
302 | |||
303 | cfg80211_process_rdev_events(rdev); | 265 | cfg80211_process_rdev_events(rdev); |
304 | cfg80211_unlock_rdev(rdev); | ||
305 | rtnl_unlock(); | 266 | rtnl_unlock(); |
306 | } | 267 | } |
307 | 268 | ||
@@ -309,7 +270,7 @@ static void cfg80211_event_work(struct work_struct *work) | |||
309 | 270 | ||
310 | struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | 271 | struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) |
311 | { | 272 | { |
312 | static int wiphy_counter; | 273 | static atomic_t wiphy_counter = ATOMIC_INIT(0); |
313 | 274 | ||
314 | struct cfg80211_registered_device *rdev; | 275 | struct cfg80211_registered_device *rdev; |
315 | int alloc_size; | 276 | int alloc_size; |
@@ -331,26 +292,18 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
331 | 292 | ||
332 | rdev->ops = ops; | 293 | rdev->ops = ops; |
333 | 294 | ||
334 | mutex_lock(&cfg80211_mutex); | 295 | rdev->wiphy_idx = atomic_inc_return(&wiphy_counter); |
335 | |||
336 | rdev->wiphy_idx = wiphy_counter++; | ||
337 | 296 | ||
338 | if (unlikely(rdev->wiphy_idx < 0)) { | 297 | if (unlikely(rdev->wiphy_idx < 0)) { |
339 | wiphy_counter--; | ||
340 | mutex_unlock(&cfg80211_mutex); | ||
341 | /* ugh, wrapped! */ | 298 | /* ugh, wrapped! */ |
299 | atomic_dec(&wiphy_counter); | ||
342 | kfree(rdev); | 300 | kfree(rdev); |
343 | return NULL; | 301 | return NULL; |
344 | } | 302 | } |
345 | 303 | ||
346 | mutex_unlock(&cfg80211_mutex); | ||
347 | |||
348 | /* give it a proper name */ | 304 | /* give it a proper name */ |
349 | dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx); | 305 | dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx); |
350 | 306 | ||
351 | mutex_init(&rdev->mtx); | ||
352 | mutex_init(&rdev->devlist_mtx); | ||
353 | mutex_init(&rdev->sched_scan_mtx); | ||
354 | INIT_LIST_HEAD(&rdev->wdev_list); | 307 | INIT_LIST_HEAD(&rdev->wdev_list); |
355 | INIT_LIST_HEAD(&rdev->beacon_registrations); | 308 | INIT_LIST_HEAD(&rdev->beacon_registrations); |
356 | spin_lock_init(&rdev->beacon_registrations_lock); | 309 | spin_lock_init(&rdev->beacon_registrations_lock); |
@@ -598,11 +551,11 @@ int wiphy_register(struct wiphy *wiphy) | |||
598 | /* check and set up bitrates */ | 551 | /* check and set up bitrates */ |
599 | ieee80211_set_bitrate_flags(wiphy); | 552 | ieee80211_set_bitrate_flags(wiphy); |
600 | 553 | ||
601 | mutex_lock(&cfg80211_mutex); | 554 | rtnl_lock(); |
602 | 555 | ||
603 | res = device_add(&rdev->wiphy.dev); | 556 | res = device_add(&rdev->wiphy.dev); |
604 | if (res) { | 557 | if (res) { |
605 | mutex_unlock(&cfg80211_mutex); | 558 | rtnl_unlock(); |
606 | return res; | 559 | return res; |
607 | } | 560 | } |
608 | 561 | ||
@@ -631,25 +584,18 @@ int wiphy_register(struct wiphy *wiphy) | |||
631 | } | 584 | } |
632 | 585 | ||
633 | cfg80211_debugfs_rdev_add(rdev); | 586 | cfg80211_debugfs_rdev_add(rdev); |
634 | mutex_unlock(&cfg80211_mutex); | ||
635 | 587 | ||
636 | /* | ||
637 | * due to a locking dependency this has to be outside of the | ||
638 | * cfg80211_mutex lock | ||
639 | */ | ||
640 | res = rfkill_register(rdev->rfkill); | 588 | res = rfkill_register(rdev->rfkill); |
641 | if (res) { | 589 | if (res) { |
642 | device_del(&rdev->wiphy.dev); | 590 | device_del(&rdev->wiphy.dev); |
643 | 591 | ||
644 | mutex_lock(&cfg80211_mutex); | ||
645 | debugfs_remove_recursive(rdev->wiphy.debugfsdir); | 592 | debugfs_remove_recursive(rdev->wiphy.debugfsdir); |
646 | list_del_rcu(&rdev->list); | 593 | list_del_rcu(&rdev->list); |
647 | wiphy_regulatory_deregister(wiphy); | 594 | wiphy_regulatory_deregister(wiphy); |
648 | mutex_unlock(&cfg80211_mutex); | 595 | rtnl_unlock(); |
649 | return res; | 596 | return res; |
650 | } | 597 | } |
651 | 598 | ||
652 | rtnl_lock(); | ||
653 | rdev->wiphy.registered = true; | 599 | rdev->wiphy.registered = true; |
654 | rtnl_unlock(); | 600 | rtnl_unlock(); |
655 | return 0; | 601 | return 0; |
@@ -679,25 +625,19 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
679 | { | 625 | { |
680 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 626 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
681 | 627 | ||
682 | rtnl_lock(); | ||
683 | rdev->wiphy.registered = false; | ||
684 | rtnl_unlock(); | ||
685 | |||
686 | rfkill_unregister(rdev->rfkill); | ||
687 | |||
688 | /* protect the device list */ | ||
689 | mutex_lock(&cfg80211_mutex); | ||
690 | |||
691 | wait_event(rdev->dev_wait, ({ | 628 | wait_event(rdev->dev_wait, ({ |
692 | int __count; | 629 | int __count; |
693 | mutex_lock(&rdev->devlist_mtx); | 630 | rtnl_lock(); |
694 | __count = rdev->opencount; | 631 | __count = rdev->opencount; |
695 | mutex_unlock(&rdev->devlist_mtx); | 632 | rtnl_unlock(); |
696 | __count == 0; })); | 633 | __count == 0; })); |
697 | 634 | ||
698 | mutex_lock(&rdev->devlist_mtx); | 635 | rtnl_lock(); |
636 | rdev->wiphy.registered = false; | ||
637 | |||
638 | rfkill_unregister(rdev->rfkill); | ||
639 | |||
699 | BUG_ON(!list_empty(&rdev->wdev_list)); | 640 | BUG_ON(!list_empty(&rdev->wdev_list)); |
700 | mutex_unlock(&rdev->devlist_mtx); | ||
701 | 641 | ||
702 | /* | 642 | /* |
703 | * First remove the hardware from everywhere, this makes | 643 | * First remove the hardware from everywhere, this makes |
@@ -708,20 +648,6 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
708 | synchronize_rcu(); | 648 | synchronize_rcu(); |
709 | 649 | ||
710 | /* | 650 | /* |
711 | * Try to grab rdev->mtx. If a command is still in progress, | ||
712 | * hopefully the driver will refuse it since it's tearing | ||
713 | * down the device already. We wait for this command to complete | ||
714 | * before unlinking the item from the list. | ||
715 | * Note: as codified by the BUG_ON above we cannot get here if | ||
716 | * a virtual interface is still present. Hence, we can only get | ||
717 | * to lock contention here if userspace issues a command that | ||
718 | * identified the hardware by wiphy index. | ||
719 | */ | ||
720 | cfg80211_lock_rdev(rdev); | ||
721 | /* nothing */ | ||
722 | cfg80211_unlock_rdev(rdev); | ||
723 | |||
724 | /* | ||
725 | * If this device got a regulatory hint tell core its | 651 | * If this device got a regulatory hint tell core its |
726 | * free to listen now to a new shiny device regulatory hint | 652 | * free to listen now to a new shiny device regulatory hint |
727 | */ | 653 | */ |
@@ -730,15 +656,17 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
730 | cfg80211_rdev_list_generation++; | 656 | cfg80211_rdev_list_generation++; |
731 | device_del(&rdev->wiphy.dev); | 657 | device_del(&rdev->wiphy.dev); |
732 | 658 | ||
733 | mutex_unlock(&cfg80211_mutex); | 659 | rtnl_unlock(); |
734 | 660 | ||
735 | flush_work(&rdev->scan_done_wk); | 661 | flush_work(&rdev->scan_done_wk); |
736 | cancel_work_sync(&rdev->conn_work); | 662 | cancel_work_sync(&rdev->conn_work); |
737 | flush_work(&rdev->event_work); | 663 | flush_work(&rdev->event_work); |
738 | cancel_delayed_work_sync(&rdev->dfs_update_channels_wk); | 664 | cancel_delayed_work_sync(&rdev->dfs_update_channels_wk); |
739 | 665 | ||
740 | if (rdev->wowlan && rdev->ops->set_wakeup) | 666 | #ifdef CONFIG_PM |
667 | if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup) | ||
741 | rdev_set_wakeup(rdev, false); | 668 | rdev_set_wakeup(rdev, false); |
669 | #endif | ||
742 | cfg80211_rdev_free_wowlan(rdev); | 670 | cfg80211_rdev_free_wowlan(rdev); |
743 | } | 671 | } |
744 | EXPORT_SYMBOL(wiphy_unregister); | 672 | EXPORT_SYMBOL(wiphy_unregister); |
@@ -748,9 +676,6 @@ void cfg80211_dev_free(struct cfg80211_registered_device *rdev) | |||
748 | struct cfg80211_internal_bss *scan, *tmp; | 676 | struct cfg80211_internal_bss *scan, *tmp; |
749 | struct cfg80211_beacon_registration *reg, *treg; | 677 | struct cfg80211_beacon_registration *reg, *treg; |
750 | rfkill_destroy(rdev->rfkill); | 678 | rfkill_destroy(rdev->rfkill); |
751 | mutex_destroy(&rdev->mtx); | ||
752 | mutex_destroy(&rdev->devlist_mtx); | ||
753 | mutex_destroy(&rdev->sched_scan_mtx); | ||
754 | list_for_each_entry_safe(reg, treg, &rdev->beacon_registrations, list) { | 679 | list_for_each_entry_safe(reg, treg, &rdev->beacon_registrations, list) { |
755 | list_del(®->list); | 680 | list_del(®->list); |
756 | kfree(reg); | 681 | kfree(reg); |
@@ -775,36 +700,6 @@ void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked) | |||
775 | } | 700 | } |
776 | EXPORT_SYMBOL(wiphy_rfkill_set_hw_state); | 701 | EXPORT_SYMBOL(wiphy_rfkill_set_hw_state); |
777 | 702 | ||
778 | static void wdev_cleanup_work(struct work_struct *work) | ||
779 | { | ||
780 | struct wireless_dev *wdev; | ||
781 | struct cfg80211_registered_device *rdev; | ||
782 | |||
783 | wdev = container_of(work, struct wireless_dev, cleanup_work); | ||
784 | rdev = wiphy_to_dev(wdev->wiphy); | ||
785 | |||
786 | mutex_lock(&rdev->sched_scan_mtx); | ||
787 | |||
788 | if (WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev)) { | ||
789 | rdev->scan_req->aborted = true; | ||
790 | ___cfg80211_scan_done(rdev, true); | ||
791 | } | ||
792 | |||
793 | if (WARN_ON(rdev->sched_scan_req && | ||
794 | rdev->sched_scan_req->dev == wdev->netdev)) { | ||
795 | __cfg80211_stop_sched_scan(rdev, false); | ||
796 | } | ||
797 | |||
798 | mutex_unlock(&rdev->sched_scan_mtx); | ||
799 | |||
800 | mutex_lock(&rdev->devlist_mtx); | ||
801 | rdev->opencount--; | ||
802 | mutex_unlock(&rdev->devlist_mtx); | ||
803 | wake_up(&rdev->dev_wait); | ||
804 | |||
805 | dev_put(wdev->netdev); | ||
806 | } | ||
807 | |||
808 | void cfg80211_unregister_wdev(struct wireless_dev *wdev) | 703 | void cfg80211_unregister_wdev(struct wireless_dev *wdev) |
809 | { | 704 | { |
810 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | 705 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
@@ -814,8 +709,6 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev) | |||
814 | if (WARN_ON(wdev->netdev)) | 709 | if (WARN_ON(wdev->netdev)) |
815 | return; | 710 | return; |
816 | 711 | ||
817 | mutex_lock(&rdev->devlist_mtx); | ||
818 | mutex_lock(&rdev->sched_scan_mtx); | ||
819 | list_del_rcu(&wdev->list); | 712 | list_del_rcu(&wdev->list); |
820 | rdev->devlist_generation++; | 713 | rdev->devlist_generation++; |
821 | 714 | ||
@@ -827,8 +720,6 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev) | |||
827 | WARN_ON_ONCE(1); | 720 | WARN_ON_ONCE(1); |
828 | break; | 721 | break; |
829 | } | 722 | } |
830 | mutex_unlock(&rdev->sched_scan_mtx); | ||
831 | mutex_unlock(&rdev->devlist_mtx); | ||
832 | } | 723 | } |
833 | EXPORT_SYMBOL(cfg80211_unregister_wdev); | 724 | EXPORT_SYMBOL(cfg80211_unregister_wdev); |
834 | 725 | ||
@@ -847,7 +738,7 @@ void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, | |||
847 | } | 738 | } |
848 | 739 | ||
849 | void cfg80211_leave(struct cfg80211_registered_device *rdev, | 740 | void cfg80211_leave(struct cfg80211_registered_device *rdev, |
850 | struct wireless_dev *wdev) | 741 | struct wireless_dev *wdev) |
851 | { | 742 | { |
852 | struct net_device *dev = wdev->netdev; | 743 | struct net_device *dev = wdev->netdev; |
853 | 744 | ||
@@ -857,9 +748,7 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev, | |||
857 | break; | 748 | break; |
858 | case NL80211_IFTYPE_P2P_CLIENT: | 749 | case NL80211_IFTYPE_P2P_CLIENT: |
859 | case NL80211_IFTYPE_STATION: | 750 | case NL80211_IFTYPE_STATION: |
860 | mutex_lock(&rdev->sched_scan_mtx); | ||
861 | __cfg80211_stop_sched_scan(rdev, false); | 751 | __cfg80211_stop_sched_scan(rdev, false); |
862 | mutex_unlock(&rdev->sched_scan_mtx); | ||
863 | 752 | ||
864 | wdev_lock(wdev); | 753 | wdev_lock(wdev); |
865 | #ifdef CONFIG_CFG80211_WEXT | 754 | #ifdef CONFIG_CFG80211_WEXT |
@@ -868,8 +757,8 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev, | |||
868 | wdev->wext.ie_len = 0; | 757 | wdev->wext.ie_len = 0; |
869 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; | 758 | wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; |
870 | #endif | 759 | #endif |
871 | __cfg80211_disconnect(rdev, dev, | 760 | cfg80211_disconnect(rdev, dev, |
872 | WLAN_REASON_DEAUTH_LEAVING, true); | 761 | WLAN_REASON_DEAUTH_LEAVING, true); |
873 | wdev_unlock(wdev); | 762 | wdev_unlock(wdev); |
874 | break; | 763 | break; |
875 | case NL80211_IFTYPE_MESH_POINT: | 764 | case NL80211_IFTYPE_MESH_POINT: |
@@ -911,13 +800,11 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
911 | * are added with nl80211. | 800 | * are added with nl80211. |
912 | */ | 801 | */ |
913 | mutex_init(&wdev->mtx); | 802 | mutex_init(&wdev->mtx); |
914 | INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work); | ||
915 | INIT_LIST_HEAD(&wdev->event_list); | 803 | INIT_LIST_HEAD(&wdev->event_list); |
916 | spin_lock_init(&wdev->event_lock); | 804 | spin_lock_init(&wdev->event_lock); |
917 | INIT_LIST_HEAD(&wdev->mgmt_registrations); | 805 | INIT_LIST_HEAD(&wdev->mgmt_registrations); |
918 | spin_lock_init(&wdev->mgmt_registrations_lock); | 806 | spin_lock_init(&wdev->mgmt_registrations_lock); |
919 | 807 | ||
920 | mutex_lock(&rdev->devlist_mtx); | ||
921 | wdev->identifier = ++rdev->wdev_id; | 808 | wdev->identifier = ++rdev->wdev_id; |
922 | list_add_rcu(&wdev->list, &rdev->wdev_list); | 809 | list_add_rcu(&wdev->list, &rdev->wdev_list); |
923 | rdev->devlist_generation++; | 810 | rdev->devlist_generation++; |
@@ -930,7 +817,6 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
930 | } | 817 | } |
931 | wdev->netdev = dev; | 818 | wdev->netdev = dev; |
932 | wdev->sme_state = CFG80211_SME_IDLE; | 819 | wdev->sme_state = CFG80211_SME_IDLE; |
933 | mutex_unlock(&rdev->devlist_mtx); | ||
934 | #ifdef CONFIG_CFG80211_WEXT | 820 | #ifdef CONFIG_CFG80211_WEXT |
935 | wdev->wext.default_key = -1; | 821 | wdev->wext.default_key = -1; |
936 | wdev->wext.default_mgmt_key = -1; | 822 | wdev->wext.default_mgmt_key = -1; |
@@ -956,26 +842,22 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
956 | break; | 842 | break; |
957 | case NETDEV_DOWN: | 843 | case NETDEV_DOWN: |
958 | cfg80211_update_iface_num(rdev, wdev->iftype, -1); | 844 | cfg80211_update_iface_num(rdev, wdev->iftype, -1); |
959 | dev_hold(dev); | 845 | if (rdev->scan_req && rdev->scan_req->wdev == wdev) { |
960 | queue_work(cfg80211_wq, &wdev->cleanup_work); | 846 | if (WARN_ON(!rdev->scan_req->notified)) |
847 | rdev->scan_req->aborted = true; | ||
848 | ___cfg80211_scan_done(rdev, true); | ||
849 | } | ||
850 | |||
851 | if (WARN_ON(rdev->sched_scan_req && | ||
852 | rdev->sched_scan_req->dev == wdev->netdev)) { | ||
853 | __cfg80211_stop_sched_scan(rdev, false); | ||
854 | } | ||
855 | |||
856 | rdev->opencount--; | ||
857 | wake_up(&rdev->dev_wait); | ||
961 | break; | 858 | break; |
962 | case NETDEV_UP: | 859 | case NETDEV_UP: |
963 | /* | ||
964 | * If we have a really quick DOWN/UP succession we may | ||
965 | * have this work still pending ... cancel it and see | ||
966 | * if it was pending, in which case we need to account | ||
967 | * for some of the work it would have done. | ||
968 | */ | ||
969 | if (cancel_work_sync(&wdev->cleanup_work)) { | ||
970 | mutex_lock(&rdev->devlist_mtx); | ||
971 | rdev->opencount--; | ||
972 | mutex_unlock(&rdev->devlist_mtx); | ||
973 | dev_put(dev); | ||
974 | } | ||
975 | cfg80211_update_iface_num(rdev, wdev->iftype, 1); | 860 | cfg80211_update_iface_num(rdev, wdev->iftype, 1); |
976 | cfg80211_lock_rdev(rdev); | ||
977 | mutex_lock(&rdev->devlist_mtx); | ||
978 | mutex_lock(&rdev->sched_scan_mtx); | ||
979 | wdev_lock(wdev); | 861 | wdev_lock(wdev); |
980 | switch (wdev->iftype) { | 862 | switch (wdev->iftype) { |
981 | #ifdef CONFIG_CFG80211_WEXT | 863 | #ifdef CONFIG_CFG80211_WEXT |
@@ -1007,10 +889,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
1007 | break; | 889 | break; |
1008 | } | 890 | } |
1009 | wdev_unlock(wdev); | 891 | wdev_unlock(wdev); |
1010 | mutex_unlock(&rdev->sched_scan_mtx); | ||
1011 | rdev->opencount++; | 892 | rdev->opencount++; |
1012 | mutex_unlock(&rdev->devlist_mtx); | ||
1013 | cfg80211_unlock_rdev(rdev); | ||
1014 | 893 | ||
1015 | /* | 894 | /* |
1016 | * Configure power management to the driver here so that its | 895 | * Configure power management to the driver here so that its |
@@ -1027,12 +906,6 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
1027 | break; | 906 | break; |
1028 | case NETDEV_UNREGISTER: | 907 | case NETDEV_UNREGISTER: |
1029 | /* | 908 | /* |
1030 | * NB: cannot take rdev->mtx here because this may be | ||
1031 | * called within code protected by it when interfaces | ||
1032 | * are removed with nl80211. | ||
1033 | */ | ||
1034 | mutex_lock(&rdev->devlist_mtx); | ||
1035 | /* | ||
1036 | * It is possible to get NETDEV_UNREGISTER | 909 | * It is possible to get NETDEV_UNREGISTER |
1037 | * multiple times. To detect that, check | 910 | * multiple times. To detect that, check |
1038 | * that the interface is still on the list | 911 | * that the interface is still on the list |
@@ -1048,7 +921,6 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
1048 | kfree(wdev->wext.keys); | 921 | kfree(wdev->wext.keys); |
1049 | #endif | 922 | #endif |
1050 | } | 923 | } |
1051 | mutex_unlock(&rdev->devlist_mtx); | ||
1052 | /* | 924 | /* |
1053 | * synchronise (so that we won't find this netdev | 925 | * synchronise (so that we won't find this netdev |
1054 | * from other code any more) and then clear the list | 926 | * from other code any more) and then clear the list |
@@ -1068,9 +940,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, | |||
1068 | return notifier_from_errno(-EOPNOTSUPP); | 940 | return notifier_from_errno(-EOPNOTSUPP); |
1069 | if (rfkill_blocked(rdev->rfkill)) | 941 | if (rfkill_blocked(rdev->rfkill)) |
1070 | return notifier_from_errno(-ERFKILL); | 942 | return notifier_from_errno(-ERFKILL); |
1071 | mutex_lock(&rdev->devlist_mtx); | ||
1072 | ret = cfg80211_can_add_interface(rdev, wdev->iftype); | 943 | ret = cfg80211_can_add_interface(rdev, wdev->iftype); |
1073 | mutex_unlock(&rdev->devlist_mtx); | ||
1074 | if (ret) | 944 | if (ret) |
1075 | return notifier_from_errno(ret); | 945 | return notifier_from_errno(ret); |
1076 | break; | 946 | break; |
@@ -1088,12 +958,10 @@ static void __net_exit cfg80211_pernet_exit(struct net *net) | |||
1088 | struct cfg80211_registered_device *rdev; | 958 | struct cfg80211_registered_device *rdev; |
1089 | 959 | ||
1090 | rtnl_lock(); | 960 | rtnl_lock(); |
1091 | mutex_lock(&cfg80211_mutex); | ||
1092 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | 961 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { |
1093 | if (net_eq(wiphy_net(&rdev->wiphy), net)) | 962 | if (net_eq(wiphy_net(&rdev->wiphy), net)) |
1094 | WARN_ON(cfg80211_switch_netns(rdev, &init_net)); | 963 | WARN_ON(cfg80211_switch_netns(rdev, &init_net)); |
1095 | } | 964 | } |
1096 | mutex_unlock(&cfg80211_mutex); | ||
1097 | rtnl_unlock(); | 965 | rtnl_unlock(); |
1098 | } | 966 | } |
1099 | 967 | ||