--- /usr/src/linux-2.6.14/drivers/net/wireless/airo.c 2005-10-28 02:02:08.000000000 +0200 +++ airo.c 2005-11-02 19:36:35.000000000 +0100 @@ -46,6 +46,26 @@ #include #include +#include +#include + + +int trace_io=0; +u8 rx_key [8]; +u8 tx_key [8]; +struct crypto_tfm *tfm_michael = NULL; + +static void dump(u8* data,int size) { + int i; + printk("0: "); + for (i=0;iflags); + PC4500_readrid(ai, RID_MIC, &mic_rid, sizeof(mic_rid), 0); + up(&ai->sem); + + if (mic_rid.state & 0xff) { + /* Key must be valid and different */ + if (mic_rid.multicastValid) { + } + + /* Key must be valid and different */ + if (mic_rid.unicastValid) { + memcpy(rx_key,mic_rid.unicast,8); + memcpy(tx_key,mic_rid.unicast+8,8); + + } + } else { + /* So next time we have a valid key and mic is enabled, we will update + * the sequence number if the key is the same as before. + */ + memset(rx_key,0,8); + memset(tx_key,0,8); + } + dump(rx_key, 8); + dump(tx_key, 8); +} + +static int micsetup(struct airo_info *ai) { + return SUCCESS; +} #ifdef MICSUPPORT /*********************************************************************** * MIC ROUTINES * @@ -1244,7 +1325,7 @@ 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); +/*static */int flashpchar(struct airo_info *ai,int byte,int dwelltime); /* micinit - Initialize mic seed */ @@ -1755,7 +1836,23 @@ } return rc; } +static int writeWpaKeyRid(struct airo_info*ai, WpaKeyRid *pwkr, int lock) { + int rc; + WpaKeyRid wkr = *pwkr; + wkr.len = cpu_to_le16(sizeof(WpaKeyRid)); + wkr.kindex = cpu_to_le16(wkr.kindex); + wkr.klen = cpu_to_le16(wkr.klen); + + //for (rc=0;rc< sizeof(WpaKeyRid)/2; rc++) + // printk("wpa %d : %x\n", rc, *(((u16*)&(wkr)) + rc)); + + trace_io = 0; + rc = PC4500_writerid(ai, 0xff25, &wkr, sizeof(wkr), lock); + trace_io = 0; + if (rc!=SUCCESS) printk(KERN_ERR "airo: WEP_TEMP 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); @@ -2412,6 +2509,7 @@ #ifdef MICSUPPORT crypto_free_tfm(ai->tfm); #endif + crypto_free_tfm(tfm_michael); del_airo_dev( dev ); free_netdev( dev ); } @@ -2769,8 +2867,9 @@ SET_NETDEV_DEV(dev, dmdev); - if (test_bit(FLAG_MPI,&ai->flags)) + //if (test_bit(FLAG_MPI,&ai->flags)) reset_card (dev, 1); + msleep(300); rc = request_irq( dev->irq, airo_interrupt, SA_SHIRQ, dev->name, dev ); if (rc) { @@ -2898,8 +2997,21 @@ struct airo_info *ai = dev->priv; union iwreq_data wrqu; StatusRid status_rid; + IERID ie_rid; clear_bit(JOB_EVENT, &ai->flags); + + PC4500_readrid(ai, 0xff76, &ie_rid, sizeof(ie_rid), 0); + + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = 52; + wireless_send_event(dev, IWEVASSOCREQIE, &wrqu, ie_rid.reqIE); + + wrqu.data.length = 6; + wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, ie_rid.respIE); + memset(&wrqu, 0, sizeof(wrqu)); + + PC4500_readrid(ai, RID_STATUS, &status_rid, sizeof(status_rid), 0); up(&ai->sem); wrqu.data.length = 0; @@ -3024,12 +3136,14 @@ if ( status & EV_MIC ) { OUT4500( apriv, EVACK, EV_MIC ); -#ifdef MICSUPPORT + printk("new mic key...\n"); + //XXX update mic key for WPA... +//#ifdef MICSUPPORT if (test_bit(FLAG_MIC_CAPABLE, &apriv->flags)) { set_bit(JOB_MIC, &apriv->flags); wake_up_interruptible(&apriv->thr_wait); } -#endif +//#endif } if ( status & EV_LINK ) { union iwreq_data wrqu; @@ -3112,6 +3226,13 @@ /* Send event to user space */ wireless_send_event(dev, SIOCGIWAP, &wrqu,NULL); } + + if(newStatus == ASSOCIATED) { + /*IWEVASSOCREQIE*/ + /*IWEVASSOCRESPIE*/ + } + + printk("status : %x\n", newStatus); } /* Check to see if there is something to receive */ @@ -3264,6 +3385,32 @@ } #endif /* WIRELESS_SPY */ OUT4500( apriv, EVACK, EV_RX); + if (tfm_michael && rx_key [0]) { + struct scatterlist sg[3]; + u8 mic [8]; + + sg[0].page = virt_to_page(skb->data); + sg[0].offset = offset_in_page(skb->data); + sg[0].length = 12; + + + sg[1].page = virt_to_page(apriv->LLC); + sg[1].offset = offset_in_page(apriv->LLC); + sg[1].length = sizeof(apriv->LLC); + + sg[2].page = virt_to_page(skb->data+12); + sg[2].offset = offset_in_page(skb->data+12); + sg[2].length = len - 8; + crypto_digest_init(tfm_michael); + crypto_digest_setkey(tfm_michael, rx_key, 8); + crypto_digest_update(tfm_michael, sg, 3); + crypto_digest_final(tfm_michael, mic); + if (memcmp(mic, skb->data + skb->len - 8, 8)) + printk("rx mic error \n"); + + len -= 8; + skb_trim (skb, len + hdrlen); + } if (test_bit(FLAG_802_11, &apriv->flags)) { skb->mac.raw = skb->data; @@ -3357,8 +3504,10 @@ static void OUT4500( struct airo_info *ai, u16 reg, u16 val ) { if (test_bit(FLAG_MPI,&ai->flags)) reg <<= 1; - if ( !do8bitIO ) - outw( val, ai->dev->base_addr + reg ); + if ( !do8bitIO ) { + if (trace_io) + printk("->port (0x%x) val :0x%x\n",reg, val); + outw( val, ai->dev->base_addr + reg ); } else { outb( val & 0xff, ai->dev->base_addr + reg ); outb( val >> 8, ai->dev->base_addr + reg + 1 ); @@ -3711,6 +3860,7 @@ ai->config.authType = AUTH_OPEN; ai->config.modulation = MOD_CCK; + //XXX don"t work for wpa... #ifdef MICSUPPORT if ((cap_rid.len>=sizeof(cap_rid)) && (cap_rid.extSoftCap&1) && (micsetup(ai) == SUCCESS)) { @@ -3718,6 +3868,17 @@ set_bit(FLAG_MIC_CAPABLE, &ai->flags); } #endif + tfm_michael = crypto_alloc_tfm("michael_mic", 0); + + { + char LLC1 [] = {0, 0, 0, 0, 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; + memcpy(ai->LLC, LLC1, sizeof(LLC1)); + } + if (tfm_michael == NULL) { + printk(KERN_DEBUG "crypto API michael_mic\n"); + } + + /* Save off the MAC */ for( i = 0; i < ETH_ALEN; i++ ) { @@ -3774,6 +3935,7 @@ return ERROR; } +#if 0 /* Grab the initial wep key, we gotta save it for auto_wep */ rc = readWepKeyRid(ai, &wkr, 1, lock); if (rc == SUCCESS) do { @@ -3783,6 +3945,7 @@ } rc = readWepKeyRid(ai, &wkr, 0, lock); } while(lastindex != wkr.kindex); +#endif if (auto_wep) { ai->expires = RUN_AT(3*HZ); @@ -3950,7 +4113,12 @@ static int bap_write(struct airo_info *ai, const u16 *pu16Src, int bytelen, int whichbap) { + int i; bytelen = (bytelen + 1) & (~1); // round up to even value + if (trace_io) + for (i=0;i>1;i++) { + printk(" idx : %d val :0x%x\n", i, *(pu16Src+i)); + } if ( !do8bitIO ) outsw( ai->dev->base_addr+DATA0+whichbap, pu16Src, bytelen>>1 ); @@ -4206,12 +4374,49 @@ if (bap_setup(ai, txFid, 0x0036, BAP1) != SUCCESS) return ERROR; /* The hardware addresses aren't counted as part of the payload, so * we have to subtract the 12 bytes for the addresses off */ - payloadLen = cpu_to_le16(len + miclen); + //if (tfm_michael && tx_key [0]) + // miclen += 8; + payloadLen = cpu_to_le16(len + miclen + 8); bap_write(ai, &payloadLen, sizeof(payloadLen),BAP1); bap_write(ai, (const u16*)pPacket, sizeof(etherHead), BAP1); if (miclen) bap_write(ai, (const u16*)&pMic, miclen, BAP1); + if (tfm_michael && tx_key [0]) { + struct scatterlist sg[3]; + u8 mic [8]; + + sg[0].page = virt_to_page(pPacket); + sg[0].offset = offset_in_page(pPacket); + sg[0].length = sizeof(etherHead); + + + sg[1].page = virt_to_page(ai->LLC); + sg[1].offset = offset_in_page(ai->LLC); + sg[1].length = sizeof(ai->LLC); + + sg[2].page = virt_to_page(pPacket + sizeof(etherHead)); + sg[2].offset = offset_in_page(pPacket + sizeof(etherHead)); + sg[2].length = len; + crypto_digest_init(tfm_michael); + crypto_digest_setkey(tfm_michael, tx_key, 8); + crypto_digest_update(tfm_michael, sg, 3); + crypto_digest_final(tfm_michael, mic); + + //XXX ugly hack + bap_write(ai, (const u16*)(pPacket + sizeof(etherHead)), len - (len&1), BAP1); + if (len&1) { + u8 tmp [2]; + tmp [0] = pPacket [sizeof(etherHead) + len-1]; + tmp [1] = mic[0]; + bap_write(ai, (const u16*)tmp, 2, BAP1); + bap_write(ai, (const u16*)(mic+1), sizeof(mic)-1, BAP1); + } + else + bap_write(ai, (const u16*)mic, sizeof(mic), BAP1); + } + else bap_write(ai, (const u16*)(pPacket + sizeof(etherHead)), len, BAP1); + // issue the transmit command memset( &cmd, 0, sizeof( cmd ) ); cmd.cmd = CMD_TRANSMIT; @@ -5125,6 +5330,8 @@ return 0; } + + static void proc_wepkey_on_close( struct inode *inode, struct file *file ) { struct proc_data *data; struct proc_dir_entry *dp = PDE(inode); @@ -5401,6 +5608,7 @@ static void timer_func( struct net_device *dev ) { struct airo_info *apriv = dev->priv; Resp rsp; +#if 0 /* We don't have a link so try changing the authtype */ readConfigRid(apriv, 0); @@ -5428,6 +5636,7 @@ set_bit (FLAG_COMMIT, &apriv->flags); writeConfigRid(apriv, 0); enable_MAC(apriv, &rsp, 0); +#endif up(&apriv->sem); /* Schedule check to see if the change worked */ @@ -5815,7 +6024,7 @@ /* 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; @@ -6278,6 +6487,102 @@ return -EINPROGRESS; /* Call commit handler */ } +static int airo_set_encode_ext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; + struct airo_info *local = dev->priv; + CapabilityRid cap_rid; /* Card capability info */ + static const unsigned char macaddr[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 }; + WpaKeyRid wkr; + Resp rsp; + + int index = (wrqu->encoding.flags & IW_ENCODE_INDEX) - 1; + + /* Is WEP supported ? */ + readCapabilityRid(local, &cap_rid, 1); + /* Older firmware doesn't support this... + if(!(cap_rid.softCap & 2)) { + return -EOPNOTSUPP; + } */ + readConfigRid(local, 1); + + /* Check the index (none -> use current) */ + if ((index < 0) || (index >= ((cap_rid.softCap & 0x80) ? 4:1))) + return -EINVAL; + + + //printk("set wpa : %d %d %x\n", ext->alg, ext->key_len, sizeof(wkr)); + msleep(10); + if (down_interruptible(&local->sem)) + return ERROR; + + memset(&wkr, 0, sizeof(wkr)); + wkr.len = sizeof(wkr); + if ((wrqu->encoding.flags & IW_ENCODE_DISABLED) || + ext->alg == IW_ENCODE_ALG_NONE || ext->key_len == 0) { + //remove key + wkr.kindex = index; + memcpy( wkr.mac, macaddr, ETH_ALEN ); + printk(KERN_INFO "Removing key %d\n", index); + + memset(rx_key,0,8); + memset(tx_key,0,8); + } + else if (ext->alg == IW_ENCODE_ALG_TKIP && ext->key_len == 32) { + wkr.kindex = index; + memcpy( wkr.mac, macaddr, ETH_ALEN ); + wkr.klen = /*ext->key_len*/ 0x30; + //memcpy(wkr.key, ext->key, ext->key_len); + /* firmware use ndis order + a hole */ + memcpy(wkr.key, ext->key, 16); + memcpy(wkr.key + 32, ext->key + 24, 8); /*RX*/ + memcpy(wkr.key + 40, ext->key + 16, 8); /*TX*/ + /*printk("key : "); + int i; + for (i=0;i<32;i++) + printk("%x ", (char)(*(char*)(ext->key + i))); + printk("\n");*/ + dump(ext->key, 32); + printk(KERN_INFO "Setting key %d\n", index); + } + else + return -EINVAL; + + + + printk("len %d, idx %d, mac %x, key %x\n", wkr.klen, wkr.kindex, wkr.mac[0], wkr.key[0]); + + //disable_MAC(local, 1); + //if (index >= 3) + writeWpaKeyRid(local, &wkr, 0); + //enable_MAC(local, &rsp, 1); + + if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { + //disable_MAC(local, 1); + //set the key active + wkr.kindex = 0xffff; + wkr.mac[0] = (char)index; + //wkr.klen = /*ext->key_len*/0x30; + memset(wkr.key, 0, sizeof(wkr.key)); + printk(KERN_INFO "Setting transmit key to %d\n", index); + writeWpaKeyRid(local, &wkr, 0); + + + memcpy(rx_key,ext->key+24,8); + memcpy(tx_key,ext->key+16,8); + + //enable_MAC(local, &rsp, 1); + } + + up(&local->sem); + return 0; +} + + + /*------------------------------------------------------------------*/ /* * Wireless Handler : get Encryption Key @@ -6571,6 +6876,8 @@ IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); range->event_capa[1] = IW_EVENT_CAPA_K_1; range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVTXDROP); + + range->enc_capa = IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_WPA; return 0; } @@ -6821,6 +7128,7 @@ u16 capabilities; char * current_val; /* For rates */ int i; + unsigned char buf[40/*MAX_WPA_IE_LEN*/ * 2 + 30]; /* First entry *MUST* be the AP MAC address */ iwe.cmd = SIOCGIWAP; @@ -6909,6 +7217,35 @@ /* The other data in the scan result are not really * interesting, so for now drop it - Jean II */ + iwe.cmd = IWEVCUSTOM; + sprintf(buf, "bcn_int=%d", bss->beaconInterval); + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf); + + iwe.cmd = IWEVCUSTOM; + sprintf(buf, "atim=%u", bss->atimWindow); + current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf); + + if (/*WPA*/ 1) { + unsigned char ielen = 2 + bss->iep[1]; + if (ielen <= 40/*SSID_MAX_WPA_IE_LEN*/) { + + if (bss->iep[0] == 0xdd /* WLAN_EID_GENERIC */ && bss->iep[1] >= 4 + && memcmp(bss->iep + 2, "\x00\x50\xf2\x01", 4) == 0) { + unsigned char *p = buf; + p += sprintf(p, "wpa_ie="); + for (i = 0; i < ielen; i++) + p += sprintf(p, "%02x", bss->iep[i]); + + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, + buf); + } + } + } + + return current_ev; } @@ -7021,6 +7358,79 @@ return 0; } +static int airo_set_auth(struct net_device *dev, struct iw_request_info *info, + struct iw_param *data, char *extra) +{ + struct airo_info *local = dev->priv; + readConfigRid(local, 1); + + switch (data->flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_ENABLED: + if (data->value == 0) { + printk("WPA dis\n"); + local->config.wap=1; + local->config.authType=0x1; + } + else { + printk("WPA enable\n"); + local->config.wap=0x8; + local->config.enc_algo=0x210; + local->config.authType=0xc101; + local->config._reserved5[0]=0x40; + } + break; + default: + return /*-EOPNOTSUPP*/0; + } + + set_bit (FLAG_COMMIT, &local->flags); + + return -EINPROGRESS; /* Call commit handler */ + +} + +static int airo_set_ie(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra) +{ +return 0; +} + + +static int airo_disasociate(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + struct airo_info *local = dev->priv; + Resp rsp; +#if 0 + Cmd cmd; + memset(&cmd, 0, sizeof(cmd)); + cmd.cmd=CMD_LOSE_SYNC; + if (down_interruptible(&local->sem)) + return -ERESTARTSYS; + issuecommand(local, &cmd, &rsp); + up(&local->sem); +#else + SsidRid SSID_rid; /* SSIDs */ + + /* reset the list */ + memset(&SSID_rid, 0, sizeof(SSID_rid)); + + /* Set the SSID */ + strcpy(SSID_rid.ssids[0].ssid, "tsunami"); + SSID_rid.ssids[0].len = 7; + SSID_rid.len = sizeof(SSID_rid); + /* Write it to the card */ + disable_MAC(local, 1); + writeSsidRid(local, &SSID_rid, 1); + enable_MAC(local, &rsp, 1); + +#endif + return 0; + +} + /*------------------------------------------------------------------*/ /* * Structures to export the Wireless Handlers @@ -7082,6 +7492,10 @@ (iw_handler) airo_get_encode, /* SIOCGIWENCODE */ (iw_handler) airo_set_power, /* SIOCSIWPOWER */ (iw_handler) airo_get_power, /* SIOCGIWPOWER */ + [SIOCSIWAUTH-SIOCSIWCOMMIT] = (iw_handler) airo_set_auth, + [SIOCSIWGENIE-SIOCSIWCOMMIT] = (iw_handler) airo_set_ie, + [SIOCSIWENCODEEXT-SIOCSIWCOMMIT] = (iw_handler) airo_set_encode_ext, + [SIOCSIWMLME-SIOCSIWCOMMIT] = (iw_handler) airo_disasociate, }; /* Note : don't describe AIROIDIFC and AIROOLDIDIFC in here. @@ -7570,7 +7984,7 @@ * x 50us for echo . */ -static 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;