cfg80211: fix BSS double-unlinking (continued)
authorJuuso Oikarinen <juuso.oikarinen@nokia.com>
Mon, 28 Mar 2011 11:32:32 +0000 (14:32 +0300)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 28 Mar 2011 19:42:02 +0000 (15:42 -0400)
This patch adds to the fix "fix BSS double-unlinking"
(commit 3207390a8b58bfc1335750f91cf6783c48ca19ca) by Johannes Berg.

It turns out, that the double-unlinking scenario can also occur if expired
BSS elements are removed whilst an interface is performing association.

To work around that, replace list_del with list_del_init also in the
"cfg80211_bss_expire" function, so that the check for whether the BSS still is
in the list works correctly in cfg80211_unlink_bss.

Signed-off-by: Juuso Oikarinen <juuso.oikarinen@nokia.com>
Reviewed-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
net/wireless/scan.c

index 300c11d..fbf6f33 100644 (file)
@@ -124,6 +124,15 @@ void cfg80211_bss_age(struct cfg80211_registered_device *dev,
 }
 
 /* must hold dev->bss_lock! */
+static void __cfg80211_unlink_bss(struct cfg80211_registered_device *dev,
+                                 struct cfg80211_internal_bss *bss)
+{
+       list_del_init(&bss->list);
+       rb_erase(&bss->rbn, &dev->bss_tree);
+       kref_put(&bss->ref, bss_release);
+}
+
+/* must hold dev->bss_lock! */
 void cfg80211_bss_expire(struct cfg80211_registered_device *dev)
 {
        struct cfg80211_internal_bss *bss, *tmp;
@@ -134,9 +143,7 @@ void cfg80211_bss_expire(struct cfg80211_registered_device *dev)
                        continue;
                if (!time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE))
                        continue;
-               list_del(&bss->list);
-               rb_erase(&bss->rbn, &dev->bss_tree);
-               kref_put(&bss->ref, bss_release);
+               __cfg80211_unlink_bss(dev, bss);
                expired = true;
        }
 
@@ -669,11 +676,8 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
 
        spin_lock_bh(&dev->bss_lock);
        if (!list_empty(&bss->list)) {
-               list_del_init(&bss->list);
+               __cfg80211_unlink_bss(dev, bss);
                dev->bss_generation++;
-               rb_erase(&bss->rbn, &dev->bss_tree);
-
-               kref_put(&bss->ref, bss_release);
        }
        spin_unlock_bh(&dev->bss_lock);
 }