X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fnet%2Fwireless%2Fairo.c;h=00764ddd74d8fc5593339107cd149fac3fec8ed1;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=40231b6c4b6a3ad0ccecc5a4318872af6be1cbf0;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 40231b6c4..00764ddd7 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -32,11 +33,12 @@ #include #include #include -#include #include +#include +#include +#include #include #include -#include #include #include @@ -46,6 +48,8 @@ #include #include +#include "airo.h" + #ifdef CONFIG_PCI static struct pci_device_id card_ids[] = { { 0x14b9, 1, PCI_ANY_ID, PCI_ANY_ID, }, @@ -61,7 +65,7 @@ MODULE_DEVICE_TABLE(pci, card_ids); static int airo_pci_probe(struct pci_dev *, const struct pci_device_id *); static void airo_pci_remove(struct pci_dev *); -static int airo_pci_suspend(struct pci_dev *pdev, u32 state); +static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state); static int airo_pci_resume(struct pci_dev *pdev); static struct pci_driver airo_driver = { @@ -84,14 +88,6 @@ static struct pci_driver airo_driver = { #include #endif -/* Support Cisco MIC feature */ -#define MICSUPPORT - -#if defined(MICSUPPORT) && !defined(CONFIG_CRYPTO) -#warning MIC support requires Crypto API -#undef MICSUPPORT -#endif - /* Hack to do some power saving */ #define POWER_ON_DOWN @@ -101,7 +97,7 @@ static struct pci_driver airo_driver = { infront of the label, that statistic will not be included in the list of statistics in the /proc filesystem */ -#define IGNLABEL(comment) 0 +#define IGNLABEL(comment) NULL static char *statsLabels[] = { "RxOverrun", IGNLABEL("RxPlcpCrcErr"), @@ -245,36 +241,36 @@ MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet \ for PCMCIA when used with airo_cs."); MODULE_LICENSE("Dual BSD/GPL"); MODULE_SUPPORTED_DEVICE("Aironet 4500, 4800 and Cisco 340/350"); -MODULE_PARM(io,"1-4i"); -MODULE_PARM(irq,"1-4i"); -MODULE_PARM(basic_rate,"i"); -MODULE_PARM(rates,"1-8i"); -MODULE_PARM(ssids,"1-3s"); -MODULE_PARM(auto_wep,"i"); +module_param_array(io, int, NULL, 0); +module_param_array(irq, int, NULL, 0); +module_param(basic_rate, int, 0); +module_param_array(rates, int, NULL, 0); +module_param_array(ssids, charp, NULL, 0); +module_param(auto_wep, int, 0); MODULE_PARM_DESC(auto_wep, "If non-zero, the driver will keep looping through \ the authentication options until an association is made. The value of \ auto_wep is number of the wep keys to check. A value of 2 will try using \ the key at index 0 and index 1."); -MODULE_PARM(aux_bap,"i"); +module_param(aux_bap, int, 0); MODULE_PARM_DESC(aux_bap, "If non-zero, the driver will switch into a mode \ than seems to work better for older cards with some older buses. Before \ switching it checks that the switch is needed."); -MODULE_PARM(maxencrypt, "i"); +module_param(maxencrypt, int, 0); MODULE_PARM_DESC(maxencrypt, "The maximum speed that the card can do \ encryption. Units are in 512kbs. Zero (default) means there is no limit. \ Older cards used to be limited to 2mbs (4)."); -MODULE_PARM(adhoc, "i"); +module_param(adhoc, int, 0); MODULE_PARM_DESC(adhoc, "If non-zero, the card will start in adhoc mode."); -MODULE_PARM(probe, "i"); +module_param(probe, int, 0); MODULE_PARM_DESC(probe, "If zero, the driver won't start the card."); -MODULE_PARM(proc_uid, "i"); +module_param(proc_uid, int, 0); MODULE_PARM_DESC(proc_uid, "The uid that the /proc files will belong to."); -MODULE_PARM(proc_gid, "i"); +module_param(proc_gid, int, 0); MODULE_PARM_DESC(proc_gid, "The gid that the /proc files will belong to."); -MODULE_PARM(airo_perm, "i"); +module_param(airo_perm, int, 0); MODULE_PARM_DESC(airo_perm, "The permission bits of /proc/[driver/]aironet."); -MODULE_PARM(proc_perm, "i"); +module_param(proc_perm, int, 0); MODULE_PARM_DESC(proc_perm, "The permission bits of the files in /proc"); /* This is a kind of sloppy hack to get this information to OUT4500 and @@ -754,7 +750,7 @@ typedef struct { u8 zero; u8 ssidLen; u8 ssid[32]; - u16 rssi; + u16 dBm; #define CAP_ESS (1<<0) #define CAP_IBSS (1<<1) #define CAP_PRIVACY (1<<4) @@ -773,6 +769,11 @@ typedef struct { u16 atimWindow; } BSSListRid; +typedef struct { + BSSListRid bss; + struct list_head list; +} BSSListElement; + typedef struct { u8 rssipct; u8 rssidBm; @@ -861,7 +862,9 @@ typedef struct { #define AIROGMICRID 11 #define AIROGMICSTATS 12 #define AIROGFLAGS 13 +#define AIROGID 14 #define AIRORRID 15 +#define AIRORSWVERSION 17 /* Leave gap of 40 commands after AIROGSTATSD32 for future */ @@ -892,15 +895,19 @@ typedef struct { #define AUXMEMSIZE (256 * 1024) typedef struct aironet_ioctl { - unsigned short command; // What to do + unsigned short command; // What to do unsigned short len; // Len of data - unsigned char *data; // d-data + unsigned short ridnum; // rid number + unsigned char __user *data; // d-data } aironet_ioctl; + +static char swversion[] = "2.1"; #endif /* CISCO_EXT */ #define NUM_MODULES 2 #define MIC_MSGLEN_MAX 2400 #define EMMH32_MSGLEN_MAX MIC_MSGLEN_MAX +#define AIRO_DEF_MTU 2312 typedef struct { u32 size; // size @@ -964,7 +971,7 @@ typedef struct { * Host receive descriptor */ typedef struct { - unsigned char *card_ram_off; /* offset into card memory of the + unsigned char __iomem *card_ram_off; /* offset into card memory of the desc */ RxFid rx_desc; /* card receive descriptor */ char *virtual_host_addr; /* virtual address of host receive @@ -976,7 +983,7 @@ typedef struct { * Host transmit descriptor */ typedef struct { - unsigned char *card_ram_off; /* offset into card memory of the + unsigned char __iomem *card_ram_off; /* offset into card memory of the desc */ TxFid tx_desc; /* card transmit descriptor */ char *virtual_host_addr; /* virtual address of host receive @@ -988,7 +995,7 @@ typedef struct { * Host RID descriptor */ typedef struct { - unsigned char *card_ram_off; /* offset into card memory of the + unsigned char __iomem *card_ram_off; /* offset into card memory of the descriptor */ Rid rid_desc; /* card RID descriptor */ char *virtual_host_addr; /* virtual address of host receive @@ -1035,13 +1042,12 @@ typedef struct { u16 status; } WifiCtlHdr; -WifiCtlHdr wifictlhdr8023 = { +static WifiCtlHdr wifictlhdr8023 = { .ctlhdr = { .ctl = HOST_DONT_RLSE, } }; -#ifdef WIRELESS_EXT // Frequency list (map channels to frequencies) static const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484 }; @@ -1062,7 +1068,6 @@ typedef struct wep_key_t { /* List of Wireless Handlers (new API) */ static const struct iw_handler_def airo_handler_def; -#endif /* WIRELESS_EXT */ static const char version[] = "airo.c 0.6 (Ben Reed & Javier Achirica)"; @@ -1097,6 +1102,7 @@ static int transmit_802_11_packet(struct airo_info*, int len, char *pPacket); static int mpi_send_packet (struct net_device *dev); static void mpi_unmap_card(struct pci_dev *pci); 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 @@ -1104,23 +1110,22 @@ static irqreturn_t airo_interrupt( int irq, void* dev_id, struct pt_regs 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); -#ifdef WIRELESS_EXT -struct iw_statistics *airo_get_wireless_stats (struct net_device *dev); +static struct iw_statistics *airo_get_wireless_stats (struct net_device *dev); static void airo_read_wireless_stats (struct airo_info *local); -#endif /* WIRELESS_EXT */ #ifdef CISCO_EXT static int readrids(struct net_device *dev, aironet_ioctl *comp); static int writerids(struct net_device *dev, aironet_ioctl *comp); -int flashcard(struct net_device *dev, aironet_ioctl *comp); +static int flashcard(struct net_device *dev, aironet_ioctl *comp); #endif /* CISCO_EXT */ -#ifdef MICSUPPORT static void micinit(struct airo_info *ai); static int micsetup(struct airo_info *ai); static int encapsulate(struct airo_info *ai, etherHead *pPacket, MICBuffer *buffer, int len); static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *pPacket, u16 payLen); -#include -#endif +static u8 airo_rssi_to_dbm (tdsRssiEntry *rssi_rid, u8 rssi); +static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm); + +static void airo_networks_free(struct airo_info *ai); struct airo_info { struct net_device_stats stats; @@ -1153,7 +1158,7 @@ struct airo_info { #define FLAG_COMMIT 13 #define FLAG_RESET 14 #define FLAG_FLASHING 15 -#define JOB_MASK 0x1ff0000 +#define JOB_MASK 0x2ff0000 #define JOB_DIE 16 #define JOB_XMIT 17 #define JOB_XMIT11 18 @@ -1163,6 +1168,7 @@ struct airo_info { #define JOB_EVENT 22 #define JOB_AUTOWEP 23 #define JOB_WSTATS 24 +#define JOB_SCAN_RESULTS 25 int (*bap_read)(struct airo_info*, u16 *pu16Dst, int bytelen, int whichbap); unsigned short *flash; @@ -1178,31 +1184,33 @@ struct airo_info { int fid; } xmit, xmit11; struct net_device *wifidev; -#ifdef WIRELESS_EXT struct iw_statistics wstats; // wireless stats - unsigned long scan_timestamp; /* Time started to scan */ + unsigned long scan_timeout; /* Time scan should be read */ struct iw_spy_data spy_data; -#endif /* WIRELESS_EXT */ -#ifdef MICSUPPORT + struct iw_public_data wireless_data; /* MIC stuff */ struct crypto_tfm *tfm; mic_module mod[2]; mic_statistics micstats; -#endif HostRxDesc rxfids[MPI_MAX_FIDS]; // rx/tx/config MPI350 descriptors HostTxDesc txfids[MPI_MAX_FIDS]; HostRidDesc config_desc; unsigned long ridbus; // phys addr of config_desc struct sk_buff_head txq;// tx queue used by mpi350 code struct pci_dev *pci; - unsigned char *pcimem; - unsigned char *pciaux; + unsigned char __iomem *pcimem; + unsigned char __iomem *pciaux; unsigned char *shared; dma_addr_t shared_dma; - int power; + pm_message_t power; SsidRid *SSID; APListRid *APList; #define PCI_SHARED_LEN 2*MPI_MAX_FIDS*PKTSIZE+RIDSIZE + char proc_name[IFNAMSIZ]; + + struct list_head network_list; + struct list_head network_free_list; + BSSListElement *networks; }; static inline int bap_read(struct airo_info *ai, u16 *pu16Dst, int bytelen, @@ -1215,7 +1223,28 @@ static int setup_proc_entry( struct net_device *dev, static int takedown_proc_entry( struct net_device *dev, struct airo_info *apriv ); -#ifdef MICSUPPORT +static int cmdreset(struct airo_info *ai); +static int setflashmode (struct airo_info *ai); +static int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime); +static int flashputbuf(struct airo_info *ai); +static int flashrestart(struct airo_info *ai,struct net_device *dev); + +#define airo_print(type, name, fmt, args...) \ + { printk(type "airo(%s): " fmt "\n", name, ##args); } + +#define airo_print_info(name, fmt, args...) \ + airo_print(KERN_INFO, name, fmt, ##args) + +#define airo_print_dbg(name, fmt, args...) \ + airo_print(KERN_DEBUG, name, fmt, ##args) + +#define airo_print_warn(name, fmt, args...) \ + airo_print(KERN_WARNING, name, fmt, ##args) + +#define airo_print_err(name, fmt, args...) \ + airo_print(KERN_ERR, name, fmt, ##args) + + /*********************************************************************** * MIC ROUTINES * *********************************************************************** @@ -1223,10 +1252,11 @@ static int takedown_proc_entry( struct net_device *dev, static int RxSeqValid (struct airo_info *ai,miccntx *context,int mcast,u32 micSeq); static void MoveWindow(miccntx *context, u32 micSeq); -void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *); -void emmh32_init(emmh32_context *context); -void emmh32_update(emmh32_context *context, u8 *pOctets, int len); -void emmh32_final(emmh32_context *context, u8 digest[4]); +static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_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]); +static int flashpchar(struct airo_info *ai,int byte,int dwelltime); /* micinit - Initialize mic seed */ @@ -1290,10 +1320,10 @@ static int micsetup(struct airo_info *ai) { int i; if (ai->tfm == NULL) - ai->tfm = crypto_alloc_tfm("aes", 0); + ai->tfm = crypto_alloc_tfm("aes", CRYPTO_TFM_REQ_MAY_SLEEP); if (ai->tfm == NULL) { - printk(KERN_ERR "airo: failed to load transform for AES\n"); + airo_print_err(ai->dev->name, "failed to load transform for AES"); return ERROR; } @@ -1304,7 +1334,7 @@ static int micsetup(struct airo_info *ai) { return SUCCESS; } -char micsnap[]= {0xAA,0xAA,0x03,0x00,0x40,0x96,0x00,0x02}; +static char micsnap[] = {0xAA,0xAA,0x03,0x00,0x40,0x96,0x00,0x02}; /*=========================================================================== * Description: Mic a packet @@ -1559,7 +1589,7 @@ static void MoveWindow(miccntx *context, u32 micSeq) static unsigned char aes_counter[16]; /* expand the key to fill the MMH coefficient array */ -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_tfm *tfm) { /* take the keying material, expand if necessary, truncate at 16-bytes */ /* run through AES counter mode to generate context->coeff[] */ @@ -1578,11 +1608,9 @@ void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto aes_counter[12] = (u8)(counter >> 24); counter++; memcpy (plain, aes_counter, 16); - sg[0].page = virt_to_page(plain); - sg[0].offset = ((long) plain & ~PAGE_MASK); - sg[0].length = 16; + sg_set_buf(sg, plain, 16); crypto_cipher_encrypt(tfm, sg, sg, 16); - cipher = kmap(sg[0].page) + sg[0].offset; + cipher = kmap(sg->page) + sg->offset; for (j=0; (j<16) && (i< (sizeof(context->coeff)/sizeof(context->coeff[0]))); ) { context->coeff[i++] = ntohl(*(u32 *)&cipher[j]); j += 4; @@ -1591,7 +1619,7 @@ void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto } /* prepare for calculation of a new mic */ -void emmh32_init(emmh32_context *context) +static void emmh32_init(emmh32_context *context) { /* prepare for new mic calculation */ context->accum = 0; @@ -1599,7 +1627,7 @@ void emmh32_init(emmh32_context *context) } /* add some bytes to the mic calculation */ -void emmh32_update(emmh32_context *context, u8 *pOctets, int len) +static void emmh32_update(emmh32_context *context, u8 *pOctets, int len) { int coeff_position, byte_position; @@ -1641,7 +1669,7 @@ void emmh32_update(emmh32_context *context, u8 *pOctets, int len) static u32 mask32[4] = { 0x00000000L, 0xFF000000L, 0xFFFF0000L, 0xFFFFFF00L }; /* calculate the mic */ -void emmh32_final(emmh32_context *context, u8 digest[4]) +static void emmh32_final(emmh32_context *context, u8 digest[4]) { int coeff_position, byte_position; u32 val; @@ -1673,7 +1701,6 @@ void emmh32_final(emmh32_context *context, u8 digest[4]) digest[2] = (val>>8) & 0xFF; digest[3] = val & 0xFF; } -#endif static int readBSSListRid(struct airo_info *ai, int first, BSSListRid *list) { @@ -1690,9 +1717,8 @@ static int readBSSListRid(struct airo_info *ai, int first, issuecommand(ai, &cmd, &rsp); up(&ai->sem); /* Let the command take effect */ - set_current_state (TASK_INTERRUPTIBLE); ai->task = current; - schedule_timeout (3*HZ); + ssleep(3); ai->task = NULL; } rc = PC4500_readrid(ai, first ? RID_BSSLISTFIRST : RID_BSSLISTNEXT, @@ -1706,6 +1732,7 @@ static int readBSSListRid(struct airo_info *ai, int first, list->fh.dwell = le16_to_cpu(list->fh.dwell); list->dsChannel = le16_to_cpu(list->dsChannel); list->atimWindow = le16_to_cpu(list->atimWindow); + list->dBm = le16_to_cpu(list->dBm); return rc; } @@ -1728,11 +1755,11 @@ static int writeWepKeyRid(struct airo_info*ai, WepKeyRid *pwkr, int perm, int lo wkr.kindex = cpu_to_le16(wkr.kindex); wkr.klen = cpu_to_le16(wkr.klen); rc = PC4500_writerid(ai, RID_WEP_TEMP, &wkr, sizeof(wkr), lock); - if (rc!=SUCCESS) printk(KERN_ERR "airo: WEP_TEMP set %x\n", rc); + if (rc!=SUCCESS) airo_print_err(ai->dev->name, "WEP_TEMP set %x", rc); if (perm) { rc = PC4500_writerid(ai, RID_WEP_PERM, &wkr, sizeof(wkr), lock); if (rc!=SUCCESS) { - printk(KERN_ERR "airo: WEP_PERM set %x\n", rc); + airo_print_err(ai->dev->name, "WEP_PERM set %x", rc); } } return rc; @@ -1807,7 +1834,8 @@ static int writeConfigRid(struct airo_info*ai, int lock) { if (!test_bit (FLAG_COMMIT, &ai->flags)) return SUCCESS; - clear_bit (FLAG_COMMIT | FLAG_RESET, &ai->flags); + clear_bit (FLAG_COMMIT, &ai->flags); + clear_bit (FLAG_RESET, &ai->flags); checkThrottle(ai); cfgr = ai->config; @@ -1910,7 +1938,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct airo_info *ai = dev->priv; if (!skb) { - printk(KERN_ERR "airo: %s: skb==NULL\n",__FUNCTION__); + airo_print_err(dev->name, "%s: skb == NULL!",__FUNCTION__); return 0; } npacks = skb_queue_len (&ai->txq); @@ -1956,8 +1984,8 @@ static int mpi_send_packet (struct net_device *dev) /* get a packet to send */ if ((skb = skb_dequeue(&ai->txq)) == 0) { - printk (KERN_ERR - "airo_mpi: %s: Dequeue'd zero in send_packet()\n", + airo_print_err(dev->name, + "%s: Dequeue'd zero in send_packet()", __FUNCTION__); return 0; } @@ -1971,9 +1999,6 @@ static int mpi_send_packet (struct net_device *dev) ai->txfids[0].tx_desc.eoc = 1; ai->txfids[0].tx_desc.len =len+sizeof(WifiHdr); - memcpy((char *)ai->txfids[0].card_ram_off, - (char *)&ai->txfids[0].tx_desc, sizeof(TxFid)); - /* * Magic, the cards firmware needs a length count (2 bytes) in the host buffer * right after TXFID_HDR.The TXFID_HDR contains the status short so payloadlen @@ -1994,7 +2019,6 @@ static int mpi_send_packet (struct net_device *dev) * Firmware automaticly puts 802 header on so * we don't need to account for it in the length */ -#ifdef MICSUPPORT if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled && (ntohs(((u16 *)buffer)[6]) != 0x888E)) { MICBuffer pMic; @@ -2003,6 +2027,7 @@ static int mpi_send_packet (struct net_device *dev) return ERROR; *payloadLen = cpu_to_le16(len-sizeof(etherHead)+sizeof(pMic)); + ai->txfids[0].tx_desc.len += sizeof(pMic); /* copy data into airo dma buffer */ memcpy (sendbuf, buffer, sizeof(etherHead)); buffer += sizeof(etherHead); @@ -2010,9 +2035,7 @@ static int mpi_send_packet (struct net_device *dev) memcpy (sendbuf, &pMic, sizeof(pMic)); sendbuf += sizeof(pMic); memcpy (sendbuf, buffer, len - sizeof(etherHead)); - } else -#endif - { + } else { *payloadLen = cpu_to_le16(len - sizeof(etherHead)); dev->trans_start = jiffies; @@ -2021,13 +2044,16 @@ static int mpi_send_packet (struct net_device *dev) memcpy(sendbuf, buffer, len); } + memcpy_toio(ai->txfids[0].card_ram_off, + &ai->txfids[0].tx_desc, sizeof(TxFid)); + OUT4500(ai, EVACK, 8); dev_kfree_skb_any(skb); return 1; } -static void get_tx_error(struct airo_info *ai, u32 fid) +static void get_tx_error(struct airo_info *ai, s32 fid) { u16 status; @@ -2111,7 +2137,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) { u32 *fids = priv->fids; if ( skb == NULL ) { - printk( KERN_ERR "airo: skb == NULL!!!\n" ); + airo_print_err(dev->name, "%s: skb == NULL!", __FUNCTION__); return 0; } @@ -2175,8 +2201,14 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) { struct airo_info *priv = dev->priv; u32 *fids = priv->fids; + if (test_bit(FLAG_MPI, &priv->flags)) { + /* Not implemented yet for MPI350 */ + netif_stop_queue(dev); + return -ENETDOWN; + } + if ( skb == NULL ) { - printk( KERN_ERR "airo: skb == NULL!!!\n" ); + airo_print_err(dev->name, "%s: skb == NULL!", __FUNCTION__); return 0; } @@ -2213,7 +2245,7 @@ static void airo_read_stats(struct airo_info *ai) { u32 *vals = stats_rid.vals; clear_bit(JOB_STATS, &ai->flags); - if (ai->power) { + if (ai->power.event) { up(&ai->sem); return; } @@ -2236,16 +2268,18 @@ static void airo_read_stats(struct airo_info *ai) { ai->stats.rx_fifo_errors = vals[0]; } -struct net_device_stats *airo_get_stats(struct net_device *dev) +static struct net_device_stats *airo_get_stats(struct net_device *dev) { struct airo_info *local = dev->priv; - /* Get stats out of the card if available */ - if (down_trylock(&local->sem) != 0) { - set_bit(JOB_STATS, &local->flags); - wake_up_interruptible(&local->thr_wait); - } else - airo_read_stats(local); + if (!test_bit(JOB_STATS, &local->flags)) { + /* Get stats out of the card if available */ + if (down_trylock(&local->sem) != 0) { + set_bit(JOB_STATS, &local->flags); + wake_up_interruptible(&local->thr_wait); + } else + airo_read_stats(local); + } return &local->stats; } @@ -2331,6 +2365,9 @@ static void del_airo_dev( struct net_device *dev ); void stop_airo_card( struct net_device *dev, int freeres ) { struct airo_info *ai = dev->priv; + + set_bit(FLAG_RADIO_DOWN, &ai->flags); + disable_MAC(ai, 1); disable_interrupts(ai); free_irq( dev->irq, dev ); takedown_proc_entry( dev, ai ); @@ -2339,7 +2376,7 @@ void stop_airo_card( struct net_device *dev, int freeres ) if (ai->wifidev) { unregister_netdev(ai->wifidev); free_netdev(ai->wifidev); - ai->wifidev = 0; + ai->wifidev = NULL; } clear_bit(FLAG_REGISTERED, &ai->flags); } @@ -2350,20 +2387,18 @@ void stop_airo_card( struct net_device *dev, int freeres ) /* * Clean out tx queue */ - if (test_bit(FLAG_MPI, &ai->flags) && skb_queue_len (&ai->txq) > 0) { - struct sk_buff *skb = 0; + if (test_bit(FLAG_MPI, &ai->flags) && !skb_queue_empty(&ai->txq)) { + struct sk_buff *skb = NULL; for (;(skb = skb_dequeue(&ai->txq));) dev_kfree_skb(skb); } - if (ai->flash) - kfree(ai->flash); - if (ai->rssi) - kfree(ai->rssi); - if (ai->APList) - kfree(ai->APList); - if (ai->SSID) - kfree(ai->SSID); + airo_networks_free (ai); + + kfree(ai->flash); + kfree(ai->rssi); + kfree(ai->APList); + kfree(ai->SSID); if (freeres) { /* PCMCIA frees this stuff, so only for PCI and ISA */ release_region( dev->base_addr, 64 ); @@ -2378,10 +2413,7 @@ void stop_airo_card( struct net_device *dev, int freeres ) ai->shared, ai->shared_dma); } } -#ifdef MICSUPPORT - if (ai->tfm) - crypto_free_tfm(ai->tfm); -#endif + crypto_free_tfm(ai->tfm); del_airo_dev( dev ); free_netdev( dev ); } @@ -2390,7 +2422,7 @@ EXPORT_SYMBOL(stop_airo_card); static int add_airo_dev( struct net_device *dev ); -int wll_header_parse(struct sk_buff *skb, unsigned char *haddr) +static int wll_header_parse(struct sk_buff *skb, unsigned char *haddr) { memcpy(haddr, skb->mac.raw + 10, ETH_ALEN); return ETH_ALEN; @@ -2433,12 +2465,12 @@ static int mpi_init_descriptors (struct airo_info *ai) cmd.parm2 = MPI_MAX_FIDS; rc=issuecommand(ai, &cmd, &rsp); if (rc != SUCCESS) { - printk(KERN_ERR "airo: Couldn't allocate RX FID\n"); + airo_print_err(ai->dev->name, "Couldn't allocate RX FID"); return rc; } for (i=0; irxfids[i].card_ram_off, + memcpy_toio(ai->rxfids[i].card_ram_off, &ai->rxfids[i].rx_desc, sizeof(RxFid)); } @@ -2451,17 +2483,19 @@ static int mpi_init_descriptors (struct airo_info *ai) cmd.parm0 = FID_TX; cmd.parm1 = (ai->txfids[0].card_ram_off - ai->pciaux); cmd.parm2 = MPI_MAX_FIDS; - rc=issuecommand(ai, &cmd, &rsp); - if (rc != SUCCESS) { - printk(KERN_ERR "airo: Couldn't allocate TX FID\n"); - return rc; - } for (i=0; itxfids[i].tx_desc.valid = 1; - memcpy((char *)ai->txfids[i].card_ram_off, + memcpy_toio(ai->txfids[i].card_ram_off, &ai->txfids[i].tx_desc, sizeof(TxFid)); } + ai->txfids[i-1].tx_desc.eoc = 1; /* Last descriptor has EOC set */ + + rc=issuecommand(ai, &cmd, &rsp); + if (rc != SUCCESS) { + airo_print_err(ai->dev->name, "Couldn't allocate TX FID"); + return rc; + } /* Alloc card Rid descriptor */ memset(&rsp,0,sizeof(rsp)); @@ -2473,12 +2507,12 @@ static int mpi_init_descriptors (struct airo_info *ai) cmd.parm2 = 1; /* Magic number... */ rc=issuecommand(ai, &cmd, &rsp); if (rc != SUCCESS) { - printk(KERN_ERR "airo: Couldn't allocate RID\n"); + airo_print_err(ai->dev->name, "Couldn't allocate RID"); return rc; } - memcpy((char *)ai->config_desc.card_ram_off, - (char *)&ai->config_desc.rid_desc, sizeof(Rid)); + memcpy_toio(ai->config_desc.card_ram_off, + &ai->config_desc.rid_desc, sizeof(Rid)); return rc; } @@ -2495,8 +2529,9 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci, unsigned long mem_start, mem_len, aux_start, aux_len; int rc = -1; int i; - unsigned char *busaddroff,*vpackoff; - unsigned char *pciaddroff; + dma_addr_t busaddroff; + unsigned char *vpackoff; + unsigned char __iomem *pciaddroff; mem_start = pci_resource_start(pci, 1); mem_len = pci_resource_len(pci, 1); @@ -2504,25 +2539,25 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci, aux_len = AUXMEMSIZE; if (!request_mem_region(mem_start, mem_len, name)) { - printk(KERN_ERR "airo: Couldn't get region %x[%x] for %s\n", + airo_print_err(ai->dev->name, "Couldn't get region %x[%x] for %s", (int)mem_start, (int)mem_len, name); goto out; } if (!request_mem_region(aux_start, aux_len, name)) { - printk(KERN_ERR "airo: Couldn't get region %x[%x] for %s\n", + airo_print_err(ai->dev->name, "Couldn't get region %x[%x] for %s", (int)aux_start, (int)aux_len, name); goto free_region1; } ai->pcimem = ioremap(mem_start, mem_len); if (!ai->pcimem) { - printk(KERN_ERR "airo: Couldn't map region %x[%x] for %s\n", + airo_print_err(ai->dev->name, "Couldn't map region %x[%x] for %s", (int)mem_start, (int)mem_len, name); goto free_region2; } ai->pciaux = ioremap(aux_start, aux_len); if (!ai->pciaux) { - printk(KERN_ERR "airo: Couldn't map region %x[%x] for %s\n", + airo_print_err(ai->dev->name, "Couldn't map region %x[%x] for %s", (int)aux_start, (int)aux_len, name); goto free_memmap; } @@ -2530,7 +2565,7 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci, /* Reserve PKTSIZE for each fid and 2K for the Rids */ ai->shared = pci_alloc_consistent(pci, PCI_SHARED_LEN, &ai->shared_dma); if (!ai->shared) { - printk(KERN_ERR "airo: Couldn't alloc_consistent %d\n", + airo_print_err(ai->dev->name, "Couldn't alloc_consistent %d", PCI_SHARED_LEN); goto free_auxmap; } @@ -2538,7 +2573,7 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci, /* * Setup descriptor RX, TX, CONFIG */ - busaddroff = (unsigned char *)ai->shared_dma; + busaddroff = ai->shared_dma; pciaddroff = ai->pciaux + AUX_OFFSET; vpackoff = ai->shared; @@ -2547,7 +2582,7 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci, ai->rxfids[i].pending = 0; ai->rxfids[i].card_ram_off = pciaddroff; ai->rxfids[i].virtual_host_addr = vpackoff; - ai->rxfids[i].rx_desc.host_addr = (dma_addr_t) busaddroff; + ai->rxfids[i].rx_desc.host_addr = busaddroff; ai->rxfids[i].rx_desc.valid = 1; ai->rxfids[i].rx_desc.len = PKTSIZE; ai->rxfids[i].rx_desc.rdy = 0; @@ -2562,7 +2597,7 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci, ai->txfids[i].card_ram_off = pciaddroff; ai->txfids[i].virtual_host_addr = vpackoff; ai->txfids[i].tx_desc.valid = 1; - ai->txfids[i].tx_desc.host_addr = (dma_addr_t) busaddroff; + ai->txfids[i].tx_desc.host_addr = busaddroff; memcpy(ai->txfids[i].virtual_host_addr, &wifictlhdr8023, sizeof(wifictlhdr8023)); @@ -2575,8 +2610,8 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci, /* Rid descriptor setup */ ai->config_desc.card_ram_off = pciaddroff; ai->config_desc.virtual_host_addr = vpackoff; - ai->config_desc.rid_desc.host_addr = (dma_addr_t) busaddroff; - ai->ridbus = (dma_addr_t)busaddroff; + ai->config_desc.rid_desc.host_addr = busaddroff; + ai->ridbus = busaddroff; ai->config_desc.rid_desc.rid = 0; ai->config_desc.rid_desc.len = RIDSIZE; ai->config_desc.rid_desc.valid = 1; @@ -2605,27 +2640,24 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci, static void wifi_setup(struct net_device *dev) { - dev->hard_header = 0; - dev->rebuild_header = 0; - dev->hard_header_cache = 0; - dev->header_cache_update= 0; + dev->hard_header = NULL; + dev->rebuild_header = NULL; + dev->hard_header_cache = NULL; + dev->header_cache_update= NULL; dev->hard_header_parse = wll_header_parse; 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; -#ifdef WIRELESS_EXT - dev->get_wireless_stats = airo_get_wireless_stats; - dev->wireless_handlers = (struct iw_handler_def *)&airo_handler_def; -#endif /* WIRELESS_EXT */ + 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; - dev->mtu = 2312; + dev->mtu = AIRO_DEF_MTU; dev->addr_len = ETH_ALEN; dev->tx_queue_len = 100; @@ -2644,6 +2676,7 @@ static struct net_device *init_wifidev(struct airo_info *ai, dev->priv = ethdev->priv; dev->irq = ethdev->irq; dev->base_addr = ethdev->base_addr; + dev->wireless_data = ethdev->wireless_data; memcpy(dev->dev_addr, ethdev->dev_addr, dev->addr_len); err = register_netdev(dev); if (err<0) { @@ -2653,25 +2686,60 @@ static struct net_device *init_wifidev(struct airo_info *ai, return dev; } -int reset_mpi_card( struct net_device *dev , int lock) { +static int reset_card( struct net_device *dev , int lock) { struct airo_info *ai = dev->priv; if (lock && down_interruptible(&ai->sem)) return -1; waitbusy (ai); OUT4500(ai,COMMAND,CMD_SOFTRESET); - set_current_state (TASK_UNINTERRUPTIBLE); - schedule_timeout (HZ/5); + msleep(200); waitbusy (ai); - set_current_state (TASK_UNINTERRUPTIBLE); - schedule_timeout (HZ/5); + msleep(200); if (lock) up(&ai->sem); return 0; } -struct net_device *_init_airo_card( unsigned short irq, int port, - int is_pcmcia, struct pci_dev *pci ) +#define 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), + GFP_KERNEL); + if (!ai->networks) { + airo_print_warn(ai->dev->name, "Out of memory allocating beacons"); + return -ENOMEM; + } + + return 0; +} + +static void airo_networks_free(struct airo_info *ai) +{ + if (!ai->networks) + return; + kfree(ai->networks); + ai->networks = NULL; +} + +static void airo_networks_initialize(struct airo_info *ai) +{ + int i; + + INIT_LIST_HEAD(&ai->network_free_list); + INIT_LIST_HEAD(&ai->network_list); + for (i = 0; i < MAX_NETWORK_COUNT; i++) + list_add_tail(&ai->networks[i].list, + &ai->network_free_list); +} + +static struct net_device *_init_airo_card( unsigned short irq, int port, + int is_pcmcia, struct pci_dev *pci, + struct device *dmdev ) { struct net_device *dev; struct airo_info *ai; @@ -2680,23 +2748,23 @@ struct net_device *_init_airo_card( unsigned short irq, int port, /* Create the network device object. */ dev = alloc_etherdev(sizeof(*ai)); if (!dev) { - printk(KERN_ERR "airo: Couldn't alloc_etherdev\n"); + airo_print_err("", "Couldn't alloc_etherdev"); return NULL; } if (dev_alloc_name(dev, dev->name) < 0) { - printk(KERN_ERR "airo: Couldn't get name!\n"); + airo_print_err("", "Couldn't get name!"); goto err_out_free; } ai = dev->priv; - ai->wifidev = 0; + ai->wifidev = NULL; ai->flags = 0; + ai->dev = dev; if (pci && (pci->device == 0x5000 || pci->device == 0xa504)) { - printk(KERN_DEBUG "airo: Found an MPI350 card\n"); + airo_print_dbg(dev->name, "Found an MPI350 card"); set_bit(FLAG_MPI, &ai->flags); } - ai->dev = dev; - ai->aux_lock = SPIN_LOCK_UNLOCKED; + spin_lock_init(&ai->aux_lock); sema_init(&ai->sem, 1); ai->config.len = 0; ai->pci = pci; @@ -2705,13 +2773,15 @@ struct net_device *_init_airo_card( unsigned short irq, int port, ai->thr_pid = kernel_thread(airo_thread, dev, CLONE_FS | CLONE_FILES); if (ai->thr_pid < 0) goto err_out_free; -#ifdef MICSUPPORT ai->tfm = NULL; -#endif rc = add_airo_dev( dev ); if (rc) goto err_out_thr; + if (airo_networks_allocate (ai)) + goto err_out_unlink; + airo_networks_initialize (ai); + /* The Airo-specific entries in the device structure. */ if (test_bit(FLAG_MPI,&ai->flags)) { skb_queue_head_init (&ai->txq); @@ -2722,47 +2792,44 @@ struct net_device *_init_airo_card( unsigned short irq, int port, dev->set_multicast_list = &airo_set_multicast_list; dev->set_mac_address = &airo_set_mac_address; dev->do_ioctl = &airo_ioctl; -#ifdef WIRELESS_EXT - dev->get_wireless_stats = airo_get_wireless_stats; - dev->wireless_handlers = (struct iw_handler_def *)&airo_handler_def; -#endif /* WIRELESS_EXT */ + 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; - /* what is with PCMCIA ??? */ - if (pci) { - SET_NETDEV_DEV(dev, &pci->dev); - } + SET_NETDEV_DEV(dev, dmdev); - if (test_bit(FLAG_MPI,&ai->flags)) - reset_mpi_card (dev, 1); + reset_card (dev, 1); + msleep(400); rc = request_irq( dev->irq, airo_interrupt, SA_SHIRQ, dev->name, dev ); if (rc) { - printk(KERN_ERR "airo: register interrupt %d failed, rc %d\n", irq, rc ); + airo_print_err(dev->name, "register interrupt %d failed, rc %d", + irq, rc); goto err_out_unlink; } if (!is_pcmcia) { if (!request_region( dev->base_addr, 64, dev->name )) { rc = -EBUSY; - printk(KERN_ERR "airo: Couldn't request region\n"); + airo_print_err(dev->name, "Couldn't request region"); goto err_out_irq; } } if (test_bit(FLAG_MPI,&ai->flags)) { if (mpi_map_card(ai, pci, dev->name)) { - printk(KERN_ERR "airo: Could not map memory\n"); + airo_print_err(dev->name, "Could not map memory"); goto err_out_res; } } if (probe) { if ( setup_card( ai, dev->dev_addr, 1 ) != SUCCESS ) { - printk( KERN_ERR "airo: MAC could not be enabled\n" ); + airo_print_err(dev->name, "MAC could not be enabled" ); rc = -EIO; goto err_out_map; } @@ -2773,22 +2840,20 @@ struct net_device *_init_airo_card( unsigned short irq, int port, rc = register_netdev(dev); if (rc) { - printk(KERN_ERR "airo: Couldn't register_netdev\n"); + airo_print_err(dev->name, "Couldn't register_netdev"); goto err_out_map; } - if (!test_bit(FLAG_MPI,&ai->flags)) - ai->wifidev = init_wifidev(ai, dev); + ai->wifidev = init_wifidev(ai, dev); set_bit(FLAG_REGISTERED,&ai->flags); - printk( KERN_INFO "airo: MAC enabled %s %x:%x:%x:%x:%x:%x\n", - dev->name, + airo_print_info(dev->name, "MAC enabled %x:%x:%x:%x:%x:%x", dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] ); /* Allocate the transmit buffers */ if (probe && !test_bit(FLAG_MPI,&ai->flags)) for( i = 0; i < MAX_FIDS; i++ ) - ai->fids[i] = transmit_allocate(ai,2312,i>=MAX_FIDS/2); + ai->fids[i] = transmit_allocate(ai,AIRO_DEF_MTU,i>=MAX_FIDS/2); setup_proc_entry( dev, dev->priv ); /* XXX check for failure */ netif_start_queue(dev); @@ -2818,9 +2883,10 @@ err_out_free: return NULL; } -struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia ) +struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia, + struct device *dmdev) { - return _init_airo_card ( irq, port, is_pcmcia, 0); + return _init_airo_card ( irq, port, is_pcmcia, NULL, dmdev); } EXPORT_SYMBOL(init_airo_card); @@ -2840,20 +2906,20 @@ int reset_airo_card( struct net_device *dev ) int i; struct airo_info *ai = dev->priv; - if (reset_mpi_card (dev, 1)) + if (reset_card (dev, 1)) return -1; if ( setup_card(ai, dev->dev_addr, 1 ) != SUCCESS ) { - printk( KERN_ERR "airo: MAC could not be enabled\n" ); + airo_print_err(dev->name, "MAC could not be enabled"); return -1; } - printk( KERN_INFO "airo: MAC enabled %s %x:%x:%x:%x:%x:%x\n", dev->name, + airo_print_info(dev->name, "MAC enabled %x:%x:%x:%x:%x:%x", dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); /* Allocate the transmit buffers if needed */ if (!test_bit(FLAG_MPI,&ai->flags)) for( i = 0; i < MAX_FIDS; i++ ) - ai->fids[i] = transmit_allocate (ai,2312,i>=MAX_FIDS/2); + ai->fids[i] = transmit_allocate (ai,AIRO_DEF_MTU,i>=MAX_FIDS/2); enable_interrupts( ai ); netif_wake_queue(dev); @@ -2879,6 +2945,65 @@ static void airo_send_event(struct net_device *dev) { wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); } +static void airo_process_scan_results (struct airo_info *ai) { + union iwreq_data wrqu; + BSSListRid BSSList; + int rc; + BSSListElement * loop_net; + BSSListElement * tmp_net; + + /* Blow away current list of scan results */ + list_for_each_entry_safe (loop_net, tmp_net, &ai->network_list, list) { + list_move_tail (&loop_net->list, &ai->network_free_list); + /* Don't blow away ->list, just BSS data */ + memset (loop_net, 0, sizeof (loop_net->bss)); + } + + /* Try to read the first entry of the scan result */ + rc = PC4500_readrid(ai, RID_BSSLISTFIRST, &BSSList, sizeof(BSSList), 0); + if((rc) || (BSSList.index == 0xffff)) { + /* No scan results */ + goto out; + } + + /* Read and parse all entries */ + tmp_net = NULL; + while((!rc) && (BSSList.index != 0xffff)) { + /* Grab a network off the free list */ + if (!list_empty(&ai->network_free_list)) { + tmp_net = list_entry(ai->network_free_list.next, + BSSListElement, list); + list_del(ai->network_free_list.next); + } + + if (tmp_net != NULL) { + memcpy(tmp_net, &BSSList, 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); + } + +out: + ai->scan_timeout = 0; + clear_bit(JOB_SCAN_RESULTS, &ai->flags); + up(&ai->sem); + + /* Send an empty event to user space. + * We don't send the received data on + * the event because it would require + * us to do complex transcoding, and + * we want to minimise the work done in + * the irq handler. Use a request to + * extract the data - Jean II */ + wrqu.data.length = 0; + wrqu.data.flags = 0; + wireless_send_event(ai->dev, SIOCGIWSCAN, &wrqu, NULL); +} + static int airo_thread(void *data) { struct net_device *dev = data; struct airo_info *ai = dev->priv; @@ -2892,8 +3017,7 @@ static int airo_thread(void *data) { flush_signals(current); /* make swsusp happy with our thread */ - if (current->flags & PF_FREEZE) - refrigerator(PF_FREEZE); + try_to_freeze(); if (test_bit(JOB_DIE, &ai->flags)) break; @@ -2909,13 +3033,26 @@ static int airo_thread(void *data) { set_current_state(TASK_INTERRUPTIBLE); if (ai->flags & JOB_MASK) break; - if (ai->expires) { - if (time_after_eq(jiffies,ai->expires)){ + if (ai->expires || ai->scan_timeout) { + if (ai->scan_timeout && + time_after_eq(jiffies,ai->scan_timeout)){ + set_bit(JOB_SCAN_RESULTS,&ai->flags); + break; + } else if (ai->expires && + time_after_eq(jiffies,ai->expires)){ set_bit(JOB_AUTOWEP,&ai->flags); break; } if (!signal_pending(current)) { - schedule_timeout(ai->expires - jiffies); + unsigned long wake_at; + if (!ai->expires || !ai->scan_timeout) { + wake_at = max(ai->expires, + ai->scan_timeout); + } else { + wake_at = min(ai->expires, + ai->scan_timeout); + } + schedule_timeout(wake_at - jiffies); continue; } } else if (!signal_pending(current)) { @@ -2937,7 +3074,7 @@ static int airo_thread(void *data) { break; } - if (ai->power || test_bit(FLAG_FLASHING, &ai->flags)) { + if (ai->power.event || test_bit(FLAG_FLASHING, &ai->flags)) { up(&ai->sem); continue; } @@ -2952,14 +3089,16 @@ static int airo_thread(void *data) { airo_read_wireless_stats(ai); else if (test_bit(JOB_PROMISC, &ai->flags)) airo_set_promisc(ai); -#ifdef MICSUPPORT else if (test_bit(JOB_MIC, &ai->flags)) micinit(ai); -#endif else if (test_bit(JOB_EVENT, &ai->flags)) airo_send_event(dev); else if (test_bit(JOB_AUTOWEP, &ai->flags)) timer_func(dev); + else if (test_bit(JOB_SCAN_RESULTS, &ai->flags)) + airo_process_scan_results(ai); + else /* Shouldn't get here, but we make sure to unlock */ + up(&ai->sem); } complete_and_exit (&ai->thr_exited, 0); } @@ -2993,15 +3132,14 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) if ( status & EV_MIC ) { OUT4500( apriv, EVACK, EV_MIC ); -#ifdef MICSUPPORT if (test_bit(FLAG_MIC_CAPABLE, &apriv->flags)) { set_bit(JOB_MIC, &apriv->flags); wake_up_interruptible(&apriv->thr_wait); } -#endif } if ( status & EV_LINK ) { union iwreq_data wrqu; + int scan_forceloss = 0; /* The link status has changed, if you want to put a monitor hook in, do it here. (Remember that interrupts are still disabled!) @@ -3020,7 +3158,8 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) code) */ #define AUTHFAIL 0x0300 /* Authentication failure (low byte is reason code) */ -#define ASSOCIATED 0x0400 /* Assocatied */ +#define ASSOCIATED 0x0400 /* Associated */ +#define REASSOCIATED 0x0600 /* Reassociated? Only on firmware >= 5.30.17 */ #define RC_RESERVED 0 /* Reserved return code */ #define RC_NOREASON 1 /* Unspecified reason */ #define RC_AUTHINV 2 /* Previous authentication invalid */ @@ -3037,48 +3176,30 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) leaving BSS */ #define RC_NOAUTH 9 /* Station requesting (Re)Association is not Authenticated with the responding station */ - if (newStatus != ASSOCIATED) { - if (auto_wep && !apriv->expires) { - apriv->expires = RUN_AT(3*HZ); - wake_up_interruptible(&apriv->thr_wait); - } - } else { - struct task_struct *task = apriv->task; + if (newStatus == FORCELOSS && apriv->scan_timeout > 0) + scan_forceloss = 1; + if(newStatus == ASSOCIATED || newStatus == REASSOCIATED) { if (auto_wep) apriv->expires = 0; - if (task) - wake_up_process (task); + if (apriv->task) + wake_up_process (apriv->task); set_bit(FLAG_UPDATE_UNI, &apriv->flags); set_bit(FLAG_UPDATE_MULTI, &apriv->flags); - } - /* Question : is ASSOCIATED the only status - * that is valid ? We want to catch handover - * and reassociations as valid status - * Jean II */ - if(newStatus == ASSOCIATED) { - if (apriv->scan_timestamp) { - /* Send an empty event to user space. - * We don't send the received data on - * the event because it would require - * us to do complex transcoding, and - * we want to minimise the work done in - * the irq handler. Use a request to - * extract the data - Jean II */ - wrqu.data.length = 0; - wrqu.data.flags = 0; - wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); - apriv->scan_timestamp = 0; - } + if (down_trylock(&apriv->sem) != 0) { set_bit(JOB_EVENT, &apriv->flags); wake_up_interruptible(&apriv->thr_wait); } else airo_send_event(dev); - } else { - memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; + } else if (!scan_forceloss) { + if (auto_wep && !apriv->expires) { + apriv->expires = RUN_AT(3*HZ); + wake_up_interruptible(&apriv->thr_wait); + } /* Send event to user space */ + memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; wireless_send_event(dev, SIOCGIWAP, &wrqu,NULL); } } @@ -3101,7 +3222,10 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) u16 *buffer; if (test_bit(FLAG_MPI,&apriv->flags)) { - mpi_receive_802_3(apriv); + if (test_bit(FLAG_802_11, &apriv->flags)) + mpi_receive_802_11(apriv); + else + mpi_receive_802_3(apriv); OUT4500(apriv, EVACK, EV_RX); goto exitrx; } @@ -3123,8 +3247,8 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) } len = le16_to_cpu(hdr.len); - if (len > 2312) { - printk( KERN_ERR "airo: Bad size %d\n", len ); + if (len > AIRO_DEF_MTU) { + airo_print_err(apriv->dev->name, "Bad size %d", len); goto badrx; } if (len == 0) @@ -3151,11 +3275,12 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) } else hdrlen = ETH_ALEN * 2; - skb = dev_alloc_skb( len + hdrlen + 2 ); + skb = dev_alloc_skb( len + hdrlen + 2 + 2 ); if ( !skb ) { apriv->stats.rx_dropped++; goto badrx; } + skb_reserve(skb, 2); /* This way the IP header is aligned */ buffer = (u16*)skb_put (skb, len + hdrlen); if (test_bit(FLAG_802_11, &apriv->flags)) { buffer[0] = fc; @@ -3166,18 +3291,17 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) bap_read (apriv, &gap, sizeof(gap), BAP0); gap = le16_to_cpu(gap); if (gap) { - if (gap <= 8) + if (gap <= 8) { bap_read (apriv, tmpbuf, gap, BAP0); - else - printk(KERN_ERR "airo: gaplen too big. Problems will follow...\n"); + } else { + airo_print_err(apriv->dev->name, "gaplen too " + "big. Problems will follow..."); + } } bap_read (apriv, buffer + hdrlen/2, len, BAP0); } else { -#ifdef MICSUPPORT MICBuffer micbuf; -#endif bap_read (apriv, buffer, ETH_ALEN*2, BAP0); -#ifdef MICSUPPORT if (apriv->micstats.enabled) { bap_read (apriv,(u16*)&micbuf,sizeof(micbuf),BAP0); if (ntohs(micbuf.typelen) > 0x05DC) @@ -3190,21 +3314,16 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) skb_trim (skb, len + hdrlen); } } -#endif bap_read(apriv,buffer+ETH_ALEN,len,BAP0); -#ifdef MICSUPPORT if (decapsulate(apriv,&micbuf,(etherHead*)buffer,len)) { badmic: dev_kfree_skb_irq (skb); -#else - if (0) { -#endif badrx: OUT4500( apriv, EVACK, EV_RX); goto exitrx; } } -#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ +#ifdef WIRELESS_SPY if (apriv->spy_data.spy_number > 0) { char *sa; struct iw_quality wstats; @@ -3220,11 +3339,14 @@ badrx: wstats.level = 0x100 - apriv->rssi[hdr.rssi[1]].rssidBm; else wstats.level = (hdr.rssi[1] + 321) / 2; - wstats.updated = 3; + wstats.noise = apriv->wstats.qual.noise; + wstats.updated = IW_QUAL_LEVEL_UPDATED + | IW_QUAL_QUAL_UPDATED + | IW_QUAL_DBM; /* Update spy records */ wireless_spy_update(dev, sa, &wstats); } -#endif /* IW_WIRELESS_SPY */ +#endif /* WIRELESS_SPY */ OUT4500( apriv, EVACK, EV_RX); if (test_bit(FLAG_802_11, &apriv->flags)) { @@ -3255,7 +3377,7 @@ exitrx: if (status & EV_TXEXC) get_tx_error(apriv, -1); spin_lock_irqsave(&apriv->aux_lock, flags); - if (skb_queue_len (&apriv->txq)) { + if (!skb_queue_empty(&apriv->txq)) { spin_unlock_irqrestore(&apriv->aux_lock,flags); mpi_send_packet (dev); } else { @@ -3291,12 +3413,13 @@ exitrx: } } else { OUT4500( apriv, EVACK, status & (EV_TX | EV_TXCPY | EV_TXEXC)); - printk( KERN_ERR "airo: Unallocated FID was used to xmit\n" ); + airo_print_err(apriv->dev->name, "Unallocated FID was " + "used to xmit" ); } } exittx: if ( status & ~STATUS_INTS & ~IGNORE_INTS ) - printk( KERN_WARNING "airo: Got weird status %x\n", + airo_print_warn(apriv->dev->name, "Got weird status %x", status & ~STATUS_INTS & ~IGNORE_INTS ); } @@ -3369,8 +3492,8 @@ static int enable_MAC( struct airo_info *ai, Resp *rsp, int lock ) { up(&ai->sem); if (rc) - printk(KERN_ERR "%s: Cannot enable MAC, err=%d\n", - __FUNCTION__,rc); + airo_print_err(ai->dev->name, "%s: Cannot enable MAC, err=%d", + __FUNCTION__, rc); return rc; } @@ -3392,13 +3515,8 @@ static void disable_MAC( struct airo_info *ai, int lock ) { } static void enable_interrupts( struct airo_info *ai ) { - /* Reset the status register */ - u16 status = IN4500( ai, EVSTAT ); - OUT4500( ai, EVACK, status ); /* Enable the interrupts */ OUT4500( ai, EVINTEN, STATUS_INTS ); - /* Note there is a race condition between the last two lines that - I don't know how to get rid of right now... */ } static void disable_interrupts( struct airo_info *ai ) { @@ -3411,16 +3529,14 @@ static void mpi_receive_802_3(struct airo_info *ai) int len = 0; struct sk_buff *skb; char *buffer; -#ifdef MICSUPPORT int off = 0; MICBuffer micbuf; -#endif - memcpy ((char *)&rxd, ai->rxfids[0].card_ram_off, sizeof(rxd)); + memcpy_fromio(&rxd, ai->rxfids[0].card_ram_off, sizeof(rxd)); /* Make sure we got something */ if (rxd.rdy && rxd.valid == 0) { len = rxd.len + 12; - if (len < 12 && len > 2048) + if (len < 12 || len > 2048) goto badrx; skb = dev_alloc_skb(len); @@ -3429,7 +3545,6 @@ static void mpi_receive_802_3(struct airo_info *ai) goto badrx; } buffer = skb_put(skb,len); -#ifdef MICSUPPORT memcpy(buffer, ai->rxfids[0].virtual_host_addr, ETH_ALEN * 2); if (ai->micstats.enabled) { memcpy(&micbuf, @@ -3446,15 +3561,12 @@ static void mpi_receive_802_3(struct airo_info *ai) memcpy(buffer + ETH_ALEN * 2, ai->rxfids[0].virtual_host_addr + ETH_ALEN * 2 + off, len - ETH_ALEN * 2 - off); - if (decapsulate (ai, &micbuf, (etherHead*)buffer, len - off)) { + if (decapsulate (ai, &micbuf, (etherHead*)buffer, len - off - ETH_ALEN * 2)) { badmic: dev_kfree_skb_irq (skb); goto badrx; } -#else - memcpy(buffer, ai->rxfids[0].virtual_host_addr, len); -#endif -#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ +#ifdef WIRELESS_SPY if (ai->spy_data.spy_number > 0) { char *sa; struct iw_quality wstats; @@ -3466,7 +3578,7 @@ badmic: /* Update spy records */ wireless_spy_update(ai->dev, sa, &wstats); } -#endif /* IW_WIRELESS_SPY */ +#endif /* WIRELESS_SPY */ skb->dev = ai->dev; skb->ip_summed = CHECKSUM_NONE; @@ -3479,7 +3591,116 @@ badrx: rxd.valid = 1; rxd.rdy = 0; rxd.len = PKTSIZE; - memcpy (ai->rxfids[0].card_ram_off, (char *)&rxd, sizeof(rxd)); + memcpy_toio(ai->rxfids[0].card_ram_off, &rxd, sizeof(rxd)); + } +} + +void mpi_receive_802_11 (struct airo_info *ai) +{ + RxFid rxd; + struct sk_buff *skb = NULL; + u16 fc, len, hdrlen = 0; +#pragma pack(1) + struct { + u16 status, len; + u8 rssi[2]; + u8 rate; + u8 freq; + u16 tmp[4]; + } hdr; +#pragma pack() + u16 gap; + u16 *buffer; + char *ptr = ai->rxfids[0].virtual_host_addr+4; + + memcpy_fromio(&rxd, ai->rxfids[0].card_ram_off, sizeof(rxd)); + memcpy ((char *)&hdr, ptr, sizeof(hdr)); + ptr += sizeof(hdr); + /* Bad CRC. Ignore packet */ + if (le16_to_cpu(hdr.status) & 2) + hdr.len = 0; + if (ai->wifidev == NULL) + hdr.len = 0; + len = le16_to_cpu(hdr.len); + if (len > AIRO_DEF_MTU) { + airo_print_err(ai->dev->name, "Bad size %d", len); + goto badrx; + } + if (len == 0) + goto badrx; + + memcpy ((char *)&fc, ptr, sizeof(fc)); + fc = le16_to_cpu(fc); + switch (fc & 0xc) { + case 4: + if ((fc & 0xe0) == 0xc0) + hdrlen = 10; + else + hdrlen = 16; + break; + case 8: + if ((fc&0x300)==0x300){ + hdrlen = 30; + break; + } + default: + hdrlen = 24; + } + + skb = dev_alloc_skb( len + hdrlen + 2 ); + if ( !skb ) { + ai->stats.rx_dropped++; + goto badrx; + } + buffer = (u16*)skb_put (skb, len + hdrlen); + memcpy ((char *)buffer, ptr, hdrlen); + ptr += hdrlen; + if (hdrlen == 24) + ptr += 6; + memcpy ((char *)&gap, ptr, sizeof(gap)); + ptr += sizeof(gap); + gap = le16_to_cpu(gap); + if (gap) { + if (gap <= 8) + ptr += gap; + else + airo_print_err(ai->dev->name, + "gaplen too big. Problems will follow..."); + } + memcpy ((char *)buffer + hdrlen, ptr, len); + ptr += len; +#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ + if (ai->spy_data.spy_number > 0) { + char *sa; + struct iw_quality wstats; + /* Prepare spy data : addr + qual */ + sa = (char*)buffer + 10; + wstats.qual = hdr.rssi[0]; + if (ai->rssi) + wstats.level = 0x100 - ai->rssi[hdr.rssi[1]].rssidBm; + else + wstats.level = (hdr.rssi[1] + 321) / 2; + wstats.noise = ai->wstats.qual.noise; + wstats.updated = IW_QUAL_QUAL_UPDATED + | IW_QUAL_LEVEL_UPDATED + | IW_QUAL_DBM; + /* Update spy records */ + wireless_spy_update(ai->dev, sa, &wstats); + } +#endif /* IW_WIRELESS_SPY */ + skb->mac.raw = skb->data; + skb->pkt_type = PACKET_OTHERHOST; + skb->dev = ai->wifidev; + skb->protocol = htons(ETH_P_802_2); + skb->dev->last_rx = jiffies; + skb->ip_summed = CHECKSUM_NONE; + netif_rx( skb ); +badrx: + if (rxd.valid == 0) { + rxd.valid = 1; + rxd.rdy = 0; + rxd.len = PKTSIZE; + memcpy_toio(ai->rxfids[0].card_ram_off, &rxd, sizeof(rxd)); } } @@ -3495,10 +3716,8 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock) int rc; memset( &mySsid, 0, sizeof( mySsid ) ); - if (ai->flash) { - kfree (ai->flash); - ai->flash = NULL; - } + kfree (ai->flash); + ai->flash = NULL; /* The NOP is the first step in getting the card going */ cmd.cmd = NOP; @@ -3518,15 +3737,15 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock) if (issuecommand(ai, &cmd, &rsp) != SUCCESS) { if (lock) up(&ai->sem); - printk(KERN_ERR "airo: Error checking for AUX port\n"); + airo_print_err(ai->dev->name, "Error checking for AUX port"); return ERROR; } if (!aux_bap || rsp.status & 0xff00) { ai->bap_read = fast_bap_read; - printk(KERN_DEBUG "airo: Doing fast bap_reads\n"); + airo_print_dbg(ai->dev->name, "Doing fast bap_reads"); } else { ai->bap_read = aux_bap_read; - printk(KERN_DEBUG "airo: Doing AUX bap_reads\n"); + airo_print_dbg(ai->dev->name, "Doing AUX bap_reads"); } } if (lock) @@ -3535,14 +3754,10 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock) tdsRssiRid rssi_rid; CapabilityRid cap_rid; - if (ai->APList) { - kfree(ai->APList); - ai->APList = NULL; - } - if (ai->SSID) { - kfree(ai->SSID); - ai->SSID = NULL; - } + kfree(ai->APList); + ai->APList = NULL; + kfree(ai->SSID); + ai->SSID = NULL; // general configuration (read/modify/write) status = readConfigRid(ai, lock); if ( status != SUCCESS ) return ERROR; @@ -3550,38 +3765,29 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock) status = readCapabilityRid(ai, &cap_rid, lock); if ( status != SUCCESS ) return ERROR; - if (test_bit(FLAG_MPI, &ai->flags) && - strcmp (cap_rid.prodVer, "5.00.01") && - strcmp (cap_rid.prodVer, "5.00.03") && - strcmp (cap_rid.prodVer, "5b00.08")) - printk(KERN_ERR "airo: Firmware version %s is not supported. Use it at your own risk!\n", cap_rid.prodVer); - status = PC4500_readrid(ai,RID_RSSI,&rssi_rid,sizeof(rssi_rid),lock); if ( status == SUCCESS ) { if (ai->rssi || (ai->rssi = kmalloc(512, GFP_KERNEL)) != NULL) - memcpy(ai->rssi, (u8*)&rssi_rid + 2, 512); + memcpy(ai->rssi, (u8*)&rssi_rid + 2, 512); /* Skip RID length member */ } else { - if (ai->rssi) { - kfree(ai->rssi); - ai->rssi = NULL; - } + kfree(ai->rssi); + ai->rssi = NULL; if (cap_rid.softCap & 8) ai->config.rmode |= RXMODE_NORMALIZED_RSSI; else - printk(KERN_WARNING "airo: unknown received signal level scale\n"); + airo_print_warn(ai->dev->name, "unknown received signal " + "level scale"); } ai->config.opmode = adhoc ? MODE_STA_IBSS : MODE_STA_ESS; ai->config.authType = AUTH_OPEN; ai->config.modulation = MOD_CCK; -#ifdef MICSUPPORT if ((cap_rid.len>=sizeof(cap_rid)) && (cap_rid.extSoftCap&1) && (micsetup(ai) == SUCCESS)) { ai->config.opmode |= MODE_MIC; set_bit(FLAG_MIC_CAPABLE, &ai->flags); } -#endif /* Save off the MAC */ for( i = 0; i < ETH_ALEN; i++ ) { @@ -3590,9 +3796,9 @@ 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 ) { + if ( rates[0] ) { int i = 0; - if ( rates[0] ) memset(ai->config.rates,0,sizeof(ai->config.rates)); + memset(ai->config.rates,0,sizeof(ai->config.rates)); for( i = 0; i < 8 && rates[i]; i++ ) { ai->config.rates[i] = rates[i]; } @@ -3634,7 +3840,8 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock) status = enable_MAC(ai, &rsp, lock); if ( status != SUCCESS || (rsp.status & 0xFF00) != 0) { - printk( KERN_ERR "airo: Bad MAC enable reason = %x, rid = %x, offset = %d\n", rsp.rsp0, rsp.rsp1, rsp.rsp2 ); + airo_print_err(ai->dev->name, "Bad MAC enable reason = %x, rid = %x," + " offset = %d", rsp.rsp0, rsp.rsp1, rsp.rsp2 ); return ERROR; } @@ -3659,7 +3866,6 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock) static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) { // Im really paranoid about letting it run forever! int max_tries = 600000; - u16 cmd; if (IN4500(ai, EVSTAT) & EV_CMD) OUT4500(ai, EVACK, EV_CMD); @@ -3668,37 +3874,34 @@ static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) { OUT4500(ai, PARAM1, pCmd->parm1); OUT4500(ai, PARAM2, pCmd->parm2); OUT4500(ai, COMMAND, pCmd->cmd); - while ( max_tries-- && (IN4500(ai, EVSTAT) & EV_CMD) == 0 && - (cmd = IN4500(ai, COMMAND)) != 0 ) - if (cmd == pCmd->cmd) - // PC4500 didn't notice command, try again - OUT4500(ai, COMMAND, pCmd->cmd); - if ( max_tries == -1 ) { - printk( KERN_ERR - "airo: Max tries exceeded when issueing command\n" ); - return ERROR; - } while (max_tries-- && (IN4500(ai, EVSTAT) & EV_CMD) == 0) { + if ((IN4500(ai, COMMAND)) == pCmd->cmd) + // PC4500 didn't notice command, try again + OUT4500(ai, COMMAND, pCmd->cmd); if (!in_atomic() && (max_tries & 255) == 0) schedule(); } + if ( max_tries == -1 ) { - printk( KERN_ERR - "airo: Max tries exceeded waiting for command\n" ); - return ERROR; + airo_print_err(ai->dev->name, + "Max tries exceeded when issueing command"); + if (IN4500(ai, COMMAND) & COMMAND_BUSY) + OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY); + return ERROR; } + // command completed pRsp->status = IN4500(ai, STATUS); pRsp->rsp0 = IN4500(ai, RESP0); pRsp->rsp1 = IN4500(ai, RESP1); pRsp->rsp2 = IN4500(ai, RESP2); if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET) { - printk (KERN_ERR "airo: cmd= %x\n", pCmd->cmd); - printk (KERN_ERR "airo: status= %x\n", pRsp->status); - printk (KERN_ERR "airo: Rsp0= %x\n", pRsp->rsp0); - printk (KERN_ERR "airo: Rsp1= %x\n", pRsp->rsp1); - printk (KERN_ERR "airo: Rsp2= %x\n", pRsp->rsp2); + 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); } // clear stuck command busy if necessary @@ -3731,15 +3934,15 @@ static int bap_setup(struct airo_info *ai, u16 rid, u16 offset, int whichbap ) } } else if ( status & BAP_ERR ) { /* invalid rid or offset */ - printk( KERN_ERR "airo: BAP error %x %d\n", + airo_print_err(ai->dev->name, "BAP error %x %d", status, whichbap ); return ERROR; } else if (status & BAP_DONE) { // success return SUCCESS; } if ( !(max_tries--) ) { - printk( KERN_ERR - "airo: BAP setup error too many retries\n" ); + airo_print_err(ai->dev->name, + "airo: BAP setup error too many retries\n"); return ERROR; } // -- PC4500 missed it, try again @@ -3869,8 +4072,8 @@ static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len, in cmd.cmd = CMD_ACCESS; cmd.parm0 = rid; - memcpy((char *)ai->config_desc.card_ram_off, - (char *)&ai->config_desc.rid_desc, sizeof(Rid)); + memcpy_toio(ai->config_desc.card_ram_off, + &ai->config_desc.rid_desc, sizeof(Rid)); rc = issuecommand(ai, &cmd, &rsp); @@ -3894,8 +4097,8 @@ static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len, in len = min(len, (int)le16_to_cpu(*(u16*)pBuf)) - 2; if ( len <= 2 ) { - printk( KERN_ERR - "airo: Rid %x has a length of %d which is too short\n", + airo_print_err(ai->dev->name, + "Rid %x has a length of %d which is too short", (int)rid, (int)len ); rc = ERROR; goto done; @@ -3927,24 +4130,25 @@ static int PC4500_writerid(struct airo_info *ai, u16 rid, Cmd cmd; Resp rsp; - if (test_bit(FLAG_ENABLED, &ai->flags)) - printk(KERN_ERR "%s: MAC should be disabled (rid=%d)\n", + if (test_bit(FLAG_ENABLED, &ai->flags) && (RID_WEP_TEMP != rid)) + airo_print_err(ai->dev->name, + "%s: MAC should be disabled (rid=%04x)", __FUNCTION__, rid); memset(&cmd, 0, sizeof(cmd)); memset(&rsp, 0, sizeof(rsp)); ai->config_desc.rid_desc.valid = 1; - ai->config_desc.rid_desc.len = RIDSIZE; + ai->config_desc.rid_desc.len = *((u16 *)pBuf); ai->config_desc.rid_desc.rid = 0; cmd.cmd = CMD_WRITERID; cmd.parm0 = rid; - memcpy((char *)ai->config_desc.card_ram_off, - (char *)&ai->config_desc.rid_desc, sizeof(Rid)); + memcpy_toio(ai->config_desc.card_ram_off, + &ai->config_desc.rid_desc, sizeof(Rid)); if (len < 4 || len > 2047) { - printk(KERN_ERR "%s: len=%d\n",__FUNCTION__,len); + airo_print_err(ai->dev->name, "%s: len=%d", __FUNCTION__, len); rc = -1; } else { memcpy((char *)ai->config_desc.virtual_host_addr, @@ -3952,10 +4156,10 @@ static int PC4500_writerid(struct airo_info *ai, u16 rid, rc = issuecommand(ai, &cmd, &rsp); if ((rc & 0xff00) != 0) { - printk(KERN_ERR "%s: Write rid Error %d\n", - __FUNCTION__,rc); - printk(KERN_ERR "%s: Cmd=%04x\n", - __FUNCTION__,cmd.cmd); + airo_print_err(ai->dev->name, "%s: Write rid Error %d", + __FUNCTION__, rc); + airo_print_err(ai->dev->name, "%s: Cmd=%04x", + __FUNCTION__, cmd.cmd); } if ((rsp.status & 0x7f00)) @@ -4054,20 +4258,17 @@ static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket) len >>= 16; if (len <= ETH_ALEN * 2) { - printk( KERN_WARNING "Short packet %d\n", len ); + airo_print_warn(ai->dev->name, "Short packet %d", len); return ERROR; } len -= ETH_ALEN * 2; -#ifdef MICSUPPORT if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled && (ntohs(((u16 *)pPacket)[6]) != 0x888E)) { if (encapsulate(ai,(etherHead *)pPacket,&pMic,len) != SUCCESS) return ERROR; miclen = sizeof(pMic); } -#endif - // packet is destination[6], source[6], payload[len-12] // write the payload length and dst/src/payload if (bap_setup(ai, txFid, 0x0036, BAP1) != SUCCESS) return ERROR; @@ -4121,7 +4322,7 @@ static int transmit_802_11_packet(struct airo_info *ai, int len, char *pPacket) } if (len < hdrlen) { - printk( KERN_WARNING "Short packet %d\n", len ); + airo_print_warn(ai->dev->name, "Short packet %d", len); return ERROR; } @@ -4153,12 +4354,12 @@ static int transmit_802_11_packet(struct airo_info *ai, int len, char *pPacket) */ static ssize_t proc_read( struct file *file, - char *buffer, + char __user *buffer, size_t len, loff_t *offset); static ssize_t proc_write( struct file *file, - const char *buffer, + const char __user *buffer, size_t len, loff_t *offset ); static int proc_close( struct inode *inode, struct file *file ); @@ -4225,7 +4426,7 @@ static struct file_operations proc_wepkey_ops = { .release = proc_close }; -static struct proc_dir_entry *airo_entry = 0; +static struct proc_dir_entry *airo_entry; struct proc_data { int release_buffer; @@ -4245,7 +4446,8 @@ static int setup_proc_entry( struct net_device *dev, struct airo_info *apriv ) { struct proc_dir_entry *entry; /* First setup the device directory */ - apriv->proc_entry = create_proc_entry(dev->name, + strcpy(apriv->proc_name,dev->name); + apriv->proc_entry = create_proc_entry(apriv->proc_name, S_IFDIR|airo_perm, airo_entry); apriv->proc_entry->uid = proc_uid; @@ -4346,7 +4548,7 @@ static int takedown_proc_entry( struct net_device *dev, remove_proc_entry("APList",apriv->proc_entry); remove_proc_entry("BSSList",apriv->proc_entry); remove_proc_entry("WepKey",apriv->proc_entry); - remove_proc_entry(dev->name,airo_entry); + remove_proc_entry(apriv->proc_name,airo_entry); return 0; } @@ -4363,23 +4565,26 @@ static int takedown_proc_entry( struct net_device *dev, * to supply the data. */ static ssize_t proc_read( struct file *file, - char *buffer, + char __user *buffer, size_t len, loff_t *offset ) { - int i; - int pos; + loff_t pos = *offset; struct proc_data *priv = (struct proc_data*)file->private_data; - if( !priv->rbuffer ) return -EINVAL; + if (!priv->rbuffer) + return -EINVAL; - pos = *offset; - for( i = 0; i+pos < priv->readlen && i < len; i++ ) { - if (put_user( priv->rbuffer[i+pos], buffer+i )) - return -EFAULT; - } - *offset += i; - return i; + if (pos < 0) + return -EINVAL; + if (pos >= priv->readlen) + return 0; + if (len > priv->readlen - pos) + len = priv->readlen - pos; + if (copy_to_user(buffer, priv->rbuffer + pos, len)) + return -EFAULT; + *offset = pos + len; + return len; } /* @@ -4387,28 +4592,28 @@ static ssize_t proc_read( struct file *file, * to supply the data. */ static ssize_t proc_write( struct file *file, - const char *buffer, + const char __user *buffer, size_t len, loff_t *offset ) { - int i; - int pos; + loff_t pos = *offset; struct proc_data *priv = (struct proc_data*)file->private_data; - if ( !priv->wbuffer ) { + if (!priv->wbuffer) return -EINVAL; - } - pos = *offset; - - for( i = 0; i + pos < priv->maxwritelen && - i < len; i++ ) { - if (get_user( priv->wbuffer[i+pos], buffer + i )) - return -EFAULT; - } - if ( i+pos > priv->writelen ) priv->writelen = i+file->f_pos; - *offset += i; - return i; + if (pos < 0) + return -EINVAL; + if (pos >= priv->maxwritelen) + return 0; + if (len > priv->maxwritelen - pos) + len = priv->maxwritelen - pos; + if (copy_from_user(priv->wbuffer + pos, buffer, len)) + return -EFAULT; + if ( pos + len > priv->writelen ) + priv->writelen = len + file->f_pos; + *offset = pos + len; + return len; } static int proc_status_open( struct inode *inode, struct file *file ) { @@ -4420,9 +4625,8 @@ static int proc_status_open( struct inode *inode, struct file *file ) { StatusRid status_rid; int i; - if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) + if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) return -ENOMEM; - memset(file->private_data, 0, sizeof(struct proc_data)); data = (struct proc_data *)file->private_data; if ((data->rbuffer = kmalloc( 2048, GFP_KERNEL )) == NULL) { kfree (file->private_data); @@ -4500,9 +4704,8 @@ static int proc_stats_rid_open( struct inode *inode, int i, j; u32 *vals = stats.vals; - if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) + if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) return -ENOMEM; - memset(file->private_data, 0, sizeof(struct proc_data)); data = (struct proc_data *)file->private_data; if ((data->rbuffer = kmalloc( 4096, GFP_KERNEL )) == NULL) { kfree (file->private_data); @@ -4516,15 +4719,14 @@ static int proc_stats_rid_open( struct inode *inode, i*44096) { - printk(KERN_WARNING - "airo: Potentially disasterous buffer overflow averted!\n"); + airo_print_warn(apriv->dev->name, + "Potentially disasterous buffer overflow averted!"); break; } j+=sprintf(data->rbuffer+j, "%s: %u\n", statsLabels[i], vals[i]); } if (i*4>=stats.len){ - printk(KERN_WARNING - "airo: Got a short rid\n"); + airo_print_warn(apriv->dev->name, "Got a short rid"); } data->readlen = j; return 0; @@ -4686,7 +4888,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) { line += 14; v = get_dec_u16(line, &i, 4); - v = (v<0) ? 0 : ((v>2312) ? 2312 : v); + v = (v<0) ? 0 : ((v>AIRO_DEF_MTU) ? AIRO_DEF_MTU : v); ai->config.rtsThres = (u16)v; set_bit (FLAG_COMMIT, &ai->flags); } else if ( !strncmp( line, "TXMSDULifetime: ", 16 ) ) { @@ -4720,7 +4922,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) { line += 15; v = get_dec_u16(line, &i, 4); - v = (v<256) ? 256 : ((v>2312) ? 2312 : v); + v = (v<256) ? 256 : ((v>AIRO_DEF_MTU) ? AIRO_DEF_MTU : v); v = v & 0xfffe; /* Make sure its even */ ai->config.fragThresh = (u16)v; set_bit (FLAG_COMMIT, &ai->flags); @@ -4730,8 +4932,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) { case 'd': ai->config.modulation=MOD_DEFAULT; set_bit(FLAG_COMMIT, &ai->flags); break; case 'c': ai->config.modulation=MOD_CCK; set_bit(FLAG_COMMIT, &ai->flags); break; case 'm': ai->config.modulation=MOD_MOK; set_bit(FLAG_COMMIT, &ai->flags); break; - default: - printk( KERN_WARNING "airo: Unknown modulation\n" ); + default: airo_print_warn(ai->dev->name, "Unknown modulation"); } } else if (!strncmp(line, "Preamble: ", 10)) { line += 10; @@ -4739,10 +4940,10 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) { case 'a': ai->config.preamble=PREAMBLE_AUTO; set_bit(FLAG_COMMIT, &ai->flags); break; case 'l': ai->config.preamble=PREAMBLE_LONG; set_bit(FLAG_COMMIT, &ai->flags); break; case 's': ai->config.preamble=PREAMBLE_SHORT; set_bit(FLAG_COMMIT, &ai->flags); break; - default: printk(KERN_WARNING "airo: Unknown preamble\n"); + default: airo_print_warn(ai->dev->name, "Unknown preamble"); } } else { - printk( KERN_WARNING "Couldn't figure out %s\n", line ); + airo_print_warn(ai->dev->name, "Couldn't figure out %s", line); } while( line[0] && line[0] != '\n' ) line++; if ( line[0] ) line++; @@ -4766,20 +4967,18 @@ static int proc_config_open( struct inode *inode, struct file *file ) { struct airo_info *ai = dev->priv; int i; - if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) + if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) return -ENOMEM; - memset(file->private_data, 0, sizeof(struct proc_data)); data = (struct proc_data *)file->private_data; if ((data->rbuffer = kmalloc( 2048, GFP_KERNEL )) == NULL) { kfree (file->private_data); return -ENOMEM; } - if ((data->wbuffer = kmalloc( 2048, GFP_KERNEL )) == NULL) { + if ((data->wbuffer = kzalloc( 2048, GFP_KERNEL )) == NULL) { kfree (data->rbuffer); kfree (file->private_data); return -ENOMEM; } - memset( data->wbuffer, 0, 2048 ); data->maxwritelen = 2048; data->on_close = proc_config_on_close; @@ -4882,7 +5081,7 @@ static void proc_SSID_on_close( struct inode *inode, struct file *file ) { enable_MAC(ai, &rsp, 1); } -inline static u8 hexVal(char c) { +static inline u8 hexVal(char c) { if (c>='0' && c<='9') return c -= '0'; if (c>='a' && c<='f') return c -= 'a'-10; if (c>='A' && c<='F') return c -= 'A'-10; @@ -4970,7 +5169,6 @@ static int set_wep_key(struct airo_info *ai, u16 index, wkr.len = sizeof(wkr); wkr.kindex = 0xffff; wkr.mac[0] = (char)index; - if (perm) printk(KERN_INFO "Setting transmit key to %d\n", index); if (perm) ai->defindex = (char)index; } else { // We are actually setting the key @@ -4979,12 +5177,11 @@ static int set_wep_key(struct airo_info *ai, u16 index, wkr.klen = keylen; memcpy( wkr.key, key, keylen ); memcpy( wkr.mac, macaddr, ETH_ALEN ); - printk(KERN_INFO "Setting key %d\n", index); } - disable_MAC(ai, lock); + if (perm) disable_MAC(ai, lock); writeWepKeyRid(ai, &wkr, perm, lock); - enable_MAC(ai, &rsp, lock); + if (perm) enable_MAC(ai, &rsp, lock); return 0; } @@ -5007,12 +5204,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, 0, 0, 1, 1); + set_wep_key(ai, index, NULL, 0, 1, 1); return; } j = 2; } else { - printk(KERN_ERR "airo: WepKey passed invalid key index\n"); + airo_print_err(ai->dev->name, "WepKey passed invalid key index"); return; } @@ -5040,24 +5237,21 @@ static int proc_wepkey_open( struct inode *inode, struct file *file ) { int j=0; int rc; - if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) + if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) return -ENOMEM; - memset(file->private_data, 0, sizeof(struct proc_data)); memset(&wkr, 0, sizeof(wkr)); data = (struct proc_data *)file->private_data; - if ((data->rbuffer = kmalloc( 180, GFP_KERNEL )) == NULL) { + if ((data->rbuffer = kzalloc( 180, GFP_KERNEL )) == NULL) { kfree (file->private_data); return -ENOMEM; } - memset(data->rbuffer, 0, 180); data->writelen = 0; data->maxwritelen = 80; - if ((data->wbuffer = kmalloc( 80, GFP_KERNEL )) == NULL) { + if ((data->wbuffer = kzalloc( 80, GFP_KERNEL )) == NULL) { kfree (data->rbuffer); kfree (file->private_data); return -ENOMEM; } - memset( data->wbuffer, 0, 80 ); data->on_close = proc_wepkey_on_close; ptr = data->rbuffer; @@ -5088,9 +5282,8 @@ static int proc_SSID_open( struct inode *inode, struct file *file ) { char *ptr; SsidRid SSID_rid; - if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) + if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) return -ENOMEM; - memset(file->private_data, 0, sizeof(struct proc_data)); data = (struct proc_data *)file->private_data; if ((data->rbuffer = kmalloc( 104, GFP_KERNEL )) == NULL) { kfree (file->private_data); @@ -5098,12 +5291,11 @@ static int proc_SSID_open( struct inode *inode, struct file *file ) { } data->writelen = 0; data->maxwritelen = 33*3; - if ((data->wbuffer = kmalloc( 33*3, GFP_KERNEL )) == NULL) { + if ((data->wbuffer = kzalloc( 33*3, GFP_KERNEL )) == NULL) { kfree (data->rbuffer); kfree (file->private_data); return -ENOMEM; } - memset( data->wbuffer, 0, 33*3 ); data->on_close = proc_SSID_on_close; readSsidRid(ai, &SSID_rid); @@ -5132,9 +5324,8 @@ static int proc_APList_open( struct inode *inode, struct file *file ) { char *ptr; APListRid APList_rid; - if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) + if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) return -ENOMEM; - memset(file->private_data, 0, sizeof(struct proc_data)); data = (struct proc_data *)file->private_data; if ((data->rbuffer = kmalloc( 104, GFP_KERNEL )) == NULL) { kfree (file->private_data); @@ -5142,12 +5333,11 @@ static int proc_APList_open( struct inode *inode, struct file *file ) { } data->writelen = 0; data->maxwritelen = 4*6*3; - if ((data->wbuffer = kmalloc( data->maxwritelen, GFP_KERNEL )) == NULL) { + if ((data->wbuffer = kzalloc( data->maxwritelen, GFP_KERNEL )) == NULL) { kfree (data->rbuffer); kfree (file->private_data); return -ENOMEM; } - memset( data->wbuffer, 0, data->maxwritelen ); data->on_close = proc_APList_on_close; readAPListRid(ai, &APList_rid); @@ -5182,9 +5372,8 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) { /* If doLoseSync is not 1, we won't do a Lose Sync */ int doLoseSync = -1; - if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) + if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) return -ENOMEM; - memset(file->private_data, 0, sizeof(struct proc_data)); data = (struct proc_data *)file->private_data; if ((data->rbuffer = kmalloc( 1024, GFP_KERNEL )) == NULL) { kfree (file->private_data); @@ -5192,8 +5381,8 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) { } data->writelen = 0; data->maxwritelen = 0; - data->wbuffer = 0; - data->on_close = 0; + data->wbuffer = NULL; + data->on_close = NULL; if (file->f_mode & FMODE_WRITE) { if (!(file->f_mode & FMODE_READ)) { @@ -5227,7 +5416,7 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) { (int)BSSList_rid.bssid[5], (int)BSSList_rid.ssidLen, BSSList_rid.ssid, - (int)BSSList_rid.rssi); + (int)BSSList_rid.dBm); ptr += sprintf(ptr, " channel = %d %s %s %s %s\n", (int)BSSList_rid.dsChannel, BSSList_rid.cap & CAP_ESS ? "ESS" : "", @@ -5243,18 +5432,20 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) { static int proc_close( struct inode *inode, struct file *file ) { - struct proc_data *data = (struct proc_data *)file->private_data; - if ( data->on_close != NULL ) data->on_close( inode, file ); - if ( data->rbuffer ) kfree( data->rbuffer ); - if ( data->wbuffer ) kfree( data->wbuffer ); - kfree( data ); + struct proc_data *data = file->private_data; + + if (data->on_close != NULL) + data->on_close(inode, file); + kfree(data->rbuffer); + kfree(data->wbuffer); + kfree(data); return 0; } static struct net_device_list { struct net_device *dev; struct net_device_list *next; -} *airo_devices = 0; +} *airo_devices; /* Since the card doesn't automatically switch to the right WEP mode, we will make it do it. If the card isn't associated, every secs we @@ -5275,13 +5466,13 @@ static void timer_func( struct net_device *dev ) { break; case AUTH_SHAREDKEY: if (apriv->keyindex < auto_wep) { - set_wep_key(apriv, apriv->keyindex, 0, 0, 0, 0); + set_wep_key(apriv, apriv->keyindex, NULL, 0, 0, 0); apriv->config.authType = AUTH_SHAREDKEY; apriv->keyindex++; } else { /* Drop to ENCRYPT */ apriv->keyindex = 0; - set_wep_key(apriv, apriv->defindex, 0, 0, 0, 0); + set_wep_key(apriv, apriv->defindex, NULL, 0, 0, 0); apriv->config.authType = AUTH_ENCRYPT; } break; @@ -5329,9 +5520,9 @@ static int __devinit airo_pci_probe(struct pci_dev *pdev, pci_set_master(pdev); if (pdev->device == 0x5000 || pdev->device == 0xa504) - dev = _init_airo_card(pdev->irq, pdev->resource[0].start, 0, pdev); + dev = _init_airo_card(pdev->irq, pdev->resource[0].start, 0, pdev, &pdev->dev); else - dev = _init_airo_card(pdev->irq, pdev->resource[2].start, 0, pdev); + dev = _init_airo_card(pdev->irq, pdev->resource[2].start, 0, pdev, &pdev->dev); if (!dev) return -ENODEV; @@ -5343,16 +5534,13 @@ static void __devexit airo_pci_remove(struct pci_dev *pdev) { } -static int airo_pci_suspend(struct pci_dev *pdev, u32 state) +static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *dev = pci_get_drvdata(pdev); struct airo_info *ai = dev->priv; Cmd cmd; Resp rsp; - printk(KERN_DEBUG "%s: airo_mpi entering sleep mode (state=%d)\n", - dev->name, state); - if ((ai->APList == NULL) && (ai->APList = kmalloc(sizeof(APListRid), GFP_KERNEL)) == NULL) return -ENOMEM; @@ -5370,7 +5558,10 @@ static int airo_pci_suspend(struct pci_dev *pdev, u32 state) ai->power = state; cmd.cmd=HOSTSLEEP; issuecommand(ai, &cmd, &rsp); - return 0; + + 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)); } static int airo_pci_resume(struct pci_dev *pdev) @@ -5378,35 +5569,27 @@ static int airo_pci_resume(struct pci_dev *pdev) struct net_device *dev = pci_get_drvdata(pdev); struct airo_info *ai = dev->priv; Resp rsp; - int err; + pci_power_t prev_state = pdev->current_state; - printk(KERN_DEBUG "%s: airo_mpi waking up\n", dev->name); + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + pci_enable_wake(pdev, PCI_D0, 0); - if (!ai->power) - return 0; - - if (ai->power > 1) { - err = reset_mpi_card(dev, 0); - if (err) { - printk(KERN_ERR "%s: Error %d resetting on %s()\n", - dev->name, err, __FUNCTION__); - return err; - } - schedule_timeout (HZ/2); + if (prev_state != PCI_D1) { + reset_card(dev, 0); mpi_init_descriptors(ai); setup_card(ai, dev->dev_addr, 0); clear_bit(FLAG_RADIO_OFF, &ai->flags); - clear_bit(FLAG_RADIO_DOWN, &ai->flags); clear_bit(FLAG_PENDING_XMIT, &ai->flags); } else { OUT4500(ai, EVACK, EV_AWAKEN); OUT4500(ai, EVACK, EV_AWAKEN); - schedule_timeout(HZ/10); + msleep(100); } set_bit (FLAG_COMMIT, &ai->flags); disable_MAC(ai, 0); - schedule_timeout (HZ/5); + msleep(200); if (ai->SSID) { writeSsidRid(ai, ai->SSID, 0); kfree(ai->SSID); @@ -5419,7 +5602,7 @@ static int airo_pci_resume(struct pci_dev *pdev) } writeConfigRid(ai, 0); enable_MAC(ai, &rsp, 0); - ai->power = 0; + ai->power = PMSG_ON; netif_device_attach(dev); netif_wake_queue(dev); enable_interrupts(ai); @@ -5439,17 +5622,16 @@ static int __init airo_init_module( void ) airo_entry->gid = proc_gid; for( i = 0; i < 4 && io[i] && irq[i]; i++ ) { - printk( KERN_INFO - "airo: Trying to configure ISA adapter at irq=%d io=0x%x\n", - irq[i], io[i] ); - if (init_airo_card( irq[i], io[i], 0 )) + 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 )) have_isa_dev = 1; } #ifdef CONFIG_PCI - printk( KERN_INFO "airo: Probing for PCI adapters\n" ); + airo_print_info("", "Probing for PCI adapters"); pci_register_driver(&airo_driver); - printk( KERN_INFO "airo: Finished probing for PCI adapters\n" ); + airo_print_info("", "Finished probing for PCI adapters"); #endif /* Always exit with success, as we are a library module @@ -5461,7 +5643,7 @@ static int __init airo_init_module( void ) static void __exit airo_cleanup_module( void ) { while( airo_devices ) { - printk( KERN_INFO "airo: Unregistering %s\n", airo_devices->dev->name ); + airo_print_info(airo_devices->dev->name, "Unregistering...\n"); stop_airo_card( airo_devices->dev, 1 ); } #ifdef CONFIG_PCI @@ -5470,7 +5652,6 @@ static void __exit airo_cleanup_module( void ) remove_proc_entry("aironet", proc_root_driver); } -#ifdef WIRELESS_EXT /* * Initial Wireless Extension code for Aironet driver by : * Jean Tourrilhes - HPL - 17 November 00 @@ -5481,6 +5662,53 @@ static void __exit airo_cleanup_module( void ) * would not work at all... - Jean II */ +static u8 airo_rssi_to_dbm (tdsRssiEntry *rssi_rid, u8 rssi) +{ + if( !rssi_rid ) + return 0; + + return (0x100 - rssi_rid[rssi].rssidBm); +} + +static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm) +{ + int i; + + if( !rssi_rid ) + return 0; + + for( i = 0; i < 256; i++ ) + if (rssi_rid[i].rssidBm == dbm) + return rssi_rid[i].rssipct; + + return 0; +} + + +static int airo_get_quality (StatusRid *status_rid, CapabilityRid *cap_rid) +{ + int quality = 0; + + if ((status_rid->mode & 0x3f) == 0x3f && (cap_rid->hardCap & 8)) { + if (memcmp(cap_rid->prodName, "350", 3)) + if (status_rid->signalQuality > 0x20) + quality = 0; + else + quality = 0x20 - status_rid->signalQuality; + else + if (status_rid->signalQuality > 0xb0) + quality = 0; + else if (status_rid->signalQuality < 0x10) + quality = 0xa0; + else + quality = 0xb0 - status_rid->signalQuality; + } + return quality; +} + +#define airo_get_max_quality(cap_rid) (memcmp((cap_rid)->prodName, "350", 3) ? 0x20 : 0xa0) +#define airo_get_avg_quality(cap_rid) (memcmp((cap_rid)->prodName, "350", 3) ? 0x10 : 0x50); + /*------------------------------------------------------------------*/ /* * Wireless Handler : get protocol name @@ -5525,13 +5753,14 @@ static int airo_set_freq(struct net_device *dev, int channel = fwrq->m; /* We should do a better check than that, * based on the card capability !!! */ - if((channel < 1) || (channel > 16)) { - printk(KERN_DEBUG "%s: New channel value of %d is invalid!\n", dev->name, fwrq->m); + if((channel < 1) || (channel > 14)) { + airo_print_dbg(dev->name, "New channel value of %d is invalid!", + fwrq->m); rc = -EINVAL; } else { readConfigRid(local, 1); /* Yes ! We can set it !!! */ - local->config.channelSet = (u16)(channel - 1); + local->config.channelSet = (u16) channel; set_bit (FLAG_COMMIT, &local->flags); } } @@ -5549,6 +5778,7 @@ static int airo_get_freq(struct net_device *dev, { struct airo_info *local = dev->priv; StatusRid status_rid; /* Card status info */ + int ch; readConfigRid(local, 1); if ((local->config.opmode & 0xFF) == MODE_STA_ESS) @@ -5556,16 +5786,14 @@ static int airo_get_freq(struct net_device *dev, else readStatusRid(local, &status_rid, 1); -#ifdef WEXT_USECHANNELS - fwrq->m = ((int)status_rid.channel) + 1; - fwrq->e = 0; -#else - { - int f = (int)status_rid.channel; - fwrq->m = frequency_list[f] * 100000; + ch = (int)status_rid.channel; + if((ch > 0) && (ch < 15)) { + fwrq->m = frequency_list[ch - 1] * 100000; fwrq->e = 1; + } else { + fwrq->m = ch; + fwrq->e = 0; } -#endif return 0; } @@ -5640,7 +5868,7 @@ static int airo_get_essid(struct net_device *dev, /* If none, we may want to get the one that was set */ /* Push it out ! */ - dwrq->length = status_rid.SSIDlen + 1; + dwrq->length = status_rid.SSIDlen; dwrq->flags = 1; /* active */ return 0; @@ -5659,11 +5887,13 @@ static int airo_set_wap(struct net_device *dev, Cmd cmd; Resp rsp; APListRid APList_rid; - static const unsigned char bcast[ETH_ALEN] = { 255, 255, 255, 255, 255, 255 }; + static const u8 any[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + static const u8 off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; if (awrq->sa_family != ARPHRD_ETHER) return -EINVAL; - else if (!memcmp(bcast, awrq->sa_data, ETH_ALEN)) { + else if (!memcmp(any, awrq->sa_data, ETH_ALEN) || + !memcmp(off, awrq->sa_data, ETH_ALEN)) { memset(&cmd, 0, sizeof(cmd)); cmd.cmd=CMD_LOSE_SYNC; if (down_interruptible(&local->sem)) @@ -5849,8 +6079,8 @@ static int airo_set_rts(struct net_device *dev, int rthr = vwrq->value; if(vwrq->disabled) - rthr = 2312; - if((rthr < 0) || (rthr > 2312)) { + rthr = AIRO_DEF_MTU; + if((rthr < 0) || (rthr > AIRO_DEF_MTU)) { return -EINVAL; } readConfigRid(local, 1); @@ -5873,7 +6103,7 @@ static int airo_get_rts(struct net_device *dev, readConfigRid(local, 1); vwrq->value = local->config.rtsThres; - vwrq->disabled = (vwrq->value >= 2312); + vwrq->disabled = (vwrq->value >= AIRO_DEF_MTU); vwrq->fixed = 1; return 0; @@ -5892,8 +6122,8 @@ static int airo_set_frag(struct net_device *dev, int fthr = vwrq->value; if(vwrq->disabled) - fthr = 2312; - if((fthr < 256) || (fthr > 2312)) { + fthr = AIRO_DEF_MTU; + if((fthr < 256) || (fthr > AIRO_DEF_MTU)) { return -EINVAL; } fthr &= ~0x1; /* Get an even value - is it really needed ??? */ @@ -5917,7 +6147,7 @@ static int airo_get_frag(struct net_device *dev, readConfigRid(local, 1); vwrq->value = local->config.fragThresh; - vwrq->disabled = (vwrq->value >= 2312); + vwrq->disabled = (vwrq->value >= AIRO_DEF_MTU); vwrq->fixed = 1; return 0; @@ -6027,6 +6257,8 @@ static int airo_set_encode(struct net_device *dev, { struct airo_info *local = dev->priv; CapabilityRid cap_rid; /* Card capability info */ + int perm = ( dwrq->flags & IW_ENCODE_TEMP ? 0 : 1 ); + u16 currentAuthType = local->config.authType; /* Is WEP supported ? */ readCapabilityRid(local, &cap_rid, 1); @@ -6069,7 +6301,7 @@ 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, 1, 1); + set_wep_key(local, index, key.key, key.len, perm, 1); } /* WE specify that if a valid key is set, encryption * should be enabled (user may turn it off later) @@ -6077,13 +6309,12 @@ static int airo_set_encode(struct net_device *dev, if((index == current_index) && (key.len > 0) && (local->config.authType == AUTH_OPEN)) { local->config.authType = AUTH_ENCRYPT; - set_bit (FLAG_COMMIT, &local->flags); } } else { /* Do we want to just set the transmit key index ? */ int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; if ((index >= 0) && (index < ((cap_rid.softCap & 0x80)?4:1))) { - set_wep_key(local, index, 0, 0, 1, 1); + set_wep_key(local, index, NULL, 0, perm, 1); } else /* Don't complain if only change the mode */ if(!dwrq->flags & IW_ENCODE_MODE) { @@ -6098,7 +6329,7 @@ static int airo_set_encode(struct net_device *dev, if(dwrq->flags & IW_ENCODE_OPEN) local->config.authType = AUTH_ENCRYPT; // Only Wep /* Commit the changes to flags if needed */ - if(dwrq->flags & IW_ENCODE_MODE) + if (local->config.authType != currentAuthType) set_bit (FLAG_COMMIT, &local->flags); return -EINPROGRESS; /* Call commit handler */ } @@ -6151,6 +6382,272 @@ static int airo_get_encode(struct net_device *dev, return 0; } +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set extended Encryption parameters + */ +static int airo_set_encodeext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct airo_info *local = dev->priv; + struct iw_point *encoding = &wrqu->encoding; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + CapabilityRid cap_rid; /* Card capability info */ + int perm = ( encoding->flags & IW_ENCODE_TEMP ? 0 : 1 ); + u16 currentAuthType = local->config.authType; + int idx, key_len, alg = ext->alg, set_key = 1; + wep_key_t key; + + /* Is WEP supported ? */ + readCapabilityRid(local, &cap_rid, 1); + /* Older firmware doesn't support this... + if(!(cap_rid.softCap & 2)) { + return -EOPNOTSUPP; + } */ + readConfigRid(local, 1); + + /* Determine and validate the key index */ + idx = encoding->flags & IW_ENCODE_INDEX; + if (idx) { + if (idx < 1 || idx > ((cap_rid.softCap & 0x80) ? 4:1)) + return -EINVAL; + idx--; + } else + idx = get_wep_key(local, 0xffff); + + if (encoding->flags & IW_ENCODE_DISABLED) + alg = IW_ENCODE_ALG_NONE; + + if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { + /* Only set transmit key index here, actual + * key is set below if needed. + */ + set_wep_key(local, idx, NULL, 0, perm, 1); + set_key = ext->key_len > 0 ? 1 : 0; + } + + if (set_key) { + /* Set the requested key first */ + memset(key.key, 0, MAX_KEY_SIZE); + switch (alg) { + case IW_ENCODE_ALG_NONE: + key.len = 0; + break; + case IW_ENCODE_ALG_WEP: + if (ext->key_len > MIN_KEY_SIZE) { + key.len = MAX_KEY_SIZE; + } else if (ext->key_len > 0) { + key.len = MIN_KEY_SIZE; + } else { + return -EINVAL; + } + key_len = min (ext->key_len, key.len); + memcpy(key.key, ext->key, key_len); + break; + default: + return -EINVAL; + } + /* Send the key to the card */ + set_wep_key(local, idx, key.key, key.len, perm, 1); + } + + /* Read the flags */ + if(encoding->flags & IW_ENCODE_DISABLED) + local->config.authType = AUTH_OPEN; // disable encryption + if(encoding->flags & IW_ENCODE_RESTRICTED) + local->config.authType = AUTH_SHAREDKEY; // Only Both + if(encoding->flags & IW_ENCODE_OPEN) + local->config.authType = AUTH_ENCRYPT; // Only Wep + /* Commit the changes to flags if needed */ + if (local->config.authType != currentAuthType) + set_bit (FLAG_COMMIT, &local->flags); + + return -EINPROGRESS; +} + + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get extended Encryption parameters + */ +static int airo_get_encodeext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct airo_info *local = dev->priv; + struct iw_point *encoding = &wrqu->encoding; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + CapabilityRid cap_rid; /* Card capability info */ + int idx, max_key_len; + + /* Is it supported ? */ + readCapabilityRid(local, &cap_rid, 1); + if(!(cap_rid.softCap & 2)) { + return -EOPNOTSUPP; + } + readConfigRid(local, 1); + + max_key_len = encoding->length - sizeof(*ext); + if (max_key_len < 0) + return -EINVAL; + + idx = encoding->flags & IW_ENCODE_INDEX; + if (idx) { + if (idx < 1 || idx > ((cap_rid.softCap & 0x80) ? 4:1)) + return -EINVAL; + idx--; + } else + idx = get_wep_key(local, 0xffff); + + encoding->flags = idx + 1; + memset(ext, 0, sizeof(*ext)); + + /* Check encryption mode */ + switch(local->config.authType) { + case AUTH_ENCRYPT: + encoding->flags = IW_ENCODE_ALG_WEP | IW_ENCODE_ENABLED; + break; + case AUTH_SHAREDKEY: + encoding->flags = IW_ENCODE_ALG_WEP | IW_ENCODE_ENABLED; + break; + default: + case AUTH_OPEN: + encoding->flags = IW_ENCODE_ALG_NONE | IW_ENCODE_DISABLED; + break; + } + /* We can't return the key, so set the proper flag and return zero */ + encoding->flags |= IW_ENCODE_NOKEY; + memset(extra, 0, 16); + + /* Copy the key to the user buffer */ + ext->key_len = get_wep_key(local, idx); + if (ext->key_len > 16) { + ext->key_len=0; + } + + return 0; +} + + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set extended authentication parameters + */ +static int airo_set_auth(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct airo_info *local = dev->priv; + struct iw_param *param = &wrqu->param; + u16 currentAuthType = local->config.authType; + + switch (param->flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_VERSION: + case IW_AUTH_CIPHER_PAIRWISE: + case IW_AUTH_CIPHER_GROUP: + case IW_AUTH_KEY_MGMT: + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + case IW_AUTH_PRIVACY_INVOKED: + /* + * airo does not use these parameters + */ + break; + + case IW_AUTH_DROP_UNENCRYPTED: + if (param->value) { + /* Only change auth type if unencrypted */ + if (currentAuthType == AUTH_OPEN) + local->config.authType = AUTH_ENCRYPT; + } else { + local->config.authType = AUTH_OPEN; + } + + /* Commit the changes to flags if needed */ + if (local->config.authType != currentAuthType) + set_bit (FLAG_COMMIT, &local->flags); + break; + + case IW_AUTH_80211_AUTH_ALG: { + /* FIXME: What about AUTH_OPEN? This API seems to + * disallow setting our auth to AUTH_OPEN. + */ + if (param->value & IW_AUTH_ALG_SHARED_KEY) { + local->config.authType = AUTH_SHAREDKEY; + } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) { + local->config.authType = AUTH_ENCRYPT; + } else + return -EINVAL; + break; + + /* Commit the changes to flags if needed */ + if (local->config.authType != currentAuthType) + set_bit (FLAG_COMMIT, &local->flags); + } + + case IW_AUTH_WPA_ENABLED: + /* Silently accept disable of WPA */ + if (param->value > 0) + return -EOPNOTSUPP; + break; + + default: + return -EOPNOTSUPP; + } + return -EINPROGRESS; +} + + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get extended authentication parameters + */ +static int airo_get_auth(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct airo_info *local = dev->priv; + struct iw_param *param = &wrqu->param; + u16 currentAuthType = local->config.authType; + + switch (param->flags & IW_AUTH_INDEX) { + case IW_AUTH_DROP_UNENCRYPTED: + switch (currentAuthType) { + case AUTH_SHAREDKEY: + case AUTH_ENCRYPT: + param->value = 1; + break; + default: + param->value = 0; + break; + } + break; + + case IW_AUTH_80211_AUTH_ALG: + switch (currentAuthType) { + case AUTH_SHAREDKEY: + param->value = IW_AUTH_ALG_SHARED_KEY; + break; + case AUTH_ENCRYPT: + default: + param->value = IW_AUTH_ALG_OPEN_SYSTEM; + break; + } + break; + + case IW_AUTH_WPA_ENABLED: + param->value = 0; + break; + + default: + return -EOPNOTSUPP; + } + return 0; +} + + /*------------------------------------------------------------------*/ /* * Wireless Handler : set Tx-Power @@ -6168,7 +6665,8 @@ static int airo_set_txpow(struct net_device *dev, readCapabilityRid(local, &cap_rid, 1); if (vwrq->disabled) { - set_bit (FLAG_RADIO_OFF | FLAG_COMMIT, &local->flags); + set_bit (FLAG_RADIO_OFF, &local->flags); + set_bit (FLAG_COMMIT, &local->flags); return -EINPROGRESS; /* Call commit handler */ } if (vwrq->flags != IW_TXPOW_MWATT) { @@ -6306,11 +6804,27 @@ static int airo_get_range(struct net_device *dev, } range->num_frequency = k; + range->sensitivity = 65535; + /* Hum... Should put the right values there */ - range->max_qual.qual = 10; + if (local->rssi) + range->max_qual.qual = 100; /* % */ + else + range->max_qual.qual = airo_get_max_quality(&cap_rid); range->max_qual.level = 0x100 - 120; /* -120 dBm */ - range->max_qual.noise = 0; - range->sensitivity = 65535; + range->max_qual.noise = 0x100 - 120; /* -120 dBm */ + + /* Experimental measurements - boundary 11/5.5 Mb/s */ + /* Note : with or without the (local->rssi), results + * are somewhat different. - Jean II */ + if (local->rssi) { + range->avg_qual.qual = 50; /* % */ + range->avg_qual.level = 0x100 - 70; /* -70 dBm */ + } else { + range->avg_qual.qual = airo_get_avg_quality(&cap_rid); + range->avg_qual.level = 0x100 - 80; /* -80 dBm */ + } + range->avg_qual.noise = 0x100 - 85; /* -85 dBm */ for(i = 0 ; i < 8 ; i++) { range->bitrate[i] = cap_rid.supportedRates[i] * 500000; @@ -6328,9 +6842,9 @@ static int airo_get_range(struct net_device *dev, range->throughput = 1500 * 1000; range->min_rts = 0; - range->max_rts = 2312; + range->max_rts = AIRO_DEF_MTU; range->min_frag = 256; - range->max_frag = 2312; + range->max_frag = AIRO_DEF_MTU; if(cap_rid.softCap & 2) { // WEP: RC4 40 bits @@ -6371,16 +6885,14 @@ static int airo_get_range(struct net_device *dev, range->max_retry = 65535; range->min_r_time = 1024; range->max_r_time = 65535 * 1024; - /* Experimental measurements - boundary 11/5.5 Mb/s */ - /* Note : with or without the (local->rssi), results - * are somewhat different. - Jean II */ - range->avg_qual.qual = 6; - if (local->rssi) - range->avg_qual.level = 186; /* -70 dBm */ - else - range->avg_qual.level = 176; /* -80 dBm */ - range->avg_qual.noise = 0; + /* Event capability (kernel + driver) */ + range->event_capa[0] = (IW_EVENT_CAPA_K_0 | + IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) | + IW_EVENT_CAPA_MASK(SIOCGIWAP) | + IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); + range->event_capa[1] = IW_EVENT_CAPA_K_1; + range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVTXDROP); return 0; } @@ -6532,12 +7044,20 @@ static int airo_get_aplist(struct net_device *dev, loseSync = 0; memcpy(address[i].sa_data, BSSList.bssid, ETH_ALEN); address[i].sa_family = ARPHRD_ETHER; - if (local->rssi) - qual[i].level = 0x100 - local->rssi[BSSList.rssi].rssidBm; - else - qual[i].level = (BSSList.rssi + 321) / 2; - qual[i].qual = qual[i].noise = 0; - qual[i].updated = 2; + if (local->rssi) { + qual[i].level = 0x100 - BSSList.dBm; + qual[i].qual = airo_dbm_to_pct( local->rssi, BSSList.dBm ); + qual[i].updated = IW_QUAL_QUAL_UPDATED + | IW_QUAL_LEVEL_UPDATED + | IW_QUAL_DBM; + } else { + qual[i].level = (BSSList.dBm + 321) / 2; + qual[i].qual = 0; + qual[i].updated = IW_QUAL_QUAL_INVALID + | IW_QUAL_LEVEL_UPDATED + | IW_QUAL_DBM; + } + qual[i].noise = local->wstats.qual.noise; if (BSSList.index == 0xffff) break; } @@ -6585,6 +7105,7 @@ static int airo_set_scan(struct net_device *dev, struct airo_info *ai = dev->priv; Cmd cmd; Resp rsp; + int wake = 0; /* Note : you may have realised that, as this is a SET operation, * this is privileged and therefore a normal user can't @@ -6594,17 +7115,25 @@ static int airo_set_scan(struct net_device *dev, * Jean II */ if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN; + if (down_interruptible(&ai->sem)) + return -ERESTARTSYS; + + /* If there's already a scan in progress, don't + * trigger another one. */ + if (ai->scan_timeout > 0) + goto out; + /* Initiate a scan command */ + ai->scan_timeout = RUN_AT(3*HZ); memset(&cmd, 0, sizeof(cmd)); cmd.cmd=CMD_LISTBSS; - if (down_interruptible(&ai->sem)) - return -ERESTARTSYS; issuecommand(ai, &cmd, &rsp); - ai->scan_timestamp = jiffies; - up(&ai->sem); - - /* At this point, just return to the user. */ + wake = 1; +out: + up(&ai->sem); + if (wake) + wake_up_interruptible(&ai->thr_wait); return 0; } @@ -6616,7 +7145,7 @@ static int airo_set_scan(struct net_device *dev, static inline char *airo_translate_scan(struct net_device *dev, char *current_ev, char *end_buf, - BSSListRid *list) + BSSListRid *bss) { struct airo_info *ai = dev->priv; struct iw_event iwe; /* Temporary buffer */ @@ -6627,22 +7156,22 @@ static inline char *airo_translate_scan(struct net_device *dev, /* First entry *MUST* be the AP MAC address */ iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, list->bssid, ETH_ALEN); + memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN); current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); /* Other entries will be displayed in the order we give them */ /* Add the ESSID */ - iwe.u.data.length = list->ssidLen; + iwe.u.data.length = bss->ssidLen; if(iwe.u.data.length > 32) iwe.u.data.length = 32; iwe.cmd = SIOCGIWESSID; iwe.u.data.flags = 1; - current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, list->ssid); + current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->ssid); /* Add mode */ iwe.cmd = SIOCGIWMODE; - capabilities = le16_to_cpu(list->cap); + capabilities = le16_to_cpu(bss->cap); if(capabilities & (CAP_ESS | CAP_IBSS)) { if(capabilities & CAP_ESS) iwe.u.mode = IW_MODE_MASTER; @@ -6653,19 +7182,30 @@ static inline char *airo_translate_scan(struct net_device *dev, /* Add frequency */ iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = le16_to_cpu(list->dsChannel); - iwe.u.freq.m = frequency_list[iwe.u.freq.m] * 100000; + iwe.u.freq.m = le16_to_cpu(bss->dsChannel); + /* iwe.u.freq.m containt the channel (starting 1), our + * frequency_list array start at index 0... + */ + iwe.u.freq.m = frequency_list[iwe.u.freq.m - 1] * 100000; iwe.u.freq.e = 1; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); /* Add quality statistics */ iwe.cmd = IWEVQUAL; - if (ai->rssi) - iwe.u.qual.level = 0x100 - ai->rssi[list->rssi].rssidBm; - else - iwe.u.qual.level = (list->rssi + 321) / 2; - iwe.u.qual.noise = 0; - iwe.u.qual.qual = 0; + if (ai->rssi) { + iwe.u.qual.level = 0x100 - bss->dBm; + iwe.u.qual.qual = airo_dbm_to_pct( ai->rssi, bss->dBm ); + iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED + | IW_QUAL_LEVEL_UPDATED + | IW_QUAL_DBM; + } else { + iwe.u.qual.level = (bss->dBm + 321) / 2; + iwe.u.qual.qual = 0; + iwe.u.qual.updated = IW_QUAL_QUAL_INVALID + | IW_QUAL_LEVEL_UPDATED + | IW_QUAL_DBM; + } + iwe.u.qual.noise = ai->wstats.qual.noise; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); /* Add encryption capability */ @@ -6675,7 +7215,7 @@ static inline char *airo_translate_scan(struct net_device *dev, else iwe.u.data.flags = IW_ENCODE_DISABLED; iwe.u.data.length = 0; - current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, list->ssid); + current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->ssid); /* Rate : stuffing multiple values in a single event require a bit * more of magic - Jean II */ @@ -6687,10 +7227,10 @@ static inline char *airo_translate_scan(struct net_device *dev, /* Max 8 values */ for(i = 0 ; i < 8 ; i++) { /* NULL terminated */ - if(list->rates[i] == 0) + if(bss->rates[i] == 0) break; /* Bit rate given in 500 kb/s units (+ 0x80) */ - iwe.u.bitrate.value = ((list->rates[i] & 0x7f) * 500000); + iwe.u.bitrate.value = ((bss->rates[i] & 0x7f) * 500000); /* Add new value to event */ current_val = iwe_stream_add_value(current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN); } @@ -6713,53 +7253,38 @@ static int airo_get_scan(struct net_device *dev, char *extra) { struct airo_info *ai = dev->priv; - BSSListRid BSSList; - int rc; + BSSListElement *net; + int err = 0; char *current_ev = extra; - /* When we are associated again, the scan has surely finished. - * Just in case, let's make sure enough time has elapsed since - * we started the scan. - Javier */ - if(ai->scan_timestamp && time_before(jiffies,ai->scan_timestamp+3*HZ)) { - /* Important note : we don't want to block the caller - * until results are ready for various reasons. - * First, managing wait queues is complex and racy - * (there may be multiple simultaneous callers). - * Second, we grab some rtnetlink lock before comming - * here (in dev_ioctl()). - * Third, the caller can wait on the Wireless Event - * - Jean II */ + /* If a scan is in-progress, return -EAGAIN */ + if (ai->scan_timeout > 0) return -EAGAIN; - } - ai->scan_timestamp = 0; - /* There's only a race with proc_BSSList_open(), but its - * consequences are begnign. So I don't bother fixing it - Javier */ - - /* Try to read the first entry of the scan result */ - rc = PC4500_readrid(ai, RID_BSSLISTFIRST, &BSSList, sizeof(BSSList), 1); - if((rc) || (BSSList.index == 0xffff)) { - /* Client error, no scan results... - * The caller need to restart the scan. */ - return -ENODATA; - } + if (down_interruptible(&ai->sem)) + return -EAGAIN; - /* Read and parse all entries */ - while((!rc) && (BSSList.index != 0xffff)) { + list_for_each_entry (net, &ai->network_list, list) { /* Translate to WE format this entry */ current_ev = airo_translate_scan(dev, current_ev, - extra + IW_SCAN_MAX_DATA, - &BSSList); - - /* Read next entry */ - rc = PC4500_readrid(ai, RID_BSSLISTNEXT, - &BSSList, sizeof(BSSList), 1); + extra + dwrq->length, + &net->bss); + + /* Check if there is space for one more entry */ + if((extra + dwrq->length - current_ev) <= IW_EV_ADDR_LEN) { + /* Ask user space to try again with a bigger buffer */ + err = -E2BIG; + goto out; + } } + /* Length of data */ dwrq->length = (current_ev - extra); dwrq->flags = 0; /* todo */ - return 0; +out: + up(&ai->sem); + return err; } /*------------------------------------------------------------------*/ @@ -6786,7 +7311,10 @@ static int airo_config_commit(struct net_device *dev, readAPListRid(local, &APList_rid); readSsidRid(local, &SSID_rid); - reset_airo_card(dev); + if (test_bit(FLAG_MPI,&local->flags)) + setup_card(local, dev->dev_addr, 1 ); + else + reset_airo_card(dev); disable_MAC(local, 1); writeSsidRid(local, &SSID_rid, 1); writeAPListRid(local, &APList_rid, 1); @@ -6864,6 +7392,15 @@ static const iw_handler airo_handler[] = (iw_handler) airo_get_encode, /* SIOCGIWENCODE */ (iw_handler) airo_set_power, /* SIOCSIWPOWER */ (iw_handler) airo_get_power, /* SIOCGIWPOWER */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* SIOCSIWGENIE */ + (iw_handler) NULL, /* SIOCGIWGENIE */ + (iw_handler) airo_set_auth, /* SIOCSIWAUTH */ + (iw_handler) airo_get_auth, /* SIOCGIWAUTH */ + (iw_handler) airo_set_encodeext, /* SIOCSIWENCODEEXT */ + (iw_handler) airo_get_encodeext, /* SIOCGIWENCODEEXT */ + (iw_handler) NULL, /* SIOCSIWPMKSA */ }; /* Note : don't describe AIROIDIFC and AIROOLDIDIFC in here. @@ -6883,16 +7420,12 @@ static const struct iw_handler_def airo_handler_def = .num_standard = sizeof(airo_handler)/sizeof(iw_handler), .num_private = sizeof(airo_private_handler)/sizeof(iw_handler), .num_private_args = sizeof(airo_private_args)/sizeof(struct iw_priv_args), - .standard = (iw_handler *) airo_handler, - .private = (iw_handler *) airo_private_handler, - .private_args = (struct iw_priv_args *) airo_private_args, - .spy_offset = ((void *) (&((struct airo_info *) NULL)->spy_data) - - (void *) NULL), - + .standard = airo_handler, + .private = airo_private_handler, + .private_args = airo_private_args, + .get_wireless_stats = airo_get_wireless_stats, }; -#endif /* WIRELESS_EXT */ - /* * This defines the configuration part of the Wireless Extensions * Note : irq and spinlock protection will occur in the subroutines @@ -6911,7 +7444,7 @@ static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) int rc = 0; struct airo_info *ai = (struct airo_info *)dev->priv; - if (ai->power) + if (ai->power.event) return 0; switch (cmd) { @@ -6946,9 +7479,15 @@ static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) /* Separate R/W functions bracket legality here */ - if ( com.command <= AIRORRID ) + if ( com.command == AIRORSWVERSION ) { + if (copy_to_user(com.data, swversion, sizeof(swversion))) + rc = -EFAULT; + else + rc = 0; + } + else if ( com.command <= AIRORRID) rc = readrids(dev,&com); - else if ( com.command >= AIROPCAP && com.command <= AIROPLEAPUSR ) + else if ( com.command >= AIROPCAP && com.command <= (AIROPLEAPUSR+2) ) rc = writerids(dev,&com); else if ( com.command >= AIROFLSHRST && com.command <= AIRORESTART ) rc = flashcard(dev,&com); @@ -6965,7 +7504,6 @@ static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return rc; } -#ifdef WIRELESS_EXT /* * Get the Wireless stats out of the driver * Note : irq and spinlock protection will occur in the subroutines @@ -6979,14 +7517,16 @@ static void airo_read_wireless_stats(struct airo_info *local) { StatusRid status_rid; StatsRid stats_rid; + CapabilityRid cap_rid; u32 *vals = stats_rid.vals; /* Get stats out of the card */ clear_bit(JOB_WSTATS, &local->flags); - if (local->power) { + if (local->power.event) { up(&local->sem); return; } + readCapabilityRid(local, &cap_rid, 0); readStatusRid(local, &status_rid, 0); readStatsRid(local, &stats_rid, RID_STATS, 0); up(&local->sem); @@ -6994,18 +7534,21 @@ static void airo_read_wireless_stats(struct airo_info *local) /* The status */ local->wstats.status = status_rid.mode; - /* Signal quality and co. But where is the noise level ??? */ - local->wstats.qual.qual = status_rid.signalQuality; - if (local->rssi) - local->wstats.qual.level = 0x100 - local->rssi[status_rid.sigQuality].rssidBm; - else + /* Signal quality and co */ + if (local->rssi) { + local->wstats.qual.level = airo_rssi_to_dbm( local->rssi, status_rid.sigQuality ); + /* normalizedSignalStrength appears to be a percentage */ + local->wstats.qual.qual = status_rid.normalizedSignalStrength; + } else { local->wstats.qual.level = (status_rid.normalizedSignalStrength + 321) / 2; + local->wstats.qual.qual = airo_get_quality(&status_rid, &cap_rid); + } if (status_rid.len >= 124) { - local->wstats.qual.noise = 256 - status_rid.noisedBm; - local->wstats.qual.updated = 7; + local->wstats.qual.noise = 0x100 - status_rid.noisedBm; + local->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; } else { local->wstats.qual.noise = 0; - local->wstats.qual.updated = 3; + local->wstats.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_INVALID | IW_QUAL_DBM; } /* Packets discarded in the wireless adapter due to wireless @@ -7018,20 +7561,21 @@ static void airo_read_wireless_stats(struct airo_info *local) local->wstats.miss.beacon = vals[34]; } -struct iw_statistics *airo_get_wireless_stats(struct net_device *dev) +static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev) { struct airo_info *local = dev->priv; - /* Get stats out of the card if available */ - if (down_trylock(&local->sem) != 0) { - set_bit(JOB_WSTATS, &local->flags); - wake_up_interruptible(&local->thr_wait); - } else - airo_read_wireless_stats(local); + if (!test_bit(JOB_WSTATS, &local->flags)) { + /* Get stats out of the card if available */ + if (down_trylock(&local->sem) != 0) { + set_bit(JOB_WSTATS, &local->flags); + wake_up_interruptible(&local->thr_wait); + } else + airo_read_wireless_stats(local); + } return &local->wstats; } -#endif /* WIRELESS_EXT */ #ifdef CISCO_EXT /* @@ -7045,6 +7589,7 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) { unsigned char *iobuf; int len; struct airo_info *ai = dev->priv; + Resp rsp; if (test_bit(FLAG_FLASHING, &ai->flags)) return -EIO; @@ -7052,8 +7597,13 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) { switch(comp->command) { case AIROGCAP: ridcode = RID_CAPABILITIES; break; - case AIROGCFG: writeConfigRid (ai, 1); - ridcode = RID_CONFIG; break; + case AIROGCFG: ridcode = RID_CONFIG; + if (test_bit(FLAG_COMMIT, &ai->flags)) { + disable_MAC (ai, 1); + writeConfigRid (ai, 1); + enable_MAC (ai, &rsp, 1); + } + break; case AIROGSLIST: ridcode = RID_SSID; break; case AIROGVLIST: ridcode = RID_APLIST; break; case AIROGDRVNAM: ridcode = RID_DRVNAME; break; @@ -7071,14 +7621,12 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) { case AIROGSTAT: ridcode = RID_STATUS; break; case AIROGSTATSD32: ridcode = RID_STATSDELTA; break; case AIROGSTATSC32: ridcode = RID_STATS; break; -#ifdef MICSUPPORT case AIROGMICSTATS: if (copy_to_user(comp->data, &ai->micstats, min((int)comp->len,(int)sizeof(ai->micstats)))) return -EFAULT; return 0; -#endif - case AIRORRID: ridcode = comp->len; break; + case AIRORRID: ridcode = comp->ridnum; break; default: return -EINVAL; break; @@ -7092,10 +7640,7 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) { * then return it to the user * 9/22/2000 Honor user given length */ - if (comp->command == AIRORRID) - len = le16_to_cpu(*(unsigned short *)iobuf); /* Yuck! */ - else - len = comp->len; + len = comp->len; if (copy_to_user(comp->data, iobuf, min(len, (int)RIDSIZE))) { kfree (iobuf); @@ -7112,9 +7657,7 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) { static int writerids(struct net_device *dev, aironet_ioctl *comp) { struct airo_info *ai = dev->priv; int ridcode; -#ifdef MICSUPPORT int enabled; -#endif Resp rsp; static int (* writer)(struct airo_info *, u16 rid, const void *, int, int); unsigned char *iobuf; @@ -7135,12 +7678,15 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) { case AIROPCAP: ridcode = RID_CAPABILITIES; break; case AIROPAPLIST: ridcode = RID_APLIST; break; case AIROPCFG: ai->config.len = 0; + clear_bit(FLAG_COMMIT, &ai->flags); ridcode = RID_CONFIG; break; case AIROPWEPKEYNV: ridcode = RID_WEP_PERM; break; case AIROPLEAPUSR: ridcode = RID_LEAPUSERNAME; break; case AIROPLEAPPWD: ridcode = RID_LEAPPASSWORD; break; case AIROPWEPKEY: ridcode = RID_WEP_TEMP; writer = PC4500_writerid; break; + case AIROPLEAPUSR+1: ridcode = 0xFF2A; break; + case AIROPLEAPUSR+2: ridcode = 0xFF2B; break; /* this is not really a rid but a command given to the card * same with MAC off @@ -7168,11 +7714,9 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) { PC4500_readrid(ai,RID_STATSDELTACLEAR,iobuf,RIDSIZE, 1); -#ifdef MICSUPPORT enabled = ai->micstats.enabled; memset(&ai->micstats,0,sizeof(ai->micstats)); ai->micstats.enabled = enabled; -#endif if (copy_to_user(comp->data, iobuf, min((int)comp->len, (int)RIDSIZE))) { @@ -7225,14 +7769,8 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) { * Flash command switch table */ -int flashcard(struct net_device *dev, aironet_ioctl *comp) { +static int flashcard(struct net_device *dev, aironet_ioctl *comp) { int z; - int cmdreset(struct airo_info *); - int setflashmode(struct airo_info *); - int flashgchar(struct airo_info *,int,int); - int flashpchar(struct airo_info *,int,int); - int flashputbuf(struct airo_info *); - int flashrestart(struct airo_info *,struct net_device *); /* Only super-user can modify flash */ if (!capable(CAP_NET_ADMIN)) @@ -7290,21 +7828,20 @@ int flashcard(struct net_device *dev, aironet_ioctl *comp) { * card. */ -int cmdreset(struct airo_info *ai) { +static int cmdreset(struct airo_info *ai) { disable_MAC(ai, 1); if(!waitbusy (ai)){ - printk(KERN_INFO "Waitbusy hang before RESET\n"); + airo_print_info(ai->dev->name, "Waitbusy hang before RESET"); return -EBUSY; } OUT4500(ai,COMMAND,CMD_SOFTRESET); - set_current_state (TASK_UNINTERRUPTIBLE); - schedule_timeout (HZ); /* WAS 600 12/7/00 */ + ssleep(1); /* WAS 600 12/7/00 */ if(!waitbusy (ai)){ - printk(KERN_INFO "Waitbusy hang AFTER RESET\n"); + airo_print_info(ai->dev->name, "Waitbusy hang AFTER RESET"); return -EBUSY; } return 0; @@ -7315,7 +7852,7 @@ int cmdreset(struct airo_info *ai) { * mode */ -int setflashmode (struct airo_info *ai) { +static int setflashmode (struct airo_info *ai) { set_bit (FLAG_FLASHING, &ai->flags); OUT4500(ai, SWS0, FLASH_COMMAND); @@ -7328,12 +7865,11 @@ int setflashmode (struct airo_info *ai) { OUT4500(ai, SWS3, FLASH_COMMAND); OUT4500(ai, COMMAND,0); } - set_current_state (TASK_UNINTERRUPTIBLE); - schedule_timeout (HZ/2); /* 500ms delay */ + msleep(500); /* 500ms delay */ if(!waitbusy(ai)) { clear_bit (FLAG_FLASHING, &ai->flags); - printk(KERN_INFO "Waitbusy hang after setflash mode\n"); + airo_print_info(ai->dev->name, "Waitbusy hang after setflash mode"); return -EIO; } return 0; @@ -7343,7 +7879,7 @@ int setflashmode (struct airo_info *ai) { * x 50us for echo . */ -int flashpchar(struct airo_info *ai,int byte,int dwelltime) { +static int flashpchar(struct airo_info *ai,int byte,int dwelltime) { int echo; int waittime; @@ -7362,7 +7898,7 @@ int flashpchar(struct airo_info *ai,int byte,int dwelltime) { /* timeout for busy clear wait */ if(waittime <= 0 ){ - printk(KERN_INFO "flash putchar busywait timeout! \n"); + airo_print_info(ai->dev->name, "flash putchar busywait timeout!"); return -EBUSY; } @@ -7383,7 +7919,7 @@ int flashpchar(struct airo_info *ai,int byte,int dwelltime) { * Get a character from the card matching matchbyte * Step 3) */ -int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime){ +static int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime){ int rchar; unsigned char rbyte=0; @@ -7414,12 +7950,12 @@ int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime){ * send to the card */ -int flashputbuf(struct airo_info *ai){ +static int flashputbuf(struct airo_info *ai){ int nwords; /* Write stuff */ if (test_bit(FLAG_MPI,&ai->flags)) - memcpy(ai->pciaux + 0x8000, ai->flash, FLASHSIZE); + memcpy_toio(ai->pciaux + 0x8000, ai->flash, FLASHSIZE); else { OUT4500(ai,AUXPAGE,0x100); OUT4500(ai,AUXOFF,0); @@ -7436,22 +7972,25 @@ int flashputbuf(struct airo_info *ai){ /* * */ -int flashrestart(struct airo_info *ai,struct net_device *dev){ +static int flashrestart(struct airo_info *ai,struct net_device *dev){ int i,status; - set_current_state (TASK_UNINTERRUPTIBLE); - schedule_timeout (HZ); /* Added 12/7/00 */ + ssleep(1); /* Added 12/7/00 */ clear_bit (FLAG_FLASHING, &ai->flags); + if (test_bit(FLAG_MPI, &ai->flags)) { + status = mpi_init_descriptors(ai); + if (status != SUCCESS) + return status; + } status = setup_card(ai, dev->dev_addr, 1); if (!test_bit(FLAG_MPI,&ai->flags)) for( i = 0; i < MAX_FIDS; i++ ) { ai->fids[i] = transmit_allocate - ( ai, 2312, i >= MAX_FIDS / 2 ); + ( ai, AIRO_DEF_MTU, i >= MAX_FIDS / 2 ); } - set_current_state (TASK_UNINTERRUPTIBLE); - schedule_timeout (HZ); /* Added 12/7/00 */ + ssleep(1); /* Added 12/7/00 */ return status; } #endif /* CISCO_EXT */