📄 airo.c
字号:
}/*==============================================*//*========== EMMH ROUTINES ====================*//*==============================================*//* mic accumulate */#define MIC_ACCUM(val) \ context->accum += (u64)(val) * context->coeff[coeff_position++];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){ /* take the keying material, expand if necessary, truncate at 16-bytes */ /* run through AES counter mode to generate context->coeff[] */ int i,j; u32 counter; u8 *cipher, plain[16]; struct scatterlist sg[1]; crypto_cipher_setkey(tfm, pkey, 16); counter = 0; for (i = 0; i < (sizeof(context->coeff)/sizeof(context->coeff[0])); ) { aes_counter[15] = (u8)(counter >> 0); aes_counter[14] = (u8)(counter >> 8); aes_counter[13] = (u8)(counter >> 16); 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; crypto_cipher_encrypt(tfm, sg, sg, 16); cipher = kmap(sg[0].page) + sg[0].offset; for (j=0; (j<16) && (i< (sizeof(context->coeff)/sizeof(context->coeff[0]))); ) { context->coeff[i++] = ntohl(*(u32 *)&cipher[j]); j += 4; } }}/* prepare for calculation of a new mic */void emmh32_init(emmh32_context *context){ /* prepare for new mic calculation */ context->accum = 0; context->position = 0;}/* add some bytes to the mic calculation */void emmh32_update(emmh32_context *context, u8 *pOctets, int len){ int coeff_position, byte_position; if (len == 0) return; coeff_position = context->position >> 2; /* deal with partial 32-bit word left over from last update */ byte_position = context->position & 3; if (byte_position) { /* have a partial word in part to deal with */ do { if (len == 0) return; context->part.d8[byte_position++] = *pOctets++; context->position++; len--; } while (byte_position < 4); MIC_ACCUM(htonl(context->part.d32)); } /* deal with full 32-bit words */ while (len >= 4) { MIC_ACCUM(htonl(*(u32 *)pOctets)); context->position += 4; pOctets += 4; len -= 4; } /* deal with partial 32-bit word that will be left over from this update */ byte_position = 0; while (len > 0) { context->part.d8[byte_position++] = *pOctets++; context->position++; len--; }}/* mask used to zero empty bytes for final partial word */static u32 mask32[4] = { 0x00000000L, 0xFF000000L, 0xFFFF0000L, 0xFFFFFF00L };/* calculate the mic */void emmh32_final(emmh32_context *context, u8 digest[4]){ int coeff_position, byte_position; u32 val; u64 sum, utmp; s64 stmp; coeff_position = context->position >> 2; /* deal with partial 32-bit word left over from last update */ byte_position = context->position & 3; if (byte_position) { /* have a partial word in part to deal with */ val = htonl(context->part.d32); MIC_ACCUM(val & mask32[byte_position]); /* zero empty bytes */ } /* reduce the accumulated u64 to a 32-bit MIC */ sum = context->accum; stmp = (sum & 0xffffffffLL) - ((sum >> 32) * 15); utmp = (stmp & 0xffffffffLL) - ((stmp >> 32) * 15); sum = utmp & 0xffffffffLL; if (utmp > 0x10000000fLL) sum -= 15; val = (u32)sum; digest[0] = (val>>24) & 0xFF; digest[1] = (val>>16) & 0xFF; digest[2] = (val>>8) & 0xFF; digest[3] = val & 0xFF;}#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), 1); 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), 1); 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 lock) { 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), lock); 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), lock); 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), 1); 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), 1); return rc;}static int readConfigRid(struct airo_info*ai, int lock) { int rc; u16 *s; ConfigRid cfg; if (ai->config.len) return SUCCESS; rc = PC4500_readrid(ai, RID_ACTUALCONFIG, &cfg, sizeof(cfg), lock); 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, int lock) { u16 *s; ConfigRid cfgr; if (!ai->need_commit) return SUCCESS; ai->need_commit = 0; checkThrottle(ai); cfgr = ai->config; if ((cfgr.opmode & 0xFF) == MODE_STA_IBSS) set_bit(FLAG_ADHOC, &ai->flags); else clear_bit(FLAG_ADHOC, &ai->flags); 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), lock);}static int readStatusRid(struct airo_info*ai, StatusRid *statr, int lock) { int rc = PC4500_readrid(ai, RID_STATUS, statr, sizeof(*statr), lock); 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->shortPreamble; s++) *s = le16_to_cpu(*s); statr->load = le16_to_cpu(statr->load); statr->assocStatus = le16_to_cpu(statr->assocStatus); return rc;}static int readAPListRid(struct airo_info*ai, APListRid *aplr) { int rc = PC4500_readrid(ai, RID_APLIST, aplr, sizeof(*aplr), 1); 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), 1); return rc;}static int readCapabilityRid(struct airo_info*ai, CapabilityRid *capr) { int rc = PC4500_readrid(ai, RID_CAPABILITIES, capr, sizeof(*capr), 1); 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 lock) { int rc = PC4500_readrid(ai, rid, sr, sizeof(*sr), lock); 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 (test_bit(FLAG_FLASHING, &info->flags)) 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, 1); writeConfigRid(info, 1); } if (info->wifidev != dev) { /* Power on the MAC controller (which may have been disabled) */ clear_bit(FLAG_RADIO_DOWN, &info->flags); enable_interrupts(info); } enable_MAC(info, &rsp, 1); 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_end_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; clear_bit(JOB_XMIT, &priv->flags); clear_bit(FLAG_PENDING_XMIT, &priv->flags); 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); dev_kfree_skb(skb);}static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) { s16 len; int i, j; 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++ ); for( j = i + 1; j < MAX_FIDS / 2 && (fids[j] & 0xffff0000); j++ ); if ( j >= MAX_FIDS / 2 ) { netif_stop_queue(dev); if (i == MAX_FIDS / 2) { priv->stats.tx_fifo_errors++; return 1; } } /* 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; if (down_trylock(&priv->sem) != 0) { set_bit(FLAG_PENDING_XMIT, &priv->flags); netif_stop_queue(dev); set_bit(JOB_XMIT, &priv->flags); wake_up_interruptible(&priv->thr_wait); } else airo_end_xmit(dev); return 0;}static void airo_end_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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -