airo: sanitize handling of WepKeyRid
[safe/jmp/linux-2.6] / drivers / net / wireless / airo.c
index d8948bf..8eac7fb 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/crypto.h>
 #include <asm/io.h>
 #include <asm/system.h>
+#include <asm/unaligned.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -500,21 +501,21 @@ typedef struct {
 /* This structure came from an email sent to me from an engineer at
    aironet for inclusion into this driver */
 typedef struct {
-       u16 len;
-       u16 kindex;
+       __le16 len;
+       __le16 kindex;
        u8 mac[ETH_ALEN];
-       u16 klen;
+       __le16 klen;
        u8 key[16];
 } WepKeyRid;
 
 /* These structures are from the Aironet's PC4500 Developers Manual */
 typedef struct {
-       u16 len;
+       __le16 len;
        u8 ssid[32];
 } Ssid;
 
 typedef struct {
-       u16 len;
+       __le16 len;
        Ssid ssids[3];
 } SsidRid;
 
@@ -748,39 +749,39 @@ typedef struct {
 
 /* Only present on firmware >= 5.30.17 */
 typedef struct {
-  u16 unknown[4];
+  __le16 unknown[4];
   u8 fixed[12]; /* WLAN management frame */
   u8 iep[624];
 } BSSListRidExtra;
 
 typedef struct {
-  u16 len;
-  u16 index; /* First is 0 and 0xffff means end of list */
+  __le16 len;
+  __le16 index; /* First is 0 and 0xffff means end of list */
 #define RADIO_FH 1 /* Frequency hopping radio type */
 #define RADIO_DS 2 /* Direct sequence radio type */
 #define RADIO_TMA 4 /* Proprietary radio used in old cards (2500) */
-  u16 radioType;
+  __le16 radioType;
   u8 bssid[ETH_ALEN]; /* Mac address of the BSS */
   u8 zero;
   u8 ssidLen;
   u8 ssid[32];
-  u16 dBm;
-#define CAP_ESS (1<<0)
-#define CAP_IBSS (1<<1)
-#define CAP_PRIVACY (1<<4)
-#define CAP_SHORTHDR (1<<5)
-  u16 cap;
-  u16 beaconInterval;
+  __le16 dBm;
+#define CAP_ESS cpu_to_le16(1<<0)
+#define CAP_IBSS cpu_to_le16(1<<1)
+#define CAP_PRIVACY cpu_to_le16(1<<4)
+#define CAP_SHORTHDR cpu_to_le16(1<<5)
+  __le16 cap;
+  __le16 beaconInterval;
   u8 rates[8]; /* Same as rates for config rid */
   struct { /* For frequency hopping only */
-    u16 dwell;
+    __le16 dwell;
     u8 hopSet;
     u8 hopPattern;
     u8 hopIndex;
     u8 fill;
   } fh;
-  u16 dsChannel;
-  u16 atimWindow;
+  __le16 dsChannel;
+  __le16 atimWindow;
 
   /* Only present on firmware >= 5.30.17 */
   BSSListRidExtra extra;
@@ -811,7 +812,7 @@ typedef struct {
 } MICRid;
 
 typedef struct {
-       u16 typelen;
+       __be16 typelen;
 
        union {
            u8 snap[8];
@@ -823,8 +824,8 @@ typedef struct {
                u8 fieldtype[2];
            } llc;
        } u;
-       u32 mic;
-       u32 seq;
+       __be32 mic;
+       __be32 seq;
 } MICBuffer;
 
 typedef struct {
@@ -943,7 +944,7 @@ typedef struct {
        int position;   // current position (byte offset) in message
        union {
                u8  d8[4];
-               u32 d32;
+               __be32 d32;
        } part; // saves partial message word across update() calls
 } emmh32_context;
 
@@ -1100,11 +1101,11 @@ static void enable_interrupts(struct airo_info*);
 static void disable_interrupts(struct airo_info*);
 static u16 issuecommand(struct airo_info*, Cmd *pCmd, Resp *pRsp);
 static int bap_setup(struct airo_info*, u16 rid, u16 offset, int whichbap);
-static int aux_bap_read(struct airo_info*, u16 *pu16Dst, int bytelen,
+static int aux_bap_read(struct airo_info*, __le16 *pu16Dst, int bytelen,
                        int whichbap);
-static int fast_bap_read(struct airo_info*, u16 *pu16Dst, int bytelen,
+static int fast_bap_read(struct airo_info*, __le16 *pu16Dst, int bytelen,
                         int whichbap);
-static int bap_write(struct airo_info*, const u16 *pu16Src, int bytelen,
+static int bap_write(struct airo_info*, const __le16 *pu16Src, int bytelen,
                     int whichbap);
 static int PC4500_accessrid(struct airo_info*, u16 rid, u16 accmd);
 static int PC4500_readrid(struct airo_info*, u16 rid, void *pBuf, int len, int lock);
@@ -1187,7 +1188,7 @@ struct airo_info {
 #define JOB_WSTATS     8
 #define JOB_SCAN_RESULTS  9
        unsigned long jobs;
-       int (*bap_read)(struct airo_info*, u16 *pu16Dst, int bytelen,
+       int (*bap_read)(struct airo_info*, __le16 *pu16Dst, int bytelen,
                        int whichbap);
        unsigned short *flash;
        tdsRssiEntry *rssi;
@@ -1235,8 +1236,9 @@ struct airo_info {
        BSSListElement *networks;
 };
 
-static inline int bap_read(struct airo_info *ai, u16 *pu16Dst, int bytelen,
-                          int whichbap) {
+static inline int bap_read(struct airo_info *ai, __le16 *pu16Dst, int bytelen,
+                          int whichbap)
+{
        return ai->bap_read(ai, pu16Dst, bytelen, whichbap);
 }
 
@@ -1635,7 +1637,7 @@ static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen,
                crypto_cipher_encrypt_one(tfm, plain, plain);
                cipher = plain;
                for (j = 0; (j < 16) && (i < ARRAY_SIZE(context->coeff)); ) {
-                       context->coeff[i++] = ntohl(*(u32 *)&cipher[j]);
+                       context->coeff[i++] = ntohl(*(__be32 *)&cipher[j]);
                        j += 4;
                }
        }
@@ -1668,12 +1670,12 @@ static void emmh32_update(emmh32_context *context, u8 *pOctets, int len)
                        context->position++;
                        len--;
                } while (byte_position < 4);
-               MIC_ACCUM(htonl(context->part.d32));
+               MIC_ACCUM(ntohl(context->part.d32));
        }
 
        /* deal with full 32-bit words */
        while (len >= 4) {
-               MIC_ACCUM(htonl(*(u32 *)pOctets));
+               MIC_ACCUM(ntohl(*(__be32 *)pOctets));
                context->position += 4;
                pOctets += 4;
                len -= 4;
@@ -1706,7 +1708,7 @@ static void emmh32_final(emmh32_context *context, u8 digest[4])
        byte_position = context->position & 3;
        if (byte_position) {
                /* have a partial word in part to deal with */
-               val = htonl(context->part.d32);
+               val = ntohl(context->part.d32);
                MIC_ACCUM(val & mask32[byte_position]); /* zero empty bytes */
        }
 
@@ -1726,8 +1728,8 @@ static void emmh32_final(emmh32_context *context, u8 digest[4])
 }
 
 static int readBSSListRid(struct airo_info *ai, int first,
-                     BSSListRid *list) {
-       int rc;
+                     BSSListRid *list)
+{
        Cmd cmd;
        Resp rsp;
 
@@ -1744,72 +1746,40 @@ static int readBSSListRid(struct airo_info *ai, int first,
                schedule_timeout_uninterruptible(3 * HZ);
                ai->list_bss_task = NULL;
        }
-       rc = PC4500_readrid(ai, first ? ai->bssListFirst : ai->bssListNext,
+       return PC4500_readrid(ai, first ? ai->bssListFirst : ai->bssListNext,
                            list, ai->bssListRidLen, 1);
-
-       list->len = le16_to_cpu(list->len);
-       list->index = le16_to_cpu(list->index);
-       list->radioType = le16_to_cpu(list->radioType);
-       list->cap = le16_to_cpu(list->cap);
-       list->beaconInterval = le16_to_cpu(list->beaconInterval);
-       list->fh.dwell = le16_to_cpu(list->fh.dwell);
-       list->dsChannel = le16_to_cpu(list->dsChannel);
-       list->atimWindow = le16_to_cpu(list->atimWindow);
-       list->dBm = le16_to_cpu(list->dBm);
-       return rc;
 }
 
-static int readWepKeyRid(struct airo_info*ai, WepKeyRid *wkr, int temp, int lock) {
-       int rc = PC4500_readrid(ai, temp ? RID_WEP_TEMP : RID_WEP_PERM,
+static int readWepKeyRid(struct airo_info *ai, WepKeyRid *wkr, int temp, int lock)
+{
+       return PC4500_readrid(ai, temp ? RID_WEP_TEMP : RID_WEP_PERM,
                                wkr, sizeof(*wkr), lock);
-
-       wkr->len = le16_to_cpu(wkr->len);
-       wkr->kindex = le16_to_cpu(wkr->kindex);
-       wkr->klen = le16_to_cpu(wkr->klen);
-       return rc;
 }
-/* In the writeXXXRid routines we copy the rids so that we don't screwup
- * the originals when we endian them... */
-static int writeWepKeyRid(struct airo_info*ai, WepKeyRid *pwkr, int perm, int lock) {
-       int rc;
-       WepKeyRid wkr = *pwkr;
 
-       wkr.len = cpu_to_le16(wkr.len);
-       wkr.kindex = cpu_to_le16(wkr.kindex);
-       wkr.klen = cpu_to_le16(wkr.klen);
-       rc = PC4500_writerid(ai, RID_WEP_TEMP, &wkr, sizeof(wkr), lock);
-       if (rc!=SUCCESS) airo_print_err(ai->dev->name, "WEP_TEMP set %x", rc);
+static int writeWepKeyRid(struct airo_info *ai, WepKeyRid *wkr, int perm, int lock)
+{
+       int rc;
+       rc = PC4500_writerid(ai, RID_WEP_TEMP, wkr, sizeof(*wkr), lock);
+       if (rc!=SUCCESS)
+               airo_print_err(ai->dev->name, "WEP_TEMP set %x", rc);
        if (perm) {
-               rc = PC4500_writerid(ai, RID_WEP_PERM, &wkr, sizeof(wkr), lock);
-               if (rc!=SUCCESS) {
+               rc = PC4500_writerid(ai, RID_WEP_PERM, wkr, sizeof(*wkr), lock);
+               if (rc!=SUCCESS)
                        airo_print_err(ai->dev->name, "WEP_PERM set %x", rc);
-               }
        }
        return rc;
 }
 
-static int readSsidRid(struct airo_info*ai, SsidRid *ssidr) {
-       int i;
-       int rc = PC4500_readrid(ai, RID_SSID, ssidr, sizeof(*ssidr), 1);
-
-       ssidr->len = le16_to_cpu(ssidr->len);
-       for(i = 0; i < 3; i++) {
-               ssidr->ssids[i].len = le16_to_cpu(ssidr->ssids[i].len);
-       }
-       return rc;
+static int readSsidRid(struct airo_info*ai, SsidRid *ssidr)
+{
+       return PC4500_readrid(ai, RID_SSID, ssidr, sizeof(*ssidr), 1);
 }
-static int writeSsidRid(struct airo_info*ai, SsidRid *pssidr, int lock) {
-       int rc;
-       int i;
-       SsidRid ssidr = *pssidr;
 
-       ssidr.len = cpu_to_le16(ssidr.len);
-       for(i = 0; i < 3; i++) {
-               ssidr.ssids[i].len = cpu_to_le16(ssidr.ssids[i].len);
-       }
-       rc = PC4500_writerid(ai, RID_SSID, &ssidr, sizeof(ssidr), lock);
-       return rc;
+static int writeSsidRid(struct airo_info*ai, SsidRid *pssidr, int lock)
+{
+       return PC4500_writerid(ai, RID_SSID, pssidr, sizeof(*pssidr), lock);
 }
+
 static int readConfigRid(struct airo_info*ai, int lock) {
        int rc;
        u16 *s;
@@ -2026,13 +1996,14 @@ static int mpi_send_packet (struct net_device *dev)
 {
        struct sk_buff *skb;
        unsigned char *buffer;
-       s16 len, *payloadLen;
+       s16 len;
+       __le16 *payloadLen;
        struct airo_info *ai = dev->priv;
        u8 *sendbuf;
 
        /* get a packet to send */
 
-       if ((skb = skb_dequeue(&ai->txq)) == 0) {
+       if ((skb = skb_dequeue(&ai->txq)) == NULL) {
                airo_print_err(dev->name,
                        "%s: Dequeue'd zero in send_packet()",
                        __FUNCTION__);
@@ -2059,7 +2030,7 @@ static int mpi_send_packet (struct net_device *dev)
        memcpy((char *)ai->txfids[0].virtual_host_addr,
                (char *)&wifictlhdr8023, sizeof(wifictlhdr8023));
 
-       payloadLen = (s16 *)(ai->txfids[0].virtual_host_addr +
+       payloadLen = (__le16 *)(ai->txfids[0].virtual_host_addr +
                sizeof(wifictlhdr8023));
        sendbuf = ai->txfids[0].virtual_host_addr +
                sizeof(wifictlhdr8023) + 2 ;
@@ -2069,7 +2040,7 @@ static int mpi_send_packet (struct net_device *dev)
         * we don't need to account for it in the length
         */
        if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled &&
-               (ntohs(((u16 *)buffer)[6]) != 0x888E)) {
+               (ntohs(((__be16 *)buffer)[6]) != 0x888E)) {
                MICBuffer pMic;
 
                if (encapsulate(ai, (etherHead *)buffer, &pMic, len - sizeof(etherHead)) != SUCCESS)
@@ -2104,7 +2075,7 @@ static int mpi_send_packet (struct net_device *dev)
 
 static void get_tx_error(struct airo_info *ai, s32 fid)
 {
-       u16 status;
+       __le16 status;
 
        if (fid < 0)
                status = ((WifiCtlHdr *)ai->txfids[0].virtual_host_addr)->ctlhdr.status;
@@ -2135,7 +2106,7 @@ static void get_tx_error(struct airo_info *ai, s32 fid)
                /* Faster to skip over useless data than to do
                 * another bap_setup(). We are at offset 0x6 and
                 * need to go to 0x18 and read 6 bytes - Jean II */
-               bap_read(ai, (u16 *) junk, 0x18, BAP0);
+               bap_read(ai, (__le16 *) junk, 0x18, BAP0);
 
                /* Copy 802.11 dest address.
                 * We use the 802.11 header because the frame may
@@ -3037,14 +3008,14 @@ static void airo_process_scan_results (struct airo_info *ai) {
 
        /* Try to read the first entry of the scan result */
        rc = PC4500_readrid(ai, ai->bssListFirst, &bss, ai->bssListRidLen, 0);
-       if((rc) || (bss.index == 0xffff)) {
+       if((rc) || (bss.index == cpu_to_le16(0xffff))) {
                /* No scan results */
                goto out;
        }
 
        /* Read and parse all entries */
        tmp_net = NULL;
-       while((!rc) && (bss.index != 0xffff)) {
+       while((!rc) && (bss.index != cpu_to_le16(0xffff))) {
                /* Grab a network off the free list */
                if (!list_empty(&ai->network_free_list)) {
                        tmp_net = list_entry(ai->network_free_list.next,
@@ -3177,6 +3148,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;
@@ -3282,19 +3268,20 @@ static irqreturn_t airo_interrupt(int irq, void *dev_id)
                /* Check to see if there is something to receive */
                if ( status & EV_RX  ) {
                        struct sk_buff *skb = NULL;
-                       u16 fc, len, hdrlen = 0;
+                       __le16 fc, v;
+                       u16 len, hdrlen = 0;
 #pragma pack(1)
                        struct {
-                               u16 status, len;
+                               __le16 status, len;
                                u8 rssi[2];
                                u8 rate;
                                u8 freq;
-                               u16 tmp[4];
+                               __le16 tmp[4];
                        } hdr;
 #pragma pack()
                        u16 gap;
-                       u16 tmpbuf[4];
-                       u16 *buffer;
+                       __le16 tmpbuf[4];
+                       __le16 *buffer;
 
                        if (test_bit(FLAG_MPI,&apriv->flags)) {
                                if (test_bit(FLAG_802_11, &apriv->flags))
@@ -3310,7 +3297,7 @@ static irqreturn_t airo_interrupt(int irq, void *dev_id)
                        /* Get the packet length */
                        if (test_bit(FLAG_802_11, &apriv->flags)) {
                                bap_setup (apriv, fid, 4, BAP0);
-                               bap_read (apriv, (u16*)&hdr, sizeof(hdr), BAP0);
+                               bap_read (apriv, (__le16*)&hdr, sizeof(hdr), BAP0);
                                /* Bad CRC. Ignore packet */
                                if (le16_to_cpu(hdr.status) & 2)
                                        hdr.len = 0;
@@ -3318,7 +3305,7 @@ static irqreturn_t airo_interrupt(int irq, void *dev_id)
                                        hdr.len = 0;
                        } else {
                                bap_setup (apriv, fid, 0x36, BAP0);
-                               bap_read (apriv, (u16*)&hdr.len, 2, BAP0);
+                               bap_read (apriv, &hdr.len, 2, BAP0);
                        }
                        len = le16_to_cpu(hdr.len);
 
@@ -3330,23 +3317,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;
 
@@ -3356,15 +3328,15 @@ static irqreturn_t airo_interrupt(int irq, void *dev_id)
                                goto badrx;
                        }
                        skb_reserve(skb, 2); /* This way the IP header is aligned */
-                       buffer = (u16*)skb_put (skb, len + hdrlen);
+                       buffer = (__le16*)skb_put (skb, len + hdrlen);
                        if (test_bit(FLAG_802_11, &apriv->flags)) {
                                buffer[0] = fc;
                                bap_read (apriv, buffer + 1, hdrlen - 2, BAP0);
                                if (hdrlen == 24)
                                        bap_read (apriv, tmpbuf, 6, BAP0);
 
-                               bap_read (apriv, &gap, sizeof(gap), BAP0);
-                               gap = le16_to_cpu(gap);
+                               bap_read (apriv, &v, sizeof(v), BAP0);
+                               gap = le16_to_cpu(v);
                                if (gap) {
                                        if (gap <= 8) {
                                                bap_read (apriv, tmpbuf, gap, BAP0);
@@ -3378,7 +3350,7 @@ static irqreturn_t airo_interrupt(int irq, void *dev_id)
                                MICBuffer micbuf;
                                bap_read (apriv, buffer, ETH_ALEN*2, BAP0);
                                if (apriv->micstats.enabled) {
-                                       bap_read (apriv,(u16*)&micbuf,sizeof(micbuf),BAP0);
+                                       bap_read (apriv,(__le16*)&micbuf,sizeof(micbuf),BAP0);
                                        if (ntohs(micbuf.typelen) > 0x05DC)
                                                bap_setup (apriv, fid, 0x44, BAP0);
                                        else {
@@ -3406,7 +3378,7 @@ badrx:
                                if (!test_bit(FLAG_802_11, &apriv->flags)) {
                                        sa = (char*)buffer + 6;
                                        bap_setup (apriv, fid, 8, BAP0);
-                                       bap_read (apriv, (u16*)hdr.rssi, 2, BAP0);
+                                       bap_read (apriv, (__le16*)hdr.rssi, 2, BAP0);
                                } else
                                        sa = (char*)buffer + 10;
                                wstats.qual = hdr.rssi[0];
@@ -3677,14 +3649,15 @@ 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;
+               __le16 status, len;
                u8 rssi[2];
                u8 rate;
                u8 freq;
-               u16 tmp[4];
+               __le16 tmp[4];
        } hdr;
 #pragma pack()
        u16 gap;
@@ -3707,23 +3680,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 ) {
@@ -3735,9 +3693,8 @@ void mpi_receive_802_11 (struct airo_info *ai)
        ptr += hdrlen;
        if (hdrlen == 24)
                ptr += 6;
-       memcpy ((char *)&gap, ptr, sizeof(gap));
-       ptr += sizeof(gap);
-       gap = le16_to_cpu(gap);
+       gap = le16_to_cpu(get_unaligned((__le16 *)ptr));
+       ptr += sizeof(__le16);
        if (gap) {
                if (gap <= 8)
                        ptr += gap;
@@ -3789,7 +3746,7 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
        int status;
        int i;
        SsidRid mySsid;
-       u16 lastindex;
+       __le16 lastindex;
        WepKeyRid wkr;
        int rc;
 
@@ -3861,7 +3818,8 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
                ai->config.authType = AUTH_OPEN;
                ai->config.modulation = MOD_CCK;
 
-               if ((cap_rid.len>=sizeof(cap_rid)) && (cap_rid.extSoftCap&1) &&
+               if ((cap_rid.len>=sizeof(cap_rid)) &&
+                   (cap_rid.extSoftCap & cpu_to_le16(1)) &&
                    (micsetup(ai) == SUCCESS)) {
                        ai->config.opmode |= MODE_MIC;
                        set_bit(FLAG_MIC_CAPABLE, &ai->flags);
@@ -3898,13 +3856,13 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
        if ( ssids[0] ) {
                int i;
                for( i = 0; i < 3 && ssids[i]; i++ ) {
-                       mySsid.ssids[i].len = strlen(ssids[i]);
-                       if ( mySsid.ssids[i].len > 32 )
-                               mySsid.ssids[i].len = 32;
-                       memcpy(mySsid.ssids[i].ssid, ssids[i],
-                              mySsid.ssids[i].len);
+                       size_t len = strlen(ssids[i]);
+                       if (len > 32)
+                               len = 32;
+                       mySsid.ssids[i].len = cpu_to_le16(len);
+                       memcpy(mySsid.ssids[i].ssid, ssids[i], len);
                }
-               mySsid.len = sizeof(mySsid);
+               mySsid.len = cpu_to_le16(sizeof(mySsid));
        }
 
        status = writeConfigRid(ai, lock);
@@ -3924,7 +3882,7 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
        rc = readWepKeyRid(ai, &wkr, 1, lock);
        if (rc == SUCCESS) do {
                lastindex = wkr.kindex;
-               if (wkr.kindex == 0xffff) {
+               if (wkr.kindex == cpu_to_le16(0xffff)) {
                        ai->defindex = wkr.mac[0];
                }
                rc = readWepKeyRid(ai, &wkr, 0, lock);
@@ -4039,7 +3997,7 @@ static u16 aux_setup(struct airo_info *ai, u16 page,
 }
 
 /* requires call to bap_setup() first */
-static int aux_bap_read(struct airo_info *ai, u16 *pu16Dst,
+static int aux_bap_read(struct airo_info *ai, __le16 *pu16Dst,
                        int bytelen, int whichbap)
 {
        u16 len;
@@ -4076,7 +4034,7 @@ static int aux_bap_read(struct airo_info *ai, u16 *pu16Dst,
 
 
 /* requires call to bap_setup() first */
-static int fast_bap_read(struct airo_info *ai, u16 *pu16Dst,
+static int fast_bap_read(struct airo_info *ai, __le16 *pu16Dst,
                         int bytelen, int whichbap)
 {
        bytelen = (bytelen + 1) & (~1); // round up to even value
@@ -4088,7 +4046,7 @@ static int fast_bap_read(struct airo_info *ai, u16 *pu16Dst,
 }
 
 /* requires call to bap_setup() first */
-static int bap_write(struct airo_info *ai, const u16 *pu16Src,
+static int bap_write(struct airo_info *ai, const __le16 *pu16Src,
                     int bytelen, int whichbap)
 {
        bytelen = (bytelen + 1) & (~1); // round up to even value
@@ -4164,7 +4122,7 @@ static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len, in
                // read the rid length field
                bap_read(ai, pBuf, 2, BAP1);
                // length for remaining part of rid
-               len = min(len, (int)le16_to_cpu(*(u16*)pBuf)) - 2;
+               len = min(len, (int)le16_to_cpu(*(__le16*)pBuf)) - 2;
 
                if ( len <= 2 ) {
                        airo_print_err(ai->dev->name,
@@ -4174,7 +4132,7 @@ static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len, in
                        goto done;
                }
                // read remainder of the rid
-               rc = bap_read(ai, ((u16*)pBuf)+1, len, BAP1);
+               rc = bap_read(ai, ((__le16*)pBuf)+1, len, BAP1);
        }
 done:
        if (lock)
@@ -4190,7 +4148,7 @@ static int PC4500_writerid(struct airo_info *ai, u16 rid,
        u16 status;
        int rc = SUCCESS;
 
-       *(u16*)pBuf = cpu_to_le16((u16)len);
+       *(__le16*)pBuf = cpu_to_le16((u16)len);
 
        if (lock) {
                if (down_interruptible(&ai->sem))
@@ -4264,7 +4222,7 @@ static u16 transmit_allocate(struct airo_info *ai, int lenPayload, int raw)
        Cmd cmd;
        Resp rsp;
        u16 txFid;
-       u16 txControl;
+       __le16 txControl;
 
        cmd.cmd = CMD_ALLOCATETX;
        cmd.parm0 = lenPayload;
@@ -4318,7 +4276,7 @@ done:
    Make sure the BAP1 spinlock is held when this is called. */
 static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket)
 {
-       u16 payloadLen;
+       __le16 payloadLen;
        Cmd cmd;
        Resp rsp;
        int miclen = 0;
@@ -4334,7 +4292,7 @@ static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket)
        len -= ETH_ALEN * 2;
 
        if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled && 
-           (ntohs(((u16 *)pPacket)[6]) != 0x888E)) {
+           (ntohs(((__be16 *)pPacket)[6]) != 0x888E)) {
                if (encapsulate(ai,(etherHead *)pPacket,&pMic,len) != SUCCESS)
                        return ERROR;
                miclen = sizeof(pMic);
@@ -4346,10 +4304,10 @@ static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket)
         * we have to subtract the 12 bytes for the addresses off */
        payloadLen = cpu_to_le16(len + miclen);
        bap_write(ai, &payloadLen, sizeof(payloadLen),BAP1);
-       bap_write(ai, (const u16*)pPacket, sizeof(etherHead), BAP1);
+       bap_write(ai, (__le16*)pPacket, sizeof(etherHead), BAP1);
        if (miclen)
-               bap_write(ai, (const u16*)&pMic, miclen, BAP1);
-       bap_write(ai, (const u16*)(pPacket + sizeof(etherHead)), len, BAP1);
+               bap_write(ai, (__le16*)&pMic, miclen, BAP1);
+       bap_write(ai, (__le16*)(pPacket + sizeof(etherHead)), len, BAP1);
        // issue the transmit command
        memset( &cmd, 0, sizeof( cmd ) );
        cmd.cmd = CMD_TRANSMIT;
@@ -4361,35 +4319,17 @@ static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket)
 
 static int transmit_802_11_packet(struct airo_info *ai, int len, char *pPacket)
 {
-       u16 fc, payloadLen;
+       __le16 fc, payloadLen;
        Cmd cmd;
        Resp rsp;
        int hdrlen;
-       struct {
-               u8 addr4[ETH_ALEN];
-               u16 gaplen;
-               u8 gap[6];
-       } gap;
+       static u8 tail[(30-10) + 2 + 6] = {[30-10] = 6};
+       /* padding of header to full size + le16 gaplen (6) + gaplen bytes */
        u16 txFid = len;
        len >>= 16;
-       gap.gaplen = 6;
 
-       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);
@@ -4404,11 +4344,10 @@ static int transmit_802_11_packet(struct airo_info *ai, int len, char *pPacket)
        payloadLen = cpu_to_le16(len-hdrlen);
        bap_write(ai, &payloadLen, sizeof(payloadLen),BAP1);
        if (bap_setup(ai, txFid, 0x0014, BAP1) != SUCCESS) return ERROR;
-       bap_write(ai, (const u16*)pPacket, hdrlen, BAP1);
-       bap_write(ai, hdrlen == 30 ?
-               (const u16*)&gap.gaplen : (const u16*)&gap, 38 - hdrlen, BAP1);
+       bap_write(ai, (__le16 *)pPacket, hdrlen, BAP1);
+       bap_write(ai, (__le16 *)(tail + (hdrlen - 10)), 38 - hdrlen, BAP1);
 
-       bap_write(ai, (const u16*)(pPacket + hdrlen), len - hdrlen, BAP1);
+       bap_write(ai, (__le16 *)(pPacket + hdrlen), len - hdrlen, BAP1);
        // issue the transmit command
        memset( &cmd, 0, sizeof( cmd ) );
        cmd.cmd = CMD_TRANSMIT;
@@ -5154,34 +5093,38 @@ static int proc_config_open( struct inode *inode, struct file *file ) {
        return 0;
 }
 
-static void proc_SSID_on_close( struct inode *inode, struct file *file ) {
+static void proc_SSID_on_close(struct inode *inode, struct file *file)
+{
        struct proc_data *data = (struct proc_data *)file->private_data;
        struct proc_dir_entry *dp = PDE(inode);
        struct net_device *dev = dp->data;
        struct airo_info *ai = dev->priv;
        SsidRid SSID_rid;
        int i;
-       int offset = 0;
+       char *p = data->wbuffer;
+       char *end = p + data->writelen;
 
-       if ( !data->writelen ) return;
+       if (!data->writelen)
+               return;
 
-       memset( &SSID_rid, 0, sizeof( SSID_rid ) );
+       *end = '\n'; /* sentinel; we have space for it */
 
-       for( i = 0; i < 3; i++ ) {
-               int j;
-               for( j = 0; j+offset < data->writelen && j < 32 &&
-                            data->wbuffer[offset+j] != '\n'; j++ ) {
-                       SSID_rid.ssids[i].ssid[j] = data->wbuffer[offset+j];
-               }
-               if ( j == 0 ) break;
-               SSID_rid.ssids[i].len = j;
-               offset += j;
-               while( data->wbuffer[offset] != '\n' &&
-                      offset < data->writelen ) offset++;
-               offset++;
+       memset(&SSID_rid, 0, sizeof(SSID_rid));
+
+       for (i = 0; i < 3 && p < end; i++) {
+               int j = 0;
+               /* copy up to 32 characters from this line */
+               while (*p != '\n' && j < 32)
+                       SSID_rid.ssids[i].ssid[j++] = *p++;
+               if (j == 0)
+                       break;
+               SSID_rid.ssids[i].len = cpu_to_le16(j);
+               /* skip to the beginning of the next line */
+               while (*p++ != '\n')
+                       ;
        }
        if (i)
-               SSID_rid.len = sizeof(SSID_rid);
+               SSID_rid.len = cpu_to_le16(sizeof(SSID_rid));
        disable_MAC(ai, 1);
        writeSsidRid(ai, &SSID_rid, 1);
        enable_MAC(ai, 1);
@@ -5245,39 +5188,40 @@ static int do_writerid( struct airo_info *ai, u16 rid, const void *rid_data,
 static int get_wep_key(struct airo_info *ai, u16 index) {
        WepKeyRid wkr;
        int rc;
-       u16 lastindex;
+       __le16 lastindex;
 
        rc = readWepKeyRid(ai, &wkr, 1, 1);
        if (rc == SUCCESS) do {
                lastindex = wkr.kindex;
-               if (wkr.kindex == index) {
+               if (wkr.kindex == cpu_to_le16(index)) {
                        if (index == 0xffff) {
                                return wkr.mac[0];
                        }
-                       return wkr.klen;
+                       return le16_to_cpu(wkr.klen);
                }
                readWepKeyRid(ai, &wkr, 0, 1);
-       } while(lastindex != wkr.kindex);
+       } while (lastindex != wkr.kindex);
        return -1;
 }
 
 static int set_wep_key(struct airo_info *ai, u16 index,
-                      const char *key, u16 keylen, int perm, int lock ) {
+                      const char *key, u16 keylen, int perm, int lock )
+{
        static const unsigned char macaddr[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 };
        WepKeyRid wkr;
 
        memset(&wkr, 0, sizeof(wkr));
        if (keylen == 0) {
 // We are selecting which key to use
-               wkr.len = sizeof(wkr);
-               wkr.kindex = 0xffff;
+               wkr.len = cpu_to_le16(sizeof(wkr));
+               wkr.kindex = cpu_to_le16(0xffff);
                wkr.mac[0] = (char)index;
                if (perm) ai->defindex = (char)index;
        } else {
 // We are actually setting the key
-               wkr.len = sizeof(wkr);
-               wkr.kindex = index;
-               wkr.klen = keylen;
+               wkr.len = cpu_to_le16(sizeof(wkr));
+               wkr.kindex = cpu_to_le16(index);
+               wkr.klen = cpu_to_le16(keylen);
                memcpy( wkr.key, key, keylen );
                memcpy( wkr.mac, macaddr, ETH_ALEN );
        }
@@ -5329,14 +5273,15 @@ static void proc_wepkey_on_close( struct inode *inode, struct file *file ) {
        set_wep_key(ai, index, key, i/3, 1, 1);
 }
 
-static int proc_wepkey_open( struct inode *inode, struct file *file ) {
+static int proc_wepkey_open( struct inode *inode, struct file *file )
+{
        struct proc_data *data;
        struct proc_dir_entry *dp = PDE(inode);
        struct net_device *dev = dp->data;
        struct airo_info *ai = dev->priv;
        char *ptr;
        WepKeyRid wkr;
-       u16 lastindex;
+       __le16 lastindex;
        int j=0;
        int rc;
 
@@ -5362,12 +5307,13 @@ static int proc_wepkey_open( struct inode *inode, struct file *file ) {
        rc = readWepKeyRid(ai, &wkr, 1, 1);
        if (rc == SUCCESS) do {
                lastindex = wkr.kindex;
-               if (wkr.kindex == 0xffff) {
+               if (wkr.kindex == cpu_to_le16(0xffff)) {
                        j += sprintf(ptr+j, "Tx key = %d\n",
                                     (int)wkr.mac[0]);
                } else {
                        j += sprintf(ptr+j, "Key %d set with length = %d\n",
-                                    (int)wkr.kindex, (int)wkr.klen);
+                                    le16_to_cpu(wkr.kindex),
+                                    le16_to_cpu(wkr.klen));
                }
                readWepKeyRid(ai, &wkr, 0, 1);
        } while((lastindex != wkr.kindex) && (j < 180-30));
@@ -5376,7 +5322,8 @@ static int proc_wepkey_open( struct inode *inode, struct file *file ) {
        return 0;
 }
 
-static int proc_SSID_open( struct inode *inode, struct file *file ) {
+static int proc_SSID_open(struct inode *inode, struct file *file)
+{
        struct proc_data *data;
        struct proc_dir_entry *dp = PDE(inode);
        struct net_device *dev = dp->data;
@@ -5394,7 +5341,8 @@ static int proc_SSID_open( struct inode *inode, struct file *file ) {
        }
        data->writelen = 0;
        data->maxwritelen = 33*3;
-       if ((data->wbuffer = kzalloc( 33*3, GFP_KERNEL )) == NULL) {
+       /* allocate maxwritelen + 1; we'll want a sentinel */
+       if ((data->wbuffer = kzalloc(33*3 + 1, GFP_KERNEL)) == NULL) {
                kfree (data->rbuffer);
                kfree (file->private_data);
                return -ENOMEM;
@@ -5403,14 +5351,15 @@ static int proc_SSID_open( struct inode *inode, struct file *file ) {
 
        readSsidRid(ai, &SSID_rid);
        ptr = data->rbuffer;
-       for( i = 0; i < 3; i++ ) {
+       for (i = 0; i < 3; i++) {
                int j;
-               if ( !SSID_rid.ssids[i].len ) break;
-               for( j = 0; j < 32 &&
-                            j < SSID_rid.ssids[i].len &&
-                            SSID_rid.ssids[i].ssid[j]; j++ ) {
+               size_t len = le16_to_cpu(SSID_rid.ssids[i].len);
+               if (!len)
+                       break;
+               if (len > 32)
+                       len = 32;
+               for (j = 0; j < len && SSID_rid.ssids[i].ssid[j]; j++)
                        *ptr++ = SSID_rid.ssids[i].ssid[j];
-               }
                *ptr++ = '\n';
        }
        *ptr = '\0';
@@ -5506,14 +5455,14 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) {
            Since it is a rare condition, we'll just live with it, otherwise
            we have to add a spin lock... */
        rc = readBSSListRid(ai, doLoseSync, &BSSList_rid);
-       while(rc == 0 && BSSList_rid.index != 0xffff) {
+       while(rc == 0 && BSSList_rid.index != cpu_to_le16(0xffff)) {
                ptr += sprintf(ptr, "%s %*s rssi = %d",
                               print_mac(mac, BSSList_rid.bssid),
                                (int)BSSList_rid.ssidLen,
                                BSSList_rid.ssid,
-                               (int)BSSList_rid.dBm);
+                               le16_to_cpu(BSSList_rid.dBm));
                ptr += sprintf(ptr, " channel = %d %s %s %s %s\n",
-                               (int)BSSList_rid.dsChannel,
+                               le16_to_cpu(BSSList_rid.dsChannel),
                                BSSList_rid.cap & CAP_ESS ? "ESS" : "",
                                BSSList_rid.cap & CAP_IBSS ? "adhoc" : "",
                                BSSList_rid.cap & CAP_PRIVACY ? "wep" : "",
@@ -5926,9 +5875,9 @@ static int airo_set_essid(struct net_device *dev,
                memset(SSID_rid.ssids[index].ssid, 0,
                       sizeof(SSID_rid.ssids[index].ssid));
                memcpy(SSID_rid.ssids[index].ssid, extra, dwrq->length);
-               SSID_rid.ssids[index].len = dwrq->length;
+               SSID_rid.ssids[index].len = cpu_to_le16(dwrq->length);
        }
-       SSID_rid.len = sizeof(SSID_rid);
+       SSID_rid.len = cpu_to_le16(sizeof(SSID_rid));
        /* Write it to the card */
        disable_MAC(local, 1);
        writeSsidRid(local, &SSID_rid, 1);
@@ -6408,9 +6357,8 @@ static int airo_set_encode(struct net_device *dev,
                        set_wep_key(local, index, NULL, 0, perm, 1);
                } else
                        /* Don't complain if only change the mode */
-                       if(!(dwrq->flags & IW_ENCODE_MODE)) {
+                       if (!(dwrq->flags & IW_ENCODE_MODE))
                                return -EINVAL;
-                       }
        }
        /* Read the flags */
        if(dwrq->flags & IW_ENCODE_DISABLED)
@@ -7131,26 +7079,28 @@ static int airo_get_aplist(struct net_device *dev,
        int loseSync = capable(CAP_NET_ADMIN) ? 1: -1;
 
        for (i = 0; i < IW_MAX_AP; i++) {
+               u16 dBm;
                if (readBSSListRid(local, loseSync, &BSSList))
                        break;
                loseSync = 0;
                memcpy(address[i].sa_data, BSSList.bssid, ETH_ALEN);
                address[i].sa_family = ARPHRD_ETHER;
+               dBm = le16_to_cpu(BSSList.dBm);
                if (local->rssi) {
-                       qual[i].level = 0x100 - BSSList.dBm;
-                       qual[i].qual = airo_dbm_to_pct( local->rssi, BSSList.dBm );
+                       qual[i].level = 0x100 - dBm;
+                       qual[i].qual = airo_dbm_to_pct(local->rssi, dBm);
                        qual[i].updated = IW_QUAL_QUAL_UPDATED
                                        | IW_QUAL_LEVEL_UPDATED
                                        | IW_QUAL_DBM;
                } else {
-                       qual[i].level = (BSSList.dBm + 321) / 2;
+                       qual[i].level = (dBm + 321) / 2;
                        qual[i].qual = 0;
                        qual[i].updated = IW_QUAL_QUAL_INVALID
                                        | IW_QUAL_LEVEL_UPDATED
                                        | IW_QUAL_DBM;
                }
                qual[i].noise = local->wstats.qual.noise;
-               if (BSSList.index == 0xffff)
+               if (BSSList.index == cpu_to_le16(0xffff))
                        break;
        }
        if (!i) {
@@ -7241,10 +7191,11 @@ static inline char *airo_translate_scan(struct net_device *dev,
 {
        struct airo_info *ai = dev->priv;
        struct iw_event         iwe;            /* Temporary buffer */
-       u16                     capabilities;
+       __le16                  capabilities;
        char *                  current_val;    /* For rates */
        int                     i;
        char *          buf;
+       u16 dBm;
 
        /* First entry *MUST* be the AP MAC address */
        iwe.cmd = SIOCGIWAP;
@@ -7264,7 +7215,7 @@ static inline char *airo_translate_scan(struct net_device *dev,
 
        /* Add mode */
        iwe.cmd = SIOCGIWMODE;
-       capabilities = le16_to_cpu(bss->cap);
+       capabilities = bss->cap;
        if(capabilities & (CAP_ESS | CAP_IBSS)) {
                if(capabilities & CAP_ESS)
                        iwe.u.mode = IW_MODE_MASTER;
@@ -7283,16 +7234,18 @@ static inline char *airo_translate_scan(struct net_device *dev,
        iwe.u.freq.e = 1;
        current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN);
 
+       dBm = le16_to_cpu(bss->dBm);
+
        /* Add quality statistics */
        iwe.cmd = IWEVQUAL;
        if (ai->rssi) {
-               iwe.u.qual.level = 0x100 - bss->dBm;
-               iwe.u.qual.qual = airo_dbm_to_pct( ai->rssi, bss->dBm );
+               iwe.u.qual.level = 0x100 - dBm;
+               iwe.u.qual.qual = airo_dbm_to_pct(ai->rssi, dBm);
                iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED
                                | IW_QUAL_LEVEL_UPDATED
                                | IW_QUAL_DBM;
        } else {
-               iwe.u.qual.level = (bss->dBm + 321) / 2;
+               iwe.u.qual.level = (dBm + 321) / 2;
                iwe.u.qual.qual = 0;
                iwe.u.qual.updated = IW_QUAL_QUAL_INVALID
                                | IW_QUAL_LEVEL_UPDATED
@@ -7895,9 +7848,9 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) {
                ConfigRid *cfg = (ConfigRid *)iobuf;
 
                if (test_bit(FLAG_MIC_CAPABLE, &ai->flags))
-                       cfg->opmode |= MODE_MIC;
+                       cfg->opmode |= cpu_to_le16(MODE_MIC);
 
-               if ((cfg->opmode & 0xFF) == MODE_STA_IBSS)
+               if ((le16_to_cpu(cfg->opmode) & 0xFF) == MODE_STA_IBSS)
                        set_bit (FLAG_ADHOC, &ai->flags);
                else
                        clear_bit (FLAG_ADHOC, &ai->flags);