[PATCH] libertas: tweak association debug output
[safe/jmp/linux-2.6] / drivers / net / wireless / airo.c
index 9c577f7..2d3a180 100644 (file)
 
 ======================================================================*/
 
-#include <linux/config.h>
+#include <linux/err.h>
 #include <linux/init.h>
 
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/proc_fs.h>
-#include <linux/smp_lock.h>
 
 #include <linux/sched.h>
 #include <linux/ptrace.h>
@@ -47,6 +46,9 @@
 #include <linux/ioport.h>
 #include <linux/pci.h>
 #include <asm/uaccess.h>
+#include <net/ieee80211.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
 
 #include "airo.h"
 
@@ -467,6 +469,8 @@ static int do8bitIO = 0;
 #define RID_ECHOTEST_RESULTS 0xFF71
 #define RID_BSSLISTFIRST 0xFF72
 #define RID_BSSLISTNEXT  0xFF73
+#define RID_WPA_BSSLISTFIRST 0xFF74
+#define RID_WPA_BSSLISTNEXT  0xFF75
 
 typedef struct {
        u16 cmd;
@@ -739,6 +743,14 @@ typedef struct {
        u16 extSoftCap;
 } CapabilityRid;
 
+
+/* Only present on firmware >= 5.30.17 */
+typedef struct {
+  u16 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 */
@@ -767,9 +779,17 @@ typedef struct {
   } fh;
   u16 dsChannel;
   u16 atimWindow;
+
+  /* Only present on firmware >= 5.30.17 */
+  BSSListRidExtra extra;
 } BSSListRid;
 
 typedef struct {
+  BSSListRid bss;
+  struct list_head list;
+} BSSListElement;
+
+typedef struct {
   u8 rssipct;
   u8 rssidBm;
 } tdsRssiEntry;
@@ -902,6 +922,7 @@ static char swversion[] = "2.1";
 #define NUM_MODULES       2
 #define MIC_MSGLEN_MAX    2400
 #define EMMH32_MSGLEN_MAX MIC_MSGLEN_MAX
+#define AIRO_DEF_MTU      2312
 
 typedef struct {
        u32   size;            // size
@@ -1099,8 +1120,7 @@ static void mpi_receive_802_3(struct airo_info *ai);
 static void mpi_receive_802_11(struct airo_info *ai);
 static int waitbusy (struct airo_info *ai);
 
-static irqreturn_t airo_interrupt( int irq, void* dev_id, struct pt_regs
-                           *regs);
+static irqreturn_t airo_interrupt( int irq, void* dev_id);
 static int airo_thread(void *data);
 static void timer_func( struct net_device *dev );
 static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
@@ -1119,9 +1139,12 @@ static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *pPacket,
 static u8 airo_rssi_to_dbm (tdsRssiEntry *rssi_rid, u8 rssi);
 static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm);
 
+static void airo_networks_free(struct airo_info *ai);
+
 struct airo_info {
        struct net_device_stats stats;
        struct net_device             *dev;
+       struct list_head              dev_list;
        /* Note, we can have MAX_FIDS outstanding.  FIDs are 16-bits, so we
           use the high bit to mark whether it is in use. */
 #define MAX_FIDS 6
@@ -1132,8 +1155,6 @@ struct airo_info {
        char defindex; // Used with auto wep
        struct proc_dir_entry *proc_entry;
         spinlock_t aux_lock;
-        unsigned long flags;
-#define FLAG_PROMISC   8       /* IFF_PROMISC 0x100 - include/linux/if.h */
 #define FLAG_RADIO_OFF 0       /* User disabling of MAC */
 #define FLAG_RADIO_DOWN        1       /* ifup/ifdown disabling of MAC */
 #define FLAG_RADIO_MASK 0x03
@@ -1143,6 +1164,7 @@ struct airo_info {
 #define FLAG_UPDATE_MULTI 5
 #define FLAG_UPDATE_UNI 6
 #define FLAG_802_11    7
+#define FLAG_PROMISC   8       /* IFF_PROMISC 0x100 - include/linux/if.h */
 #define FLAG_PENDING_XMIT 9
 #define FLAG_PENDING_XMIT11 10
 #define FLAG_MPI       11
@@ -1150,25 +1172,27 @@ struct airo_info {
 #define FLAG_COMMIT    13
 #define FLAG_RESET     14
 #define FLAG_FLASHING  15
-#define JOB_MASK       0x1ff0000
-#define JOB_DIE                16
-#define JOB_XMIT       17
-#define JOB_XMIT11     18
-#define JOB_STATS      19
-#define JOB_PROMISC    20
-#define JOB_MIC                21
-#define JOB_EVENT      22
-#define JOB_AUTOWEP    23
-#define JOB_WSTATS     24
+#define FLAG_WPA_CAPABLE       16
+       unsigned long flags;
+#define JOB_DIE        0
+#define JOB_XMIT       1
+#define JOB_XMIT11     2
+#define JOB_STATS      3
+#define JOB_PROMISC    4
+#define JOB_MIC        5
+#define JOB_EVENT      6
+#define JOB_AUTOWEP    7
+#define JOB_WSTATS     8
+#define JOB_SCAN_RESULTS  9
+       unsigned long jobs;
        int (*bap_read)(struct airo_info*, u16 *pu16Dst, int bytelen,
                        int whichbap);
        unsigned short *flash;
        tdsRssiEntry *rssi;
-       struct task_struct *task;
+       struct task_struct *list_bss_task;
+       struct task_struct *airo_thread_task;
        struct semaphore sem;
-       pid_t thr_pid;
        wait_queue_head_t thr_wait;
-       struct completion thr_exited;
        unsigned long expires;
        struct {
                struct sk_buff *skb;
@@ -1176,11 +1200,11 @@ struct airo_info {
        } xmit, xmit11;
        struct net_device *wifidev;
        struct iw_statistics    wstats;         // wireless stats
-       unsigned long           scan_timestamp; /* Time started to scan */
+       unsigned long           scan_timeout;   /* Time scan should be read */
        struct iw_spy_data      spy_data;
        struct iw_public_data   wireless_data;
        /* MIC stuff */
-       struct crypto_tfm       *tfm;
+       struct crypto_cipher    *tfm;
        mic_module              mod[2];
        mic_statistics          micstats;
        HostRxDesc rxfids[MPI_MAX_FIDS]; // rx/tx/config MPI350 descriptors
@@ -1198,6 +1222,15 @@ struct airo_info {
        APListRid               *APList;
 #define        PCI_SHARED_LEN          2*MPI_MAX_FIDS*PKTSIZE+RIDSIZE
        char                    proc_name[IFNAMSIZ];
+
+       /* WPA-related stuff */
+       unsigned int bssListFirst;
+       unsigned int bssListNext;
+       unsigned int bssListRidLen;
+
+       struct list_head network_list;
+       struct list_head network_free_list;
+       BSSListElement *networks;
 };
 
 static inline int bap_read(struct airo_info *ai, u16 *pu16Dst, int bytelen,
@@ -1216,6 +1249,22 @@ static int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime);
 static int flashputbuf(struct airo_info *ai);
 static int flashrestart(struct airo_info *ai,struct net_device *dev);
 
+#define airo_print(type, name, fmt, args...) \
+       { printk(type "airo(%s): " fmt "\n", name, ##args); }
+
+#define airo_print_info(name, fmt, args...) \
+       airo_print(KERN_INFO, name, fmt, ##args)
+
+#define airo_print_dbg(name, fmt, args...) \
+       airo_print(KERN_DEBUG, name, fmt, ##args)
+
+#define airo_print_warn(name, fmt, args...) \
+       airo_print(KERN_WARNING, name, fmt, ##args)
+
+#define airo_print_err(name, fmt, args...) \
+       airo_print(KERN_ERR, name, fmt, ##args)
+
+
 /***********************************************************************
  *                              MIC ROUTINES                           *
  ***********************************************************************
@@ -1223,7 +1272,8 @@ static int flashrestart(struct airo_info *ai,struct net_device *dev);
 
 static int RxSeqValid (struct airo_info *ai,miccntx *context,int mcast,u32 micSeq);
 static void MoveWindow(miccntx *context, u32 micSeq);
-static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *);
+static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen,
+                          struct crypto_cipher *tfm);
 static void emmh32_init(emmh32_context *context);
 static void emmh32_update(emmh32_context *context, u8 *pOctets, int len);
 static void emmh32_final(emmh32_context *context, u8 digest[4]);
@@ -1235,7 +1285,7 @@ static void micinit(struct airo_info *ai)
 {
        MICRid mic_rid;
 
-       clear_bit(JOB_MIC, &ai->flags);
+       clear_bit(JOB_MIC, &ai->jobs);
        PC4500_readrid(ai, RID_MIC, &mic_rid, sizeof(mic_rid), 0);
        up(&ai->sem);
 
@@ -1291,10 +1341,11 @@ static int micsetup(struct airo_info *ai) {
        int i;
 
        if (ai->tfm == NULL)
-               ai->tfm = crypto_alloc_tfm("aes", CRYPTO_TFM_REQ_MAY_SLEEP);
+               ai->tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
 
-        if (ai->tfm == NULL) {
-                printk(KERN_ERR "airo: failed to load transform for AES\n");
+        if (IS_ERR(ai->tfm)) {
+                airo_print_err(ai->dev->name, "failed to load transform for AES");
+                ai->tfm = NULL;
                 return ERROR;
         }
 
@@ -1560,7 +1611,8 @@ static void MoveWindow(miccntx *context, u32 micSeq)
 static unsigned char aes_counter[16];
 
 /* expand the key to fill the MMH coefficient array */
-static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *tfm)
+static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen,
+                          struct crypto_cipher *tfm)
 {
   /* take the keying material, expand if necessary, truncate at 16-bytes */
   /* run through AES counter mode to generate context->coeff[] */
@@ -1568,21 +1620,19 @@ static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct
        int i,j;
        u32 counter;
        u8 *cipher, plain[16];
-       struct scatterlist sg[1];
 
        crypto_cipher_setkey(tfm, pkey, 16);
        counter = 0;
-       for (i = 0; i < (sizeof(context->coeff)/sizeof(context->coeff[0])); ) {
+       for (i = 0; i < ARRAY_SIZE(context->coeff); ) {
                aes_counter[15] = (u8)(counter >> 0);
                aes_counter[14] = (u8)(counter >> 8);
                aes_counter[13] = (u8)(counter >> 16);
                aes_counter[12] = (u8)(counter >> 24);
                counter++;
                memcpy (plain, aes_counter, 16);
-               sg_set_buf(sg, plain, 16);
-               crypto_cipher_encrypt(tfm, sg, sg, 16);
-               cipher = kmap(sg->page) + sg->offset;
-               for (j=0; (j<16) && (i< (sizeof(context->coeff)/sizeof(context->coeff[0]))); ) {
+               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]);
                        j += 4;
                }
@@ -1676,24 +1726,24 @@ static void emmh32_final(emmh32_context *context, u8 digest[4])
 static int readBSSListRid(struct airo_info *ai, int first,
                      BSSListRid *list) {
        int rc;
-                       Cmd cmd;
-                       Resp rsp;
+       Cmd cmd;
+       Resp rsp;
 
        if (first == 1) {
-                       if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN;
-                       memset(&cmd, 0, sizeof(cmd));
-                       cmd.cmd=CMD_LISTBSS;
-                       if (down_interruptible(&ai->sem))
-                               return -ERESTARTSYS;
-                       issuecommand(ai, &cmd, &rsp);
-                       up(&ai->sem);
-                       /* Let the command take effect */
-                       ai->task = current;
-                       ssleep(3);
-                       ai->task = NULL;
-               }
-       rc = PC4500_readrid(ai, first ? RID_BSSLISTFIRST : RID_BSSLISTNEXT,
-                           list, sizeof(*list), 1);
+               if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN;
+               memset(&cmd, 0, sizeof(cmd));
+               cmd.cmd=CMD_LISTBSS;
+               if (down_interruptible(&ai->sem))
+                       return -ERESTARTSYS;
+               ai->list_bss_task = current;
+               issuecommand(ai, &cmd, &rsp);
+               up(&ai->sem);
+               /* Let the command take effect */
+               schedule_timeout_uninterruptible(3 * HZ);
+               ai->list_bss_task = NULL;
+       }
+       rc = 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);
@@ -1726,11 +1776,11 @@ static int writeWepKeyRid(struct airo_info*ai, WepKeyRid *pwkr, int perm, int lo
        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) printk(KERN_ERR "airo:  WEP_TEMP set %x\n", rc);
+       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) {
-                       printk(KERN_ERR "airo:  WEP_PERM set %x\n", rc);
+                       airo_print_err(ai->dev->name, "WEP_PERM set %x", rc);
                }
        }
        return rc;
@@ -1909,7 +1959,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) {
        struct airo_info *ai = dev->priv;
 
        if (!skb) {
-               printk(KERN_ERR "airo: %s: skb==NULL\n",__FUNCTION__);
+               airo_print_err(dev->name, "%s: skb == NULL!",__FUNCTION__);
                return 0;
        }
        npacks = skb_queue_len (&ai->txq);
@@ -1955,8 +2005,8 @@ static int mpi_send_packet (struct net_device *dev)
        /* get a packet to send */
 
        if ((skb = skb_dequeue(&ai->txq)) == 0) {
-               printk (KERN_ERR
-                       "airo: %s: Dequeue'd zero in send_packet()\n",
+               airo_print_err(dev->name,
+                       "%s: Dequeue'd zero in send_packet()",
                        __FUNCTION__);
                return 0;
        }
@@ -2083,7 +2133,7 @@ static void airo_end_xmit(struct net_device *dev) {
        int fid = priv->xmit.fid;
        u32 *fids = priv->fids;
 
-       clear_bit(JOB_XMIT, &priv->flags);
+       clear_bit(JOB_XMIT, &priv->jobs);
        clear_bit(FLAG_PENDING_XMIT, &priv->flags);
        status = transmit_802_3_packet (priv, fids[fid], skb->data);
        up(&priv->sem);
@@ -2108,7 +2158,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
        u32 *fids = priv->fids;
 
        if ( skb == NULL ) {
-               printk( KERN_ERR "airo:  skb == NULL!!!\n" );
+               airo_print_err(dev->name, "%s: skb == NULL!", __FUNCTION__);
                return 0;
        }
 
@@ -2133,7 +2183,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
        if (down_trylock(&priv->sem) != 0) {
                set_bit(FLAG_PENDING_XMIT, &priv->flags);
                netif_stop_queue(dev);
-               set_bit(JOB_XMIT, &priv->flags);
+               set_bit(JOB_XMIT, &priv->jobs);
                wake_up_interruptible(&priv->thr_wait);
        } else
                airo_end_xmit(dev);
@@ -2148,7 +2198,7 @@ static void airo_end_xmit11(struct net_device *dev) {
        int fid = priv->xmit11.fid;
        u32 *fids = priv->fids;
 
-       clear_bit(JOB_XMIT11, &priv->flags);
+       clear_bit(JOB_XMIT11, &priv->jobs);
        clear_bit(FLAG_PENDING_XMIT11, &priv->flags);
        status = transmit_802_11_packet (priv, fids[fid], skb->data);
        up(&priv->sem);
@@ -2179,7 +2229,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
        }
 
        if ( skb == NULL ) {
-               printk( KERN_ERR "airo:  skb == NULL!!!\n" );
+               airo_print_err(dev->name, "%s: skb == NULL!", __FUNCTION__);
                return 0;
        }
 
@@ -2204,7 +2254,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
        if (down_trylock(&priv->sem) != 0) {
                set_bit(FLAG_PENDING_XMIT11, &priv->flags);
                netif_stop_queue(dev);
-               set_bit(JOB_XMIT11, &priv->flags);
+               set_bit(JOB_XMIT11, &priv->jobs);
                wake_up_interruptible(&priv->thr_wait);
        } else
                airo_end_xmit11(dev);
@@ -2215,7 +2265,7 @@ static void airo_read_stats(struct airo_info *ai) {
        StatsRid stats_rid;
        u32 *vals = stats_rid.vals;
 
-       clear_bit(JOB_STATS, &ai->flags);
+       clear_bit(JOB_STATS, &ai->jobs);
        if (ai->power.event) {
                up(&ai->sem);
                return;
@@ -2243,10 +2293,10 @@ static struct net_device_stats *airo_get_stats(struct net_device *dev)
 {
        struct airo_info *local =  dev->priv;
 
-       if (!test_bit(JOB_STATS, &local->flags)) {
+       if (!test_bit(JOB_STATS, &local->jobs)) {
                /* Get stats out of the card if available */
                if (down_trylock(&local->sem) != 0) {
-                       set_bit(JOB_STATS, &local->flags);
+                       set_bit(JOB_STATS, &local->jobs);
                        wake_up_interruptible(&local->thr_wait);
                } else
                        airo_read_stats(local);
@@ -2261,7 +2311,7 @@ static void airo_set_promisc(struct airo_info *ai) {
 
        memset(&cmd, 0, sizeof(cmd));
        cmd.cmd=CMD_SETMODE;
-       clear_bit(JOB_PROMISC, &ai->flags);
+       clear_bit(JOB_PROMISC, &ai->jobs);
        cmd.parm0=(ai->flags&IFF_PROMISC) ? PROMISC : NOPROMISC;
        issuecommand(ai, &cmd, &rsp);
        up(&ai->sem);
@@ -2273,7 +2323,7 @@ static void airo_set_multicast_list(struct net_device *dev) {
        if ((dev->flags ^ ai->flags) & IFF_PROMISC) {
                change_bit(FLAG_PROMISC, &ai->flags);
                if (down_trylock(&ai->sem) != 0) {
-                       set_bit(JOB_PROMISC, &ai->flags);
+                       set_bit(JOB_PROMISC, &ai->jobs);
                        wake_up_interruptible(&ai->thr_wait);
                } else
                        airo_set_promisc(ai);
@@ -2310,6 +2360,21 @@ static int airo_change_mtu(struct net_device *dev, int new_mtu)
        return 0;
 }
 
+static LIST_HEAD(airo_devices);
+
+static void add_airo_dev(struct airo_info *ai)
+{
+       /* Upper layers already keep track of PCI devices,
+        * so we only need to remember our non-PCI cards. */
+       if (!ai->pci)
+               list_add_tail(&ai->dev_list, &airo_devices);
+}
+
+static void del_airo_dev(struct airo_info *ai)
+{
+       if (!ai->pci)
+               list_del(&ai->dev_list);
+}
 
 static int airo_close(struct net_device *dev) {
        struct airo_info *ai = dev->priv;
@@ -2331,8 +2396,6 @@ static int airo_close(struct net_device *dev) {
        return 0;
 }
 
-static void del_airo_dev( struct net_device *dev );
-
 void stop_airo_card( struct net_device *dev, int freeres )
 {
        struct airo_info *ai = dev->priv;
@@ -2351,9 +2414,8 @@ void stop_airo_card( struct net_device *dev, int freeres )
                }
                clear_bit(FLAG_REGISTERED, &ai->flags);
        }
-       set_bit(JOB_DIE, &ai->flags);
-       kill_proc(ai->thr_pid, SIGTERM, 1);
-       wait_for_completion(&ai->thr_exited);
+       set_bit(JOB_DIE, &ai->jobs);
+       kthread_stop(ai->airo_thread_task);
 
        /*
         * Clean out tx queue
@@ -2364,6 +2426,8 @@ void stop_airo_card( struct net_device *dev, int freeres )
                        dev_kfree_skb(skb);
        }
 
+       airo_networks_free (ai);
+
        kfree(ai->flash);
        kfree(ai->rssi);
        kfree(ai->APList);
@@ -2382,18 +2446,16 @@ void stop_airo_card( struct net_device *dev, int freeres )
                                ai->shared, ai->shared_dma);
                }
         }
-       crypto_free_tfm(ai->tfm);
-       del_airo_dev( dev );
+       crypto_free_cipher(ai->tfm);
+       del_airo_dev(ai);
        free_netdev( dev );
 }
 
 EXPORT_SYMBOL(stop_airo_card);
 
-static int add_airo_dev( struct net_device *dev );
-
 static int wll_header_parse(struct sk_buff *skb, unsigned char *haddr)
 {
-       memcpy(haddr, skb->mac.raw + 10, ETH_ALEN);
+       memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN);
        return ETH_ALEN;
 }
 
@@ -2434,7 +2496,7 @@ static int mpi_init_descriptors (struct airo_info *ai)
        cmd.parm2 = MPI_MAX_FIDS;
        rc=issuecommand(ai, &cmd, &rsp);
        if (rc != SUCCESS) {
-               printk(KERN_ERR "airo:  Couldn't allocate RX FID\n");
+               airo_print_err(ai->dev->name, "Couldn't allocate RX FID");
                return rc;
        }
 
@@ -2462,7 +2524,7 @@ static int mpi_init_descriptors (struct airo_info *ai)
 
        rc=issuecommand(ai, &cmd, &rsp);
        if (rc != SUCCESS) {
-               printk(KERN_ERR "airo:  Couldn't allocate TX FID\n");
+               airo_print_err(ai->dev->name, "Couldn't allocate TX FID");
                return rc;
        }
 
@@ -2476,7 +2538,7 @@ static int mpi_init_descriptors (struct airo_info *ai)
        cmd.parm2 = 1; /* Magic number... */
        rc=issuecommand(ai, &cmd, &rsp);
        if (rc != SUCCESS) {
-               printk(KERN_ERR "airo:  Couldn't allocate RID\n");
+               airo_print_err(ai->dev->name, "Couldn't allocate RID");
                return rc;
        }
 
@@ -2508,25 +2570,25 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci,
        aux_len = AUXMEMSIZE;
 
        if (!request_mem_region(mem_start, mem_len, name)) {
-               printk(KERN_ERR "airo: Couldn't get region %x[%x] for %s\n",
+               airo_print_err(ai->dev->name, "Couldn't get region %x[%x] for %s",
                       (int)mem_start, (int)mem_len, name);
                goto out;
        }
        if (!request_mem_region(aux_start, aux_len, name)) {
-               printk(KERN_ERR "airo: Couldn't get region %x[%x] for %s\n",
+               airo_print_err(ai->dev->name, "Couldn't get region %x[%x] for %s",
                       (int)aux_start, (int)aux_len, name);
                goto free_region1;
        }
 
        ai->pcimem = ioremap(mem_start, mem_len);
        if (!ai->pcimem) {
-               printk(KERN_ERR "airo: Couldn't map region %x[%x] for %s\n",
+               airo_print_err(ai->dev->name, "Couldn't map region %x[%x] for %s",
                       (int)mem_start, (int)mem_len, name);
                goto free_region2;
        }
        ai->pciaux = ioremap(aux_start, aux_len);
        if (!ai->pciaux) {
-               printk(KERN_ERR "airo: Couldn't map region %x[%x] for %s\n",
+               airo_print_err(ai->dev->name, "Couldn't map region %x[%x] for %s",
                       (int)aux_start, (int)aux_len, name);
                goto free_memmap;
        }
@@ -2534,7 +2596,7 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci,
        /* Reserve PKTSIZE for each fid and 2K for the Rids */
        ai->shared = pci_alloc_consistent(pci, PCI_SHARED_LEN, &ai->shared_dma);
        if (!ai->shared) {
-               printk(KERN_ERR "airo: Couldn't alloc_consistent %d\n",
+               airo_print_err(ai->dev->name, "Couldn't alloc_consistent %d",
                       PCI_SHARED_LEN);
                goto free_auxmap;
        }
@@ -2626,7 +2688,7 @@ static void wifi_setup(struct net_device *dev)
 
        dev->type               = ARPHRD_IEEE80211;
        dev->hard_header_len    = ETH_HLEN;
-       dev->mtu                = 2312;
+       dev->mtu                = AIRO_DEF_MTU;
        dev->addr_len           = ETH_ALEN;
        dev->tx_queue_len       = 100; 
 
@@ -2670,6 +2732,62 @@ static int reset_card( struct net_device *dev , int lock) {
        return 0;
 }
 
+#define AIRO_MAX_NETWORK_COUNT 64
+static int airo_networks_allocate(struct airo_info *ai)
+{
+       if (ai->networks)
+               return 0;
+
+       ai->networks =
+           kzalloc(AIRO_MAX_NETWORK_COUNT * sizeof(BSSListElement),
+                   GFP_KERNEL);
+       if (!ai->networks) {
+               airo_print_warn(ai->dev->name, "Out of memory allocating beacons");
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void airo_networks_free(struct airo_info *ai)
+{
+       kfree(ai->networks);
+       ai->networks = NULL;
+}
+
+static void airo_networks_initialize(struct airo_info *ai)
+{
+       int i;
+
+       INIT_LIST_HEAD(&ai->network_free_list);
+       INIT_LIST_HEAD(&ai->network_list);
+       for (i = 0; i < AIRO_MAX_NETWORK_COUNT; i++)
+               list_add_tail(&ai->networks[i].list,
+                             &ai->network_free_list);
+}
+
+static int airo_test_wpa_capable(struct airo_info *ai)
+{
+       int status;
+       CapabilityRid cap_rid;
+       const char *name = ai->dev->name;
+
+       status = readCapabilityRid(ai, &cap_rid, 1);
+       if (status != SUCCESS) return 0;
+
+       /* Only firmware versions 5.30.17 or better can do WPA */
+       if ((cap_rid.softVer > 0x530)
+         || ((cap_rid.softVer == 0x530) && (cap_rid.softSubVer >= 17))) {
+               airo_print_info(name, "WPA is supported.");
+               return 1;
+       }
+
+       /* No WPA support */
+       airo_print_info(name, "WPA unsupported (only firmware versions 5.30.17"
+               " and greater support WPA.  Detected %s)", cap_rid.prodVer);
+       return 0;
+}
+
 static struct net_device *_init_airo_card( unsigned short irq, int port,
                                           int is_pcmcia, struct pci_dev *pci,
                                           struct device *dmdev )
@@ -2681,35 +2799,37 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
        /* Create the network device object. */
         dev = alloc_etherdev(sizeof(*ai));
         if (!dev) {
-               printk(KERN_ERR "airo:  Couldn't alloc_etherdev\n");
+               airo_print_err("", "Couldn't alloc_etherdev");
                return NULL;
         }
        if (dev_alloc_name(dev, dev->name) < 0) {
-               printk(KERN_ERR "airo:  Couldn't get name!\n");
+               airo_print_err("", "Couldn't get name!");
                goto err_out_free;
        }
 
        ai = dev->priv;
        ai->wifidev = NULL;
        ai->flags = 0;
+       ai->jobs = 0;
+       ai->dev = dev;
        if (pci && (pci->device == 0x5000 || pci->device == 0xa504)) {
-               printk(KERN_DEBUG "airo: Found an MPI350 card\n");
+               airo_print_dbg(dev->name, "Found an MPI350 card");
                set_bit(FLAG_MPI, &ai->flags);
        }
-        ai->dev = dev;
        spin_lock_init(&ai->aux_lock);
        sema_init(&ai->sem, 1);
        ai->config.len = 0;
        ai->pci = pci;
        init_waitqueue_head (&ai->thr_wait);
-       init_completion (&ai->thr_exited);
-       ai->thr_pid = kernel_thread(airo_thread, dev, CLONE_FS | CLONE_FILES);
-       if (ai->thr_pid < 0)
+       ai->airo_thread_task = kthread_run(airo_thread, dev, dev->name);
+       if (IS_ERR(ai->airo_thread_task))
                goto err_out_free;
        ai->tfm = NULL;
-       rc = add_airo_dev( dev );
-       if (rc)
+       add_airo_dev(ai);
+
+       if (airo_networks_allocate (ai))
                goto err_out_thr;
+       airo_networks_initialize (ai);
 
        /* The Airo-specific entries in the device structure. */
        if (test_bit(FLAG_MPI,&ai->flags)) {
@@ -2732,33 +2852,33 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
 
        SET_NETDEV_DEV(dev, dmdev);
 
-
        reset_card (dev, 1);
        msleep(400);
 
-       rc = request_irq( dev->irq, airo_interrupt, SA_SHIRQ, dev->name, dev );
+       rc = request_irq( dev->irq, airo_interrupt, IRQF_SHARED, dev->name, dev );
        if (rc) {
-               printk(KERN_ERR "airo: register interrupt %d failed, rc %d\n", irq, rc );
-               goto err_out_unlink;
+               airo_print_err(dev->name, "register interrupt %d failed, rc %d",
+                               irq, rc);
+               goto err_out_nets;
        }
        if (!is_pcmcia) {
                if (!request_region( dev->base_addr, 64, dev->name )) {
                        rc = -EBUSY;
-                       printk(KERN_ERR "airo: Couldn't request region\n");
+                       airo_print_err(dev->name, "Couldn't request region");
                        goto err_out_irq;
                }
        }
 
        if (test_bit(FLAG_MPI,&ai->flags)) {
                if (mpi_map_card(ai, pci, dev->name)) {
-                       printk(KERN_ERR "airo: Could not map memory\n");
+                       airo_print_err(dev->name, "Could not map memory");
                        goto err_out_res;
                }
        }
 
        if (probe) {
                if ( setup_card( ai, dev->dev_addr, 1 ) != SUCCESS ) {
-                       printk( KERN_ERR "airo: MAC could not be enabled\n" );
+                       airo_print_err(dev->name, "MAC could not be enabled" );
                        rc = -EIO;
                        goto err_out_map;
                }
@@ -2767,29 +2887,49 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
                set_bit(FLAG_FLASHING, &ai->flags);
        }
 
+       /* Test for WPA support */
+       if (airo_test_wpa_capable(ai)) {
+               set_bit(FLAG_WPA_CAPABLE, &ai->flags);
+               ai->bssListFirst = RID_WPA_BSSLISTFIRST;
+               ai->bssListNext = RID_WPA_BSSLISTNEXT;
+               ai->bssListRidLen = sizeof(BSSListRid);
+       } else {
+               ai->bssListFirst = RID_BSSLISTFIRST;
+               ai->bssListNext = RID_BSSLISTNEXT;
+               ai->bssListRidLen = sizeof(BSSListRid) - sizeof(BSSListRidExtra);
+       }
+
        rc = register_netdev(dev);
        if (rc) {
-               printk(KERN_ERR "airo: Couldn't register_netdev\n");
+               airo_print_err(dev->name, "Couldn't register_netdev");
                goto err_out_map;
        }
        ai->wifidev = init_wifidev(ai, dev);
+       if (!ai->wifidev)
+               goto err_out_reg;
 
        set_bit(FLAG_REGISTERED,&ai->flags);
-       printk( KERN_INFO "airo: MAC enabled %s %x:%x:%x:%x:%x:%x\n",
-               dev->name,
+       airo_print_info(dev->name, "MAC enabled %x:%x:%x:%x:%x:%x",
                dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
                dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] );
 
        /* Allocate the transmit buffers */
        if (probe && !test_bit(FLAG_MPI,&ai->flags))
                for( i = 0; i < MAX_FIDS; i++ )
-                       ai->fids[i] = transmit_allocate(ai,2312,i>=MAX_FIDS/2);
+                       ai->fids[i] = transmit_allocate(ai,AIRO_DEF_MTU,i>=MAX_FIDS/2);
+
+       if (setup_proc_entry(dev, dev->priv) < 0)
+               goto err_out_wifi;
 
-       setup_proc_entry( dev, dev->priv ); /* XXX check for failure */
        netif_start_queue(dev);
        SET_MODULE_OWNER(dev);
        return dev;
 
+err_out_wifi:
+       unregister_netdev(ai->wifidev);
+       free_netdev(ai->wifidev);
+err_out_reg:
+       unregister_netdev(dev);
 err_out_map:
        if (test_bit(FLAG_MPI,&ai->flags) && pci) {
                pci_free_consistent(pci, PCI_SHARED_LEN, ai->shared, ai->shared_dma);
@@ -2802,12 +2942,12 @@ err_out_res:
                release_region( dev->base_addr, 64 );
 err_out_irq:
        free_irq(dev->irq, dev);
-err_out_unlink:
-       del_airo_dev(dev);
+err_out_nets:
+       airo_networks_free(ai);
 err_out_thr:
-       set_bit(JOB_DIE, &ai->flags);
-       kill_proc(ai->thr_pid, SIGTERM, 1);
-       wait_for_completion(&ai->thr_exited);
+       del_airo_dev(ai);
+       set_bit(JOB_DIE, &ai->jobs);
+       kthread_stop(ai->airo_thread_task);
 err_out_free:
        free_netdev(dev);
        return NULL;
@@ -2840,16 +2980,16 @@ int reset_airo_card( struct net_device *dev )
                return -1;
 
        if ( setup_card(ai, dev->dev_addr, 1 ) != SUCCESS ) {
-               printk( KERN_ERR "airo: MAC could not be enabled\n" );
+               airo_print_err(dev->name, "MAC could not be enabled");
                return -1;
        }
-       printk( KERN_INFO "airo: MAC enabled %s %x:%x:%x:%x:%x:%x\n", dev->name,
+       airo_print_info(dev->name, "MAC enabled %x:%x:%x:%x:%x:%x",
                        dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
                        dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
        /* Allocate the transmit buffers if needed */
        if (!test_bit(FLAG_MPI,&ai->flags))
                for( i = 0; i < MAX_FIDS; i++ )
-                       ai->fids[i] = transmit_allocate (ai,2312,i>=MAX_FIDS/2);
+                       ai->fids[i] = transmit_allocate (ai,AIRO_DEF_MTU,i>=MAX_FIDS/2);
 
        enable_interrupts( ai );
        netif_wake_queue(dev);
@@ -2863,7 +3003,7 @@ static void airo_send_event(struct net_device *dev) {
        union iwreq_data wrqu;
        StatusRid status_rid;
 
-       clear_bit(JOB_EVENT, &ai->flags);
+       clear_bit(JOB_EVENT, &ai->jobs);
        PC4500_readrid(ai, RID_STATUS, &status_rid, sizeof(status_rid), 0);
        up(&ai->sem);
        wrqu.data.length = 0;
@@ -2875,25 +3015,78 @@ static void airo_send_event(struct net_device *dev) {
        wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
 }
 
+static void airo_process_scan_results (struct airo_info *ai) {
+       union iwreq_data        wrqu;
+       BSSListRid bss;
+       int rc;
+       BSSListElement * loop_net;
+       BSSListElement * tmp_net;
+
+       /* Blow away current list of scan results */
+       list_for_each_entry_safe (loop_net, tmp_net, &ai->network_list, list) {
+               list_move_tail (&loop_net->list, &ai->network_free_list);
+               /* Don't blow away ->list, just BSS data */
+               memset (loop_net, 0, sizeof (loop_net->bss));
+       }
+
+       /* 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)) {
+               /* No scan results */
+               goto out;
+       }
+
+       /* Read and parse all entries */
+       tmp_net = NULL;
+       while((!rc) && (bss.index != 0xffff)) {
+               /* Grab a network off the free list */
+               if (!list_empty(&ai->network_free_list)) {
+                       tmp_net = list_entry(ai->network_free_list.next,
+                                           BSSListElement, list);
+                       list_del(ai->network_free_list.next);
+               }
+
+               if (tmp_net != NULL) {
+                       memcpy(tmp_net, &bss, sizeof(tmp_net->bss));
+                       list_add_tail(&tmp_net->list, &ai->network_list);
+                       tmp_net = NULL;
+               }
+
+               /* Read next entry */
+               rc = PC4500_readrid(ai, ai->bssListNext,
+                                   &bss, ai->bssListRidLen, 0);
+       }
+
+out:
+       ai->scan_timeout = 0;
+       clear_bit(JOB_SCAN_RESULTS, &ai->jobs);
+       up(&ai->sem);
+
+       /* Send an empty event to user space.
+        * We don't send the received data on
+        * the event because it would require
+        * us to do complex transcoding, and
+        * we want to minimise the work done in
+        * the irq handler. Use a request to
+        * extract the data - Jean II */
+       wrqu.data.length = 0;
+       wrqu.data.flags = 0;
+       wireless_send_event(ai->dev, SIOCGIWSCAN, &wrqu, NULL);
+}
+
 static int airo_thread(void *data) {
        struct net_device *dev = data;
        struct airo_info *ai = dev->priv;
        int locked;
        
-       daemonize("%s", dev->name);
-       allow_signal(SIGTERM);
-
        while(1) {
-               if (signal_pending(current))
-                       flush_signals(current);
-
                /* make swsusp happy with our thread */
                try_to_freeze();
 
-               if (test_bit(JOB_DIE, &ai->flags))
+               if (test_bit(JOB_DIE, &ai->jobs))
                        break;
 
-               if (ai->flags & JOB_MASK) {
+               if (ai->jobs) {
                        locked = down_interruptible(&ai->sem);
                } else {
                        wait_queue_t wait;
@@ -2902,18 +3095,33 @@ static int airo_thread(void *data) {
                        add_wait_queue(&ai->thr_wait, &wait);
                        for (;;) {
                                set_current_state(TASK_INTERRUPTIBLE);
-                               if (ai->flags & JOB_MASK)
+                               if (ai->jobs)
                                        break;
-                               if (ai->expires) {
-                                       if (time_after_eq(jiffies,ai->expires)){
-                                               set_bit(JOB_AUTOWEP,&ai->flags);
+                               if (ai->expires || ai->scan_timeout) {
+                                       if (ai->scan_timeout &&
+                                                       time_after_eq(jiffies,ai->scan_timeout)){
+                                               set_bit(JOB_SCAN_RESULTS, &ai->jobs);
+                                               break;
+                                       } else if (ai->expires &&
+                                                       time_after_eq(jiffies,ai->expires)){
+                                               set_bit(JOB_AUTOWEP, &ai->jobs);
                                                break;
                                        }
-                                       if (!signal_pending(current)) {
-                                               schedule_timeout(ai->expires - jiffies);
+                                       if (!kthread_should_stop() &&
+                                           !freezing(current)) {
+                                               unsigned long wake_at;
+                                               if (!ai->expires || !ai->scan_timeout) {
+                                                       wake_at = max(ai->expires,
+                                                               ai->scan_timeout);
+                                               } else {
+                                                       wake_at = min(ai->expires,
+                                                               ai->scan_timeout);
+                                               }
+                                               schedule_timeout(wake_at - jiffies);
                                                continue;
                                        }
-                               } else if (!signal_pending(current)) {
+                               } else if (!kthread_should_stop() &&
+                                          !freezing(current)) {
                                        schedule();
                                        continue;
                                }
@@ -2927,7 +3135,7 @@ static int airo_thread(void *data) {
                if (locked)
                        continue;
 
-               if (test_bit(JOB_DIE, &ai->flags)) {
+               if (test_bit(JOB_DIE, &ai->jobs)) {
                        up(&ai->sem);
                        break;
                }
@@ -2937,27 +3145,32 @@ static int airo_thread(void *data) {
                        continue;
                }
 
-               if (test_bit(JOB_XMIT, &ai->flags))
+               if (test_bit(JOB_XMIT, &ai->jobs))
                        airo_end_xmit(dev);
-               else if (test_bit(JOB_XMIT11, &ai->flags))
+               else if (test_bit(JOB_XMIT11, &ai->jobs))
                        airo_end_xmit11(dev);
-               else if (test_bit(JOB_STATS, &ai->flags))
+               else if (test_bit(JOB_STATS, &ai->jobs))
                        airo_read_stats(ai);
-               else if (test_bit(JOB_WSTATS, &ai->flags))
+               else if (test_bit(JOB_WSTATS, &ai->jobs))
                        airo_read_wireless_stats(ai);
-               else if (test_bit(JOB_PROMISC, &ai->flags))
+               else if (test_bit(JOB_PROMISC, &ai->jobs))
                        airo_set_promisc(ai);
-               else if (test_bit(JOB_MIC, &ai->flags))
+               else if (test_bit(JOB_MIC, &ai->jobs))
                        micinit(ai);
-               else if (test_bit(JOB_EVENT, &ai->flags))
+               else if (test_bit(JOB_EVENT, &ai->jobs))
                        airo_send_event(dev);
-               else if (test_bit(JOB_AUTOWEP, &ai->flags))
+               else if (test_bit(JOB_AUTOWEP, &ai->jobs))
                        timer_func(dev);
+               else if (test_bit(JOB_SCAN_RESULTS, &ai->jobs))
+                       airo_process_scan_results(ai);
+               else  /* Shouldn't get here, but we make sure to unlock */
+                       up(&ai->sem);
        }
-       complete_and_exit (&ai->thr_exited, 0);
+
+       return 0;
 }
 
-static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) {
+static irqreturn_t airo_interrupt ( int irq, void* dev_id) {
        struct net_device *dev = (struct net_device *)dev_id;
        u16 status;
        u16 fid;
@@ -2987,12 +3200,13 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
                if ( status & EV_MIC ) {
                        OUT4500( apriv, EVACK, EV_MIC );
                        if (test_bit(FLAG_MIC_CAPABLE, &apriv->flags)) {
-                               set_bit(JOB_MIC, &apriv->flags);
+                               set_bit(JOB_MIC, &apriv->jobs);
                                wake_up_interruptible(&apriv->thr_wait);
                        }
                }
                if ( status & EV_LINK ) {
                        union iwreq_data        wrqu;
+                       int scan_forceloss = 0;
                        /* The link status has changed, if you want to put a
                           monitor hook in, do it here.  (Remember that
                           interrupts are still disabled!)
@@ -3011,7 +3225,8 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
                          code) */
 #define AUTHFAIL 0x0300 /* Authentication failure (low byte is reason
                           code) */
-#define ASSOCIATED 0x0400 /* Assocatied */
+#define ASSOCIATED 0x0400 /* Associated */
+#define REASSOCIATED 0x0600 /* Reassociated?  Only on firmware >= 5.30.17 */
 #define RC_RESERVED 0 /* Reserved return code */
 #define RC_NOREASON 1 /* Unspecified reason */
 #define RC_AUTHINV 2 /* Previous authentication invalid */
@@ -3028,48 +3243,30 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
                          leaving BSS */
 #define RC_NOAUTH 9 /* Station requesting (Re)Association is not
                       Authenticated with the responding station */
-                       if (newStatus != ASSOCIATED) {
-                               if (auto_wep && !apriv->expires) {
-                                       apriv->expires = RUN_AT(3*HZ);
-                                       wake_up_interruptible(&apriv->thr_wait);
-                               }
-                       } else {
-                               struct task_struct *task = apriv->task;
+                       if (newStatus == FORCELOSS && apriv->scan_timeout > 0)
+                               scan_forceloss = 1;
+                       if(newStatus == ASSOCIATED || newStatus == REASSOCIATED) {
                                if (auto_wep)
                                        apriv->expires = 0;
-                               if (task)
-                                       wake_up_process (task);
+                               if (apriv->list_bss_task)
+                                       wake_up_process(apriv->list_bss_task);
                                set_bit(FLAG_UPDATE_UNI, &apriv->flags);
                                set_bit(FLAG_UPDATE_MULTI, &apriv->flags);
-                       }
-                       /* Question : is ASSOCIATED the only status
-                        * that is valid ? We want to catch handover
-                        * and reassociations as valid status
-                        * Jean II */
-                       if(newStatus == ASSOCIATED) {
-                               if (apriv->scan_timestamp) {
-                                       /* Send an empty event to user space.
-                                        * We don't send the received data on
-                                        * the event because it would require
-                                        * us to do complex transcoding, and
-                                        * we want to minimise the work done in
-                                        * the irq handler. Use a request to
-                                        * extract the data - Jean II */
-                                       wrqu.data.length = 0;
-                                       wrqu.data.flags = 0;
-                                       wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
-                                       apriv->scan_timestamp = 0;
-                               }
+
                                if (down_trylock(&apriv->sem) != 0) {
-                                       set_bit(JOB_EVENT, &apriv->flags);
+                                       set_bit(JOB_EVENT, &apriv->jobs);
                                        wake_up_interruptible(&apriv->thr_wait);
                                } else
                                        airo_send_event(dev);
-                       } else {
-                               memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN);
-                               wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+                       } else if (!scan_forceloss) {
+                               if (auto_wep && !apriv->expires) {
+                                       apriv->expires = RUN_AT(3*HZ);
+                                       wake_up_interruptible(&apriv->thr_wait);
+                               }
 
                                /* Send event to user space */
+                               memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN);
+                               wrqu.ap_addr.sa_family = ARPHRD_ETHER;
                                wireless_send_event(dev, SIOCGIWAP, &wrqu,NULL);
                        }
                }
@@ -3117,8 +3314,8 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
                        }
                        len = le16_to_cpu(hdr.len);
 
-                       if (len > 2312) {
-                               printk( KERN_ERR "airo: Bad size %d\n", len );
+                       if (len > AIRO_DEF_MTU) {
+                               airo_print_err(apriv->dev->name, "Bad size %d", len);
                                goto badrx;
                        }
                        if (len == 0)
@@ -3161,10 +3358,12 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
                                bap_read (apriv, &gap, sizeof(gap), BAP0);
                                gap = le16_to_cpu(gap);
                                if (gap) {
-                                       if (gap <= 8)
+                                       if (gap <= 8) {
                                                bap_read (apriv, tmpbuf, gap, BAP0);
-                                       else
-                                               printk(KERN_ERR "airo: gaplen too big. Problems will follow...\n");
+                                       } else {
+                                               airo_print_err(apriv->dev->name, "gaplen too "
+                                                       "big. Problems will follow...");
+                                       }
                                }
                                bap_read (apriv, buffer + hdrlen/2, len, BAP0);
                        } else {
@@ -3218,14 +3417,12 @@ badrx:
                        OUT4500( apriv, EVACK, EV_RX);
 
                        if (test_bit(FLAG_802_11, &apriv->flags)) {
-                               skb->mac.raw = skb->data;
+                               skb_reset_mac_header(skb);
                                skb->pkt_type = PACKET_OTHERHOST;
                                skb->dev = apriv->wifidev;
                                skb->protocol = htons(ETH_P_802_2);
-                       } else {
-                               skb->dev = dev;
+                       } else
                                skb->protocol = eth_type_trans(skb,dev);
-                       }
                        skb->dev->last_rx = jiffies;
                        skb->ip_summed = CHECKSUM_NONE;
 
@@ -3281,12 +3478,13 @@ exitrx:
                                }
                        } else {
                                OUT4500( apriv, EVACK, status & (EV_TX | EV_TXCPY | EV_TXEXC));
-                               printk( KERN_ERR "airo: Unallocated FID was used to xmit\n" );
+                               airo_print_err(apriv->dev->name, "Unallocated FID was "
+                                       "used to xmit" );
                        }
                }
 exittx:
                if ( status & ~STATUS_INTS & ~IGNORE_INTS )
-                       printk( KERN_WARNING "airo: Got weird status %x\n",
+                       airo_print_warn(apriv->dev->name, "Got weird status %x",
                                status & ~STATUS_INTS & ~IGNORE_INTS );
        }
 
@@ -3359,8 +3557,8 @@ static int enable_MAC( struct airo_info *ai, Resp *rsp, int lock ) {
            up(&ai->sem);
 
        if (rc)
-               printk(KERN_ERR "%s: Cannot enable MAC, err=%d\n",
-                       __FUNCTION__,rc);
+               airo_print_err(ai->dev->name, "%s: Cannot enable MAC, err=%d",
+                       __FUNCTION__, rc);
        return rc;
 }
 
@@ -3447,7 +3645,6 @@ badmic:
                }
 #endif /* WIRELESS_SPY */
 
-               skb->dev = ai->dev;
                skb->ip_summed = CHECKSUM_NONE;
                skb->protocol = eth_type_trans(skb, ai->dev);
                skb->dev->last_rx = jiffies;
@@ -3489,8 +3686,8 @@ void mpi_receive_802_11 (struct airo_info *ai)
        if (ai->wifidev == NULL)
                hdr.len = 0;
        len = le16_to_cpu(hdr.len);
-       if (len > 2312) {
-               printk( KERN_ERR "airo: Bad size %d\n", len );
+       if (len > AIRO_DEF_MTU) {
+               airo_print_err(ai->dev->name, "Bad size %d", len);
                goto badrx;
        }
        if (len == 0)
@@ -3531,8 +3728,8 @@ void mpi_receive_802_11 (struct airo_info *ai)
                if (gap <= 8)
                        ptr += gap;
                else
-                       printk(KERN_ERR
-                           "airo: gaplen too big. Problems will follow...\n");
+                       airo_print_err(ai->dev->name,
+                           "gaplen too big. Problems will follow...");
        }
        memcpy ((char *)buffer + hdrlen, ptr, len);
        ptr += len;
@@ -3555,7 +3752,7 @@ void mpi_receive_802_11 (struct airo_info *ai)
                wireless_spy_update(ai->dev, sa, &wstats);
        }
 #endif /* IW_WIRELESS_SPY */
-       skb->mac.raw = skb->data;
+       skb_reset_mac_header(skb);
        skb->pkt_type = PACKET_OTHERHOST;
        skb->dev = ai->wifidev;
        skb->protocol = htons(ETH_P_802_2);
@@ -3604,15 +3801,15 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
                if (issuecommand(ai, &cmd, &rsp) != SUCCESS) {
                        if (lock)
                                up(&ai->sem);
-                       printk(KERN_ERR "airo: Error checking for AUX port\n");
+                       airo_print_err(ai->dev->name, "Error checking for AUX port");
                        return ERROR;
                }
                if (!aux_bap || rsp.status & 0xff00) {
                        ai->bap_read = fast_bap_read;
-                       printk(KERN_DEBUG "airo: Doing fast bap_reads\n");
+                       airo_print_dbg(ai->dev->name, "Doing fast bap_reads");
                } else {
                        ai->bap_read = aux_bap_read;
-                       printk(KERN_DEBUG "airo: Doing AUX bap_reads\n");
+                       airo_print_dbg(ai->dev->name, "Doing AUX bap_reads");
                }
        }
        if (lock)
@@ -3643,7 +3840,8 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
                        if (cap_rid.softCap & 8)
                                ai->config.rmode |= RXMODE_NORMALIZED_RSSI;
                        else
-                               printk(KERN_WARNING "airo: unknown received signal level scale\n");
+                               airo_print_warn(ai->dev->name, "unknown received signal "
+                                               "level scale");
                }
                ai->config.opmode = adhoc ? MODE_STA_IBSS : MODE_STA_ESS;
                ai->config.authType = AUTH_OPEN;
@@ -3706,7 +3904,8 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
 
        status = enable_MAC(ai, &rsp, lock);
        if ( status != SUCCESS || (rsp.status & 0xFF00) != 0) {
-               printk( KERN_ERR "airo: Bad MAC enable reason = %x, rid = %x, offset = %d\n", rsp.rsp0, rsp.rsp1, rsp.rsp2 );
+               airo_print_err(ai->dev->name, "Bad MAC enable reason = %x, rid = %x,"
+                       " offset = %d", rsp.rsp0, rsp.rsp1, rsp.rsp2 );
                return ERROR;
        }
 
@@ -3749,8 +3948,8 @@ static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) {
        }
 
        if ( max_tries == -1 ) {
-               printk( KERN_ERR
-                       "airo: Max tries exceeded when issueing command\n" );
+               airo_print_err(ai->dev->name,
+                       "Max tries exceeded when issueing command");
                if (IN4500(ai, COMMAND) & COMMAND_BUSY)
                        OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY);
                return ERROR;
@@ -3761,13 +3960,11 @@ static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) {
        pRsp->rsp0 = IN4500(ai, RESP0);
        pRsp->rsp1 = IN4500(ai, RESP1);
        pRsp->rsp2 = IN4500(ai, RESP2);
-       if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET) {
-               printk (KERN_ERR "airo: cmd= %x\n", pCmd->cmd);
-               printk (KERN_ERR "airo: status= %x\n", pRsp->status);
-               printk (KERN_ERR "airo: Rsp0= %x\n", pRsp->rsp0);
-               printk (KERN_ERR "airo: Rsp1= %x\n", pRsp->rsp1);
-               printk (KERN_ERR "airo: Rsp2= %x\n", pRsp->rsp2);
-       }
+       if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET)
+               airo_print_err(ai->dev->name,
+                       "cmd:%x status:%x rsp0:%x rsp1:%x rsp2:%x",
+                       pCmd->cmd, pRsp->status, pRsp->rsp0, pRsp->rsp1,
+                       pRsp->rsp2);
 
        // clear stuck command busy if necessary
        if (IN4500(ai, COMMAND) & COMMAND_BUSY) {
@@ -3799,15 +3996,15 @@ static int bap_setup(struct airo_info *ai, u16 rid, u16 offset, int whichbap )
                        }
                } else if ( status & BAP_ERR ) {
                        /* invalid rid or offset */
-                       printk( KERN_ERR "airo: BAP error %x %d\n",
+                       airo_print_err(ai->dev->name, "BAP error %x %d",
                                status, whichbap );
                        return ERROR;
                } else if (status & BAP_DONE) { // success
                        return SUCCESS;
                }
                if ( !(max_tries--) ) {
-                       printk( KERN_ERR
-                               "airo: BAP setup error too many retries\n" );
+                       airo_print_err(ai->dev->name,
+                               "airo: BAP setup error too many retries\n");
                        return ERROR;
                }
                // -- PC4500 missed it, try again
@@ -3962,8 +4159,8 @@ static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len, in
                len = min(len, (int)le16_to_cpu(*(u16*)pBuf)) - 2;
 
                if ( len <= 2 ) {
-                       printk( KERN_ERR
-                       "airo: Rid %x has a length of %d which is too short\n",
+                       airo_print_err(ai->dev->name,
+                               "Rid %x has a length of %d which is too short",
                                (int)rid, (int)len );
                        rc = ERROR;
                        goto done;
@@ -3996,8 +4193,8 @@ static int PC4500_writerid(struct airo_info *ai, u16 rid,
                Resp rsp;
 
                if (test_bit(FLAG_ENABLED, &ai->flags) && (RID_WEP_TEMP != rid))
-                       printk(KERN_ERR
-                               "%s: MAC should be disabled (rid=%04x)\n",
+                       airo_print_err(ai->dev->name,
+                               "%s: MAC should be disabled (rid=%04x)",
                                __FUNCTION__, rid);
                memset(&cmd, 0, sizeof(cmd));
                memset(&rsp, 0, sizeof(rsp));
@@ -4013,7 +4210,7 @@ static int PC4500_writerid(struct airo_info *ai, u16 rid,
                        &ai->config_desc.rid_desc, sizeof(Rid));
 
                if (len < 4 || len > 2047) {
-                       printk(KERN_ERR "%s: len=%d\n",__FUNCTION__,len);
+                       airo_print_err(ai->dev->name, "%s: len=%d", __FUNCTION__, len);
                        rc = -1;
                } else {
                        memcpy((char *)ai->config_desc.virtual_host_addr,
@@ -4021,10 +4218,10 @@ static int PC4500_writerid(struct airo_info *ai, u16 rid,
 
                        rc = issuecommand(ai, &cmd, &rsp);
                        if ((rc & 0xff00) != 0) {
-                               printk(KERN_ERR "%s: Write rid Error %d\n",
-                                       __FUNCTION__,rc);
-                               printk(KERN_ERR "%s: Cmd=%04x\n",
-                                               __FUNCTION__,cmd.cmd);
+                               airo_print_err(ai->dev->name, "%s: Write rid Error %d",
+                                               __FUNCTION__, rc);
+                               airo_print_err(ai->dev->name, "%s: Cmd=%04x",
+                                               __FUNCTION__, cmd.cmd);
                        }
 
                        if ((rsp.status & 0x7f00))
@@ -4123,7 +4320,7 @@ static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket)
        len >>= 16;
 
        if (len <= ETH_ALEN * 2) {
-               printk( KERN_WARNING "Short packet %d\n", len );
+               airo_print_warn(ai->dev->name, "Short packet %d", len);
                return ERROR;
        }
        len -= ETH_ALEN * 2;
@@ -4187,7 +4384,7 @@ static int transmit_802_11_packet(struct airo_info *ai, int len, char *pPacket)
        }
 
        if (len < hdrlen) {
-               printk( KERN_WARNING "Short packet %d\n", len );
+               airo_print_warn(ai->dev->name, "Short packet %d", len);
                return ERROR;
        }
 
@@ -4238,53 +4435,53 @@ static int proc_BSSList_open( struct inode *inode, struct file *file );
 static int proc_config_open( struct inode *inode, struct file *file );
 static int proc_wepkey_open( struct inode *inode, struct file *file );
 
-static struct file_operations proc_statsdelta_ops = {
+static const struct file_operations proc_statsdelta_ops = {
        .read           = proc_read,
        .open           = proc_statsdelta_open,
        .release        = proc_close
 };
 
-static struct file_operations proc_stats_ops = {
+static const struct file_operations proc_stats_ops = {
        .read           = proc_read,
        .open           = proc_stats_open,
        .release        = proc_close
 };
 
-static struct file_operations proc_status_ops = {
+static const struct file_operations proc_status_ops = {
        .read           = proc_read,
        .open           = proc_status_open,
        .release        = proc_close
 };
 
-static struct file_operations proc_SSID_ops = {
+static const struct file_operations proc_SSID_ops = {
        .read           = proc_read,
        .write          = proc_write,
        .open           = proc_SSID_open,
        .release        = proc_close
 };
 
-static struct file_operations proc_BSSList_ops = {
+static const struct file_operations proc_BSSList_ops = {
        .read           = proc_read,
        .write          = proc_write,
        .open           = proc_BSSList_open,
        .release        = proc_close
 };
 
-static struct file_operations proc_APList_ops = {
+static const struct file_operations proc_APList_ops = {
        .read           = proc_read,
        .write          = proc_write,
        .open           = proc_APList_open,
        .release        = proc_close
 };
 
-static struct file_operations proc_config_ops = {
+static const struct file_operations proc_config_ops = {
        .read           = proc_read,
        .write          = proc_write,
        .open           = proc_config_open,
        .release        = proc_close
 };
 
-static struct file_operations proc_wepkey_ops = {
+static const struct file_operations proc_wepkey_ops = {
        .read           = proc_read,
        .write          = proc_write,
        .open           = proc_wepkey_open,
@@ -4315,91 +4512,128 @@ static int setup_proc_entry( struct net_device *dev,
        apriv->proc_entry = create_proc_entry(apriv->proc_name,
                                              S_IFDIR|airo_perm,
                                              airo_entry);
-        apriv->proc_entry->uid = proc_uid;
-        apriv->proc_entry->gid = proc_gid;
-        apriv->proc_entry->owner = THIS_MODULE;
+       if (!apriv->proc_entry)
+               goto fail;
+       apriv->proc_entry->uid = proc_uid;
+       apriv->proc_entry->gid = proc_gid;
+       apriv->proc_entry->owner = THIS_MODULE;
 
        /* Setup the StatsDelta */
        entry = create_proc_entry("StatsDelta",
                                  S_IFREG | (S_IRUGO&proc_perm),
                                  apriv->proc_entry);
-        entry->uid = proc_uid;
-        entry->gid = proc_gid;
+       if (!entry)
+               goto fail_stats_delta;
+       entry->uid = proc_uid;
+       entry->gid = proc_gid;
        entry->data = dev;
-        entry->owner = THIS_MODULE;
+       entry->owner = THIS_MODULE;
        SETPROC_OPS(entry, proc_statsdelta_ops);
 
        /* Setup the Stats */
        entry = create_proc_entry("Stats",
                                  S_IFREG | (S_IRUGO&proc_perm),
                                  apriv->proc_entry);
-        entry->uid = proc_uid;
-        entry->gid = proc_gid;
+       if (!entry)
+               goto fail_stats;
+       entry->uid = proc_uid;
+       entry->gid = proc_gid;
        entry->data = dev;
-        entry->owner = THIS_MODULE;
+       entry->owner = THIS_MODULE;
        SETPROC_OPS(entry, proc_stats_ops);
 
        /* Setup the Status */
        entry = create_proc_entry("Status",
                                  S_IFREG | (S_IRUGO&proc_perm),
                                  apriv->proc_entry);
-        entry->uid = proc_uid;
-        entry->gid = proc_gid;
+       if (!entry)
+               goto fail_status;
+       entry->uid = proc_uid;
+       entry->gid = proc_gid;
        entry->data = dev;
-        entry->owner = THIS_MODULE;
+       entry->owner = THIS_MODULE;
        SETPROC_OPS(entry, proc_status_ops);
 
        /* Setup the Config */
        entry = create_proc_entry("Config",
                                  S_IFREG | proc_perm,
                                  apriv->proc_entry);
-        entry->uid = proc_uid;
-        entry->gid = proc_gid;
+       if (!entry)
+               goto fail_config;
+       entry->uid = proc_uid;
+       entry->gid = proc_gid;
        entry->data = dev;
-        entry->owner = THIS_MODULE;
+       entry->owner = THIS_MODULE;
        SETPROC_OPS(entry, proc_config_ops);
 
        /* Setup the SSID */
        entry = create_proc_entry("SSID",
                                  S_IFREG | proc_perm,
                                  apriv->proc_entry);
-        entry->uid = proc_uid;
-        entry->gid = proc_gid;
+       if (!entry)
+               goto fail_ssid;
+       entry->uid = proc_uid;
+       entry->gid = proc_gid;
        entry->data = dev;
-        entry->owner = THIS_MODULE;
+       entry->owner = THIS_MODULE;
        SETPROC_OPS(entry, proc_SSID_ops);
 
        /* Setup the APList */
        entry = create_proc_entry("APList",
                                  S_IFREG | proc_perm,
                                  apriv->proc_entry);
-        entry->uid = proc_uid;
-        entry->gid = proc_gid;
+       if (!entry)
+               goto fail_aplist;
+       entry->uid = proc_uid;
+       entry->gid = proc_gid;
        entry->data = dev;
-        entry->owner = THIS_MODULE;
+       entry->owner = THIS_MODULE;
        SETPROC_OPS(entry, proc_APList_ops);
 
        /* Setup the BSSList */
        entry = create_proc_entry("BSSList",
                                  S_IFREG | proc_perm,
                                  apriv->proc_entry);
+       if (!entry)
+               goto fail_bsslist;
        entry->uid = proc_uid;
        entry->gid = proc_gid;
        entry->data = dev;
-        entry->owner = THIS_MODULE;
+       entry->owner = THIS_MODULE;
        SETPROC_OPS(entry, proc_BSSList_ops);
 
        /* Setup the WepKey */
        entry = create_proc_entry("WepKey",
                                  S_IFREG | proc_perm,
                                  apriv->proc_entry);
-        entry->uid = proc_uid;
-        entry->gid = proc_gid;
+       if (!entry)
+               goto fail_wepkey;
+       entry->uid = proc_uid;
+       entry->gid = proc_gid;
        entry->data = dev;
-        entry->owner = THIS_MODULE;
+       entry->owner = THIS_MODULE;
        SETPROC_OPS(entry, proc_wepkey_ops);
 
        return 0;
+
+fail_wepkey:
+       remove_proc_entry("BSSList", apriv->proc_entry);
+fail_bsslist:
+       remove_proc_entry("APList", apriv->proc_entry);
+fail_aplist:
+       remove_proc_entry("SSID", apriv->proc_entry);
+fail_ssid:
+       remove_proc_entry("Config", apriv->proc_entry);
+fail_config:
+       remove_proc_entry("Status", apriv->proc_entry);
+fail_status:
+       remove_proc_entry("Stats", apriv->proc_entry);
+fail_stats:
+       remove_proc_entry("StatsDelta", apriv->proc_entry);
+fail_stats_delta:
+       remove_proc_entry(apriv->proc_name, airo_entry);
+fail:
+       return -ENOMEM;
 }
 
 static int takedown_proc_entry( struct net_device *dev,
@@ -4584,15 +4818,14 @@ static int proc_stats_rid_open( struct inode *inode,
                    i*4<stats.len; i++){
                if (!statsLabels[i]) continue;
                if (j+strlen(statsLabels[i])+16>4096) {
-                       printk(KERN_WARNING
-                              "airo: Potentially disasterous buffer overflow averted!\n");
+                       airo_print_warn(apriv->dev->name,
+                              "Potentially disasterous buffer overflow averted!");
                        break;
                }
                j+=sprintf(data->rbuffer+j, "%s: %u\n", statsLabels[i], vals[i]);
        }
        if (i*4>=stats.len){
-               printk(KERN_WARNING
-                      "airo: Got a short rid\n");
+               airo_print_warn(apriv->dev->name, "Got a short rid");
        }
        data->readlen = j;
        return 0;
@@ -4754,7 +4987,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
 
                        line += 14;
                        v = get_dec_u16(line, &i, 4);
-                       v = (v<0) ? 0 : ((v>2312) ? 2312 : v);
+                       v = (v<0) ? 0 : ((v>AIRO_DEF_MTU) ? AIRO_DEF_MTU : v);
                        ai->config.rtsThres = (u16)v;
                        set_bit (FLAG_COMMIT, &ai->flags);
                } else if ( !strncmp( line, "TXMSDULifetime: ", 16 ) ) {
@@ -4788,7 +5021,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
 
                        line += 15;
                        v = get_dec_u16(line, &i, 4);
-                       v = (v<256) ? 256 : ((v>2312) ? 2312 : v);
+                       v = (v<256) ? 256 : ((v>AIRO_DEF_MTU) ? AIRO_DEF_MTU : v);
                        v = v & 0xfffe; /* Make sure its even */
                        ai->config.fragThresh = (u16)v;
                        set_bit (FLAG_COMMIT, &ai->flags);
@@ -4798,8 +5031,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
                        case 'd':  ai->config.modulation=MOD_DEFAULT; set_bit(FLAG_COMMIT, &ai->flags); break;
                        case 'c':  ai->config.modulation=MOD_CCK; set_bit(FLAG_COMMIT, &ai->flags); break;
                        case 'm':  ai->config.modulation=MOD_MOK; set_bit(FLAG_COMMIT, &ai->flags); break;
-                       default:
-                               printk( KERN_WARNING "airo: Unknown modulation\n" );
+                       default: airo_print_warn(ai->dev->name, "Unknown modulation");
                        }
                } else if (!strncmp(line, "Preamble: ", 10)) {
                        line += 10;
@@ -4807,10 +5039,10 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
                        case 'a': ai->config.preamble=PREAMBLE_AUTO; set_bit(FLAG_COMMIT, &ai->flags); break;
                        case 'l': ai->config.preamble=PREAMBLE_LONG; set_bit(FLAG_COMMIT, &ai->flags); break;
                        case 's': ai->config.preamble=PREAMBLE_SHORT; set_bit(FLAG_COMMIT, &ai->flags); break;
-                       default: printk(KERN_WARNING "airo: Unknown preamble\n");
+                       default: airo_print_warn(ai->dev->name, "Unknown preamble");
                        }
                } else {
-                       printk( KERN_WARNING "Couldn't figure out %s\n", line );
+                       airo_print_warn(ai->dev->name, "Couldn't figure out %s", line);
                }
                while( line[0] && line[0] != '\n' ) line++;
                if ( line[0] ) line++;
@@ -5036,7 +5268,6 @@ static int set_wep_key(struct airo_info *ai, u16 index,
                wkr.len = sizeof(wkr);
                wkr.kindex = 0xffff;
                wkr.mac[0] = (char)index;
-               if (perm) printk(KERN_INFO "Setting transmit key to %d\n", index);
                if (perm) ai->defindex = (char)index;
        } else {
 // We are actually setting the key
@@ -5045,7 +5276,6 @@ static int set_wep_key(struct airo_info *ai, u16 index,
                wkr.klen = keylen;
                memcpy( wkr.key, key, keylen );
                memcpy( wkr.mac, macaddr, ETH_ALEN );
-               printk(KERN_INFO "Setting key %d\n", index);
        }
 
        if (perm) disable_MAC(ai, lock);
@@ -5078,7 +5308,7 @@ static void proc_wepkey_on_close( struct inode *inode, struct file *file ) {
                }
                j = 2;
        } else {
-               printk(KERN_ERR "airo:  WepKey passed invalid key index\n");
+               airo_print_err(ai->dev->name, "WepKey passed invalid key index");
                return;
        }
 
@@ -5311,11 +5541,6 @@ static int proc_close( struct inode *inode, struct file *file )
        return 0;
 }
 
-static struct net_device_list {
-       struct net_device *dev;
-       struct net_device_list *next;
-} *airo_devices;
-
 /* Since the card doesn't automatically switch to the right WEP mode,
    we will make it do it.  If the card isn't associated, every secs we
    will switch WEP modes to see if that will help.  If the card is
@@ -5354,30 +5579,10 @@ static void timer_func( struct net_device *dev ) {
        up(&apriv->sem);
 
 /* Schedule check to see if the change worked */
-       clear_bit(JOB_AUTOWEP, &apriv->flags);
+       clear_bit(JOB_AUTOWEP, &apriv->jobs);
        apriv->expires = RUN_AT(HZ*3);
 }
 
-static int add_airo_dev( struct net_device *dev ) {
-       struct net_device_list *node = kmalloc( sizeof( *node ), GFP_KERNEL );
-       if ( !node )
-               return -ENOMEM;
-
-       node->dev = dev;
-       node->next = airo_devices;
-       airo_devices = node;
-
-       return 0;
-}
-
-static void del_airo_dev( struct net_device *dev ) {
-       struct net_device_list **p = &airo_devices;
-       while( *p && ( (*p)->dev != dev ) )
-               p = &(*p)->next;
-       if ( *p && (*p)->dev == dev )
-               *p = (*p)->next;
-}
-
 #ifdef CONFIG_PCI
 static int __devinit airo_pci_probe(struct pci_dev *pdev,
                                    const struct pci_device_id *pent)
@@ -5401,6 +5606,10 @@ static int __devinit airo_pci_probe(struct pci_dev *pdev,
 
 static void __devexit airo_pci_remove(struct pci_dev *pdev)
 {
+       struct net_device *dev = pci_get_drvdata(pdev);
+
+       airo_print_info(dev->name, "Unregistering...");
+       stop_airo_card(dev, 1);
 }
 
 static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state)
@@ -5482,26 +5691,40 @@ static int airo_pci_resume(struct pci_dev *pdev)
 
 static int __init airo_init_module( void )
 {
-       int i, have_isa_dev = 0;
+       int i;
+#if 0
+       int have_isa_dev = 0;
+#endif
 
        airo_entry = create_proc_entry("aironet",
                                       S_IFDIR | airo_perm,
                                       proc_root_driver);
-        airo_entry->uid = proc_uid;
-        airo_entry->gid = proc_gid;
+
+       if (airo_entry) {
+               airo_entry->uid = proc_uid;
+               airo_entry->gid = proc_gid;
+       }
 
        for( i = 0; i < 4 && io[i] && irq[i]; i++ ) {
-               printk( KERN_INFO
-                       "airo:  Trying to configure ISA adapter at irq=%d io=0x%x\n",
-                       irq[i], io[i] );
+               airo_print_info("", "Trying to configure ISA adapter at irq=%d "
+                       "io=0x%x", irq[i], io[i] );
                if (init_airo_card( irq[i], io[i], 0, NULL ))
+#if 0
                        have_isa_dev = 1;
+#else
+                       /* do nothing */ ;
+#endif
        }
 
 #ifdef CONFIG_PCI
-       printk( KERN_INFO "airo:  Probing for PCI adapters\n" );
-       pci_register_driver(&airo_driver);
-       printk( KERN_INFO "airo:  Finished probing for PCI adapters\n" );
+       airo_print_info("", "Probing for PCI adapters");
+       i = pci_register_driver(&airo_driver);
+       airo_print_info("", "Finished probing for PCI adapters");
+
+       if (i) {
+               remove_proc_entry("aironet", proc_root_driver);
+               return i;
+       }
 #endif
 
        /* Always exit with success, as we are a library module
@@ -5512,9 +5735,11 @@ static int __init airo_init_module( void )
 
 static void __exit airo_cleanup_module( void )
 {
-       while( airo_devices ) {
-               printk( KERN_INFO "airo: Unregistering %s\n", airo_devices->dev->name );
-               stop_airo_card( airo_devices->dev, 1 );
+       struct airo_info *ai;
+       while(!list_empty(&airo_devices)) {
+               ai = list_entry(airo_devices.next, struct airo_info, dev_list);
+               airo_print_info(ai->dev->name, "Unregistering...");
+               stop_airo_card(ai->dev, 1);
        }
 #ifdef CONFIG_PCI
        pci_unregister_driver(&airo_driver);
@@ -5624,7 +5849,8 @@ static int airo_set_freq(struct net_device *dev,
                /* We should do a better check than that,
                 * based on the card capability !!! */
                if((channel < 1) || (channel > 14)) {
-                       printk(KERN_DEBUG "%s: New channel value of %d is invalid!\n", dev->name, fwrq->m);
+                       airo_print_dbg(dev->name, "New channel value of %d is invalid!",
+                               fwrq->m);
                        rc = -EINVAL;
                } else {
                        readConfigRid(local, 1);
@@ -5691,7 +5917,7 @@ static int airo_set_essid(struct net_device *dev,
                int     index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
 
                /* Check the size of the string */
-               if(dwrq->length > IW_ESSID_MAX_SIZE+1) {
+               if(dwrq->length > IW_ESSID_MAX_SIZE) {
                        return -E2BIG ;
                }
                /* Check if index is valid */
@@ -5703,7 +5929,7 @@ 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 - 1;
+               SSID_rid.ssids[index].len = dwrq->length;
        }
        SSID_rid.len = sizeof(SSID_rid);
        /* Write it to the card */
@@ -5733,7 +5959,6 @@ static int airo_get_essid(struct net_device *dev,
 
        /* Get the current SSID */
        memcpy(extra, status_rid.SSID, status_rid.SSIDlen);
-       extra[status_rid.SSIDlen] = '\0';
        /* If none, we may want to get the one that was set */
 
        /* Push it out ! */
@@ -5756,11 +5981,13 @@ static int airo_set_wap(struct net_device *dev,
        Cmd cmd;
        Resp rsp;
        APListRid APList_rid;
-       static const unsigned char bcast[ETH_ALEN] = { 255, 255, 255, 255, 255, 255 };
+       static const u8 any[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+       static const u8 off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
 
        if (awrq->sa_family != ARPHRD_ETHER)
                return -EINVAL;
-       else if (!memcmp(bcast, awrq->sa_data, ETH_ALEN)) {
+       else if (!memcmp(any, awrq->sa_data, ETH_ALEN) ||
+                !memcmp(off, awrq->sa_data, ETH_ALEN)) {
                memset(&cmd, 0, sizeof(cmd));
                cmd.cmd=CMD_LOSE_SYNC;
                if (down_interruptible(&local->sem))
@@ -5811,7 +6038,7 @@ static int airo_set_nick(struct net_device *dev,
        struct airo_info *local = dev->priv;
 
        /* Check the size of the string */
-       if(dwrq->length > 16 + 1) {
+       if(dwrq->length > 16) {
                return -E2BIG;
        }
        readConfigRid(local, 1);
@@ -5836,7 +6063,7 @@ static int airo_get_nick(struct net_device *dev,
        readConfigRid(local, 1);
        strncpy(extra, local->config.nodeName, 16);
        extra[16] = '\0';
-       dwrq->length = strlen(extra) + 1;
+       dwrq->length = strlen(extra);
 
        return 0;
 }
@@ -5946,8 +6173,8 @@ static int airo_set_rts(struct net_device *dev,
        int rthr = vwrq->value;
 
        if(vwrq->disabled)
-               rthr = 2312;
-       if((rthr < 0) || (rthr > 2312)) {
+               rthr = AIRO_DEF_MTU;
+       if((rthr < 0) || (rthr > AIRO_DEF_MTU)) {
                return -EINVAL;
        }
        readConfigRid(local, 1);
@@ -5970,7 +6197,7 @@ static int airo_get_rts(struct net_device *dev,
 
        readConfigRid(local, 1);
        vwrq->value = local->config.rtsThres;
-       vwrq->disabled = (vwrq->value >= 2312);
+       vwrq->disabled = (vwrq->value >= AIRO_DEF_MTU);
        vwrq->fixed = 1;
 
        return 0;
@@ -5989,8 +6216,8 @@ static int airo_set_frag(struct net_device *dev,
        int fthr = vwrq->value;
 
        if(vwrq->disabled)
-               fthr = 2312;
-       if((fthr < 256) || (fthr > 2312)) {
+               fthr = AIRO_DEF_MTU;
+       if((fthr < 256) || (fthr > AIRO_DEF_MTU)) {
                return -EINVAL;
        }
        fthr &= ~0x1;   /* Get an even value - is it really needed ??? */
@@ -6014,7 +6241,7 @@ static int airo_get_frag(struct net_device *dev,
 
        readConfigRid(local, 1);
        vwrq->value = local->config.fragThresh;
-       vwrq->disabled = (vwrq->value >= 2312);
+       vwrq->disabled = (vwrq->value >= AIRO_DEF_MTU);
        vwrq->fixed = 1;
 
        return 0;
@@ -6251,6 +6478,272 @@ static int airo_get_encode(struct net_device *dev,
 
 /*------------------------------------------------------------------*/
 /*
+ * Wireless Handler : set extended Encryption parameters
+ */
+static int airo_set_encodeext(struct net_device *dev,
+                          struct iw_request_info *info,
+                           union iwreq_data *wrqu,
+                           char *extra)
+{
+       struct airo_info *local = dev->priv;
+       struct iw_point *encoding = &wrqu->encoding;
+       struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+       CapabilityRid cap_rid;          /* Card capability info */
+       int perm = ( encoding->flags & IW_ENCODE_TEMP ? 0 : 1 );
+       u16 currentAuthType = local->config.authType;
+       int idx, key_len, alg = ext->alg, set_key = 1;
+       wep_key_t key;
+
+       /* Is WEP supported ? */
+       readCapabilityRid(local, &cap_rid, 1);
+       /* Older firmware doesn't support this...
+       if(!(cap_rid.softCap & 2)) {
+               return -EOPNOTSUPP;
+       } */
+       readConfigRid(local, 1);
+
+       /* Determine and validate the key index */
+       idx = encoding->flags & IW_ENCODE_INDEX;
+       if (idx) {
+               if (idx < 1 || idx > ((cap_rid.softCap & 0x80) ? 4:1))
+                       return -EINVAL;
+               idx--;
+       } else
+               idx = get_wep_key(local, 0xffff);
+
+       if (encoding->flags & IW_ENCODE_DISABLED)
+               alg = IW_ENCODE_ALG_NONE;
+
+       if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
+               /* Only set transmit key index here, actual
+                * key is set below if needed.
+                */
+               set_wep_key(local, idx, NULL, 0, perm, 1);
+               set_key = ext->key_len > 0 ? 1 : 0;
+       }
+
+       if (set_key) {
+               /* Set the requested key first */
+               memset(key.key, 0, MAX_KEY_SIZE);
+               switch (alg) {
+               case IW_ENCODE_ALG_NONE:
+                       key.len = 0;
+                       break;
+               case IW_ENCODE_ALG_WEP:
+                       if (ext->key_len > MIN_KEY_SIZE) {
+                               key.len = MAX_KEY_SIZE;
+                       } else if (ext->key_len > 0) {
+                               key.len = MIN_KEY_SIZE;
+                       } else {
+                               return -EINVAL;
+                       }
+                       key_len = min (ext->key_len, key.len);
+                       memcpy(key.key, ext->key, key_len);
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               /* Send the key to the card */
+               set_wep_key(local, idx, key.key, key.len, perm, 1);
+       }
+
+       /* Read the flags */
+       if(encoding->flags & IW_ENCODE_DISABLED)
+               local->config.authType = AUTH_OPEN;     // disable encryption
+       if(encoding->flags & IW_ENCODE_RESTRICTED)
+               local->config.authType = AUTH_SHAREDKEY;        // Only Both
+       if(encoding->flags & IW_ENCODE_OPEN)
+               local->config.authType = AUTH_ENCRYPT;  // Only Wep
+       /* Commit the changes to flags if needed */
+       if (local->config.authType != currentAuthType)
+               set_bit (FLAG_COMMIT, &local->flags);
+
+       return -EINPROGRESS;
+}
+
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get extended Encryption parameters
+ */
+static int airo_get_encodeext(struct net_device *dev,
+                           struct iw_request_info *info,
+                           union iwreq_data *wrqu,
+                           char *extra)
+{
+       struct airo_info *local = dev->priv;
+       struct iw_point *encoding = &wrqu->encoding;
+       struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+       CapabilityRid cap_rid;          /* Card capability info */
+       int idx, max_key_len;
+
+       /* Is it supported ? */
+       readCapabilityRid(local, &cap_rid, 1);
+       if(!(cap_rid.softCap & 2)) {
+               return -EOPNOTSUPP;
+       }
+       readConfigRid(local, 1);
+
+       max_key_len = encoding->length - sizeof(*ext);
+       if (max_key_len < 0)
+               return -EINVAL;
+
+       idx = encoding->flags & IW_ENCODE_INDEX;
+       if (idx) {
+               if (idx < 1 || idx > ((cap_rid.softCap & 0x80) ? 4:1))
+                       return -EINVAL;
+               idx--;
+       } else
+               idx = get_wep_key(local, 0xffff);
+
+       encoding->flags = idx + 1;
+       memset(ext, 0, sizeof(*ext));
+
+       /* Check encryption mode */
+       switch(local->config.authType) {
+               case AUTH_ENCRYPT:
+                       encoding->flags = IW_ENCODE_ALG_WEP | IW_ENCODE_ENABLED;
+                       break;
+               case AUTH_SHAREDKEY:
+                       encoding->flags = IW_ENCODE_ALG_WEP | IW_ENCODE_ENABLED;
+                       break;
+               default:
+               case AUTH_OPEN:
+                       encoding->flags = IW_ENCODE_ALG_NONE | IW_ENCODE_DISABLED;
+                       break;
+       }
+       /* We can't return the key, so set the proper flag and return zero */
+       encoding->flags |= IW_ENCODE_NOKEY;
+       memset(extra, 0, 16);
+       
+       /* Copy the key to the user buffer */
+       ext->key_len = get_wep_key(local, idx);
+       if (ext->key_len > 16) {
+               ext->key_len=0;
+       }
+
+       return 0;
+}
+
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : set extended authentication parameters
+ */
+static int airo_set_auth(struct net_device *dev,
+                              struct iw_request_info *info,
+                              union iwreq_data *wrqu, char *extra)
+{
+       struct airo_info *local = dev->priv;
+       struct iw_param *param = &wrqu->param;
+       u16 currentAuthType = local->config.authType;
+
+       switch (param->flags & IW_AUTH_INDEX) {
+       case IW_AUTH_WPA_VERSION:
+       case IW_AUTH_CIPHER_PAIRWISE:
+       case IW_AUTH_CIPHER_GROUP:
+       case IW_AUTH_KEY_MGMT:
+       case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+       case IW_AUTH_PRIVACY_INVOKED:
+               /*
+                * airo does not use these parameters
+                */
+               break;
+
+       case IW_AUTH_DROP_UNENCRYPTED:
+               if (param->value) {
+                       /* Only change auth type if unencrypted */
+                       if (currentAuthType == AUTH_OPEN)
+                               local->config.authType = AUTH_ENCRYPT;
+               } else {
+                       local->config.authType = AUTH_OPEN;
+               }
+
+               /* Commit the changes to flags if needed */
+               if (local->config.authType != currentAuthType)
+                       set_bit (FLAG_COMMIT, &local->flags);
+               break;
+
+       case IW_AUTH_80211_AUTH_ALG: {
+                       /* FIXME: What about AUTH_OPEN?  This API seems to
+                        * disallow setting our auth to AUTH_OPEN.
+                        */
+                       if (param->value & IW_AUTH_ALG_SHARED_KEY) {
+                               local->config.authType = AUTH_SHAREDKEY;
+                       } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) {
+                               local->config.authType = AUTH_ENCRYPT;
+                       } else
+                               return -EINVAL;
+                       break;
+
+                       /* Commit the changes to flags if needed */
+                       if (local->config.authType != currentAuthType)
+                               set_bit (FLAG_COMMIT, &local->flags);
+               }
+
+       case IW_AUTH_WPA_ENABLED:
+               /* Silently accept disable of WPA */
+               if (param->value > 0)
+                       return -EOPNOTSUPP;
+               break;
+
+       default:
+               return -EOPNOTSUPP;
+       }
+       return -EINPROGRESS;
+}
+
+
+/*------------------------------------------------------------------*/
+/*
+ * Wireless Handler : get extended authentication parameters
+ */
+static int airo_get_auth(struct net_device *dev,
+                              struct iw_request_info *info,
+                              union iwreq_data *wrqu, char *extra)
+{
+       struct airo_info *local = dev->priv;
+       struct iw_param *param = &wrqu->param;
+       u16 currentAuthType = local->config.authType;
+
+       switch (param->flags & IW_AUTH_INDEX) {
+       case IW_AUTH_DROP_UNENCRYPTED:
+               switch (currentAuthType) {
+               case AUTH_SHAREDKEY:
+               case AUTH_ENCRYPT:
+                       param->value = 1;
+                       break;
+               default:
+                       param->value = 0;
+                       break;
+               }
+               break;
+
+       case IW_AUTH_80211_AUTH_ALG:
+               switch (currentAuthType) {
+               case AUTH_SHAREDKEY:
+                       param->value = IW_AUTH_ALG_SHARED_KEY;
+                       break;
+               case AUTH_ENCRYPT:
+               default:
+                       param->value = IW_AUTH_ALG_OPEN_SYSTEM;
+                       break;
+               }
+               break;
+
+       case IW_AUTH_WPA_ENABLED:
+               param->value = 0;
+               break;
+
+       default:
+               return -EOPNOTSUPP;
+       }
+       return 0;
+}
+
+
+/*------------------------------------------------------------------*/
+/*
  * Wireless Handler : set Tx-Power
  */
 static int airo_set_txpow(struct net_device *dev,
@@ -6322,9 +6815,9 @@ static int airo_set_retry(struct net_device *dev,
        }
        readConfigRid(local, 1);
        if(vwrq->flags & IW_RETRY_LIMIT) {
-               if(vwrq->flags & IW_RETRY_MAX)
+               if(vwrq->flags & IW_RETRY_LONG)
                        local->config.longRetryLimit = vwrq->value;
-               else if (vwrq->flags & IW_RETRY_MIN)
+               else if (vwrq->flags & IW_RETRY_SHORT)
                        local->config.shortRetryLimit = vwrq->value;
                else {
                        /* No modifier : set both */
@@ -6360,14 +6853,14 @@ static int airo_get_retry(struct net_device *dev,
        if((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
                vwrq->flags = IW_RETRY_LIFETIME;
                vwrq->value = (int)local->config.txLifetime * 1024;
-       } else if((vwrq->flags & IW_RETRY_MAX)) {
-               vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+       } else if((vwrq->flags & IW_RETRY_LONG)) {
+               vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
                vwrq->value = (int)local->config.longRetryLimit;
        } else {
                vwrq->flags = IW_RETRY_LIMIT;
                vwrq->value = (int)local->config.shortRetryLimit;
                if((int)local->config.shortRetryLimit != (int)local->config.longRetryLimit)
-                       vwrq->flags |= IW_RETRY_MIN;
+                       vwrq->flags |= IW_RETRY_SHORT;
        }
 
        return 0;
@@ -6443,9 +6936,9 @@ static int airo_get_range(struct net_device *dev,
                range->throughput = 1500 * 1000;
 
        range->min_rts = 0;
-       range->max_rts = 2312;
+       range->max_rts = AIRO_DEF_MTU;
        range->min_frag = 256;
-       range->max_frag = 2312;
+       range->max_frag = AIRO_DEF_MTU;
 
        if(cap_rid.softCap & 2) {
                // WEP: RC4 40 bits
@@ -6477,7 +6970,7 @@ static int airo_get_range(struct net_device *dev,
        }
        range->num_txpower = i;
        range->txpower_capa = IW_TXPOW_MWATT;
-       range->we_version_source = 12;
+       range->we_version_source = 19;
        range->we_version_compiled = WIRELESS_EXT;
        range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
        range->retry_flags = IW_RETRY_LIMIT;
@@ -6545,6 +7038,7 @@ static int airo_set_power(struct net_device *dev,
                        local->config.rmode |= RXMODE_BC_MC_ADDR;
                        set_bit (FLAG_COMMIT, &local->flags);
                case IW_POWER_ON:
+                       /* This is broken, fixme ;-) */
                        break;
                default:
                        return -EINVAL;
@@ -6706,6 +7200,7 @@ static int airo_set_scan(struct net_device *dev,
        struct airo_info *ai = dev->priv;
        Cmd cmd;
        Resp rsp;
+       int wake = 0;
 
        /* Note : you may have realised that, as this is a SET operation,
         * this is privileged and therefore a normal user can't
@@ -6715,17 +7210,25 @@ static int airo_set_scan(struct net_device *dev,
         * Jean II */
        if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN;
 
+       if (down_interruptible(&ai->sem))
+               return -ERESTARTSYS;
+
+       /* If there's already a scan in progress, don't
+        * trigger another one. */
+       if (ai->scan_timeout > 0)
+               goto out;
+
        /* Initiate a scan command */
+       ai->scan_timeout = RUN_AT(3*HZ);
        memset(&cmd, 0, sizeof(cmd));
        cmd.cmd=CMD_LISTBSS;
-       if (down_interruptible(&ai->sem))
-               return -ERESTARTSYS;
        issuecommand(ai, &cmd, &rsp);
-       ai->scan_timestamp = jiffies;
-       up(&ai->sem);
-
-       /* At this point, just return to the user. */
+       wake = 1;
 
+out:
+       up(&ai->sem);
+       if (wake)
+               wake_up_interruptible(&ai->thr_wait);
        return 0;
 }
 
@@ -6744,6 +7247,7 @@ static inline char *airo_translate_scan(struct net_device *dev,
        u16                     capabilities;
        char *                  current_val;    /* For rates */
        int                     i;
+       char *          buf;
 
        /* First entry *MUST* be the AP MAC address */
        iwe.cmd = SIOCGIWAP;
@@ -6830,8 +7334,69 @@ static inline char *airo_translate_scan(struct net_device *dev,
        if((current_val - current_ev) > IW_EV_LCP_LEN)
                current_ev = current_val;
 
-       /* The other data in the scan result are not really
-        * interesting, so for now drop it - Jean II */
+       /* Beacon interval */
+       buf = kmalloc(30, GFP_KERNEL);
+       if (buf) {
+               iwe.cmd = IWEVCUSTOM;
+               sprintf(buf, "bcn_int=%d", bss->beaconInterval);
+               iwe.u.data.length = strlen(buf);
+               current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf);
+               kfree(buf);
+       }
+
+       /* Put WPA/RSN Information Elements into the event stream */
+       if (test_bit(FLAG_WPA_CAPABLE, &ai->flags)) {
+               unsigned int num_null_ies = 0;
+               u16 length = sizeof (bss->extra.iep);
+               struct ieee80211_info_element *info_element =
+                       (struct ieee80211_info_element *) &bss->extra.iep;
+
+               while ((length >= sizeof(*info_element)) && (num_null_ies < 2)) {
+                       if (sizeof(*info_element) + info_element->len > length) {
+                               /* Invalid element, don't continue parsing IE */
+                               break;
+                       }
+
+                       switch (info_element->id) {
+                       case MFIE_TYPE_SSID:
+                               /* Two zero-length SSID elements
+                                * mean we're done parsing elements */
+                               if (!info_element->len)
+                                       num_null_ies++;
+                               break;
+
+                       case MFIE_TYPE_GENERIC:
+                               if (info_element->len >= 4 &&
+                                   info_element->data[0] == 0x00 &&
+                                   info_element->data[1] == 0x50 &&
+                                   info_element->data[2] == 0xf2 &&
+                                   info_element->data[3] == 0x01) {
+                                       iwe.cmd = IWEVGENIE;
+                                       iwe.u.data.length = min(info_element->len + 2,
+                                                                 MAX_WPA_IE_LEN);
+                                       current_ev = iwe_stream_add_point(current_ev, end_buf,
+                                                       &iwe, (char *) info_element);
+                               }
+                               break;
+
+                       case MFIE_TYPE_RSN:
+                               iwe.cmd = IWEVGENIE;
+                               iwe.u.data.length = min(info_element->len + 2,
+                                                         MAX_WPA_IE_LEN);
+                               current_ev = iwe_stream_add_point(current_ev, end_buf,
+                                               &iwe, (char *) info_element);
+                               break;
+
+                       default:
+                               break;
+                       }
+
+                       length -= sizeof(*info_element) + info_element->len;
+                       info_element =
+                           (struct ieee80211_info_element *)&info_element->
+                           data[info_element->len];
+               }
+       }
        return current_ev;
 }
 
@@ -6845,59 +7410,38 @@ static int airo_get_scan(struct net_device *dev,
                         char *extra)
 {
        struct airo_info *ai = dev->priv;
-       BSSListRid BSSList;
-       int rc;
+       BSSListElement *net;
+       int err = 0;
        char *current_ev = extra;
 
-       /* When we are associated again, the scan has surely finished.
-        * Just in case, let's make sure enough time has elapsed since
-        * we started the scan. - Javier */
-       if(ai->scan_timestamp && time_before(jiffies,ai->scan_timestamp+3*HZ)) {
-               /* Important note : we don't want to block the caller
-                * until results are ready for various reasons.
-                * First, managing wait queues is complex and racy
-                * (there may be multiple simultaneous callers).
-                * Second, we grab some rtnetlink lock before comming
-                * here (in dev_ioctl()).
-                * Third, the caller can wait on the Wireless Event
-                * - Jean II */
+       /* If a scan is in-progress, return -EAGAIN */
+       if (ai->scan_timeout > 0)
                return -EAGAIN;
-       }
-       ai->scan_timestamp = 0;
 
-       /* There's only a race with proc_BSSList_open(), but its
-        * consequences are begnign. So I don't bother fixing it - Javier */
-
-       /* Try to read the first entry of the scan result */
-       rc = PC4500_readrid(ai, RID_BSSLISTFIRST, &BSSList, sizeof(BSSList), 1);
-       if((rc) || (BSSList.index == 0xffff)) {
-               /* Client error, no scan results...
-                * The caller need to restart the scan. */
-               return -ENODATA;
-       }
+       if (down_interruptible(&ai->sem))
+               return -EAGAIN;
 
-       /* Read and parse all entries */
-       while((!rc) && (BSSList.index != 0xffff)) {
+       list_for_each_entry (net, &ai->network_list, list) {
                /* Translate to WE format this entry */
                current_ev = airo_translate_scan(dev, current_ev,
                                                 extra + dwrq->length,
-                                                &BSSList);
+                                                &net->bss);
 
                /* Check if there is space for one more entry */
                if((extra + dwrq->length - current_ev) <= IW_EV_ADDR_LEN) {
                        /* Ask user space to try again with a bigger buffer */
-                       return -E2BIG;
+                       err = -E2BIG;
+                       goto out;
                }
-
-               /* Read next entry */
-               rc = PC4500_readrid(ai, RID_BSSLISTNEXT,
-                                   &BSSList, sizeof(BSSList), 1);
        }
+
        /* Length of data */
        dwrq->length = (current_ev - extra);
        dwrq->flags = 0;        /* todo */
 
-       return 0;
+out:
+       up(&ai->sem);
+       return err;
 }
 
 /*------------------------------------------------------------------*/
@@ -7005,6 +7549,15 @@ static const iw_handler          airo_handler[] =
        (iw_handler) airo_get_encode,           /* SIOCGIWENCODE */
        (iw_handler) airo_set_power,            /* SIOCSIWPOWER */
        (iw_handler) airo_get_power,            /* SIOCGIWPOWER */
+       (iw_handler) NULL,                      /* -- hole -- */
+       (iw_handler) NULL,                      /* -- hole -- */
+       (iw_handler) NULL,                      /* SIOCSIWGENIE */
+       (iw_handler) NULL,                      /* SIOCGIWGENIE */
+       (iw_handler) airo_set_auth,             /* SIOCSIWAUTH */
+       (iw_handler) airo_get_auth,             /* SIOCGIWAUTH */
+       (iw_handler) airo_set_encodeext,        /* SIOCSIWENCODEEXT */
+       (iw_handler) airo_get_encodeext,        /* SIOCGIWENCODEEXT */
+       (iw_handler) NULL,                      /* SIOCSIWPMKSA */
 };
 
 /* Note : don't describe AIROIDIFC and AIROOLDIDIFC in here.
@@ -7125,7 +7678,7 @@ static void airo_read_wireless_stats(struct airo_info *local)
        u32 *vals = stats_rid.vals;
 
        /* Get stats out of the card */
-       clear_bit(JOB_WSTATS, &local->flags);
+       clear_bit(JOB_WSTATS, &local->jobs);
        if (local->power.event) {
                up(&local->sem);
                return;
@@ -7169,10 +7722,10 @@ static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev)
 {
        struct airo_info *local =  dev->priv;
 
-       if (!test_bit(JOB_WSTATS, &local->flags)) {
+       if (!test_bit(JOB_WSTATS, &local->jobs)) {
                /* Get stats out of the card if available */
                if (down_trylock(&local->sem) != 0) {
-                       set_bit(JOB_WSTATS, &local->flags);
+                       set_bit(JOB_WSTATS, &local->jobs);
                        wake_up_interruptible(&local->thr_wait);
                } else
                        airo_read_wireless_stats(local);
@@ -7436,7 +7989,7 @@ static int cmdreset(struct airo_info *ai) {
        disable_MAC(ai, 1);
 
        if(!waitbusy (ai)){
-               printk(KERN_INFO "Waitbusy hang before RESET\n");
+               airo_print_info(ai->dev->name, "Waitbusy hang before RESET");
                return -EBUSY;
        }
 
@@ -7445,7 +7998,7 @@ static int cmdreset(struct airo_info *ai) {
        ssleep(1);                      /* WAS 600 12/7/00 */
 
        if(!waitbusy (ai)){
-               printk(KERN_INFO "Waitbusy hang AFTER RESET\n");
+               airo_print_info(ai->dev->name, "Waitbusy hang AFTER RESET");
                return -EBUSY;
        }
        return 0;
@@ -7473,7 +8026,7 @@ static int setflashmode (struct airo_info *ai) {
 
        if(!waitbusy(ai)) {
                clear_bit (FLAG_FLASHING, &ai->flags);
-               printk(KERN_INFO "Waitbusy hang after setflash mode\n");
+               airo_print_info(ai->dev->name, "Waitbusy hang after setflash mode");
                return -EIO;
        }
        return 0;
@@ -7502,7 +8055,7 @@ static int flashpchar(struct airo_info *ai,int byte,int dwelltime) {
 
        /* timeout for busy clear wait */
        if(waittime <= 0 ){
-               printk(KERN_INFO "flash putchar busywait timeout! \n");
+               airo_print_info(ai->dev->name, "flash putchar busywait timeout!");
                return -EBUSY;
        }
 
@@ -7591,7 +8144,7 @@ static int flashrestart(struct airo_info *ai,struct net_device *dev){
        if (!test_bit(FLAG_MPI,&ai->flags))
                for( i = 0; i < MAX_FIDS; i++ ) {
                        ai->fids[i] = transmit_allocate
-                               ( ai, 2312, i >= MAX_FIDS / 2 );
+                               ( ai, AIRO_DEF_MTU, i >= MAX_FIDS / 2 );
                }
 
        ssleep(1);                      /* Added 12/7/00 */