aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/wireless/core.c4
-rw-r--r--net/wireless/core.h2
-rw-r--r--net/wireless/scan.c21
3 files changed, 22 insertions, 5 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 154e1e294cb9..9b157caa74fd 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -664,7 +664,7 @@ static void wdev_cleanup_work(struct work_struct *work)
664 664
665 if (WARN_ON(rdev->scan_req && rdev->scan_req->dev == wdev->netdev)) { 665 if (WARN_ON(rdev->scan_req && rdev->scan_req->dev == wdev->netdev)) {
666 rdev->scan_req->aborted = true; 666 rdev->scan_req->aborted = true;
667 ___cfg80211_scan_done(rdev); 667 ___cfg80211_scan_done(rdev, true);
668 } 668 }
669 669
670 cfg80211_unlock_rdev(rdev); 670 cfg80211_unlock_rdev(rdev);
@@ -755,6 +755,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
755 default: 755 default:
756 break; 756 break;
757 } 757 }
758 break;
759 case NETDEV_DOWN:
758 dev_hold(dev); 760 dev_hold(dev);
759 schedule_work(&wdev->cleanup_work); 761 schedule_work(&wdev->cleanup_work);
760 break; 762 break;
diff --git a/net/wireless/core.h b/net/wireless/core.h
index f565432ae22f..68eaf340d613 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -370,7 +370,7 @@ void cfg80211_sme_scan_done(struct net_device *dev);
370void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); 370void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len);
371void cfg80211_sme_disassoc(struct net_device *dev, int idx); 371void cfg80211_sme_disassoc(struct net_device *dev, int idx);
372void __cfg80211_scan_done(struct work_struct *wk); 372void __cfg80211_scan_done(struct work_struct *wk);
373void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev); 373void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak);
374void cfg80211_upload_connect_keys(struct wireless_dev *wdev); 374void cfg80211_upload_connect_keys(struct wireless_dev *wdev);
375 375
376struct ieee80211_channel * 376struct ieee80211_channel *
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index fe575a24c95c..7043de6221ab 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -18,7 +18,7 @@
18 18
19#define IEEE80211_SCAN_RESULT_EXPIRE (15 * HZ) 19#define IEEE80211_SCAN_RESULT_EXPIRE (15 * HZ)
20 20
21void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev) 21void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
22{ 22{
23 struct cfg80211_scan_request *request; 23 struct cfg80211_scan_request *request;
24 struct net_device *dev; 24 struct net_device *dev;
@@ -26,8 +26,13 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev)
26 union iwreq_data wrqu; 26 union iwreq_data wrqu;
27#endif 27#endif
28 28
29 ASSERT_RDEV_LOCK(rdev);
30
29 request = rdev->scan_req; 31 request = rdev->scan_req;
30 32
33 if (!request)
34 return;
35
31 dev = request->dev; 36 dev = request->dev;
32 37
33 /* 38 /*
@@ -53,7 +58,17 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev)
53 dev_put(dev); 58 dev_put(dev);
54 59
55 rdev->scan_req = NULL; 60 rdev->scan_req = NULL;
56 kfree(request); 61
62 /*
63 * OK. If this is invoked with "leak" then we can't
64 * free this ... but we've cleaned it up anyway. The
65 * driver failed to call the scan_done callback, so
66 * all bets are off, it might still be trying to use
67 * the scan request or not ... if it accesses the dev
68 * in there (it shouldn't anyway) then it may crash.
69 */
70 if (!leak)
71 kfree(request);
57} 72}
58 73
59void __cfg80211_scan_done(struct work_struct *wk) 74void __cfg80211_scan_done(struct work_struct *wk)
@@ -64,7 +79,7 @@ void __cfg80211_scan_done(struct work_struct *wk)
64 scan_done_wk); 79 scan_done_wk);
65 80
66 cfg80211_lock_rdev(rdev); 81 cfg80211_lock_rdev(rdev);
67 ___cfg80211_scan_done(rdev); 82 ___cfg80211_scan_done(rdev, false);
68 cfg80211_unlock_rdev(rdev); 83 cfg80211_unlock_rdev(rdev);
69} 84}
70 85