diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2009-06-07 15:58:37 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-06-10 13:28:37 -0400 |
commit | 8f77f3849cc3ae2d6df9301785a3d316ea7d7ee1 (patch) | |
tree | 02143d1e81c85f64900546e3e9c2b820f72745d1 /net/mac80211/main.c | |
parent | fc240e3fc5791c572402b0857948da7b1e68d77f (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.c | 61 |
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 | */ | ||
376 | static 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 | |||
413 | no_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 | |||
422 | static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, | 372 | static 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 | ||