diff options
author | Johannes Berg <johannes.berg@intel.com> | 2013-03-19 10:04:07 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-03-24 06:15:58 -0400 |
commit | f9f475292dbb0e7035fb6661d1524761ea0888d9 (patch) | |
tree | 77f4bf7741deb74108ef033eeb68131069a8e406 /net/wireless/scan.c | |
parent | 8b305780ed0c49a49c6bd58a4372fd6b22a5a71e (diff) |
cfg80211: always check for scan end on P2P device
If a P2P device wdev is removed while it has a scan, then the
scan completion might crash later as it is already freed by
that time. To avoid the crash always check the scan completion
when the P2P device is being removed for some reason. If the
driver already canceled it, don't want and free it, otherwise
warn and leak it to avoid later crashes.
In order to do this, locking needs to be changed away from the
rdev mutex (which can't always be guaranteed). For now, use
the sched_scan_mtx instead, I'll rename it to just scan_mtx in
a later patch.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/wireless/scan.c')
-rw-r--r-- | net/wireless/scan.c | 8 |
1 files changed, 5 insertions, 3 deletions
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 | ||
238 | void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) | 238 | void 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; |