aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/util.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-07-04 06:49:59 -0400
committerJohannes Berg <johannes.berg@intel.com>2012-07-06 09:26:58 -0400
commita6f38ac3cc853189705006cc1e0f17ce8467a1df (patch)
tree82184dc3a42ecc6849457d10423dd6676cb09b77 /net/mac80211/util.c
parentc62094889f7bb0b3343d5404c9d139d2fb1712bb (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.c12
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);
268void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue) 268void 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);