diff options
-rw-r--r-- | net/wireless/core.c | 4 | ||||
-rw-r--r-- | net/wireless/core.h | 2 | ||||
-rw-r--r-- | net/wireless/scan.c | 21 |
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); | |||
370 | void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); | 370 | void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); |
371 | void cfg80211_sme_disassoc(struct net_device *dev, int idx); | 371 | void cfg80211_sme_disassoc(struct net_device *dev, int idx); |
372 | void __cfg80211_scan_done(struct work_struct *wk); | 372 | void __cfg80211_scan_done(struct work_struct *wk); |
373 | void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev); | 373 | void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak); |
374 | void cfg80211_upload_connect_keys(struct wireless_dev *wdev); | 374 | void cfg80211_upload_connect_keys(struct wireless_dev *wdev); |
375 | 375 | ||
376 | struct ieee80211_channel * | 376 | struct 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 | ||
21 | void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev) | 21 | void ___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 | ||
59 | void __cfg80211_scan_done(struct work_struct *wk) | 74 | void __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 | ||