Commit 44dbb4fd authored by Javier Achirica's avatar Javier Achirica Committed by Jeff Garzik

[wireless airo] add support for MIC and latest firmwares

parent f15151bd
...@@ -81,12 +81,12 @@ static struct pci_driver airo_driver = { ...@@ -81,12 +81,12 @@ static struct pci_driver airo_driver = {
#endif #endif
/* Support Cisco MIC feature */ /* Support Cisco MIC feature */
/* As this feature requires the AES encryption algorithm, it is not included #define MICSUPPORT
in the kernel tree. If you want to enable it, you need to download the
aes.h, aestab.h and mic.h files from the CVS at #if defined(MICSUPPORT) && !defined(CONFIG_CRYPTO)
http://sf.net/projects/airo-linux/ Put the files in the same directory #warning MIC support requires Crypto API
as airo.c and compile normally */
#undef MICSUPPORT #undef MICSUPPORT
#endif
/* Hack to do some power saving */ /* Hack to do some power saving */
#define POWER_ON_DOWN #define POWER_ON_DOWN
...@@ -615,14 +615,14 @@ typedef struct { ...@@ -615,14 +615,14 @@ typedef struct {
u16 arlDelay; u16 arlDelay;
u16 _reserved4[1]; u16 _reserved4[1];
/*---------- Aironet Extensions ----------*/ /*---------- Aironet Extensions ----------*/
u16 magicAction; u8 magicAction;
#define MAGIC_ACTION_STSCHG 1 #define MAGIC_ACTION_STSCHG 1
#define MACIC_ACTION_RESUME 2 #define MACIC_ACTION_RESUME 2
#define MAGIC_IGNORE_MCAST (1<<8) #define MAGIC_IGNORE_MCAST (1<<8)
#define MAGIC_IGNORE_BCAST (1<<9) #define MAGIC_IGNORE_BCAST (1<<9)
#define MAGIC_SWITCH_TO_PSP (0<<10) #define MAGIC_SWITCH_TO_PSP (0<<10)
#define MAGIC_STAY_IN_CAM (1<<10) #define MAGIC_STAY_IN_CAM (1<<10)
u16 magicControl; u8 magicControl;
u16 autoWake; u16 autoWake;
} ConfigRid; } ConfigRid;
...@@ -843,6 +843,7 @@ typedef struct { ...@@ -843,6 +843,7 @@ typedef struct {
#define AIROGMICRID 11 #define AIROGMICRID 11
#define AIROGMICSTATS 12 #define AIROGMICSTATS 12
#define AIROGFLAGS 13 #define AIROGFLAGS 13
#define AIRORRID 15
/* Leave gap of 40 commands after AIROGSTATSD32 for future */ /* Leave gap of 40 commands after AIROGSTATSD32 for future */
...@@ -994,6 +995,8 @@ static void micinit(struct airo_info *ai); ...@@ -994,6 +995,8 @@ static void micinit(struct airo_info *ai);
static int micsetup(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 encapsulate(struct airo_info *ai, etherHead *pPacket, MICBuffer *buffer, int len);
static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *pPacket, u16 payLen); static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *pPacket, u16 payLen);
#include <linux/crypto.h>
#endif #endif
struct airo_info { struct airo_info {
...@@ -1063,9 +1066,12 @@ struct airo_info { ...@@ -1063,9 +1066,12 @@ struct airo_info {
#endif /* WIRELESS_SPY */ #endif /* WIRELESS_SPY */
#endif /* WIRELESS_EXT > 15 */ #endif /* WIRELESS_EXT > 15 */
#endif /* WIRELESS_EXT */ #endif /* WIRELESS_EXT */
#ifdef MICSUPPORT
/* MIC stuff */ /* MIC stuff */
struct crypto_tfm *tfm;
mic_module mod[2]; mic_module mod[2];
mic_statistics micstats; mic_statistics micstats;
#endif
}; };
static inline int bap_read(struct airo_info *ai, u16 *pu16Dst, int bytelen, static inline int bap_read(struct airo_info *ai, u16 *pu16Dst, int bytelen,
...@@ -1079,7 +1085,462 @@ static int takedown_proc_entry( struct net_device *dev, ...@@ -1079,7 +1085,462 @@ static int takedown_proc_entry( struct net_device *dev,
struct airo_info *apriv ); struct airo_info *apriv );
#ifdef MICSUPPORT #ifdef MICSUPPORT
#include "mic.h" /***********************************************************************
* MIC ROUTINES *
***********************************************************************
*/
static int RxSeqValid (struct airo_info *ai,miccntx *context,int mcast,u32 micSeq);
static void MoveWindow(miccntx *context, u32 micSeq);
void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *);
void emmh32_init(emmh32_context *context);
void emmh32_update(emmh32_context *context, u8 *pOctets, int len);
void emmh32_final(emmh32_context *context, u8 digest[4]);
/* micinit - Initialize mic seed */
static void micinit(struct airo_info *ai)
{
MICRid mic_rid;
clear_bit(JOB_MIC, &ai->flags);
PC4500_readrid(ai, RID_MIC, &mic_rid, sizeof(mic_rid), 0);
up(&ai->sem);
ai->micstats.enabled = (mic_rid.state & 0x00FF) ? 1 : 0;
if (ai->micstats.enabled) {
/* Key must be valid and different */
if (mic_rid.multicastValid && (!ai->mod[0].mCtx.valid ||
(memcmp (ai->mod[0].mCtx.key, mic_rid.multicast,
sizeof(ai->mod[0].mCtx.key)) != 0))) {
/* Age current mic Context */
memcpy(&ai->mod[1].mCtx,&ai->mod[0].mCtx,sizeof(miccntx));
/* Initialize new context */
memcpy(&ai->mod[0].mCtx.key,mic_rid.multicast,sizeof(mic_rid.multicast));
ai->mod[0].mCtx.window = 33; //Window always points to the middle
ai->mod[0].mCtx.rx = 0; //Rx Sequence numbers
ai->mod[0].mCtx.tx = 0; //Tx sequence numbers
ai->mod[0].mCtx.valid = 1; //Key is now valid
/* Give key to mic seed */
emmh32_setseed(&ai->mod[0].mCtx.seed,mic_rid.multicast,sizeof(mic_rid.multicast), ai->tfm);
}
/* Key must be valid and different */
if (mic_rid.unicastValid && (!ai->mod[0].uCtx.valid ||
(memcmp(ai->mod[0].uCtx.key, mic_rid.unicast,
sizeof(ai->mod[0].uCtx.key)) != 0))) {
/* Age current mic Context */
memcpy(&ai->mod[1].uCtx,&ai->mod[0].uCtx,sizeof(miccntx));
/* Initialize new context */
memcpy(&ai->mod[0].uCtx.key,mic_rid.unicast,sizeof(mic_rid.unicast));
ai->mod[0].uCtx.window = 33; //Window always points to the middle
ai->mod[0].uCtx.rx = 0; //Rx Sequence numbers
ai->mod[0].uCtx.tx = 0; //Tx sequence numbers
ai->mod[0].uCtx.valid = 1; //Key is now valid
//Give key to mic seed
emmh32_setseed(&ai->mod[0].uCtx.seed, mic_rid.unicast, sizeof(mic_rid.unicast), ai->tfm);
}
} 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.
*/
ai->mod[0].uCtx.valid = 0;
ai->mod[0].mCtx.valid = 0;
}
}
/* micsetup - Get ready for business */
static int micsetup(struct airo_info *ai) {
int i;
if (ai->tfm == NULL)
ai->tfm = crypto_alloc_tfm("aes", 0);
if (ai->tfm == NULL) {
printk(KERN_ERR "airo: failed to load transform for AES\n");
return ERROR;
}
for (i=0; i < NUM_MODULES; i++) {
memset(&ai->mod[i].mCtx,0,sizeof(miccntx));
memset(&ai->mod[i].uCtx,0,sizeof(miccntx));
}
return SUCCESS;
}
char micsnap[]= {0xAA,0xAA,0x03,0x00,0x40,0x96,0x00,0x02};
/*===========================================================================
* Description: Mic a packet
*
* Inputs: etherHead * pointer to an 802.3 frame
*
* Returns: BOOLEAN if successful, otherwise false.
* PacketTxLen will be updated with the mic'd packets size.
*
* Caveats: It is assumed that the frame buffer will already
* be big enough to hold the largets mic message possible.
* (No memory allocation is done here).
*
* Author: sbraneky (10/15/01)
* Merciless hacks by rwilcher (1/14/02)
*/
static int encapsulate(struct airo_info *ai ,etherHead *frame, MICBuffer *mic, int payLen)
{
miccntx *context;
// Determine correct context
// If not adhoc, always use unicast key
if (test_bit(FLAG_ADHOC, &ai->flags) && (frame->da[0] & 0x1))
context = &ai->mod[0].mCtx;
else
context = &ai->mod[0].uCtx;
if (!context->valid)
return ERROR;
mic->typelen = htons(payLen + 16); //Length of Mic'd packet
memcpy(&mic->u.snap, micsnap, sizeof(micsnap)); // Add Snap
// Add Tx sequence
mic->seq = htonl(context->tx);
context->tx += 2;
emmh32_init(&context->seed); // Mic the packet
emmh32_update(&context->seed,frame->da,ETH_ALEN * 2); // DA,SA
emmh32_update(&context->seed,(u8*)&mic->typelen,10); // Type/Length and Snap
emmh32_update(&context->seed,(u8*)&mic->seq,sizeof(mic->seq)); //SEQ
emmh32_update(&context->seed,frame->da + ETH_ALEN * 2,payLen); //payload
emmh32_final(&context->seed, (u8*)&mic->mic);
/* New Type/length ?????????? */
mic->typelen = 0; //Let NIC know it could be an oversized packet
return SUCCESS;
}
typedef enum {
NONE,
NOMIC,
NOMICPLUMMED,
SEQUENCE,
INCORRECTMIC,
} mic_error;
/*===========================================================================
* Description: Decapsulates a MIC'd packet and returns the 802.3 packet
* (removes the MIC stuff) if packet is a valid packet.
*
* Inputs: etherHead pointer to the 802.3 packet
*
* Returns: BOOLEAN - TRUE if packet should be dropped otherwise FALSE
*
* Author: sbraneky (10/15/01)
* Merciless hacks by rwilcher (1/14/02)
*---------------------------------------------------------------------------
*/
static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *eth, u16 payLen)
{
int i;
u32 micSEQ;
miccntx *context;
u8 digest[4];
mic_error micError = NONE;
// Check if the packet is a Mic'd packet
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 ((u32)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 */
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;
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++;
sg[0].page = virt_to_page(aes_counter);
sg[0].offset = ((long) aes_counter & ~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;
}
#endif #endif
static int readBSSListRid(struct airo_info *ai, int first, static int readBSSListRid(struct airo_info *ai, int first,
...@@ -1556,6 +2017,7 @@ static int airo_set_mac_address(struct net_device *dev, void *p) ...@@ -1556,6 +2017,7 @@ static int airo_set_mac_address(struct net_device *dev, void *p)
struct sockaddr *addr = p; struct sockaddr *addr = p;
Resp rsp; Resp rsp;
readConfigRid(ai, 1);
memcpy (ai->config.macAddr, addr->sa_data, dev->addr_len); memcpy (ai->config.macAddr, addr->sa_data, dev->addr_len);
ai->need_commit = 1; ai->need_commit = 1;
disable_MAC(ai, 1); disable_MAC(ai, 1);
...@@ -1624,6 +2086,10 @@ void stop_airo_card( struct net_device *dev, int freeres ) ...@@ -1624,6 +2086,10 @@ void stop_airo_card( struct net_device *dev, int freeres )
/* PCMCIA frees this stuff, so only for PCI and ISA */ /* PCMCIA frees this stuff, so only for PCI and ISA */
release_region( dev->base_addr, 64 ); release_region( dev->base_addr, 64 );
} }
#ifdef MICSUPPORT
if (ai->tfm)
crypto_free_tfm(ai->tfm);
#endif
del_airo_dev( dev ); del_airo_dev( dev );
free_netdev( dev ); free_netdev( dev );
} }
...@@ -1725,6 +2191,9 @@ struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia ) ...@@ -1725,6 +2191,9 @@ struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia )
ai->thr_pid = kernel_thread(airo_thread, dev, CLONE_FS | CLONE_FILES); ai->thr_pid = kernel_thread(airo_thread, dev, CLONE_FS | CLONE_FILES);
if (ai->thr_pid < 0) if (ai->thr_pid < 0)
goto err_out_free; goto err_out_free;
#ifdef MICSUPPORT
ai->tfm = NULL;
#endif
rc = add_airo_dev( dev ); rc = add_airo_dev( dev );
if (rc) if (rc)
goto err_out_thr; goto err_out_thr;
...@@ -2125,9 +2594,11 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) ...@@ -2125,9 +2594,11 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
if (len > 2312) { if (len > 2312) {
printk( KERN_ERR "airo: Bad size %d\n", len ); printk( KERN_ERR "airo: Bad size %d\n", len );
len = 0; goto badrx;
} }
if (len) { if (len == 0)
goto badrx;
if (test_bit(FLAG_802_11, &apriv->flags)) { if (test_bit(FLAG_802_11, &apriv->flags)) {
bap_read (apriv, (u16*)&fc, sizeof(fc), BAP0); bap_read (apriv, (u16*)&fc, sizeof(fc), BAP0);
fc = le16_to_cpu(fc); fc = le16_to_cpu(fc);
...@@ -2152,10 +2623,8 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) ...@@ -2152,10 +2623,8 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
skb = dev_alloc_skb( len + hdrlen + 2 ); skb = dev_alloc_skb( len + hdrlen + 2 );
if ( !skb ) { if ( !skb ) {
apriv->stats.rx_dropped++; apriv->stats.rx_dropped++;
len = 0; goto badrx;
} }
}
if (len) {
buffer = (u16*)skb_put (skb, len + hdrlen); buffer = (u16*)skb_put (skb, len + hdrlen);
if (test_bit(FLAG_802_11, &apriv->flags)) { if (test_bit(FLAG_802_11, &apriv->flags)) {
buffer[0] = fc; buffer[0] = fc;
...@@ -2171,33 +2640,37 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) ...@@ -2171,33 +2640,37 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
else else
printk(KERN_ERR "airo: gaplen too big. Problems will follow...\n"); printk(KERN_ERR "airo: gaplen too big. Problems will follow...\n");
} }
bap_read (apriv, buffer + hdrlen/2, len, BAP0); bap_read (apriv, buffer + hdrlen/2, len, BAP0);
} else { } else {
#ifdef MICSUPPORT
MICBuffer micbuf; MICBuffer micbuf;
#endif
bap_read (apriv, buffer, ETH_ALEN*2, BAP0); bap_read (apriv, buffer, ETH_ALEN*2, BAP0);
#ifdef MICSUPPORT
if (apriv->micstats.enabled) { if (apriv->micstats.enabled) {
bap_read (apriv,(u16*)&micbuf,sizeof(micbuf),BAP0); bap_read (apriv,(u16*)&micbuf,sizeof(micbuf),BAP0);
if (ntohs(micbuf.typelen) > 0x05DC) if (ntohs(micbuf.typelen) > 0x05DC)
bap_setup (apriv, fid, 0x44, BAP0); bap_setup (apriv, fid, 0x44, BAP0);
else { else {
if (len <= sizeof(micbuf))
goto badmic;
len -= sizeof(micbuf); len -= sizeof(micbuf);
if (len < 48)
len = 48;
skb_trim (skb, len + hdrlen); skb_trim (skb, len + hdrlen);
} }
} }
#endif
bap_read(apriv,buffer+ETH_ALEN,len,BAP0); bap_read(apriv,buffer+ETH_ALEN,len,BAP0);
#ifdef MICSUPPORT #ifdef MICSUPPORT
if (decapsulate(apriv,&micbuf,(etherHead*)buffer,len)) { if (decapsulate(apriv,&micbuf,(etherHead*)buffer,len)) {
badmic:
dev_kfree_skb_irq (skb); dev_kfree_skb_irq (skb);
len = 0; badrx:
OUT4500( apriv, EVACK, EV_RX);
goto exitrx;
} }
#endif #endif
} }
}
if (len) {
#if WIRELESS_EXT > 15 #if WIRELESS_EXT > 15
#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ #ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */
if (apriv->spy_data.spy_number > 0) { if (apriv->spy_data.spy_number > 0) {
...@@ -2262,9 +2735,8 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) ...@@ -2262,9 +2735,8 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
skb->ip_summed = CHECKSUM_NONE; skb->ip_summed = CHECKSUM_NONE;
netif_rx( skb ); netif_rx( skb );
} else
OUT4500( apriv, EVACK, EV_RX);
} }
exitrx:
/* Check to see if a packet has been transmitted */ /* Check to see if a packet has been transmitted */
if ( status & ( EV_TX|EV_TXEXC ) ) { if ( status & ( EV_TX|EV_TXEXC ) ) {
...@@ -2469,6 +2941,9 @@ static u16 setup_card(struct airo_info *ai, u8 *mac) ...@@ -2469,6 +2941,9 @@ static u16 setup_card(struct airo_info *ai, u8 *mac)
printk(KERN_WARNING "airo: unknown received signal level scale\n"); printk(KERN_WARNING "airo: unknown received signal level scale\n");
} }
ai->config.opmode = adhoc ? MODE_STA_IBSS : MODE_STA_ESS; ai->config.opmode = adhoc ? MODE_STA_IBSS : MODE_STA_ESS;
ai->config.authType = AUTH_OPEN;
ai->config.modulation = MOD_CCK;
ai->config._reserved1a[0] = 2; /* ??? */
#ifdef MICSUPPORT #ifdef MICSUPPORT
if ((cap_rid.len>=sizeof(cap_rid)) && (cap_rid.extSoftCap&1) && if ((cap_rid.len>=sizeof(cap_rid)) && (cap_rid.extSoftCap&1) &&
...@@ -2515,6 +2990,7 @@ static u16 setup_card(struct airo_info *ai, u8 *mac) ...@@ -2515,6 +2990,7 @@ static u16 setup_card(struct airo_info *ai, u8 *mac)
memcpy(mySsid.ssids[i].ssid, ssids[i], memcpy(mySsid.ssids[i].ssid, ssids[i],
mySsid.ssids[i].len); mySsid.ssids[i].len);
} }
mySsid.len = sizeof(mySsid);
} }
status = writeConfigRid(ai, 1); status = writeConfigRid(ai, 1);
...@@ -3692,6 +4168,8 @@ static void proc_SSID_on_close( struct inode *inode, struct file *file ) { ...@@ -3692,6 +4168,8 @@ static void proc_SSID_on_close( struct inode *inode, struct file *file ) {
offset < data->writelen ) offset++; offset < data->writelen ) offset++;
offset++; offset++;
} }
if (i)
SSID_rid.len = sizeof(SSID_rid);
disable_MAC(ai, 1); disable_MAC(ai, 1);
writeSsidRid(ai, &SSID_rid); writeSsidRid(ai, &SSID_rid);
enable_MAC(ai, &rsp, 1); enable_MAC(ai, &rsp, 1);
...@@ -4260,6 +4738,7 @@ static int airo_set_freq(struct net_device *dev, ...@@ -4260,6 +4738,7 @@ static int airo_set_freq(struct net_device *dev,
printk(KERN_DEBUG "%s: New channel value of %d is invalid!\n", dev->name, fwrq->m); printk(KERN_DEBUG "%s: New channel value of %d is invalid!\n", dev->name, fwrq->m);
rc = -EINVAL; rc = -EINVAL;
} else { } else {
readConfigRid(local, 1);
/* Yes ! We can set it !!! */ /* Yes ! We can set it !!! */
local->config.channelSet = (u16)(channel - 1); local->config.channelSet = (u16)(channel - 1);
local->need_commit = 1; local->need_commit = 1;
...@@ -4280,6 +4759,7 @@ static int airo_get_freq(struct net_device *dev, ...@@ -4280,6 +4759,7 @@ static int airo_get_freq(struct net_device *dev,
struct airo_info *local = dev->priv; struct airo_info *local = dev->priv;
StatusRid status_rid; /* Card status info */ StatusRid status_rid; /* Card status info */
readConfigRid(local, 1);
if ((local->config.opmode & 0xFF) == MODE_STA_ESS) if ((local->config.opmode & 0xFF) == MODE_STA_ESS)
status_rid.channel = local->config.channelSet; status_rid.channel = local->config.channelSet;
else else
...@@ -4336,6 +4816,7 @@ static int airo_set_essid(struct net_device *dev, ...@@ -4336,6 +4816,7 @@ static int airo_set_essid(struct net_device *dev,
sizeof(SSID_rid.ssids[index].ssid)); sizeof(SSID_rid.ssids[index].ssid));
memcpy(SSID_rid.ssids[index].ssid, extra, dwrq->length); memcpy(SSID_rid.ssids[index].ssid, extra, dwrq->length);
SSID_rid.ssids[index].len = dwrq->length - 1; SSID_rid.ssids[index].len = dwrq->length - 1;
SSID_rid.len = sizeof(SSID_rid);
} }
/* Write it to the card */ /* Write it to the card */
disable_MAC(local, 1); disable_MAC(local, 1);
...@@ -4445,6 +4926,7 @@ static int airo_set_nick(struct net_device *dev, ...@@ -4445,6 +4926,7 @@ static int airo_set_nick(struct net_device *dev,
if(dwrq->length > 16 + 1) { if(dwrq->length > 16 + 1) {
return -E2BIG; return -E2BIG;
} }
readConfigRid(local, 1);
memset(local->config.nodeName, 0, sizeof(local->config.nodeName)); memset(local->config.nodeName, 0, sizeof(local->config.nodeName));
memcpy(local->config.nodeName, extra, dwrq->length); memcpy(local->config.nodeName, extra, dwrq->length);
local->need_commit = 1; local->need_commit = 1;
...@@ -4463,6 +4945,7 @@ static int airo_get_nick(struct net_device *dev, ...@@ -4463,6 +4945,7 @@ static int airo_get_nick(struct net_device *dev,
{ {
struct airo_info *local = dev->priv; struct airo_info *local = dev->priv;
readConfigRid(local, 1);
strncpy(extra, local->config.nodeName, 16); strncpy(extra, local->config.nodeName, 16);
extra[16] = '\0'; extra[16] = '\0';
dwrq->length = strlen(extra) + 1; dwrq->length = strlen(extra) + 1;
...@@ -4519,6 +5002,7 @@ static int airo_set_rate(struct net_device *dev, ...@@ -4519,6 +5002,7 @@ static int airo_set_rate(struct net_device *dev,
return -EINVAL; return -EINVAL;
} }
readConfigRid(local, 1);
/* Now, check if we want a fixed or auto value */ /* Now, check if we want a fixed or auto value */
if(vwrq->fixed == 0) { if(vwrq->fixed == 0) {
/* Fill all the rates up to this max rate */ /* Fill all the rates up to this max rate */
...@@ -4555,6 +5039,7 @@ static int airo_get_rate(struct net_device *dev, ...@@ -4555,6 +5039,7 @@ static int airo_get_rate(struct net_device *dev,
vwrq->value = status_rid.currentXmitRate * 500000; vwrq->value = status_rid.currentXmitRate * 500000;
/* If more than one rate, set auto */ /* If more than one rate, set auto */
readConfigRid(local, 1);
vwrq->fixed = (local->config.rates[1] == 0); vwrq->fixed = (local->config.rates[1] == 0);
return 0; return 0;
...@@ -4577,6 +5062,7 @@ static int airo_set_rts(struct net_device *dev, ...@@ -4577,6 +5062,7 @@ static int airo_set_rts(struct net_device *dev,
if((rthr < 0) || (rthr > 2312)) { if((rthr < 0) || (rthr > 2312)) {
return -EINVAL; return -EINVAL;
} }
readConfigRid(local, 1);
local->config.rtsThres = rthr; local->config.rtsThres = rthr;
local->need_commit = 1; local->need_commit = 1;
...@@ -4594,6 +5080,7 @@ static int airo_get_rts(struct net_device *dev, ...@@ -4594,6 +5080,7 @@ static int airo_get_rts(struct net_device *dev,
{ {
struct airo_info *local = dev->priv; struct airo_info *local = dev->priv;
readConfigRid(local, 1);
vwrq->value = local->config.rtsThres; vwrq->value = local->config.rtsThres;
vwrq->disabled = (vwrq->value >= 2312); vwrq->disabled = (vwrq->value >= 2312);
vwrq->fixed = 1; vwrq->fixed = 1;
...@@ -4619,6 +5106,7 @@ static int airo_set_frag(struct net_device *dev, ...@@ -4619,6 +5106,7 @@ static int airo_set_frag(struct net_device *dev,
return -EINVAL; return -EINVAL;
} }
fthr &= ~0x1; /* Get an even value - is it really needed ??? */ fthr &= ~0x1; /* Get an even value - is it really needed ??? */
readConfigRid(local, 1);
local->config.fragThresh = (u16)fthr; local->config.fragThresh = (u16)fthr;
local->need_commit = 1; local->need_commit = 1;
...@@ -4636,6 +5124,7 @@ static int airo_get_frag(struct net_device *dev, ...@@ -4636,6 +5124,7 @@ static int airo_get_frag(struct net_device *dev,
{ {
struct airo_info *local = dev->priv; struct airo_info *local = dev->priv;
readConfigRid(local, 1);
vwrq->value = local->config.fragThresh; vwrq->value = local->config.fragThresh;
vwrq->disabled = (vwrq->value >= 2312); vwrq->disabled = (vwrq->value >= 2312);
vwrq->fixed = 1; vwrq->fixed = 1;
...@@ -4655,6 +5144,7 @@ static int airo_set_mode(struct net_device *dev, ...@@ -4655,6 +5144,7 @@ static int airo_set_mode(struct net_device *dev,
struct airo_info *local = dev->priv; struct airo_info *local = dev->priv;
int commit = 1; int commit = 1;
readConfigRid(local, 1);
if ((local->config.rmode & 0xff) >= RXMODE_RFMON) if ((local->config.rmode & 0xff) >= RXMODE_RFMON)
commit = 2; commit = 2;
...@@ -4714,6 +5204,7 @@ static int airo_get_mode(struct net_device *dev, ...@@ -4714,6 +5204,7 @@ static int airo_get_mode(struct net_device *dev,
{ {
struct airo_info *local = dev->priv; struct airo_info *local = dev->priv;
readConfigRid(local, 1);
/* If not managed, assume it's ad-hoc */ /* If not managed, assume it's ad-hoc */
switch (local->config.opmode & 0xFF) { switch (local->config.opmode & 0xFF) {
case MODE_STA_ESS: case MODE_STA_ESS:
...@@ -4750,6 +5241,7 @@ static int airo_set_encode(struct net_device *dev, ...@@ -4750,6 +5241,7 @@ static int airo_set_encode(struct net_device *dev,
if(!(cap_rid.softCap & 2)) { if(!(cap_rid.softCap & 2)) {
return -EOPNOTSUPP; return -EOPNOTSUPP;
} */ } */
readConfigRid(local, 1);
/* Basic checking: do we have a key to set ? /* Basic checking: do we have a key to set ?
* Note : with the new API, it's impossible to get a NULL pointer. * Note : with the new API, it's impossible to get a NULL pointer.
...@@ -4836,6 +5328,7 @@ static int airo_get_encode(struct net_device *dev, ...@@ -4836,6 +5328,7 @@ static int airo_get_encode(struct net_device *dev,
if(!(cap_rid.softCap & 2)) { if(!(cap_rid.softCap & 2)) {
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
readConfigRid(local, 1);
/* Check encryption mode */ /* Check encryption mode */
switch(local->config.authType) { switch(local->config.authType) {
case AUTH_ENCRYPT: case AUTH_ENCRYPT:
...@@ -4892,6 +5385,7 @@ static int airo_set_txpow(struct net_device *dev, ...@@ -4892,6 +5385,7 @@ static int airo_set_txpow(struct net_device *dev,
clear_bit (FLAG_RADIO_OFF, &local->flags); clear_bit (FLAG_RADIO_OFF, &local->flags);
for (i = 0; cap_rid.txPowerLevels[i] && (i < 8); i++) for (i = 0; cap_rid.txPowerLevels[i] && (i < 8); i++)
if ((vwrq->value==cap_rid.txPowerLevels[i])) { if ((vwrq->value==cap_rid.txPowerLevels[i])) {
readConfigRid(local, 1);
local->config.txPower = vwrq->value; local->config.txPower = vwrq->value;
local->need_commit = 1; local->need_commit = 1;
rc = -EINPROGRESS; /* Call commit handler */ rc = -EINPROGRESS; /* Call commit handler */
...@@ -4911,6 +5405,7 @@ static int airo_get_txpow(struct net_device *dev, ...@@ -4911,6 +5405,7 @@ static int airo_get_txpow(struct net_device *dev,
{ {
struct airo_info *local = dev->priv; struct airo_info *local = dev->priv;
readConfigRid(local, 1);
vwrq->value = local->config.txPower; vwrq->value = local->config.txPower;
vwrq->fixed = 1; /* No power control */ vwrq->fixed = 1; /* No power control */
vwrq->disabled = test_bit(FLAG_RADIO_OFF, &local->flags); vwrq->disabled = test_bit(FLAG_RADIO_OFF, &local->flags);
...@@ -4934,6 +5429,7 @@ static int airo_set_retry(struct net_device *dev, ...@@ -4934,6 +5429,7 @@ static int airo_set_retry(struct net_device *dev,
if(vwrq->disabled) { if(vwrq->disabled) {
return -EINVAL; return -EINVAL;
} }
readConfigRid(local, 1);
if(vwrq->flags & IW_RETRY_LIMIT) { if(vwrq->flags & IW_RETRY_LIMIT) {
if(vwrq->flags & IW_RETRY_MAX) if(vwrq->flags & IW_RETRY_MAX)
local->config.longRetryLimit = vwrq->value; local->config.longRetryLimit = vwrq->value;
...@@ -4968,6 +5464,7 @@ static int airo_get_retry(struct net_device *dev, ...@@ -4968,6 +5464,7 @@ static int airo_get_retry(struct net_device *dev,
vwrq->disabled = 0; /* Can't be disabled */ vwrq->disabled = 0; /* Can't be disabled */
readConfigRid(local, 1);
/* Note : by default, display the min retry number */ /* Note : by default, display the min retry number */
if((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { if((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
vwrq->flags = IW_RETRY_LIFETIME; vwrq->flags = IW_RETRY_LIFETIME;
...@@ -5106,6 +5603,7 @@ static int airo_set_power(struct net_device *dev, ...@@ -5106,6 +5603,7 @@ static int airo_set_power(struct net_device *dev,
{ {
struct airo_info *local = dev->priv; struct airo_info *local = dev->priv;
readConfigRid(local, 1);
if (vwrq->disabled) { if (vwrq->disabled) {
if ((local->config.rmode & 0xFF) >= RXMODE_RFMON) { if ((local->config.rmode & 0xFF) >= RXMODE_RFMON) {
return -EINVAL; return -EINVAL;
...@@ -5162,6 +5660,7 @@ static int airo_get_power(struct net_device *dev, ...@@ -5162,6 +5660,7 @@ static int airo_get_power(struct net_device *dev,
{ {
struct airo_info *local = dev->priv; struct airo_info *local = dev->priv;
readConfigRid(local, 1);
int mode = local->config.powerSaveMode; int mode = local->config.powerSaveMode;
if ((vwrq->disabled = (mode == POWERSAVE_CAM))) if ((vwrq->disabled = (mode == POWERSAVE_CAM)))
return 0; return 0;
...@@ -5191,6 +5690,7 @@ static int airo_set_sens(struct net_device *dev, ...@@ -5191,6 +5690,7 @@ static int airo_set_sens(struct net_device *dev,
{ {
struct airo_info *local = dev->priv; struct airo_info *local = dev->priv;
readConfigRid(local, 1);
local->config.rssiThreshold = vwrq->disabled ? RSSI_DEFAULT : vwrq->value; local->config.rssiThreshold = vwrq->disabled ? RSSI_DEFAULT : vwrq->value;
local->need_commit = 1; local->need_commit = 1;
...@@ -5208,6 +5708,7 @@ static int airo_get_sens(struct net_device *dev, ...@@ -5208,6 +5708,7 @@ static int airo_get_sens(struct net_device *dev,
{ {
struct airo_info *local = dev->priv; struct airo_info *local = dev->priv;
readConfigRid(local, 1);
vwrq->value = local->config.rssiThreshold; vwrq->value = local->config.rssiThreshold;
vwrq->disabled = (vwrq->value == 0); vwrq->disabled = (vwrq->value == 0);
vwrq->fixed = 1; vwrq->fixed = 1;
...@@ -6017,7 +6518,7 @@ static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ...@@ -6017,7 +6518,7 @@ static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
/* Separate R/W functions bracket legality here /* Separate R/W functions bracket legality here
*/ */
if ( com.command <= AIROGMICSTATS ) if ( com.command <= AIRORRID )
rc = readrids(dev,&com); rc = readrids(dev,&com);
else if ( com.command >= AIROPCAP && com.command <= AIROPLEAPUSR ) else if ( com.command >= AIROPCAP && com.command <= AIROPLEAPUSR )
rc = writerids(dev,&com); rc = writerids(dev,&com);
...@@ -6107,6 +6608,7 @@ struct iw_statistics *airo_get_wireless_stats(struct net_device *dev) ...@@ -6107,6 +6608,7 @@ struct iw_statistics *airo_get_wireless_stats(struct net_device *dev)
static int readrids(struct net_device *dev, aironet_ioctl *comp) { static int readrids(struct net_device *dev, aironet_ioctl *comp) {
unsigned short ridcode; unsigned short ridcode;
unsigned char *iobuf; unsigned char *iobuf;
int len;
struct airo_info *ai = dev->priv; struct airo_info *ai = dev->priv;
if (test_bit(FLAG_FLASHING, &ai->flags)) if (test_bit(FLAG_FLASHING, &ai->flags))
...@@ -6134,11 +6636,14 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) { ...@@ -6134,11 +6636,14 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) {
case AIROGSTAT: ridcode = RID_STATUS; break; case AIROGSTAT: ridcode = RID_STATUS; break;
case AIROGSTATSD32: ridcode = RID_STATSDELTA; break; case AIROGSTATSD32: ridcode = RID_STATSDELTA; break;
case AIROGSTATSC32: ridcode = RID_STATS; break; case AIROGSTATSC32: ridcode = RID_STATS; break;
#ifdef MICSUPPORT
case AIROGMICSTATS: case AIROGMICSTATS:
if (copy_to_user(comp->data, &ai->micstats, if (copy_to_user(comp->data, &ai->micstats,
min((int)comp->len,(int)sizeof(ai->micstats)))) min((int)comp->len,(int)sizeof(ai->micstats))))
return -EFAULT; return -EFAULT;
return 0; return 0;
#endif
case AIRORRID: ridcode = comp->len; break;
default: default:
return -EINVAL; return -EINVAL;
break; break;
...@@ -6152,9 +6657,12 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) { ...@@ -6152,9 +6657,12 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) {
* then return it to the user * then return it to the user
* 9/22/2000 Honor user given length * 9/22/2000 Honor user given length
*/ */
if (comp->command == AIRORRID)
len = le16_to_cpu(*(unsigned short *)iobuf); /* Yuck! */
else
len = comp->len;
if (copy_to_user(comp->data, iobuf, if (copy_to_user(comp->data, iobuf, min(len, (int)RIDS_SIZE))) {
min((int)comp->len, (int)RIDS_SIZE))) {
kfree (iobuf); kfree (iobuf);
return -EFAULT; return -EFAULT;
} }
...@@ -6222,9 +6730,11 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) { ...@@ -6222,9 +6730,11 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) {
PC4500_readrid(ai,RID_STATSDELTACLEAR,iobuf,RIDS_SIZE, 1); PC4500_readrid(ai,RID_STATSDELTACLEAR,iobuf,RIDS_SIZE, 1);
#ifdef MICSUPPORT
enabled = ai->micstats.enabled; enabled = ai->micstats.enabled;
memset(&ai->micstats,0,sizeof(ai->micstats)); memset(&ai->micstats,0,sizeof(ai->micstats));
ai->micstats.enabled = enabled; ai->micstats.enabled = enabled;
#endif
if (copy_to_user(comp->data, iobuf, if (copy_to_user(comp->data, iobuf,
min((int)comp->len, (int)RIDS_SIZE))) { min((int)comp->len, (int)RIDS_SIZE))) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment