]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - net/mac80211/main.c
mac80211: fix scan vs. interface removal race
[linux-2.6-omap-h63xx.git] / net / mac80211 / main.c
index ebdec7106d6365af4b25c16f3d7c591322e4fd73..4bfac4b41c51e4de008d33fd7b3bbed8270b1ae0 100644 (file)
@@ -564,14 +564,6 @@ static int ieee80211_stop(struct net_device *dev)
                synchronize_rcu();
                skb_queue_purge(&sdata->u.sta.skb_queue);
 
-               if (local->scan_sdata == sdata) {
-                       if (!local->ops->hw_scan) {
-                               local->sta_sw_scanning = 0;
-                               cancel_delayed_work(&local->scan_work);
-                       } else
-                               local->sta_hw_scanning = 0;
-               }
-
                sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED;
                kfree(sdata->u.sta.extra_ie);
                sdata->u.sta.extra_ie = NULL;
@@ -585,6 +577,31 @@ static int ieee80211_stop(struct net_device *dev)
                }
                /* fall through */
        default:
+               if (local->scan_sdata == sdata) {
+                       if (!local->ops->hw_scan)
+                               cancel_delayed_work_sync(&local->scan_work);
+                       /*
+                        * The software scan can no longer run now, so we can
+                        * clear out the scan_sdata reference. However, the
+                        * hardware scan may still be running. The complete
+                        * function must be prepared to handle a NULL value.
+                        */
+                       local->scan_sdata = NULL;
+                       /*
+                        * The memory barrier guarantees that another CPU
+                        * that is hardware-scanning will now see the fact
+                        * that this interface is gone.
+                        */
+                       smp_mb();
+                       /*
+                        * If software scanning, complete the scan but since
+                        * the scan_sdata is NULL already don't send out a
+                        * scan event to userspace -- the scan is incomplete.
+                        */
+                       if (local->sta_sw_scanning)
+                               ieee80211_scan_completed(&local->hw);
+               }
+
                conf.vif = &sdata->vif;
                conf.type = sdata->vif.type;
                conf.mac_addr = dev->dev_addr;