]> git.neil.brown.name Git - history.git/commitdiff
airo wireless net drvr: add Cisco MIC support
authorJavier Achirica <achirica@ttd.net>
Sat, 28 Sep 2002 16:01:27 +0000 (12:01 -0400)
committerJeff Garzik <jgarzik@mandrakesoft.com>
Sat, 28 Sep 2002 16:01:27 +0000 (12:01 -0400)
Conditionally enabled when out-of-tree, but open source, crypto lib
is present.

drivers/net/wireless/airo.c

index 57c8bfec8d7a5e0354a989da7843aca5df03cca9..ff39b528e64b4b5565fa9aff216249380efb7401 100644 (file)
@@ -80,6 +80,14 @@ static struct pci_driver airo_driver = {
 #include <linux/delay.h>
 #endif
 
+/* Support Cisco MIC feature */
+/* As this feature requires the AES encryption algorithm, it is not included
+   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
+   http://sf.net/projects/airo-linux/ Put the files in the same directory
+   as airo.c and compile normally */
+#undef MICSUPPORT
+
 /* Hack to do some power saving */
 #define POWER_ON_DOWN
 
@@ -276,42 +284,41 @@ static int do8bitIO = 0;
 #define NO_PACKET -2
 
 /* Commands */
-#define NOP2 0x00    
-#define MAC_ENABLE 0x01
-#define MAC_ENABLETX 0x101
-#define CMD_ENABLEAUX 0x111
-#define MAC_ENABLERX 0x201   
-#define MAC_DISABLE 0x02    
-#define CMD_LOSE_SYNC 0x03    
-#define CMD_LOSE_SYNC_BSS 0x103
-#define CMD_SOFTRESET 0x04    
-#define HOSTSLEEP 0x05    
-#define CMD_MAGICPACKET 0x06
-#define CMD_SETWAKEMASK 0x07
-#define CMD_SAVECONFIG 0x108   
-#define CMD_READCONFIG 0x08
-#define CMD_SETMODE 0x09    
-#define CMD_ALLOCATETX 0x0A
-#define CMD_TRANSMIT 0x0B    
-#define CMD_DEALLOC 0x0C
-#define CMD_LISTBSS 0x103
-#define NOP 0x10    
-#define CMD_WORKAROUND 0x11
-#define CMD_ACCESS 0x21
-#define CMD_WRITERID 0x121
-#define CMD_PCIBAP 0x22
-#define CMD_PCIAUX 0x23
-#define CMD_ALLOCTLV 0x28
-#define CMD_GETTLV 0x29
-#define CMD_PUTTLV 0x2A
-#define CMD_DELTLV 0x2B    
-#define CMD_FINDNEXTTLV 0x2C    
-#define CMD_SETPHYREG 0x3E
-#define CMD_TXTEST 0x3F    
-#define CMD_NOPSPNODES 0x30    
-#define CMD_USEPSPNODES 0x130
-#define CMD_SETCW 0x31    
-#define CMD_SETPCF 0x32    
+#define NOP2           0x0000
+#define MAC_ENABLE     0x0001
+#define MAC_DISABLE    0x0002
+#define CMD_LOSE_SYNC  0x0003 /* Not sure what this does... */
+#define CMD_SOFTRESET  0x0004
+#define HOSTSLEEP      0x0005
+#define CMD_MAGIC_PKT  0x0006
+#define CMD_SETWAKEMASK        0x0007
+#define CMD_READCFG    0x0008
+#define CMD_SETMODE    0x0009
+#define CMD_ALLOCATETX 0x000a
+#define CMD_TRANSMIT   0x000b
+#define CMD_DEALLOCATETX 0x000c
+#define NOP            0x0010
+#define CMD_WORKAROUND 0x0011
+#define CMD_ACCESS     0x0021
+#define CMD_PCIBAP     0x0022
+#define CMD_PCIAUX     0x0023
+#define CMD_ALLOCBUF   0x0028
+#define CMD_GETTLV     0x0029
+#define CMD_PUTTLV     0x002a
+#define CMD_DELTLV     0x002b
+#define CMD_FINDNEXTTLV        0x002c
+#define CMD_PSPNODES   0x0030
+#define CMD_SETCW      0x0031    
+#define CMD_SETPCF     0x0032    
+#define CMD_SETPHYREG  0x003e
+#define CMD_TXTEST     0x003f
+#define MAC_ENABLETX   0x0101
+#define CMD_LISTBSS    0x0103
+#define CMD_SAVECFG    0x0108
+#define CMD_ENABLEAUX  0x0111
+#define CMD_WRITERID   0x0121
+#define CMD_USEPSPNODES        0x0130
+#define MAC_ENABLERX   0x0201
 
 /* Command errors */
 #define ERROR_QUALIF 0x00
@@ -398,10 +405,10 @@ static int do8bitIO = 0;
 #define EV_AWAKE 0x100
 #define EV_UNKNOWN 0x800
 #define EV_MIC 0x1000 /* Message Integrity Check Interrupt */
-#define STATUS_INTS ( EV_AWAKE | EV_LINK | EV_TXEXC | EV_TX | EV_RX)
+#define STATUS_INTS ( EV_AWAKE | EV_LINK | EV_TXEXC | EV_TX | EV_RX | EV_MIC )
 
 #ifdef CHECK_UNKNOWN_INTS
-#define IGNORE_INTS ( EV_MIC | EV_CMD | EV_UNKNOWN)
+#define IGNORE_INTS ( EV_CMD | EV_UNKNOWN)
 #else
 #define IGNORE_INTS (~STATUS_INTS)
 #endif
@@ -433,6 +440,7 @@ static int do8bitIO = 0;
 #define RID_UNKNOWN54  0xFF54
 #define RID_UNKNOWN55  0xFF55
 #define RID_UNKNOWN56  0xFF56
+#define RID_MIC        0xFF57
 #define RID_STATS16    0xFF60
 #define RID_STATS16DELTA 0xFF61
 #define RID_STATS16DELTACLEAR 0xFF62
@@ -511,6 +519,7 @@ typedef struct {
 #define MODE_ETHER_LLC (1<<12) /* enable ethernet LLC */
 #define MODE_LEAF_NODE (1<<13) /* enable leaf node bridge */
 #define MODE_CF_POLLABLE (1<<14) /* enable CF pollable */
+#define MODE_MIC (1<<15) /* enable MIC */
        u16 rmode; /* receive mode */
 #define RXMODE_BC_MC_ADDR 0
 #define RXMODE_BC_ADDR 1 /* ignore multicasts */
@@ -682,6 +691,7 @@ typedef struct {
        u16 softCap;
        u16 bootBlockVer;
        u16 requiredHard;
+       u16 extSoftCap;
 } CapabilityRid;
 
 typedef struct {
@@ -724,6 +734,37 @@ typedef struct {
   tdsRssiEntry x[256];
 } tdsRssiRid;
 
+typedef struct {
+       u16 len;
+       u16 state;
+       u16 multicastValid;
+       u8  multicast[16];
+       u16 unicastValid;
+       u8  unicast[16];
+} MICRid;
+
+typedef struct {
+       u16 typelen;
+
+       union {
+           u8 snap[8];
+           struct {
+               u8 dsap;
+               u8 ssap;
+               u8 control;
+               u8 orgcode[3];
+               u8 fieldtype[2];
+           } llc;
+       } u;
+       u32 mic;
+       u32 seq;
+} MICBuffer;
+
+typedef struct {
+       u8 da[ETH_ALEN];
+       u8 sa[ETH_ALEN];
+} etherHead;
+
 #pragma pack()
 
 #define TXCTL_TXOK (1<<1) /* report if tx is ok */
@@ -768,10 +809,13 @@ typedef struct {
 #define AIROGSTAT              8
 #define AIROGSTATSC32          9
 #define AIROGSTATSD32          10
+#define AIROGMICRID            11
+#define AIROGMICSTATS          12
+#define AIROGFLAGS             13
 
 /* Leave gap of 40 commands after AIROGSTATSD32 for future */
 
-#define AIROPCAP               AIROGSTATSD32 + 40
+#define AIROPCAP                       AIROGSTATSD32 + 40
 #define AIROPVLIST              AIROPCAP      + 1
 #define AIROPSLIST             AIROPVLIST    + 1
 #define AIROPCFG               AIROPSLIST    + 1
@@ -803,6 +847,45 @@ typedef struct aironet_ioctl {
 } aironet_ioctl;
 #endif /* CISCO_EXT */
 
+#define NUM_MODULES       2
+#define MIC_MSGLEN_MAX    2400
+#define EMMH32_MSGLEN_MAX MIC_MSGLEN_MAX
+
+typedef struct {
+       u32   size;            // size
+       u8    enabled;         // MIC enabled or not
+       u32   rxSuccess;       // successful packets received
+       u32   rxIncorrectMIC;  // pkts dropped due to incorrect MIC comparison
+       u32   rxNotMICed;      // pkts dropped due to not being MIC'd
+       u32   rxMICPlummed;    // pkts dropped due to not having a MIC plummed
+       u32   rxWrongSequence; // pkts dropped due to sequence number violation
+       u32   reserve[32];
+} mic_statistics;
+
+typedef struct {
+       u32 coeff[((EMMH32_MSGLEN_MAX)+3)>>2];
+       u64 accum;      // accumulated mic, reduced to u32 in final()
+       int position;   // current position (byte offset) in message
+       union {
+               u8  d8[4];
+               u32 d32;
+       } part; // saves partial message word across update() calls
+} emmh32_context;
+
+typedef struct {
+       emmh32_context seed;        // Context - the seed
+       u32              rx;        // Received sequence number
+       u32              tx;        // Tx sequence number
+       u32              window;    // Start of window
+       u8               valid;     // Flag to say if context is valid or not
+       u8               key[16];
+} miccntx;
+
+typedef struct {
+       miccntx mCtx;           // Multicast context
+       miccntx uCtx;           // Unicast context
+} mic_module;
+
 #ifdef WIRELESS_EXT
 // Frequency list (map channels to frequencies)
 const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442,
@@ -832,7 +915,7 @@ struct iw_request_info {};
 #endif /* WIRELESS_EXT > 12 */
 #endif /* WIRELESS_EXT */
 
-static const char version[] = "airo.c 0.5 (Ben Reed & Javier Achirica)";
+static const char version[] = "airo.c 0.6 (Ben Reed & Javier Achirica)";
 
 struct airo_info;
 
@@ -875,6 +958,12 @@ 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 MICSUPPORT
+static 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);
+#endif
 
 struct airo_info {
        struct net_device_stats stats;
@@ -899,6 +988,10 @@ struct airo_info {
 #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);
@@ -923,6 +1016,10 @@ struct airo_info {
        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,
@@ -935,6 +1032,10 @@ static int setup_proc_entry( struct net_device *dev,
 static int takedown_proc_entry( struct net_device *dev,
                                struct airo_info *apriv );
 
+#ifdef MICSUPPORT
+#include "mic.h"
+#endif
+
 static int readBSSListRid(struct airo_info *ai, int first,
                      BSSListRid *list) {
        int rc;
@@ -1065,6 +1166,11 @@ static int writeConfigRid(struct airo_info*ai) {
 
        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);
@@ -1713,6 +1819,24 @@ static void airo_send_event(struct net_device *dev) {
 }
 #endif
 
+static void airo_read_mic(struct airo_info *ai) {
+       MICRid mic_rid;
+
+       if (down_trylock(&ai->sem) == 0) {
+               __set_bit(FLAG_LOCKED, &ai->flags);
+               PC4500_readrid(ai, RID_MIC, &mic_rid, sizeof(mic_rid));
+               clear_bit(FLAG_LOCKED, &ai->flags);
+               up(&ai->sem);
+#ifdef MICSUPPORT
+               micinit (ai, &mic_rid);
+#endif
+       } else {
+               ai->mic_task.routine = (void (*)(void *))airo_read_mic;
+               ai->mic_task.data = (void *)ai;
+               schedule_task(&ai->mic_task);
+       }
+}
+
 static void airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) {
        struct net_device *dev = (struct net_device *)dev_id;
        u16 status;
@@ -1737,6 +1861,10 @@ static void airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) {
                        OUT4500( apriv, EVINTEN, 0 );
                }
 
+               if ( status & EV_MIC ) {
+                       OUT4500( apriv, EVACK, EV_MIC );
+                       airo_read_mic( apriv );
+               }
                if ( status & EV_LINK ) {
 #if WIRELESS_EXT > 13
                        union iwreq_data        wrqu;
@@ -1785,6 +1913,7 @@ static void airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) {
                                struct task_struct *task = apriv->task;
                                if (task)
                                        wake_up_process (task);
+                               apriv->flags|=FLAG_UPDATE_UNI|FLAG_UPDATE_MULTI;
                        }
 #if WIRELESS_EXT > 13
                        /* Question : is ASSOCIATED the only status
@@ -1902,7 +2031,26 @@ static void airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) {
 
                                        bap_read (apriv, buffer + hdrlen/2, len, BAP0);
                                } else {
-                                       bap_read (apriv, buffer,len + hdrlen,BAP0);
+                                       MICBuffer micbuf;
+                                       bap_read (apriv, buffer, ETH_ALEN*2, BAP0);
+                                       if (apriv->micstats.enabled) {
+                                               bap_read (apriv,(u16*)&micbuf,sizeof(micbuf),BAP0);
+                                               if (ntohs(micbuf.typelen) > 0x05DC)
+                                                       bap_setup (apriv, fid, 0x44, BAP0);
+                                               else {
+                                                       len -= sizeof(micbuf);
+                                                       if (len < 48)
+                                                               len = 48;
+                                                       skb_trim (skb, len + hdrlen);
+                                               }
+                                       }
+                                       bap_read(apriv,buffer+ETH_ALEN,len,BAP0);
+#ifdef MICSUPPORT
+                                       if (decapsulate(apriv,&micbuf,(etherHead*)buffer,len)) {
+                                               dev_kfree_skb_irq (skb);
+                                               len = 0;
+                                       }
+#endif
                                }
                        }
                        if (len) {
@@ -2122,30 +2270,40 @@ static u16 setup_card(struct airo_info *ai, u8 *mac)
        up(&ai->sem);
        if (ai->config.len == 0) {
                tdsRssiRid rssi_rid;
+               CapabilityRid cap_rid;
 
                // general configuration (read/modify/write)
                status = readConfigRid(ai);
                if ( status != SUCCESS ) return ERROR;
 
+               status = readCapabilityRid(ai, &cap_rid);
+               if ( status != SUCCESS ) return ERROR;
+
                status = PC4500_readrid(ai,RID_RSSI,&rssi_rid,sizeof(rssi_rid));
                if ( status == SUCCESS ) {
                        if (ai->rssi || (ai->rssi = kmalloc(512, GFP_KERNEL)) != NULL)
                                memcpy(ai->rssi, (u8*)&rssi_rid + 2, 512);
                }
                else {
-                       CapabilityRid cap_rid;
                        if (ai->rssi) {
                                kfree(ai->rssi);
                                ai->rssi = NULL;
                        }
-                       status = readCapabilityRid(ai, &cap_rid);
-                       if ((status == SUCCESS) && (cap_rid.softCap & 8))
+                       if (cap_rid.softCap & 8)
                                ai->config.rmode |= RXMODE_NORMALIZED_RSSI;
                        else
                                printk(KERN_WARNING "airo: unknown received signal level scale\n");
                }
                ai->config.opmode = adhoc ? MODE_STA_IBSS : MODE_STA_ESS;
 
+#ifdef MICSUPPORT
+               if ((cap_rid.len==sizeof(cap_rid)) && (cap_rid.extSoftCap&1)) {
+                       ai->config.opmode |= MODE_MIC;
+                       ai->flags |= FLAG_MIC_CAPABLE;
+                       micsetup(ai);
+               }
+#endif
+
                /* Save off the MAC */
                for( i = 0; i < ETH_ALEN; i++ ) {
                        mac[i] = ai->config.macAddr[i];
@@ -2170,8 +2328,6 @@ static u16 setup_card(struct airo_info *ai, u8 *mac)
                                }
                        }
                }
-               if (auto_wep)
-                       ai->config.authType = AUTH_SHAREDKEY;
                ai->need_commit = 1;
        }
 
@@ -2539,22 +2695,38 @@ static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket)
        u16 payloadLen;
        Cmd cmd;
        Resp rsp;
+       int miclen = 0;
        u16 txFid = len;
+       MICBuffer pMic;
+
        len >>= 16;
 
        if (len < ETH_ALEN * 2) {
                printk( KERN_WARNING "Short packet %d\n", len );
                return ERROR;
        }
+       len -= ETH_ALEN * 2;
+
+#ifdef MICSUPPORT
+       if ((ai->flags & FLAG_MIC_CAPABLE) && ai->micstats.enabled && 
+           (ntohs(((u16 *)pPacket)[6]) != 0x888E)) {
+               if (encapsulate(ai,(etherHead *)pPacket,&pMic,len) != SUCCESS)
+                       return ERROR;
+               miclen = sizeof(pMic);
+       }
+#endif
 
        // packet is destination[6], source[6], payload[len-12]
        // write the payload length and dst/src/payload
        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-12);
+       payloadLen = cpu_to_le16(len + miclen);
        bap_write(ai, &payloadLen, sizeof(payloadLen),BAP1);
-       bap_write(ai, (const u16*)pPacket, len, BAP1);
+       bap_write(ai, (const u16*)pPacket, sizeof(etherHead), BAP1);
+       if (miclen)
+               bap_write(ai, (const u16*)&pMic, miclen, BAP1);
+       bap_write(ai, (const u16*)(pPacket + sizeof(etherHead)), len, BAP1);
        // issue the transmit command
        memset( &cmd, 0, sizeof( cmd ) );
        cmd.cmd = CMD_TRANSMIT;
@@ -3037,10 +3209,11 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
                                        need_reset = 1;
                        ai->config.rmode &= 0xfe00;
                        ai->flags &= ~FLAG_802_11;
+                       ai->config.opmode &= 0xFF00;
                        if ( line[0] == 'a' ) {
-                               ai->config.opmode = 0;
+                               ai->config.opmode |= 0;
                        } else {
-                               ai->config.opmode = 1;
+                               ai->config.opmode |= 1;
                                if ( line[0] == 'r' ) {
                                        ai->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER;
                                        ai->flags |= FLAG_802_11;
@@ -3274,10 +3447,10 @@ static int proc_config_open( struct inode *inode, struct file *file ) {
                     "DataRates: %d %d %d %d %d %d %d %d\n"
                     "Channel: %d\n"
                     "XmitPower: %d\n",
-                    ai->config.opmode == 0 ? "adhoc" :
-                    ai->config.opmode == 1 ? get_rmode(ai->config.rmode):
-                    ai->config.opmode == 2 ? "AP" :
-                    ai->config.opmode == 3 ? "AP RPTR" : "Error",
+                    (ai->config.opmode & 0xFF) == 0 ? "adhoc" :
+                    (ai->config.opmode & 0xFF) == 1 ? get_rmode(ai->config.rmode):
+                    (ai->config.opmode & 0xFF) == 2 ? "AP" :
+                    (ai->config.opmode & 0xFF) == 3 ? "AP RPTR" : "Error",
                     ai->flags&FLAG_RADIO_OFF ? "off" : "on",
                     ai->config.nodeName,
                     ai->config.powerSaveMode == 0 ? "CAM" :
@@ -4335,16 +4508,20 @@ static int airo_set_mode(struct net_device *dev,
 
        switch(*uwrq) {
                case IW_MODE_ADHOC:
-                       local->config.opmode = MODE_STA_IBSS;
+                       local->config.opmode &= 0xFF00;
+                       local->config.opmode |= MODE_STA_IBSS;
                        break;
                case IW_MODE_INFRA:
-                       local->config.opmode = MODE_STA_ESS;
+                       local->config.opmode &= 0xFF00;
+                       local->config.opmode |= MODE_STA_ESS;
                        break;
                case IW_MODE_MASTER:
-                       local->config.opmode = MODE_AP;
+                       local->config.opmode &= 0xFF00;
+                       local->config.opmode |= MODE_AP;
                        break;
                case IW_MODE_REPEAT:
-                       local->config.opmode = MODE_AP_RPTR;
+                       local->config.opmode &= 0xFF00;
+                       local->config.opmode |= MODE_AP_RPTR;
                        break;
                default:
                        return -EINVAL;
@@ -5637,7 +5814,7 @@ static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 
                /* Seperate R/W functions bracket legality here
                 */
-               if ( com.command <= AIROGSTATSD32 )
+               if ( com.command <= AIROGMICSTATS )
                        rc = readrids(dev,&com);
                else if ( com.command >= AIROPCAP && com.command <= AIROPLEAPUSR )
                        rc = writerids(dev,&com);
@@ -5730,8 +5907,7 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) {
        switch(comp->command)
        {
        case AIROGCAP:      ridcode = RID_CAPABILITIES; break;
-       case AIROGCFG:      ridcode = RID_CONFIG;       break;
-       case AIROPCFG: writeConfigRid ((struct airo_info *)dev->priv);
+       case AIROGCFG: writeConfigRid (ai);
                            ridcode = RID_CONFIG;       break;
        case AIROGSLIST:    ridcode = RID_SSID;         break;
        case AIROGVLIST:    ridcode = RID_APLIST;       break;
@@ -5750,12 +5926,17 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) {
        case AIROGSTAT:     ridcode = RID_STATUS;       break;
        case AIROGSTATSD32: ridcode = RID_STATSDELTA;   break;
        case AIROGSTATSC32: ridcode = RID_STATS;        break;
+       case AIROGMICSTATS:
+               if (copy_to_user(comp->data, &ai->micstats,
+                                min((int)comp->len,(int)sizeof(ai->micstats))))
+                       return -EFAULT;
+               return 0;
        default:
                return -EINVAL;
                break;
        }
 
-       PC4500_readrid((struct airo_info *)dev->priv,ridcode,iobuf,sizeof(iobuf));
+       PC4500_readrid(ai,ridcode,iobuf,sizeof(iobuf));
        /* get the count of bytes in the rid  docs say 1st 2 bytes is it.
         * then return it to the user
         * 9/22/2000 Honor user given length
@@ -5773,7 +5954,7 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) {
 
 static int writerids(struct net_device *dev, aironet_ioctl *comp) {
        struct airo_info *ai = dev->priv;
-       int  ridcode;
+       int  ridcode, enabled;
        Resp      rsp;
        static int (* writer)(struct airo_info *, u16 rid, const void *, int);
        unsigned char iobuf[2048];
@@ -5793,7 +5974,7 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) {
        case AIROPSIDS:     ridcode = RID_SSID;         break;
        case AIROPCAP:      ridcode = RID_CAPABILITIES; break;
        case AIROPAPLIST:   ridcode = RID_APLIST;       break;
-       case AIROPCFG: ((struct airo_info *)dev->priv)->config.len = 0;
+       case AIROPCFG: ai->config.len = 0;
                            ridcode = RID_CONFIG;       break;
        case AIROPWEPKEYNV: ridcode = RID_WEP_PERM;     break;
        case AIROPLEAPUSR:  ridcode = RID_LEAPUSERNAME; break;
@@ -5805,7 +5986,7 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) {
                 * same with MAC off
                 */
        case AIROPMACON:
-               if (enable_MAC(dev->priv, &rsp) != 0)
+               if (enable_MAC(ai, &rsp) != 0)
                        return -EIO;
                return 0;
 
@@ -5814,7 +5995,7 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) {
                 * as disable_MAC. it's probably so short the compiler does not gen one.
                 */
        case AIROPMACOFF:
-               disable_MAC(dev->priv);
+               disable_MAC(ai);
                return 0;
 
                /* This command merely clears the counts does not actually store any data
@@ -5822,9 +6003,11 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) {
                 * writerid routines.
                 */
        case AIROPSTCLR:
-               ridcode = RID_STATSDELTACLEAR;
+               PC4500_readrid(ai,RID_STATSDELTACLEAR,iobuf,sizeof(iobuf));
 
-               PC4500_readrid(dev->priv,ridcode,iobuf,sizeof(iobuf));
+               enabled = ai->micstats.enabled;
+               memset(&ai->micstats,0,sizeof(ai->micstats));
+               ai->micstats.enabled = enabled;
 
                if (copy_to_user(comp->data, iobuf,
                                 min((int)comp->len, (int)sizeof(iobuf))))
@@ -5839,7 +6022,20 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) {
 
        if (copy_from_user(iobuf,comp->data,comp->len))
                return -EFAULT;
-       if((*writer)((struct airo_info *)dev->priv, ridcode, iobuf,comp->len))
+
+       if (comp->command == AIROPCFG) {
+               ConfigRid *cfg = (ConfigRid *)iobuf;
+
+               if (ai->flags & FLAG_MIC_CAPABLE)
+                       cfg->opmode |= MODE_MIC;
+
+               if ((cfg->opmode & 0xFF) == MODE_STA_IBSS)
+                       ai->flags |= FLAG_ADHOC;
+               else
+                       ai->flags &= ~FLAG_ADHOC;
+       }
+
+       if((*writer)(ai, ridcode, iobuf,comp->len))
                return -EIO;
        return 0;
 }