Minor improvement of orinoco driver

Jean Tourrilhes jt at bougret.hpl.hp.com
Fri Dec 14 08:53:42 EST 2001


	Hi David,

	I've made some minor improvement to the Wireless Extension
support of the Orinoco driver (some stuff we were talking about a
month ago).
	Would you mind having a quick look at the patch attached and
send me your comments ?

	Have fun...

	Jean
-------------- next part --------------
diff -u -p -r linux/drivers/net/wireless-w12/orinoco.c linux/drivers/net/wireless/orinoco.c
--- linux/drivers/net/wireless-w12/orinoco.c	Tue Dec 11 15:36:06 2001
+++ linux/drivers/net/wireless/orinoco.c	Thu Dec 13 13:36:48 2001
@@ -263,8 +263,11 @@
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/etherdevice.h>
-#include <linux/wireless.h>
 #include <linux/list.h>
+#include <linux/wireless.h>
+#if WIRELESS_EXT > 12
+#include <net/iw_handler.h>
+#endif	/* WIRELESS_EXT > 12 */
 
 #include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
@@ -279,10 +282,21 @@
 #include "orinoco.h"
 #include "ieee802_11.h"
 
-/* Wireless extensions backwares compatibility */
+#if WIRELESS_EXT <= 12
+/* Wireless extensions backward compatibility */
+
+/* Part of iw_handler prototype we need */
+struct iw_request_info
+{
+	__u16		cmd;		/* Wireless Extension command */
+	__u16		flags;		/* More to come ;-) */
+};
+
+/* Private ioctl is migrating to a new range... */
 #ifndef SIOCIWFIRSTPRIV
 #define SIOCIWFIRSTPRIV		SIOCDEVPRIVATE
 #endif /* SIOCIWFIRSTPRIV */
+#endif	/* WIRELESS_EXT <= 12 */
 
 static char version[] __initdata = "orinoco.c 0.08b (David Gibson <hermes at gibson.dropbear.id.au> and others)";
 MODULE_AUTHOR("David Gibson <hermes at gibson.dropbear.id.au>");
@@ -439,6 +453,8 @@ static void __orinoco_ev_txexc(struct or
 static void __orinoco_ev_tx(struct orinoco_private *priv, hermes_t *hw);
 static void __orinoco_ev_alloc(struct orinoco_private *priv, hermes_t *hw);
 
+#if 0
+/* Either we fix those prototypes or we get rid of them - Jean II */
 static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq);
 static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq);
 static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq);
@@ -458,6 +474,7 @@ static int orinoco_ioctl_setpower(struct
 static int orinoco_ioctl_getpower(struct net_device *dev, struct iw_param *prq);
 static int orinoco_ioctl_setport3(struct net_device *dev, struct iwreq *wrq);
 static int orinoco_ioctl_getport3(struct net_device *dev, struct iwreq *wrq);
+#endif
 static void __orinoco_set_multicast_list(struct net_device *dev);
 
 /* /proc debugging stuff */
@@ -909,7 +926,9 @@ static int __orinoco_hw_setup_wep(struct
 	return 0;
 }
 
-static int orinoco_hw_get_bssid(struct orinoco_private *priv, char buf[ETH_ALEN])
+/* This is called only once from orinoco_ioctl_getwap(). */
+static inline int orinoco_hw_get_bssid(struct orinoco_private *priv,
+				       char buf[ETH_ALEN])
 {
 	hermes_t *hw = &priv->hw;
 	int err = 0;
@@ -924,8 +943,10 @@ static int orinoco_hw_get_bssid(struct o
 	return err;
 }
 
-static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
-			      char buf[IW_ESSID_MAX_SIZE+1])
+/* This is called only once from orinoco_ioctl_getessid(). */
+static inline int orinoco_hw_get_essid(struct orinoco_private *priv,
+				       int *active,
+				       char buf[IW_ESSID_MAX_SIZE+1])
 {
 	hermes_t *hw = &priv->hw;
 	int err = 0;
@@ -979,7 +1000,8 @@ static int orinoco_hw_get_essid(struct o
 	return err;       
 }
 
-static long orinoco_hw_get_freq(struct orinoco_private *priv)
+/* This is called only once from orinoco_ioctl_getfreq(). */
+static inline long orinoco_hw_get_freq(struct orinoco_private *priv)
 {
 	
 	hermes_t *hw = &priv->hw;
@@ -1011,8 +1033,10 @@ static long orinoco_hw_get_freq(struct o
 	return err ? err : freq;
 }
 
-static int orinoco_hw_get_bitratelist(struct orinoco_private *priv, int *numrates,
-				    int32_t *rates, int max)
+/* This is called only once from orinoco_ioctl_getiwrange(). */
+static inline int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
+					     int *numrates,
+					     int32_t *rates, int max)
 {
 	hermes_t *hw = &priv->hw;
 	struct hermes_idstring list;
@@ -2138,175 +2162,235 @@ orinoco_tx_timeout(struct net_device *de
 	}
 }
 
-static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq)
+static int orinoco_ioctl_getname(struct net_device *dev,
+				 struct iw_request_info *info,
+				 union iwreq_data *wrqu,
+				 char *extra)
+{
+	strcpy(wrqu->name, "IEEE 802.11-DS");
+	return 0;
+}
+
+static int orinoco_ioctl_getwap(struct net_device *dev,
+				struct iw_request_info *info,
+				union iwreq_data *wrqu,
+				char *extra)
+{
+	struct orinoco_private *priv = dev->priv;
+
+	wrqu->ap_addr.sa_family = ARPHRD_ETHER;
+	return orinoco_hw_get_bssid(priv, wrqu->ap_addr.sa_data);
+}
+
+static int orinoco_ioctl_setmode(struct net_device *dev,
+				 struct iw_request_info *info,
+				 union iwreq_data *wrqu,
+				 char *extra)
+{
+	struct orinoco_private *priv = dev->priv;
+	int err = -EINPROGRESS;		/* Call commit handler */
+
+	orinoco_lock(priv);
+	switch (wrqu->mode) {
+		case IW_MODE_ADHOC:
+			if (! (priv->has_ibss || priv->has_port3) )
+				err = -EINVAL;
+			else {
+				priv->iw_mode = IW_MODE_ADHOC;
+			}
+			break;
+
+		case IW_MODE_INFRA:
+			priv->iw_mode = IW_MODE_INFRA;
+			break;
+
+		default:
+			err = -EINVAL;
+			break;
+		}
+	set_port_type(priv);
+	orinoco_unlock(priv);
+
+	return err;
+}
+
+static int orinoco_ioctl_getmode(struct net_device *dev,
+				struct iw_request_info *info,
+				union iwreq_data *wrqu,
+				char *extra)
+{
+	struct orinoco_private *priv = dev->priv;
+
+	/* No real need to lock here */
+	orinoco_lock(priv);
+	wrqu->mode = priv->iw_mode;
+	orinoco_unlock(priv);
+	return 0;
+}
+
+static int orinoco_ioctl_getiwrange(struct net_device *dev,
+				    struct iw_request_info *info,
+				    union iwreq_data *wrqu,
+				    char *extra)
 {
 	struct orinoco_private *priv = dev->priv;
 	int err = 0;
 	int mode;
-	struct iw_range range;
+	struct iw_range *range = (struct iw_range *) extra;
 	int numrates;
 	int i, k;
 
 	TRACE_ENTER(dev->name);
 
-	err = verify_area(VERIFY_WRITE, rrq->pointer, sizeof(range));
-	if (err)
-		return err;
+	wrqu->data.length = sizeof(struct iw_range);
 
-	rrq->length = sizeof(range);
-
-	orinoco_lock(priv);
-	mode = priv->iw_mode;
-	orinoco_unlock(priv);
-
-	memset(&range, 0, sizeof(range));
+	memset(range, 0, sizeof(struct iw_range));
 
 	/* Much of this shamelessly taken from wvlan_cs.c. No idea
 	 * what it all means -dgibson */
 #if WIRELESS_EXT > 10
-	range.we_version_compiled = WIRELESS_EXT;
-	range.we_version_source = 11;
+	range->we_version_compiled = WIRELESS_EXT;
+	range->we_version_source = 13;
 #endif /* WIRELESS_EXT > 10 */
 
-	range.min_nwid = range.max_nwid = 0; /* We don't use nwids */
+	// Already done in memset, don't redo it
+	range->min_nwid = range->max_nwid = 0; /* We don't use nwids */
 
 	/* Set available channels/frequencies */
-	range.num_channels = NUM_CHANNELS;
+	range->num_channels = NUM_CHANNELS;
 	k = 0;
 	for (i = 0; i < NUM_CHANNELS; i++) {
 		if (priv->channel_mask & (1 << i)) {
-			range.freq[k].i = i + 1;
-			range.freq[k].m = channel_frequency[i] * 100000;
-			range.freq[k].e = 1;
+			range->freq[k].i = i + 1;
+			range->freq[k].m = channel_frequency[i] * 100000;
+			range->freq[k].e = 1;
 			k++;
 		}
 		
 		if (k >= IW_MAX_FREQUENCIES)
 			break;
 	}
-	range.num_frequency = k;
+	range->num_frequency = k;
+
+	range->sensitivity = 3;
+
+	orinoco_lock(priv);
+	/* Group all operation that need locking here - Jean II */
+	/* Actually, as we just read a bunch of ints, we don't really
+	 * need any locking (writing an int is atomic) - Jean II */
+	mode = priv->iw_mode;
+	if (priv->has_wep) {
+		range->max_encoding_tokens = ORINOCO_MAX_KEYS;
 
-	range.sensitivity = 3;
+		range->encoding_size[0] = SMALL_KEY_SIZE;
+		range->num_encoding_sizes = 1;
+
+		if (priv->has_big_wep) {
+			range->encoding_size[1] = LARGE_KEY_SIZE;
+			range->num_encoding_sizes = 2;
+		}
+	} else {
+		// Already done in memset, don't redo it
+		range->num_encoding_sizes = 0;
+		range->max_encoding_tokens = 0;
+	}
+	orinoco_unlock(priv);
 
 	if ((mode == IW_MODE_ADHOC) && (priv->spy_number == 0)){
 		/* Quality stats meaningless in ad-hoc mode */
-		range.max_qual.qual = 0;
-		range.max_qual.level = 0;
-		range.max_qual.noise = 0;
+		range->max_qual.qual = 0;
+		range->max_qual.level = 0;
+		range->max_qual.noise = 0;
+		// Already done in memset, don't redo it
 #if WIRELESS_EXT > 11
-		range.avg_qual.qual = 0;
-		range.avg_qual.level = 0;
-		range.avg_qual.noise = 0;
+		range->avg_qual.qual = 0;
+		range->avg_qual.level = 0;
+		range->avg_qual.noise = 0;
 #endif /* WIRELESS_EXT > 11 */
 
 	} else {
-		range.max_qual.qual = 0x8b - 0x2f;
-		range.max_qual.level = 0x2f - 0x95 - 1;
-		range.max_qual.noise = 0x2f - 0x95 - 1;
+		range->max_qual.qual = 0x8b - 0x2f;
+		range->max_qual.level = 0x2f - 0x95 - 1;
+		range->max_qual.noise = 0x2f - 0x95 - 1;
 #if WIRELESS_EXT > 11
 		/* Need to get better values */
-		range.avg_qual.qual = 0x24;
-		range.avg_qual.level = 0xC2;
-		range.avg_qual.noise = 0x9E;
+		range->avg_qual.qual = 0x24;
+		range->avg_qual.level = 0xC2;
+		range->avg_qual.noise = 0x9E;
 #endif /* WIRELESS_EXT > 11 */
 	}
 
 	err = orinoco_hw_get_bitratelist(priv, &numrates,
-				       range.bitrate, IW_MAX_BITRATES);
+				       range->bitrate, IW_MAX_BITRATES);
 	if (err)
 		return err;
-	range.num_bitrates = numrates;
+	range->num_bitrates = numrates;
 	
 	/* 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(numrates > 2)
-		range.throughput = 5 * 1000 * 1000;	/* ~5 Mb/s */
+		range->throughput = 5 * 1000 * 1000;	/* ~5 Mb/s */
 	else
-		range.throughput = 1.5 * 1000 * 1000;	/* ~1.5 Mb/s */
-
-	range.min_rts = 0;
-	range.max_rts = 2347;
-	range.min_frag = 256;
-	range.max_frag = 2346;
+		range->throughput = 1.5 * 1000 * 1000;	/* ~1.5 Mb/s */
 
-	orinoco_lock(priv);
-	if (priv->has_wep) {
-		range.max_encoding_tokens = ORINOCO_MAX_KEYS;
-
-		range.encoding_size[0] = SMALL_KEY_SIZE;
-		range.num_encoding_sizes = 1;
-
-		if (priv->has_big_wep) {
-			range.encoding_size[1] = LARGE_KEY_SIZE;
-			range.num_encoding_sizes = 2;
-		}
-	} else {
-		range.num_encoding_sizes = 0;
-		range.max_encoding_tokens = 0;
-	}
-	orinoco_unlock(priv);
-		
-	range.min_pmp = 0;
-	range.max_pmp = 65535000;
-	range.min_pmt = 0;
-	range.max_pmt = 65535 * 1000;	/* ??? */
-	range.pmp_flags = IW_POWER_PERIOD;
-	range.pmt_flags = IW_POWER_TIMEOUT;
-	range.pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R;
-
-	range.num_txpower = 1;
-	range.txpower[0] = 15; /* 15dBm */
-	range.txpower_capa = IW_TXPOW_DBM;
+	range->min_rts = 0;
+	range->max_rts = 2347;
+	range->min_frag = 256;
+	range->max_frag = 2346;
+
+	range->min_pmp = 0;
+	range->max_pmp = 65535000;
+	range->min_pmt = 0;
+	range->max_pmt = 65535 * 1000;	/* ??? */
+	range->pmp_flags = IW_POWER_PERIOD;
+	range->pmt_flags = IW_POWER_TIMEOUT;
+	range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R;
+
+	range->num_txpower = 1;
+	range->txpower[0] = 15; /* 15dBm */
+	range->txpower_capa = IW_TXPOW_DBM;
 
 #if WIRELESS_EXT > 10
-	range.retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
-	range.retry_flags = IW_RETRY_LIMIT;
-	range.r_time_flags = IW_RETRY_LIFETIME;
-	range.min_retry = 0;
-	range.max_retry = 65535;	/* ??? */
-	range.min_r_time = 0;
-	range.max_r_time = 65535 * 1000;	/* ??? */
+	range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
+	range->retry_flags = IW_RETRY_LIMIT;
+	range->r_time_flags = IW_RETRY_LIFETIME;
+	range->min_retry = 0;
+	range->max_retry = 65535;	/* ??? */
+	range->min_r_time = 0;
+	range->max_r_time = 65535 * 1000;	/* ??? */
 #endif /* WIRELESS_EXT > 10 */
 
-	if (copy_to_user(rrq->pointer, &range, sizeof(range)))
-		return -EFAULT;
-
 	TRACE_EXIT(dev->name);
 
 	return 0;
 }
 
