diff options
author | Johannes Berg <johannes.berg@intel.com> | 2013-03-26 22:23:20 +0100 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-04-08 11:06:28 +0200 |
commit | 2b730daacee6c318bce7b6373c19909e36a74590 (patch) | |
tree | 9fd2b28079afae8672cd5bfb695e74abdba0cddf | |
parent | a23108248a9d41400e686becddb5584b3a3fec1e (diff) | |
download | op-kernel-dev-2b730daacee6c318bce7b6373c19909e36a74590.zip op-kernel-dev-2b730daacee6c318bce7b6373c19909e36a74590.tar.gz |
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.c | 24 |
1 files changed, 22 insertions, 2 deletions
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 63b6367..b6abaaa 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: |