Skip to contentSkip to conversation

ath5k : Fix correct padding

PATCH In review Benoit PAPILLAULT 5 participants 9 messages Dec 11, 2008 – Dec 12, 2008 Networking drivers (wireless)

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 ath5k : Fix correct padding

Padding the 802.11 header to a multiple of 4 bytes needs to be done only for DATA frames. This fixes a bug where 2 bytes were missing in monitor mode for ACK frames.

Ref: http://bugzilla.kernel.org/show_bug.cgi?id=12101 :

---
 drivers/net/wireless/ath5k/base.c |   49
+++++++++++++++++++++++-------------
 1 files changed, 31 insertions(+), 18 deletions(-)
(quoted diff) +0 -0

b/drivers/net/wireless/ath5k/base.c
index bfb0c49..2318b1c 100644

drivers/net/wireless/ath5k/base.c +14 -7
@@ -1668,6 +1668,7 @@ ath5k_tasklet_rx(unsigned long data)
 	int ret;
 	int hdrlen;
 	int pad;
+	struct ieee80211_hdr * hdr;
 
 	spin_lock(&sc->rxbuflock);
 	if (list_empty(&sc->rxbuf)) {
@@ -1754,14 +1755,19 @@ accept:
 
 		/*
 		 * the hardware adds a padding to 4 byte boundaries between
-		 * the header and the payload data if the header length is
-		 * not multiples of 4 - remove it
+		 * the header and the payload data if the header length is not
+		 * multiple of 4 - remove it. This only affect data frames.
 		 */
-		hdrlen = ieee80211_get_hdrlen_from_skb(skb);
-		if (hdrlen & 3) {
-			pad = hdrlen % 4;
-			memmove(skb->data + pad, skb->data, hdrlen);
-			skb_pull(skb, pad);
+
+		hdr = (struct ieee80211_hdr *) skb;
+		if ((skb->len >= 2) && ieee80211_is_data(hdr->frame_control)) {
+
+			hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+			if (hdrlen & 3) {
+				pad = hdrlen % 4;
+				memmove(skb->data + pad, skb->data, hdrlen);
+				skb_pull(skb, pad);
+			}
 		}
 
 		/*
@@ -2623,6 +2629,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 	unsigned long flags;
 	int hdrlen;
 	int pad;
+	const struct ieee80211_hdr * hdr = (const struct ieee80211_hdr *)skb;
 
 	ath5k_debug_dump_skb(sc, skb, "TX  ", 1);
 
@@ -2630,19 +2637,25 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff

*skb)
ATH5K_DBG(sc, ATH5K_DEBUG_XMIT, "tx in monitor (scan?)\n");

/*
- * the hardware expects the header padded to 4 byte boundaries
- * if this is not the case we add the padding after the header
+ * the hardware expects the header padded to 4 byte boundaries for
+ * data frames, if this is not the case we add the padding after the
+ * header
*/
- hdrlen = ieee80211_get_hdrlen_from_skb(skb);
- if (hdrlen & 3) {
- pad = hdrlen % 4;
- if (skb_headroom(skb) < pad) {
- ATH5K_ERR(sc, "tx hdrlen not %%4: %d not enough"
- " headroom to pad %d\n", hdrlen, pad);
- return -1;
+
+ if ((skb->len >= 2) && ieee80211_is_data(hdr->frame_control)) {
+
+ hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+ if (hdrlen & 3) {
+ pad = hdrlen % 4;
+ if (skb_headroom(skb) < pad) {
+ ATH5K_ERR(sc,
+ "tx hdrlen not %%4: %d not enough"
+ " headroom to pad %d\n", hdrlen, pad);
+ return -1;
+ }
+ skb_push(skb, pad);
+ memmove(skb->data, skb->data+pad, hdrlen);
}
- skb_push(skb, pad);
- memmove(skb->data, skb->data+pad, hdrlen);
}

spin_lock_irqsave(&sc->txbuflock, flags);
-- 1.5.6.5

#1 lore raw
Quoted 2 lines · On Thursday 11 December 2008 22:58:59 Benoit PAPILLAULT wrote:

Padding the 802.11 header to a multiple of 4 bytes needs to be done only for DATA frames.

Uhm, can you explain _why_ it's only needed for data frames?

Signature · 1 line
Greetings, Michael.
maintainer
#2 lore raw
Quoted 5 lines · Michael Buesch
Quoted 2 lines · On Thursday 11 December 2008 22:58:59 Benoit PAPILLAULT wrote:

Padding the 802.11 header to a multiple of 4 bytes needs to be done only for DATA frames.

Uhm, can you explain _why_ it's only needed for data frames?

Well, it's only _needed_ for data frames because the alignment is something the IP stack needs. That doesn't answer the question, of course, the answer to that would have to be something like "because the hardware uses the same algorithm to insert the padding"

johannes

maintainer
#3 lore raw
In reply to Benoit PAPILLAULT
Quoted 3 lines · Benoit PAPILLAULT

Padding the 802.11 header to a multiple of 4 bytes needs to be done only for DATA frames. This fixes a bug where 2 bytes were missing in monitor mode for ACK frames.

That's the wrong way around, you're not padding anything, you're unpadding it.

Your patch is also line-wrapped.

johannes

#4 lore raw

2008/12/11 Johannes Berg <[email protected]>:

Quoted 8 lines · Benoit PAPILLAULT
Quoted 3 lines

Padding the 802.11 header to a multiple of 4 bytes needs to be done only for DATA frames. This fixes a bug where 2 bytes were missing in monitor mode for ACK frames.

That's the wrong way around, you're not padding anything, you're unpadding it.

Agreed, does the hardware really care for control frames if there's a padding on the TX side?

Also, Patrick already posted a patch:

http://marc.info/?l=linux-wireless&m=122888546315200&w=2

Signature · 1 line
Bob Copeland %% www.bobcopeland.com
#5 lore raw
In reply to Benoit PAPILLAULT
Quoted 3 lines · Benoit PAPILLAULT

Padding the 802.11 header to a multiple of 4 bytes needs to be done only for DATA frames. This fixes a bug where 2 bytes were missing in monitor mode for ACK frames.

Without commenting on whether or not this is needed

drivers/net/wireless/ath5k/base.c ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) · line 2632

Quoted 6 lines

/*

drivers/net/wireless/ath5k/base.c +1 -0
@@ -2623,6 +2629,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
  	unsigned long flags;
  	int hdrlen;
  	int pad;
+	const struct ieee80211_hdr * hdr = (const struct ieee80211_hdr *)skb;

skb->data perhaps.

Harvey

maintainer
#6 lore raw
Quoted 7 lines · Harvey Harrison
Quoted 3 lines · Benoit PAPILLAULT

Padding the 802.11 header to a multiple of 4 bytes needs to be done only for DATA frames. This fixes a bug where 2 bytes were missing in monitor mode for ACK frames.

Without commenting on whether or not this is needed

Quoted 8 lines

drivers/net/wireless/ath5k/base.c ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) · line 2632

Quoted 6 lines

/*

drivers/net/wireless/ath5k/base.c +1 -0
@@ -2623,6 +2629,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
  	unsigned long flags;
  	int hdrlen;
  	int pad;
+	const struct ieee80211_hdr * hdr = (const struct ieee80211_hdr *)skb;

skb->data perhaps.

For sure, there's a second place like that too.

johannes

#7 lore raw

Johannes Berg a =E9crit :

Quoted 3 lines · Harvey Harrison
Quoted 2 lines · Benoit PAPILLAULT
Quoted 1 line

Padding the 802.11 header to a multiple of 4 bytes needs to be done=

only

Quoted 1 line
Quoted 1 line
Quoted 1 line

for DATA frames. This fixes a bug where 2 bytes were missing in mon=

itor

Quoted 5 lines
Quoted 5 lines
Quoted 1 line

mode for ACK frames.

Without commenting on whether or not this is needed

Review ath5k_tx(struct ieee80211_hw *hw, struct sk_b=

Quoted 2 lines

/*

(quoted diff) +0 -0
@@ -2623,6 +2629,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_b=

uff *skb)

Quoted 4 lines
Quoted 4 lines

drivers/net/wireless/ath5k/base.c ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)

Quoted 4 lines
drivers/net/wireless/ath5k/base.c +1 -0
  	unsigned long flags;
  	int hdrlen;
  	int pad;
+	const struct ieee80211_hdr * hdr =3D (const struct ieee80211_hdr =

*)skb;

Quoted 5 lines
Quoted 1 line

skb->data perhaps.

=20
For sure, there's a second place like that too.
=20
johannes

Nice catch! I wonder how it was working in my preliminary tests. Sorry=20 for the duplicates with the same patch for ath9k. The padding/unpadding= =20
stuff is needed by the hardware, ie the hardware insert padding on RX=20 and expect padding on TX, as mentioned in earlier ath5k and madwifi=20 source code.

According to my tests, there are 4 kinds of frames:
- Management
- Control
- Data (including QoS data)
- Invalid

Management frames have a fixed header of 24 bytes, so are already a=20 multiple of 4. Control frames are either 10 (ACK!) or 16 bytes and it's= =20
clear that none of them needs padding (hence the current bug). Data=20 frames can be 24, 26, 30 or 32 bytes so it clearly needs some=20 padding/unpadding in some cases. At last, we don't care about Invalid f= rame.

The ath9k patch does padding/unpadding for hdrlen >=3D 24, which appear= s=20
to be equivalent and simpler to compute. I will rewrite the patch using= =20
the ath9k formula.

Regards,
Benoit
--
To unsubscribe from this list: send the line "unsubscribe linux-wireles= s" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#8 lore raw
Quoted 5 lines · Benoit PAPILLAULT

Nice catch! I wonder how it was working in my preliminary tests. Sorry for the duplicates with the same patch for ath9k. The padding/unpadding stuff is needed by the hardware, ie the hardware insert padding on RX and expect padding on TX, as mentioned in earlier ath5k and madwifi source code.

I should clarify: I meant Patrick already posted a fix for ath5k (and possibly the ensuing discussion led to the ath9k patch). Anyway, let's just get a patch in :)

The extra padding on TX side shouldn't hurt anything, OTOH, yeah it is probably unnecessary to do it for ACK/CTS.

Also take a look at desc.c when setting up TX descriptor:

     frame_len = pkt_len - (hdr_len & 3) + FCS_LEN;

What we have now will be 10 - 2 + 4 = 12 vs what should probably be 14.

Signature · 1 line
Bob Copeland %% www.bobcopeland.com