diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2009-08-12 22:21:21 +0200 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-08-14 09:14:07 -0400 |
commit | 36e6fea84905512ea776707e82b5b435220efc17 (patch) | |
tree | db588e7dbbfcf0fa47f4954344a03961e960c898 /net/wireless/core.c | |
parent | 70bdb6b275d789ddf05c3a858e6b57715539394b (diff) | |
download | blackbird-op-linux-36e6fea84905512ea776707e82b5b435220efc17.tar.gz blackbird-op-linux-36e6fea84905512ea776707e82b5b435220efc17.zip |
cfg80211: check for and abort dangling scan requests
If you trigger a scan request on an interface and then
take it down, or rmmod the module or unplug the device
the driver might "forget" to cancel the scan request.
That is a bug in the driver, but the current behaviour
is that we just hang endlessly waiting for the netdev
refcount to become 0 which it never will. To improve
robustness, check for this situation in cfg80211, warn
about it and clean up behind the driver. I don't just
clean up silently because it's likely that the driver
also has some internal state it has now leaked.
Additionally, this fixes a locking bug, clearing the
scan_req pointer should be done under the rdev lock.
Finally, we also need to _wait_ for the scan work and
not just abort it since it might be pending and wanting
to do a cleanup.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless/core.c')
-rw-r--r-- | net/wireless/core.c | 10 |
1 files changed, 9 insertions, 1 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c index e630648fef79..35d83bedfe5b 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -601,8 +601,8 @@ void wiphy_unregister(struct wiphy *wiphy) mutex_unlock(&cfg80211_mutex); + flush_work(&rdev->scan_done_wk); cancel_work_sync(&rdev->conn_work); - cancel_work_sync(&rdev->scan_done_wk); kfree(rdev->scan_req); flush_work(&rdev->event_work); } @@ -728,6 +728,13 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, #endif break; case NETDEV_UNREGISTER: + cfg80211_lock_rdev(rdev); + + if (WARN_ON(rdev->scan_req && rdev->scan_req->dev == dev)) { + rdev->scan_req->aborted = true; + ___cfg80211_scan_done(rdev); + } + mutex_lock(&rdev->devlist_mtx); /* * It is possible to get NETDEV_UNREGISTER @@ -746,6 +753,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, #endif } mutex_unlock(&rdev->devlist_mtx); + cfg80211_unlock_rdev(rdev); break; case NETDEV_PRE_UP: if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype))) |