Merge to Fedora kernel-2.6.18-1.2224_FC5 patched with stable patch-2.6.18.1-vs2.0...
[linux-2.6.git] / drivers / net / wireless / airo.c
index 00764dd..a4dd139 100644 (file)
@@ -19,7 +19,6 @@
 
 ======================================================================*/
 
-#include <linux/config.h>
 #include <linux/init.h>
 
 #include <linux/kernel.h>
@@ -47,6 +46,7 @@
 #include <linux/ioport.h>
 #include <linux/pci.h>
 #include <asm/uaccess.h>
+#include <net/ieee80211.h>
 
 #include "airo.h"
 
@@ -467,6 +467,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 +741,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,6 +777,9 @@ typedef struct {
   } fh;
   u16 dsChannel;
   u16 atimWindow;
+
+  /* Only present on firmware >= 5.30.17 */
+  BSSListRidExtra extra;
 } BSSListRid;
 
 typedef struct {
@@ -1140,8 +1153,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
@@ -1151,6 +1162,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
@@ -1158,17 +1170,19 @@ struct airo_info {
 #define FLAG_COMMIT    13
 #define FLAG_RESET     14
 #define FLAG_FLASHING  15
-#define JOB_MASK       0x2ff0000
-#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 JOB_SCAN_RESULTS  25
+#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;
@@ -1208,6 +1222,11 @@ struct airo_info {
 #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;
@@ -1264,7 +1283,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);
 
@@ -1705,24 +1724,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;
+               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 ? ai->bssListFirst : ai->bssListNext,
+                           list, ai->bssListRidLen, 1);
 
        list->len = le16_to_cpu(list->len);
        list->index = le16_to_cpu(list->index);
@@ -2112,7 +2131,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);
@@ -2162,7 +2181,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);
@@ -2177,7 +2196,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);
@@ -2233,7 +2252,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);
@@ -2244,7 +2263,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;
@@ -2272,10 +2291,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);
@@ -2290,7 +2309,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);
@@ -2302,7 +2321,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);
@@ -2380,7 +2399,7 @@ void stop_airo_card( struct net_device *dev, int freeres )
                }
                clear_bit(FLAG_REGISTERED, &ai->flags);
        }
-       set_bit(JOB_DIE, &ai->flags);
+       set_bit(JOB_DIE, &ai->jobs);
        kill_proc(ai->thr_pid, SIGTERM, 1);
        wait_for_completion(&ai->thr_exited);
 
@@ -2701,14 +2720,14 @@ static int reset_card( struct net_device *dev , int lock) {
        return 0;
 }
 
-#define MAX_NETWORK_COUNT      64
+#define AIRO_MAX_NETWORK_COUNT 64
 static int airo_networks_allocate(struct airo_info *ai)
 {
        if (ai->networks)
                return 0;
 
        ai->networks =
-           kzalloc(MAX_NETWORK_COUNT * sizeof(BSSListElement),
+           kzalloc(AIRO_MAX_NETWORK_COUNT * sizeof(BSSListElement),
                    GFP_KERNEL);
        if (!ai->networks) {
                airo_print_warn(ai->dev->name, "Out of memory allocating beacons");
@@ -2732,11 +2751,33 @@ static void airo_networks_initialize(struct airo_info *ai)
 
        INIT_LIST_HEAD(&ai->network_free_list);
        INIT_LIST_HEAD(&ai->network_list);
-       for (i = 0; i < MAX_NETWORK_COUNT; i++)
+       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 )
@@ -2759,6 +2800,7 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
        ai = dev->priv;
        ai->wifidev = NULL;
        ai->flags = 0;
+       ai->jobs = 0;
        ai->dev = dev;
        if (pci && (pci->device == 0x5000 || pci->device == 0xa504)) {
                airo_print_dbg(dev->name, "Found an MPI350 card");
@@ -2806,7 +2848,7 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
        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) {
                airo_print_err(dev->name, "register interrupt %d failed, rc %d",
                                irq, rc);
@@ -2838,6 +2880,18 @@ 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) {
                airo_print_err(dev->name, "Couldn't register_netdev");
@@ -2875,7 +2929,7 @@ err_out_irq:
 err_out_unlink:
        del_airo_dev(dev);
 err_out_thr:
-       set_bit(JOB_DIE, &ai->flags);
+       set_bit(JOB_DIE, &ai->jobs);
        kill_proc(ai->thr_pid, SIGTERM, 1);
        wait_for_completion(&ai->thr_exited);
 err_out_free:
@@ -2933,7 +2987,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;
@@ -2947,7 +3001,7 @@ static void airo_send_event(struct net_device *dev) {
 
 static void airo_process_scan_results (struct airo_info *ai) {
        union iwreq_data        wrqu;
-       BSSListRid BSSList;
+       BSSListRid bss;
        int rc;
        BSSListElement * loop_net;
        BSSListElement * tmp_net;
@@ -2960,15 +3014,15 @@ static void airo_process_scan_results (struct airo_info *ai) {
        }
 
        /* Try to read the first entry of the scan result */
-       rc = PC4500_readrid(ai, RID_BSSLISTFIRST, &BSSList, sizeof(BSSList), 0);
-       if((rc) || (BSSList.index == 0xffff)) {
+       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) && (BSSList.index != 0xffff)) {
+       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,
@@ -2977,19 +3031,19 @@ static void airo_process_scan_results (struct airo_info *ai) {
                }
 
                if (tmp_net != NULL) {
-                       memcpy(tmp_net, &BSSList, sizeof(tmp_net->bss));
+                       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, RID_BSSLISTNEXT,
-                                   &BSSList, sizeof(BSSList), 0);
+               rc = PC4500_readrid(ai, ai->bssListNext,
+                                   &bss, ai->bssListRidLen, 0);
        }
 
 out:
        ai->scan_timeout = 0;
-       clear_bit(JOB_SCAN_RESULTS, &ai->flags);
+       clear_bit(JOB_SCAN_RESULTS, &ai->jobs);
        up(&ai->sem);
 
        /* Send an empty event to user space.
@@ -3019,10 +3073,10 @@ static int airo_thread(void *data) {
                /* 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;
@@ -3031,16 +3085,16 @@ 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 || ai->scan_timeout) {
                                        if (ai->scan_timeout &&
                                                        time_after_eq(jiffies,ai->scan_timeout)){
-                                               set_bit(JOB_SCAN_RESULTS,&ai->flags);
+                                               set_bit(JOB_SCAN_RESULTS, &ai->jobs);
                                                break;
                                        } else if (ai->expires &&
                                                        time_after_eq(jiffies,ai->expires)){
-                                               set_bit(JOB_AUTOWEP,&ai->flags);
+                                               set_bit(JOB_AUTOWEP, &ai->jobs);
                                                break;
                                        }
                                        if (!signal_pending(current)) {
@@ -3069,7 +3123,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;
                }
@@ -3079,23 +3133,23 @@ 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->flags))
+               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);
@@ -3133,7 +3187,7 @@ 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);
                        }
                }
@@ -3187,7 +3241,7 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
                                set_bit(FLAG_UPDATE_MULTI, &apriv->flags);
 
                                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);
@@ -5485,7 +5539,7 @@ 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);
 }
 
@@ -6876,7 +6930,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;
@@ -7152,6 +7206,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;
@@ -7238,8 +7293,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;
 }
 
@@ -7521,7 +7637,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;
@@ -7565,10 +7681,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);