diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2007-12-19 22:38:33 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 18:08:50 -0500 |
commit | 0300b3321d9ed73a0c3f575f2df250c577852356 (patch) | |
tree | f08a833e60d4276fabbd79a20361acec740fa725 /drivers/net/wireless/airo.c | |
parent | 851b3e5e3de0feea7bfee634f99a940648de58c8 (diff) |
airo: bug in airo_interrupt() handling on incoming 802.11
On big-endian we end up with swapped first two bytes in packet,
due to earlier conversion to host-endian and forgotten conversion
back.
The code we calculated that host-endian for had been duplicated
several time - it finds the 802.11 MAC header length by the first
two bytes of packet; taken into a new helper (header_len(__le16 ctl)).
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/airo.c')
-rw-r--r-- | drivers/net/wireless/airo.c | 74 |
1 files changed, 23 insertions, 51 deletions
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 6d4cc684afa6..9d3f3357b6e1 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c | |||
@@ -3177,6 +3177,21 @@ static int airo_thread(void *data) { | |||
3177 | return 0; | 3177 | return 0; |
3178 | } | 3178 | } |
3179 | 3179 | ||
3180 | static int header_len(__le16 ctl) | ||
3181 | { | ||
3182 | u16 fc = le16_to_cpu(ctl); | ||
3183 | switch (fc & 0xc) { | ||
3184 | case 4: | ||
3185 | if ((fc & 0xe0) == 0xc0) | ||
3186 | return 10; /* one-address control packet */ | ||
3187 | return 16; /* two-address control packet */ | ||
3188 | case 8: | ||
3189 | if ((fc & 0x300) == 0x300) | ||
3190 | return 30; /* WDS packet */ | ||
3191 | } | ||
3192 | return 24; | ||
3193 | } | ||
3194 | |||
3180 | static irqreturn_t airo_interrupt(int irq, void *dev_id) | 3195 | static irqreturn_t airo_interrupt(int irq, void *dev_id) |
3181 | { | 3196 | { |
3182 | struct net_device *dev = dev_id; | 3197 | struct net_device *dev = dev_id; |
@@ -3330,23 +3345,8 @@ static irqreturn_t airo_interrupt(int irq, void *dev_id) | |||
3330 | goto badrx; | 3345 | goto badrx; |
3331 | 3346 | ||
3332 | if (test_bit(FLAG_802_11, &apriv->flags)) { | 3347 | if (test_bit(FLAG_802_11, &apriv->flags)) { |
3333 | bap_read (apriv, (u16*)&fc, sizeof(fc), BAP0); | 3348 | bap_read (apriv, &fc, sizeof(fc), BAP0); |
3334 | fc = le16_to_cpu(fc); | 3349 | hdrlen = header_len(fc); |
3335 | switch (fc & 0xc) { | ||
3336 | case 4: | ||
3337 | if ((fc & 0xe0) == 0xc0) | ||
3338 | hdrlen = 10; | ||
3339 | else | ||
3340 | hdrlen = 16; | ||
3341 | break; | ||
3342 | case 8: | ||
3343 | if ((fc&0x300)==0x300){ | ||
3344 | hdrlen = 30; | ||
3345 | break; | ||
3346 | } | ||
3347 | default: | ||
3348 | hdrlen = 24; | ||
3349 | } | ||
3350 | } else | 3350 | } else |
3351 | hdrlen = ETH_ALEN * 2; | 3351 | hdrlen = ETH_ALEN * 2; |
3352 | 3352 | ||
@@ -3677,7 +3677,8 @@ void mpi_receive_802_11 (struct airo_info *ai) | |||
3677 | { | 3677 | { |
3678 | RxFid rxd; | 3678 | RxFid rxd; |
3679 | struct sk_buff *skb = NULL; | 3679 | struct sk_buff *skb = NULL; |
3680 | u16 fc, len, hdrlen = 0; | 3680 | u16 len, hdrlen = 0; |
3681 | __le16 fc; | ||
3681 | #pragma pack(1) | 3682 | #pragma pack(1) |
3682 | struct { | 3683 | struct { |
3683 | u16 status, len; | 3684 | u16 status, len; |
@@ -3707,23 +3708,8 @@ void mpi_receive_802_11 (struct airo_info *ai) | |||
3707 | if (len == 0) | 3708 | if (len == 0) |
3708 | goto badrx; | 3709 | goto badrx; |
3709 | 3710 | ||
3710 | memcpy ((char *)&fc, ptr, sizeof(fc)); | 3711 | fc = get_unaligned((__le16 *)ptr); |
3711 | fc = le16_to_cpu(fc); | 3712 | hdrlen = header_len(fc); |
3712 | switch (fc & 0xc) { | ||
3713 | case 4: | ||
3714 | if ((fc & 0xe0) == 0xc0) | ||
3715 | hdrlen = 10; | ||
3716 | else | ||
3717 | hdrlen = 16; | ||
3718 | break; | ||
3719 | case 8: | ||
3720 | if ((fc&0x300)==0x300){ | ||
3721 | hdrlen = 30; | ||
3722 | break; | ||
3723 | } | ||
3724 | default: | ||
3725 | hdrlen = 24; | ||
3726 | } | ||
3727 | 3713 | ||
3728 | skb = dev_alloc_skb( len + hdrlen + 2 ); | 3714 | skb = dev_alloc_skb( len + hdrlen + 2 ); |
3729 | if ( !skb ) { | 3715 | if ( !skb ) { |
@@ -4370,22 +4356,8 @@ static int transmit_802_11_packet(struct airo_info *ai, int len, char *pPacket) | |||
4370 | u16 txFid = len; | 4356 | u16 txFid = len; |
4371 | len >>= 16; | 4357 | len >>= 16; |
4372 | 4358 | ||
4373 | fc = le16_to_cpu(*(const u16*)pPacket); | 4359 | fc = *(__le16*)pPacket; |
4374 | switch (fc & 0xc) { | 4360 | hdrlen = header_len(fc); |
4375 | case 4: | ||
4376 | if ((fc & 0xe0) == 0xc0) | ||
4377 | hdrlen = 10; | ||
4378 | else | ||
4379 | hdrlen = 16; | ||
4380 | break; | ||
4381 | case 8: | ||
4382 | if ((fc&0x300)==0x300){ | ||
4383 | hdrlen = 30; | ||
4384 | break; | ||
4385 | } | ||
4386 | default: | ||
4387 | hdrlen = 24; | ||
4388 | } | ||
4389 | 4361 | ||
4390 | if (len < hdrlen) { | 4362 | if (len < hdrlen) { |
4391 | airo_print_warn(ai->dev->name, "Short packet %d", len); | 4363 | airo_print_warn(ai->dev->name, "Short packet %d", len); |