aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/core.c')
-rw-r--r--net/wireless/core.c67
1 files changed, 48 insertions, 19 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 5ffff039b017..6ddf74f0ae1e 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -212,6 +212,39 @@ static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data)
212 rdev_rfkill_poll(rdev); 212 rdev_rfkill_poll(rdev);
213} 213}
214 214
215void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev,
216 struct wireless_dev *wdev)
217{
218 lockdep_assert_held(&rdev->devlist_mtx);
219 lockdep_assert_held(&rdev->sched_scan_mtx);
220
221 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_P2P_DEVICE))
222 return;
223
224 if (!wdev->p2p_started)
225 return;
226
227 rdev_stop_p2p_device(rdev, wdev);
228 wdev->p2p_started = false;
229
230 rdev->opencount--;
231
232 if (rdev->scan_req && rdev->scan_req->wdev == wdev) {
233 bool busy = work_busy(&rdev->scan_done_wk);
234
235 /*
236 * If the work isn't pending or running (in which case it would
237 * be waiting for the lock we hold) the driver didn't properly
238 * cancel the scan when the interface was removed. In this case
239 * warn and leak the scan request object to not crash later.
240 */
241 WARN_ON(!busy);
242
243 rdev->scan_req->aborted = true;
244 ___cfg80211_scan_done(rdev, !busy);
245 }
246}
247
215static int cfg80211_rfkill_set_block(void *data, bool blocked) 248static int cfg80211_rfkill_set_block(void *data, bool blocked)
216{ 249{
217 struct cfg80211_registered_device *rdev = data; 250 struct cfg80211_registered_device *rdev = data;
@@ -221,7 +254,8 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked)
221 return 0; 254 return 0;
222 255
223 rtnl_lock(); 256 rtnl_lock();
224 mutex_lock(&rdev->devlist_mtx); 257
258 /* read-only iteration need not hold the devlist_mtx */
225 259
226 list_for_each_entry(wdev, &rdev->wdev_list, list) { 260 list_for_each_entry(wdev, &rdev->wdev_list, list) {
227 if (wdev->netdev) { 261 if (wdev->netdev) {
@@ -231,18 +265,18 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked)
231 /* otherwise, check iftype */ 265 /* otherwise, check iftype */
232 switch (wdev->iftype) { 266 switch (wdev->iftype) {
233 case NL80211_IFTYPE_P2P_DEVICE: 267 case NL80211_IFTYPE_P2P_DEVICE:
234 if (!wdev->p2p_started) 268 /* but this requires it */
235 break; 269 mutex_lock(&rdev->devlist_mtx);
236 rdev_stop_p2p_device(rdev, wdev); 270 mutex_lock(&rdev->sched_scan_mtx);
237 wdev->p2p_started = false; 271 cfg80211_stop_p2p_device(rdev, wdev);
238 rdev->opencount--; 272 mutex_unlock(&rdev->sched_scan_mtx);
273 mutex_unlock(&rdev->devlist_mtx);
239 break; 274 break;
240 default: 275 default:
241 break; 276 break;
242 } 277 }
243 } 278 }
244 279
245 mutex_unlock(&rdev->devlist_mtx);
246 rtnl_unlock(); 280 rtnl_unlock();
247 281
248 return 0; 282 return 0;
@@ -367,8 +401,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
367 rdev->wiphy.rts_threshold = (u32) -1; 401 rdev->wiphy.rts_threshold = (u32) -1;
368 rdev->wiphy.coverage_class = 0; 402 rdev->wiphy.coverage_class = 0;
369 403
370 rdev->wiphy.features = NL80211_FEATURE_SCAN_FLUSH | 404 rdev->wiphy.features = NL80211_FEATURE_SCAN_FLUSH;
371 NL80211_FEATURE_ADVERTISE_CHAN_LIMITS;
372 405
373 return &rdev->wiphy; 406 return &rdev->wiphy;
374} 407}
@@ -746,17 +779,13 @@ static void wdev_cleanup_work(struct work_struct *work)
746 wdev = container_of(work, struct wireless_dev, cleanup_work); 779 wdev = container_of(work, struct wireless_dev, cleanup_work);
747 rdev = wiphy_to_dev(wdev->wiphy); 780 rdev = wiphy_to_dev(wdev->wiphy);
748 781
749 cfg80211_lock_rdev(rdev); 782 mutex_lock(&rdev->sched_scan_mtx);
750 783
751 if (WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev)) { 784 if (WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev)) {
752 rdev->scan_req->aborted = true; 785 rdev->scan_req->aborted = true;
753 ___cfg80211_scan_done(rdev, true); 786 ___cfg80211_scan_done(rdev, true);
754 } 787 }
755 788
756 cfg80211_unlock_rdev(rdev);
757
758 mutex_lock(&rdev->sched_scan_mtx);
759
760 if (WARN_ON(rdev->sched_scan_req && 789 if (WARN_ON(rdev->sched_scan_req &&
761 rdev->sched_scan_req->dev == wdev->netdev)) { 790 rdev->sched_scan_req->dev == wdev->netdev)) {
762 __cfg80211_stop_sched_scan(rdev, false); 791 __cfg80211_stop_sched_scan(rdev, false);
@@ -782,21 +811,19 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev)
782 return; 811 return;
783 812
784 mutex_lock(&rdev->devlist_mtx); 813 mutex_lock(&rdev->devlist_mtx);
814 mutex_lock(&rdev->sched_scan_mtx);
785 list_del_rcu(&wdev->list); 815 list_del_rcu(&wdev->list);
786 rdev->devlist_generation++; 816 rdev->devlist_generation++;
787 817
788 switch (wdev->iftype) { 818 switch (wdev->iftype) {
789 case NL80211_IFTYPE_P2P_DEVICE: 819 case NL80211_IFTYPE_P2P_DEVICE:
790 if (!wdev->p2p_started) 820 cfg80211_stop_p2p_device(rdev, wdev);
791 break;
792 rdev_stop_p2p_device(rdev, wdev);
793 wdev->p2p_started = false;
794 rdev->opencount--;
795 break; 821 break;
796 default: 822 default:
797 WARN_ON_ONCE(1); 823 WARN_ON_ONCE(1);
798 break; 824 break;
799 } 825 }
826 mutex_unlock(&rdev->sched_scan_mtx);
800 mutex_unlock(&rdev->devlist_mtx); 827 mutex_unlock(&rdev->devlist_mtx);
801} 828}
802EXPORT_SYMBOL(cfg80211_unregister_wdev); 829EXPORT_SYMBOL(cfg80211_unregister_wdev);
@@ -937,6 +964,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
937 cfg80211_update_iface_num(rdev, wdev->iftype, 1); 964 cfg80211_update_iface_num(rdev, wdev->iftype, 1);
938 cfg80211_lock_rdev(rdev); 965 cfg80211_lock_rdev(rdev);
939 mutex_lock(&rdev->devlist_mtx); 966 mutex_lock(&rdev->devlist_mtx);
967 mutex_lock(&rdev->sched_scan_mtx);
940 wdev_lock(wdev); 968 wdev_lock(wdev);
941 switch (wdev->iftype) { 969 switch (wdev->iftype) {
942#ifdef CONFIG_CFG80211_WEXT 970#ifdef CONFIG_CFG80211_WEXT
@@ -968,6 +996,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
968 break; 996 break;
969 } 997 }
970 wdev_unlock(wdev); 998 wdev_unlock(wdev);
999 mutex_unlock(&rdev->sched_scan_mtx);
971 rdev->opencount++; 1000 rdev->opencount++;
972 mutex_unlock(&rdev->devlist_mtx); 1001 mutex_unlock(&rdev->devlist_mtx);
973 cfg80211_unlock_rdev(rdev); 1002 cfg80211_unlock_rdev(rdev);