cfg80211: check lost scans later, fix bug
[safe/jmp/linux-2.6] / net / wireless / scan.c
index fe575a2..7043de6 100644 (file)
@@ -18,7 +18,7 @@
 
 #define IEEE80211_SCAN_RESULT_EXPIRE   (15 * HZ)
 
-void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev)
+void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
 {
        struct cfg80211_scan_request *request;
        struct net_device *dev;
@@ -26,8 +26,13 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev)
        union iwreq_data wrqu;
 #endif
 
+       ASSERT_RDEV_LOCK(rdev);
+
        request = rdev->scan_req;
 
+       if (!request)
+               return;
+
        dev = request->dev;
 
        /*
@@ -53,7 +58,17 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev)
        dev_put(dev);
 
        rdev->scan_req = NULL;
-       kfree(request);
+
+       /*
+        * OK. If this is invoked with "leak" then we can't
+        * free this ... but we've cleaned it up anyway. The
+        * driver failed to call the scan_done callback, so
+        * all bets are off, it might still be trying to use
+        * the scan request or not ... if it accesses the dev
+        * in there (it shouldn't anyway) then it may crash.
+        */
+       if (!leak)
+               kfree(request);
 }
 
 void __cfg80211_scan_done(struct work_struct *wk)
@@ -64,7 +79,7 @@ void __cfg80211_scan_done(struct work_struct *wk)
                            scan_done_wk);
 
        cfg80211_lock_rdev(rdev);
-       ___cfg80211_scan_done(rdev);
+       ___cfg80211_scan_done(rdev, false);
        cfg80211_unlock_rdev(rdev);
 }