diff options
Diffstat (limited to 'drivers/net/wireless/airo.c')
-rw-r--r-- | drivers/net/wireless/airo.c | 7667 |
1 files changed, 7667 insertions, 0 deletions
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c new file mode 100644 index 000000000000..2899144f2153 --- /dev/null +++ b/drivers/net/wireless/airo.c @@ -0,0 +1,7667 @@ +/*====================================================================== + + Aironet driver for 4500 and 4800 series cards + + This code is released under both the GPL version 2 and BSD licenses. + Either license may be used. The respective licenses are found at + the end of this file. + + This code was developed by Benjamin Reed <breed@users.sourceforge.net> + including portions of which come from the Aironet PC4500 + Developer's Reference Manual and used with permission. Copyright + (C) 1999 Benjamin Reed. All Rights Reserved. Permission to use + code in the Developer's manual was granted for this driver by + Aironet. Major code contributions were received from Javier Achirica + <achirica@users.sourceforge.net> and Jean Tourrilhes <jt@hpl.hp.com>. + Code was also integrated from the Cisco Aironet driver for Linux. + Support for MPI350 cards was added by Fabrice Bellet + <fabrice@bellet.info>. + +======================================================================*/ + +#include <linux/config.h> +#include <linux/init.h> + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/proc_fs.h> +#include <linux/smp_lock.h> + +#include <linux/sched.h> +#include <linux/ptrace.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/interrupt.h> +#include <linux/in.h> +#include <linux/bitops.h> +#include <asm/io.h> +#include <asm/system.h> + +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/if_arp.h> +#include <linux/ioport.h> +#include <linux/pci.h> +#include <asm/uaccess.h> + +#ifdef CONFIG_PCI +static struct pci_device_id card_ids[] = { + { 0x14b9, 1, PCI_ANY_ID, PCI_ANY_ID, }, + { 0x14b9, 0x4500, PCI_ANY_ID, PCI_ANY_ID }, + { 0x14b9, 0x4800, PCI_ANY_ID, PCI_ANY_ID, }, + { 0x14b9, 0x0340, PCI_ANY_ID, PCI_ANY_ID, }, + { 0x14b9, 0x0350, PCI_ANY_ID, PCI_ANY_ID, }, + { 0x14b9, 0x5000, PCI_ANY_ID, PCI_ANY_ID, }, + { 0x14b9, 0xa504, PCI_ANY_ID, PCI_ANY_ID, }, + { 0, } +}; +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_resume(struct pci_dev *pdev); + +static struct pci_driver airo_driver = { + .name = "airo", + .id_table = card_ids, + .probe = airo_pci_probe, + .remove = __devexit_p(airo_pci_remove), + .suspend = airo_pci_suspend, + .resume = airo_pci_resume, +}; +#endif /* CONFIG_PCI */ + +/* Include Wireless Extension definition and check version - Jean II */ +#include <linux/wireless.h> +#define WIRELESS_SPY // enable iwspy support +#include <net/iw_handler.h> // New driver API + +#define CISCO_EXT // enable Cisco extensions +#ifdef CISCO_EXT +#include <linux/delay.h> +#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 + +/* As you can see this list is HUGH! + I really don't know what a lot of these counts are about, but they + are all here for completeness. If the IGNLABEL macro is put in + infront of the label, that statistic will not be included in the list + of statistics in the /proc filesystem */ + +#define IGNLABEL(comment) NULL +static char *statsLabels[] = { + "RxOverrun", + IGNLABEL("RxPlcpCrcErr"), + IGNLABEL("RxPlcpFormatErr"), + IGNLABEL("RxPlcpLengthErr"), + "RxMacCrcErr", + "RxMacCrcOk", + "RxWepErr", + "RxWepOk", + "RetryLong", + "RetryShort", + "MaxRetries", + "NoAck", + "NoCts", + "RxAck", + "RxCts", + "TxAck", + "TxRts", + "TxCts", + "TxMc", + "TxBc", + "TxUcFrags", + "TxUcPackets", + "TxBeacon", + "RxBeacon", + "TxSinColl", + "TxMulColl", + "DefersNo", + "DefersProt", + "DefersEngy", + "DupFram", + "RxFragDisc", + "TxAged", + "RxAged", + "LostSync-MaxRetry", + "LostSync-MissedBeacons", + "LostSync-ArlExceeded", + "LostSync-Deauth", + "LostSync-Disassoced", + "LostSync-TsfTiming", + "HostTxMc", + "HostTxBc", + "HostTxUc", + "HostTxFail", + "HostRxMc", + "HostRxBc", + "HostRxUc", + "HostRxDiscard", + IGNLABEL("HmacTxMc"), + IGNLABEL("HmacTxBc"), + IGNLABEL("HmacTxUc"), + IGNLABEL("HmacTxFail"), + IGNLABEL("HmacRxMc"), + IGNLABEL("HmacRxBc"), + IGNLABEL("HmacRxUc"), + IGNLABEL("HmacRxDiscard"), + IGNLABEL("HmacRxAccepted"), + "SsidMismatch", + "ApMismatch", + "RatesMismatch", + "AuthReject", + "AuthTimeout", + "AssocReject", + "AssocTimeout", + IGNLABEL("ReasonOutsideTable"), + IGNLABEL("ReasonStatus1"), + IGNLABEL("ReasonStatus2"), + IGNLABEL("ReasonStatus3"), + IGNLABEL("ReasonStatus4"), + IGNLABEL("ReasonStatus5"), + IGNLABEL("ReasonStatus6"), + IGNLABEL("ReasonStatus7"), + IGNLABEL("ReasonStatus8"), + IGNLABEL("ReasonStatus9"), + IGNLABEL("ReasonStatus10"), + IGNLABEL("ReasonStatus11"), + IGNLABEL("ReasonStatus12"), + IGNLABEL("ReasonStatus13"), + IGNLABEL("ReasonStatus14"), + IGNLABEL("ReasonStatus15"), + IGNLABEL("ReasonStatus16"), + IGNLABEL("ReasonStatus17"), + IGNLABEL("ReasonStatus18"), + IGNLABEL("ReasonStatus19"), + "RxMan", + "TxMan", + "RxRefresh", + "TxRefresh", + "RxPoll", + "TxPoll", + "HostRetries", + "LostSync-HostReq", + "HostTxBytes", + "HostRxBytes", + "ElapsedUsec", + "ElapsedSec", + "LostSyncBetterAP", + "PrivacyMismatch", + "Jammed", + "DiscRxNotWepped", + "PhyEleMismatch", + (char*)-1 }; +#ifndef RUN_AT +#define RUN_AT(x) (jiffies+(x)) +#endif + + +/* These variables are for insmod, since it seems that the rates + can only be set in setup_card. Rates should be a comma separated + (no spaces) list of rates (up to 8). */ + +static int rates[8]; +static int basic_rate; +static char *ssids[3]; + +static int io[4]; +static int irq[4]; + +static +int maxencrypt /* = 0 */; /* The highest rate that the card can encrypt at. + 0 means no limit. For old cards this was 4 */ + +static int auto_wep /* = 0 */; /* If set, it tries to figure out the wep mode */ +static int aux_bap /* = 0 */; /* Checks to see if the aux ports are needed to read + the bap, needed on some older cards and buses. */ +static int adhoc; + +static int probe = 1; + +static int proc_uid /* = 0 */; + +static int proc_gid /* = 0 */; + +static int airo_perm = 0555; + +static int proc_perm = 0644; + +MODULE_AUTHOR("Benjamin Reed"); +MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet \ + cards. Direct support for ISA/PCI/MPI cards and support \ + for PCMCIA when used with airo_cs."); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_SUPPORTED_DEVICE("Aironet 4500, 4800 and Cisco 340/350"); +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_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_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_param(adhoc, int, 0); +MODULE_PARM_DESC(adhoc, "If non-zero, the card will start in adhoc mode."); +module_param(probe, int, 0); +MODULE_PARM_DESC(probe, "If zero, the driver won't start the card."); + +module_param(proc_uid, int, 0); +MODULE_PARM_DESC(proc_uid, "The uid that the /proc files will belong to."); +module_param(proc_gid, int, 0); +MODULE_PARM_DESC(proc_gid, "The gid that the /proc files will belong to."); +module_param(airo_perm, int, 0); +MODULE_PARM_DESC(airo_perm, "The permission bits of /proc/[driver/]aironet."); +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 + IN4500. I would be extremely interested in the situation where this + doesn't work though!!! */ +static int do8bitIO = 0; + +/* Return codes */ +#define SUCCESS 0 +#define ERROR -1 +#define NO_PACKET -2 + +/* Commands */ +#define NOP2 0x0000 +#define MAC_ENABLE 0x0001 +#define MAC_DISABLE 0x0002 +#define CMD_LOSE_SYNC 0x0003 /* Not sure what this does... */ +#define CMD_SOFTRESET 0x0004 +#define HOSTSLEEP 0x0005 +#define CMD_MAGIC_PKT 0x0006 +#define CMD_SETWAKEMASK 0x0007 +#define CMD_READCFG 0x0008 +#define CMD_SETMODE 0x0009 +#define CMD_ALLOCATETX 0x000a +#define CMD_TRANSMIT 0x000b +#define CMD_DEALLOCATETX 0x000c +#define NOP 0x0010 +#define CMD_WORKAROUND 0x0011 +#define CMD_ALLOCATEAUX 0x0020 +#define CMD_ACCESS 0x0021 +#define CMD_PCIBAP 0x0022 +#define CMD_PCIAUX 0x0023 +#define CMD_ALLOCBUF 0x0028 +#define CMD_GETTLV 0x0029 +#define CMD_PUTTLV 0x002a +#define CMD_DELTLV 0x002b +#define CMD_FINDNEXTTLV 0x002c +#define CMD_PSPNODES 0x0030 +#define CMD_SETCW 0x0031 +#define CMD_SETPCF 0x0032 +#define CMD_SETPHYREG 0x003e +#define CMD_TXTEST 0x003f +#define MAC_ENABLETX 0x0101 +#define CMD_LISTBSS 0x0103 +#define CMD_SAVECFG 0x0108 +#define CMD_ENABLEAUX 0x0111 +#define CMD_WRITERID 0x0121 +#define CMD_USEPSPNODES 0x0130 +#define MAC_ENABLERX 0x0201 + +/* Command errors */ +#define ERROR_QUALIF 0x00 +#define ERROR_ILLCMD 0x01 +#define ERROR_ILLFMT 0x02 +#define ERROR_INVFID 0x03 +#define ERROR_INVRID 0x04 +#define ERROR_LARGE 0x05 +#define ERROR_NDISABL 0x06 +#define ERROR_ALLOCBSY 0x07 +#define ERROR_NORD 0x0B +#define ERROR_NOWR 0x0C +#define ERROR_INVFIDTX 0x0D +#define ERROR_TESTACT 0x0E +#define ERROR_TAGNFND 0x12 +#define ERROR_DECODE 0x20 +#define ERROR_DESCUNAV 0x21 +#define ERROR_BADLEN 0x22 +#define ERROR_MODE 0x80 +#define ERROR_HOP 0x81 +#define ERROR_BINTER 0x82 +#define ERROR_RXMODE 0x83 +#define ERROR_MACADDR 0x84 +#define ERROR_RATES 0x85 +#define ERROR_ORDER 0x86 +#define ERROR_SCAN 0x87 +#define ERROR_AUTH 0x88 +#define ERROR_PSMODE 0x89 +#define ERROR_RTYPE 0x8A +#define ERROR_DIVER 0x8B +#define ERROR_SSID 0x8C +#define ERROR_APLIST 0x8D +#define ERROR_AUTOWAKE 0x8E +#define ERROR_LEAP 0x8F + +/* Registers */ +#define COMMAND 0x00 +#define PARAM0 0x02 +#define PARAM1 0x04 +#define PARAM2 0x06 +#define STATUS 0x08 +#define RESP0 0x0a +#define RESP1 0x0c +#define RESP2 0x0e +#define LINKSTAT 0x10 +#define SELECT0 0x18 +#define OFFSET0 0x1c +#define RXFID 0x20 +#define TXALLOCFID 0x22 +#define TXCOMPLFID 0x24 +#define DATA0 0x36 +#define EVSTAT 0x30 +#define EVINTEN 0x32 +#define EVACK 0x34 +#define SWS0 0x28 +#define SWS1 0x2a +#define SWS2 0x2c +#define SWS3 0x2e +#define AUXPAGE 0x3A +#define AUXOFF 0x3C +#define AUXDATA 0x3E + +#define FID_TX 1 +#define FID_RX 2 +/* Offset into aux memory for descriptors */ +#define AUX_OFFSET 0x800 +/* Size of allocated packets */ +#define PKTSIZE 1840 +#define RIDSIZE 2048 +/* Size of the transmit queue */ +#define MAXTXQ 64 + +/* BAP selectors */ +#define BAP0 0 // Used for receiving packets +#define BAP1 2 // Used for xmiting packets and working with RIDS + +/* Flags */ +#define COMMAND_BUSY 0x8000 + +#define BAP_BUSY 0x8000 +#define BAP_ERR 0x4000 +#define BAP_DONE 0x2000 + +#define PROMISC 0xffff +#define NOPROMISC 0x0000 + +#define EV_CMD 0x10 +#define EV_CLEARCOMMANDBUSY 0x4000 +#define EV_RX 0x01 +#define EV_TX 0x02 +#define EV_TXEXC 0x04 +#define EV_ALLOC 0x08 +#define EV_LINK 0x80 +#define EV_AWAKE 0x100 +#define EV_TXCPY 0x400 +#define EV_UNKNOWN 0x800 +#define EV_MIC 0x1000 /* Message Integrity Check Interrupt */ +#define EV_AWAKEN 0x2000 +#define STATUS_INTS (EV_AWAKE|EV_LINK|EV_TXEXC|EV_TX|EV_TXCPY|EV_RX|EV_MIC) + +#ifdef CHECK_UNKNOWN_INTS +#define IGNORE_INTS ( EV_CMD | EV_UNKNOWN) +#else +#define IGNORE_INTS (~STATUS_INTS) +#endif + +/* RID TYPES */ +#define RID_RW 0x20 + +/* The RIDs */ +#define RID_CAPABILITIES 0xFF00 +#define RID_APINFO 0xFF01 +#define RID_RADIOINFO 0xFF02 +#define RID_UNKNOWN3 0xFF03 +#define RID_RSSI 0xFF04 +#define RID_CONFIG 0xFF10 +#define RID_SSID 0xFF11 +#define RID_APLIST 0xFF12 +#define RID_DRVNAME 0xFF13 +#define RID_ETHERENCAP 0xFF14 +#define RID_WEP_TEMP 0xFF15 +#define RID_WEP_PERM 0xFF16 +#define RID_MODULATION 0xFF17 +#define RID_OPTIONS 0xFF18 +#define RID_ACTUALCONFIG 0xFF20 /*readonly*/ +#define RID_FACTORYCONFIG 0xFF21 +#define RID_UNKNOWN22 0xFF22 +#define RID_LEAPUSERNAME 0xFF23 +#define RID_LEAPPASSWORD 0xFF24 +#define RID_STATUS 0xFF50 +#define RID_BEACON_HST 0xFF51 +#define RID_BUSY_HST 0xFF52 +#define RID_RETRIES_HST 0xFF53 +#define RID_UNKNOWN54 0xFF54 +#define RID_UNKNOWN55 0xFF55 +#define RID_UNKNOWN56 0xFF56 +#define RID_MIC 0xFF57 +#define RID_STATS16 0xFF60 +#define RID_STATS16DELTA 0xFF61 +#define RID_STATS16DELTACLEAR 0xFF62 +#define RID_STATS 0xFF68 +#define RID_STATSDELTA 0xFF69 +#define RID_STATSDELTACLEAR 0xFF6A +#define RID_ECHOTEST_RID 0xFF70 +#define RID_ECHOTEST_RESULTS 0xFF71 +#define RID_BSSLISTFIRST 0xFF72 +#define RID_BSSLISTNEXT 0xFF73 + +typedef struct { + u16 cmd; + u16 parm0; + u16 parm1; + u16 parm2; +} Cmd; + +typedef struct { + u16 status; + u16 rsp0; + u16 rsp1; + u16 rsp2; +} Resp; + +/* + * Rids and endian-ness: The Rids will always be in cpu endian, since + * this all the patches from the big-endian guys end up doing that. + * so all rid access should use the read/writeXXXRid routines. + */ + +/* This is redundant for x86 archs, but it seems necessary for ARM */ +#pragma pack(1) + +/* This structure came from an email sent to me from an engineer at + aironet for inclusion into this driver */ +typedef struct { + u16 len; + u16 kindex; + u8 mac[ETH_ALEN]; + u16 klen; + u8 key[16]; +} WepKeyRid; + +/* These structures are from the Aironet's PC4500 Developers Manual */ +typedef struct { + u16 len; + u8 ssid[32]; +} Ssid; + +typedef struct { + u16 len; + Ssid ssids[3]; +} SsidRid; + +typedef struct { + u16 len; + u16 modulation; +#define MOD_DEFAULT 0 +#define MOD_CCK 1 +#define MOD_MOK 2 +} ModulationRid; + +typedef struct { + u16 len; /* sizeof(ConfigRid) */ + u16 opmode; /* operating mode */ +#define MODE_STA_IBSS 0 +#define MODE_STA_ESS 1 +#define MODE_AP 2 +#define MODE_AP_RPTR 3 +#define MODE_ETHERNET_HOST (0<<8) /* rx payloads converted */ +#define MODE_LLC_HOST (1<<8) /* rx payloads left as is */ +#define MODE_AIRONET_EXTEND (1<<9) /* enable Aironet extenstions */ +#define MODE_AP_INTERFACE (1<<10) /* enable ap interface extensions */ +#define MODE_ANTENNA_ALIGN (1<<11) /* enable antenna alignment */ +#define MODE_ETHER_LLC (1<<12) /* enable ethernet LLC */ +#define MODE_LEAF_NODE (1<<13) /* enable leaf node bridge */ +#define MODE_CF_POLLABLE (1<<14) /* enable CF pollable */ +#define MODE_MIC (1<<15) /* enable MIC */ + u16 rmode; /* receive mode */ +#define RXMODE_BC_MC_ADDR 0 +#define RXMODE_BC_ADDR 1 /* ignore multicasts */ +#define RXMODE_ADDR 2 /* ignore multicast and broadcast */ +#define RXMODE_RFMON 3 /* wireless monitor mode */ +#define RXMODE_RFMON_ANYBSS 4 +#define RXMODE_LANMON 5 /* lan style monitor -- data packets only */ +#define RXMODE_DISABLE_802_3_HEADER (1<<8) /* disables 802.3 header on rx */ +#define RXMODE_NORMALIZED_RSSI (1<<9) /* return normalized RSSI */ + u16 fragThresh; + u16 rtsThres; + u8 macAddr[ETH_ALEN]; + u8 rates[8]; + u16 shortRetryLimit; + u16 longRetryLimit; + u16 txLifetime; /* in kusec */ + u16 rxLifetime; /* in kusec */ + u16 stationary; + u16 ordering; + u16 u16deviceType; /* for overriding device type */ + u16 cfpRate; + u16 cfpDuration; + u16 _reserved1[3]; + /*---------- Scanning/Associating ----------*/ + u16 scanMode; +#define SCANMODE_ACTIVE 0 +#define SCANMODE_PASSIVE 1 +#define SCANMODE_AIROSCAN 2 + u16 probeDelay; /* in kusec */ + u16 probeEnergyTimeout; /* in kusec */ + u16 probeResponseTimeout; + u16 beaconListenTimeout; + u16 joinNetTimeout; + u16 authTimeout; + u16 authType; +#define AUTH_OPEN 0x1 +#define AUTH_ENCRYPT 0x101 +#define AUTH_SHAREDKEY 0x102 +#define AUTH_ALLOW_UNENCRYPTED 0x200 + u16 associationTimeout; + u16 specifiedApTimeout; + u16 offlineScanInterval; + u16 offlineScanDuration; + u16 linkLossDelay; + u16 maxBeaconLostTime; + u16 refreshInterval; +#define DISABLE_REFRESH 0xFFFF + u16 _reserved1a[1]; + /*---------- Power save operation ----------*/ + u16 powerSaveMode; +#define POWERSAVE_CAM 0 +#define POWERSAVE_PSP 1 +#define POWERSAVE_PSPCAM 2 + u16 sleepForDtims; + u16 listenInterval; + u16 fastListenInterval; + u16 listenDecay; + u16 fastListenDelay; + u16 _reserved2[2]; + /*---------- Ap/Ibss config items ----------*/ + u16 beaconPeriod; + u16 atimDuration; + u16 hopPeriod; + u16 channelSet; + u16 channel; + u16 dtimPeriod; + u16 bridgeDistance; + u16 radioID; + /*---------- Radio configuration ----------*/ + u16 radioType; +#define RADIOTYPE_DEFAULT 0 +#define RADIOTYPE_802_11 1 +#define RADIOTYPE_LEGACY 2 + u8 rxDiversity; + u8 txDiversity; + u16 txPower; +#define TXPOWER_DEFAULT 0 + u16 rssiThreshold; +#define RSSI_DEFAULT 0 + u16 modulation; +#define PREAMBLE_AUTO 0 +#define PREAMBLE_LONG 1 +#define PREAMBLE_SHORT 2 + u16 preamble; + u16 homeProduct; + u16 radioSpecific; + /*---------- Aironet Extensions ----------*/ + u8 nodeName[16]; + u16 arlThreshold; + u16 arlDecay; + u16 arlDelay; + u16 _reserved4[1]; + /*---------- Aironet Extensions ----------*/ + u8 magicAction; +#define MAGIC_ACTION_STSCHG 1 +#define MAGIC_ACTION_RESUME 2 +#define MAGIC_IGNORE_MCAST (1<<8) +#define MAGIC_IGNORE_BCAST (1<<9) +#define MAGIC_SWITCH_TO_PSP (0<<10) +#define MAGIC_STAY_IN_CAM (1<<10) + u8 magicControl; + u16 autoWake; +} ConfigRid; + +typedef struct { + u16 len; + u8 mac[ETH_ALEN]; + u16 mode; + u16 errorCode; + u16 sigQuality; + u16 SSIDlen; + char SSID[32]; + char apName[16]; + u8 bssid[4][ETH_ALEN]; + u16 beaconPeriod; + u16 dimPeriod; + u16 atimDuration; + u16 hopPeriod; + u16 channelSet; + u16 channel; + u16 hopsToBackbone; + u16 apTotalLoad; + u16 generatedLoad; + u16 accumulatedArl; + u16 signalQuality; + u16 currentXmitRate; + u16 apDevExtensions; + u16 normalizedSignalStrength; + u16 shortPreamble; + u8 apIP[4]; + u8 noisePercent; /* Noise percent in last second */ + u8 noisedBm; /* Noise dBm in last second */ + u8 noiseAvePercent; /* Noise percent in last minute */ + u8 noiseAvedBm; /* Noise dBm in last minute */ + u8 noiseMaxPercent; /* Highest noise percent in last minute */ + u8 noiseMaxdBm; /* Highest noise dbm in last minute */ + u16 load; + u8 carrier[4]; + u16 assocStatus; +#define STAT_NOPACKETS 0 +#define STAT_NOCARRIERSET 10 +#define STAT_GOTCARRIERSET 11 +#define STAT_WRONGSSID 20 +#define STAT_BADCHANNEL 25 +#define STAT_BADBITRATES 30 +#define STAT_BADPRIVACY 35 +#define STAT_APFOUND 40 +#define STAT_APREJECTED 50 +#define STAT_AUTHENTICATING 60 +#define STAT_DEAUTHENTICATED 61 +#define STAT_AUTHTIMEOUT 62 +#define STAT_ASSOCIATING 70 +#define STAT_DEASSOCIATED 71 +#define STAT_ASSOCTIMEOUT 72 +#define STAT_NOTAIROAP 73 +#define STAT_ASSOCIATED 80 +#define STAT_LEAPING 90 +#define STAT_LEAPFAILED 91 +#define STAT_LEAPTIMEDOUT 92 +#define STAT_LEAPCOMPLETE 93 +} StatusRid; + +typedef struct { + u16 len; + u16 spacer; + u32 vals[100]; +} StatsRid; + + +typedef struct { + u16 len; + u8 ap[4][ETH_ALEN]; +} APListRid; + +typedef struct { + u16 len; + char oui[3]; + char zero; + u16 prodNum; + char manName[32]; + char prodName[16]; + char prodVer[8]; + char factoryAddr[ETH_ALEN]; + char aironetAddr[ETH_ALEN]; + u16 radioType; + u16 country; + char callid[ETH_ALEN]; + char supportedRates[8]; + char rxDiversity; + char txDiversity; + u16 txPowerLevels[8]; + u16 hardVer; + u16 hardCap; + u16 tempRange; + u16 softVer; + u16 softSubVer; + u16 interfaceVer; + u16 softCap; + u16 bootBlockVer; + u16 requiredHard; + u16 extSoftCap; +} CapabilityRid; + +typedef struct { + u16 len; + u16 index; /* First is 0 and 0xffff means end of list */ +#define RADIO_FH 1 /* Frequency hopping radio type */ +#define RADIO_DS 2 /* Direct sequence radio type */ +#define RADIO_TMA 4 /* Proprietary radio used in old cards (2500) */ + u16 radioType; + u8 bssid[ETH_ALEN]; /* Mac address of the BSS */ + u8 zero; + u8 ssidLen; + u8 ssid[32]; + u16 rssi; +#define CAP_ESS (1<<0) +#define CAP_IBSS (1<<1) +#define CAP_PRIVACY (1<<4) +#define CAP_SHORTHDR (1<<5) + u16 cap; + u16 beaconInterval; + u8 rates[8]; /* Same as rates for config rid */ + struct { /* For frequency hopping only */ + u16 dwell; + u8 hopSet; + u8 hopPattern; + u8 hopIndex; + u8 fill; + } fh; + u16 dsChannel; + u16 atimWindow; +} BSSListRid; + +typedef struct { + u8 rssipct; + u8 rssidBm; +} tdsRssiEntry; + +typedef struct { + u16 len; + tdsRssiEntry x[256]; +} tdsRssiRid; + +typedef struct { + u16 len; + u16 state; + u16 multicastValid; + u8 multicast[16]; + u16 unicastValid; + u8 unicast[16]; +} MICRid; + +typedef struct { + u16 typelen; + + union { + u8 snap[8]; + struct { + u8 dsap; + u8 ssap; + u8 control; + u8 orgcode[3]; + u8 fieldtype[2]; + } llc; + } u; + u32 mic; + u32 seq; +} MICBuffer; + +typedef struct { + u8 da[ETH_ALEN]; + u8 sa[ETH_ALEN]; +} etherHead; + +#pragma pack() + +#define TXCTL_TXOK (1<<1) /* report if tx is ok */ +#define TXCTL_TXEX (1<<2) /* report if tx fails */ +#define TXCTL_802_3 (0<<3) /* 802.3 packet */ +#define TXCTL_802_11 (1<<3) /* 802.11 mac packet */ +#define TXCTL_ETHERNET (0<<4) /* payload has ethertype */ +#define TXCTL_LLC (1<<4) /* payload is llc */ +#define TXCTL_RELEASE (0<<5) /* release after completion */ +#define TXCTL_NORELEASE (1<<5) /* on completion returns to host */ + +#define BUSY_FID 0x10000 + +#ifdef CISCO_EXT +#define AIROMAGIC 0xa55a +/* Warning : SIOCDEVPRIVATE may disapear during 2.5.X - Jean II */ +#ifdef SIOCIWFIRSTPRIV +#ifdef SIOCDEVPRIVATE +#define AIROOLDIOCTL SIOCDEVPRIVATE +#define AIROOLDIDIFC AIROOLDIOCTL + 1 +#endif /* SIOCDEVPRIVATE */ +#else /* SIOCIWFIRSTPRIV */ +#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE +#endif /* SIOCIWFIRSTPRIV */ +/* This may be wrong. When using the new SIOCIWFIRSTPRIV range, we probably + * should use only "GET" ioctls (last bit set to 1). "SET" ioctls are root + * only and don't return the modified struct ifreq to the application which + * is usually a problem. - Jean II */ +#define AIROIOCTL SIOCIWFIRSTPRIV +#define AIROIDIFC AIROIOCTL + 1 + +/* Ioctl constants to be used in airo_ioctl.command */ + +#define AIROGCAP 0 // Capability rid +#define AIROGCFG 1 // USED A LOT +#define AIROGSLIST 2 // System ID list +#define AIROGVLIST 3 // List of specified AP's +#define AIROGDRVNAM 4 // NOTUSED +#define AIROGEHTENC 5 // NOTUSED +#define AIROGWEPKTMP 6 +#define AIROGWEPKNV 7 +#define AIROGSTAT 8 +#define AIROGSTATSC32 9 +#define AIROGSTATSD32 10 +#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 */ + +#define AIROPCAP AIROGSTATSD32 + 40 +#define AIROPVLIST AIROPCAP + 1 +#define AIROPSLIST AIROPVLIST + 1 +#define AIROPCFG AIROPSLIST + 1 +#define AIROPSIDS AIROPCFG + 1 +#define AIROPAPLIST AIROPSIDS + 1 +#define AIROPMACON AIROPAPLIST + 1 /* Enable mac */ +#define AIROPMACOFF AIROPMACON + 1 /* Disable mac */ +#define AIROPSTCLR AIROPMACOFF + 1 +#define AIROPWEPKEY AIROPSTCLR + 1 +#define AIROPWEPKEYNV AIROPWEPKEY + 1 +#define AIROPLEAPPWD AIROPWEPKEYNV + 1 +#define AIROPLEAPUSR AIROPLEAPPWD + 1 + +/* Flash codes */ + +#define AIROFLSHRST AIROPWEPKEYNV + 40 +#define AIROFLSHGCHR AIROFLSHRST + 1 +#define AIROFLSHSTFL AIROFLSHGCHR + 1 +#define AIROFLSHPCHR AIROFLSHSTFL + 1 +#define AIROFLPUTBUF AIROFLSHPCHR + 1 +#define AIRORESTART AIROFLPUTBUF + 1 + +#define FLASHSIZE 32768 +#define AUXMEMSIZE (256 * 1024) + +typedef struct aironet_ioctl { + unsigned short command; // What to do + unsigned short len; // Len of 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 + +typedef struct { + u32 size; // size + u8 enabled; // MIC enabled or not + u32 rxSuccess; // successful packets received + u32 rxIncorrectMIC; // pkts dropped due to incorrect MIC comparison + u32 rxNotMICed; // pkts dropped due to not being MIC'd + u32 rxMICPlummed; // pkts dropped due to not having a MIC plummed + u32 rxWrongSequence; // pkts dropped due to sequence number violation + u32 reserve[32]; +} mic_statistics; + +typedef struct { + u32 coeff[((EMMH32_MSGLEN_MAX)+3)>>2]; + u64 accum; // accumulated mic, reduced to u32 in final() + int position; // current position (byte offset) in message + union { + u8 d8[4]; + u32 d32; + } part; // saves partial message word across update() calls +} emmh32_context; + +typedef struct { + emmh32_context seed; // Context - the seed + u32 rx; // Received sequence number + u32 tx; // Tx sequence number + u32 window; // Start of window + u8 valid; // Flag to say if context is valid or not + u8 key[16]; +} miccntx; + +typedef struct { + miccntx mCtx; // Multicast context + miccntx uCtx; // Unicast context +} mic_module; + +typedef struct { + unsigned int rid: 16; + unsigned int len: 15; + unsigned int valid: 1; + dma_addr_t host_addr; +} Rid; + +typedef struct { + unsigned int offset: 15; + unsigned int eoc: 1; + unsigned int len: 15; + unsigned int valid: 1; + dma_addr_t host_addr; +} TxFid; + +typedef struct { + unsigned int ctl: 15; + unsigned int rdy: 1; + unsigned int len: 15; + unsigned int valid: 1; + dma_addr_t host_addr; +} RxFid; + +/* + * Host receive descriptor + */ +typedef struct { + 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 + buffer */ + int pending; +} HostRxDesc; + +/* + * Host transmit descriptor + */ +typedef struct { + 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 + buffer */ + int pending; +} HostTxDesc; + +/* + * Host RID descriptor + */ +typedef struct { + 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 + buffer */ +} HostRidDesc; + +typedef struct { + u16 sw0; + u16 sw1; + u16 status; + u16 len; +#define HOST_SET (1 << 0) +#define HOST_INT_TX (1 << 1) /* Interrupt on successful TX */ +#define HOST_INT_TXERR (1 << 2) /* Interrupt on unseccessful TX */ +#define HOST_LCC_PAYLOAD (1 << 4) /* LLC payload, 0 = Ethertype */ +#define HOST_DONT_RLSE (1 << 5) /* Don't release buffer when done */ +#define HOST_DONT_RETRY (1 << 6) /* Don't retry trasmit */ +#define HOST_CLR_AID (1 << 7) /* clear AID failure */ +#define HOST_RTS (1 << 9) /* Force RTS use */ +#define HOST_SHORT (1 << 10) /* Do short preamble */ + u16 ctl; + u16 aid; + u16 retries; + u16 fill; +} TxCtlHdr; + +typedef struct { + u16 ctl; + u16 duration; + char addr1[6]; + char addr2[6]; + char addr3[6]; + u16 seq; + char addr4[6]; +} WifiHdr; + + +typedef struct { + TxCtlHdr ctlhdr; + u16 fill1; + u16 fill2; + WifiHdr wifihdr; + u16 gaplen; + u16 status; +} WifiCtlHdr; + +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 }; + +// A few details needed for WEP (Wireless Equivalent Privacy) +#define MAX_KEY_SIZE 13 // 128 (?) bits +#define MIN_KEY_SIZE 5 // 40 bits RC4 - WEP +typedef struct wep_key_t { + u16 len; + u8 key[16]; /* 40-bit and 104-bit keys */ +} wep_key_t; + +/* Backward compatibility */ +#ifndef IW_ENCODE_NOKEY +#define IW_ENCODE_NOKEY 0x0800 /* Key is write only, so not present */ +#define IW_ENCODE_MODE (IW_ENCODE_DISABLED | IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN) +#endif /* IW_ENCODE_NOKEY */ + +/* List of Wireless Handlers (new API) */ +static const struct iw_handler_def airo_handler_def; +#endif /* WIRELESS_EXT */ + +static const char version[] = "airo.c 0.6 (Ben Reed & Javier Achirica)"; + +struct airo_info; + +static int get_dec_u16( char *buffer, int *start, int limit ); +static void OUT4500( struct airo_info *, u16 register, u16 value ); +static unsigned short IN4500( struct airo_info *, u16 register ); +static u16 setup_card(struct airo_info*, u8 *mac, int lock); +static int enable_MAC( struct airo_info *ai, Resp *rsp, int lock ); +static void disable_MAC(struct airo_info *ai, int lock); +static void enable_interrupts(struct airo_info*); +static void disable_interrupts(struct airo_info*); +static u16 issuecommand(struct airo_info*, Cmd *pCmd, Resp *pRsp); +static int bap_setup(struct airo_info*, u16 rid, u16 offset, int whichbap); +static int aux_bap_read(struct airo_info*, u16 *pu16Dst, int bytelen, + int whichbap); +static int fast_bap_read(struct airo_info*, u16 *pu16Dst, int bytelen, + int whichbap); +static int bap_write(struct airo_info*, const u16 *pu16Src, int bytelen, + int whichbap); +static int PC4500_accessrid(struct airo_info*, u16 rid, u16 accmd); +static int PC4500_readrid(struct airo_info*, u16 rid, void *pBuf, int len, int lock); +static int PC4500_writerid(struct airo_info*, u16 rid, const void + *pBuf, int len, int lock); +static int do_writerid( struct airo_info*, u16 rid, const void *rid_data, + int len, int dummy ); +static u16 transmit_allocate(struct airo_info*, int lenPayload, int raw); +static int transmit_802_3_packet(struct airo_info*, int len, char *pPacket); +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 + *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 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); +#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 <linux/crypto.h> +#endif + +struct airo_info { + struct net_device_stats stats; + struct net_device *dev; + /* Note, we can have MAX_FIDS outstanding. FIDs are 16-bits, so we + use the high bit to mark whether it is in use. */ +#define MAX_FIDS 6 +#define MPI_MAX_FIDS 1 + int fids[MAX_FIDS]; + ConfigRid config; + char keyindex; // Used with auto wep + char defindex; // Used with auto wep + struct proc_dir_entry *proc_entry; + spinlock_t aux_lock; + unsigned long flags; +#define FLAG_PROMISC 8 /* IFF |