📄 airo.c
字号:
if (!ai->micstats.enabled) { //No Mic set or Mic OFF but we received a MIC'd packet. if (memcmp ((u8*)eth + 14, micsnap, sizeof(micsnap)) == 0) { ai->micstats.rxMICPlummed++; return ERROR; } return SUCCESS; } if (ntohs(mic->typelen) == 0x888E) return SUCCESS; if (memcmp (mic->u.snap, micsnap, sizeof(micsnap)) != 0) { // Mic enabled but packet isn't Mic'd ai->micstats.rxMICPlummed++; return ERROR; } micSEQ = ntohl(mic->seq); //store SEQ as CPU order //At this point we a have a mic'd packet and mic is enabled //Now do the mic error checking. //Receive seq must be odd if ( (micSEQ & 1) == 0 ) { ai->micstats.rxWrongSequence++; return ERROR; } for (i = 0; i < NUM_MODULES; i++) { int mcast = eth->da[0] & 1; //Determine proper context context = mcast ? &ai->mod[i].mCtx : &ai->mod[i].uCtx; //Make sure context is valid if (!context->valid) { if (i == 0) micError = NOMICPLUMMED; continue; } //DeMic it if (!mic->typelen) mic->typelen = htons(payLen + sizeof(MICBuffer) - 2); emmh32_init(&context->seed); emmh32_update(&context->seed, eth->da, ETH_ALEN*2); emmh32_update(&context->seed, (u8 *)&mic->typelen, sizeof(mic->typelen)+sizeof(mic->u.snap)); emmh32_update(&context->seed, (u8 *)&mic->seq,sizeof(mic->seq)); emmh32_update(&context->seed, eth->da + ETH_ALEN*2,payLen); //Calculate MIC emmh32_final(&context->seed, digest); if (memcmp(digest, &mic->mic, 4)) { //Make sure the mics match //Invalid Mic if (i == 0) micError = INCORRECTMIC; continue; } //Check Sequence number if mics pass if (RxSeqValid(ai, context, mcast, micSEQ) == SUCCESS) { ai->micstats.rxSuccess++; return SUCCESS; } if (i == 0) micError = SEQUENCE; } // Update statistics switch (micError) { case NOMICPLUMMED: ai->micstats.rxMICPlummed++; break; case SEQUENCE: ai->micstats.rxWrongSequence++; break; case INCORRECTMIC: ai->micstats.rxIncorrectMIC++; break; case NONE: break; case NOMIC: break; } return ERROR;}/*=========================================================================== * Description: Checks the Rx Seq number to make sure it is valid * and hasn't already been received * * Inputs: miccntx - mic context to check seq against * micSeq - the Mic seq number * * Returns: TRUE if valid otherwise FALSE. * * Author: sbraneky (10/15/01) * Merciless hacks by rwilcher (1/14/02) *--------------------------------------------------------------------------- */static int RxSeqValid (struct airo_info *ai,miccntx *context,int mcast,u32 micSeq){ u32 seq,index; //Allow for the ap being rebooted - if it is then use the next //sequence number of the current sequence number - might go backwards if (mcast) { if (test_bit(FLAG_UPDATE_MULTI, &ai->flags)) { clear_bit (FLAG_UPDATE_MULTI, &ai->flags); context->window = (micSeq > 33) ? micSeq : 33; context->rx = 0; // Reset rx } } else if (test_bit(FLAG_UPDATE_UNI, &ai->flags)) { clear_bit (FLAG_UPDATE_UNI, &ai->flags); context->window = (micSeq > 33) ? micSeq : 33; // Move window context->rx = 0; // Reset rx } //Make sequence number relative to START of window seq = micSeq - (context->window - 33); //Too old of a SEQ number to check. if ((s32)seq < 0) return ERROR; if ( seq > 64 ) { //Window is infinite forward MoveWindow(context,micSeq); return SUCCESS; } // We are in the window. Now check the context rx bit to see if it was already sent seq >>= 1; //divide by 2 because we only have odd numbers index = 1 << seq; //Get an index number if (!(context->rx & index)) { //micSEQ falls inside the window. //Add seqence number to the list of received numbers. context->rx |= index; MoveWindow(context,micSeq); return SUCCESS; } return ERROR;}static void MoveWindow(miccntx *context, u32 micSeq){ u32 shift; //Move window if seq greater than the middle of the window if (micSeq > context->window) { shift = (micSeq - context->window) >> 1; //Shift out old if (shift < 32) context->rx >>= shift; else context->rx = 0; context->window = micSeq; //Move window }}/*==============================================*//*========== 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 */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[] */ 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_set_buf(sg, plain, 16); crypto_cipher_encrypt(tfm, sg, sg, 16); 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; } }}/* prepare for calculation of a new mic */static void emmh32_init(emmh32_context *context){ /* prepare for new mic calculation */ context->accum = 0; context->position = 0;}/* add some bytes to the mic calculation */static 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 */static 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) { if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN; 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 */ ai->task = current; ssleep(3); 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); list->dBm = le16_to_cpu(list->dBm); return rc;}static int readWepKeyRid(struct airo_info*ai, WepKeyRid *wkr, int temp, int lock) { int rc = PC4500_readrid(ai, temp ? RID_WEP_TEMP : RID_WEP_PERM, wkr, sizeof(*wkr), lock); 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 lock) { 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), lock); 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._reserved4[0]; s++) *s = cpu_to_le16(*s); for(s = &cfg.autoWake; s <= &cfg.autoWake; s++) *s = cpu_to_le16(*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 (!test_bit (FLAG_COMMIT, &ai->flags)) return SUCCESS; clear_bit (FLAG_COMMIT, &ai->flags); clear_bit (FLAG_RESET, &ai->flags); 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._reserved4[0]; s++) *s = cpu_to_le16(*s); for(s = &cfgr.autoWake; 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 lock) { int rc; aplr->len = cpu_to_le16(aplr->len); rc = PC4500_writerid(ai, RID_APLIST, aplr, sizeof(*aplr), lock); return rc;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -