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 15:08:50 -0800 |
commit | 0300b3321d9ed73a0c3f575f2df250c577852356 (patch) | |
tree | f08a833e60d4276fabbd79a20361acec740fa725 /drivers | |
parent | 851b3e5e3de0feea7bfee634f99a940648de58c8 (diff) | |
download | linux-3.10-0300b3321d9ed73a0c3f575f2df250c577852356.tar.gz linux-3.10-0300b3321d9ed73a0c3f575f2df250c577852356.tar.bz2 linux-3.10-0300b3321d9ed73a0c3f575f2df250c577852356.zip |
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')
-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 6d4cc684afa..9d3f3357b6e 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -3177,6 +3177,21 @@ static int airo_thread(void *data) { return 0; } +static int header_len(__le16 ctl) +{ + u16 fc = le16_to_cpu(ctl); + switch (fc & 0xc) { + case 4: + if ((fc & 0xe0) == 0xc0) + return 10; /* one-address control packet */ + return 16; /* two-address control packet */ + case 8: + if ((fc & 0x300) == 0x300) + return 30; /* WDS packet */ + } + return 24; +} + static irqreturn_t airo_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; @@ -3330,23 +3345,8 @@ static irqreturn_t airo_interrupt(int irq, void *dev_id) goto badrx; if (test_bit(FLAG_802_11, &apriv->flags)) { - bap_read (apriv, (u16*)&fc, sizeof(fc), BAP0); - fc = le16_to_cpu(fc); - switch (fc & 0xc) { - case 4: - if ((fc & 0xe0) == 0xc0) - hdrlen = 10; - else - hdrlen = 16; - break; - case 8: - if ((fc&0x300)==0x300){ - hdrlen = 30; - break; - } - default: - hdrlen = 24; - } + bap_read (apriv, &fc, sizeof(fc), BAP0); + hdrlen = header_len(fc); } else hdrlen = ETH_ALEN * 2; @@ -3677,7 +3677,8 @@ void mpi_receive_802_11 (struct airo_info *ai) { RxFid rxd; struct sk_buff *skb = NULL; - u16 fc, len, hdrlen = 0; + u16 len, hdrlen = 0; + __le16 fc; #pragma pack(1) struct { u16 status, len; @@ -3707,23 +3708,8 @@ void mpi_receive_802_11 (struct airo_info *ai) if (len == 0) goto badrx; - memcpy ((char *)&fc, ptr, sizeof(fc)); - fc = le16_to_cpu(fc); - switch (fc & 0xc) { - case 4: - if ((fc & 0xe0) == 0xc0) - hdrlen = 10; - else - hdrlen = 16; - break; - case 8: - if ((fc&0x300)==0x300){ - hdrlen = 30; - break; - } - default: - hdrlen = 24; - } + fc = get_unaligned((__le16 *)ptr); + hdrlen = header_len(fc); skb = dev_alloc_skb( len + hdrlen + 2 ); if ( !skb ) { @@ -4370,22 +4356,8 @@ static int transmit_802_11_packet(struct airo_info *ai, int len, char *pPacket) u16 txFid = len; len >>= 16; - fc = le16_to_cpu(*(const u16*)pPacket); - switch (fc & 0xc) { - case 4: - if ((fc & 0xe0) == 0xc0) - hdrlen = 10; - else - hdrlen = 16; - break; - case 8: - if ((fc&0x300)==0x300){ - hdrlen = 30; - break; - } - default: - hdrlen = 24; - } + fc = *(__le16*)pPacket; + hdrlen = header_len(fc); if (len < hdrlen) { airo_print_warn(ai->dev->name, "Short packet %d", len); |