diff options
author | Johannes Berg <johannes.berg@intel.com> | 2012-07-04 06:49:59 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2012-07-06 09:26:58 -0400 |
commit | a6f38ac3cc853189705006cc1e0f17ce8467a1df (patch) | |
tree | 82184dc3a42ecc6849457d10423dd6676cb09b77 /net/mac80211/util.c | |
parent | c62094889f7bb0b3343d5404c9d139d2fb1712bb (diff) |
mac80211: fix crash with single-queue drivers
Larry (and some others I think) reported that with
single-queue drivers mac80211 crashes when waking
the queues. This happens because we allocate just
a single queue for each virtual interface in case
the driver doesn't have at least 4 queues, but the
code stopping/waking the virtual interface queues
wasn't taking this into account.
Reported-by: Larry Finger <Larry.Finger@lwfinger.net>
Tested-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/util.c')
-rw-r--r-- | net/mac80211/util.c | 12 |
1 files changed, 10 insertions, 2 deletions
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 5715e7b3affc..64493a7bef1a 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -268,6 +268,10 @@ EXPORT_SYMBOL(ieee80211_ctstoself_duration); | |||
268 | void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue) | 268 | void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue) |
269 | { | 269 | { |
270 | struct ieee80211_sub_if_data *sdata; | 270 | struct ieee80211_sub_if_data *sdata; |
271 | int n_acs = IEEE80211_NUM_ACS; | ||
272 | |||
273 | if (local->hw.queues < IEEE80211_NUM_ACS) | ||
274 | n_acs = 1; | ||
271 | 275 | ||
272 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | 276 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
273 | int ac; | 277 | int ac; |
@@ -279,7 +283,7 @@ void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue) | |||
279 | local->queue_stop_reasons[sdata->vif.cab_queue] != 0) | 283 | local->queue_stop_reasons[sdata->vif.cab_queue] != 0) |
280 | continue; | 284 | continue; |
281 | 285 | ||
282 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | 286 | for (ac = 0; ac < n_acs; ac++) { |
283 | int ac_queue = sdata->vif.hw_queue[ac]; | 287 | int ac_queue = sdata->vif.hw_queue[ac]; |
284 | 288 | ||
285 | if (ac_queue == queue || | 289 | if (ac_queue == queue || |
@@ -341,6 +345,7 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, | |||
341 | { | 345 | { |
342 | struct ieee80211_local *local = hw_to_local(hw); | 346 | struct ieee80211_local *local = hw_to_local(hw); |
343 | struct ieee80211_sub_if_data *sdata; | 347 | struct ieee80211_sub_if_data *sdata; |
348 | int n_acs = IEEE80211_NUM_ACS; | ||
344 | 349 | ||
345 | trace_stop_queue(local, queue, reason); | 350 | trace_stop_queue(local, queue, reason); |
346 | 351 | ||
@@ -352,11 +357,14 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, | |||
352 | 357 | ||
353 | __set_bit(reason, &local->queue_stop_reasons[queue]); | 358 | __set_bit(reason, &local->queue_stop_reasons[queue]); |
354 | 359 | ||
360 | if (local->hw.queues < IEEE80211_NUM_ACS) | ||
361 | n_acs = 1; | ||
362 | |||
355 | rcu_read_lock(); | 363 | rcu_read_lock(); |
356 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | 364 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
357 | int ac; | 365 | int ac; |
358 | 366 | ||
359 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { | 367 | for (ac = 0; ac < n_acs; ac++) { |
360 | if (sdata->vif.hw_queue[ac] == queue || | 368 | if (sdata->vif.hw_queue[ac] == queue || |
361 | sdata->vif.cab_queue == queue) | 369 | sdata->vif.cab_queue == queue) |
362 | netif_stop_subqueue(sdata->dev, ac); | 370 | netif_stop_subqueue(sdata->dev, ac); |