Commit 0300b332 authored by Al Viro's avatar Al Viro Committed by David S. Miller

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: default avatarAl Viro <viro@zeniv.linux.org.uk>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 851b3e5e
...@@ -3177,6 +3177,21 @@ static int airo_thread(void *data) { ...@@ -3177,6 +3177,21 @@ static int airo_thread(void *data) {
return 0; 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) static irqreturn_t airo_interrupt(int irq, void *dev_id)
{ {
struct net_device *dev = dev_id; struct net_device *dev = dev_id;
...@@ -3330,23 +3345,8 @@ static irqreturn_t airo_interrupt(int irq, void *dev_id) ...@@ -3330,23 +3345,8 @@ static irqreturn_t airo_interrupt(int irq, void *dev_id)
goto badrx; goto badrx;
if (test_bit(FLAG_802_11, &apriv->flags)) { if (test_bit(FLAG_802_11, &apriv->flags)) {
bap_read (apriv, (u16*)&fc, sizeof(fc), BAP0); bap_read (apriv, &fc, sizeof(fc), BAP0);
fc = le16_to_cpu(fc); hdrlen = header_len(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;
}
} else } else
hdrlen = ETH_ALEN * 2; hdrlen = ETH_ALEN * 2;
...@@ -3677,7 +3677,8 @@ void mpi_receive_802_11 (struct airo_info *ai) ...@@ -3677,7 +3677,8 @@ void mpi_receive_802_11 (struct airo_info *ai)
{ {
RxFid rxd; RxFid rxd;
struct sk_buff *skb = NULL; struct sk_buff *skb = NULL;
u16 fc, len, hdrlen = 0; u16 len, hdrlen = 0;
__le16 fc;
#pragma pack(1) #pragma pack(1)
struct { struct {
u16 status, len; u16 status, len;
...@@ -3707,23 +3708,8 @@ void mpi_receive_802_11 (struct airo_info *ai) ...@@ -3707,23 +3708,8 @@ void mpi_receive_802_11 (struct airo_info *ai)
if (len == 0) if (len == 0)
goto badrx; goto badrx;
memcpy ((char *)&fc, ptr, sizeof(fc)); fc = get_unaligned((__le16 *)ptr);
fc = le16_to_cpu(fc); hdrlen = header_len(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;
}
skb = dev_alloc_skb( len + hdrlen + 2 ); skb = dev_alloc_skb( len + hdrlen + 2 );
if ( !skb ) { if ( !skb ) {
...@@ -4370,22 +4356,8 @@ static int transmit_802_11_packet(struct airo_info *ai, int len, char *pPacket) ...@@ -4370,22 +4356,8 @@ static int transmit_802_11_packet(struct airo_info *ai, int len, char *pPacket)
u16 txFid = len; u16 txFid = len;
len >>= 16; len >>= 16;
fc = le16_to_cpu(*(const u16*)pPacket); fc = *(__le16*)pPacket;
switch (fc & 0xc) { hdrlen = header_len(fc);
case 4:
if ((fc & 0xe0) == 0xc0)
hdrlen = 10;
else
hdrlen = 16;
break;
case 8:
if ((fc&0x300)==0x300){
hdrlen = 30;
break;
}
default:
hdrlen = 24;
}
if (len < hdrlen) { if (len < hdrlen) {
airo_print_warn(ai->dev->name, "Short packet %d", len); airo_print_warn(ai->dev->name, "Short packet %d", len);
......
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