patch-2.4.22 linux-2.4.22/drivers/net/wireless/airo.c

Next file: linux-2.4.22/drivers/net/wireless/airport.c
Previous file: linux-2.4.22/drivers/net/wan/z85230.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.21/drivers/net/wireless/airo.c linux-2.4.22/drivers/net/wireless/airo.c
@@ -97,12 +97,12 @@
    infront of the label, that statistic will not be included in the list
    of statistics in the /proc filesystem */
 
-#define IGNLABEL 0&(int)
+#define IGNLABEL(comment) 0
 static char *statsLabels[] = {
 	"RxOverrun",
-	IGNLABEL "RxPlcpCrcErr",
-	IGNLABEL "RxPlcpFormatErr",
-	IGNLABEL "RxPlcpLengthErr",
+	IGNLABEL("RxPlcpCrcErr"),
+	IGNLABEL("RxPlcpFormatErr"),
+	IGNLABEL("RxPlcpLengthErr"),
 	"RxMacCrcErr",
 	"RxMacCrcOk",
 	"RxWepErr",
@@ -146,15 +146,15 @@
 	"HostRxBc",
 	"HostRxUc",
 	"HostRxDiscard",
-	IGNLABEL "HmacTxMc",
-	IGNLABEL "HmacTxBc",
-	IGNLABEL "HmacTxUc",
-	IGNLABEL "HmacTxFail",
-	IGNLABEL "HmacRxMc",
-	IGNLABEL "HmacRxBc",
-	IGNLABEL "HmacRxUc",
-	IGNLABEL "HmacRxDiscard",
-	IGNLABEL "HmacRxAccepted",
+	IGNLABEL("HmacTxMc"),
+	IGNLABEL("HmacTxBc"),
+	IGNLABEL("HmacTxUc"),
+	IGNLABEL("HmacTxFail"),
+	IGNLABEL("HmacRxMc"),
+	IGNLABEL("HmacRxBc"),
+	IGNLABEL("HmacRxUc"),
+	IGNLABEL("HmacRxDiscard"),
+	IGNLABEL("HmacRxAccepted"),
 	"SsidMismatch",
 	"ApMismatch",
 	"RatesMismatch",
@@ -162,26 +162,26 @@
 	"AuthTimeout",
 	"AssocReject",
 	"AssocTimeout",
-	IGNLABEL "ReasonOutsideTable",
-	IGNLABEL "ReasonStatus1",
-	IGNLABEL "ReasonStatus2",
-	IGNLABEL "ReasonStatus3",
-	IGNLABEL "ReasonStatus4",
-	IGNLABEL "ReasonStatus5",
-	IGNLABEL "ReasonStatus6",
-	IGNLABEL "ReasonStatus7",
-	IGNLABEL "ReasonStatus8",
-	IGNLABEL "ReasonStatus9",
-	IGNLABEL "ReasonStatus10",
-	IGNLABEL "ReasonStatus11",
-	IGNLABEL "ReasonStatus12",
-	IGNLABEL "ReasonStatus13",
-	IGNLABEL "ReasonStatus14",
-	IGNLABEL "ReasonStatus15",
-	IGNLABEL "ReasonStatus16",
-	IGNLABEL "ReasonStatus17",
-	IGNLABEL "ReasonStatus18",
-	IGNLABEL "ReasonStatus19",
+	IGNLABEL("ReasonOutsideTable"),
+	IGNLABEL("ReasonStatus1"),
+	IGNLABEL("ReasonStatus2"),
+	IGNLABEL("ReasonStatus3"),
+	IGNLABEL("ReasonStatus4"),
+	IGNLABEL("ReasonStatus5"),
+	IGNLABEL("ReasonStatus6"),
+	IGNLABEL("ReasonStatus7"),
+	IGNLABEL("ReasonStatus8"),
+	IGNLABEL("ReasonStatus9"),
+	IGNLABEL("ReasonStatus10"),
+	IGNLABEL("ReasonStatus11"),
+	IGNLABEL("ReasonStatus12"),
+	IGNLABEL("ReasonStatus13"),
+	IGNLABEL("ReasonStatus14"),
+	IGNLABEL("ReasonStatus15"),
+	IGNLABEL("ReasonStatus16"),
+	IGNLABEL("ReasonStatus17"),
+	IGNLABEL("ReasonStatus18"),
+	IGNLABEL("ReasonStatus19"),
 	"RxMan",
 	"TxMan",
 	"RxRefresh",
@@ -654,9 +654,38 @@
 	u16 currentXmitRate;
 	u16 apDevExtensions;
 	u16 normalizedSignalStrength;
-	u16 _reserved1;
+	u16 shortPreamble;
 	u8 apIP[4];
-	u16 _reserved[7];
+	u8 noisePercent; /* Noise percent in last second */
+	u8 noisedBm; /* Noise dBm in last second */
+	u8 noiseAvePercent; /* Noise percent in last minute */
+	u8 noiseAvedBm; /* Noise dBm in last minute */
+	u8 noiseMaxPercent; /* Highest noise percent in last minute */
+	u8 noiseMaxdBm; /* Highest noise dbm in last minute */
+	u16 load;
+	u8 carrier[4];
+	u16 assocStatus;
+#define STAT_NOPACKETS 0
+#define STAT_NOCARRIERSET 10
+#define STAT_GOTCARRIERSET 11
+#define STAT_WRONGSSID 20
+#define STAT_BADCHANNEL 25
+#define STAT_BADBITRATES 30
+#define STAT_BADPRIVACY 35
+#define STAT_APFOUND 40
+#define STAT_APREJECTED 50
+#define STAT_AUTHENTICATING 60
+#define STAT_DEAUTHENTICATED 61
+#define STAT_AUTHTIMEOUT 62
+#define STAT_ASSOCIATING 70
+#define STAT_DEASSOCIATED 71
+#define STAT_ASSOCTIMEOUT 72
+#define STAT_NOTAIROAP 73
+#define STAT_ASSOCIATED 80
+#define STAT_LEAPING 90
+#define STAT_LEAPFAILED 91
+#define STAT_LEAPTIMEDOUT 92
+#define STAT_LEAPCOMPLETE 93
 } StatusRid;
 
 typedef struct {
@@ -894,7 +923,7 @@
 
 #ifdef WIRELESS_EXT
 // Frequency list (map channels to frequencies)
-const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442,
+static const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442,
 				2447, 2452, 2457, 2462, 2467, 2472, 2484 };
 
 // A few details needed for WEP (Wireless Equivalent Privacy)
@@ -929,8 +958,8 @@
 static void OUT4500( struct airo_info *, u16 register, u16 value );
 static unsigned short IN4500( struct airo_info *, u16 register );
 static u16 setup_card(struct airo_info*, u8 *mac);
-static int enable_MAC( struct airo_info *ai, Resp *rsp );
-static void disable_MAC(struct airo_info *ai);
+static int enable_MAC( struct airo_info *ai, Resp *rsp, int lock );
+static void disable_MAC(struct airo_info *ai, int lock);
 static void enable_interrupts(struct airo_info*);
 static void disable_interrupts(struct airo_info*);
 static u16 issuecommand(struct airo_info*, Cmd *pCmd, Resp *pRsp);
@@ -944,11 +973,11 @@
 static int bap_write(struct airo_info*, const u16 *pu16Src, int bytelen,
 		     int whichbap);
 static int PC4500_accessrid(struct airo_info*, u16 rid, u16 accmd);
-static int PC4500_readrid(struct airo_info*, u16 rid, void *pBuf, int len);
+static int PC4500_readrid(struct airo_info*, u16 rid, void *pBuf, int len, int lock);
 static int PC4500_writerid(struct airo_info*, u16 rid, const void
-			   *pBuf, int len);
+			   *pBuf, int len, int lock);
 static int do_writerid( struct airo_info*, u16 rid, const void *rid_data,
-			int len );
+			int len, int dummy );
 static u16 transmit_allocate(struct airo_info*, int lenPayload, int raw);
 static int transmit_802_3_packet(struct airo_info*, int len, char *pPacket);
 static int transmit_802_11_packet(struct airo_info*, int len, char *pPacket);
@@ -976,7 +1005,7 @@
 	int open;
 	struct net_device             *dev;
 	/* Note, we can have MAX_FIDS outstanding.  FIDs are 16-bits, so we
-	   use the high bit to mark wether it is in use. */
+	   use the high bit to mark whether it is in use. */
 #define MAX_FIDS 6
 	int                           fids[MAX_FIDS];
 	int registered;
@@ -992,19 +1021,21 @@
 #define FLAG_PROMISC   IFF_PROMISC	/* 0x100 - include/linux/if.h */
 #define FLAG_RADIO_OFF 0x02		/* User disabling of MAC */
 #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
+#define FLAG_PENDING_XMIT   0x400
+#define FLAG_PENDING_XMIT11 0x800
 	int (*bap_read)(struct airo_info*, u16 *pu16Dst, int bytelen,
 			int whichbap);
 	unsigned short *flash;
 	tdsRssiEntry *rssi;
 	struct semaphore sem;
 	struct task_struct *task;
+	struct tq_struct stats_task;
 	struct tq_struct promisc_task;
 	struct {
 		struct sk_buff *skb;
@@ -1062,7 +1093,7 @@
 			ai->task = NULL;
 		}
 	rc = PC4500_readrid(ai, first ? RID_BSSLISTFIRST : RID_BSSLISTNEXT,
-			    list, sizeof(*list));
+			    list, sizeof(*list), 1);
 
 	list->len = le16_to_cpu(list->len);
 	list->index = le16_to_cpu(list->index);
@@ -1077,7 +1108,7 @@
 
 static int readWepKeyRid(struct airo_info*ai, WepKeyRid *wkr, int temp) {
 	int rc = PC4500_readrid(ai, temp ? RID_WEP_TEMP : RID_WEP_PERM,
-				wkr, sizeof(*wkr));
+				wkr, sizeof(*wkr), 1);
 
 	wkr->len = le16_to_cpu(wkr->len);
 	wkr->kindex = le16_to_cpu(wkr->kindex);
@@ -1086,17 +1117,17 @@
 }
 /* In the writeXXXRid routines we copy the rids so that we don't screwup
  * the originals when we endian them... */
-static int writeWepKeyRid(struct airo_info*ai, WepKeyRid *pwkr, int perm) {
+static int writeWepKeyRid(struct airo_info*ai, WepKeyRid *pwkr, int perm, int lock) {
 	int rc;
 	WepKeyRid wkr = *pwkr;
 
 	wkr.len = cpu_to_le16(wkr.len);
 	wkr.kindex = cpu_to_le16(wkr.kindex);
 	wkr.klen = cpu_to_le16(wkr.klen);
-	rc = PC4500_writerid(ai, RID_WEP_TEMP, &wkr, sizeof(wkr));
+	rc = PC4500_writerid(ai, RID_WEP_TEMP, &wkr, sizeof(wkr), lock);
 	if (rc!=SUCCESS) printk(KERN_ERR "airo:  WEP_TEMP set %x\n", rc);
 	if (perm) {
-		rc = PC4500_writerid(ai, RID_WEP_PERM, &wkr, sizeof(wkr));
+		rc = PC4500_writerid(ai, RID_WEP_PERM, &wkr, sizeof(wkr), lock);
 		if (rc!=SUCCESS) {
 			printk(KERN_ERR "airo:  WEP_PERM set %x\n", rc);
 		}
@@ -1106,7 +1137,7 @@
 
 static int readSsidRid(struct airo_info*ai, SsidRid *ssidr) {
 	int i;
-	int rc = PC4500_readrid(ai, RID_SSID, ssidr, sizeof(*ssidr));
+	int rc = PC4500_readrid(ai, RID_SSID, ssidr, sizeof(*ssidr), 1);
 
 	ssidr->len = le16_to_cpu(ssidr->len);
 	for(i = 0; i < 3; i++) {
@@ -1123,10 +1154,10 @@
 	for(i = 0; i < 3; i++) {
 		ssidr.ssids[i].len = cpu_to_le16(ssidr.ssids[i].len);
 	}
-	rc = PC4500_writerid(ai, RID_SSID, &ssidr, sizeof(ssidr));
+	rc = PC4500_writerid(ai, RID_SSID, &ssidr, sizeof(ssidr), 1);
 	return rc;
 }
-static int readConfigRid(struct airo_info*ai) {
+static int readConfigRid(struct airo_info*ai, int lock) {
 	int rc;
 	u16 *s;
 	ConfigRid cfg;
@@ -1134,7 +1165,7 @@
 	if (ai->config.len)
 		return SUCCESS;
 
-	rc = PC4500_readrid(ai, RID_ACTUALCONFIG, &cfg, sizeof(cfg));
+	rc = PC4500_readrid(ai, RID_ACTUALCONFIG, &cfg, sizeof(cfg), lock);
 	if (rc != SUCCESS)
 		return rc;
 
@@ -1163,7 +1194,7 @@
 		}
 	}
 }
-static int writeConfigRid(struct airo_info*ai) {
+static int writeConfigRid(struct airo_info*ai, int lock) {
 	u16 *s;
 	ConfigRid cfgr;
 
@@ -1190,33 +1221,34 @@
 	for(s = &cfgr.arlThreshold; s <= &cfgr.autoWake; s++)
 		*s = cpu_to_le16(*s);
 
-	return PC4500_writerid( ai, RID_CONFIG, &cfgr, sizeof(cfgr));
+	return PC4500_writerid( ai, RID_CONFIG, &cfgr, sizeof(cfgr), lock);
 }
 static int readStatusRid(struct airo_info*ai, StatusRid *statr) {
-	int rc = PC4500_readrid(ai, RID_STATUS, statr, sizeof(*statr));
+	int rc = PC4500_readrid(ai, RID_STATUS, statr, sizeof(*statr), 1);
 	u16 *s;
 
 	statr->len = le16_to_cpu(statr->len);
 	for(s = &statr->mode; s <= &statr->SSIDlen; s++) *s = le16_to_cpu(*s);
 
-	for(s = &statr->beaconPeriod; s <= &statr->_reserved[9]; s++)
+	for(s = &statr->beaconPeriod; s <= &statr->shortPreamble; s++)
 		*s = le16_to_cpu(*s);
-
+	statr->load = le16_to_cpu(statr->load);
+	statr->assocStatus = le16_to_cpu(statr->assocStatus);
 	return rc;
 }
 static int readAPListRid(struct airo_info*ai, APListRid *aplr) {
-	int rc =  PC4500_readrid(ai, RID_APLIST, aplr, sizeof(*aplr));
+	int rc =  PC4500_readrid(ai, RID_APLIST, aplr, sizeof(*aplr), 1);
 	aplr->len = le16_to_cpu(aplr->len);
 	return rc;
 }
 static int writeAPListRid(struct airo_info*ai, APListRid *aplr) {
 	int rc;
 	aplr->len = cpu_to_le16(aplr->len);
-	rc = PC4500_writerid(ai, RID_APLIST, aplr, sizeof(*aplr));
+	rc = PC4500_writerid(ai, RID_APLIST, aplr, sizeof(*aplr), 1);
 	return rc;
 }
 static int readCapabilityRid(struct airo_info*ai, CapabilityRid *capr) {
-	int rc = PC4500_readrid(ai, RID_CAPABILITIES, capr, sizeof(*capr));
+	int rc = PC4500_readrid(ai, RID_CAPABILITIES, capr, sizeof(*capr), 1);
 	u16 *s;
 
 	capr->len = le16_to_cpu(capr->len);
@@ -1227,8 +1259,8 @@
 		*s = le16_to_cpu(*s);
 	return rc;
 }
-static int readStatsRid(struct airo_info*ai, StatsRid *sr, int rid) {
-	int rc = PC4500_readrid(ai, rid, sr, sizeof(*sr));
+static int readStatsRid(struct airo_info*ai, StatsRid *sr, int rid, int lock) {
+	int rc = PC4500_readrid(ai, rid, sr, sizeof(*sr), lock);
 	u32 *i;
 
 	sr->len = le16_to_cpu(sr->len);
@@ -1248,8 +1280,8 @@
 	 * is open (to pipeline changes and speed-up card setup). If
 	 * those changes are not yet commited, do it now - Jean II */
 	if(info->need_commit) {
-		disable_MAC(info);
-		writeConfigRid(info);
+		disable_MAC(info, 1);
+		writeConfigRid(info, 1);
 	}
 
 	if (info->wifidev != dev) {
@@ -1257,7 +1289,7 @@
 		info->flags &= ~FLAG_RADIO_DOWN;
 		enable_interrupts(info);
 	}
-	enable_MAC(info, &rsp);
+	enable_MAC(info, &rsp, 1);
 
 	netif_start_queue(dev);
 	return 0;
@@ -1321,6 +1353,7 @@
 	u32 *fids = priv->fids;
 
 	if (down_trylock(&priv->sem) != 0) {
+		priv->flags |= FLAG_PENDING_XMIT;
 		netif_stop_queue(dev);
 		priv->xmit.task.routine = (void (*)(void *))airo_do_xmit;
 		priv->xmit.task.data = (void *)dev;
@@ -1329,6 +1362,7 @@
 	}
 	status = transmit_802_3_packet (priv, fids[fid], skb->data);
 	up(&priv->sem);
+	priv->flags &= ~FLAG_PENDING_XMIT;
 
 	i = 0;
 	if ( status == SUCCESS ) {
@@ -1340,14 +1374,12 @@
 	}
 	if (i < MAX_FIDS / 2)
 		netif_wake_queue(dev);
-	else
-		netif_stop_queue(dev);
 	dev_kfree_skb(skb);
 }
 
 static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
 	s16 len;
-	int i;
+	int i, j;
 	struct airo_info *priv = dev->priv;
 	u32 *fids = priv->fids;
 
@@ -1358,19 +1390,23 @@
 
 	/* Find a vacant FID */
 	for( i = 0; i < MAX_FIDS / 2 && (fids[i] & 0xffff0000); i++ );
+	for( j = i + 1; j < MAX_FIDS / 2 && (fids[j] & 0xffff0000); j++ );
 
-	if ( i == MAX_FIDS / 2 ) {
-		priv->stats.tx_fifo_errors++;
-		dev_kfree_skb(skb);
-	} else {
-		/* check min length*/
-		len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-	        /* Mark fid as used & save length for later */
-		fids[i] |= (len << 16);
-		priv->xmit.skb = skb;
-		priv->xmit.fid = i;
-		airo_do_xmit(dev);
+	if ( j >= MAX_FIDS / 2 ) {
+		netif_stop_queue(dev);
+
+		if (i == MAX_FIDS / 2) {
+			priv->stats.tx_fifo_errors++;
+			return 1;
+		}
 	}
+	/* check min length*/
+	len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+        /* Mark fid as used & save length for later */
+	fids[i] |= (len << 16);
+	priv->xmit.skb = skb;
+	priv->xmit.fid = i;
+	airo_do_xmit(dev);
 	return 0;
 }
 
@@ -1383,6 +1419,7 @@
 	u32 *fids = priv->fids;
 
 	if (down_trylock(&priv->sem) != 0) {
+		priv->flags |= FLAG_PENDING_XMIT11;
 		netif_stop_queue(dev);
 		priv->xmit11.task.routine = (void (*)(void *))airo_do_xmit11;
 		priv->xmit11.task.data = (void *)dev;
@@ -1391,6 +1428,7 @@
 	}
 	status = transmit_802_11_packet (priv, fids[fid], skb->data);
 	up(&priv->sem);
+	priv->flags &= ~FLAG_PENDING_XMIT11;
 
 	i = MAX_FIDS / 2;
 	if ( status == SUCCESS ) {
@@ -1402,14 +1440,12 @@
 	}
 	if (i < MAX_FIDS)
 		netif_wake_queue(dev);
-	else
-		netif_stop_queue(dev);
 	dev_kfree_skb(skb);
 }
 
 static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
 	s16 len;
-	int i;
+	int i, j;
 	struct airo_info *priv = dev->priv;
 	u32 *fids = priv->fids;
 
@@ -1420,45 +1456,61 @@
 
 	/* Find a vacant FID */
 	for( i = MAX_FIDS / 2; i < MAX_FIDS && (fids[i] & 0xffff0000); i++ );
+	for( j = i + 1; j < MAX_FIDS && (fids[j] & 0xffff0000); j++ );
 
-	if ( i == MAX_FIDS ) {
-		priv->stats.tx_fifo_errors++;
-		dev_kfree_skb(skb);
-	} else {
-		/* check min length*/
-		len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-	        /* Mark fid as used & save length for later */
-		fids[i] |= (len << 16);
-		priv->xmit11.skb = skb;
-		priv->xmit11.fid = i;
-		airo_do_xmit11(dev);
+	if ( j >= MAX_FIDS ) {
+		netif_stop_queue(dev);
+
+		if (i == MAX_FIDS) {
+			priv->stats.tx_fifo_errors++;
+			return 1;
+		}
 	}
+	/* check min length*/
+	len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+        /* Mark fid as used & save length for later */
+	fids[i] |= (len << 16);
+	priv->xmit11.skb = skb;
+	priv->xmit11.fid = i;
+	airo_do_xmit11(dev);
 	return 0;
 }
 
-struct net_device_stats *airo_get_stats(struct net_device *dev)
-{
-	struct airo_info *local =  dev->priv;
+static void airo_read_stats(struct airo_info *ai) {
 	StatsRid stats_rid;
 	u32 *vals = stats_rid.vals;
 
-	/* Get stats out of the card */
-	readStatsRid(local, &stats_rid, RID_STATS);
+	if (down_trylock(&ai->sem) == 0) {
+		readStatsRid(ai, &stats_rid, RID_STATS, 0);
+		up(&ai->sem);
 
-	local->stats.rx_packets = vals[43] + vals[44] + vals[45];
-	local->stats.tx_packets = vals[39] + vals[40] + vals[41];
-	local->stats.rx_bytes = vals[92];
-	local->stats.tx_bytes = vals[91];
-	local->stats.rx_errors = vals[0] + vals[2] + vals[3] + vals[4];
-	local->stats.tx_errors = vals[42] + local->stats.tx_fifo_errors;
-	local->stats.multicast = vals[43];
-	local->stats.collisions = vals[89];
-
-	/* detailed rx_errors: */
-	local->stats.rx_length_errors = vals[3];
-	local->stats.rx_crc_errors = vals[4];
-	local->stats.rx_frame_errors = vals[2];
-	local->stats.rx_fifo_errors = vals[0];
+		ai->stats.rx_packets = vals[43] + vals[44] + vals[45];
+		ai->stats.tx_packets = vals[39] + vals[40] + vals[41];
+		ai->stats.rx_bytes = vals[92];
+		ai->stats.tx_bytes = vals[91];
+		ai->stats.rx_errors = vals[0] + vals[2] + vals[3] + vals[4];
+		ai->stats.tx_errors = vals[42] + ai->stats.tx_fifo_errors;
+		ai->stats.multicast = vals[43];
+		ai->stats.collisions = vals[89];
+
+		/* detailed rx_errors: */
+		ai->stats.rx_length_errors = vals[3];
+		ai->stats.rx_crc_errors = vals[4];
+		ai->stats.rx_frame_errors = vals[2];
+		ai->stats.rx_fifo_errors = vals[0];
+	} else {
+		ai->stats_task.routine = (void (*)(void *))airo_read_stats;
+		ai->stats_task.data = (void *)ai;
+		schedule_task(&ai->stats_task);
+	}
+}
+
+struct net_device_stats *airo_get_stats(struct net_device *dev)
+{
+	struct airo_info *local =  dev->priv;
+
+	/* Get stats out of the card if available */
+	airo_read_stats(local);
 
 	return &local->stats;
 }
@@ -1513,9 +1565,9 @@
 
 	memcpy (ai->config.macAddr, addr->sa_data, dev->addr_len);
 	ai->need_commit = 1;
-	disable_MAC(ai);
-	writeConfigRid (ai);
-	enable_MAC(ai, &rsp);
+	disable_MAC(ai, 1);
+	writeConfigRid (ai, 1);
+	enable_MAC(ai, &rsp, 1);
 	memcpy (ai->dev->dev_addr, addr->sa_data, dev->addr_len);
 	if (ai->wifidev)
 		memcpy (ai->wifidev->dev_addr, addr->sa_data, dev->addr_len);
@@ -1544,7 +1596,7 @@
 		 * stack (i.e. the network stack won't try to broadcast
 		 * anything on the interface and routes are gone. Jean II */
 		ai->flags |= FLAG_RADIO_DOWN;
-		disable_MAC(ai);
+		disable_MAC(ai, 1);
 #endif
 		disable_interrupts( ai );
 	}
@@ -1557,6 +1609,8 @@
 {
 	struct airo_info *ai = dev->priv;
 	flush_scheduled_tasks();
+	disable_interrupts(ai);
+	free_irq( dev->irq, dev );
 	if (ai->flash)
 		kfree(ai->flash);
 	if (ai->rssi)
@@ -1571,8 +1625,6 @@
 		}
 		ai->registered = 0;
 	}
-	disable_interrupts(ai);
-	free_irq( dev->irq, dev );
 	if (auto_wep) del_timer_sync(&ai->timer);
 	if (freeres) {
 		/* PCMCIA frees this stuff, so only for PCI and ISA */
@@ -1768,6 +1820,9 @@
 	int i;
 	struct airo_info *ai = dev->priv;
 
+
+	if (down_interruptible(&ai->sem))
+		return -1;
 	waitbusy (ai);
 	OUT4500(ai,COMMAND,CMD_SOFTRESET);
 	set_current_state (TASK_UNINTERRUPTIBLE);
@@ -1777,6 +1832,7 @@
 	schedule_timeout (HZ/5);
 	if ( setup_card(ai, dev->dev_addr ) != SUCCESS ) {
 		printk( KERN_ERR "airo: MAC could not be enabled\n" );
+		up(&ai->sem);
 		return -1;
 	} else {
 		printk( KERN_INFO "airo: MAC enabled %s %x:%x:%x:%x:%x:%x\n",
@@ -1794,6 +1850,7 @@
 	}
 	enable_interrupts( ai );
 	netif_wake_queue(dev);
+	up(&ai->sem);
 	return 0;
 }
 
@@ -1806,9 +1863,7 @@
 	StatusRid status_rid;
 
 	if (down_trylock(&ai->sem) == 0) {
-		__set_bit(FLAG_LOCKED, &ai->flags);
-		PC4500_readrid(ai, RID_STATUS, &status_rid, sizeof(status_rid));
-		clear_bit(FLAG_LOCKED, &ai->flags);
+		PC4500_readrid(ai, RID_STATUS, &status_rid, sizeof(status_rid), 0);
 		up(&ai->sem);
 		wrqu.data.length = 0;
 		wrqu.data.flags = 0;
@@ -1829,9 +1884,7 @@
 	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);
+		PC4500_readrid(ai, RID_MIC, &mic_rid, sizeof(mic_rid), 0);
 		up(&ai->sem);
 #ifdef MICSUPPORT
 		micinit (ai, &mic_rid);
@@ -1869,7 +1922,8 @@
 
 		if ( status & EV_MIC ) {
 			OUT4500( apriv, EVACK, EV_MIC );
-			airo_read_mic( apriv );
+			if (apriv->flags & FLAG_MIC_CAPABLE)
+				airo_read_mic( apriv );
 		}
 		if ( status & EV_LINK ) {
 #if WIRELESS_EXT > 13
@@ -2060,6 +2114,28 @@
 				}
 			}
 			if (len) {
+#if WIRELESS_EXT > 15
+#ifdef IW_WIRELESS_SPY		/* defined in iw_handler.h */
+				if (apriv->spy_data.spy_number > 0) {
+					char *sa;
+					struct iw_quality wstats;
+					/* Prepare spy data : addr + qual */
+					sa = (char*)buffer + ((apriv->flags & FLAG_802_11) ? 10 : 6);
+					if (!(apriv->flags & FLAG_802_11)) {
+						bap_setup (apriv, fid, 8, BAP0);
+						bap_read (apriv, (u16*)hdr.rssi, 2, BAP0);
+					}
+					wstats.qual = hdr.rssi[0];
+					if (apriv->rssi)
+						wstats.level = 0x100 - apriv->rssi[hdr.rssi[1]].rssidBm;
+					else
+						wstats.level = (hdr.rssi[1] + 321) / 2;
+					wstats.updated = 3;	
+					/* Update spy records */
+					wireless_spy_update(dev, sa, &wstats);
+				}
+#endif /* IW_WIRELESS_SPY */
+#else /* WIRELESS_EXT > 15 */
 #ifdef WIRELESS_SPY
 				if (apriv->spy_number > 0) {
 					int i;
@@ -2085,6 +2161,7 @@
 						}
 				}
 #endif /* WIRELESS_SPY  */
+#endif /* WIRELESS_EXT > 15 */
 				OUT4500( apriv, EVACK, EV_RX);
 
 				if (apriv->flags & FLAG_802_11) {
@@ -2116,17 +2193,23 @@
 				if ( ( apriv->fids[i] & 0xffff ) == fid ) {
 					len = apriv->fids[i] >> 16;
 					index = i;
-					/* Set up to be used again */
-					apriv->fids[i] &= 0xffff;
 				}
 			}
 			if (index != -1) {
-				netif_wake_queue(dev);
 				if (status & EV_TXEXC)
 					get_tx_error(apriv, index);
-			}
-			OUT4500( apriv, EVACK, status & (EV_TX | EV_TXEXC));
-			if (index==-1) {
+				OUT4500( apriv, EVACK, status & (EV_TX | EV_TXEXC));
+				/* Set up to be used again */
+				apriv->fids[index] &= 0xffff;
+				if (index < MAX_FIDS / 2) {
+					if (!(apriv->flags & FLAG_PENDING_XMIT))
+						netif_wake_queue(dev);
+				} else {
+					if (!(apriv->flags & FLAG_PENDING_XMIT11))
+						netif_wake_queue(apriv->wifidev);
+				}
+			} else {
+				OUT4500( apriv, EVACK, status & (EV_TX | EV_TXEXC));
 				printk( KERN_ERR "airo: Unallocated FID was used to xmit\n" );
 			}
 		}
@@ -2172,7 +2255,7 @@
 	return rc;
 }
 
-static int enable_MAC( struct airo_info *ai, Resp *rsp ) {
+static int enable_MAC( struct airo_info *ai, Resp *rsp, int lock ) {
 	int rc;
         Cmd cmd;
 
@@ -2185,7 +2268,7 @@
 	if (ai->flags & (FLAG_RADIO_OFF|FLAG_RADIO_DOWN)) return SUCCESS;
 	memset(&cmd, 0, sizeof(cmd));
 	cmd.cmd = MAC_ENABLE;
-	if (test_bit(FLAG_LOCKED, &ai->flags) != 0)
+	if (!lock)
 		return issuecommand(ai, &cmd, rsp);
 
 	if (down_interruptible(&ai->sem))
@@ -2195,13 +2278,13 @@
 	return rc;
 }
 
-static void disable_MAC( struct airo_info *ai ) {
+static void disable_MAC( struct airo_info *ai, int lock ) {
         Cmd cmd;
 	Resp rsp;
 
 	memset(&cmd, 0, sizeof(cmd));
 	cmd.cmd = MAC_DISABLE; // disable in case already enabled
-	if (test_bit(FLAG_LOCKED, &ai->flags) != 0) {
+	if (!lock) {
 		issuecommand(ai, &cmd, &rsp);
 		return;
 	}
@@ -2219,7 +2302,7 @@
 	/* Enable the interrupts */
 	OUT4500( ai, EVINTEN, STATUS_INTS );
 	/* Note there is a race condition between the last two lines that
-	   I dont know how to get rid of right now... */
+	   I don't know how to get rid of right now... */
 }
 
 static void disable_interrupts( struct airo_info *ai ) {
@@ -2279,13 +2362,13 @@
 		CapabilityRid cap_rid;
 
 		// general configuration (read/modify/write)
-		status = readConfigRid(ai);
+		status = readConfigRid(ai, 1);
 		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));
+		status = PC4500_readrid(ai,RID_RSSI,&rssi_rid,sizeof(rssi_rid),1);
 		if ( status == SUCCESS ) {
 			if (ai->rssi || (ai->rssi = kmalloc(512, GFP_KERNEL)) != NULL)
 				memcpy(ai->rssi, (u8*)&rssi_rid + 2, 512);
@@ -2349,14 +2432,14 @@
 		}
 	}
 
-	status = writeConfigRid(ai);
+	status = writeConfigRid(ai, 1);
 	if ( status != SUCCESS ) return ERROR;
 
 	/* Set up the SSID list */
 	status = writeSsidRid(ai, &mySsid);
 	if ( status != SUCCESS ) return ERROR;
 
-	status = enable_MAC(ai, &rsp);
+	status = enable_MAC(ai, &rsp, 1);
 	if ( status != SUCCESS || (rsp.status & 0xFF00) != 0) {
 		printk( KERN_ERR "airo: Bad MAC enable reason = %x, rid = %x, offset = %d\n", rsp.rsp0, rsp.rsp1, rsp.rsp2 );
 		return ERROR;
@@ -2500,7 +2583,7 @@
 	u16 next;
 	int words;
 	int i;
-	long flags;
+	unsigned long flags;
 
 	spin_lock_irqsave(&ai->aux_lock, flags);
 	page = IN4500(ai, SWS0+whichbap);
@@ -2571,13 +2654,12 @@
 
 /*  Note, that we are using BAP1 which is also used by transmit, so
  *  we must get a lock. */
-static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len)
+static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len, int lock)
 {
-	u16 status, dolock = 0;
+	u16 status;
         int rc = SUCCESS;
 
-	if (test_bit(FLAG_LOCKED, &ai->flags) == 0) {
-		dolock = 1;
+	if (lock) {
 		if (down_interruptible(&ai->sem))
 			return ERROR;
 	}
@@ -2605,7 +2687,7 @@
 	// read remainder of the rid
 	rc = bap_read(ai, ((u16*)pBuf)+1, len, BAP1);
 done:
-	if (dolock)
+	if (lock)
 		up(&ai->sem);
 	return rc;
 }
@@ -2613,13 +2695,14 @@
 /*  Note, that we are using BAP1 which is also used by transmit, so
  *  make sure this isnt called when a transmit is happening */
 static int PC4500_writerid(struct airo_info *ai, u16 rid,
-			   const void *pBuf, int len)
+			   const void *pBuf, int len, int lock)
 {
-	u16 status, dolock = 0;
+	u16 status;
 	int rc = SUCCESS;
 
-	if (test_bit(FLAG_LOCKED, &ai->flags) == 0) {
-		dolock = 1;
+	*(u16*)pBuf = cpu_to_le16((u16)len);
+
+	if (lock) {
 		if (down_interruptible(&ai->sem))
 			return ERROR;
 	}
@@ -2637,7 +2720,7 @@
 	// ---now commit the rid data
 	rc = PC4500_accessrid(ai, rid, 0x100|CMD_ACCESS);
  done:
-	if (dolock)
+	if (lock)
 		up(&ai->sem);
         return rc;
 }
@@ -2646,6 +2729,7 @@
    one for now. */
 static u16 transmit_allocate(struct airo_info *ai, int lenPayload, int raw)
 {
+	unsigned int loop = 3000;
 	Cmd cmd;
 	Resp rsp;
 	u16 txFid;
@@ -2656,17 +2740,22 @@
 	if (down_interruptible(&ai->sem))
 		return ERROR;
 	if (issuecommand(ai, &cmd, &rsp) != SUCCESS) {
-		txFid = 0;
+		txFid = ERROR;
 		goto done;
 	}
 	if ( (rsp.status & 0xFF00) != 0) {
-		txFid = 0;
+		txFid = ERROR;
 		goto done;
 	}
 	/* wait for the allocate event/indication
 	 * It makes me kind of nervous that this can just sit here and spin,
 	 * but in practice it only loops like four times. */
-	while ( (IN4500(ai, EVSTAT) & EV_ALLOC) == 0) ;
+	while (((IN4500(ai, EVSTAT) & EV_ALLOC) == 0) && --loop);
+	if (!loop) {
+		txFid = ERROR;
+		goto done;
+	}
+
 	// get the allocated fid and acknowledge
 	txFid = IN4500(ai, TXALLOCFID);
 	OUT4500(ai, EVACK, EV_ALLOC);
@@ -2707,7 +2796,7 @@
 
 	len >>= 16;
 
-	if (len < ETH_ALEN * 2) {
+	if (len <= ETH_ALEN * 2) {
 		printk( KERN_WARNING "Short packet %d\n", len );
 		return ERROR;
 	}
@@ -3158,10 +3247,10 @@
 		return -ENOMEM;
 	}
 
-	readStatsRid(apriv, &stats, rid);
+	readStatsRid(apriv, &stats, rid, 1);
 
         j = 0;
-	for(i=0; (int)statsLabels[i]!=-1 &&
+	for(i=0; statsLabels[i]!=(char *)-1 &&
 		    i*4<stats.len; i++){
 		if (!statsLabels[i]) continue;
 		if (j+strlen(statsLabels[i])+16>4096) {
@@ -3193,18 +3282,21 @@
 	return value;
 }
 
+static int airo_config_commit(struct net_device *dev,
+			      struct iw_request_info *info, void *zwrq,
+			      char *extra);
+
 static void proc_config_on_close( struct inode *inode, struct file *file ) {
 	struct proc_data *data = file->private_data;
 	struct proc_dir_entry *dp = PDE(inode);
 	struct net_device *dev = dp->data;
 	struct airo_info *ai = dev->priv;
-	Resp rsp;
 	char *line;
-	int need_reset = 0;
 
 	if ( !data->writelen ) return;
 
-	readConfigRid(ai);
+	readConfigRid(ai, 1);
+	ai->need_commit = 1;
 
 	line = data->wbuffer;
 	while( line[0] ) {
@@ -3212,19 +3304,22 @@
 		if ( !strncmp( line, "Mode: ", 6 ) ) {
 			line += 6;
 			if ((ai->config.rmode & 0xff) >= RXMODE_RFMON)
-					need_reset = 1;
+					ai->need_commit = 2;
 			ai->config.rmode &= 0xfe00;
 			ai->flags &= ~FLAG_802_11;
 			ai->config.opmode &= 0xFF00;
+			ai->config.scanMode = SCANMODE_ACTIVE;
 			if ( line[0] == 'a' ) {
 				ai->config.opmode |= 0;
 			} else {
 				ai->config.opmode |= 1;
 				if ( line[0] == 'r' ) {
 					ai->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER;
+					ai->config.scanMode = SCANMODE_PASSIVE;
 					ai->flags |= FLAG_802_11;
 				} else if ( line[0] == 'y' ) {
 					ai->config.rmode |= RXMODE_RFMON_ANYBSS | RXMODE_DISABLE_802_3_HEADER;
+					ai->config.scanMode = SCANMODE_PASSIVE;
 					ai->flags |= FLAG_802_11;
 				} else if ( line[0] == 'l' )
 					ai->config.rmode |= RXMODE_LANMON;
@@ -3390,22 +3485,7 @@
 		while( line[0] && line[0] != '\n' ) line++;
 		if ( line[0] ) line++;
 	}
-	disable_MAC(ai);
-	if (need_reset) {
-		APListRid APList_rid;
-		SsidRid SSID_rid;
-
-		readAPListRid(ai, &APList_rid);
-		readSsidRid(ai, &SSID_rid);
-		reset_airo_card(dev);
-		disable_MAC(ai);
-		writeSsidRid(ai, &SSID_rid);
-		writeAPListRid(ai, &APList_rid);
-	}
-	writeConfigRid(ai);
-	enable_MAC(ai, &rsp);
-	if (need_reset)
-		airo_set_promisc(ai);
+	airo_config_commit(dev, NULL, NULL, NULL);
 }
 
 static char *get_rmode(u16 mode) {
@@ -3443,7 +3523,7 @@
 	data->maxwritelen = 2048;
 	data->on_close = proc_config_on_close;
 
-	readConfigRid(ai);
+	readConfigRid(ai, 1);
 
 	i = sprintf( data->rbuffer,
 		     "Mode: %s\n"
@@ -3535,9 +3615,9 @@
 		       offset < data->writelen ) offset++;
 		offset++;
 	}
-	disable_MAC(ai);
+	disable_MAC(ai, 1);
 	writeSsidRid(ai, &SSID_rid);
-	enable_MAC(ai, &rsp);
+	enable_MAC(ai, &rsp, 1);
 }
 
 inline static u8 hexVal(char c) {
@@ -3576,20 +3656,20 @@
 			}
 		}
 	}
-	disable_MAC(ai);
+	disable_MAC(ai, 1);
 	writeAPListRid(ai, &APList_rid);
-	enable_MAC(ai, &rsp);
+	enable_MAC(ai, &rsp, 1);
 }
 
 /* This function wraps PC4500_writerid with a MAC disable */
 static int do_writerid( struct airo_info *ai, u16 rid, const void *rid_data,
-			int len ) {
+			int len, int dummy ) {
 	int rc;
 	Resp rsp;
 
-	disable_MAC(ai);
-	rc = PC4500_writerid(ai, rid, rid_data, len);
-	enable_MAC(ai, &rsp);
+	disable_MAC(ai, 1);
+	rc = PC4500_writerid(ai, rid, rid_data, len, 1);
+	enable_MAC(ai, &rsp, 1);
 	return rc;
 }
 
@@ -3617,7 +3697,7 @@
 }
 
 static int set_wep_key(struct airo_info *ai, u16 index,
-		       const char *key, u16 keylen, int perm ) {
+		       const char *key, u16 keylen, int perm, int lock ) {
 	static const unsigned char macaddr[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 };
 	WepKeyRid wkr;
 
@@ -3639,7 +3719,7 @@
 		printk(KERN_INFO "Setting key %d\n", index);
 	}
 
-	writeWepKeyRid(ai, &wkr, perm);
+	writeWepKeyRid(ai, &wkr, perm, lock);
 	return 0;
 }
 
@@ -3662,7 +3742,7 @@
 	    (data->wbuffer[1] == ' ' || data->wbuffer[1] == '\n')) {
 		index = data->wbuffer[0] - '0';
 		if (data->wbuffer[1] == '\n') {
-			set_wep_key(ai, index, 0, 0, 1);
+			set_wep_key(ai, index, 0, 0, 1, 1);
 			return;
 		}
 		j = 2;
@@ -3681,7 +3761,7 @@
 			break;
 		}
 	}
-	set_wep_key(ai, index, key, i/3, 1);
+	set_wep_key(ai, index, key, i/3, 1, 1);
 }
 
 static int proc_wepkey_open( struct inode *inode, struct file *file ) {
@@ -3937,10 +4017,9 @@
 			add_timer(&apriv->timer);
 			return;
 		}
-		__set_bit(FLAG_LOCKED, &apriv->flags);
 
-		readConfigRid(apriv);
-		disable_MAC(apriv);
+		readConfigRid(apriv, 0);
+		disable_MAC(apriv, 0);
 		switch(apriv->config.authType) {
 		case AUTH_ENCRYPT:
 /* So drop to OPEN */
@@ -3948,13 +4027,13 @@
 			break;
 		case AUTH_SHAREDKEY:
 			if (apriv->keyindex < auto_wep) {
-				set_wep_key(apriv, apriv->keyindex, 0, 0, 0);
+				set_wep_key(apriv, apriv->keyindex, 0, 0, 0, 0);
 				apriv->config.authType = AUTH_SHAREDKEY;
 				apriv->keyindex++;
 			} else {
 			        /* Drop to ENCRYPT */
 				apriv->keyindex = 0;
-				set_wep_key(apriv, apriv->defindex, 0, 0, 0);
+				set_wep_key(apriv, apriv->defindex, 0, 0, 0, 0);
 				apriv->config.authType = AUTH_ENCRYPT;
 			}
 			break;
@@ -3962,9 +4041,8 @@
 			apriv->config.authType = AUTH_SHAREDKEY;
 		}
 		apriv->need_commit = 1;
-		writeConfigRid(apriv);
-		enable_MAC(apriv, &rsp);
-		clear_bit(FLAG_LOCKED, &apriv->flags);
+		writeConfigRid(apriv, 0);
+		enable_MAC(apriv, &rsp, 0);
 		up(&apriv->sem);
 
 /* Schedule check to see if the change worked */
@@ -4144,9 +4222,11 @@
 	struct airo_info *local = dev->priv;
 	StatusRid status_rid;		/* Card status info */
 
-	readStatusRid(local, &status_rid);
+	if ((local->config.opmode & 0xFF) == MODE_STA_ESS)
+		status_rid.channel = local->config.channelSet;
+	else
+		readStatusRid(local, &status_rid);
 
-	/* Will return zero in infrastructure mode */
 #ifdef WEXT_USECHANNELS
 	fwrq->m = ((int)status_rid.channel) + 1;
 	fwrq->e = 0;
@@ -4200,9 +4280,9 @@
 		SSID_rid.ssids[index].len = dwrq->length - 1;
 	}
 	/* Write it to the card */
-	disable_MAC(local);
+	disable_MAC(local, 1);
 	writeSsidRid(local, &SSID_rid);
-	enable_MAC(local, &rsp);
+	enable_MAC(local, &rsp, 1);
 
 	return 0;
 }
@@ -4264,9 +4344,9 @@
 		memset(&APList_rid, 0, sizeof(APList_rid));
 		APList_rid.len = sizeof(APList_rid);
 		memcpy(APList_rid.ap[0], awrq->sa_data, ETH_ALEN);
-		disable_MAC(local);
+		disable_MAC(local, 1);
 		writeAPListRid(local, &APList_rid);
-		enable_MAC(local, &rsp);
+		enable_MAC(local, &rsp, 1);
 	}
 	return 0;
 }
@@ -4515,28 +4595,52 @@
 			 char *extra)
 {
 	struct airo_info *local = dev->priv;
+	int commit = 1;
+
+	if ((local->config.rmode & 0xff) >= RXMODE_RFMON)
+		commit = 2;
 
 	switch(*uwrq) {
 		case IW_MODE_ADHOC:
 			local->config.opmode &= 0xFF00;
 			local->config.opmode |= MODE_STA_IBSS;
+			local->config.rmode &= 0xfe00;
+			local->config.scanMode = SCANMODE_ACTIVE;
+			local->flags &= ~FLAG_802_11;
 			break;
 		case IW_MODE_INFRA:
 			local->config.opmode &= 0xFF00;
 			local->config.opmode |= MODE_STA_ESS;
+			local->config.rmode &= 0xfe00;
+			local->config.scanMode = SCANMODE_ACTIVE;
+			local->flags &= ~FLAG_802_11;
 			break;
 		case IW_MODE_MASTER:
 			local->config.opmode &= 0xFF00;
 			local->config.opmode |= MODE_AP;
+			local->config.rmode &= 0xfe00;
+			local->config.scanMode = SCANMODE_ACTIVE;
+			local->flags &= ~FLAG_802_11;
 			break;
 		case IW_MODE_REPEAT:
 			local->config.opmode &= 0xFF00;
 			local->config.opmode |= MODE_AP_RPTR;
+			local->config.rmode &= 0xfe00;
+			local->config.scanMode = SCANMODE_ACTIVE;
+			local->flags &= ~FLAG_802_11;
+			break;
+		case IW_MODE_MONITOR:
+			local->config.opmode &= 0xFF00;
+			local->config.opmode |= MODE_STA_ESS;
+			local->config.rmode &= 0xfe00;
+			local->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER;
+			local->config.scanMode = SCANMODE_PASSIVE;
+			local->flags |= FLAG_802_11;
 			break;
 		default:
 			return -EINVAL;
 	}
-	local->need_commit = 1;
+	local->need_commit = commit;
 
 	return -EINPROGRESS;		/* Call commit handler */
 }
@@ -4622,7 +4726,7 @@
 			/* Copy the key in the driver */
 			memcpy(key.key, extra, dwrq->length);
 			/* Send the key to the card */
-			set_wep_key(local, index, key.key, key.len, 1);
+			set_wep_key(local, index, key.key, key.len, 1, 1);
 		}
 		/* WE specify that if a valid key is set, encryption
 		 * should be enabled (user may turn it off later)
@@ -4636,7 +4740,7 @@
 		/* Do we want to just set the transmit key index ? */
 		int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
 		if ((index>=0) && (index<(cap_rid.softCap&0x80)?4:1)) {
-			set_wep_key(local, index, 0, 0, 1);
+			set_wep_key(local, index, 0, 0, 1, 1);
 		} else
 			/* Don't complain if only change the mode */
 			if(!dwrq->flags & IW_ENCODE_MODE) {
@@ -4841,7 +4945,7 @@
 	readCapabilityRid(local, &cap_rid);
 
 	dwrq->length = sizeof(struct iw_range);
-	memset(range, 0, sizeof(range));
+	memset(range, 0, sizeof(*range));
 	range->min_nwid = 0x0000;
 	range->max_nwid = 0x0000;
 	range->num_channels = 14;
@@ -5132,7 +5236,7 @@
 	Resp rsp;
 
 	/* Note : you may have realised that, as this is a SET operation,
-	 * this is priviledged and therefore a normal user can't
+	 * this is privileged and therefore a normal user can't
 	 * perform scanning.
 	 * This is not an error, while the device perform scanning,
 	 * traffic doesn't flow, so it's a perfect DoS...
@@ -5154,7 +5258,7 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Translate scan data returned from the card to a card independant
+ * Translate scan data returned from the card to a card independent
  * format that the Wireless Tools will understand - Jean II
  */
 static inline char *airo_translate_scan(struct net_device *dev,
@@ -5281,7 +5385,7 @@
 	 * consequences are begnign. So I don't bother fixing it - Javier */
 
 	/* Try to read the first entry of the scan result */
-	rc = PC4500_readrid(ai, RID_BSSLISTFIRST, &BSSList, sizeof(BSSList));
+	rc = PC4500_readrid(ai, RID_BSSLISTFIRST, &BSSList, sizeof(BSSList), 1);
 	if((rc) || (BSSList.index == 0xffff)) {
 		/* Client error, no scan results...
 		 * The caller need to restart the scan. */
@@ -5297,7 +5401,7 @@
 
 		/* Read next entry */
 		rc = PC4500_readrid(ai, RID_BSSLISTNEXT,
-				    &BSSList, sizeof(BSSList));
+				    &BSSList, sizeof(BSSList), 1);
 	}
 	/* Length of data */
 	dwrq->length = (current_ev - extra);
@@ -5307,6 +5411,7 @@
 }
 #endif	/* WIRELESS_EXT > 13 */
 
+#if WIRELESS_EXT <= 15
 #ifdef WIRELESS_SPY
 /*------------------------------------------------------------------*/
 /*
@@ -5369,6 +5474,7 @@
 	return 0;
 }
 #endif			/* WIRELESS_SPY */
+#endif /* WIRELESS_EXT <= 15 */
 
 /*------------------------------------------------------------------*/
 /*
@@ -5387,9 +5493,22 @@
 
 	/* Some of the "SET" function may have modified some of the
 	 * parameters. It's now time to commit them in the card */
-	disable_MAC(local);
-	writeConfigRid(local);
-	enable_MAC(local, &rsp);
+	disable_MAC(local, 1);
+	if (local->need_commit > 1) {
+		APListRid APList_rid;
+		SsidRid SSID_rid;
+
+		readAPListRid(local, &APList_rid);
+		readSsidRid(local, &SSID_rid);
+		reset_airo_card(dev);
+		disable_MAC(local, 1);
+		writeSsidRid(local, &SSID_rid);
+		writeAPListRid(local, &APList_rid);
+	}
+	writeConfigRid(local, 1);
+	enable_MAC(local, &rsp, 1);
+	if (local->need_commit > 1)
+		airo_set_promisc(local);
 
 	return 0;
 }
@@ -5426,6 +5545,12 @@
 	(iw_handler) NULL,			/* SIOCGIWPRIV */
 	(iw_handler) NULL,			/* SIOCSIWSTATS */
 	(iw_handler) NULL,			/* SIOCGIWSTATS */
+#if WIRELESS_EXT > 15
+	iw_handler_set_spy,			/* SIOCSIWSPY */
+	iw_handler_get_spy,			/* SIOCGIWSPY */
+	iw_handler_set_thrspy,			/* SIOCSIWTHRSPY */
+	iw_handler_get_thrspy,			/* SIOCGIWTHRSPY */
+#else /* WIRELESS_EXT > 15 */
 #ifdef WIRELESS_SPY
 	(iw_handler) airo_set_spy,		/* SIOCSIWSPY */
 	(iw_handler) airo_get_spy,		/* SIOCGIWSPY */
