# --------------------------------------------
# 02/09/28	achirica@ttd.net	1.692
# airo wireless net drvr: add Cisco MIC support
# Conditionally enabled when out-of-tree, but open source, crypto lib
# is present.
# --------------------------------------------
#
diff -Nru a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
--- a/drivers/net/wireless/airo.c	Sun Sep 29 19:36:05 2002
+++ b/drivers/net/wireless/airo.c	Sun Sep 29 19:36:05 2002
@@ -80,6 +80,14 @@
 #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
 
@@ -282,42 +290,41 @@
 #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
@@ -404,10 +411,10 @@
 #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
@@ -439,6 +446,7 @@
 #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
@@ -517,6 +525,7 @@
 #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 */
@@ -688,6 +697,7 @@
 	u16 softCap;
 	u16 bootBlockVer;
 	u16 requiredHard;
+	u16 extSoftCap;
 } CapabilityRid;
 
 typedef struct {
@@ -730,6 +740,37 @@
   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 */
@@ -774,10 +815,13 @@
 #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
@@ -809,6 +853,45 @@
 } 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,
@@ -838,7 +921,7 @@
 #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;
 
@@ -881,6 +964,12 @@
 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;
@@ -905,6 +994,10 @@
 #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);
@@ -929,6 +1022,10 @@
 	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,
@@ -941,6 +1038,10 @@
 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;
@@ -1071,6 +1172,11 @@
 
 	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);
@@ -1719,6 +1825,24 @@
 }
 #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;
@@ -1743,6 +1867,10 @@
 			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;
@@ -1791,6 +1919,7 @@
 				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
@@ -1908,7 +2037,26 @@
 
 					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) {
@@ -2128,30 +2276,40 @@
 	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];
@@ -2176,8 +2334,6 @@
 				}
 			}
 		}
-		if (auto_wep)
-			ai->config.authType = AUTH_SHAREDKEY;
 		ai->need_commit = 1;
 	}
 
@@ -2545,22 +2701,38 @@
 	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;
@@ -3043,10 +3215,11 @@
 					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;
@@ -3280,10 +3453,10 @@
 		     "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" :
@@ -4341,16 +4514,20 @@
 
 	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;
@@ -5643,7 +5820,7 @@
 
 		/* 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);
@@ -5736,8 +5913,7 @@
 	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;
@@ -5756,12 +5932,17 @@
 	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
@@ -5779,7 +5960,7 @@
 
 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];
@@ -5799,7 +5980,7 @@
 	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;
@@ -5811,7 +5992,7 @@
 		 * same with MAC off
 		 */
 	case AIROPMACON:
-		if (enable_MAC(dev->priv, &rsp) != 0)
+		if (enable_MAC(ai, &rsp) != 0)
 			return -EIO;
 		return 0;
 
@@ -5820,7 +6001,7 @@
 		 * 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
@@ -5828,9 +6009,11 @@
 		 * 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))))
@@ -5845,7 +6028,20 @@
 
 	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;
 }
