aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
authorJukka Rissanen <jukka.rissanen@linux.intel.com>2014-12-15 06:25:38 -0500
committerJohannes Berg <johannes.berg@intel.com>2014-12-18 08:38:09 -0500
commit31a60ed1e95ab8afbadb65599bef12b195080a0c (patch)
tree0be2e75a0554a2c1e1c01c6708af80c7388b6e74 /net/wireless
parent0f8b82456178d558f14011e06ebf9af937c4b197 (diff)
nl80211: Convert sched_scan_req pointer to RCU pointer
Because of possible races when accessing sched_scan_req pointer in rdev, the sched_scan_req is converted to RCU pointer. Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/core.c10
-rw-r--r--net/wireless/core.h2
-rw-r--r--net/wireless/nl80211.c19
-rw-r--r--net/wireless/scan.c13
4 files changed, 27 insertions, 17 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c
index b661fcce7e3c..0743449405ca 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -867,6 +867,7 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev,
867 struct wireless_dev *wdev) 867 struct wireless_dev *wdev)
868{ 868{
869 struct net_device *dev = wdev->netdev; 869 struct net_device *dev = wdev->netdev;
870 struct cfg80211_sched_scan_request *sched_scan_req;
870 871
871 ASSERT_RTNL(); 872 ASSERT_RTNL();
872 ASSERT_WDEV_LOCK(wdev); 873 ASSERT_WDEV_LOCK(wdev);
@@ -877,7 +878,8 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev,
877 break; 878 break;
878 case NL80211_IFTYPE_P2P_CLIENT: 879 case NL80211_IFTYPE_P2P_CLIENT:
879 case NL80211_IFTYPE_STATION: 880 case NL80211_IFTYPE_STATION:
880 if (rdev->sched_scan_req && dev == rdev->sched_scan_req->dev) 881 sched_scan_req = rtnl_dereference(rdev->sched_scan_req);
882 if (sched_scan_req && dev == sched_scan_req->dev)
881 __cfg80211_stop_sched_scan(rdev, false); 883 __cfg80211_stop_sched_scan(rdev, false);
882 884
883#ifdef CONFIG_CFG80211_WEXT 885#ifdef CONFIG_CFG80211_WEXT
@@ -956,6 +958,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
956 struct net_device *dev = netdev_notifier_info_to_dev(ptr); 958 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
957 struct wireless_dev *wdev = dev->ieee80211_ptr; 959 struct wireless_dev *wdev = dev->ieee80211_ptr;
958 struct cfg80211_registered_device *rdev; 960 struct cfg80211_registered_device *rdev;
961 struct cfg80211_sched_scan_request *sched_scan_req;
959 962
960 if (!wdev) 963 if (!wdev)
961 return NOTIFY_DONE; 964 return NOTIFY_DONE;
@@ -1021,8 +1024,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
1021 ___cfg80211_scan_done(rdev, false); 1024 ___cfg80211_scan_done(rdev, false);
1022 } 1025 }
1023 1026
1024 if (WARN_ON(rdev->sched_scan_req && 1027 sched_scan_req = rtnl_dereference(rdev->sched_scan_req);
1025 rdev->sched_scan_req->dev == wdev->netdev)) { 1028 if (WARN_ON(sched_scan_req &&
1029 sched_scan_req->dev == wdev->netdev)) {
1026 __cfg80211_stop_sched_scan(rdev, false); 1030 __cfg80211_stop_sched_scan(rdev, false);
1027 } 1031 }
1028 1032
diff --git a/net/wireless/core.h b/net/wireless/core.h
index e87cae57a83b..e82030c32311 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -70,7 +70,7 @@ struct cfg80211_registered_device {
70 u32 bss_generation; 70 u32 bss_generation;
71 struct cfg80211_scan_request *scan_req; /* protected by RTNL */ 71 struct cfg80211_scan_request *scan_req; /* protected by RTNL */
72 struct sk_buff *scan_msg; 72 struct sk_buff *scan_msg;
73 struct cfg80211_sched_scan_request *sched_scan_req; 73 struct cfg80211_sched_scan_request __rcu *sched_scan_req;
74 unsigned long suspend_at; 74 unsigned long suspend_at;
75 struct work_struct scan_done_wk; 75 struct work_struct scan_done_wk;
76 struct work_struct sched_scan_results_wk; 76 struct work_struct sched_scan_results_wk;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 5b1907f4c181..bacdf22fa472 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -6190,6 +6190,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
6190 struct cfg80211_registered_device *rdev = info->user_ptr[0]; 6190 struct cfg80211_registered_device *rdev = info->user_ptr[0];
6191 struct net_device *dev = info->user_ptr[1]; 6191 struct net_device *dev = info->user_ptr[1];
6192 struct wireless_dev *wdev = dev->ieee80211_ptr; 6192 struct wireless_dev *wdev = dev->ieee80211_ptr;
6193 struct cfg80211_sched_scan_request *sched_scan_req;
6193 int err; 6194 int err;
6194 6195
6195 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || 6196 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
@@ -6199,27 +6200,29 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
6199 if (rdev->sched_scan_req) 6200 if (rdev->sched_scan_req)
6200 return -EINPROGRESS; 6201 return -EINPROGRESS;
6201 6202
6202 rdev->sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy, wdev, 6203 sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy, wdev,
6203 info->attrs); 6204 info->attrs);
6204 err = PTR_ERR_OR_ZERO(rdev->sched_scan_req); 6205
6206 err = PTR_ERR_OR_ZERO(sched_scan_req);
6205 if (err) 6207 if (err)
6206 goto out_err; 6208 goto out_err;
6207 6209
6208 err = rdev_sched_scan_start(rdev, dev, rdev->sched_scan_req); 6210 err = rdev_sched_scan_start(rdev, dev, sched_scan_req);
6209 if (err) 6211 if (err)
6210 goto out_free; 6212 goto out_free;
6211 6213
6212 rdev->sched_scan_req->dev = dev; 6214 sched_scan_req->dev = dev;
6213 rdev->sched_scan_req->wiphy = &rdev->wiphy; 6215 sched_scan_req->wiphy = &rdev->wiphy;
6216
6217 rcu_assign_pointer(rdev->sched_scan_req, sched_scan_req);
6214 6218
6215 nl80211_send_sched_scan(rdev, dev, 6219 nl80211_send_sched_scan(rdev, dev,
6216 NL80211_CMD_START_SCHED_SCAN); 6220 NL80211_CMD_START_SCHED_SCAN);
6217 return 0; 6221 return 0;
6218 6222
6219out_free: 6223out_free:
6220 kfree(rdev->sched_scan_req); 6224 kfree(sched_scan_req);
6221out_err: 6225out_err:
6222 rdev->sched_scan_req = NULL;
6223 return err; 6226 return err;
6224} 6227}
6225 6228
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index bda39f149810..c705c3e2b751 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -257,7 +257,7 @@ void __cfg80211_sched_scan_results(struct work_struct *wk)
257 257
258 rtnl_lock(); 258 rtnl_lock();
259 259
260 request = rdev->sched_scan_req; 260 request = rtnl_dereference(rdev->sched_scan_req);
261 261
262 /* we don't have sched_scan_req anymore if the scan is stopping */ 262 /* we don't have sched_scan_req anymore if the scan is stopping */
263 if (request) { 263 if (request) {
@@ -279,7 +279,8 @@ void cfg80211_sched_scan_results(struct wiphy *wiphy)
279{ 279{
280 trace_cfg80211_sched_scan_results(wiphy); 280 trace_cfg80211_sched_scan_results(wiphy);
281 /* ignore if we're not scanning */ 281 /* ignore if we're not scanning */
282 if (wiphy_to_rdev(wiphy)->sched_scan_req) 282
283 if (rcu_access_pointer(wiphy_to_rdev(wiphy)->sched_scan_req))
283 queue_work(cfg80211_wq, 284 queue_work(cfg80211_wq,
284 &wiphy_to_rdev(wiphy)->sched_scan_results_wk); 285 &wiphy_to_rdev(wiphy)->sched_scan_results_wk);
285} 286}
@@ -308,6 +309,7 @@ EXPORT_SYMBOL(cfg80211_sched_scan_stopped);
308int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, 309int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
309 bool driver_initiated) 310 bool driver_initiated)
310{ 311{
312 struct cfg80211_sched_scan_request *sched_scan_req;
311 struct net_device *dev; 313 struct net_device *dev;
312 314
313 ASSERT_RTNL(); 315 ASSERT_RTNL();
@@ -315,7 +317,8 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
315 if (!rdev->sched_scan_req) 317 if (!rdev->sched_scan_req)
316 return -ENOENT; 318 return -ENOENT;
317 319
318 dev = rdev->sched_scan_req->dev; 320 sched_scan_req = rtnl_dereference(rdev->sched_scan_req);
321 dev = sched_scan_req->dev;
319 322
320 if (!driver_initiated) { 323 if (!driver_initiated) {
321 int err = rdev_sched_scan_stop(rdev, dev); 324 int err = rdev_sched_scan_stop(rdev, dev);
@@ -325,8 +328,8 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
325 328
326 nl80211_send_sched_scan(rdev, dev, NL80211_CMD_SCHED_SCAN_STOPPED); 329 nl80211_send_sched_scan(rdev, dev, NL80211_CMD_SCHED_SCAN_STOPPED);
327 330
328 kfree(rdev->sched_scan_req); 331 RCU_INIT_POINTER(rdev->sched_scan_req, NULL);
329 rdev->sched_scan_req = NULL; 332 kfree_rcu(sched_scan_req, rcu_head);
330 333
331 return 0; 334 return 0;
332} 335}