aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/main.c
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/main.c
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/main.c')
-rw-r--r--net/mac80211/main.c61
1 files changed, 6 insertions, 55 deletions
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