summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-03-26 22:23:20 +0100
committerJohannes Berg <johannes.berg@intel.com>2013-04-08 11:06:28 +0200
commit2b730daacee6c318bce7b6373c19909e36a74590 (patch)
tree9fd2b28079afae8672cd5bfb695e74abdba0cddf
parentmac80211: replace some dead code by a warning (diff)
downloadlinux-2b730daacee6c318bce7b6373c19909e36a74590.tar.xz
linux-2b730daacee6c318bce7b6373c19909e36a74590.zip
mac80211: don't start new netdev queues if driver stopped
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>
-rw-r--r--net/mac80211/iface.c24
1 files changed, 22 insertions, 2 deletions
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 63b63675aa6d..b6abaaa3676f 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -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: