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

Next file: linux/drivers/net/wireless/airo_cs.c
Previous file: linux/drivers/net/winbond-840.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.9/linux/drivers/net/wireless/airo.c linux/drivers/net/wireless/airo.c
@@ -28,7 +28,7 @@
 
 #include <linux/sched.h>
 #include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/interrupt.h>
@@ -44,6 +44,7 @@
 #include <linux/ioport.h>
 #include <linux/config.h>
 #include <linux/pci.h>
+#include <asm/uaccess.h>
 
 #ifdef CONFIG_PCI
 static struct pci_device_id card_ids[] = __devinitdata {
@@ -69,11 +70,12 @@
 
 /* Include Wireless Extension definition and check version - Jean II */
 #include <linux/wireless.h>
+#define WIRELESS_SPY		// enable iwspy support
 #if WIRELESS_EXT < 9
 #warning "Wireless extension v9 or newer required - please upgrade your kernel"
 #undef WIRELESS_EXT
+#undef WIRELESS_SPY
 #endif
-#define WIRELESS_SPY		// enable iwspy support
 #define CISCO_EXT		// enable Cisco extensions
 
 #ifdef CISCO_EXT
@@ -226,6 +228,7 @@
 MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet \
                    cards.  Direct support for ISA/PCI cards and support \
 		   for PCMCIA when used with airo_cs.");
+MODULE_LICENSE("Dual BSD/GPL");
 MODULE_SUPPORTED_DEVICE("Aironet 4500, 4800 and Cisco 340");
 MODULE_PARM(io,"1-4i");
 MODULE_PARM(irq,"1-4i");
@@ -273,6 +276,7 @@
 #define NOP 0x0010
 #define MAC_ENABLE 0x0001
 #define MAC_DISABLE 0x0002
+#define CMD_LOSE_SYNC 0x0003 /* Not sure what this does... */
 #define CMD_ACCESS 0x0021
 #define CMD_ALLOCATETX 0x000a
 #define CMD_TRANSMIT 0x000b
@@ -280,6 +284,7 @@
 #define CMD_SETMODE 0x0009
 #define CMD_ENABLEAUX 0x0111
 #define CMD_SOFTRESET 0x0004
+#define CMD_LISTBSS 0x0103
 
 /* Registers */
 #define COMMAND 0x00
@@ -351,6 +356,22 @@
 #define RID_STATS      0xFF68
 #define RID_STATSDELTA 0xFF69
 #define RID_STATSDELTACLEAR 0xFF6A
+#define RID_BSSLISTFIRST 0xFF72
+#define RID_BSSLISTNEXT  0xFF73
+
+typedef struct {
+	u16 cmd;
+	u16 parm0;
+	u16 parm1;
+	u16 parm2;
+} Cmd;
+
+typedef struct {
+	u16 status;
+	u16 rsp0;
+	u16 rsp1;
+	u16 rsp2;
+} Resp;
 
 /*
  * Rids and endian-ness:  The Rids will always be in cpu endian, since
@@ -358,6 +379,9 @@
  * so all rid access should use the read/writeXXXRid routines.
  */
 
+/* This is redundant for x86 archs, but it seems necessary for ARM */
+#pragma pack(1)
+
 /* This structure came from an email sent to me from an engineer at
    aironet for inclusion into this driver */
 typedef struct {
@@ -388,20 +412,6 @@
 } ModulationRid;
 
 typedef struct {
-	u16 cmd;
-	u16 parm0;
-	u16 parm1;
-	u16 parm2;
-} Cmd;
-
-typedef struct {
-	u16 status;
-	u16 rsp0;
-	u16 rsp1;
-	u16 rsp2;
-} Resp;
-
-typedef struct {
 	u16 len; /* sizeof(ConfigRid) */
 	u16 opmode; /* operating mode */
 #define MODE_STA_IBSS 0
@@ -496,7 +506,10 @@
 	u16 rssiThreshold;
 #define RSSI_DEFAULT 0
         u16 modulation;
-	u16 shortPreamble;
+#define PREAMBLE_AUTO 0
+#define PREAMBLE_LONG 1
+#define PREAMBLE_SHORT 2
+	u16 preamble;
 	u16 homeProduct;
 	u16 radioSpecific;
 	/*---------- Aironet Extensions ----------*/
@@ -559,6 +572,7 @@
 typedef struct {
 	u16 len;
 	char oui[3];
+	char zero;
 	u16 prodNum;
 	char manName[32];
 	char prodName[16];
@@ -583,6 +597,38 @@
 	u16 requiredHard;
 } CapabilityRid;
 
+typedef struct {
+  u16 len;
+  u16 index; /* First is 0 and 0xffff means end of list */
+#define RADIO_FH 1 /* Frequency hopping radio type */
+#define RADIO_DS 2 /* Direct sequence radio type */
+#define RADIO_TMA 4 /* Proprietary radio used in old cards (2500) */
+  u16 radioType; 
+  u8 bssid[6]; /* Mac address of the BSS */
+  u8 zero;
+  u8 ssidLen;
+  u8 ssid[32];
+  u16 rssi;
+#define CAP_ESS (1<<0)
+#define CAP_IBSS (1<<1)
+#define CAP_PRIVACY (1<<4)
+#define CAP_SHORTHDR (1<<5)
+  u16 cap;
+  u16 beaconInterval;
+  u8 rates[8]; /* Same as rates for config rid */
+  struct { /* For frequency hopping only */
+    u16 dwell;
+    u8 hopSet;
+    u8 hopPattern;
+    u8 hopIndex;
+    u8 fill;
+  } fh;
+  u16 dsChannel;
+  u16 atimWindow;
+} BSSListRid;
+
+#pragma pack()
+
 #define TXCTL_TXOK (1<<1) /* report if tx is ok */
 #define TXCTL_TXEX (1<<2) /* report if tx fails */
 #define TXCTL_802_3 (0<<3) /* 802.3 packet */
@@ -661,7 +707,7 @@
 } wep_key_t;
 #endif /* WIRELESS_EXT */
 
-static const char version[] = "airo.c 0.2 (Ben Reed & Javier Achirica)";
+static const char version[] = "airo.c 0.3 (Ben Reed & Javier Achirica)";
 
 struct airo_info;
 
@@ -749,6 +795,35 @@
 static int takedown_proc_entry( struct net_device *dev,
 				struct airo_info *apriv );
 
+static int readBSSListRid(struct airo_info *ai, int first,
+		      BSSListRid *list) {
+	int rc;
+			Cmd cmd;
+			Resp rsp;
+
+	if (first == 1) {
+			memset(&cmd, 0, sizeof(cmd));
+			cmd.cmd=CMD_LISTBSS;
+			issuecommand(ai, &cmd, &rsp);
+			/* Let the command take effect */
+			set_current_state (TASK_INTERRUPTIBLE);
+			schedule_timeout (3*HZ);
+		}
+	rc = PC4500_readrid(ai, 
+		            first ? RID_BSSLISTFIRST : RID_BSSLISTNEXT,
+			    list, sizeof(*list));
+
+	list->len = le16_to_cpu(list->len);
+	list->index = le16_to_cpu(list->index);
+	list->radioType = le16_to_cpu(list->radioType);
+	list->cap = le16_to_cpu(list->cap);
+	list->beaconInterval = le16_to_cpu(list->beaconInterval);
+	list->fh.dwell = le16_to_cpu(list->fh.dwell);
+	list->dsChannel = le16_to_cpu(list->dsChannel);
+	list->atimWindow = le16_to_cpu(list->atimWindow);
+	return rc;
+}
+
 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));
@@ -918,7 +993,6 @@
 	
 	len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; /* check min length*/
 	buffer = skb->data;
-	
 	status = transmit_802_3_packet( priv, 
 					fids[i],
 					skb->data, len );
@@ -1167,7 +1241,6 @@
 	struct airo_info *apriv = (struct airo_info *)dev->priv;
 	u16 savedInterrupts;
 	
-
 	if (!netif_device_present(dev))
 		return;
 	
@@ -1228,7 +1301,7 @@
 	/* Check to see if there is something to receive */
 	if ( status & EV_RX  ) {
 		struct sk_buff *skb = NULL;
-		int flags;
+		long flags;
 		u16 fc, len, hdrlen = 0;
 		struct {
 			u16 status, len;
@@ -1362,6 +1435,16 @@
 			if(index!=-1)
 				apriv->stats.tx_bytes += len;
 		} else {
+			if (bap_setup(apriv, fid, 0x0004, BAP1) == SUCCESS) {
+				u16 status;
+				bap_read(apriv, &status, 2, BAP1);
+				if (le16_to_cpu(status) & 2)
+					apriv->stats.tx_aborted_errors++;
+				if (le16_to_cpu(status) & 4)
+					apriv->stats.tx_heartbeat_errors++;
+				if (le16_to_cpu(status) & 0x10)
+					apriv->stats.tx_carrier_errors++;
+			}
 			apriv->stats.tx_errors++;
 		}
 	}
@@ -1559,7 +1642,7 @@
         // Im really paranoid about letting it run forever!
 	int max_tries = 600000;  
         int rc = SUCCESS;
-	int flags;
+	long flags;
 
 	spin_lock_irqsave(&ai->cmd_lock, flags);
 	OUT4500(ai, PARAM0, pCmd->parm0);
@@ -1664,7 +1747,7 @@
 	u16 next;
 	int words;
 	int i;
-	int flags;
+	long flags;
 
 	spin_lock_irqsave(&ai->aux_lock, flags);
 	page = IN4500(ai, SWS0+whichbap);
@@ -1738,7 +1821,7 @@
 static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len)
 {
 	u16 status;
-        int flags;
+        long flags;
         int rc = SUCCESS;
 
 	spin_lock_irqsave(&ai->bap1_lock, flags);
@@ -1753,7 +1836,7 @@
 	// read the rid length field
 	bap_read(ai, pBuf, 2, BAP1);
 	// length for remaining part of rid
-	len = min(unsigned int, len, le16_to_cpu(*(u16*)pBuf)) - 2;
+	len = min_t(unsigned int, len, le16_to_cpu(*(u16*)pBuf)) - 2;
 	
 	if ( len <= 2 ) {
 		printk( KERN_ERR 
@@ -1780,7 +1863,7 @@
 			   const void *pBuf, int len)
 {
 	u16 status;
-        int flags;
+        long flags;
 	int rc = SUCCESS;
 
 	spin_lock_irqsave(&ai->bap1_lock, flags);
@@ -1810,7 +1893,7 @@
 	Resp rsp;
 	u16 txFid;
 	u16 txControl;
-        int flags;
+        long flags;
 
 	cmd.cmd = CMD_ALLOCATETX;
 	cmd.parm0 = lenPayload;
@@ -1879,12 +1962,6 @@
  *  like!  Feel free to clean it up!
  */
 
-/*
- *  Unfortunately sometime between 2.0 and 2.2 the proc interface changed...
- *  Unfortunately I dont know when it was...
- *  Im guessing it is sometime around 0x20155...  Anybody know?
- */
-
 static ssize_t proc_read( struct file *file,
 			  char *buffer,
 			  size_t len,
@@ -1901,6 +1978,7 @@
 static int proc_status_open( struct inode *inode, struct file *file );
 static int proc_SSID_open( struct inode *inode, struct file *file );
 static int proc_APList_open( struct inode *inode, struct file *file );
+static int proc_BSSList_open( struct inode *inode, struct file *file );
 static int proc_config_open( struct inode *inode, struct file *file );
 static int proc_wepkey_open( struct inode *inode, struct file *file );
 
@@ -1929,6 +2007,13 @@
 	release:       proc_close
 };
 
+static struct file_operations proc_BSSList_ops = {
+	read:          proc_read,
+	write:         proc_write,
+	open:          proc_BSSList_open,
+	release:       proc_close
+};
+
 static struct file_operations proc_APList_ops = {
 	read:          proc_read,
 	write:         proc_write,
@@ -1962,6 +2047,10 @@
 	void (*on_close) (struct inode *, struct file *);
 };
 
+#ifndef SETPROC_OPS
+#define SETPROC_OPS(entry, ops) (entry)->proc_fops = &(ops)
+#endif
+
 static int setup_proc_entry( struct net_device *dev,
 			     struct airo_info *apriv ) {
 	struct proc_dir_entry *entry;
@@ -1979,11 +2068,7 @@
         entry->uid = proc_uid;
         entry->gid = proc_gid;
 	entry->data = dev;
-/*	This is what was needed right up to the last few versions
-        of 2.3:
-	entry->ops = &proc_inode_statsdelta_ops;
-*/
-	entry->proc_fops = &proc_statsdelta_ops;
+	SETPROC_OPS(entry, proc_statsdelta_ops);
 	
 	/* Setup the Stats */
 	entry = create_proc_entry("Stats",
@@ -1992,7 +2077,7 @@
         entry->uid = proc_uid;
         entry->gid = proc_gid;
 	entry->data = dev;
-	entry->proc_fops = &proc_stats_ops;
+	SETPROC_OPS(entry, proc_stats_ops);
 	
 	/* Setup the Status */
 	entry = create_proc_entry("Status",
@@ -2001,7 +2086,7 @@
         entry->uid = proc_uid;
         entry->gid = proc_gid;
 	entry->data = dev;
-	entry->proc_fops = &proc_status_ops;
+	SETPROC_OPS(entry, proc_status_ops);
 	
 	/* Setup the Config */
 	entry = create_proc_entry("Config",
@@ -2010,7 +2095,7 @@
         entry->uid = proc_uid;
         entry->gid = proc_gid;
 	entry->data = dev;
-	entry->proc_fops = &proc_config_ops;
+	SETPROC_OPS(entry, proc_config_ops);
 
 	/* Setup the SSID */
 	entry = create_proc_entry("SSID",
@@ -2019,7 +2104,7 @@
         entry->uid = proc_uid;
         entry->gid = proc_gid;
 	entry->data = dev;
-	entry->proc_fops = &proc_SSID_ops;
+	SETPROC_OPS(entry, proc_SSID_ops);
 
 	/* Setup the APList */
 	entry = create_proc_entry("APList",
@@ -2028,7 +2113,16 @@
         entry->uid = proc_uid;
         entry->gid = proc_gid;
 	entry->data = dev;
-	entry->proc_fops = &proc_APList_ops;
+	SETPROC_OPS(entry, proc_APList_ops);
+
+	/* Setup the BSSList */
+	entry = create_proc_entry("BSSList",
+				  S_IFREG | proc_perm,
+				  apriv->proc_entry);
+	entry->uid = proc_uid;
+	entry->gid = proc_gid;
+	entry->data = dev;
+	SETPROC_OPS(entry, proc_BSSList_ops);
 
 	/* Setup the WepKey */
 	entry = create_proc_entry("WepKey",
@@ -2037,7 +2131,7 @@
         entry->uid = proc_uid;
         entry->gid = proc_gid;
 	entry->data = dev;
-	entry->proc_fops = &proc_wepkey_ops;
+	SETPROC_OPS(entry, proc_wepkey_ops);
 
 	return 0;
 }
@@ -2051,6 +2145,7 @@
 	remove_proc_entry("Config",apriv->proc_entry);
 	remove_proc_entry("SSID",apriv->proc_entry);
 	remove_proc_entry("APList",apriv->proc_entry);
+	remove_proc_entry("BSSList",apriv->proc_entry);
 	remove_proc_entry("WepKey",apriv->proc_entry);
 	remove_proc_entry(dev->name,airo_entry);
 	return 0;
@@ -2124,6 +2219,7 @@
 	struct airo_info *apriv = (struct airo_info *)dev->priv;
 	CapabilityRid cap_rid;
 	StatusRid status_rid;
+	int i;
 	
 	MOD_INC_USE_COUNT;
 	
@@ -2141,7 +2237,17 @@
 	readStatusRid(apriv, &status_rid);
 	readCapabilityRid(apriv, &cap_rid);
 	
-	sprintf( data->rbuffer, "Mode: %x\n"
+        i = sprintf(data->rbuffer, "Status: %s%s%s%s%s%s%s%s%s\n",
+                    status_rid.mode & 1 ? "CFG ": "",
+                    status_rid.mode & 2 ? "ACT ": "",
+                    status_rid.mode & 0x10 ? "SYN ": "",
+                    status_rid.mode & 0x20 ? "LNK ": "",
+                    status_rid.mode & 0x40 ? "LEAP ": "",
+                    status_rid.mode & 0x80 ? "PRIV ": "",
+                    status_rid.mode & 0x100 ? "KEY ": "",
+                    status_rid.mode & 0x200 ? "WEP ": "",
+                    status_rid.mode & 0x8000 ? "ERR ": "");
+	sprintf( data->rbuffer+i, "Mode: %x\n"
 		 "Signal Strength: %d\n"
 		 "Signal Quality: %d\n"
 		 "SSID: %-.*s\n"
@@ -2425,6 +2531,14 @@
 			default:
 				printk( KERN_WARNING "airo: Unknown modulation\n" );
 			}
+		} else if (!strncmp(line, "Preamble: ", 10)) {
+			line += 10;
+			switch(*line) {
+			case 'a': config.preamble=PREAMBLE_AUTO; break;
+			case 'l': config.preamble=PREAMBLE_LONG; break;
+			case 's': config.preamble=PREAMBLE_SHORT; break;
+		        default: printk(KERN_WARNING "airo: Unknown preamble\n");
+			}
 		} else {
 			printk( KERN_WARNING "Couldn't figure out %s\n", line );
 		}
@@ -2516,7 +2630,8 @@
 		 "RXDiversity: %s\n"
 		 "FragThreshold: %d\n"
 		 "WEP: %s\n"
-		 "Modulation: %s\n",
+		 "Modulation: %s\n"
+		 "Preamble: %s\n",
 		 (int)config.longRetryLimit,
 		 (int)config.shortRetryLimit,
 		 (int)config.rtsThres,
@@ -2531,7 +2646,10 @@
 		 config.authType == AUTH_SHAREDKEY ? "shared" : "open",
 		 config.modulation == 0 ? "default" :
 		 config.modulation == MOD_CCK ? "cck" :
-		 config.modulation == MOD_MOK ? "mok" : "error"
+		 config.modulation == MOD_MOK ? "mok" : "error",
+		 config.preamble == PREAMBLE_AUTO ? "auto" :
+		 config.preamble == PREAMBLE_LONG ? "long" :
+		 config.preamble == PREAMBLE_SHORT ? "short" : "error"
 		);
 	data->readlen = strlen( data->rbuffer );
 	return 0;
@@ -2862,6 +2980,76 @@
 	return 0;
 }
 
+static int proc_BSSList_open( struct inode *inode, struct file *file ) {
+	struct proc_data *data;
+	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct net_device *dev = dp->data;
+	struct airo_info *ai = (struct airo_info*)dev->priv;
+	char *ptr;
+	BSSListRid BSSList_rid;
+	int rc;
+	/* If doLoseSync is not 1, we won't do a Lose Sync */
+	int doLoseSync = -1;
+        
+	MOD_INC_USE_COUNT;
+	
+	dp = (struct proc_dir_entry *) inode->u.generic_ip;
+	
+	if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
+		return -ENOMEM;
+	memset(file->private_data, 0, sizeof(struct proc_data));
+	data = (struct proc_data *)file->private_data;
+	if ((data->rbuffer = kmalloc( 1024, GFP_KERNEL )) == NULL) {
+		kfree (file->private_data);
+		return -ENOMEM;
+	}
+	data->writelen = 0;
+	data->maxwritelen = 0;
+	data->wbuffer = 0;
+	data->on_close = 0;
+	
+	if (file->f_mode & FMODE_WRITE) {
+		if (!(file->f_mode & FMODE_READ)) {
+			Cmd cmd;
+			Resp rsp;
+                        
+			memset(&cmd, 0, sizeof(cmd));
+			cmd.cmd=CMD_LISTBSS;
+			issuecommand(ai, &cmd, &rsp);
+			data->readlen = 0;
+			return 0;
+		}
+		doLoseSync = 1;
+	}
+	ptr = data->rbuffer;
+	/* There is a race condition here if there are concurrent opens.
+           Since it is a rare condition, we'll just live with it, otherwise
+           we have to add a spin lock... */
+	rc = readBSSListRid(ai, doLoseSync, &BSSList_rid);
+	while(rc == 0 && BSSList_rid.index != 0xffff) {
+		ptr += sprintf(ptr, "%02x:%02x:%02x:%02x:%02x:%02x %*s rssi = %d",
+				(int)BSSList_rid.bssid[0],
+				(int)BSSList_rid.bssid[1],
+				(int)BSSList_rid.bssid[2],
+				(int)BSSList_rid.bssid[3],
+				(int)BSSList_rid.bssid[4],
+				(int)BSSList_rid.bssid[5],
+				(int)BSSList_rid.ssidLen,
+				BSSList_rid.ssid,
+				(int)BSSList_rid.rssi);
+		ptr += sprintf(ptr, " channel = %d %s %s %s %s\n",
+				(int)BSSList_rid.dsChannel,
+				BSSList_rid.cap & CAP_ESS ? "ESS" : "",
+				BSSList_rid.cap & CAP_IBSS ? "adhoc" : "",
+				BSSList_rid.cap & CAP_PRIVACY ? "wep" : "",
+				BSSList_rid.cap & CAP_SHORTHDR ? "shorthdr" : "");
+		rc = readBSSListRid(ai, 0, &BSSList_rid);
+	}
+	*ptr = '\0';
+	data->readlen = strlen( data->rbuffer );
+	return 0;
+}
+
 static int proc_close( struct inode *inode, struct file *file ) 
 {
 	struct proc_data *data = (struct proc_data *)file->private_data;
@@ -2971,7 +3159,6 @@
 {
 	stop_airo_card(pdev->driver_data, 1);
 }
-
 #endif
 
 static int __init airo_init_module( void )
@@ -3041,14 +3228,13 @@
  */
 static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	int rc = 0;
+	int i, rc = 0;
 #ifdef WIRELESS_EXT
 	struct airo_info *local = (struct airo_info*) dev->priv;
 	struct iwreq *wrq = (struct iwreq *) rq;
 	ConfigRid config;		/* Configuration info */
 	CapabilityRid cap_rid;		/* Card capability info */
 	StatusRid status_rid;		/* Card status info */
-	int i;
 
 #ifdef CISCO_EXT
 	if (cmd != SIOCGIWPRIV && cmd != AIROIOCTL && cmd != AIROIDIFC)
@@ -3557,31 +3743,50 @@
 #endif /* WIRELESS_EXT > 9 */
 
 #if WIRELESS_EXT > 10
-	case SIOCGIWRETRY:
-		wrq->u.retry.disabled = 0;
-		if ((wrq->u.retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME)
-			wrq->u.retry.value = (int)config.txLifetime * 1024;
-		else {
-			wrq->u.retry.value = (int)config.shortRetryLimit;
-			wrq->u.retry.flags = IW_RETRY_LIMIT;
-		}
-		break;
-
-	case SIOCSIWRETRY: 
-		if (wrq->u.retry.disabled) {
-			config.shortRetryLimit = 0;
-			config.longRetryLimit = 0;
-			config.txLifetime = 0;
-			local->need_commit = 1;
+	case SIOCSIWRETRY:
+		if(wrq->u.retry.disabled) {
+			rc = -EINVAL;
 			break;
 		}
-		if ((wrq->u.retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
-			config.txLifetime = (wrq->u.retry.value + 500) / 1024;
+		local->need_commit = 0;
+		if(wrq->u.retry.flags & IW_RETRY_LIMIT) {
+			if(wrq->u.retry.flags & IW_RETRY_MAX)
+				config.longRetryLimit = wrq->u.retry.value;
+			else if (wrq->u.retry.flags & IW_RETRY_MIN)
+				config.shortRetryLimit = wrq->u.retry.value;
+			else {
+				/* No modifier : set both */
+				config.longRetryLimit = wrq->u.retry.value;
+				config.shortRetryLimit = wrq->u.retry.value;
+			}
 			local->need_commit = 1;
-		} else if ((wrq->u.retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIMIT) {
-			config.shortRetryLimit = config.longRetryLimit = wrq->u.retry.value;
+		}
+		if(wrq->u.retry.flags & IW_RETRY_LIFETIME) {
+			config.txLifetime = wrq->u.retry.value / 1024;
 			local->need_commit = 1;
 		}
+		if(local->need_commit == 0) {
+			rc = -EINVAL;
+		}
+		break;
+
+	case SIOCGIWRETRY:
+		wrq->u.retry.disabled = 0;      /* Can't be disabled */
+
+		/* Note : by default, display the min retry number */
+		if((wrq->u.retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
+			wrq->u.retry.flags = IW_RETRY_LIFETIME;
+			wrq->u.retry.value = (int)config.txLifetime * 1024;
+		} else if((wrq->u.retry.flags & IW_RETRY_MAX)) {
+			wrq->u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+			wrq->u.retry.value = (int)config.longRetryLimit;
+		} else {
+			wrq->u.retry.flags = IW_RETRY_LIMIT;
+			wrq->u.retry.value = (int)config.shortRetryLimit;
+			if((int)config.shortRetryLimit != (int)config.longRetryLimit)
+				wrq->u.retry.flags |= IW_RETRY_MIN;
+		}
+
 		break;
 #endif /* WIRELESS_EXT > 10 */
 
@@ -3593,8 +3798,7 @@
 			int		k;
 
 			wrq->u.data.length = sizeof(range);
-			/* Should adapt depending on max rate */
-			range.throughput = 1.6 * 1024 * 1024;
+			memset(&range, 0, sizeof(range));
 			range.min_nwid = 0x0000;
 			range.max_nwid = 0x0000;
 			range.num_channels = 14;
@@ -3621,6 +3825,14 @@
 			}
 			range.num_bitrates = i;
 
+			/* Set an indication of the max TCP throughput
+			 * in bit/s that we can expect using this interface.
+			 * May be use for QoS stuff... Jean II */
+			if(i > 2)
+				range.throughput = 5 * 1000 * 1000;
+			else
+				range.throughput = 1.5 * 1000 * 1000;
+
 			range.min_rts = 0;
 			range.max_rts = 2312;
 			range.min_frag = 256;
@@ -3753,15 +3965,53 @@
 
 	case SIOCGIWAPLIST:
 		if (wrq->u.data.pointer) {
-			int i;
-			struct sockaddr s[4];
-
-			for (i = 0; i < 4; i++) {
-				memcpy(s[i].sa_data, status_rid.bssid[i], 6);
+			int i, rc;
+			struct sockaddr s[IW_MAX_AP];
+			struct iw_quality qual[IW_MAX_AP];
+			BSSListRid BSSList;
+			int loseSync = capable(CAP_NET_ADMIN) ? 1: -1;
+			for (i = 0; i < IW_MAX_AP; i++) {
+				if (readBSSListRid(local, loseSync, &BSSList))
+					break;
+				loseSync = 0;
+				memcpy(s[i].sa_data, BSSList.bssid, 6);
 				s[i].sa_family = ARPHRD_ETHER;
+				qual[i].level = BSSList.rssi;
+				qual[i].qual = qual[i].noise = 0;
+				qual[i].updated = 2;
+				if (BSSList.index == 0xffff) break;
+			}
+			if (!i) {
+				for (i = 0; 
+				     i < min(IW_MAX_AP, 4) &&
+					     (status_rid.bssid[i][0]
+					      & status_rid.bssid[i][1]
+					      & status_rid.bssid[i][2]
+					      & status_rid.bssid[i][3]
+					      & status_rid.bssid[i][4]
+					      & status_rid.bssid[i][5])!=-1 &&
+					     (status_rid.bssid[i][0]
+					      | status_rid.bssid[i][1]
+					      | status_rid.bssid[i][2]
+					      | status_rid.bssid[i][3]
+					      | status_rid.bssid[i][4]
+					      | status_rid.bssid[i][5]);
+				     i++) {
+					memcpy(s[i].sa_data, 
+					       status_rid.bssid[i], 6);
+					s[i].sa_family = ARPHRD_ETHER;
+				}
+			} else {
+				wrq->u.data.flags = 1; /* Should be define'd */
+				if (copy_to_user(wrq->u.data.pointer
+						 + sizeof(struct sockaddr)*i,
+						 &qual,
+						 sizeof(struct iw_quality)*i))
+					rc = -EFAULT;
 			}
-			wrq->u.data.length = 4;
-			if (copy_to_user(wrq->u.data.pointer, &s, sizeof(s)))
+			wrq->u.data.length = i;
+			if (copy_to_user(wrq->u.data.pointer, &s, 
+					 sizeof(struct sockaddr)*i))
 				rc = -EFAULT;
 		}
 		break;
@@ -3997,7 +4247,7 @@
 	 */
 
 	if (copy_to_user(comp->data, iobuf,
-			 min(unsigned int, comp->len, sizeof(iobuf))))
+			 min_t(unsigned int, comp->len, sizeof(iobuf))))
 		return -EFAULT;
 	return 0;
 }
@@ -4057,7 +4307,7 @@
 		PC4500_readrid(dev->priv,ridcode,iobuf,sizeof(iobuf));
 
 		if (copy_to_user(comp->data, iobuf,
-				 min(unsigned int, comp->len, sizeof(iobuf))))
+				 min_t(unsigned int, comp->len, sizeof(iobuf))))
 			return -EFAULT;
 		return 0;
 

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