fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / net / wireless / airo.c
index a4dd139..44a2270 100644 (file)
@@ -19,6 +19,7 @@
 
 ======================================================================*/
 
+#include <linux/err.h>
 #include <linux/init.h>
 
 #include <linux/kernel.h>
@@ -47,6 +48,8 @@
 #include <linux/pci.h>
 #include <asm/uaccess.h>
 #include <net/ieee80211.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
 
 #include "airo.h"
 
@@ -1118,8 +1121,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);
@@ -1187,11 +1189,10 @@ struct airo_info {
                        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;
@@ -1203,7 +1204,7 @@ struct airo_info {
        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
@@ -1271,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]);
@@ -1339,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) {
+        if (IS_ERR(ai->tfm)) {
                 airo_print_err(ai->dev->name, "failed to load transform for AES");
+                ai->tfm = NULL;
                 return ERROR;
         }
 
@@ -1608,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[] */
@@ -1616,7 +1620,6 @@ 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;
@@ -1627,9 +1630,8 @@ static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct
                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;
+               crypto_cipher_encrypt_one(tfm, plain, plain);
+               cipher = plain;
                for (j=0; (j<16) && (i< (sizeof(context->coeff)/sizeof(context->coeff[0]))); ) {
                        context->coeff[i++] = ntohl(*(u32 *)&cipher[j]);
                        j += 4;
@@ -1733,12 +1735,12 @@ static int readBSSListRid(struct airo_info *ai, int first,
                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 */
-               ai->task = current;
-               ssleep(3);
-               ai->task = NULL;
+               schedule_timeout_uninterruptible(3 * HZ);
+               ai->list_bss_task = NULL;
        }
        rc = PC4500_readrid(ai, first ? ai->bssListFirst : ai->bssListNext,
                            list, ai->bssListRidLen, 1);
@@ -2400,8 +2402,7 @@ void stop_airo_card( struct net_device *dev, int freeres )
                clear_bit(FLAG_REGISTERED, &ai->flags);
        }
        set_bit(JOB_DIE, &ai->jobs);
-       kill_proc(ai->thr_pid, SIGTERM, 1);
-       wait_for_completion(&ai->thr_exited);
+       kthread_stop(ai->airo_thread_task);
 
        /*
         * Clean out tx queue
@@ -2432,7 +2433,7 @@ void stop_airo_card( struct net_device *dev, int freeres )
                                ai->shared, ai->shared_dma);
                }
         }
-       crypto_free_tfm(ai->tfm);
+       crypto_free_cipher(ai->tfm);
        del_airo_dev( dev );
        free_netdev( dev );
 }
@@ -2811,9 +2812,8 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
        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 );
@@ -2898,6 +2898,8 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
                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 %x:%x:%x:%x:%x:%x",
@@ -2909,11 +2911,18 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
                for( i = 0; i < MAX_FIDS; i++ )
                        ai->fids[i] = transmit_allocate(ai,AIRO_DEF_MTU,i>=MAX_FIDS/2);
 
-       setup_proc_entry( dev, dev->priv ); /* XXX check for failure */
+       if (setup_proc_entry(dev, dev->priv) < 0)
+               goto err_out_wifi;
+
        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);
@@ -2930,8 +2939,7 @@ err_out_unlink:
        del_airo_dev(dev);
 err_out_thr:
        set_bit(JOB_DIE, &ai->jobs);
-       kill_proc(ai->thr_pid, SIGTERM, 1);
-       wait_for_completion(&ai->thr_exited);
+       kthread_stop(ai->airo_thread_task);
 err_out_free:
        free_netdev(dev);
        return NULL;
@@ -3063,13 +3071,7 @@ static int airo_thread(void *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();
 
@@ -3097,7 +3099,8 @@ static int airo_thread(void *data) {
                                                set_bit(JOB_AUTOWEP, &ai->jobs);
                                                break;
                                        }
-                                       if (!signal_pending(current)) {
+                                       if (!kthread_should_stop() &&
+                                           !freezing(current)) {
                                                unsigned long wake_at;
                                                if (!ai->expires || !ai->scan_timeout) {
                                                        wake_at = max(ai->expires,
@@ -3109,7 +3112,8 @@ static int airo_thread(void *data) {
                                                schedule_timeout(wake_at - jiffies);
                                                continue;
                                        }
-                               } else if (!signal_pending(current)) {
+                               } else if (!kthread_should_stop() &&
+                                          !freezing(current)) {
                                        schedule();
                                        continue;
                                }
@@ -3154,10 +3158,11 @@ static int airo_thread(void *data) {
                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;
@@ -3235,8 +3240,8 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
                        if(newStatus == ASSOCIATED || newStatus == REASSOCIATED) {
                                if (auto_wep)
                                        apriv->expires = 0;
-                               if (apriv->task)
-                                       wake_up_process (apriv->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);
 
@@ -3950,13 +3955,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) {
-               airo_print_err(ai->dev->name, "cmd= %x\n", pCmd->cmd);
-               airo_print_err(ai->dev->name, "status= %x\n", pRsp->status);
-               airo_print_err(ai->dev->name, "Rsp0= %x\n", pRsp->rsp0);
-               airo_print_err(ai->dev->name, "Rsp1= %x\n", pRsp->rsp1);
-               airo_print_err(ai->dev->name, "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) {
@@ -4504,91 +4507,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,
@@ -5667,25 +5707,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++ ) {
                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
        airo_print_info("", "Probing for PCI adapters");
-       pci_register_driver(&airo_driver);
+       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
@@ -5876,7 +5931,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 */
@@ -5888,7 +5943,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 */
@@ -5918,7 +5973,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 ! */
@@ -5998,7 +6052,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);
@@ -6023,7 +6077,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;
 }
@@ -6775,9 +6829,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 */
@@ -6813,14 +6867,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;
@@ -6998,6 +7052,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;