-static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq)
+static int orinoco_ioctl_setiwencode(struct net_device *dev,
+				     struct iw_request_info *info,
+				     union iwreq_data *wrqu,
+				     char *keybuf)
 {
 	struct orinoco_private *priv = dev->priv;
-	int index = (erq->flags & IW_ENCODE_INDEX) - 1;
+	int index = (wrqu->encoding.flags & IW_ENCODE_INDEX) - 1;
 	int setindex = priv->tx_key;
 	int enable = priv->wep_on;
 	int restricted = priv->wep_restrict;
 	u16 xlen = 0;
-	int err = 0;
-	char keybuf[ORINOCO_MAX_KEY_SIZE];
+	int err = -EINPROGRESS;		/* Call commit handler */
 	
-	if (erq->pointer) {
-		/* We actually have a key to set */
-		if ( (erq->length < SMALL_KEY_SIZE) || (erq->length > ORINOCO_MAX_KEY_SIZE) )
-			return -EINVAL;
-		
-		if (copy_from_user(keybuf, erq->pointer, erq->length))
-			return -EFAULT;
+	if (! priv->has_wep) {
+		return -EOPNOTSUPP;
 	}
-	
+
 	orinoco_lock(priv);
 	
-	if (erq->pointer) {
-		if (erq->length > ORINOCO_MAX_KEY_SIZE) {
-			err = -E2BIG;
-			goto out;
-		}
-		
-		if ( (erq->length > LARGE_KEY_SIZE)
-		     || ( ! priv->has_big_wep && (erq->length > SMALL_KEY_SIZE))  ) {
+	if (wrqu->encoding.length > 0) {
+		/* Check key size. Either it's small size, or it large (but
+		 * only if the device support large keys) - Jean II */
+		if ( (wrqu->encoding.length > LARGE_KEY_SIZE)
+		     || ( ! priv->has_big_wep &&
+			  (wrqu->encoding.length > SMALL_KEY_SIZE))  ) {
 			err = -EINVAL;
 			goto out;
 		}
@@ -2314,9 +2398,9 @@ static int orinoco_ioctl_setiwencode(str
 		if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
 			index = priv->tx_key;
 		
-		if (erq->length > SMALL_KEY_SIZE) {
+		if (wrqu->encoding.length > SMALL_KEY_SIZE) {
 			xlen = LARGE_KEY_SIZE;
-		} else if (erq->length > 0) {
+		} else if (wrqu->encoding.length > 0) {
 			xlen = SMALL_KEY_SIZE;
 		} else
 			xlen = 0;
@@ -2331,7 +2415,7 @@ static int orinoco_ioctl_setiwencode(str
 		 * we will arrive there with an index of -1. This is valid
 		 * but need to be taken care off... Jean II */
 		if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) {
-			if((index != -1) || (erq->flags == 0)) {
+			if((index != -1) || (wrqu->encoding.flags == 0)) {
 				err = -EINVAL;
 				goto out;
 			}
@@ -2345,18 +2429,18 @@ static int orinoco_ioctl_setiwencode(str
 		}
 	}
 	
-	if (erq->flags & IW_ENCODE_DISABLED)
+	if (wrqu->encoding.flags & IW_ENCODE_DISABLED)
 		enable = 0;
 	/* Only for Prism2 & Symbol cards (so far) - Jean II */
-	if (erq->flags & IW_ENCODE_OPEN)
+	if (wrqu->encoding.flags & IW_ENCODE_OPEN)
 		restricted = 0;
-	if (erq->flags & IW_ENCODE_RESTRICTED)
+	if (wrqu->encoding.flags & IW_ENCODE_RESTRICTED)
 		restricted = 1;
 
-	if (erq->pointer) {
+	if (wrqu->encoding.length > 0) {
 		priv->keys[index].len = cpu_to_le16(xlen);
 		memset(priv->keys[index].data, 0, sizeof(priv->keys[index].data));
-		memcpy(priv->keys[index].data, keybuf, erq->length);
+		memcpy(priv->keys[index].data, keybuf, wrqu->encoding.length);
 	}
 	priv->tx_key = setindex;
 	priv->wep_on = enable;
@@ -2365,87 +2449,88 @@ static int orinoco_ioctl_setiwencode(str
  out:
 	orinoco_unlock(priv);
 
-	return 0;
+	return err;
 }
 
-static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq)
+static int orinoco_ioctl_getiwencode(struct net_device *dev,
+				     struct iw_request_info *info,
+				     union iwreq_data *wrqu,
+				     char *keybuf)
 {
 	struct orinoco_private *priv = dev->priv;
-	int index = (erq->flags & IW_ENCODE_INDEX) - 1;
+	int index = (wrqu->encoding.flags & IW_ENCODE_INDEX) - 1;
 	u16 xlen = 0;
-	char keybuf[ORINOCO_MAX_KEY_SIZE];
-
 	
+	if (! priv->has_wep) {
+		return -EOPNOTSUPP;
+	}
+
 	orinoco_lock(priv);
 
 	if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
 		index = priv->tx_key;
 
-	erq->flags = 0;
+	wrqu->encoding.flags = 0;
 	if (! priv->wep_on)
-		erq->flags |= IW_ENCODE_DISABLED;
-	erq->flags |= index + 1;
+		wrqu->encoding.flags |= IW_ENCODE_DISABLED;
+	wrqu->encoding.flags |= index + 1;
 	
 	/* Only for symbol cards - Jean II */
 	if (priv->firmware_type != FIRMWARE_TYPE_AGERE) {
 		if(priv->wep_restrict)
-			erq->flags |= IW_ENCODE_RESTRICTED;
+			wrqu->encoding.flags |= IW_ENCODE_RESTRICTED;
 		else
-			erq->flags |= IW_ENCODE_OPEN;
+			wrqu->encoding.flags |= IW_ENCODE_OPEN;
 	}
 
 	xlen = le16_to_cpu(priv->keys[index].len);
 
-	erq->length = xlen;
+	wrqu->encoding.length = xlen;
 
-	if (erq->pointer) {
-		memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE);
-	}
+	memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE);
 	
 	orinoco_unlock(priv);
 
-	if (erq->pointer) {
-		if (copy_to_user(erq->pointer, keybuf, xlen))
-			return -EFAULT;
-	}
-
 	return 0;
 }
 
-static int orinoco_ioctl_setessid(struct net_device *dev, struct iw_point *erq)
+static int orinoco_ioctl_setessid(struct net_device *dev,
+				  struct iw_request_info *info,
+				  union iwreq_data *wrqu,
+				  char *essidbuf)
 {
 	struct orinoco_private *priv = dev->priv;
-	char essidbuf[IW_ESSID_MAX_SIZE+1];
 
 	/* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it
 	 * anyway... - Jean II */
 
-	memset(&essidbuf, 0, sizeof(essidbuf));
-
-	if (erq->flags) {
-		if (erq->length > IW_ESSID_MAX_SIZE)
-			return -E2BIG;
+	/* Hum... Should not use Wireless Extension constant (may change),
+	 * should use our own... - Jean II */
+	if (wrqu->essid.length > IW_ESSID_MAX_SIZE)
+		return -E2BIG;
 		
-		if (copy_from_user(&essidbuf, erq->pointer, erq->length))
-			return -EFAULT;
-
-		essidbuf[erq->length] = '\0';
-	}
-
 	orinoco_lock(priv);
 
-	memcpy(priv->desired_essid, essidbuf, sizeof(priv->desired_essid));
+	/* NULL the string (for NULL termination & ESSID = ANY) - Jean II */
+	memset(priv->desired_essid, 0, sizeof(priv->desired_essid));
+
+	/* If not ANY, get the new ESSID */
+	if (wrqu->essid.flags) {
+		memcpy(priv->desired_essid, essidbuf, wrqu->essid.length);
+	}
 
 	orinoco_unlock(priv);
 
-	return 0;
+	return -EINPROGRESS;		/* Call commit handler */
 }
 
-static int orinoco_ioctl_getessid(struct net_device *dev, struct iw_point *erq)
+static int orinoco_ioctl_getessid(struct net_device *dev,
+				  struct iw_request_info *info,
+				  union iwreq_data *wrqu,
+				  char *essidbuf)
 {
 	struct orinoco_private *priv = dev->priv;
-	char essidbuf[IW_ESSID_MAX_SIZE+1];
-	int active;
+	int active;	/* ??? */
 	int err = 0;
 
 	TRACE_ENTER(dev->name);
@@ -2454,59 +2539,55 @@ static int orinoco_ioctl_getessid(struct
 	if (err)
 		return err;
 
-	erq->flags = 1;
-	erq->length = strlen(essidbuf) + 1;
-	if (erq->pointer)
-		if ( copy_to_user(erq->pointer, essidbuf, erq->length) )
-			return -EFAULT;
+	wrqu->essid.flags = 1;
+	wrqu->essid.length = strlen(essidbuf) + 1;
 
 	TRACE_EXIT(dev->name);
 	
 	return 0;
 }
 
-static int orinoco_ioctl_setnick(struct net_device *dev, struct iw_point *nrq)
+static int orinoco_ioctl_setnick(struct net_device *dev,
+				 struct iw_request_info *info,
+				 union iwreq_data *wrqu,
+				 char *nickbuf)
 {
 	struct orinoco_private *priv = dev->priv;
-	char nickbuf[IW_ESSID_MAX_SIZE+1];
 
-	if (nrq->length > IW_ESSID_MAX_SIZE)
+	if (wrqu->essid.length > IW_ESSID_MAX_SIZE)
 		return -E2BIG;
 
-	memset(nickbuf, 0, sizeof(nickbuf));
-
-	if (copy_from_user(nickbuf, nrq->pointer, nrq->length))
-		return -EFAULT;
-
-	nickbuf[nrq->length] = '\0';
-	
 	orinoco_lock(priv);
 
-	memcpy(priv->nick, nickbuf, sizeof(priv->nick));
+	memset(priv->nick, 0, sizeof(priv->nick));
+
+	memcpy(priv->nick, nickbuf, wrqu->essid.length);
 
 	orinoco_unlock(priv);
 
-	return 0;
+	return -EINPROGRESS;		/* Call commit handler */
 }
 
-static int orinoco_ioctl_getnick(struct net_device *dev, struct iw_point *nrq)
+static int orinoco_ioctl_getnick(struct net_device *dev,
+				 struct iw_request_info *info,
+				 union iwreq_data *wrqu,
+				 char *nickbuf)
 {
 	struct orinoco_private *priv = dev->priv;
-	char nickbuf[IW_ESSID_MAX_SIZE+1];
 
 	orinoco_lock(priv);
 	memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE+1);
 	orinoco_unlock(priv);
 
-	nrq->length = strlen(nickbuf)+1;
-
-	if (copy_to_user(nrq->pointer, nickbuf, sizeof(nickbuf)))
-		return -EFAULT;
+	wrqu->essid.length = strlen(nickbuf) + 1;
 
 	return 0;
 }
 
-static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq)
+static int orinoco_ioctl_setfreq(struct net_device *dev,
+				 struct iw_request_info *info,
+				 union iwreq_data *wrqu,
+				 char *extra)
 {
 	struct orinoco_private *priv = dev->priv;
 	int chan = -1;
@@ -2517,19 +2598,19 @@ static int orinoco_ioctl_setfreq(struct 
 	if (priv->iw_mode != IW_MODE_ADHOC)
 		return -EOPNOTSUPP;
 
-	if ( (frq->e == 0) && (frq->m <= 1000) ) {
+	if ( (wrqu->freq.e == 0) && (wrqu->freq.m <= 1000) ) {
 		/* Setting by channel number */
-		chan = frq->m;
+		chan = wrqu->freq.m;
 	} else {
 		/* Setting by frequency - search the table */
 		int mult = 1;
 		int i;
 
-		for (i = 0; i < (6 - frq->e); i++)
+		for (i = 0; i < (6 - wrqu->freq.e); i++)
 			mult *= 10;
 
 		for (i = 0; i < NUM_CHANNELS; i++)
-			if (frq->m == (channel_frequency[i] * mult))
+			if (wrqu->freq.m == (channel_frequency[i] * mult))
 				chan = i+1;
 	}
 
@@ -2541,10 +2622,26 @@ static int orinoco_ioctl_setfreq(struct 
 	priv->channel = chan;
 	orinoco_unlock(priv);
 
+	return -EINPROGRESS;		/* Call commit handler */
+}
+
+static int orinoco_ioctl_getfreq(struct net_device *dev,
+				 struct iw_request_info *info,
+				 union iwreq_data *wrqu,
+				 char *extra)
+{
+	struct orinoco_private *priv = dev->priv;
+
+	/* Locking done in there */
+	wrqu->freq.m = orinoco_hw_get_freq(priv);
+	wrqu->freq.e = 1;
 	return 0;
 }
 
-static int orinoco_ioctl_getsens(struct net_device *dev, struct iw_param *srq)
+static int orinoco_ioctl_getsens(struct net_device *dev,
+				 struct iw_request_info *info,
+				 union iwreq_data *wrqu,
+				 char *extra)
 {
 	struct orinoco_private *priv = dev->priv;
 	hermes_t *hw = &priv->hw;
@@ -2558,16 +2655,19 @@ static int orinoco_ioctl_getsens(struct 
 	if (err)
 		return err;
 
-	srq->value = val;
-	srq->fixed = 0; /* auto */
+	wrqu->sens.value = val;
+	wrqu->sens.fixed = 0; /* auto */
 
 	return 0;
 }
 
-static int orinoco_ioctl_setsens(struct net_device *dev, struct iw_param *srq)
+static int orinoco_ioctl_setsens(struct net_device *dev,
+				 struct iw_request_info *info,
+				 union iwreq_data *wrqu,
+				 char *extra)
 {
 	struct orinoco_private *priv = dev->priv;
-	int val = srq->value;
+	int val = wrqu->sens.value;
 
 	if ((val < 1) || (val > 3))
 		return -EINVAL;
@@ -2576,15 +2676,18 @@ static int orinoco_ioctl_setsens(struct 
 	priv->ap_density = val;
 	orinoco_unlock(priv);
 
-	return 0;
+	return -EINPROGRESS;		/* Call commit handler */
 }
 
-static int orinoco_ioctl_setrts(struct net_device *dev, struct iw_param *rrq)
+static int orinoco_ioctl_setrts(struct net_device *dev,
+				struct iw_request_info *info,
+				union iwreq_data *wrqu,
+				char *extra)
 {
 	struct orinoco_private *priv = dev->priv;
-	int val = rrq->value;
+	int val = wrqu->rts.value;
 
-	if (rrq->disabled)
+	if (wrqu->rts.disabled)
 		val = 2347;
 
 	if ( (val < 0) || (val > 2347) )
@@ -2594,33 +2697,51 @@ static int orinoco_ioctl_setrts(struct n
 	priv->rts_thresh = val;
 	orinoco_unlock(priv);
 
+	return -EINPROGRESS;		/* Call commit handler */
+}
+
+static int orinoco_ioctl_getrts(struct net_device *dev,
+				struct iw_request_info *info,
+				union iwreq_data *wrqu,
+				char *extra)
+{
+	struct orinoco_private *priv = dev->priv;
+
+	wrqu->rts.value = priv->rts_thresh;
+	wrqu->rts.disabled = (wrqu->rts.value == 2347);
+	wrqu->rts.fixed = 1;
 	return 0;
 }
 
-static int orinoco_ioctl_setfrag(struct net_device *dev, struct iw_param *frq)
+static int orinoco_ioctl_setfrag(struct net_device *dev,
+				 struct iw_request_info *info,
+				 union iwreq_data *wrqu,
+				 char *extra)
 {
 	struct orinoco_private *priv = dev->priv;
-	int err = 0;
+	int err = -EINPROGRESS;		/* Call commit handler */
 
 	orinoco_lock(priv);
 
 	if (priv->has_mwo) {
-		if (frq->disabled)
+		if (wrqu->frag.disabled)
 			priv->mwo_robust = 0;
 		else {
-			if (frq->fixed)
+			if (wrqu->frag.fixed)
 				printk(KERN_WARNING "%s: Fixed fragmentation not \
 supported on this firmware. Using MWO robust instead.\n", dev->name);
 			priv->mwo_robust = 1;
 		}
 	} else {
-		if (frq->disabled)
+		if (wrqu->frag.disabled)
 			priv->frag_thresh = 2346;
 		else {
-			if ( (frq->value < 256) || (frq->value > 2346) )
+			if ( (wrqu->frag.value < 256) ||
+			     (wrqu->frag.value > 2346) )
 				err = -EINVAL;
 			else
-				priv->frag_thresh = frq->value & ~0x1; /* must be even */
+				/* value must be even */
+				priv->frag_thresh = wrqu->frag.value & ~0x1;
 		}
 	}
 
@@ -2629,7 +2750,10 @@ supported on this firmware. Using MWO ro
 	return err;
 }
 
-static int orinoco_ioctl_getfrag(struct net_device *dev, struct iw_param *frq)
+static int orinoco_ioctl_getfrag(struct net_device *dev,
+				 struct iw_request_info *info,
+				 union iwreq_data *wrqu,
+				 char *extra)
 {
 	struct orinoco_private *priv = dev->priv;
 	hermes_t *hw = &priv->hw;
@@ -2645,18 +2769,18 @@ static int orinoco_ioctl_getfrag(struct 
 		if (err)
 			val = 0;
 
-		frq->value = val ? 2347 : 0;
-		frq->disabled = ! val;
-		frq->fixed = 0;
+		wrqu->frag.value = val ? 2347 : 0;
+		wrqu->frag.disabled = ! val;
+		wrqu->frag.fixed = 0;
 	} else {
 		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
 					  &val);
 		if (err)
 			val = 0;
 
-		frq->value = val;
-		frq->disabled = (val >= 2346);
-		frq->fixed = 1;
+		wrqu->frag.value = val;
+		wrqu->frag.disabled = (val >= 2346);
+		wrqu->frag.fixed = 1;
 	}
 
 	orinoco_unlock(priv);
@@ -2664,21 +2788,24 @@ static int orinoco_ioctl_getfrag(struct 
 	return err;
 }
 
-static int orinoco_ioctl_setrate(struct net_device *dev, struct iw_param *rrq)
+static int orinoco_ioctl_setrate(struct net_device *dev,
+				 struct iw_request_info *info,
+				 union iwreq_data *wrqu,
+				 char *extra)
 {
 	struct orinoco_private *priv = dev->priv;
-	int err = 0;
+	int err = -EINPROGRESS;		/* Call commit handler */
 	int ratemode = -1;
 	int bitrate; /* 100s of kilobits */
 	int i;
 	
 	/* As the user space doesn't know our highest rate, it uses
 	 * -1 to ask us to set the highest rate - Jean II */
-	if(rrq->value == -1)
+	if(wrqu->bitrate.value == -1)
 		bitrate = 110;
 	else {
-		bitrate = rrq->value / 100000;
-		if (rrq->value % 100000)
+		bitrate = wrqu->bitrate.value / 100000;
+		if (wrqu->bitrate.value % 100000)
 			return -EINVAL;
 	}
 
@@ -2688,7 +2815,7 @@ static int orinoco_ioctl_setrate(struct 
 
 	for (i = 0; i < BITRATE_TABLE_SIZE; i++)
 		if ( (bitrate_table[i].bitrate == bitrate) &&
-		     (bitrate_table[i].automatic == ! rrq->fixed) ) {
+		     (bitrate_table[i].automatic == ! wrqu->bitrate.fixed) ) {
 			ratemode = i;
 			break;
 		}
@@ -2703,7 +2830,10 @@ static int orinoco_ioctl_setrate(struct 
 	return err;
 }
 
-static int orinoco_ioctl_getrate(struct net_device *dev, struct iw_param *rrq)
+static int orinoco_ioctl_getrate(struct net_device *dev,
+				 struct iw_request_info *info,
+				 union iwreq_data *wrqu,
+				 char *extra)
 {
 	struct orinoco_private *priv = dev->priv;
 	hermes_t *hw = &priv->hw;
@@ -2722,9 +2852,9 @@ static int orinoco_ioctl_getrate(struct 
 	/* The firmware will tell us the current rate, but won't tell
 	 * us if it's automatic or not, so we need to remember what we
 	 * set - Jean II */
-	rrq->fixed = ! bitrate_table[ratemode].automatic;
-	rrq->value = bitrate_table[ratemode].bitrate * 100000;
-	rrq->disabled = 0;
+	wrqu->bitrate.fixed = ! bitrate_table[ratemode].automatic;
+	wrqu->bitrate.value = bitrate_table[ratemode].bitrate * 100000;
+	wrqu->bitrate.disabled = 0;
 
 	if (netif_running(dev)) {
 		/* If the device is actually operation we try to find more,
@@ -2742,9 +2872,9 @@ static int orinoco_ioctl_getrate(struct 
 			 * encoding of HERMES_RID_CNFTXRATECONTROL.
 			 * Don't forget that 6Mb/s is really 5.5Mb/s */
 			if(val == 6)
-				rrq->value = 5500000;
+				wrqu->bitrate.value = 5500000;
 			else
-				rrq->value = val * 1000000;
+				wrqu->bitrate.value = val * 1000000;
 			break;
 		case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */
 		case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */
@@ -2756,7 +2886,7 @@ static int orinoco_ioctl_getrate(struct 
 			if (i >= BITRATE_TABLE_SIZE)
 				printk(KERN_INFO "%s: Unable to determine current bitrate (0x%04hx)\n",
 				       dev->name, val);
-			rrq->value = bitrate_table[ratemode].bitrate * 100000;
+			wrqu->bitrate.value = bitrate_table[ratemode].bitrate * 100000;
 			break;
 		default:
 			BUG();
@@ -2769,18 +2899,20 @@ static int orinoco_ioctl_getrate(struct 
 	return err;
 }
 
-static int orinoco_ioctl_setpower(struct net_device *dev, struct iw_param *prq)
+static int orinoco_ioctl_setpower(struct net_device *dev,
+				  struct iw_request_info *info,
+				  union iwreq_data *wrqu,
+				  char *extra)
 {
 	struct orinoco_private *priv = dev->priv;
-	int err = 0;
-
+	int err = -EINPROGRESS;		/* Call commit handler */
 
 	orinoco_lock(priv);
 
-	if (prq->disabled) {
+	if (wrqu->power.disabled) {
 		priv->pm_on = 0;
 	} else {
-		switch (prq->flags & IW_POWER_MODE) {
+		switch (wrqu->power.flags & IW_POWER_MODE) {
 		case IW_POWER_UNICAST_R:
 			priv->pm_mcast = 0;
 			priv->pm_on = 1;
@@ -2798,13 +2930,13 @@ static int orinoco_ioctl_setpower(struct
 		if (err)
 			goto out;
 		
-		if (prq->flags & IW_POWER_TIMEOUT) {
+		if (wrqu->power.flags & IW_POWER_TIMEOUT) {
 			priv->pm_on = 1;
-			priv->pm_timeout = prq->value / 1000;
+			priv->pm_timeout = wrqu->power.value / 1000;
 		}
-		if (prq->flags & IW_POWER_PERIOD) {
+		if (wrqu->power.flags & IW_POWER_PERIOD) {
 			priv->pm_on = 1;
-			priv->pm_period = prq->value / 1000;
+			priv->pm_period = wrqu->power.value / 1000;
 		}
 		/* It's valid to not have a value if we are just toggling
 		 * the flags... Jean II */
@@ -2820,7 +2952,10 @@ static int orinoco_ioctl_setpower(struct
 	return err;
 }
 
-static int orinoco_ioctl_getpower(struct net_device *dev, struct iw_param *prq)
+static int orinoco_ioctl_getpower(struct net_device *dev,
+				  struct iw_request_info *info,
+				  union iwreq_data *wrqu,
+				  char *extra)
 {
 	struct orinoco_private *priv = dev->priv;
 	hermes_t *hw = &priv->hw;
@@ -2846,19 +2981,19 @@ static int orinoco_ioctl_getpower(struct
 	if (err)
 		goto out;
 
-	prq->disabled = !enable;
+	wrqu->power.disabled = !enable;
 	/* Note : by default, display the period */
-	if ((prq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
-		prq->flags = IW_POWER_TIMEOUT;
-		prq->value = timeout * 1000;
+	if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
+		wrqu->power.flags = IW_POWER_TIMEOUT;
+		wrqu->power.value = timeout * 1000;
 	} else {
-		prq->flags = IW_POWER_PERIOD;
-		prq->value = period * 1000;
+		wrqu->power.flags = IW_POWER_PERIOD;
+		wrqu->power.value = period * 1000;
 	}
 	if (mcast)
-		prq->flags |= IW_POWER_ALL_R;
+		wrqu->power.flags |= IW_POWER_ALL_R;
 	else
-		prq->flags |= IW_POWER_UNICAST_R;
+		wrqu->power.flags |= IW_POWER_UNICAST_R;
 
  out:
 	orinoco_unlock(priv);
@@ -2866,8 +3001,24 @@ static int orinoco_ioctl_getpower(struct
 	return err;
 }
 
+static int orinoco_ioctl_gettxpower(struct net_device *dev,
+				    struct iw_request_info *info,
+				    union iwreq_data *wrqu,
+				    char *extra)
+{
+	/* The card only supports one tx power, so this is easy */
+	wrqu->txpower.value = 15; /* dBm */
+	wrqu->txpower.fixed = 1;
+	wrqu->txpower.disabled = 0;
+	wrqu->txpower.flags = IW_TXPOW_DBM;
+	return 0;
+}
+
 #if WIRELESS_EXT > 10
-static int orinoco_ioctl_getretry(struct net_device *dev, struct iw_param *rrq)
+static int orinoco_ioctl_getretry(struct net_device *dev,
+				  struct iw_request_info *info,
+				  union iwreq_data *wrqu,
+				  char *extra)
 {
 	struct orinoco_private *priv = dev->priv;
 	hermes_t *hw = &priv->hw;
@@ -2891,22 +3042,22 @@ static int orinoco_ioctl_getretry(struct
 	if (err)
 		goto out;
 
-	rrq->disabled = 0;		/* Can't be disabled */
+	wrqu->retry.disabled = 0;		/* Can't be disabled */
 
 	/* Note : by default, display the retry number */
-	if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
-		rrq->flags = IW_RETRY_LIFETIME;
-		rrq->value = lifetime * 1000;	/* ??? */
+	if ((wrqu->retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
+		wrqu->retry.flags = IW_RETRY_LIFETIME;
+		wrqu->retry.value = lifetime * 1000;	/* ??? */
 	} else {
 		/* By default, display the min number */
-		if ((rrq->flags & IW_RETRY_MAX)) {
-			rrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
-			rrq->value = long_limit;
+		if ((wrqu->retry.flags & IW_RETRY_MAX)) {
+			wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+			wrqu->retry.value = long_limit;
 		} else {
-			rrq->flags = IW_RETRY_LIMIT;
-			rrq->value = short_limit;
+			wrqu->retry.flags = IW_RETRY_LIMIT;
+			wrqu->retry.value = short_limit;
 			if(short_limit != long_limit)
-				rrq->flags |= IW_RETRY_MIN;
+				wrqu->retry.flags |= IW_RETRY_MIN;
 		}
 	}
 
@@ -2917,10 +3068,36 @@ static int orinoco_ioctl_getretry(struct
 }
 #endif /* WIRELESS_EXT > 10 */
 
-static int orinoco_ioctl_setibssport(struct net_device *dev, struct iwreq *wrq)
+static int orinoco_ioctl_reset(struct net_device *dev,
+			       struct iw_request_info *info,
+			       union iwreq_data *wrqu,
+			       char *extra)
+{
+	struct orinoco_private *priv = dev->priv;
+
+	if (! capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name);
+
+	/* COR reset as needed */
+	if((info->cmd == (SIOCIWFIRSTPRIV + 0x1)) &&
+	   (priv->card_reset_handler != NULL))
+		priv->card_reset_handler(priv);
+
+	/* Firmware reset */
+	orinoco_reset(priv);
+
+	return 0;
+}
+
+static int orinoco_ioctl_setibssport(struct net_device *dev,
+				     struct iw_request_info *info,
+				     union iwreq_data *wrqu,
+				     char *extra)
 {
 	struct orinoco_private *priv = dev->priv;
-	int val = *( (int *) wrq->u.name );
+	int val = *( (int *) extra );
 
 	orinoco_lock(priv);
 	priv->ibss_port = val ;
@@ -2929,13 +3106,16 @@ static int orinoco_ioctl_setibssport(str
 	set_port_type(priv);
 
 	orinoco_unlock(priv);
-	return 0;
+	return -EINPROGRESS;		/* Call commit handler */
 }
 
-static int orinoco_ioctl_getibssport(struct net_device *dev, struct iwreq *wrq)
+static int orinoco_ioctl_getibssport(struct net_device *dev,
+				     struct iw_request_info *info,
+				     union iwreq_data *wrqu,
+				     char *extra)
 {
 	struct orinoco_private *priv = dev->priv;
-	int *val = (int *)wrq->u.name;
+	int *val = (int *) extra;
 
 	orinoco_lock(priv);
 	*val = priv->ibss_port;
@@ -2944,11 +3124,14 @@ static int orinoco_ioctl_getibssport(str
 	return 0;
 }
 
-static int orinoco_ioctl_setport3(struct net_device *dev, struct iwreq *wrq)
+static int orinoco_ioctl_setport3(struct net_device *dev,
+				  struct iw_request_info *info,
+				  union iwreq_data *wrqu,
+				  char *extra)
 {
 	struct orinoco_private *priv = dev->priv;
-	int val = *( (int *) wrq->u.name );
-	int err = 0;
+	int val = *( (int *) extra );
+	int err = -EINPROGRESS;		/* Call commit handler */
 
 	orinoco_lock(priv);
 	switch (val) {
@@ -2984,10 +3167,13 @@ static int orinoco_ioctl_setport3(struct
 	return err;
 }
 
-static int orinoco_ioctl_getport3(struct net_device *dev, struct iwreq *wrq)
+static int orinoco_ioctl_getport3(struct net_device *dev,
+				  struct iw_request_info *info,
+				  union iwreq_data *wrqu,
+				  char *extra)
 {
 	struct orinoco_private *priv = dev->priv;
-	int *val = (int *)wrq->u.name;
+	int *val = (int *) extra;
 
 	orinoco_lock(priv);
 	*val = priv->prefer_port3;
@@ -2996,26 +3182,64 @@ static int orinoco_ioctl_getport3(struct
 	return 0;
 }
 
+static int orinoco_ioctl_setpreamble(struct net_device *dev,
+				     struct iw_request_info *info,
+				     union iwreq_data *wrqu,
+				     char *extra)
+{
+	struct orinoco_private *priv = dev->priv;
+
+	/* 802.11b has recently defined some short preamble.
+	 * Basically, the Phy header has been reduced in size.
+	 * This increase performance, especially at high rates
+	 * (the preamble is transmitted at 1Mb/s), unfortunately
+	 * this give compatibility troubles... - Jean II */
+	if(priv->has_preamble) {
+		int val = *( (int *) extra );
+
+		orinoco_lock(priv);
+		if(val)
+			priv->preamble = 1;
+		else
+			priv->preamble = 0;
+		orinoco_unlock(priv);
+
+		return -EINPROGRESS;		/* Call commit handler */
+	} else
+		return -EOPNOTSUPP;
+}
+
+static int orinoco_ioctl_getpreamble(struct net_device *dev,
+				     struct iw_request_info *info,
+				     union iwreq_data *wrqu,
+				     char *extra)
+{
+	struct orinoco_private *priv = dev->priv;
+
+	if(priv->has_preamble) {
+		int *val = (int *) extra;
+
+		orinoco_lock(priv);
+		*val = priv->preamble;
+		orinoco_unlock(priv);
+
+		return 0;
+	} else
+		return -EOPNOTSUPP;
+}
+
 /* Spy is used for link quality/strength measurements in Ad-Hoc mode
  * Jean II */
-static int orinoco_ioctl_setspy(struct net_device *dev, struct iw_point *srq)
+static int orinoco_ioctl_setspy(struct net_device *dev,
+				struct iw_request_info *info,
+				union iwreq_data *wrqu,
+				char *extra)
 {
 	struct orinoco_private *priv = dev->priv;
-	struct sockaddr address[IW_MAX_SPY];
-	int number = srq->length;
+	struct sockaddr *address = (struct sockaddr *) extra;
+	int number = wrqu->data.length;
 	int i;
-	int err = 0;
-
-	/* Check the number of addresses */
-	if (number > IW_MAX_SPY)
-		return -E2BIG;
-
-	/* Get the data in the driver */
-	if (srq->pointer) {
-		if (copy_from_user(address, srq->pointer,
-				   sizeof(struct sockaddr) * number))
-			return -EFAULT;
-	}
+	int err = 0;	/* Do NOT call commit handler */
 
 	/* Make sure nobody mess with the structure while we do */
 	orinoco_lock(priv);
@@ -3052,55 +3276,176 @@ static int orinoco_ioctl_setspy(struct n
 	return err;
 }
 
-static int orinoco_ioctl_getspy(struct net_device *dev, struct iw_point *srq)
+static int orinoco_ioctl_getspy(struct net_device *dev,
+				struct iw_request_info *info,
+				union iwreq_data *wrqu,
+				char *extra)
 {
 	struct orinoco_private *priv = dev->priv;
-	struct sockaddr address[IW_MAX_SPY];
-	struct iw_quality spy_stat[IW_MAX_SPY];
+	struct sockaddr *address = (struct sockaddr *) extra;
 	int number;
 	int i;
 
 	orinoco_lock(priv);
 
 	number = priv->spy_number;
-	if ((number > 0) && (srq->pointer)) {
-		/* Create address struct */
-		for (i = 0; i < number; i++) {
-			memcpy(address[i].sa_data, priv->spy_address[i],
-			       ETH_ALEN);
-			address[i].sa_family = AF_UNIX;
-		}
+	/* Create address struct */
+	for (i = 0; i < number; i++) {
+		memcpy(address[i].sa_data, priv->spy_address[i],
+		       ETH_ALEN);
+		address[i].sa_family = AF_UNIX;
+	}
+	if (number > 0) {
 		/* Copy stats */
 		/* In theory, we should disable irqs while copying the stats
 		 * because the rx path migh update it in the middle...
 		 * Bah, who care ? - Jean II */
-		memcpy(&spy_stat, priv->spy_stat,
-		       sizeof(struct iw_quality) * IW_MAX_SPY);
-		for (i=0; i < number; i++)
-			priv->spy_stat[i].updated = 0;
+		memcpy(extra  + (sizeof(struct sockaddr) * number),
+		        priv->spy_stat, sizeof(struct iw_quality) * number);
 	}
+	/* Reset updated flags. */
+	for (i=0; i < number; i++)
+		priv->spy_stat[i].updated = 0;
 
 	orinoco_unlock(priv);
 
-	/* Push stuff to user space */
-	srq->length = number;
-	if(copy_to_user(srq->pointer, address,
-			 sizeof(struct sockaddr) * number))
-		return -EFAULT;
-	if(copy_to_user(srq->pointer + (sizeof(struct sockaddr)*number),
-			&spy_stat, sizeof(struct iw_quality) * number))
-		return -EFAULT;
+	wrqu->data.length = number;
 
 	return 0;
 }
 
+/* Commit handler, called after a bunch of SET operation */
+static int orinoco_ioctl_commit(struct net_device *dev,
+				struct iw_request_info *info,	/* NULL */
+				union iwreq_data *wrqu,		/* NULL */
+				char *extra)			/* NULL */
+{
+	struct orinoco_private *priv = dev->priv;
+	int err = 0;
+
+	DEBUG(1, "%s: commit\n", dev->name);
+
+	err = orinoco_reset(priv);
+	if (err) {
+		/* Ouch ! What are we supposed to do ? */
+		printk(KERN_ERR "orinoco_cs: Failed to set parameters on %s\n",
+		       dev->name);
+		netif_stop_queue(dev);
+		orinoco_shutdown(priv);
+		priv->hw_ready = 0;
+	}
+
+	return err;
+}
+
+static const struct iw_priv_args orinoco_privtab[] = {
+	{ SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" },
+	{ SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" },
+	{ SIOCIWFIRSTPRIV + 0x2,
+	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	  0, "set_port3" },
+	{ SIOCIWFIRSTPRIV + 0x3, 0,
+	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	  "get_port3" },
+	{ SIOCIWFIRSTPRIV + 0x4,
+	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	  0, "set_preamble" },
+	{ SIOCIWFIRSTPRIV + 0x5, 0,
+	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	  "get_preamble" },
+	{ SIOCIWFIRSTPRIV + 0x6,
+	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	  0, "set_ibssport" },
+	{ SIOCIWFIRSTPRIV + 0x7, 0,
+	  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	  "get_ibssport" }
+};
+
+#if WIRELESS_EXT > 12
+
+/*
+ * Structures to export the Wireless Handlers
+ */
+
+static const iw_handler		orinoco_handler[] =
+{
+	orinoco_ioctl_commit,		/* SIOCSIWCOMMIT */
+	orinoco_ioctl_getname,		/* SIOCGIWNAME */
+	NULL,				/* SIOCSIWNWID */
+	NULL,				/* SIOCGIWNWID */
+	orinoco_ioctl_setfreq,		/* SIOCSIWFREQ */
+	orinoco_ioctl_getfreq,		/* SIOCGIWFREQ */
+	orinoco_ioctl_setmode,		/* SIOCSIWMODE */
+	orinoco_ioctl_getmode,		/* SIOCGIWMODE */
+	orinoco_ioctl_setsens,		/* SIOCSIWSENS */
+	orinoco_ioctl_getsens,		/* SIOCGIWSENS */
+	NULL,				/* SIOCSIWRANGE */
+	orinoco_ioctl_getiwrange,	/* SIOCGIWRANGE */
+	NULL,				/* SIOCSIWPRIV */
+	NULL,				/* SIOCGIWPRIV */
+	NULL,				/* SIOCSIWSTATS */
+	NULL,				/* SIOCGIWSTATS */
+	orinoco_ioctl_setspy,		/* SIOCSIWSPY */
+	orinoco_ioctl_getspy,		/* SIOCGIWSPY */
+	NULL,				/* -- hole -- */
+	NULL,				/* -- hole -- */
+	NULL,				/* SIOCSIWAP */
+	orinoco_ioctl_getwap,		/* SIOCGIWAP */
+	NULL,				/* -- hole -- */
+	NULL,				/* SIOCGIWAPLIST */
+	NULL,				/* -- hole -- */
+	NULL,				/* -- hole -- */
+	orinoco_ioctl_setessid,		/* SIOCSIWESSID */
+	orinoco_ioctl_getessid,		/* SIOCGIWESSID */
+	orinoco_ioctl_setnick,		/* SIOCSIWNICKN */
+	orinoco_ioctl_getnick,		/* SIOCGIWNICKN */
+	NULL,				/* -- hole -- */
+	NULL,				/* -- hole -- */
+	orinoco_ioctl_setrate,		/* SIOCSIWRATE */
+	orinoco_ioctl_getrate,		/* SIOCGIWRATE */
+	orinoco_ioctl_setrts,		/* SIOCSIWRTS */
+	orinoco_ioctl_getrts,		/* SIOCGIWRTS */
+	orinoco_ioctl_setfrag,		/* SIOCSIWFRAG */
+	orinoco_ioctl_getfrag,		/* SIOCGIWFRAG */
+	NULL,				/* SIOCSIWTXPOW */
+	orinoco_ioctl_gettxpower,	/* SIOCGIWTXPOW */
+	NULL,				/* SIOCSIWRETRY */
+	orinoco_ioctl_getretry,		/* SIOCGIWRETRY */
+	orinoco_ioctl_setiwencode,	/* SIOCSIWENCODE */
+	orinoco_ioctl_getiwencode,	/* SIOCGIWENCODE */
+	orinoco_ioctl_setpower,		/* SIOCSIWPOWER */
+	orinoco_ioctl_getpower,		/* SIOCGIWPOWER */
+};
+
+static const iw_handler		orinoco_private_handler[] =
+{
+	orinoco_ioctl_reset,		/* SIOCIWFIRSTPRIV */
+	orinoco_ioctl_reset,		/* SIOCIWFIRSTPRIV + 1 */
+	orinoco_ioctl_setport3,		/* SIOCIWFIRSTPRIV + 2 */
+	orinoco_ioctl_getport3,		/* SIOCIWFIRSTPRIV + 3 */
+	orinoco_ioctl_setpreamble,	/* SIOCIWFIRSTPRIV + 4 */
+	orinoco_ioctl_getpreamble,	/* SIOCIWFIRSTPRIV + 5 */
+	orinoco_ioctl_setibssport,	/* SIOCIWFIRSTPRIV + 6 */
+	orinoco_ioctl_getibssport,	/* SIOCIWFIRSTPRIV + 7 */
+};
+
+static const struct iw_handler_def	orinoco_handler_def =
+{
+	num_standard:	sizeof(orinoco_handler)/sizeof(iw_handler),
+	num_private:	sizeof(orinoco_private_handler)/sizeof(iw_handler),
+	num_private_args: sizeof(orinoco_privtab)/sizeof(struct iw_priv_args),
+	standard:	(iw_handler *) orinoco_handler,
+	private:	(iw_handler *) orinoco_private_handler,
+	private_args:	(struct iw_priv_args *) orinoco_privtab,
+};
+
+#else /* WIRELESS_EXT > 12 */
 int
 orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct orinoco_private *priv = dev->priv;
 	struct iwreq *wrq = (struct iwreq *)rq;
 	int err = 0;
-	int changed = 0;
 
 	TRACE_ENTER(dev->name);
 
@@ -3116,186 +3461,207 @@ orinoco_ioctl(struct net_device *dev, st
 	switch (cmd) {
 	case SIOCGIWNAME:
 		DEBUG(1, "%s: SIOCGIWNAME\n", dev->name);
-		strcpy(wrq->u.name, "IEEE 802.11-DS");
+		orinoco_ioctl_getname(dev, NULL, &(wrq->u), NULL);
 		break;
 		
 	case SIOCGIWAP:
 		DEBUG(1, "%s: SIOCGIWAP\n", dev->name);
-		wrq->u.ap_addr.sa_family = ARPHRD_ETHER;
-		err = orinoco_hw_get_bssid(priv, wrq->u.ap_addr.sa_data);
+		err = orinoco_ioctl_getwap(dev, NULL, &(wrq->u), NULL);
 		break;
 
 	case SIOCGIWRANGE:
 		DEBUG(1, "%s: SIOCGIWRANGE\n", dev->name);
-		err = orinoco_ioctl_getiwrange(dev, &wrq->u.data);
+		{
+			struct iw_range range;
+			err = orinoco_ioctl_getiwrange(dev, NULL, &(wrq->u),
+						       (char *) &range);
+			if (copy_to_user(wrq->u.data.pointer, &range,
+					 sizeof(struct iw_range)))
+				err = -EFAULT;
+		}
 		break;
 
 	case SIOCSIWMODE:
 		DEBUG(1, "%s: SIOCSIWMODE\n", dev->name);
-		orinoco_lock(priv);
-		switch (wrq->u.mode) {
-		case IW_MODE_ADHOC:
-			if (! (priv->has_ibss || priv->has_port3) )
-				err = -EINVAL;
-			else {
-				priv->iw_mode = IW_MODE_ADHOC;
-				changed = 1;
-			}
-			break;
-
-		case IW_MODE_INFRA:
-			priv->iw_mode = IW_MODE_INFRA;
-			changed = 1;
-			break;
-
-		default:
-			err = -EINVAL;
-			break;
-		}
-		set_port_type(priv);
-		orinoco_unlock(priv);
+		err = orinoco_ioctl_setmode(dev, NULL, &(wrq->u), NULL);
 		break;
 
 	case SIOCGIWMODE:
 		DEBUG(1, "%s: SIOCGIWMODE\n", dev->name);
-		orinoco_lock(priv);
-		wrq->u.mode = priv->iw_mode;
-		orinoco_unlock(priv);
+		orinoco_ioctl_getmode(dev, NULL, &(wrq->u), NULL);
 		break;
 
 	case SIOCSIWENCODE:
 		DEBUG(1, "%s: SIOCSIWENCODE\n", dev->name);
-		if (! priv->has_wep) {
-			err = -EOPNOTSUPP;
-			break;
+		{
+			char keybuf[ORINOCO_MAX_KEY_SIZE];
+			if (wrq->u.encoding.pointer) {
+				/* We actually have a key to set */
+				if (wrq->u.encoding.length > ORINOCO_MAX_KEY_SIZE) {
+					err = -E2BIG;
+					break;
+				}
+				if (copy_from_user(keybuf,
+						   wrq->u.encoding.pointer,
+						   wrq->u.encoding.length)) {
+					err = -EFAULT;
+					break;
+				}
+			} else if (wrq->u.encoding.length != 0) {
+				err = -EINVAL;
+				break;
+			}
+			err = orinoco_ioctl_setiwencode(dev, NULL, &(wrq->u), keybuf);
 		}
-
-		err = orinoco_ioctl_setiwencode(dev, &wrq->u.encoding);
-		if (! err)
-			changed = 1;
 		break;
 
 	case SIOCGIWENCODE:
 		DEBUG(1, "%s: SIOCGIWENCODE\n", dev->name);
-		if (! priv->has_wep) {
-			err = -EOPNOTSUPP;
-			break;
-		}
 
 		if (! capable(CAP_NET_ADMIN)) {
 			err = -EPERM;
 			break;
 		}
-
-		err = orinoco_ioctl_getiwencode(dev, &wrq->u.encoding);
+		{
+			char keybuf[ORINOCO_MAX_KEY_SIZE];
+			err = orinoco_ioctl_getiwencode(dev, NULL, &(wrq->u),
+							keybuf);
+			if (wrq->u.encoding.pointer) {
+				if (copy_to_user(wrq->u.encoding.pointer,
+						 keybuf,
+						 wrq->u.encoding.length))
+					err= -EFAULT;
+			}
+		}
 		break;
 
 	case SIOCSIWESSID:
 		DEBUG(1, "%s: SIOCSIWESSID\n", dev->name);
-		err = orinoco_ioctl_setessid(dev, &wrq->u.essid);
-		if (! err)
-			changed = 1;
+		{
+			char essidbuf[IW_ESSID_MAX_SIZE+1];
+			if (wrq->u.essid.length > IW_ESSID_MAX_SIZE) {
+				err = -E2BIG;
+				break;
+			}
+			if (copy_from_user(essidbuf, wrq->u.essid.pointer,
+					   wrq->u.essid.length)) {
+				err = -EFAULT;
+				break;
+			}
+			err = orinoco_ioctl_setessid(dev, NULL, &(wrq->u),
+						     essidbuf);
+		}
 		break;
 
 	case SIOCGIWESSID:
 		DEBUG(1, "%s: SIOCGIWESSID\n", dev->name);
-		err = orinoco_ioctl_getessid(dev, &wrq->u.essid);
+		{
+			char essidbuf[IW_ESSID_MAX_SIZE+1];
+			err = orinoco_ioctl_getessid(dev, NULL, &(wrq->u),
+						     essidbuf);
+			if (wrq->u.essid.pointer)
+				if ( copy_to_user(wrq->u.essid.pointer,
+						  essidbuf,
+						  wrq->u.essid.length) )
+					err = -EFAULT;
+		}
 		break;
 
 	case SIOCSIWNICKN:
 		DEBUG(1, "%s: SIOCSIWNICKN\n", dev->name);
-		err = orinoco_ioctl_setnick(dev, &wrq->u.data);
-		if (! err)
-			changed = 1;
+		{
+			char nickbuf[IW_ESSID_MAX_SIZE+1];
+			if (wrq->u.essid.length > IW_ESSID_MAX_SIZE) {
+				err = -E2BIG;
+				break;
+			}
+			if (copy_from_user(nickbuf, wrq->u.essid.pointer,
+					   wrq->u.essid.length)) {
+				err = -EFAULT;
+				break;
+			}
+			err = orinoco_ioctl_setnick(dev, NULL, &(wrq->u),
+						    nickbuf);
+		}
 		break;
 
 	case SIOCGIWNICKN:
 		DEBUG(1, "%s: SIOCGIWNICKN\n", dev->name);
-		err = orinoco_ioctl_getnick(dev, &wrq->u.data);
+		{
+			char nickbuf[IW_ESSID_MAX_SIZE+1];
+			err = orinoco_ioctl_getnick(dev, NULL, &(wrq->u),
+						    nickbuf);
+			if (wrq->u.essid.pointer)
+				if ( copy_to_user(wrq->u.essid.pointer,
+						  nickbuf,
+						  wrq->u.essid.length) )
+					err = -EFAULT;
+		}
 		break;
 
 	case SIOCGIWFREQ:
 		DEBUG(1, "%s: SIOCGIWFREQ\n", dev->name);
-		wrq->u.freq.m = orinoco_hw_get_freq(priv);
-		wrq->u.freq.e = 1;
+		orinoco_ioctl_getfreq(dev, NULL, &(wrq->u), NULL);
 		break;
 
 	case SIOCSIWFREQ:
 		DEBUG(1, "%s: SIOCSIWFREQ\n", dev->name);
-		err = orinoco_ioctl_setfreq(dev, &wrq->u.freq);
-		if (! err)
-			changed = 1;
+		err = orinoco_ioctl_setfreq(dev, NULL, &(wrq->u), NULL);
 		break;
 
 	case SIOCGIWSENS:
 		DEBUG(1, "%s: SIOCGIWSENS\n", dev->name);
-		err = orinoco_ioctl_getsens(dev, &wrq->u.sens);
+		err = orinoco_ioctl_getsens(dev, NULL, &(wrq->u), NULL);
 		break;
 
 	case SIOCSIWSENS:
 		DEBUG(1, "%s: SIOCSIWSENS\n", dev->name);
-		err = orinoco_ioctl_setsens(dev, &wrq->u.sens);
-		if (! err)
-			changed = 1;
+		err = orinoco_ioctl_setsens(dev, NULL, &(wrq->u), NULL);
 		break;
 
 	case SIOCGIWRTS:
 		DEBUG(1, "%s: SIOCGIWRTS\n", dev->name);
-		wrq->u.rts.value = priv->rts_thresh;
-		wrq->u.rts.disabled = (wrq->u.rts.value == 2347);
-		wrq->u.rts.fixed = 1;
+		orinoco_ioctl_getrts(dev, NULL, &(wrq->u), NULL);
 		break;
 
 	case SIOCSIWRTS:
 		DEBUG(1, "%s: SIOCSIWRTS\n", dev->name);
-		err = orinoco_ioctl_setrts(dev, &wrq->u.rts);
-		if (! err)
-			changed = 1;
+		err = orinoco_ioctl_setrts(dev, NULL, &(wrq->u), NULL);
 		break;
 
 	case SIOCSIWFRAG:
 		DEBUG(1, "%s: SIOCSIWFRAG\n", dev->name);
-		err = orinoco_ioctl_setfrag(dev, &wrq->u.frag);
-		if (! err)
-			changed = 1;
+		err = orinoco_ioctl_setfrag(dev, NULL, &(wrq->u), NULL);
 		break;
 
 	case SIOCGIWFRAG:
 		DEBUG(1, "%s: SIOCGIWFRAG\n", dev->name);
-		err = orinoco_ioctl_getfrag(dev, &wrq->u.frag);
+		err = orinoco_ioctl_getfrag(dev, NULL, &(wrq->u), NULL);
 		break;
 
 	case SIOCSIWRATE:
 		DEBUG(1, "%s: SIOCSIWRATE\n", dev->name);
-		err = orinoco_ioctl_setrate(dev, &wrq->u.bitrate);
-		if (! err)
-			changed = 1;
+		err = orinoco_ioctl_setrate(dev, NULL, &(wrq->u), NULL);
 		break;
 
 	case SIOCGIWRATE:
 		DEBUG(1, "%s: SIOCGIWRATE\n", dev->name);
-		err = orinoco_ioctl_getrate(dev, &wrq->u.bitrate);
+		err = orinoco_ioctl_getrate(dev, NULL, &(wrq->u), NULL);
 		break;
 
 	case SIOCSIWPOWER:
 		DEBUG(1, "%s: SIOCSIWPOWER\n", dev->name);
-		err = orinoco_ioctl_setpower(dev, &wrq->u.power);
-		if (! err)
-			changed = 1;
+		err = orinoco_ioctl_setpower(dev, NULL, &(wrq->u), NULL);
 		break;
 
 	case SIOCGIWPOWER:
 		DEBUG(1, "%s: SIOCGIWPOWER\n", dev->name);
-		err = orinoco_ioctl_getpower(dev, &wrq->u.power);
+		err = orinoco_ioctl_getpower(dev, NULL, &(wrq->u), NULL);
 		break;
 
 	case SIOCGIWTXPOW:
 		DEBUG(1, "%s: SIOCGIWTXPOW\n", dev->name);
-		/* The card only supports one tx power, so this is easy */
-		wrq->u.txpower.value = 15; /* dBm */
-		wrq->u.txpower.fixed = 1;
-		wrq->u.txpower.disabled = 0;
-		wrq->u.txpower.flags = IW_TXPOW_DBM;
+		orinoco_ioctl_gettxpower(dev, NULL, &(wrq->u), NULL);
 		break;
 
 #if WIRELESS_EXT > 10
@@ -3306,82 +3672,79 @@ orinoco_ioctl(struct net_device *dev, st
 
 	case SIOCGIWRETRY:
 		DEBUG(1, "%s: SIOCGIWRETRY\n", dev->name);
-		err = orinoco_ioctl_getretry(dev, &wrq->u.retry);
+		err = orinoco_ioctl_getretry(dev, NULL, &(wrq->u), NULL);
 		break;
 #endif /* WIRELESS_EXT > 10 */
 
 	case SIOCSIWSPY:
 		DEBUG(1, "%s: SIOCSIWSPY\n", dev->name);
-
-		err = orinoco_ioctl_setspy(dev, &wrq->u.data);
+		{
+			struct sockaddr address[IW_MAX_SPY];
+			/* Check the number of addresses */
+			if (wrq->u.data.length > IW_MAX_SPY) {
+				err = -E2BIG;
+				break;
+			}
+			/* Get the data in the driver */
+			if (wrq->u.data.pointer) {
+				if (copy_from_user((char *) address,
+						   wrq->u.data.pointer,
+						   sizeof(struct sockaddr) *
+						   wrq->u.data.length)) {
+					err = -EFAULT;
+					break;
+				}
+			} else if (wrq->u.data.length != 0) {
+				err = -EINVAL;
+				break;
+			}
+			err = orinoco_ioctl_setspy(dev, NULL, &(wrq->u),
+						   (char *) address);
+		}
 		break;
 
 	case SIOCGIWSPY:
 		DEBUG(1, "%s: SIOCGIWSPY\n", dev->name);
-
-		err = orinoco_ioctl_getspy(dev, &wrq->u.data);
+		{
+			char buffer[IW_MAX_SPY * (sizeof(struct sockaddr) +
+						  sizeof(struct iw_quality))];
+			err = orinoco_ioctl_getspy(dev, NULL, &(wrq->u),
+						   buffer);
+			if (wrq->u.data.pointer) {
+				if (copy_to_user(wrq->u.data.pointer,
+						 buffer,
+						 (wrq->u.data.length *
+						  (sizeof(struct sockaddr) +
+						   sizeof(struct iw_quality)))
+						 ))
+					err = -EFAULT;
+			}
+		}
 		break;
 
 	case SIOCGIWPRIV:
 		DEBUG(1, "%s: SIOCGIWPRIV\n", dev->name);
 		if (wrq->u.data.pointer) {
-			struct iw_priv_args privtab[] = {
-				{ SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" },
-				{ SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" },
-				{ SIOCIWFIRSTPRIV + 0x2,
-				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-				  0, "set_port3" },
-				{ SIOCIWFIRSTPRIV + 0x3, 0,
-				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-				  "get_port3" },
-				{ SIOCIWFIRSTPRIV + 0x4,
-				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-				  0, "set_preamble" },
-				{ SIOCIWFIRSTPRIV + 0x5, 0,
-				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-				  "get_preamble" },
-				{ SIOCIWFIRSTPRIV + 0x6,
-				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-				  0, "set_ibssport" },
-				{ SIOCIWFIRSTPRIV + 0x7, 0,
-				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-				  "get_ibssport" }
-			};
-
-			err = verify_area(VERIFY_WRITE, wrq->u.data.pointer, sizeof(privtab));
+			err = verify_area(VERIFY_WRITE, wrq->u.data.pointer, sizeof(orinoco_privtab));
 			if (err)
 				break;
 			
-			wrq->u.data.length = sizeof(privtab) / sizeof(privtab[0]);
-			if (copy_to_user(wrq->u.data.pointer, privtab, sizeof(privtab)))
+			wrq->u.data.length = sizeof(orinoco_privtab) / sizeof(orinoco_privtab[0]);
+			if (copy_to_user(wrq->u.data.pointer, orinoco_privtab, sizeof(orinoco_privtab)))
 				err = -EFAULT;
 		}
 		break;
 	       
 	case SIOCIWFIRSTPRIV + 0x0: /* force_reset */
-		DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x0 (force_reset)\n",
-		      dev->name);
-		if (! capable(CAP_NET_ADMIN)) {
-			err = -EPERM;
-			break;
-		}
-		
-		printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name);
-		orinoco_reset(priv);
-		break;
-
 	case SIOCIWFIRSTPRIV + 0x1: /* card_reset */
-		DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x1 (card_reset)\n",
-		      dev->name);
-		if (! capable(CAP_NET_ADMIN)) {
-			err = -EPERM;
-			break;
+		DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x%d (force_reset)\n",
+		      dev->name, cmd - SIOCIWFIRSTPRIV);
+		{
+			struct iw_request_info		info;
+			info.cmd = cmd;
+			orinoco_ioctl_reset(dev, &info, &(wrq->u),
+					    (char *) &(wrq->u));
 		}
-		
-		printk(KERN_DEBUG "%s: Forcing card reset!\n", dev->name);
-		if(priv->card_reset_handler != NULL)
-			priv->card_reset_handler(priv);
-		orinoco_reset(priv);
 		break;
 
 	case SIOCIWFIRSTPRIV + 0x2: /* set_port3 */
@@ -3392,15 +3755,15 @@ orinoco_ioctl(struct net_device *dev, st
 			break;
 		}
 
-		err = orinoco_ioctl_setport3(dev, wrq);
-		if (! err)
-			changed = 1;
+		err = orinoco_ioctl_setport3(dev, NULL, &(wrq->u),
+					     (char *) &(wrq->u));
 		break;
 
 	case SIOCIWFIRSTPRIV + 0x3: /* get_port3 */
 		DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x3 (get_port3)\n",
 		      dev->name);
-		err = orinoco_ioctl_getport3(dev, wrq);
+		err = orinoco_ioctl_getport3(dev, NULL, &(wrq->u),
+					     (char *) &(wrq->u));
 		break;
 
 	case SIOCIWFIRSTPRIV + 0x4: /* set_preamble */
@@ -3411,36 +3774,15 @@ orinoco_ioctl(struct net_device *dev, st
 			break;
 		}
 
-		/* 802.11b has recently defined some short preamble.
-		 * Basically, the Phy header has been reduced in size.
-		 * This increase performance, especially at high rates
-		 * (the preamble is transmitted at 1Mb/s), unfortunately
-		 * this give compatibility troubles... - Jean II */
-		if(priv->has_preamble) {
-			int val = *( (int *) wrq->u.name );
-
-			orinoco_lock(priv);
-			if(val)
-				priv->preamble = 1;
-			else
-				priv->preamble = 0;
-			orinoco_unlock(priv);
-			changed = 1;
-		} else
-			err = -EOPNOTSUPP;
+		err = orinoco_ioctl_setpreamble(dev, NULL, &(wrq->u),
+						(char *) &(wrq->u));
 		break;
 
 	case SIOCIWFIRSTPRIV + 0x5: /* get_preamble */
 		DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x5 (get_preamble)\n",
 		      dev->name);
-		if(priv->has_preamble) {
-			int *val = (int *)wrq->u.name;
-
-			orinoco_lock(priv);
-			*val = priv->preamble;
-			orinoco_unlock(priv);
-		} else
-			err = -EOPNOTSUPP;
+		err = orinoco_ioctl_getpreamble(dev, NULL, &(wrq->u),
+						(char *) &(wrq->u));
 		break;
 	case SIOCIWFIRSTPRIV + 0x6: /* set_ibssport */
 		DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x6 (set_ibssport)\n",
@@ -3450,15 +3792,15 @@ orinoco_ioctl(struct net_device *dev, st
 			break;
 		}
 
-		err = orinoco_ioctl_setibssport(dev, wrq);
-		if (! err)
-			changed = 1;
+		err = orinoco_ioctl_setibssport(dev, NULL, &(wrq->u),
+						(char *) &(wrq->u));
 		break;
 
 	case SIOCIWFIRSTPRIV + 0x7: /* get_ibssport */
 		DEBUG(1, "%s: SIOCIWFIRSTPRIV + 0x7 (get_ibssport)\n",
 		      dev->name);
-		err = orinoco_ioctl_getibssport(dev, wrq);
+		err = orinoco_ioctl_getibssport(dev, NULL, &(wrq->u),
+						(char *) &(wrq->u));
 		break;
 
 
@@ -3466,22 +3808,18 @@ orinoco_ioctl(struct net_device *dev, st
 		err = -EOPNOTSUPP;
 	}
 	
-	if (! err && changed && netif_running(dev)) {
-		err = orinoco_reset(priv);
-		if (err) {
-			/* Ouch ! What are we supposed to do ? */
-			printk(KERN_ERR "orinoco_cs: Failed to set parameters on %s\n",
-			       dev->name);
-			netif_stop_queue(dev);
-			orinoco_shutdown(priv);
-			priv->hw_ready = 0;
-		}
-	}		
+	if (err == -EINPROGRESS) {
+		if(netif_running(dev))
+			err = orinoco_ioctl_commit(dev, NULL, NULL, NULL);
+		else
+			err = 0;	/* Success */
+	}
 
 	TRACE_EXIT(dev->name);
 		
 	return err;
 }
+#endif /* WIRELESS_EXT > 12 */
 
 int
 orinoco_change_mtu(struct net_device *dev, int new_mtu)
@@ -4077,7 +4415,11 @@ orinoco_setup(struct orinoco_private* pr
 	dev->get_stats = orinoco_get_stats;
 	dev->get_wireless_stats = orinoco_get_wireless_stats;
 
+#if WIRELESS_EXT > 12
+	dev->wireless_handlers = (struct iw_handler_def *)&orinoco_handler_def;
+#else /* WIRELESS_EXT > 12 */
 	dev->do_ioctl = orinoco_ioctl;
+#endif /* WIRELESS_EXT > 12 */
 
 	dev->change_mtu = orinoco_change_mtu;
 	dev->set_multicast_list = orinoco_set_multicast_list;
@@ -4093,7 +4435,6 @@ EXPORT_SYMBOL(orinoco_debug);
 EXPORT_SYMBOL(orinoco_init);
 EXPORT_SYMBOL(orinoco_xmit);
 EXPORT_SYMBOL(orinoco_tx_timeout);
-EXPORT_SYMBOL(orinoco_ioctl);
 EXPORT_SYMBOL(orinoco_change_mtu);
 EXPORT_SYMBOL(orinoco_set_multicast_list);
 EXPORT_SYMBOL(orinoco_shutdown);
diff -u -p -r linux/drivers/net/wireless-w12/orinoco.h linux/drivers/net/wireless/orinoco.h
--- linux/drivers/net/wireless-w12/orinoco.h	Tue Dec 11 15:36:06 2001
+++ linux/drivers/net/wireless/orinoco.h	Thu Dec 13 13:31:02 2001
@@ -116,7 +116,9 @@ extern int orinoco_init(struct net_devic
 extern int orinoco_xmit(struct sk_buff *skb, struct net_device *dev);
 extern void orinoco_tx_timeout(struct net_device *dev);
 
+#if WIRELESS_EXT <= 12
 extern int orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+#endif /* WIRELESS_EXT <= 12 */
 extern int orinoco_change_mtu(struct net_device *dev, int new_mtu);
 extern void orinoco_set_multicast_list(struct net_device *dev);
 


More information about the wireless mailing list