aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-06-07 15:58:37 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-06-10 13:28:37 -0400
commit8f77f3849cc3ae2d6df9301785a3d316ea7d7ee1 (patch)
tree02143d1e81c85f64900546e3e9c2b820f72745d1 /net/mac80211
parentfc240e3fc5791c572402b0857948da7b1e68d77f (diff)
mac80211: do not pass PS frames out of mac80211 again
In order to handle powersave frames properly we had needed to pass these out to the device queues again, and introduce the skb->requeue bit. This, however, also has unnecessary overhead by needing to 'clean up' already tried frames, and this clean-up code is also buggy when software encryption is used. Instead of sending the frames via the master netdev queue again, simply put them into the pending queue. This also fixes a problem where frames for that particular station could be reordered when some were still on the software queues and older ones are re-injected into the software queue after them. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/ieee80211_i.h5
-rw-r--r--net/mac80211/main.c61
-rw-r--r--net/mac80211/rx.c25
-rw-r--r--net/mac80211/tx.c3
-rw-r--r--net/mac80211/util.c46
-rw-r--r--net/mac80211/wme.c2
6 files changed, 69 insertions, 73 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index c088c46704a3..4dbc28964196 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -589,6 +589,7 @@ enum queue_stop_reason {
589 IEEE80211_QUEUE_STOP_REASON_AGGREGATION, 589 IEEE80211_QUEUE_STOP_REASON_AGGREGATION,
590 IEEE80211_QUEUE_STOP_REASON_SUSPEND, 590 IEEE80211_QUEUE_STOP_REASON_SUSPEND,
591 IEEE80211_QUEUE_STOP_REASON_PENDING, 591 IEEE80211_QUEUE_STOP_REASON_PENDING,
592 IEEE80211_QUEUE_STOP_REASON_SKB_ADD,
592}; 593};
593 594
594struct ieee80211_master_priv { 595struct ieee80211_master_priv {
@@ -1121,6 +1122,10 @@ void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
1121 enum queue_stop_reason reason); 1122 enum queue_stop_reason reason);
1122void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, 1123void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
1123 enum queue_stop_reason reason); 1124 enum queue_stop_reason reason);
1125void ieee80211_add_pending_skb(struct ieee80211_local *local,
1126 struct sk_buff *skb);
1127int ieee80211_add_pending_skbs(struct ieee80211_local *local,
1128 struct sk_buff_head *skbs);
1124 1129
1125void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, 1130void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
1126 u16 transaction, u16 auth_alg, 1131 u16 transaction, u16 auth_alg,
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 2683df918073..092a017b237e 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -369,60 +369,12 @@ static void ieee80211_tasklet_handler(unsigned long data)
369 } 369 }
370} 370}
371 371
372/* Remove added headers (e.g., QoS control), encryption header/MIC, etc. to
373 * make a prepared TX frame (one that has been given to hw) to look like brand
374 * new IEEE 802.11 frame that is ready to go through TX processing again.
375 */
376static void ieee80211_remove_tx_extra(struct ieee80211_local *local,
377 struct ieee80211_key *key,
378 struct sk_buff *skb)
379{
380 unsigned int hdrlen, iv_len, mic_len;
381 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
382
383 hdrlen = ieee80211_hdrlen(hdr->frame_control);
384
385 if (!key)
386 goto no_key;
387
388 switch (key->conf.alg) {
389 case ALG_WEP:
390 iv_len = WEP_IV_LEN;
391 mic_len = WEP_ICV_LEN;
392 break;
393 case ALG_TKIP:
394 iv_len = TKIP_IV_LEN;
395 mic_len = TKIP_ICV_LEN;
396 break;
397 case ALG_CCMP:
398 iv_len = CCMP_HDR_LEN;
399 mic_len = CCMP_MIC_LEN;
400 break;
401 default:
402 goto no_key;
403 }
404
405 if (skb->len >= hdrlen + mic_len &&
406 !(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
407 skb_trim(skb, skb->len - mic_len);
408 if (skb->len >= hdrlen + iv_len) {
409 memmove(skb->data + iv_len, skb->data, hdrlen);
410 hdr = (struct ieee80211_hdr *)skb_pull(skb, iv_len);
411 }
412
413no_key:
414 if (ieee80211_is_data_qos(hdr->frame_control)) {
415 hdr->frame_control &= ~cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
416 memmove(skb->data + IEEE80211_QOS_CTL_LEN, skb->data,
417 hdrlen - IEEE80211_QOS_CTL_LEN);
418 skb_pull(skb, IEEE80211_QOS_CTL_LEN);
419 }
420}
421
422static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, 372static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
423 struct sta_info *sta, 373 struct sta_info *sta,
424 struct sk_buff *skb) 374 struct sk_buff *skb)
425{ 375{
376 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
377
426 sta->tx_filtered_count++; 378 sta->tx_filtered_count++;
427 379
428 /* 380 /*
@@ -464,16 +416,15 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
464 */ 416 */
465 if (test_sta_flags(sta, WLAN_STA_PS) && 417 if (test_sta_flags(sta, WLAN_STA_PS) &&
466 skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) { 418 skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) {
467 ieee80211_remove_tx_extra(local, sta->key, skb);
468 skb_queue_tail(&sta->tx_filtered, skb); 419 skb_queue_tail(&sta->tx_filtered, skb);
469 return; 420 return;
470 } 421 }
471 422
472 if (!test_sta_flags(sta, WLAN_STA_PS) && !skb->requeue) { 423 if (!test_sta_flags(sta, WLAN_STA_PS) &&
424 !(info->flags & IEEE80211_TX_INTFL_RETRIED)) {
473 /* Software retry the packet once */ 425 /* Software retry the packet once */
474 skb->requeue = 1; 426 info->flags |= IEEE80211_TX_INTFL_RETRIED;
475 ieee80211_remove_tx_extra(local, sta->key, skb); 427 ieee80211_add_pending_skb(local, skb);
476 dev_queue_xmit(skb);
477 return; 428 return;
478 } 429 }
479 430
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 754125185109..de5bba7f910a 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -797,8 +797,7 @@ static int ap_sta_ps_end(struct sta_info *sta)
797{ 797{
798 struct ieee80211_sub_if_data *sdata = sta->sdata; 798 struct ieee80211_sub_if_data *sdata = sta->sdata;
799 struct ieee80211_local *local = sdata->local; 799 struct ieee80211_local *local = sdata->local;
800 struct sk_buff *skb; 800 int sent, buffered;
801 int sent = 0;
802 801
803 atomic_dec(&sdata->bss->num_sta_ps); 802 atomic_dec(&sdata->bss->num_sta_ps);
804 803
@@ -814,22 +813,16 @@ static int ap_sta_ps_end(struct sta_info *sta)
814#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ 813#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
815 814
816 /* Send all buffered frames to the station */ 815 /* Send all buffered frames to the station */
817 while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { 816 sent = ieee80211_add_pending_skbs(local, &sta->tx_filtered);
818 sent++; 817 buffered = ieee80211_add_pending_skbs(local, &sta->ps_tx_buf);
819 skb->requeue = 1; 818 sent += buffered;
820 dev_queue_xmit(skb); 819 local->total_ps_buffered -= buffered;
821 } 820
822 while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
823 local->total_ps_buffered--;
824 sent++;
825#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG 821#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
826 printk(KERN_DEBUG "%s: STA %pM aid %d send PS frame " 822 printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames "
827 "since STA not sleeping anymore\n", sdata->dev->name, 823 "since STA not sleeping anymore\n", sdata->dev->name,
828 sta->sta.addr, sta->sta.aid); 824 sta->sta.addr, sta->sta.aid, sent - buffered, buffered);
829#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ 825#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
830 skb->requeue = 1;
831 dev_queue_xmit(skb);
832 }
833 826
834 return sent; 827 return sent;
835} 828}
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 1436f747531a..bfaa9ce33146 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -400,6 +400,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
400 sta_info_set_tim_bit(sta); 400 sta_info_set_tim_bit(sta);
401 401
402 info->control.jiffies = jiffies; 402 info->control.jiffies = jiffies;
403 info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
403 skb_queue_tail(&sta->ps_tx_buf, tx->skb); 404 skb_queue_tail(&sta->ps_tx_buf, tx->skb);
404 return TX_QUEUED; 405 return TX_QUEUED;
405 } 406 }
@@ -420,7 +421,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
420 * frame filtering and keeps a station blacklist on its own 421 * frame filtering and keeps a station blacklist on its own
421 * (e.g: p54), so that frames can be delivered unimpeded. 422 * (e.g: p54), so that frames can be delivered unimpeded.
422 * 423 *
423 * Note: It should be save to disable the filter now. 424 * Note: It should be safe to disable the filter now.
424 * As, it is really unlikely that we still have any pending 425 * As, it is really unlikely that we still have any pending
425 * frame for this station in the hw's buffers/fifos left, 426 * frame for this station in the hw's buffers/fifos left,
426 * that is not rejected with a unsuccessful tx_status yet. 427 * that is not rejected with a unsuccessful tx_status yet.
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 22f63815fb36..66ce96a69f31 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -341,6 +341,52 @@ void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue)
341} 341}
342EXPORT_SYMBOL(ieee80211_stop_queue); 342EXPORT_SYMBOL(ieee80211_stop_queue);
343 343
344void ieee80211_add_pending_skb(struct ieee80211_local *local,
345 struct sk_buff *skb)
346{
347 struct ieee80211_hw *hw = &local->hw;
348 unsigned long flags;
349 int queue = skb_get_queue_mapping(skb);
350
351 spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
352 __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
353 __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_PENDING);
354 skb_queue_tail(&local->pending[queue], skb);
355 __ieee80211_wake_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
356 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
357}
358
359int ieee80211_add_pending_skbs(struct ieee80211_local *local,
360 struct sk_buff_head *skbs)
361{
362 struct ieee80211_hw *hw = &local->hw;
363 struct sk_buff *skb;
364 unsigned long flags;
365 int queue, ret = 0, i;
366
367 spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
368 for (i = 0; i < hw->queues; i++)
369 __ieee80211_stop_queue(hw, i,
370 IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
371
372 while ((skb = skb_dequeue(skbs))) {
373 ret++;
374 queue = skb_get_queue_mapping(skb);
375 skb_queue_tail(&local->pending[queue], skb);
376 }
377
378 for (i = 0; i < hw->queues; i++) {
379 if (ret)
380 __ieee80211_stop_queue(hw, i,
381 IEEE80211_QUEUE_STOP_REASON_PENDING);
382 __ieee80211_wake_queue(hw, i,
383 IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
384 }
385 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
386
387 return ret;
388}
389
344void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, 390void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
345 enum queue_stop_reason reason) 391 enum queue_stop_reason reason)
346{ 392{
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index 694343b9102b..116a923b14d6 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -101,7 +101,7 @@ u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb)
101 * Now we know the 1d priority, fill in the QoS header if 101 * Now we know the 1d priority, fill in the QoS header if
102 * there is one (and we haven't done this before). 102 * there is one (and we haven't done this before).
103 */ 103 */
104 if (!skb->requeue && ieee80211_is_data_qos(hdr->frame_control)) { 104 if (ieee80211_is_data_qos(hdr->frame_control)) {
105 u8 *p = ieee80211_get_qos_ctl(hdr); 105 u8 *p = ieee80211_get_qos_ctl(hdr);
106 u8 ack_policy = 0; 106 u8 ack_policy = 0;
107 tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; 107 tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;