aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSeth Forshee <seth.forshee@canonical.com>2013-02-11 12:21:07 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-02-11 16:52:21 -0500
commit6c17b77b67587b9f9e3070fb89fe98cef3187131 (patch)
tree5e47a8feb14ec822b276c893a9fb3cca93e6bbd0
parentdf15a6c4fa7f77511663d7b5f9134f37ad2e8c92 (diff)
mac80211: Fix tx queue handling during scans
Scans currently work by stopping the netdev tx queues but leaving the mac80211 queues active. This stops the flow of incoming packets while still allowing mac80211 to transmit nullfunc and probe request frames to facilitate scanning. However, the driver may try to wake the mac80211 queues while in this state, which will also wake the netdev queues. To prevent this, add a new queue stop reason, IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL, to be used when stopping the tx queues for off-channel operation. This prevents the netdev queues from waking when a driver wakes the mac80211 queues. This also stops all frames from being transmitted, even those meant to be sent off-channel. Add a new tx control flag, IEEE80211_TX_CTL_OFFCHAN_TX_OK, which allows frames to be transmitted when the queues are stopped only for the off-channel stop reason. Update all locations transmitting off-channel frames to use this flag. Signed-off-by: Seth Forshee <seth.forshee@canonical.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--include/net/mac80211.h4
-rw-r--r--net/mac80211/cfg.c3
-rw-r--r--net/mac80211/ieee80211_i.h1
-rw-r--r--net/mac80211/mlme.c3
-rw-r--r--net/mac80211/offchannel.c30
-rw-r--r--net/mac80211/scan.c9
-rw-r--r--net/mac80211/tx.c15
7 files changed, 40 insertions, 25 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 86ad2c341525..0eaa9092364b 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -399,6 +399,9 @@ struct ieee80211_bss_conf {
399 * @IEEE80211_TX_CTL_RATE_CTRL_PROBE: internal to mac80211, can be 399 * @IEEE80211_TX_CTL_RATE_CTRL_PROBE: internal to mac80211, can be
400 * set by rate control algorithms to indicate probe rate, will 400 * set by rate control algorithms to indicate probe rate, will
401 * be cleared for fragmented frames (except on the last fragment) 401 * be cleared for fragmented frames (except on the last fragment)
402 * @IEEE80211_TX_INTFL_OFFCHAN_TX_OK: Internal to mac80211. Used to indicate
403 * that a frame can be transmitted while the queues are stopped for
404 * off-channel operation.
402 * @IEEE80211_TX_INTFL_NEED_TXPROCESSING: completely internal to mac80211, 405 * @IEEE80211_TX_INTFL_NEED_TXPROCESSING: completely internal to mac80211,
403 * used to indicate that a pending frame requires TX processing before 406 * used to indicate that a pending frame requires TX processing before
404 * it can be sent out. 407 * it can be sent out.
@@ -464,6 +467,7 @@ enum mac80211_tx_control_flags {
464 IEEE80211_TX_STAT_AMPDU = BIT(10), 467 IEEE80211_TX_STAT_AMPDU = BIT(10),
465 IEEE80211_TX_STAT_AMPDU_NO_BACK = BIT(11), 468 IEEE80211_TX_STAT_AMPDU_NO_BACK = BIT(11),
466 IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(12), 469 IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(12),
470 IEEE80211_TX_INTFL_OFFCHAN_TX_OK = BIT(13),
467 IEEE80211_TX_INTFL_NEED_TXPROCESSING = BIT(14), 471 IEEE80211_TX_INTFL_NEED_TXPROCESSING = BIT(14),
468 IEEE80211_TX_INTFL_RETRIED = BIT(15), 472 IEEE80211_TX_INTFL_RETRIED = BIT(15),
469 IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(16), 473 IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(16),
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 8f6b593a921f..e3dec80cf617 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2749,7 +2749,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
2749 goto out_unlock; 2749 goto out_unlock;
2750 } 2750 }
2751 2751
2752 IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN; 2752 IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN |
2753 IEEE80211_TX_INTFL_OFFCHAN_TX_OK;
2753 if (local->hw.flags & IEEE80211_HW_QUEUE_CONTROL) 2754 if (local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)
2754 IEEE80211_SKB_CB(skb)->hw_queue = 2755 IEEE80211_SKB_CB(skb)->hw_queue =
2755 local->hw.offchannel_tx_hw_queue; 2756 local->hw.offchannel_tx_hw_queue;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 5635dfc7da34..76cdcfcd614c 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -809,6 +809,7 @@ enum queue_stop_reason {
809 IEEE80211_QUEUE_STOP_REASON_AGGREGATION, 809 IEEE80211_QUEUE_STOP_REASON_AGGREGATION,
810 IEEE80211_QUEUE_STOP_REASON_SUSPEND, 810 IEEE80211_QUEUE_STOP_REASON_SUSPEND,
811 IEEE80211_QUEUE_STOP_REASON_SKB_ADD, 811 IEEE80211_QUEUE_STOP_REASON_SKB_ADD,
812 IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL,
812}; 813};
813 814
814#ifdef CONFIG_MAC80211_LEDS 815#ifdef CONFIG_MAC80211_LEDS
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 76cacdb062c8..efb22763d56d 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -685,7 +685,8 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
685 if (powersave) 685 if (powersave)
686 nullfunc->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); 686 nullfunc->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
687 687
688 IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; 688 IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
689 IEEE80211_TX_INTFL_OFFCHAN_TX_OK;
689 if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL | 690 if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
690 IEEE80211_STA_CONNECTION_POLL)) 691 IEEE80211_STA_CONNECTION_POLL))
691 IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_USE_MINRATE; 692 IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_USE_MINRATE;
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c
index 82baf5b6ecf4..4c3ee3e8285c 100644
--- a/net/mac80211/offchannel.c
+++ b/net/mac80211/offchannel.c
@@ -113,6 +113,10 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local)
113 * notify the AP about us leaving the channel and stop all 113 * notify the AP about us leaving the channel and stop all
114 * STA interfaces. 114 * STA interfaces.
115 */ 115 */
116
117 ieee80211_stop_queues_by_reason(&local->hw,
118 IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL);
119
116 mutex_lock(&local->iflist_mtx); 120 mutex_lock(&local->iflist_mtx);
117 list_for_each_entry(sdata, &local->interfaces, list) { 121 list_for_each_entry(sdata, &local->interfaces, list) {
118 if (!ieee80211_sdata_running(sdata)) 122 if (!ieee80211_sdata_running(sdata))
@@ -133,12 +137,9 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local)
133 sdata, BSS_CHANGED_BEACON_ENABLED); 137 sdata, BSS_CHANGED_BEACON_ENABLED);
134 } 138 }
135 139
136 if (sdata->vif.type != NL80211_IFTYPE_MONITOR) { 140 if (sdata->vif.type == NL80211_IFTYPE_STATION &&
137 netif_tx_stop_all_queues(sdata->dev); 141 sdata->u.mgd.associated)
138 if (sdata->vif.type == NL80211_IFTYPE_STATION && 142 ieee80211_offchannel_ps_enable(sdata);
139 sdata->u.mgd.associated)
140 ieee80211_offchannel_ps_enable(sdata);
141 }
142 } 143 }
143 mutex_unlock(&local->iflist_mtx); 144 mutex_unlock(&local->iflist_mtx);
144} 145}
@@ -166,20 +167,6 @@ void ieee80211_offchannel_return(struct ieee80211_local *local)
166 sdata->u.mgd.associated) 167 sdata->u.mgd.associated)
167 ieee80211_offchannel_ps_disable(sdata); 168 ieee80211_offchannel_ps_disable(sdata);
168 169
169 if (sdata->vif.type != NL80211_IFTYPE_MONITOR) {
170 /*
171 * This may wake up queues even though the driver
172 * currently has them stopped. This is not very
173 * likely, since the driver won't have gotten any
174 * (or hardly any) new packets while we weren't
175 * on the right channel, and even if it happens
176 * it will at most lead to queueing up one more
177 * packet per queue in mac80211 rather than on
178 * the interface qdisc.
179 */
180 netif_tx_wake_all_queues(sdata->dev);
181 }
182
183 if (test_and_clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, 170 if (test_and_clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED,
184 &sdata->state)) { 171 &sdata->state)) {
185 sdata->vif.bss_conf.enable_beacon = true; 172 sdata->vif.bss_conf.enable_beacon = true;
@@ -188,6 +175,9 @@ void ieee80211_offchannel_return(struct ieee80211_local *local)
188 } 175 }
189 } 176 }
190 mutex_unlock(&local->iflist_mtx); 177 mutex_unlock(&local->iflist_mtx);
178
179 ieee80211_wake_queues_by_reason(&local->hw,
180 IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL);
191} 181}
192 182
193void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc) 183void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc)
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index edd47d9acb99..d9e2df96f676 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -382,6 +382,11 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
382 int i; 382 int i;
383 struct ieee80211_sub_if_data *sdata; 383 struct ieee80211_sub_if_data *sdata;
384 enum ieee80211_band band = local->hw.conf.channel->band; 384 enum ieee80211_band band = local->hw.conf.channel->band;
385 u32 tx_flags;
386
387 tx_flags = IEEE80211_TX_INTFL_OFFCHAN_TX_OK;
388 if (local->scan_req->no_cck)
389 tx_flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
385 390
386 sdata = rcu_dereference_protected(local->scan_sdata, 391 sdata = rcu_dereference_protected(local->scan_sdata,
387 lockdep_is_held(&local->mtx)); 392 lockdep_is_held(&local->mtx));
@@ -393,9 +398,7 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
393 local->scan_req->ssids[i].ssid_len, 398 local->scan_req->ssids[i].ssid_len,
394 local->scan_req->ie, local->scan_req->ie_len, 399 local->scan_req->ie, local->scan_req->ie_len,
395 local->scan_req->rates[band], false, 400 local->scan_req->rates[band], false,
396 local->scan_req->no_cck ? 401 tx_flags, local->hw.conf.channel, true);
397 IEEE80211_TX_CTL_NO_CCK_RATE : 0,
398 local->hw.conf.channel, true);
399 402
400 /* 403 /*
401 * After sending probe requests, wait for probe responses 404 * After sending probe requests, wait for probe responses
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 2ef0e19b06bb..f476aa6a771d 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1230,6 +1230,21 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local,
1230 spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 1230 spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
1231 if (local->queue_stop_reasons[q] || 1231 if (local->queue_stop_reasons[q] ||
1232 (!txpending && !skb_queue_empty(&local->pending[q]))) { 1232 (!txpending && !skb_queue_empty(&local->pending[q]))) {
1233 if (unlikely(info->flags &
1234 IEEE80211_TX_INTFL_OFFCHAN_TX_OK &&
1235 local->queue_stop_reasons[q] &
1236 ~BIT(IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL))) {
1237 /*
1238 * Drop off-channel frames if queues are stopped
1239 * for any reason other than off-channel
1240 * operation. Never queue them.
1241 */
1242 spin_unlock_irqrestore(
1243 &local->queue_stop_reason_lock, flags);
1244 ieee80211_purge_tx_queue(&local->hw, skbs);
1245 return true;
1246 }
1247
1233 /* 1248 /*
1234 * Since queue is stopped, queue up frames for later 1249 * Since queue is stopped, queue up frames for later
1235 * transmission from the tx-pending tasklet when the 1250 * transmission from the tx-pending tasklet when the