📄 airo.c
字号:
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 MICSUPPORTstatic void micinit(struct airo_info *ai, MICRid *micr);static void 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);#endifstruct airo_info { struct net_device_stats stats; int open; struct net_device *dev; /* Note, we can have MAX_FIDS outstanding. FIDs are 16-bits, so we use the high bit to mark wether it is in use. */#define MAX_FIDS 6 int fids[MAX_FIDS]; int registered; ConfigRid config; int need_commit; // Need to set config char keyindex; // Used with auto wep char defindex; // Used with auto wep struct timer_list timer; struct proc_dir_entry *proc_entry; struct airo_info *next; spinlock_t aux_lock; unsigned long flags;#define FLAG_PROMISC IFF_PROMISC /* 0x100 - include/linux/if.h */#define FLAG_RADIO_OFF 0x02 /* User disabling of MAC */#define FLAG_RADIO_DOWN 0x08 /* ifup/ifdown disabling of MAC */#define FLAG_LOCKED 2 /* 0x04 - use as a bit offset */#define FLAG_FLASHING 0x10#define FLAG_ADHOC 0x01 /* Needed by MIC */#define FLAG_MIC_CAPABLE 0x20#define FLAG_UPDATE_MULTI 0x40#define FLAG_UPDATE_UNI 0x80#define FLAG_802_11 0x200 int (*bap_read)(struct airo_info*, u16 *pu16Dst, int bytelen, int whichbap); unsigned short *flash; tdsRssiEntry *rssi; struct semaphore sem; struct task_struct *task; struct tq_struct promisc_task; struct { struct sk_buff *skb; int fid; struct tq_struct task; } xmit, xmit11; struct net_device *wifidev;#ifdef WIRELESS_EXT struct iw_statistics wstats; // wireless stats unsigned long scan_timestamp; /* Time started to scan */ struct tq_struct event_task;#ifdef WIRELESS_SPY int spy_number; u_char spy_address[IW_MAX_SPY][ETH_ALEN]; struct iw_quality spy_stat[IW_MAX_SPY];#endif /* WIRELESS_SPY */#endif /* WIRELESS_EXT */ /* MIC stuff */ mic_module mod[2]; mic_statistics micstats; struct tq_struct mic_task;};static inline int bap_read(struct airo_info *ai, u16 *pu16Dst, int bytelen, int whichbap) { return ai->bap_read(ai, pu16Dst, bytelen, whichbap);}static int setup_proc_entry( struct net_device *dev, struct airo_info *apriv );static int takedown_proc_entry( struct net_device *dev, struct airo_info *apriv );#ifdef MICSUPPORT#include "mic.h"#endifstatic int readBSSListRid(struct airo_info *ai, int first, BSSListRid *list) { int rc; Cmd cmd; Resp rsp; if (first == 1) { memset(&cmd, 0, sizeof(cmd)); cmd.cmd=CMD_LISTBSS; if (down_interruptible(&ai->sem)) return -ERESTARTSYS; issuecommand(ai, &cmd, &rsp); up(&ai->sem); /* Let the command take effect */ set_current_state (TASK_INTERRUPTIBLE); ai->task = current; schedule_timeout (3*HZ); ai->task = NULL; } rc = PC4500_readrid(ai, first ? RID_BSSLISTFIRST : RID_BSSLISTNEXT, list, sizeof(*list)); list->len = le16_to_cpu(list->len); list->index = le16_to_cpu(list->index); list->radioType = le16_to_cpu(list->radioType); list->cap = le16_to_cpu(list->cap); list->beaconInterval = le16_to_cpu(list->beaconInterval); list->fh.dwell = le16_to_cpu(list->fh.dwell); list->dsChannel = le16_to_cpu(list->dsChannel); list->atimWindow = le16_to_cpu(list->atimWindow); return rc;}static int readWepKeyRid(struct airo_info*ai, WepKeyRid *wkr, int temp) { int rc = PC4500_readrid(ai, temp ? RID_WEP_TEMP : RID_WEP_PERM, wkr, sizeof(*wkr)); wkr->len = le16_to_cpu(wkr->len); wkr->kindex = le16_to_cpu(wkr->kindex); wkr->klen = le16_to_cpu(wkr->klen); return rc;}/* In the writeXXXRid routines we copy the rids so that we don't screwup * the originals when we endian them... */static int writeWepKeyRid(struct airo_info*ai, WepKeyRid *pwkr, int perm) { int rc; WepKeyRid wkr = *pwkr; wkr.len = cpu_to_le16(wkr.len); wkr.kindex = cpu_to_le16(wkr.kindex); wkr.klen = cpu_to_le16(wkr.klen); rc = PC4500_writerid(ai, RID_WEP_TEMP, &wkr, sizeof(wkr)); if (rc!=SUCCESS) printk(KERN_ERR "airo: WEP_TEMP set %x\n", rc); if (perm) { rc = PC4500_writerid(ai, RID_WEP_PERM, &wkr, sizeof(wkr)); if (rc!=SUCCESS) { printk(KERN_ERR "airo: WEP_PERM set %x\n", rc); } } return rc;}static int readSsidRid(struct airo_info*ai, SsidRid *ssidr) { int i; int rc = PC4500_readrid(ai, RID_SSID, ssidr, sizeof(*ssidr)); ssidr->len = le16_to_cpu(ssidr->len); for(i = 0; i < 3; i++) { ssidr->ssids[i].len = le16_to_cpu(ssidr->ssids[i].len); } return rc;}static int writeSsidRid(struct airo_info*ai, SsidRid *pssidr) { int rc; int i; SsidRid ssidr = *pssidr; ssidr.len = cpu_to_le16(ssidr.len); for(i = 0; i < 3; i++) { ssidr.ssids[i].len = cpu_to_le16(ssidr.ssids[i].len); } rc = PC4500_writerid(ai, RID_SSID, &ssidr, sizeof(ssidr)); return rc;}static int readConfigRid(struct airo_info*ai) { int rc; u16 *s; ConfigRid cfg; if (ai->config.len) return SUCCESS; rc = PC4500_readrid(ai, RID_ACTUALCONFIG, &cfg, sizeof(cfg)); if (rc != SUCCESS) return rc; for(s = &cfg.len; s <= &cfg.rtsThres; s++) *s = le16_to_cpu(*s); for(s = &cfg.shortRetryLimit; s <= &cfg.radioType; s++) *s = le16_to_cpu(*s); for(s = &cfg.txPower; s <= &cfg.radioSpecific; s++) *s = le16_to_cpu(*s); for(s = &cfg.arlThreshold; s <= &cfg.autoWake; s++) *s = le16_to_cpu(*s); ai->config = cfg; return SUCCESS;}static inline void checkThrottle(struct airo_info *ai) { int i;/* Old hardware had a limit on encryption speed */ if (ai->config.authType != AUTH_OPEN && maxencrypt) { for(i=0; i<8; i++) { if (ai->config.rates[i] > maxencrypt) { ai->config.rates[i] = 0; } } }}static int writeConfigRid(struct airo_info*ai) { u16 *s; ConfigRid cfgr; if (!ai->need_commit) return SUCCESS; ai->need_commit = 0; checkThrottle(ai); if ((cfgr.opmode & 0xFF) == MODE_STA_IBSS) ai->flags |= FLAG_ADHOC; else ai->flags &= ~FLAG_ADHOC; cfgr = ai->config; for(s = &cfgr.len; s <= &cfgr.rtsThres; s++) *s = cpu_to_le16(*s); for(s = &cfgr.shortRetryLimit; s <= &cfgr.radioType; s++) *s = cpu_to_le16(*s); for(s = &cfgr.txPower; s <= &cfgr.radioSpecific; s++) *s = cpu_to_le16(*s); for(s = &cfgr.arlThreshold; s <= &cfgr.autoWake; s++) *s = cpu_to_le16(*s); return PC4500_writerid( ai, RID_CONFIG, &cfgr, sizeof(cfgr));}static int readStatusRid(struct airo_info*ai, StatusRid *statr) { int rc = PC4500_readrid(ai, RID_STATUS, statr, sizeof(*statr)); u16 *s; statr->len = le16_to_cpu(statr->len); for(s = &statr->mode; s <= &statr->SSIDlen; s++) *s = le16_to_cpu(*s); for(s = &statr->beaconPeriod; s <= &statr->_reserved[9]; s++) *s = le16_to_cpu(*s); return rc;}static int readAPListRid(struct airo_info*ai, APListRid *aplr) { int rc = PC4500_readrid(ai, RID_APLIST, aplr, sizeof(*aplr)); aplr->len = le16_to_cpu(aplr->len); return rc;}static int writeAPListRid(struct airo_info*ai, APListRid *aplr) { int rc; aplr->len = cpu_to_le16(aplr->len); rc = PC4500_writerid(ai, RID_APLIST, aplr, sizeof(*aplr)); return rc;}static int readCapabilityRid(struct airo_info*ai, CapabilityRid *capr) { int rc = PC4500_readrid(ai, RID_CAPABILITIES, capr, sizeof(*capr)); u16 *s; capr->len = le16_to_cpu(capr->len); capr->prodNum = le16_to_cpu(capr->prodNum); capr->radioType = le16_to_cpu(capr->radioType); capr->country = le16_to_cpu(capr->country); for(s = &capr->txPowerLevels[0]; s <= &capr->requiredHard; s++) *s = le16_to_cpu(*s); return rc;}static int readStatsRid(struct airo_info*ai, StatsRid *sr, int rid) { int rc = PC4500_readrid(ai, rid, sr, sizeof(*sr)); u32 *i; sr->len = le16_to_cpu(sr->len); for(i = &sr->vals[0]; i <= &sr->vals[99]; i++) *i = le32_to_cpu(*i); return rc;}static int airo_open(struct net_device *dev) { struct airo_info *info = dev->priv; Resp rsp; if (info->flags & FLAG_FLASHING) return -EIO; /* Make sure the card is configured. * Wireless Extensions may postpone config changes until the card * is open (to pipeline changes and speed-up card setup). If * those changes are not yet commited, do it now - Jean II */ if(info->need_commit) { disable_MAC(info); writeConfigRid(info); } if (info->wifidev != dev) { /* Power on the MAC controller (which may have been disabled) */ info->flags &= ~FLAG_RADIO_DOWN; enable_interrupts(info); } enable_MAC(info, &rsp); netif_start_queue(dev); return 0;}static void get_tx_error(struct airo_info *ai, u32 fid){ u16 status; if (bap_setup(ai, ai->fids[fid] & 0xffff, 4, BAP0) == SUCCESS) { bap_read(ai, &status, 2, BAP0); if (le16_to_cpu(status) & 2) /* Too many retries */ ai->stats.tx_aborted_errors++; if (le16_to_cpu(status) & 4) /* Transmit lifetime exceeded */ ai->stats.tx_heartbeat_errors++; if (le16_to_cpu(status) & 8) /* Aid fail */ { } if (le16_to_cpu(status) & 0x10) /* MAC disabled */ ai->stats.tx_carrier_errors++; if (le16_to_cpu(status) & 0x20) /* Association lost */ { }#if WIRELESS_EXT > 13 /* We produce a TXDROP event only for retry or lifetime * exceeded, because that's the only status that really mean * that this particular node went away. * Other errors means that *we* screwed up. - Jean II */ if ((le16_to_cpu(status) & 2) || (le16_to_cpu(status) & 4)) { union iwreq_data wrqu; char junk[0x18]; /* Faster to skip over useless data than to do * another bap_setup(). We are at offset 0x6 and * need to go to 0x18 and read 6 bytes - Jean II */ bap_read(ai, (u16 *) junk, 0x18, BAP0); /* Copy 802.11 dest address. * We use the 802.11 header because the frame may * not be 802.3 or may be mangled... * In Ad-Hoc mode, it will be the node address. * In managed mode, it will be most likely the AP addr * User space will figure out how to convert it to * whatever it needs (IP address or else). * - Jean II */ memcpy(wrqu.addr.sa_data, junk + 0x12, ETH_ALEN); wrqu.addr.sa_family = ARPHRD_ETHER; /* Send event to user space */ wireless_send_event(ai->dev, IWEVTXDROP, &wrqu, NULL); }#endif /* WIRELESS_EXT > 13 */ }}static void airo_do_xmit(struct net_device *dev) { u16 status; int i; struct airo_info *priv = dev->priv; struct sk_buff *skb = priv->xmit.skb; int fid = priv->xmit.fid; u32 *fids = priv->fids; if (down_trylock(&priv->sem) != 0) { netif_stop_queue(dev); priv->xmit.task.routine = (void (*)(void *))airo_do_xmit; priv->xmit.task.data = (void *)dev; schedule_task(&priv->xmit.task); return; } status = transmit_802_3_packet (priv, fids[fid], skb->data); up(&priv->sem); i = 0; if ( status == SUCCESS ) { dev->trans_start = jiffies; for (; i < MAX_FIDS / 2 && (priv->fids[i] & 0xffff0000); i++); } else { priv->fids[fid] &= 0xffff; priv->stats.tx_window_errors++; } if (i < MAX_FIDS / 2) netif_wake_queue(dev); else netif_stop_queue(dev); dev_kfree_skb(skb);}static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) { s16 len; int i; struct airo_info *priv = dev->priv; u32 *fids = priv->fids; if ( skb == NULL ) { printk( KERN_ERR "airo: skb == NULL!!!\n" ); return 0; } /* Find a vacant FID */ for( i = 0; i < MAX_FIDS / 2 && (fids[i] & 0xffff0000); i++ ); if ( i == MAX_FIDS / 2 ) { priv->stats.tx_fifo_errors++; dev_kfree_skb(skb); } else { /* check min length*/ len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; /* Mark fid as used & save length for later */ fids[i] |= (len << 16); priv->xmit.skb = skb; priv->xmit.fid = i; airo_do_xmit(dev); } return 0;}static void airo_do_xmit11(struct net_device *dev) { u16 status; int i; struct airo_info *priv = dev->priv; struct sk_buff *skb = priv->xmit11.skb; int fid = priv->xmit11.fid; u32 *fids = priv->fids; if (down_trylock(&priv->sem) != 0) { netif_stop_queue(dev); priv->xmit11.task.routine = (void (*)(void *))airo_do_xmit11; priv->xmit11.task.data = (void *)dev; schedule_task(&priv->xmit11.task); return; } status = transmit_802_11_packet (priv, fids[fid], skb->data); up(&priv->sem); i = MAX_FIDS / 2; if ( status == SUCCESS ) { dev->trans_start = jiffies; for (; i < MAX_FIDS && (priv->fids[i] & 0xffff0000); i++); } else { priv->fids[fid] &= 0xffff; priv->stats.tx_window_errors++; } if (i < MAX_FIDS) netif_wake_queue(dev); else netif_stop_queue(dev); dev_kfree_skb(skb);}static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) { s16 len; int i; struct airo_info *priv = dev->priv; u32 *fids = priv->fids; if ( skb == NULL ) { printk( KERN_ERR "airo: skb == NULL!!!\n" ); return 0; } /* Find a vacant FID */ for( i = MAX_FIDS / 2; i < MAX_FIDS && (fids[i] & 0xffff0000); i++ ); if ( i == MAX_FIDS ) { priv->stats.tx_fifo_errors++; dev_kfree_skb(skb); } else { /* check min length*/ len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; /* Mark fid as used & save length for later */ fids[i] |= (len << 16); priv->xmit11.skb = skb; priv->xmit11.fid = i; airo_do_xmit11(dev); } return 0;}struct net_device_stats *airo_get_stats(struct net_device *dev){ struct airo_info *local = dev->priv; StatsRid stats_rid; u32 *vals = stats_rid.vals;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -