mac80211: don't start new netdev queues if driver stopped
authorJohannes Berg <johannes.berg@intel.com>
Tue, 26 Mar 2013 21:23:20 +0000 (22:23 +0100)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 8 Apr 2013 09:06:28 +0000 (11:06 +0200)
If a new netdev (e.g. an AP VLAN) is created while the driver
has queues stopped, the new netdev queues will be started even
though they shouldn't. This will lead to frames accumulating
on the internal mac80211 pending queues instead of properly
being held on the netdev queues.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/iface.c

index 63b63675aa6dbb79b91d2d0b7f4e4961be8ea4ba..b6abaaa3676f226bee037e306528851a22999692 100644 (file)
@@ -639,8 +639,28 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
 
        ieee80211_recalc_ps(local, -1);
 
-       if (dev)
-               netif_tx_start_all_queues(dev);
+       if (dev) {
+               unsigned long flags;
+               int n_acs = IEEE80211_NUM_ACS;
+               int ac;
+
+               if (local->hw.queues < IEEE80211_NUM_ACS)
+                       n_acs = 1;
+
+               spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+               if (sdata->vif.cab_queue == IEEE80211_INVAL_HW_QUEUE ||
+                   (local->queue_stop_reasons[sdata->vif.cab_queue] == 0 &&
+                    skb_queue_empty(&local->pending[sdata->vif.cab_queue]))) {
+                       for (ac = 0; ac < n_acs; ac++) {
+                               int ac_queue = sdata->vif.hw_queue[ac];
+
+                               if (local->queue_stop_reasons[ac_queue] == 0 &&
+                                   skb_queue_empty(&local->pending[ac_queue]))
+                                       netif_start_subqueue(dev, ac);
+                       }
+               }
+               spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+       }
 
        return 0;
  err_del_interface: