Commit 281c56dd authored by Bruno Randolf's avatar Bruno Randolf Committed by John W. Linville

ath5k: correct padding in tx descriptors

when setting up the tx descriptors for the hardware we must account for any
padding between the header and the data we might have added previously. frame
len is the length of the frame in the air (including FCS but no padding) and
buffer len is the length of the buffer (including padding, but without FCS).

changing the way ah_setup_tx_desc is called: now excluding the FCS, since it's
easier to add that in the function where we need it.

before this fix we sent trailing zero bytes after the packet (because frame len
included the padding) which was not a big problem without WEP, but with WEP
this resultes in a wrong WEP checksum and the packet is discarded - which is
how i noticed at all ;)

an easy way to run into header padding problems, btw, is to connect to a QoS
(WME) enabled access point (eg. madwifi) - QoS data frames are 2 byte longer
and will require padding.

this patch applies on top of luis latest patch series from 04.02.2008.

drivers/net/wireless/ath5k/base.c:      Changes-licensed-under: 3-Clause-BSD
drivers/net/wireless/ath5k/hw.c:        Changes-licensed-under: ISC
Signed-off-by: default avatarBruno Randolf <bruno@thinktube.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent bd196ec7
...@@ -1256,7 +1256,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, ...@@ -1256,7 +1256,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
if (ctl->flags & IEEE80211_TXCTL_NO_ACK) if (ctl->flags & IEEE80211_TXCTL_NO_ACK)
flags |= AR5K_TXDESC_NOACK; flags |= AR5K_TXDESC_NOACK;
pktlen = skb->len + FCS_LEN; pktlen = skb->len;
if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) { if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) {
keyidx = ctl->key_idx; keyidx = ctl->key_idx;
...@@ -1952,7 +1952,7 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, ...@@ -1952,7 +1952,7 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
} }
ds->ds_data = bf->skbaddr; ds->ds_data = bf->skbaddr;
ret = ah->ah_setup_tx_desc(ah, ds, skb->len + FCS_LEN, ret = ah->ah_setup_tx_desc(ah, ds, skb->len,
ieee80211_get_hdrlen_from_skb(skb), ieee80211_get_hdrlen_from_skb(skb),
AR5K_PKT_TYPE_BEACON, (ctl->power_level * 2), ctl->tx_rate, 1, AR5K_PKT_TYPE_BEACON, (ctl->power_level * 2), ctl->tx_rate, 1,
AR5K_TXKEYIX_INVALID, antenna, flags, 0, 0); AR5K_TXKEYIX_INVALID, antenna, flags, 0, 0);
......
...@@ -3506,7 +3506,7 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, ...@@ -3506,7 +3506,7 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
{ {
u32 frame_type; u32 frame_type;
struct ath5k_hw_2w_tx_desc *tx_desc; struct ath5k_hw_2w_tx_desc *tx_desc;
unsigned int buff_len; unsigned int frame_len;
tx_desc = (struct ath5k_hw_2w_tx_desc *)&desc->ds_ctl0; tx_desc = (struct ath5k_hw_2w_tx_desc *)&desc->ds_ctl0;
...@@ -3537,22 +3537,25 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, ...@@ -3537,22 +3537,25 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
/* Setup control descriptor */ /* Setup control descriptor */
/* Verify and set frame length */ /* Verify and set frame length */
if (pkt_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN)
/* remove padding we might have added before */
frame_len = pkt_len - (hdr_len & 3) + FCS_LEN;
if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN)
return -EINVAL; return -EINVAL;
tx_desc->tx_control_0 = pkt_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN; tx_desc->tx_control_0 = frame_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN;
/* Verify and set buffer length */ /* Verify and set buffer length */
buff_len = pkt_len - FCS_LEN;
/* NB: beacon's BufLen must be a multiple of 4 bytes */ /* NB: beacon's BufLen must be a multiple of 4 bytes */
if(type == AR5K_PKT_TYPE_BEACON) if(type == AR5K_PKT_TYPE_BEACON)
buff_len = roundup(buff_len, 4); pkt_len = roundup(pkt_len, 4);
if (buff_len & ~AR5K_2W_TX_DESC_CTL1_BUF_LEN) if (pkt_len & ~AR5K_2W_TX_DESC_CTL1_BUF_LEN)
return -EINVAL; return -EINVAL;
tx_desc->tx_control_1 = buff_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN; tx_desc->tx_control_1 = pkt_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN;
/* /*
* Verify and set header length * Verify and set header length
...@@ -3634,7 +3637,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, ...@@ -3634,7 +3637,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
{ {
struct ath5k_hw_4w_tx_desc *tx_desc; struct ath5k_hw_4w_tx_desc *tx_desc;
struct ath5k_hw_tx_status *tx_status; struct ath5k_hw_tx_status *tx_status;
unsigned int buff_len; unsigned int frame_len;
ATH5K_TRACE(ah->ah_sc); ATH5K_TRACE(ah->ah_sc);
tx_desc = (struct ath5k_hw_4w_tx_desc *)&desc->ds_ctl0; tx_desc = (struct ath5k_hw_4w_tx_desc *)&desc->ds_ctl0;
...@@ -3669,22 +3672,25 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, ...@@ -3669,22 +3672,25 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
/* Setup control descriptor */ /* Setup control descriptor */
/* Verify and set frame length */ /* Verify and set frame length */
if (pkt_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN)
/* remove padding we might have added before */
frame_len = pkt_len - (hdr_len & 3) + FCS_LEN;
if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN)
return -EINVAL; return -EINVAL;
tx_desc->tx_control_0 = pkt_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN; tx_desc->tx_control_0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN;
/* Verify and set buffer length */ /* Verify and set buffer length */
buff_len = pkt_len - FCS_LEN;
/* NB: beacon's BufLen must be a multiple of 4 bytes */ /* NB: beacon's BufLen must be a multiple of 4 bytes */
if(type == AR5K_PKT_TYPE_BEACON) if(type == AR5K_PKT_TYPE_BEACON)
buff_len = roundup(buff_len, 4); pkt_len = roundup(pkt_len, 4);
if (buff_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN) if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN)
return -EINVAL; return -EINVAL;
tx_desc->tx_control_1 = buff_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN; tx_desc->tx_control_1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN;
tx_desc->tx_control_0 |= tx_desc->tx_control_0 |=
AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) | AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) |
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment