net: use netdev_mc_count and netdev_mc_empty when appropriate
[safe/jmp/linux-2.6] / drivers / net / wireless / airo.c
index a192c44..c22a34c 100644 (file)
@@ -57,7 +57,7 @@
 #define DRV_NAME "airo"
 
 #ifdef CONFIG_PCI
-static struct pci_device_id card_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(card_ids) = {
        { 0x14b9, 1, PCI_ANY_ID, PCI_ANY_ID, },
        { 0x14b9, 0x4500, PCI_ANY_ID, PCI_ANY_ID },
        { 0x14b9, 0x4800, PCI_ANY_ID, PCI_ANY_ID, },
@@ -496,39 +496,41 @@ typedef struct {
  * so all rid access should use the read/writeXXXRid routines.
  */
 
-/* This is redundant for x86 archs, but it seems necessary for ARM */
-#pragma pack(1)
-
 /* This structure came from an email sent to me from an engineer at
    aironet for inclusion into this driver */
-typedef struct {
+typedef struct WepKeyRid WepKeyRid;
+struct WepKeyRid {
        __le16 len;
        __le16 kindex;
        u8 mac[ETH_ALEN];
        __le16 klen;
        u8 key[16];
-} WepKeyRid;
+} __attribute__ ((packed));
 
 /* These structures are from the Aironet's PC4500 Developers Manual */
-typedef struct {
+typedef struct Ssid Ssid;
+struct Ssid {
        __le16 len;
        u8 ssid[32];
-} Ssid;
+} __attribute__ ((packed));
 
-typedef struct {
+typedef struct SsidRid SsidRid;
+struct SsidRid {
        __le16 len;
        Ssid ssids[3];
-} SsidRid;
+} __attribute__ ((packed));
 
-typedef struct {
+typedef struct ModulationRid ModulationRid;
+struct ModulationRid {
         __le16 len;
         __le16 modulation;
 #define MOD_DEFAULT cpu_to_le16(0)
 #define MOD_CCK cpu_to_le16(1)
 #define MOD_MOK cpu_to_le16(2)
-} ModulationRid;
+} __attribute__ ((packed));
 
-typedef struct {
+typedef struct ConfigRid ConfigRid;
+struct ConfigRid {
        __le16 len; /* sizeof(ConfigRid) */
        __le16 opmode; /* operating mode */
 #define MODE_STA_IBSS cpu_to_le16(0)
@@ -649,9 +651,10 @@ typedef struct {
 #define MAGIC_STAY_IN_CAM (1<<10)
        u8 magicControl;
        __le16 autoWake;
-} ConfigRid;
+} __attribute__ ((packed));
 
-typedef struct {
+typedef struct StatusRid StatusRid;
+struct StatusRid {
        __le16 len;
        u8 mac[ETH_ALEN];
        __le16 mode;
@@ -707,21 +710,23 @@ typedef struct {
 #define STAT_LEAPFAILED 91
 #define STAT_LEAPTIMEDOUT 92
 #define STAT_LEAPCOMPLETE 93
-} StatusRid;
+} __attribute__ ((packed));
 
-typedef struct {
+typedef struct StatsRid StatsRid;
+struct StatsRid {
        __le16 len;
        __le16 spacer;
        __le32 vals[100];
-} StatsRid;
-
+} __attribute__ ((packed));
 
-typedef struct {
+typedef struct APListRid APListRid;
+struct APListRid {
        __le16 len;
        u8 ap[4][ETH_ALEN];
-} APListRid;
+} __attribute__ ((packed));
 
-typedef struct {
+typedef struct CapabilityRid CapabilityRid;
+struct CapabilityRid {
        __le16 len;
        char oui[3];
        char zero;
@@ -748,17 +753,18 @@ typedef struct {
        __le16 bootBlockVer;
        __le16 requiredHard;
        __le16 extSoftCap;
-} CapabilityRid;
-
+} __attribute__ ((packed));
 
 /* Only present on firmware >= 5.30.17 */
-typedef struct {
+typedef struct BSSListRidExtra BSSListRidExtra;
+struct BSSListRidExtra {
   __le16 unknown[4];
   u8 fixed[12]; /* WLAN management frame */
   u8 iep[624];
-} BSSListRidExtra;
+} __attribute__ ((packed));
 
-typedef struct {
+typedef struct BSSListRid BSSListRid;
+struct BSSListRid {
   __le16 len;
   __le16 index; /* First is 0 and 0xffff means end of list */
 #define RADIO_FH 1 /* Frequency hopping radio type */
@@ -789,33 +795,37 @@ typedef struct {
 
   /* Only present on firmware >= 5.30.17 */
   BSSListRidExtra extra;
-} BSSListRid;
+} __attribute__ ((packed));
 
 typedef struct {
   BSSListRid bss;
   struct list_head list;
 } BSSListElement;
 
-typedef struct {
+typedef struct tdsRssiEntry tdsRssiEntry;
+struct tdsRssiEntry {
   u8 rssipct;
   u8 rssidBm;
-} tdsRssiEntry;
+} __attribute__ ((packed));
 
-typedef struct {
+typedef struct tdsRssiRid tdsRssiRid;
+struct tdsRssiRid {
   u16 len;
   tdsRssiEntry x[256];
-} tdsRssiRid;
+} __attribute__ ((packed));
 
-typedef struct {
-       u16 len;
-       u16 state;
-       u16 multicastValid;
+typedef struct MICRid MICRid;
+struct MICRid {
+       __le16 len;
+       __le16 state;
+       __le16 multicastValid;
        u8  multicast[16];
-       u16 unicastValid;
+       __le16 unicastValid;
        u8  unicast[16];
-} MICRid;
+} __attribute__ ((packed));
 
-typedef struct {
+typedef struct MICBuffer MICBuffer;
+struct MICBuffer {
        __be16 typelen;
 
        union {
@@ -830,15 +840,13 @@ typedef struct {
        } u;
        __be32 mic;
        __be32 seq;
-} MICBuffer;
+} __attribute__ ((packed));
 
 typedef struct {
        u8 da[ETH_ALEN];
        u8 sa[ETH_ALEN];
 } etherHead;
 
-#pragma pack()
-
 #define TXCTL_TXOK (1<<1) /* report if tx is ok */
 #define TXCTL_TXEX (1<<2) /* report if tx fails */
 #define TXCTL_802_3 (0<<3) /* 802.3 packet */
@@ -1086,12 +1094,6 @@ typedef struct wep_key_t {
        u8      key[16];        /* 40-bit and 104-bit keys */
 } wep_key_t;
 
-/* Backward compatibility */
-#ifndef IW_ENCODE_NOKEY
-#define IW_ENCODE_NOKEY         0x0800  /* Key is write only, so not present */
-#define IW_ENCODE_MODE  (IW_ENCODE_DISABLED | IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN)
-#endif /* IW_ENCODE_NOKEY */
-
 /* List of Wireless Handlers (new API) */
 static const struct iw_handler_def     airo_handler_def;
 
@@ -1159,7 +1161,7 @@ struct airo_info {
           use the high bit to mark whether it is in use. */
 #define MAX_FIDS 6
 #define MPI_MAX_FIDS 1
-       int                           fids[MAX_FIDS];
+       u32                           fids[MAX_FIDS];
        ConfigRid config;
        char keyindex; // Used with auto wep
        char defindex; // Used with auto wep
@@ -1233,6 +1235,9 @@ struct airo_info {
 #define        PCI_SHARED_LEN          2*MPI_MAX_FIDS*PKTSIZE+RIDSIZE
        char                    proc_name[IFNAMSIZ];
 
+       int                     wep_capable;
+       int                     max_wep_idx;
+
        /* WPA-related stuff */
        unsigned int bssListFirst;
        unsigned int bssListNext;
@@ -1291,6 +1296,29 @@ static void emmh32_update(emmh32_context *context, u8 *pOctets, int len);
 static void emmh32_final(emmh32_context *context, u8 digest[4]);
 static int flashpchar(struct airo_info *ai,int byte,int dwelltime);
 
+static void age_mic_context(miccntx *cur, miccntx *old, u8 *key, int key_len,
+                           struct crypto_cipher *tfm)
+{
+       /* If the current MIC context is valid and its key is the same as
+        * the MIC register, there's nothing to do.
+        */
+       if (cur->valid && (memcmp(cur->key, key, key_len) == 0))
+               return;
+
+       /* Age current mic Context */
+       memcpy(old, cur, sizeof(*cur));
+
+       /* Initialize new context */
+       memcpy(cur->key, key, key_len);
+       cur->window  = 33; /* Window always points to the middle */
+       cur->rx      = 0;  /* Rx Sequence numbers */
+       cur->tx      = 0;  /* Tx sequence numbers */
+       cur->valid   = 1;  /* Key is now valid */
+
+       /* Give key to mic seed */
+       emmh32_setseed(&cur->seed, key, key_len, tfm);
+}
+
 /* micinit - Initialize mic seed */
 
 static void micinit(struct airo_info *ai)
@@ -1301,49 +1329,26 @@ static void micinit(struct airo_info *ai)
        PC4500_readrid(ai, RID_MIC, &mic_rid, sizeof(mic_rid), 0);
        up(&ai->sem);
 
-       ai->micstats.enabled = (mic_rid.state & 0x00FF) ? 1 : 0;
-
-       if (ai->micstats.enabled) {
-               /* Key must be valid and different */
-               if (mic_rid.multicastValid && (!ai->mod[0].mCtx.valid ||
-                   (memcmp (ai->mod[0].mCtx.key, mic_rid.multicast,
-                            sizeof(ai->mod[0].mCtx.key)) != 0))) {
-                       /* Age current mic Context */
-                       memcpy(&ai->mod[1].mCtx,&ai->mod[0].mCtx,sizeof(miccntx));
-                       /* Initialize new context */
-                       memcpy(&ai->mod[0].mCtx.key,mic_rid.multicast,sizeof(mic_rid.multicast));
-                       ai->mod[0].mCtx.window  = 33; //Window always points to the middle
-                       ai->mod[0].mCtx.rx      = 0;  //Rx Sequence numbers
-                       ai->mod[0].mCtx.tx      = 0;  //Tx sequence numbers
-                       ai->mod[0].mCtx.valid   = 1;  //Key is now valid
-  
-                       /* Give key to mic seed */
-                       emmh32_setseed(&ai->mod[0].mCtx.seed,mic_rid.multicast,sizeof(mic_rid.multicast), ai->tfm);
-               }
-
-               /* Key must be valid and different */
-               if (mic_rid.unicastValid && (!ai->mod[0].uCtx.valid || 
-                   (memcmp(ai->mod[0].uCtx.key, mic_rid.unicast,
-                           sizeof(ai->mod[0].uCtx.key)) != 0))) {
-                       /* Age current mic Context */
-                       memcpy(&ai->mod[1].uCtx,&ai->mod[0].uCtx,sizeof(miccntx));
-                       /* Initialize new context */
-                       memcpy(&ai->mod[0].uCtx.key,mic_rid.unicast,sizeof(mic_rid.unicast));
-       
-                       ai->mod[0].uCtx.window  = 33; //Window always points to the middle
-                       ai->mod[0].uCtx.rx      = 0;  //Rx Sequence numbers
-                       ai->mod[0].uCtx.tx      = 0;  //Tx sequence numbers
-                       ai->mod[0].uCtx.valid   = 1;  //Key is now valid
-       
-                       //Give key to mic seed
-                       emmh32_setseed(&ai->mod[0].uCtx.seed, mic_rid.unicast, sizeof(mic_rid.unicast), ai->tfm);
-               }
-       } else {
-      /* So next time we have a valid key and mic is enabled, we will update
-       * the sequence number if the key is the same as before.
-       */
+       ai->micstats.enabled = (le16_to_cpu(mic_rid.state) & 0x00FF) ? 1 : 0;
+       if (!ai->micstats.enabled) {
+               /* So next time we have a valid key and mic is enabled, we will
+                * update the sequence number if the key is the same as before.
+                */
                ai->mod[0].uCtx.valid = 0;
                ai->mod[0].mCtx.valid = 0;
+               return;
+       }
+
+       if (mic_rid.multicastValid) {
+               age_mic_context(&ai->mod[0].mCtx, &ai->mod[1].mCtx,
+                               mic_rid.multicast, sizeof(mic_rid.multicast),
+                               ai->tfm);
+       }
+
+       if (mic_rid.unicastValid) {
+               age_mic_context(&ai->mod[0].uCtx, &ai->mod[1].uCtx,
+                               mic_rid.unicast, sizeof(mic_rid.unicast),
+                               ai->tfm);
        }
 }
 
@@ -1915,14 +1920,16 @@ static int airo_open(struct net_device *dev) {
        return 0;
 }
 
-static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) {
+static netdev_tx_t mpi_start_xmit(struct sk_buff *skb,
+                                       struct net_device *dev)
+{
        int npacks, pending;
        unsigned long flags;
        struct airo_info *ai = dev->ml_priv;
 
        if (!skb) {
                airo_print_err(dev->name, "%s: skb == NULL!",__func__);
-               return 0;
+               return NETDEV_TX_OK;
        }
        npacks = skb_queue_len (&ai->txq);
 
@@ -1930,10 +1937,10 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) {
                netif_stop_queue (dev);
                if (npacks > MAXTXQ) {
                        dev->stats.tx_fifo_errors++;
-                       return 1;
+                       return NETDEV_TX_BUSY;
                }
                skb_queue_tail (&ai->txq, skb);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        spin_lock_irqsave(&ai->aux_lock, flags);
@@ -1946,7 +1953,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) {
                set_bit(FLAG_PENDING_XMIT, &ai->flags);
                mpi_send_packet (dev);
        }
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /*
@@ -2114,7 +2121,9 @@ static void airo_end_xmit(struct net_device *dev) {
        dev_kfree_skb(skb);
 }
 
-static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
+static netdev_tx_t airo_start_xmit(struct sk_buff *skb,
+                                        struct net_device *dev)
+{
        s16 len;
        int i, j;
        struct airo_info *priv = dev->ml_priv;
@@ -2122,7 +2131,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
 
        if ( skb == NULL ) {
                airo_print_err(dev->name, "%s: skb == NULL!", __func__);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        /* Find a vacant FID */
@@ -2134,7 +2143,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
 
                if (i == MAX_FIDS / 2) {
                        dev->stats.tx_fifo_errors++;
-                       return 1;
+                       return NETDEV_TX_BUSY;
                }
        }
        /* check min length*/
@@ -2150,7 +2159,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
                wake_up_interruptible(&priv->thr_wait);
        } else
                airo_end_xmit(dev);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void airo_end_xmit11(struct net_device *dev) {
@@ -2179,7 +2188,9 @@ static void airo_end_xmit11(struct net_device *dev) {
        dev_kfree_skb(skb);
 }
 
-static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
+static netdev_tx_t airo_start_xmit11(struct sk_buff *skb,
+                                          struct net_device *dev)
+{
        s16 len;
        int i, j;
        struct airo_info *priv = dev->ml_priv;
@@ -2188,12 +2199,13 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
        if (test_bit(FLAG_MPI, &priv->flags)) {
                /* Not implemented yet for MPI350 */
                netif_stop_queue(dev);
-               return -ENETDOWN;
+               dev_kfree_skb_any(skb);
+               return NETDEV_TX_OK;
        }
 
        if ( skb == NULL ) {
                airo_print_err(dev->name, "%s: skb == NULL!", __func__);
-               return 0;
+               return NETDEV_TX_OK;
        }
 
        /* Find a vacant FID */
@@ -2205,7 +2217,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
 
                if (i == MAX_FIDS) {
                        dev->stats.tx_fifo_errors++;
-                       return 1;
+                       return NETDEV_TX_BUSY;
                }
        }
        /* check min length*/
@@ -2221,7 +2233,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
                wake_up_interruptible(&priv->thr_wait);
        } else
                airo_end_xmit11(dev);
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void airo_read_stats(struct net_device *dev)
@@ -2298,7 +2310,7 @@ static void airo_set_multicast_list(struct net_device *dev) {
                        airo_set_promisc(ai);
        }
 
-       if ((dev->flags&IFF_ALLMULTI)||dev->mc_count>0) {
+       if ((dev->flags&IFF_ALLMULTI) || !netdev_mc_empty(dev)) {
                /* Turn on multicast.  (Should be already setup...) */
        }
 }
@@ -2641,17 +2653,21 @@ static const struct header_ops airo_header_ops = {
        .parse = wll_header_parse,
 };
 
+static const struct net_device_ops airo11_netdev_ops = {
+       .ndo_open               = airo_open,
+       .ndo_stop               = airo_close,
+       .ndo_start_xmit         = airo_start_xmit11,
+       .ndo_get_stats          = airo_get_stats,
+       .ndo_set_mac_address    = airo_set_mac_address,
+       .ndo_do_ioctl           = airo_ioctl,
+       .ndo_change_mtu         = airo_change_mtu,
+};
+
 static void wifi_setup(struct net_device *dev)
 {
+       dev->netdev_ops = &airo11_netdev_ops;
        dev->header_ops = &airo_header_ops;
-       dev->hard_start_xmit = &airo_start_xmit11;
-       dev->get_stats = &airo_get_stats;
-       dev->set_mac_address = &airo_set_mac_address;
-       dev->do_ioctl = &airo_ioctl;
        dev->wireless_handlers = &airo_handler_def;
-       dev->change_mtu = &airo_change_mtu;
-       dev->open = &airo_open;
-       dev->stop = &airo_close;
 
        dev->type               = ARPHRD_IEEE80211;
        dev->hard_header_len    = ETH_HLEN;
@@ -2734,27 +2750,30 @@ static void airo_networks_initialize(struct airo_info *ai)
                              &ai->network_free_list);
 }
 
-static int airo_test_wpa_capable(struct airo_info *ai)
-{
-       int status;
-       CapabilityRid cap_rid;
-
-       status = readCapabilityRid(ai, &cap_rid, 1);
-       if (status != SUCCESS) return 0;
+static const struct net_device_ops airo_netdev_ops = {
+       .ndo_open               = airo_open,
+       .ndo_stop               = airo_close,
+       .ndo_start_xmit         = airo_start_xmit,
+       .ndo_get_stats          = airo_get_stats,
+       .ndo_set_multicast_list = airo_set_multicast_list,
+       .ndo_set_mac_address    = airo_set_mac_address,
+       .ndo_do_ioctl           = airo_ioctl,
+       .ndo_change_mtu         = airo_change_mtu,
+       .ndo_validate_addr      = eth_validate_addr,
+};
 
-       /* Only firmware versions 5.30.17 or better can do WPA */
-       if (le16_to_cpu(cap_rid.softVer) > 0x530
-         || (le16_to_cpu(cap_rid.softVer) == 0x530
-             && le16_to_cpu(cap_rid.softSubVer) >= 17)) {
-               airo_print_info("", "WPA is supported.");
-               return 1;
-       }
+static const struct net_device_ops mpi_netdev_ops = {
+       .ndo_open               = airo_open,
+       .ndo_stop               = airo_close,
+       .ndo_start_xmit         = mpi_start_xmit,
+       .ndo_get_stats          = airo_get_stats,
+       .ndo_set_multicast_list = airo_set_multicast_list,
+       .ndo_set_mac_address    = airo_set_mac_address,
+       .ndo_do_ioctl           = airo_ioctl,
+       .ndo_change_mtu         = airo_change_mtu,
+       .ndo_validate_addr      = eth_validate_addr,
+};
 
-       /* No WPA support */
-       airo_print_info("", "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,
@@ -2763,6 +2782,7 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
        struct net_device *dev;
        struct airo_info *ai;
        int i, rc;
+       CapabilityRid cap_rid;
 
        /* Create the network device object. */
        dev = alloc_netdev(sizeof(*ai), "", ether_setup);
@@ -2792,22 +2812,16 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
                goto err_out_free;
        airo_networks_initialize (ai);
 
+       skb_queue_head_init (&ai->txq);
+
        /* The Airo-specific entries in the device structure. */
-       if (test_bit(FLAG_MPI,&ai->flags)) {
-               skb_queue_head_init (&ai->txq);
-               dev->hard_start_xmit = &mpi_start_xmit;
-       } else
-               dev->hard_start_xmit = &airo_start_xmit;
-       dev->get_stats = &airo_get_stats;
-       dev->set_multicast_list = &airo_set_multicast_list;
-       dev->set_mac_address = &airo_set_mac_address;
-       dev->do_ioctl = &airo_ioctl;
+       if (test_bit(FLAG_MPI,&ai->flags))
+               dev->netdev_ops = &mpi_netdev_ops;
+       else
+               dev->netdev_ops = &airo_netdev_ops;
        dev->wireless_handlers = &airo_handler_def;
        ai->wireless_data.spy_data = &ai->spy_data;
        dev->wireless_data = &ai->wireless_data;
-       dev->change_mtu = &airo_change_mtu;
-       dev->open = &airo_open;
-       dev->stop = &airo_close;
        dev->irq = irq;
        dev->base_addr = port;
 
@@ -2832,7 +2846,7 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
        }
 
        if (probe) {
-               if ( setup_card( ai, dev->dev_addr, 1 ) != SUCCESS ) {
+               if (setup_card(ai, dev->dev_addr, 1) != SUCCESS) {
                        airo_print_err(dev->name, "MAC could not be enabled" );
                        rc = -EIO;
                        goto err_out_map;
@@ -2842,28 +2856,50 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
                set_bit(FLAG_FLASHING, &ai->flags);
        }
 
+       strcpy(dev->name, "eth%d");
+       rc = register_netdev(dev);
+       if (rc) {
+               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;
+
+       rc = readCapabilityRid(ai, &cap_rid, 1);
+       if (rc != SUCCESS) {
+               rc = -EIO;
+               goto err_out_wifi;
+       }
+       /* WEP capability discovery */
+       ai->wep_capable = (cap_rid.softCap & cpu_to_le16(0x02)) ? 1 : 0;
+       ai->max_wep_idx = (cap_rid.softCap & cpu_to_le16(0x80)) ? 3 : 0;
+
+       airo_print_info(dev->name, "Firmware version %x.%x.%02x",
+                       ((le16_to_cpu(cap_rid.softVer) >> 8) & 0xF),
+                       (le16_to_cpu(cap_rid.softVer) & 0xFF),
+                       le16_to_cpu(cap_rid.softSubVer));
+
        /* Test for WPA support */
-       if (airo_test_wpa_capable(ai)) {
+       /* Only firmware versions 5.30.17 or better can do WPA */
+       if (le16_to_cpu(cap_rid.softVer) > 0x530
+        || (le16_to_cpu(cap_rid.softVer) == 0x530
+             && le16_to_cpu(cap_rid.softSubVer) >= 17)) {
+               airo_print_info(ai->dev->name, "WPA supported.");
+
                set_bit(FLAG_WPA_CAPABLE, &ai->flags);
                ai->bssListFirst = RID_WPA_BSSLISTFIRST;
                ai->bssListNext = RID_WPA_BSSLISTNEXT;
                ai->bssListRidLen = sizeof(BSSListRid);
        } else {
+               airo_print_info(ai->dev->name, "WPA unsupported with firmware "
+                       "versions older than 5.30.17.");
+
                ai->bssListFirst = RID_BSSLISTFIRST;
                ai->bssListNext = RID_BSSLISTNEXT;
                ai->bssListRidLen = sizeof(BSSListRid) - sizeof(BSSListRidExtra);
        }
 
-       strcpy(dev->name, "eth%d");
-       rc = register_netdev(dev);
-       if (rc) {
-               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);
        airo_print_info(dev->name, "MAC enabled %pM", dev->dev_addr);
 
@@ -3742,7 +3778,6 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
        Cmd cmd;
        Resp rsp;
        int status;
-       int i;
        SsidRid mySsid;
        __le16 lastindex;
        WepKeyRid wkr;
@@ -3784,6 +3819,7 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
        if (lock)
                up(&ai->sem);
        if (ai->config.len == 0) {
+               int i;
                tdsRssiRid rssi_rid;
                CapabilityRid cap_rid;
 
@@ -3831,14 +3867,12 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
                /* Check to see if there are any insmod configured
                   rates to add */
                if ( rates[0] ) {
-                       int i = 0;
                        memset(ai->config.rates,0,sizeof(ai->config.rates));
                        for( i = 0; i < 8 && rates[i]; i++ ) {
                                ai->config.rates[i] = rates[i];
                        }
                }
                if ( basic_rate > 0 ) {
-                       int i;
                        for( i = 0; i < 8; i++ ) {
                                if ( ai->config.rates[i] == basic_rate ||
                                     !ai->config.rates ) {
@@ -4465,7 +4499,6 @@ static int setup_proc_entry( struct net_device *dev,
                goto fail;
        apriv->proc_entry->uid = proc_uid;
        apriv->proc_entry->gid = proc_gid;
-       apriv->proc_entry->owner = THIS_MODULE;
 
        /* Setup the StatsDelta */
        entry = proc_create_data("StatsDelta",
@@ -4723,7 +4756,7 @@ static int proc_stats_rid_open( struct inode *inode,
        StatsRid stats;
        int i, j;
        __le32 *vals = stats.vals;
-       int len = le16_to_cpu(stats.len);
+       int len;
 
        if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
                return -ENOMEM;
@@ -4734,6 +4767,7 @@ static int proc_stats_rid_open( struct inode *inode,
        }
 
        readStatsRid(apriv, &stats, rid, 1);
+       len = le16_to_cpu(stats.len);
 
         j = 0;
        for(i=0; statsLabels[i]!=(char *)-1 && i*4<len; i++) {
@@ -4756,9 +4790,8 @@ static int proc_stats_rid_open( struct inode *inode,
 static int get_dec_u16( char *buffer, int *start, int limit ) {
        u16 value;
        int valid = 0;
-       for( value = 0; buffer[*start] >= '0' &&
-                    buffer[*start] <= '9' &&
-                    *start < limit; (*start)++ ) {
+       for (value = 0; *start < limit && buffer[*start] >= '0' &&
+                       buffer[*start] <= '9'; (*start)++) {
                valid = 1;
                value *= 10;
                value += buffer[*start] - '0';
@@ -4773,7 +4806,7 @@ static int airo_config_commit(struct net_device *dev,
 
 static inline int sniffing_mode(struct airo_info *ai)
 {
-       return le16_to_cpu(ai->config.rmode & RXMODE_MASK) >=
+       return (le16_to_cpu(ai->config.rmode) & le16_to_cpu(RXMODE_MASK)) >=
                le16_to_cpu(RXMODE_RFMON);
 }
 
@@ -5168,55 +5201,94 @@ static int do_writerid( struct airo_info *ai, u16 rid, const void *rid_data,
        return rc;
 }
 
-/* Returns the length of the key at the index.  If index == 0xffff
- * the index of the transmit key is returned.  If the key doesn't exist,
- * -1 will be returned.
+/* Returns the WEP key at the specified index, or -1 if that key does
+ * not exist.  The buffer is assumed to be at least 16 bytes in length.
  */
-static int get_wep_key(struct airo_info *ai, u16 index) {
+static int get_wep_key(struct airo_info *ai, u16 index, char *buf, u16 buflen)
+{
        WepKeyRid wkr;
        int rc;
        __le16 lastindex;
 
        rc = readWepKeyRid(ai, &wkr, 1, 1);
-       if (rc == SUCCESS) do {
+       if (rc != SUCCESS)
+               return -1;
+       do {
                lastindex = wkr.kindex;
-               if (wkr.kindex == cpu_to_le16(index)) {
-                       if (index == 0xffff) {
-                               return wkr.mac[0];
-                       }
-                       return le16_to_cpu(wkr.klen);
+               if (le16_to_cpu(wkr.kindex) == index) {
+                       int klen = min_t(int, buflen, le16_to_cpu(wkr.klen));
+                       memcpy(buf, wkr.key, klen);
+                       return klen;
                }
-               readWepKeyRid(ai, &wkr, 0, 1);
+               rc = readWepKeyRid(ai, &wkr, 0, 1);
+               if (rc != SUCCESS)
+                       return -1;
        } while (lastindex != wkr.kindex);
        return -1;
 }
 
-static int set_wep_key(struct airo_info *ai, u16 index,
-                      const char *key, u16 keylen, int perm, int lock )
+static int get_wep_tx_idx(struct airo_info *ai)
+{
+       WepKeyRid wkr;
+       int rc;
+       __le16 lastindex;
+
+       rc = readWepKeyRid(ai, &wkr, 1, 1);
+       if (rc != SUCCESS)
+               return -1;
+       do {
+               lastindex = wkr.kindex;
+               if (wkr.kindex == cpu_to_le16(0xffff))
+                       return wkr.mac[0];
+               rc = readWepKeyRid(ai, &wkr, 0, 1);
+               if (rc != SUCCESS)
+                       return -1;
+       } while (lastindex != wkr.kindex);
+       return -1;
+}
+
+static int set_wep_key(struct airo_info *ai, u16 index, const char *key,
+                      u16 keylen, int perm, int lock)
 {
        static const unsigned char macaddr[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 };
        WepKeyRid wkr;
+       int rc;
+
+       WARN_ON(keylen == 0);
 
        memset(&wkr, 0, sizeof(wkr));
-       if (keylen == 0) {
-// We are selecting which key to use
-               wkr.len = cpu_to_le16(sizeof(wkr));
-               wkr.kindex = cpu_to_le16(0xffff);
-               wkr.mac[0] = (char)index;
-               if (perm) ai->defindex = (char)index;
-       } else {
-// We are actually setting the key
-               wkr.len = cpu_to_le16(sizeof(wkr));
-               wkr.kindex = cpu_to_le16(index);
-               wkr.klen = cpu_to_le16(keylen);
-               memcpy( wkr.key, key, keylen );
-               memcpy( wkr.mac, macaddr, ETH_ALEN );
-       }
+       wkr.len = cpu_to_le16(sizeof(wkr));
+       wkr.kindex = cpu_to_le16(index);
+       wkr.klen = cpu_to_le16(keylen);
+       memcpy(wkr.key, key, keylen);
+       memcpy(wkr.mac, macaddr, ETH_ALEN);
 
        if (perm) disable_MAC(ai, lock);
-       writeWepKeyRid(ai, &wkr, perm, lock);
+       rc = writeWepKeyRid(ai, &wkr, perm, lock);
        if (perm) enable_MAC(ai, lock);
-       return 0;
+       return rc;
+}
+
+static int set_wep_tx_idx(struct airo_info *ai, u16 index, int perm, int lock)
+{
+       WepKeyRid wkr;
+       int rc;
+
+       memset(&wkr, 0, sizeof(wkr));
+       wkr.len = cpu_to_le16(sizeof(wkr));
+       wkr.kindex = cpu_to_le16(0xffff);
+       wkr.mac[0] = (char)index;
+
+       if (perm) {
+               ai->defindex = (char)index;
+               disable_MAC(ai, lock);
+       }
+
+       rc = writeWepKeyRid(ai, &wkr, perm, lock);
+
+       if (perm)
+               enable_MAC(ai, lock);
+       return rc;
 }
 
 static void proc_wepkey_on_close( struct inode *inode, struct file *file ) {
@@ -5224,7 +5296,7 @@ static void proc_wepkey_on_close( struct inode *inode, struct file *file ) {
        struct proc_dir_entry *dp = PDE(inode);
        struct net_device *dev = dp->data;
        struct airo_info *ai = dev->ml_priv;
-       int i;
+       int i, rc;
        char key[16];
        u16 index = 0;
        int j = 0;
@@ -5238,7 +5310,12 @@ static void proc_wepkey_on_close( struct inode *inode, struct file *file ) {
            (data->wbuffer[1] == ' ' || data->wbuffer[1] == '\n')) {
                index = data->wbuffer[0] - '0';
                if (data->wbuffer[1] == '\n') {
-                       set_wep_key(ai, index, NULL, 0, 1, 1);
+                       rc = set_wep_tx_idx(ai, index, 1, 1);
+                       if (rc < 0) {
+                               airo_print_err(ai->dev->name, "failed to set "
+                                              "WEP transmit index to %d: %d.",
+                                              index, rc);
+                       }
                        return;
                }
                j = 2;
@@ -5257,7 +5334,12 @@ static void proc_wepkey_on_close( struct inode *inode, struct file *file ) {
                        break;
                }
        }
-       set_wep_key(ai, index, key, i/3, 1, 1);
+
+       rc = set_wep_key(ai, index, key, i/3, 1, 1);
+       if (rc < 0) {
+               airo_print_err(ai->dev->name, "failed to set WEP key at index "
+                              "%d: %d.", index, rc);
+       }
 }
 
 static int proc_wepkey_open( struct inode *inode, struct file *file )
@@ -5488,13 +5570,13 @@ static void timer_func( struct net_device *dev ) {
                        break;
                case AUTH_SHAREDKEY:
                        if (apriv->keyindex < auto_wep) {
-                               set_wep_key(apriv, apriv->keyindex, NULL, 0, 0, 0);
+                               set_wep_tx_idx(apriv, apriv->keyindex, 0, 0);
                                apriv->config.authType = AUTH_SHAREDKEY;
                                apriv->keyindex++;
                        } else {
                                /* Drop to ENCRYPT */
                                apriv->keyindex = 0;
-                               set_wep_key(apriv, apriv->defindex, NULL, 0, 0, 0);
+                               set_wep_tx_idx(apriv, apriv->defindex, 0, 0);
                                apriv->config.authType = AUTH_ENCRYPT;
                        }
                        break;
@@ -5573,7 +5655,8 @@ static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 
        pci_enable_wake(pdev, pci_choose_state(pdev, state), 1);
        pci_save_state(pdev);
-       return pci_set_power_state(pdev, pci_choose_state(pdev, state));
+       pci_set_power_state(pdev, pci_choose_state(pdev, state));
+       return 0;
 }
 
 static int airo_pci_resume(struct pci_dev *pdev)
@@ -5837,20 +5920,19 @@ static int airo_set_essid(struct net_device *dev,
        readSsidRid(local, &SSID_rid);
 
        /* Check if we asked for `any' */
-       if(dwrq->flags == 0) {
+       if (dwrq->flags == 0) {
                /* Just send an empty SSID list */
                memset(&SSID_rid, 0, sizeof(SSID_rid));
        } else {
-               int     index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+               unsigned index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
 
                /* Check the size of the string */
-               if(dwrq->length > IW_ESSID_MAX_SIZE) {
+               if (dwrq->length > IW_ESSID_MAX_SIZE)
                        return -E2BIG ;
-               }
+
                /* Check if index is valid */
-               if((index < 0) || (index >= 4)) {
+               if (index >= ARRAY_SIZE(SSID_rid.ssids))
                        return -EINVAL;
-               }
 
                /* Set the SSID */
                memset(SSID_rid.ssids[index].ssid, 0,
@@ -6267,11 +6349,9 @@ static int airo_get_mode(struct net_device *dev,
        return 0;
 }
 
-static inline int valid_index(CapabilityRid *p, int index)
+static inline int valid_index(struct airo_info *ai, int index)
 {
-       if (index < 0)
-               return 0;
-       return index < (p->softCap & cpu_to_le16(0x80) ? 4 : 1);
+       return (index >= 0) && (index <= ai->max_wep_idx);
 }
 
 /*------------------------------------------------------------------*/
@@ -6284,16 +6364,13 @@ static int airo_set_encode(struct net_device *dev,
                           char *extra)
 {
        struct airo_info *local = dev->ml_priv;
-       CapabilityRid cap_rid;          /* Card capability info */
-       int perm = ( dwrq->flags & IW_ENCODE_TEMP ? 0 : 1 );
+       int perm = (dwrq->flags & IW_ENCODE_TEMP ? 0 : 1);
        __le16 currentAuthType = local->config.authType;
+       int rc = 0;
 
-       /* Is WEP supported ? */
-       readCapabilityRid(local, &cap_rid, 1);
-       /* Older firmware doesn't support this...
-       if(!(cap_rid.softCap & cpu_to_le16(2))) {
+       if (!local->wep_capable)
                return -EOPNOTSUPP;
-       } */
+
        readConfigRid(local, 1);
 
        /* Basic checking: do we have a key to set ?
@@ -6305,23 +6382,26 @@ static int airo_set_encode(struct net_device *dev,
        if (dwrq->length > 0) {
                wep_key_t key;
                int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
-               int current_index = get_wep_key(local, 0xffff);
+               int current_index;
+
                /* Check the size of the key */
                if (dwrq->length > MAX_KEY_SIZE) {
                        return -EINVAL;
                }
+
+               current_index = get_wep_tx_idx(local);
+               if (current_index < 0)
+                       current_index = 0;
+
                /* Check the index (none -> use current) */
-               if (!valid_index(&cap_rid, index))
+               if (!valid_index(local, index))
                        index = current_index;
+
                /* Set the length */
                if (dwrq->length > MIN_KEY_SIZE)
                        key.len = MAX_KEY_SIZE;
                else
-                       if (dwrq->length > 0)
-                               key.len = MIN_KEY_SIZE;
-                       else
-                               /* Disable the key */
-                               key.len = 0;
+                       key.len = MIN_KEY_SIZE;
                /* Check if the key is not marked as invalid */
                if(!(dwrq->flags & IW_ENCODE_NOKEY)) {
                        /* Cleanup */
@@ -6329,7 +6409,13 @@ static int airo_set_encode(struct net_device *dev,
                        /* Copy the key in the driver */
                        memcpy(key.key, extra, dwrq->length);
                        /* Send the key to the card */
-                       set_wep_key(local, index, key.key, key.len, perm, 1);
+                       rc = set_wep_key(local, index, key.key, key.len, perm, 1);
+                       if (rc < 0) {
+                               airo_print_err(local->dev->name, "failed to set"
+                                              " WEP key at index %d: %d.",
+                                              index, rc);
+                               return rc;
+                       }
                }
                /* WE specify that if a valid key is set, encryption
                 * should be enabled (user may turn it off later)
@@ -6341,12 +6427,19 @@ static int airo_set_encode(struct net_device *dev,
        } else {
                /* Do we want to just set the transmit key index ? */
                int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
-               if (valid_index(&cap_rid, index)) {
-                       set_wep_key(local, index, NULL, 0, perm, 1);
-               } else
+               if (valid_index(local, index)) {
+                       rc = set_wep_tx_idx(local, index, perm, 1);
+                       if (rc < 0) {
+                               airo_print_err(local->dev->name, "failed to set"
+                                              " WEP transmit index to %d: %d.",
+                                              index, rc);
+                               return rc;
+                       }
+               } else {
                        /* Don't complain if only change the mode */
                        if (!(dwrq->flags & IW_ENCODE_MODE))
                                return -EINVAL;
+               }
        }
        /* Read the flags */
        if(dwrq->flags & IW_ENCODE_DISABLED)
@@ -6372,14 +6465,14 @@ static int airo_get_encode(struct net_device *dev,
 {
        struct airo_info *local = dev->ml_priv;
        int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
-       CapabilityRid cap_rid;          /* Card capability info */
+       int wep_key_len;
+       u8 buf[16];
 
-       /* Is it supported ? */
-       readCapabilityRid(local, &cap_rid, 1);
-       if(!(cap_rid.softCap & cpu_to_le16(2))) {
+       if (!local->wep_capable)
                return -EOPNOTSUPP;
-       }
+
        readConfigRid(local, 1);
+
        /* Check encryption mode */
        switch(local->config.authType)  {
                case AUTH_ENCRYPT:
@@ -6398,14 +6491,22 @@ static int airo_get_encode(struct net_device *dev,
        memset(extra, 0, 16);
 
        /* Which key do we want ? -1 -> tx index */
-       if (!valid_index(&cap_rid, index))
-               index = get_wep_key(local, 0xffff);
+       if (!valid_index(local, index)) {
+               index = get_wep_tx_idx(local);
+               if (index < 0)
+                       index = 0;
+       }
        dwrq->flags |= index + 1;
+
        /* Copy the key to the user buffer */
-       dwrq->length = get_wep_key(local, index);
-       if (dwrq->length > 16) {
-               dwrq->length=0;
+       wep_key_len = get_wep_key(local, index, &buf[0], sizeof(buf));
+       if (wep_key_len < 0) {
+               dwrq->length = 0;
+       } else {
+               dwrq->length = wep_key_len;
+               memcpy(extra, buf, dwrq->length);
        }
+
        return 0;
 }
 
@@ -6421,28 +6522,27 @@ static int airo_set_encodeext(struct net_device *dev,
        struct airo_info *local = dev->ml_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 );
        __le16 currentAuthType = local->config.authType;
-       int idx, key_len, alg = ext->alg, set_key = 1;
+       int idx, key_len, alg = ext->alg, set_key = 1, rc;
        wep_key_t key;
 
-       /* Is WEP supported ? */
-       readCapabilityRid(local, &cap_rid, 1);
-       /* Older firmware doesn't support this...
-       if(!(cap_rid.softCap & cpu_to_le16(2))) {
+       if (!local->wep_capable)
                return -EOPNOTSUPP;
-       } */
+
        readConfigRid(local, 1);
 
        /* Determine and validate the key index */
        idx = encoding->flags & IW_ENCODE_INDEX;
        if (idx) {
-               if (!valid_index(&cap_rid, idx - 1))
+               if (!valid_index(local, idx - 1))
                        return -EINVAL;
                idx--;
-       } else
-               idx = get_wep_key(local, 0xffff);
+       } else {
+               idx = get_wep_tx_idx(local);
+               if (idx < 0)
+                       idx = 0;
+       }
 
        if (encoding->flags & IW_ENCODE_DISABLED)
                alg = IW_ENCODE_ALG_NONE;
@@ -6451,7 +6551,13 @@ static int airo_set_encodeext(struct net_device *dev,
                /* Only set transmit key index here, actual
                 * key is set below if needed.
                 */
-               set_wep_key(local, idx, NULL, 0, perm, 1);
+               rc = set_wep_tx_idx(local, idx, perm, 1);
+               if (rc < 0) {
+                       airo_print_err(local->dev->name, "failed to set "
+                                      "WEP transmit index to %d: %d.",
+                                      idx, rc);
+                       return rc;
+               }
                set_key = ext->key_len > 0 ? 1 : 0;
        }
 
@@ -6476,8 +6582,23 @@ static int airo_set_encodeext(struct net_device *dev,
                default:
                        return -EINVAL;
                }
-               /* Send the key to the card */
-               set_wep_key(local, idx, key.key, key.len, perm, 1);
+               if (key.len == 0) {
+                       rc = set_wep_tx_idx(local, idx, perm, 1);
+                       if (rc < 0) {
+                               airo_print_err(local->dev->name,
+                                              "failed to set WEP transmit index to %d: %d.",
+                                              idx, rc);
+                               return rc;
+                       }
+               } else {
+                       rc = set_wep_key(local, idx, key.key, key.len, perm, 1);
+                       if (rc < 0) {
+                               airo_print_err(local->dev->name,
+                                              "failed to set WEP key at index %d: %d.",
+                                              idx, rc);
+                               return rc;
+                       }
+               }
        }
 
        /* Read the flags */
@@ -6507,14 +6628,12 @@ static int airo_get_encodeext(struct net_device *dev,
        struct airo_info *local = dev->ml_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;
+       int idx, max_key_len, wep_key_len;
+       u8 buf[16];
 
-       /* Is it supported ? */
-       readCapabilityRid(local, &cap_rid, 1);
-       if(!(cap_rid.softCap & cpu_to_le16(2))) {
+       if (!local->wep_capable)
                return -EOPNOTSUPP;
-       }
+
        readConfigRid(local, 1);
 
        max_key_len = encoding->length - sizeof(*ext);
@@ -6523,11 +6642,14 @@ static int airo_get_encodeext(struct net_device *dev,
 
        idx = encoding->flags & IW_ENCODE_INDEX;
        if (idx) {
-               if (!valid_index(&cap_rid, idx - 1))
+               if (!valid_index(local, idx - 1))
                        return -EINVAL;
                idx--;
-       } else
-               idx = get_wep_key(local, 0xffff);
+       } else {
+               idx = get_wep_tx_idx(local);
+               if (idx < 0)
+                       idx = 0;
+       }
 
        encoding->flags = idx + 1;
        memset(ext, 0, sizeof(*ext));
@@ -6550,9 +6672,12 @@ static int airo_get_encodeext(struct net_device *dev,
        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;
+       wep_key_len = get_wep_key(local, idx, &buf[0], sizeof(buf));
+       if (wep_key_len < 0) {
+               ext->key_len = 0;
+       } else {
+               ext->key_len = wep_key_len;
+               memcpy(extra, buf, ext->key_len);
        }
 
        return 0;
@@ -6607,11 +6732,11 @@ static int airo_set_auth(struct net_device *dev,
                                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);
+                       break;
                }
 
        case IW_AUTH_WPA_ENABLED:
@@ -6701,7 +6826,7 @@ static int airo_set_txpow(struct net_device *dev,
                return -EINVAL;
        }
        clear_bit (FLAG_RADIO_OFF, &local->flags);
-       for (i = 0; cap_rid.txPowerLevels[i] && (i < 8); i++)
+       for (i = 0; i < 8 && cap_rid.txPowerLevels[i]; i++)
                if (v == cap_rid.txPowerLevels[i]) {
                        readConfigRid(local, 1);
                        local->config.txPower = v;
@@ -7064,11 +7189,15 @@ static int airo_get_aplist(struct net_device *dev,
 {
        struct airo_info *local = dev->ml_priv;
        struct sockaddr *address = (struct sockaddr *) extra;
-       struct iw_quality qual[IW_MAX_AP];
+       struct iw_quality *qual;
        BSSListRid BSSList;
        int i;
        int loseSync = capable(CAP_NET_ADMIN) ? 1: -1;
 
+       qual = kmalloc(IW_MAX_AP * sizeof(*qual), GFP_KERNEL);
+       if (!qual)
+               return -ENOMEM;
+
        for (i = 0; i < IW_MAX_AP; i++) {
                u16 dBm;
                if (readBSSListRid(local, loseSync, &BSSList))
@@ -7123,6 +7252,7 @@ static int airo_get_aplist(struct net_device *dev,
        }
        dwrq->length = i;
 
+       kfree(qual);
        return 0;
 }