aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorBenoit PAPILLAULT <benoit.papillault@free.fr>2008-12-12 09:29:58 -0500
committerJohn W. Linville <linville@tuxdriver.com>2008-12-19 15:23:07 -0500
commit0fe45b1debba7302155b62f3829119a1185a4f5a (patch)
treec248895ecf387cabb1350ca327d382a306e6f0e3 /drivers/net
parentbaad1d921b1565b6f08f60c035531d13ad8afa82 (diff)
ath5k: fix 802.11 header padding on RX, unpadding on TX
Padding the 802.11 header to a multiple of 4 bytes needs to be done only for frames with a body. This fixes a bug where 2 bytes were missing in monitor mode for ACK frames. Inspired by a patch from Jouni Malinen on ath9k. Ref: http://bugzilla.kernel.org/show_bug.cgi?id=12101 : Signed-off-by: Benoit Papillault <benoit.papillault@free.fr> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/ath5k/base.c38
1 files changed, 21 insertions, 17 deletions
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c
index 0e4317010ed0..9b5f31aab574 100644
--- a/drivers/net/wireless/ath5k/base.c
+++ b/drivers/net/wireless/ath5k/base.c
@@ -1668,7 +1668,7 @@ ath5k_tasklet_rx(unsigned long data)
1668 struct ath5k_desc *ds; 1668 struct ath5k_desc *ds;
1669 int ret; 1669 int ret;
1670 int hdrlen; 1670 int hdrlen;
1671 int pad; 1671 int padsize;
1672 1672
1673 spin_lock(&sc->rxbuflock); 1673 spin_lock(&sc->rxbuflock);
1674 if (list_empty(&sc->rxbuf)) { 1674 if (list_empty(&sc->rxbuf)) {
@@ -1753,16 +1753,19 @@ accept:
1753 1753
1754 skb_put(skb, rs.rs_datalen); 1754 skb_put(skb, rs.rs_datalen);
1755 1755
1756 /* 1756 /* The MAC header is padded to have 32-bit boundary if the
1757 * the hardware adds a padding to 4 byte boundaries between 1757 * packet payload is non-zero. The general calculation for
1758 * the header and the payload data if the header length is 1758 * padsize would take into account odd header lengths:
1759 * not multiples of 4 - remove it 1759 * padsize = (4 - hdrlen % 4) % 4; However, since only
1760 */ 1760 * even-length headers are used, padding can only be 0 or 2
1761 * bytes and we can optimize this a bit. In addition, we must
1762 * not try to remove padding from short control frames that do
1763 * not have payload. */
1761 hdrlen = ieee80211_get_hdrlen_from_skb(skb); 1764 hdrlen = ieee80211_get_hdrlen_from_skb(skb);
1762 if (hdrlen & 3) { 1765 padsize = hdrlen & 3;
1763 pad = hdrlen % 4; 1766 if (padsize && hdrlen >= 24) {
1764 memmove(skb->data + pad, skb->data, hdrlen); 1767 memmove(skb->data + padsize, skb->data, hdrlen);
1765 skb_pull(skb, pad); 1768 skb_pull(skb, padsize);
1766 } 1769 }
1767 1770
1768 /* 1771 /*
@@ -2623,7 +2626,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
2623 struct ath5k_buf *bf; 2626 struct ath5k_buf *bf;
2624 unsigned long flags; 2627 unsigned long flags;
2625 int hdrlen; 2628 int hdrlen;
2626 int pad; 2629 int padsize;
2627 2630
2628 ath5k_debug_dump_skb(sc, skb, "TX ", 1); 2631 ath5k_debug_dump_skb(sc, skb, "TX ", 1);
2629 2632
@@ -2635,15 +2638,16 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
2635 * if this is not the case we add the padding after the header 2638 * if this is not the case we add the padding after the header
2636 */ 2639 */
2637 hdrlen = ieee80211_get_hdrlen_from_skb(skb); 2640 hdrlen = ieee80211_get_hdrlen_from_skb(skb);
2638 if (hdrlen & 3) { 2641 padsize = hdrlen & 3;
2639 pad = hdrlen % 4; 2642 if (padsize && hdrlen >= 24) {
2640 if (skb_headroom(skb) < pad) { 2643
2644 if (skb_headroom(skb) < padsize) {
2641 ATH5K_ERR(sc, "tx hdrlen not %%4: %d not enough" 2645 ATH5K_ERR(sc, "tx hdrlen not %%4: %d not enough"
2642 " headroom to pad %d\n", hdrlen, pad); 2646 " headroom to pad %d\n", hdrlen, padsize);
2643 return -1; 2647 return -1;
2644 } 2648 }
2645 skb_push(skb, pad); 2649 skb_push(skb, padsize);
2646 memmove(skb->data, skb->data+pad, hdrlen); 2650 memmove(skb->data, skb->data+padsize, hdrlen);
2647 } 2651 }
2648 2652
2649 spin_lock_irqsave(&sc->txbuflock, flags); 2653 spin_lock_irqsave(&sc->txbuflock, flags);