@@ -5435,6 +5560,7 @@
 #endif	/* WIRELESS_SPY */
 	(iw_handler) NULL,			/* -- hole -- */
 	(iw_handler) NULL,			/* -- hole -- */
+#endif /* WIRELESS_EXT > 15 */
 	(iw_handler) airo_set_wap,		/* SIOCSIWAP */
 	(iw_handler) airo_get_wap,		/* SIOCGIWAP */
 	(iw_handler) NULL,			/* -- hole -- */
@@ -5488,6 +5614,10 @@
 	standard:	(iw_handler *) airo_handler,
 	private:	(iw_handler *) airo_private_handler,
 	private_args:	(struct iw_priv_args *) airo_private_args,
+#if WIRELESS_EXT > 15
+	spy_offset:	((void *) (&((struct airo_info *) NULL)->spy_data) -
+			   (void *) NULL),
+#endif /* WIRELESS_EXT > 15 */
 };
 
 #endif /* WIRELESS_EXT > 12 */
@@ -5822,7 +5952,7 @@
 			break;
 		}
 
-		/* Seperate R/W functions bracket legality here
+		/* Separate R/W functions bracket legality here
 		 */
 		if ( com.command <= AIROGMICSTATS )
 			rc = readrids(dev,&com);
@@ -5860,7 +5990,6 @@
  *
  * TODO :
  *	o Check if work in Ad-Hoc mode (otherwise, use SPY, as in wvlan_cs)
- *	o Find the noise level
  *
  * Jean
  */
@@ -5873,7 +6002,7 @@
 
 	/* Get stats out of the card */
 	readStatusRid(local, &status_rid);
-	readStatsRid(local, &stats_rid, RID_STATS);
+	readStatsRid(local, &stats_rid, RID_STATS, 1);
 
 	/* The status */
 	local->wstats.status = status_rid.mode;
@@ -5884,8 +6013,13 @@
 		local->wstats.qual.level = 0x100 - local->rssi[status_rid.sigQuality].rssidBm;
 	else
 		local->wstats.qual.level = (status_rid.normalizedSignalStrength + 321) / 2;
-	local->wstats.qual.noise = 0;
-	local->wstats.qual.updated = 3;
+	if (status_rid.len >= 124) {
+		local->wstats.qual.noise = 256 - status_rid.noisedBm;
+		local->wstats.qual.updated = 7;
+	} else {
+		local->wstats.qual.noise = 0;
+		local->wstats.qual.updated = 3;
+	}
 
 	/* Packets discarded in the wireless adapter due to wireless
 	 * specific problems */
@@ -5900,6 +6034,7 @@
 #endif /* WIRELESS_EXT */
 
 #ifdef CISCO_EXT
+#define RIDS_SIZE	2048
 /*
  * This just translates from driver IOCTL codes to the command codes to
  * feed to the radio's host interface. Things can be added/deleted
@@ -5908,7 +6043,7 @@
  */
 static int readrids(struct net_device *dev, aironet_ioctl *comp) {
 	unsigned short ridcode;
-	unsigned char iobuf[2048];
+	unsigned char *iobuf;
 	struct airo_info *ai = dev->priv;
 
 	if (ai->flags & FLAG_FLASHING)
@@ -5917,7 +6052,7 @@
 	switch(comp->command)
 	{
 	case AIROGCAP:      ridcode = RID_CAPABILITIES; break;
-	case AIROGCFG: writeConfigRid (ai);
+	case AIROGCFG: writeConfigRid (ai, 1);
 			    ridcode = RID_CONFIG;       break;
 	case AIROGSLIST:    ridcode = RID_SSID;         break;
 	case AIROGVLIST:    ridcode = RID_APLIST;       break;
@@ -5946,15 +6081,21 @@
 		break;
 	}
 
-	PC4500_readrid(ai,ridcode,iobuf,sizeof(iobuf));
+	if ((iobuf = kmalloc(RIDS_SIZE, GFP_KERNEL)) == NULL)
+		return -ENOMEM;
+
+	PC4500_readrid(ai,ridcode,iobuf,RIDS_SIZE, 1);
 	/* 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
 	 */
 
 	if (copy_to_user(comp->data, iobuf,
-			 min((int)comp->len, (int)sizeof(iobuf))))
+			 min((int)comp->len, (int)RIDS_SIZE))) {
+		kfree (iobuf);
 		return -EFAULT;
+	}
+	kfree (iobuf);
 	return 0;
 }
 
@@ -5966,8 +6107,8 @@
 	struct airo_info *ai = dev->priv;
 	int  ridcode, enabled;
 	Resp      rsp;
-	static int (* writer)(struct airo_info *, u16 rid, const void *, int);
-	unsigned char iobuf[2048];
+	static int (* writer)(struct airo_info *, u16 rid, const void *, int, int);
+	unsigned char *iobuf;
 
 	/* Only super-user can write RIDs */
 	if (!capable(CAP_NET_ADMIN))
@@ -5996,7 +6137,7 @@
 		 * same with MAC off
 		 */
 	case AIROPMACON:
-		if (enable_MAC(ai, &rsp) != 0)
+		if (enable_MAC(ai, &rsp, 1) != 0)
 			return -EIO;
 		return 0;
 
@@ -6005,7 +6146,7 @@
 		 * as disable_MAC. it's probably so short the compiler does not gen one.
 		 */
 	case AIROPMACOFF:
-		disable_MAC(ai);
+		disable_MAC(ai, 1);
 		return 0;
 
 		/* This command merely clears the counts does not actually store any data
@@ -6013,25 +6154,36 @@
 		 * writerid routines.
 		 */
 	case AIROPSTCLR:
-		PC4500_readrid(ai,RID_STATSDELTACLEAR,iobuf,sizeof(iobuf));
+		if ((iobuf = kmalloc(RIDS_SIZE, GFP_KERNEL)) == NULL)
+			return -ENOMEM;
+
+		PC4500_readrid(ai,RID_STATSDELTACLEAR,iobuf,RIDS_SIZE, 1);
 
 		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))))
+				 min((int)comp->len, (int)RIDS_SIZE))) {
+			kfree (iobuf);
 			return -EFAULT;
+		}
+		kfree (iobuf);
 		return 0;
 
 	default:
 		return -EOPNOTSUPP;	/* Blarg! */
 	}
-	if(comp->len > sizeof(iobuf))
+	if(comp->len > RIDS_SIZE)
 		return -EINVAL;
 
-	if (copy_from_user(iobuf,comp->data,comp->len))
+	if ((iobuf = kmalloc(RIDS_SIZE, GFP_KERNEL)) == NULL)
+		return -ENOMEM;
+
+	if (copy_from_user(iobuf,comp->data,comp->len)) {
+		kfree (iobuf);
 		return -EFAULT;
+	}
 
 	if (comp->command == AIROPCFG) {
 		ConfigRid *cfg = (ConfigRid *)iobuf;
@@ -6045,8 +6197,11 @@
 			ai->flags &= ~FLAG_ADHOC;
 	}
 
-	if((*writer)(ai, ridcode, iobuf,comp->len))
+	if((*writer)(ai, ridcode, iobuf,comp->len,1)) {
+		kfree (iobuf);
 		return -EIO;
+	}
+	kfree (iobuf);
 	return 0;
 }
 
@@ -6125,7 +6280,7 @@
  */
 
 int cmdreset(struct airo_info *ai) {
-	disable_MAC(ai);
+	disable_MAC(ai, 1);
 
 	if(!waitbusy (ai)){
 		printk(KERN_INFO "Waitbusy hang before RESET\n");

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)