aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/wireless/core.c64
-rw-r--r--net/wireless/core.h3
-rw-r--r--net/wireless/nl80211.c52
-rw-r--r--net/wireless/scan.c8
-rw-r--r--net/wireless/sme.c6
-rw-r--r--net/wireless/wext-sme.c6
6 files changed, 92 insertions, 47 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 922002105062..11743d48cbc2 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;
@@ -745,17 +779,13 @@ static void wdev_cleanup_work(struct work_struct *work)
745 wdev = container_of(work, struct wireless_dev, cleanup_work); 779 wdev = container_of(work, struct wireless_dev, cleanup_work);
746 rdev = wiphy_to_dev(wdev->wiphy); 780 rdev = wiphy_to_dev(wdev->wiphy);
747 781
748 cfg80211_lock_rdev(rdev); 782 mutex_lock(&rdev->sched_scan_mtx);
749 783
750 if (WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev)) { 784 if (WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev)) {
751 rdev->scan_req->aborted = true; 785 rdev->scan_req->aborted = true;
752 ___cfg80211_scan_done(rdev, true); 786 ___cfg80211_scan_done(rdev, true);
753 } 787 }
754 788
755 cfg80211_unlock_rdev(rdev);
756
757 mutex_lock(&rdev->sched_scan_mtx);
758
759 if (WARN_ON(rdev->sched_scan_req && 789 if (WARN_ON(rdev->sched_scan_req &&
760 rdev->sched_scan_req->dev == wdev->netdev)) { 790 rdev->sched_scan_req->dev == wdev->netdev)) {
761 __cfg80211_stop_sched_scan(rdev, false); 791 __cfg80211_stop_sched_scan(rdev, false);
@@ -781,21 +811,19 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev)
781 return; 811 return;
782 812
783 mutex_lock(&rdev->devlist_mtx); 813 mutex_lock(&rdev->devlist_mtx);
814 mutex_lock(&rdev->sched_scan_mtx);
784 list_del_rcu(&wdev->list); 815 list_del_rcu(&wdev->list);
785 rdev->devlist_generation++; 816 rdev->devlist_generation++;
786 817
787 switch (wdev->iftype) { 818 switch (wdev->iftype) {
788 case NL80211_IFTYPE_P2P_DEVICE: 819 case NL80211_IFTYPE_P2P_DEVICE:
789 if (!wdev->p2p_started) 820 cfg80211_stop_p2p_device(rdev, wdev);
790 break;
791 rdev_stop_p2p_device(rdev, wdev);
792 wdev->p2p_started = false;
793 rdev->opencount--;
794 break; 821 break;
795 default: 822 default:
796 WARN_ON_ONCE(1); 823 WARN_ON_ONCE(1);
797 break; 824 break;
798 } 825 }
826 mutex_unlock(&rdev->sched_scan_mtx);
799 mutex_unlock(&rdev->devlist_mtx); 827 mutex_unlock(&rdev->devlist_mtx);
800} 828}
801EXPORT_SYMBOL(cfg80211_unregister_wdev); 829EXPORT_SYMBOL(cfg80211_unregister_wdev);
@@ -937,6 +965,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
937 cfg80211_update_iface_num(rdev, wdev->iftype, 1); 965 cfg80211_update_iface_num(rdev, wdev->iftype, 1);
938 cfg80211_lock_rdev(rdev); 966 cfg80211_lock_rdev(rdev);
939 mutex_lock(&rdev->devlist_mtx); 967 mutex_lock(&rdev->devlist_mtx);
968 mutex_lock(&rdev->sched_scan_mtx);
940 wdev_lock(wdev); 969 wdev_lock(wdev);
941 switch (wdev->iftype) { 970 switch (wdev->iftype) {
942#ifdef CONFIG_CFG80211_WEXT 971#ifdef CONFIG_CFG80211_WEXT
@@ -968,6 +997,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
968 break; 997 break;
969 } 998 }
970 wdev_unlock(wdev); 999 wdev_unlock(wdev);
1000 mutex_unlock(&rdev->sched_scan_mtx);
971 rdev->opencount++; 1001 rdev->opencount++;
972 mutex_unlock(&rdev->devlist_mtx); 1002 mutex_unlock(&rdev->devlist_mtx);
973 cfg80211_unlock_rdev(rdev); 1003 cfg80211_unlock_rdev(rdev);
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 3aec0e429d8a..5845c2b37aa8 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -503,6 +503,9 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
503void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, 503void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
504 enum nl80211_iftype iftype, int num); 504 enum nl80211_iftype iftype, int num);
505 505
506void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev,
507 struct wireless_dev *wdev);
508
506#define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10 509#define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10
507 510
508#ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS 511#ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index d44ab216c0ec..58e13a8c95f9 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -4702,14 +4702,19 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
4702 if (!rdev->ops->scan) 4702 if (!rdev->ops->scan)
4703 return -EOPNOTSUPP; 4703 return -EOPNOTSUPP;
4704 4704
4705 if (rdev->scan_req) 4705 mutex_lock(&rdev->sched_scan_mtx);
4706 return -EBUSY; 4706 if (rdev->scan_req) {
4707 err = -EBUSY;
4708 goto unlock;
4709 }
4707 4710
4708 if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { 4711 if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
4709 n_channels = validate_scan_freqs( 4712 n_channels = validate_scan_freqs(
4710 info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]); 4713 info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
4711 if (!n_channels) 4714 if (!n_channels) {
4712 return -EINVAL; 4715 err = -EINVAL;
4716 goto unlock;
4717 }
4713 } else { 4718 } else {
4714 enum ieee80211_band band; 4719 enum ieee80211_band band;
4715 n_channels = 0; 4720 n_channels = 0;
@@ -4723,23 +4728,29 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
4723 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) 4728 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp)
4724 n_ssids++; 4729 n_ssids++;
4725 4730
4726 if (n_ssids > wiphy->max_scan_ssids) 4731 if (n_ssids > wiphy->max_scan_ssids) {
4727 return -EINVAL; 4732 err = -EINVAL;
4733 goto unlock;
4734 }
4728 4735
4729 if (info->attrs[NL80211_ATTR_IE]) 4736 if (info->attrs[NL80211_ATTR_IE])
4730 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); 4737 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
4731 else 4738 else
4732 ie_len = 0; 4739 ie_len = 0;
4733 4740
4734 if (ie_len > wiphy->max_scan_ie_len) 4741 if (ie_len > wiphy->max_scan_ie_len) {
4735 return -EINVAL; 4742 err = -EINVAL;
4743 goto unlock;
4744 }
4736 4745
4737 request = kzalloc(sizeof(*request) 4746 request = kzalloc(sizeof(*request)
4738 + sizeof(*request->ssids) * n_ssids 4747 + sizeof(*request->ssids) * n_ssids
4739 + sizeof(*request->channels) * n_channels 4748 + sizeof(*request->channels) * n_channels
4740 + ie_len, GFP_KERNEL); 4749 + ie_len, GFP_KERNEL);
4741 if (!request) 4750 if (!request) {
4742 return -ENOMEM; 4751 err = -ENOMEM;
4752 goto unlock;
4753 }
4743 4754
4744 if (n_ssids) 4755 if (n_ssids)
4745 request->ssids = (void *)&request->channels[n_channels]; 4756 request->ssids = (void *)&request->channels[n_channels];
@@ -4876,6 +4887,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
4876 kfree(request); 4887 kfree(request);
4877 } 4888 }
4878 4889
4890 unlock:
4891 mutex_unlock(&rdev->sched_scan_mtx);
4879 return err; 4892 return err;
4880} 4893}
4881 4894
@@ -7749,20 +7762,9 @@ static int nl80211_stop_p2p_device(struct sk_buff *skb, struct genl_info *info)
7749 if (!rdev->ops->stop_p2p_device) 7762 if (!rdev->ops->stop_p2p_device)
7750 return -EOPNOTSUPP; 7763 return -EOPNOTSUPP;
7751 7764
7752 if (!wdev->p2p_started) 7765 mutex_lock(&rdev->sched_scan_mtx);
7753 return 0; 7766 cfg80211_stop_p2p_device(rdev, wdev);
7754 7767 mutex_unlock(&rdev->sched_scan_mtx);
7755 rdev_stop_p2p_device(rdev, wdev);
7756 wdev->p2p_started = false;
7757
7758 mutex_lock(&rdev->devlist_mtx);
7759 rdev->opencount--;
7760 mutex_unlock(&rdev->devlist_mtx);
7761
7762 if (WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev)) {
7763 rdev->scan_req->aborted = true;
7764 ___cfg80211_scan_done(rdev, true);
7765 }
7766 7768
7767 return 0; 7769 return 0;
7768} 7770}
@@ -8486,7 +8488,7 @@ static int nl80211_add_scan_req(struct sk_buff *msg,
8486 struct nlattr *nest; 8488 struct nlattr *nest;
8487 int i; 8489 int i;
8488 8490
8489 ASSERT_RDEV_LOCK(rdev); 8491 lockdep_assert_held(&rdev->sched_scan_mtx);
8490 8492
8491 if (WARN_ON(!req)) 8493 if (WARN_ON(!req))
8492 return 0; 8494 return 0;
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index e93bd31d23bb..fd99ea495b7e 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -169,7 +169,7 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
169 union iwreq_data wrqu; 169 union iwreq_data wrqu;
170#endif 170#endif
171 171
172 ASSERT_RDEV_LOCK(rdev); 172 lockdep_assert_held(&rdev->sched_scan_mtx);
173 173
174 request = rdev->scan_req; 174 request = rdev->scan_req;
175 175
@@ -230,9 +230,9 @@ void __cfg80211_scan_done(struct work_struct *wk)
230 rdev = container_of(wk, struct cfg80211_registered_device, 230 rdev = container_of(wk, struct cfg80211_registered_device,
231 scan_done_wk); 231 scan_done_wk);
232 232
233 cfg80211_lock_rdev(rdev); 233 mutex_lock(&rdev->sched_scan_mtx);
234 ___cfg80211_scan_done(rdev, false); 234 ___cfg80211_scan_done(rdev, false);
235 cfg80211_unlock_rdev(rdev); 235 mutex_unlock(&rdev->sched_scan_mtx);
236} 236}
237 237
238void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) 238void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
@@ -1062,6 +1062,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,
1062 if (IS_ERR(rdev)) 1062 if (IS_ERR(rdev))
1063 return PTR_ERR(rdev); 1063 return PTR_ERR(rdev);
1064 1064
1065 mutex_lock(&rdev->sched_scan_mtx);
1065 if (rdev->scan_req) { 1066 if (rdev->scan_req) {
1066 err = -EBUSY; 1067 err = -EBUSY;
1067 goto out; 1068 goto out;
@@ -1168,6 +1169,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,
1168 dev_hold(dev); 1169 dev_hold(dev);
1169 } 1170 }
1170 out: 1171 out:
1172 mutex_unlock(&rdev->sched_scan_mtx);
1171 kfree(creq); 1173 kfree(creq);
1172 cfg80211_unlock_rdev(rdev); 1174 cfg80211_unlock_rdev(rdev);
1173 return err; 1175 return err;
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index f432bd3755b1..09d994d192ff 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -85,6 +85,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
85 ASSERT_RTNL(); 85 ASSERT_RTNL();
86 ASSERT_RDEV_LOCK(rdev); 86 ASSERT_RDEV_LOCK(rdev);
87 ASSERT_WDEV_LOCK(wdev); 87 ASSERT_WDEV_LOCK(wdev);
88 lockdep_assert_held(&rdev->sched_scan_mtx);
88 89
89 if (rdev->scan_req) 90 if (rdev->scan_req)
90 return -EBUSY; 91 return -EBUSY;
@@ -320,11 +321,9 @@ void cfg80211_sme_scan_done(struct net_device *dev)
320{ 321{
321 struct wireless_dev *wdev = dev->ieee80211_ptr; 322 struct wireless_dev *wdev = dev->ieee80211_ptr;
322 323
323 mutex_lock(&wiphy_to_dev(wdev->wiphy)->devlist_mtx);
324 wdev_lock(wdev); 324 wdev_lock(wdev);
325 __cfg80211_sme_scan_done(dev); 325 __cfg80211_sme_scan_done(dev);
326 wdev_unlock(wdev); 326 wdev_unlock(wdev);
327 mutex_unlock(&wiphy_to_dev(wdev->wiphy)->devlist_mtx);
328} 327}
329 328
330void cfg80211_sme_rx_auth(struct net_device *dev, 329void cfg80211_sme_rx_auth(struct net_device *dev,
@@ -924,9 +923,12 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
924 int err; 923 int err;
925 924
926 mutex_lock(&rdev->devlist_mtx); 925 mutex_lock(&rdev->devlist_mtx);
926 /* might request scan - scan_mtx -> wdev_mtx dependency */
927 mutex_lock(&rdev->sched_scan_mtx);
927 wdev_lock(dev->ieee80211_ptr); 928 wdev_lock(dev->ieee80211_ptr);
928 err = __cfg80211_connect(rdev, dev, connect, connkeys, NULL); 929 err = __cfg80211_connect(rdev, dev, connect, connkeys, NULL);
929 wdev_unlock(dev->ieee80211_ptr); 930 wdev_unlock(dev->ieee80211_ptr);
931 mutex_unlock(&rdev->sched_scan_mtx);
930 mutex_unlock(&rdev->devlist_mtx); 932 mutex_unlock(&rdev->devlist_mtx);
931 933
932 return err; 934 return err;
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c
index fb9622f6d99c..e79cb5c0655a 100644
--- a/net/wireless/wext-sme.c
+++ b/net/wireless/wext-sme.c
@@ -89,6 +89,7 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
89 89
90 cfg80211_lock_rdev(rdev); 90 cfg80211_lock_rdev(rdev);
91 mutex_lock(&rdev->devlist_mtx); 91 mutex_lock(&rdev->devlist_mtx);
92 mutex_lock(&rdev->sched_scan_mtx);
92 wdev_lock(wdev); 93 wdev_lock(wdev);
93 94
94 if (wdev->sme_state != CFG80211_SME_IDLE) { 95 if (wdev->sme_state != CFG80211_SME_IDLE) {
@@ -135,6 +136,7 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
135 err = cfg80211_mgd_wext_connect(rdev, wdev); 136 err = cfg80211_mgd_wext_connect(rdev, wdev);
136 out: 137 out:
137 wdev_unlock(wdev); 138 wdev_unlock(wdev);
139 mutex_unlock(&rdev->sched_scan_mtx);
138 mutex_unlock(&rdev->devlist_mtx); 140 mutex_unlock(&rdev->devlist_mtx);
139 cfg80211_unlock_rdev(rdev); 141 cfg80211_unlock_rdev(rdev);
140 return err; 142 return err;
@@ -190,6 +192,7 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,
190 192
191 cfg80211_lock_rdev(rdev); 193 cfg80211_lock_rdev(rdev);
192 mutex_lock(&rdev->devlist_mtx); 194 mutex_lock(&rdev->devlist_mtx);
195 mutex_lock(&rdev->sched_scan_mtx);
193 wdev_lock(wdev); 196 wdev_lock(wdev);
194 197
195 err = 0; 198 err = 0;
@@ -223,6 +226,7 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,
223 err = cfg80211_mgd_wext_connect(rdev, wdev); 226 err = cfg80211_mgd_wext_connect(rdev, wdev);
224 out: 227 out:
225 wdev_unlock(wdev); 228 wdev_unlock(wdev);
229 mutex_unlock(&rdev->sched_scan_mtx);
226 mutex_unlock(&rdev->devlist_mtx); 230 mutex_unlock(&rdev->devlist_mtx);
227 cfg80211_unlock_rdev(rdev); 231 cfg80211_unlock_rdev(rdev);
228 return err; 232 return err;
@@ -285,6 +289,7 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev,
285 289
286 cfg80211_lock_rdev(rdev); 290 cfg80211_lock_rdev(rdev);
287 mutex_lock(&rdev->devlist_mtx); 291 mutex_lock(&rdev->devlist_mtx);
292 mutex_lock(&rdev->sched_scan_mtx);
288 wdev_lock(wdev); 293 wdev_lock(wdev);
289 294
290 if (wdev->sme_state != CFG80211_SME_IDLE) { 295 if (wdev->sme_state != CFG80211_SME_IDLE) {
@@ -313,6 +318,7 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev,
313 err = cfg80211_mgd_wext_connect(rdev, wdev); 318 err = cfg80211_mgd_wext_connect(rdev, wdev);
314 out: 319 out:
315 wdev_unlock(wdev); 320 wdev_unlock(wdev);
321 mutex_unlock(&rdev->sched_scan_mtx);
316 mutex_unlock(&rdev->devlist_mtx); 322 mutex_unlock(&rdev->devlist_mtx);
317 cfg80211_unlock_rdev(rdev); 323 cfg80211_unlock_rdev(rdev);
318 return err; 324 return err;