if (WARN_ON(rdev->scan_req && rdev->scan_req->dev == wdev->netdev)) {
rdev->scan_req->aborted = true;
- ___cfg80211_scan_done(rdev);
+ ___cfg80211_scan_done(rdev, true);
}
cfg80211_unlock_rdev(rdev);
default:
break;
}
+ break;
+ case NETDEV_DOWN:
dev_hold(dev);
schedule_work(&wdev->cleanup_work);
break;
void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len);
void cfg80211_sme_disassoc(struct net_device *dev, int idx);
void __cfg80211_scan_done(struct work_struct *wk);
-void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev);
+void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak);
void cfg80211_upload_connect_keys(struct wireless_dev *wdev);
struct ieee80211_channel *
#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;
union iwreq_data wrqu;
#endif
+ ASSERT_RDEV_LOCK(rdev);
+
request = rdev->scan_req;
+ if (!request)
+ return;
+
dev = request->dev;
/*
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)
scan_done_wk);
cfg80211_lock_rdev(rdev);
- ___cfg80211_scan_done(rdev);
+ ___cfg80211_scan_done(rdev, false);
cfg80211_unlock_rdev(rdev);
}