12be45b66SKalle Valo /* Wireless extensions support.
22be45b66SKalle Valo  *
32be45b66SKalle Valo  * See copyright notice in main.c
42be45b66SKalle Valo  */
52be45b66SKalle Valo #include <linux/slab.h>
62be45b66SKalle Valo #include <linux/kernel.h>
72be45b66SKalle Valo #include <linux/if_arp.h>
82be45b66SKalle Valo #include <linux/wireless.h>
92be45b66SKalle Valo #include <linux/ieee80211.h>
102be45b66SKalle Valo #include <linux/etherdevice.h>
112be45b66SKalle Valo #include <net/iw_handler.h>
122be45b66SKalle Valo #include <net/cfg80211.h>
132be45b66SKalle Valo #include <net/cfg80211-wext.h>
142be45b66SKalle Valo 
152be45b66SKalle Valo #include "hermes.h"
162be45b66SKalle Valo #include "hermes_rid.h"
172be45b66SKalle Valo #include "orinoco.h"
182be45b66SKalle Valo 
192be45b66SKalle Valo #include "hw.h"
202be45b66SKalle Valo #include "mic.h"
212be45b66SKalle Valo #include "scan.h"
222be45b66SKalle Valo #include "main.h"
232be45b66SKalle Valo 
242be45b66SKalle Valo #include "wext.h"
252be45b66SKalle Valo 
262be45b66SKalle Valo #define MAX_RID_LEN 1024
272be45b66SKalle Valo 
282be45b66SKalle Valo /* Helper routine to record keys
292be45b66SKalle Valo  * It is called under orinoco_lock so it may not sleep */
orinoco_set_key(struct orinoco_private * priv,int index,enum orinoco_alg alg,const u8 * key,int key_len,const u8 * seq,int seq_len)302be45b66SKalle Valo static int orinoco_set_key(struct orinoco_private *priv, int index,
312be45b66SKalle Valo 			   enum orinoco_alg alg, const u8 *key, int key_len,
322be45b66SKalle Valo 			   const u8 *seq, int seq_len)
332be45b66SKalle Valo {
34453431a5SWaiman Long 	kfree_sensitive(priv->keys[index].key);
35453431a5SWaiman Long 	kfree_sensitive(priv->keys[index].seq);
362be45b66SKalle Valo 
372be45b66SKalle Valo 	if (key_len) {
382be45b66SKalle Valo 		priv->keys[index].key = kzalloc(key_len, GFP_ATOMIC);
392be45b66SKalle Valo 		if (!priv->keys[index].key)
402be45b66SKalle Valo 			goto nomem;
412be45b66SKalle Valo 	} else
422be45b66SKalle Valo 		priv->keys[index].key = NULL;
432be45b66SKalle Valo 
442be45b66SKalle Valo 	if (seq_len) {
452be45b66SKalle Valo 		priv->keys[index].seq = kzalloc(seq_len, GFP_ATOMIC);
462be45b66SKalle Valo 		if (!priv->keys[index].seq)
472be45b66SKalle Valo 			goto free_key;
482be45b66SKalle Valo 	} else
492be45b66SKalle Valo 		priv->keys[index].seq = NULL;
502be45b66SKalle Valo 
512be45b66SKalle Valo 	priv->keys[index].key_len = key_len;
522be45b66SKalle Valo 	priv->keys[index].seq_len = seq_len;
532be45b66SKalle Valo 
542be45b66SKalle Valo 	if (key_len)
552be45b66SKalle Valo 		memcpy((void *)priv->keys[index].key, key, key_len);
562be45b66SKalle Valo 	if (seq_len)
572be45b66SKalle Valo 		memcpy((void *)priv->keys[index].seq, seq, seq_len);
582be45b66SKalle Valo 
592be45b66SKalle Valo 	switch (alg) {
602be45b66SKalle Valo 	case ORINOCO_ALG_TKIP:
612be45b66SKalle Valo 		priv->keys[index].cipher = WLAN_CIPHER_SUITE_TKIP;
622be45b66SKalle Valo 		break;
632be45b66SKalle Valo 
642be45b66SKalle Valo 	case ORINOCO_ALG_WEP:
652be45b66SKalle Valo 		priv->keys[index].cipher = (key_len > SMALL_KEY_SIZE) ?
662be45b66SKalle Valo 			WLAN_CIPHER_SUITE_WEP104 : WLAN_CIPHER_SUITE_WEP40;
672be45b66SKalle Valo 		break;
682be45b66SKalle Valo 
692be45b66SKalle Valo 	case ORINOCO_ALG_NONE:
702be45b66SKalle Valo 	default:
712be45b66SKalle Valo 		priv->keys[index].cipher = 0;
722be45b66SKalle Valo 		break;
732be45b66SKalle Valo 	}
742be45b66SKalle Valo 
752be45b66SKalle Valo 	return 0;
762be45b66SKalle Valo 
772be45b66SKalle Valo free_key:
782be45b66SKalle Valo 	kfree(priv->keys[index].key);
792be45b66SKalle Valo 	priv->keys[index].key = NULL;
802be45b66SKalle Valo 
812be45b66SKalle Valo nomem:
822be45b66SKalle Valo 	priv->keys[index].key_len = 0;
832be45b66SKalle Valo 	priv->keys[index].seq_len = 0;
842be45b66SKalle Valo 	priv->keys[index].cipher = 0;
852be45b66SKalle Valo 
862be45b66SKalle Valo 	return -ENOMEM;
872be45b66SKalle Valo }
882be45b66SKalle Valo 
orinoco_get_wireless_stats(struct net_device * dev)892be45b66SKalle Valo static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
902be45b66SKalle Valo {
912be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
922be45b66SKalle Valo 	struct hermes *hw = &priv->hw;
932be45b66SKalle Valo 	struct iw_statistics *wstats = &priv->wstats;
942be45b66SKalle Valo 	int err;
952be45b66SKalle Valo 	unsigned long flags;
962be45b66SKalle Valo 
972be45b66SKalle Valo 	if (!netif_device_present(dev)) {
982be45b66SKalle Valo 		printk(KERN_WARNING "%s: get_wireless_stats() called while device not present\n",
992be45b66SKalle Valo 		       dev->name);
1002be45b66SKalle Valo 		return NULL; /* FIXME: Can we do better than this? */
1012be45b66SKalle Valo 	}
1022be45b66SKalle Valo 
1032be45b66SKalle Valo 	/* If busy, return the old stats.  Returning NULL may cause
1042be45b66SKalle Valo 	 * the interface to disappear from /proc/net/wireless */
1052be45b66SKalle Valo 	if (orinoco_lock(priv, &flags) != 0)
1062be45b66SKalle Valo 		return wstats;
1072be45b66SKalle Valo 
1082be45b66SKalle Valo 	/* We can't really wait for the tallies inquiry command to
1092be45b66SKalle Valo 	 * complete, so we just use the previous results and trigger
1102be45b66SKalle Valo 	 * a new tallies inquiry command for next time - Jean II */
1112be45b66SKalle Valo 	/* FIXME: Really we should wait for the inquiry to come back -
1122be45b66SKalle Valo 	 * as it is the stats we give don't make a whole lot of sense.
1132be45b66SKalle Valo 	 * Unfortunately, it's not clear how to do that within the
1142be45b66SKalle Valo 	 * wireless extensions framework: I think we're in user
1152be45b66SKalle Valo 	 * context, but a lock seems to be held by the time we get in
1162be45b66SKalle Valo 	 * here so we're not safe to sleep here. */
1172be45b66SKalle Valo 	hermes_inquire(hw, HERMES_INQ_TALLIES);
1182be45b66SKalle Valo 
1192be45b66SKalle Valo 	if (priv->iw_mode == NL80211_IFTYPE_ADHOC) {
1202be45b66SKalle Valo 		memset(&wstats->qual, 0, sizeof(wstats->qual));
1212be45b66SKalle Valo 		/* If a spy address is defined, we report stats of the
1222be45b66SKalle Valo 		 * first spy address - Jean II */
1232be45b66SKalle Valo 		if (SPY_NUMBER(priv)) {
1242be45b66SKalle Valo 			wstats->qual.qual = priv->spy_data.spy_stat[0].qual;
1252be45b66SKalle Valo 			wstats->qual.level = priv->spy_data.spy_stat[0].level;
1262be45b66SKalle Valo 			wstats->qual.noise = priv->spy_data.spy_stat[0].noise;
1272be45b66SKalle Valo 			wstats->qual.updated =
1282be45b66SKalle Valo 				priv->spy_data.spy_stat[0].updated;
1292be45b66SKalle Valo 		}
1302be45b66SKalle Valo 	} else {
1312be45b66SKalle Valo 		struct {
1322be45b66SKalle Valo 			__le16 qual, signal, noise, unused;
1332be45b66SKalle Valo 		} __packed cq;
1342be45b66SKalle Valo 
1352be45b66SKalle Valo 		err = HERMES_READ_RECORD(hw, USER_BAP,
1362be45b66SKalle Valo 					 HERMES_RID_COMMSQUALITY, &cq);
1372be45b66SKalle Valo 
1382be45b66SKalle Valo 		if (!err) {
1392be45b66SKalle Valo 			wstats->qual.qual = (int)le16_to_cpu(cq.qual);
1402be45b66SKalle Valo 			wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95;
1412be45b66SKalle Valo 			wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95;
1422be45b66SKalle Valo 			wstats->qual.updated =
1432be45b66SKalle Valo 				IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
1442be45b66SKalle Valo 		}
1452be45b66SKalle Valo 	}
1462be45b66SKalle Valo 
1472be45b66SKalle Valo 	orinoco_unlock(priv, &flags);
1482be45b66SKalle Valo 	return wstats;
1492be45b66SKalle Valo }
1502be45b66SKalle Valo 
1512be45b66SKalle Valo /********************************************************************/
1522be45b66SKalle Valo /* Wireless extensions                                              */
1532be45b66SKalle Valo /********************************************************************/
1542be45b66SKalle Valo 
orinoco_ioctl_setwap(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1552be45b66SKalle Valo static int orinoco_ioctl_setwap(struct net_device *dev,
1562be45b66SKalle Valo 				struct iw_request_info *info,
1572c0e077dSGustavo A. R. Silva 				union iwreq_data *wrqu,
1582be45b66SKalle Valo 				char *extra)
1592be45b66SKalle Valo {
1602c0e077dSGustavo A. R. Silva 	struct sockaddr *ap_addr = &wrqu->ap_addr;
1612be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
1622be45b66SKalle Valo 	int err = -EINPROGRESS;		/* Call commit handler */
1632be45b66SKalle Valo 	unsigned long flags;
1642be45b66SKalle Valo 
1652be45b66SKalle Valo 	if (orinoco_lock(priv, &flags) != 0)
1662be45b66SKalle Valo 		return -EBUSY;
1672be45b66SKalle Valo 
1682be45b66SKalle Valo 	/* Enable automatic roaming - no sanity checks are needed */
1692be45b66SKalle Valo 	if (is_zero_ether_addr(ap_addr->sa_data) ||
1702be45b66SKalle Valo 	    is_broadcast_ether_addr(ap_addr->sa_data)) {
1712be45b66SKalle Valo 		priv->bssid_fixed = 0;
1722be45b66SKalle Valo 		eth_zero_addr(priv->desired_bssid);
1732be45b66SKalle Valo 
1742be45b66SKalle Valo 		/* "off" means keep existing connection */
1752be45b66SKalle Valo 		if (ap_addr->sa_data[0] == 0) {
1762be45b66SKalle Valo 			__orinoco_hw_set_wap(priv);
1772be45b66SKalle Valo 			err = 0;
1782be45b66SKalle Valo 		}
1792be45b66SKalle Valo 		goto out;
1802be45b66SKalle Valo 	}
1812be45b66SKalle Valo 
1822be45b66SKalle Valo 	if (priv->firmware_type == FIRMWARE_TYPE_AGERE) {
1832be45b66SKalle Valo 		printk(KERN_WARNING "%s: Lucent/Agere firmware doesn't "
1842be45b66SKalle Valo 		       "support manual roaming\n",
1852be45b66SKalle Valo 		       dev->name);
1862be45b66SKalle Valo 		err = -EOPNOTSUPP;
1872be45b66SKalle Valo 		goto out;
1882be45b66SKalle Valo 	}
1892be45b66SKalle Valo 
1902be45b66SKalle Valo 	if (priv->iw_mode != NL80211_IFTYPE_STATION) {
1912be45b66SKalle Valo 		printk(KERN_WARNING "%s: Manual roaming supported only in "
1922be45b66SKalle Valo 		       "managed mode\n", dev->name);
1932be45b66SKalle Valo 		err = -EOPNOTSUPP;
1942be45b66SKalle Valo 		goto out;
1952be45b66SKalle Valo 	}
1962be45b66SKalle Valo 
1972be45b66SKalle Valo 	/* Intersil firmware hangs without Desired ESSID */
1982be45b66SKalle Valo 	if (priv->firmware_type == FIRMWARE_TYPE_INTERSIL &&
1992be45b66SKalle Valo 	    strlen(priv->desired_essid) == 0) {
2002be45b66SKalle Valo 		printk(KERN_WARNING "%s: Desired ESSID must be set for "
2012be45b66SKalle Valo 		       "manual roaming\n", dev->name);
2022be45b66SKalle Valo 		err = -EOPNOTSUPP;
2032be45b66SKalle Valo 		goto out;
2042be45b66SKalle Valo 	}
2052be45b66SKalle Valo 
2062be45b66SKalle Valo 	/* Finally, enable manual roaming */
2072be45b66SKalle Valo 	priv->bssid_fixed = 1;
2082be45b66SKalle Valo 	memcpy(priv->desired_bssid, &ap_addr->sa_data, ETH_ALEN);
2092be45b66SKalle Valo 
2102be45b66SKalle Valo  out:
2112be45b66SKalle Valo 	orinoco_unlock(priv, &flags);
2122be45b66SKalle Valo 	return err;
2132be45b66SKalle Valo }
2142be45b66SKalle Valo 
orinoco_ioctl_getwap(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)2152be45b66SKalle Valo static int orinoco_ioctl_getwap(struct net_device *dev,
2162be45b66SKalle Valo 				struct iw_request_info *info,
2172c0e077dSGustavo A. R. Silva 				union iwreq_data *wrqu,
2182be45b66SKalle Valo 				char *extra)
2192be45b66SKalle Valo {
2202c0e077dSGustavo A. R. Silva 	struct sockaddr *ap_addr = &wrqu->ap_addr;
2212be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
2222be45b66SKalle Valo 
2232be45b66SKalle Valo 	int err = 0;
2242be45b66SKalle Valo 	unsigned long flags;
2252be45b66SKalle Valo 
2262be45b66SKalle Valo 	if (orinoco_lock(priv, &flags) != 0)
2272be45b66SKalle Valo 		return -EBUSY;
2282be45b66SKalle Valo 
2292be45b66SKalle Valo 	ap_addr->sa_family = ARPHRD_ETHER;
2302be45b66SKalle Valo 	err = orinoco_hw_get_current_bssid(priv, ap_addr->sa_data);
2312be45b66SKalle Valo 
2322be45b66SKalle Valo 	orinoco_unlock(priv, &flags);
2332be45b66SKalle Valo 
2342be45b66SKalle Valo 	return err;
2352be45b66SKalle Valo }
2362be45b66SKalle Valo 
orinoco_ioctl_setiwencode(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * keybuf)2372be45b66SKalle Valo static int orinoco_ioctl_setiwencode(struct net_device *dev,
2382be45b66SKalle Valo 				     struct iw_request_info *info,
2392c0e077dSGustavo A. R. Silva 				     union iwreq_data *wrqu,
2402be45b66SKalle Valo 				     char *keybuf)
2412be45b66SKalle Valo {
2422c0e077dSGustavo A. R. Silva 	struct iw_point *erq = &wrqu->encoding;
2432be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
2442be45b66SKalle Valo 	int index = (erq->flags & IW_ENCODE_INDEX) - 1;
2452be45b66SKalle Valo 	int setindex = priv->tx_key;
2462be45b66SKalle Valo 	enum orinoco_alg encode_alg = priv->encode_alg;
2472be45b66SKalle Valo 	int restricted = priv->wep_restrict;
2482be45b66SKalle Valo 	int err = -EINPROGRESS;		/* Call commit handler */
2492be45b66SKalle Valo 	unsigned long flags;
2502be45b66SKalle Valo 
2512be45b66SKalle Valo 	if (!priv->has_wep)
2522be45b66SKalle Valo 		return -EOPNOTSUPP;
2532be45b66SKalle Valo 
2542be45b66SKalle Valo 	if (erq->pointer) {
2552be45b66SKalle Valo 		/* We actually have a key to set - check its length */
2562be45b66SKalle Valo 		if (erq->length > LARGE_KEY_SIZE)
2572be45b66SKalle Valo 			return -E2BIG;
2582be45b66SKalle Valo 
2592be45b66SKalle Valo 		if ((erq->length > SMALL_KEY_SIZE) && !priv->has_big_wep)
2602be45b66SKalle Valo 			return -E2BIG;
2612be45b66SKalle Valo 	}
2622be45b66SKalle Valo 
2632be45b66SKalle Valo 	if (orinoco_lock(priv, &flags) != 0)
2642be45b66SKalle Valo 		return -EBUSY;
2652be45b66SKalle Valo 
2662be45b66SKalle Valo 	/* Clear any TKIP key we have */
2672be45b66SKalle Valo 	if ((priv->has_wpa) && (priv->encode_alg == ORINOCO_ALG_TKIP))
2682be45b66SKalle Valo 		(void) orinoco_clear_tkip_key(priv, setindex);
2692be45b66SKalle Valo 
2702be45b66SKalle Valo 	if (erq->length > 0) {
2712be45b66SKalle Valo 		if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
2722be45b66SKalle Valo 			index = priv->tx_key;
2732be45b66SKalle Valo 
2742be45b66SKalle Valo 		/* Switch on WEP if off */
2752be45b66SKalle Valo 		if (encode_alg != ORINOCO_ALG_WEP) {
2762be45b66SKalle Valo 			setindex = index;
2772be45b66SKalle Valo 			encode_alg = ORINOCO_ALG_WEP;
2782be45b66SKalle Valo 		}
2792be45b66SKalle Valo 	} else {
2802be45b66SKalle Valo 		/* Important note : if the user do "iwconfig eth0 enc off",
2812be45b66SKalle Valo 		 * we will arrive there with an index of -1. This is valid
2822be45b66SKalle Valo 		 * but need to be taken care off... Jean II */
2832be45b66SKalle Valo 		if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) {
2842be45b66SKalle Valo 			if ((index != -1) || (erq->flags == 0)) {
2852be45b66SKalle Valo 				err = -EINVAL;
2862be45b66SKalle Valo 				goto out;
2872be45b66SKalle Valo 			}
2882be45b66SKalle Valo 		} else {
2892be45b66SKalle Valo 			/* Set the index : Check that the key is valid */
2902be45b66SKalle Valo 			if (priv->keys[index].key_len == 0) {
2912be45b66SKalle Valo 				err = -EINVAL;
2922be45b66SKalle Valo 				goto out;
2932be45b66SKalle Valo 			}
2942be45b66SKalle Valo 			setindex = index;
2952be45b66SKalle Valo 		}
2962be45b66SKalle Valo 	}
2972be45b66SKalle Valo 
2982be45b66SKalle Valo 	if (erq->flags & IW_ENCODE_DISABLED)
2992be45b66SKalle Valo 		encode_alg = ORINOCO_ALG_NONE;
3002be45b66SKalle Valo 	if (erq->flags & IW_ENCODE_OPEN)
3012be45b66SKalle Valo 		restricted = 0;
3022be45b66SKalle Valo 	if (erq->flags & IW_ENCODE_RESTRICTED)
3032be45b66SKalle Valo 		restricted = 1;
3042be45b66SKalle Valo 
3052be45b66SKalle Valo 	if (erq->pointer && erq->length > 0) {
3062be45b66SKalle Valo 		err = orinoco_set_key(priv, index, ORINOCO_ALG_WEP, keybuf,
3072be45b66SKalle Valo 				      erq->length, NULL, 0);
3082be45b66SKalle Valo 	}
3092be45b66SKalle Valo 	priv->tx_key = setindex;
3102be45b66SKalle Valo 
3112be45b66SKalle Valo 	/* Try fast key change if connected and only keys are changed */
3122be45b66SKalle Valo 	if ((priv->encode_alg == encode_alg) &&
3132be45b66SKalle Valo 	    (priv->wep_restrict == restricted) &&
3142be45b66SKalle Valo 	    netif_carrier_ok(dev)) {
3152be45b66SKalle Valo 		err = __orinoco_hw_setup_wepkeys(priv);
3162be45b66SKalle Valo 		/* No need to commit if successful */
3172be45b66SKalle Valo 		goto out;
3182be45b66SKalle Valo 	}
3192be45b66SKalle Valo 
3202be45b66SKalle Valo 	priv->encode_alg = encode_alg;
3212be45b66SKalle Valo 	priv->wep_restrict = restricted;
3222be45b66SKalle Valo 
3232be45b66SKalle Valo  out:
3242be45b66SKalle Valo 	orinoco_unlock(priv, &flags);
3252be45b66SKalle Valo 
3262be45b66SKalle Valo 	return err;
3272be45b66SKalle Valo }
3282be45b66SKalle Valo 
orinoco_ioctl_getiwencode(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * keybuf)3292be45b66SKalle Valo static int orinoco_ioctl_getiwencode(struct net_device *dev,
3302be45b66SKalle Valo 				     struct iw_request_info *info,
3312c0e077dSGustavo A. R. Silva 				     union iwreq_data *wrqu,
3322be45b66SKalle Valo 				     char *keybuf)
3332be45b66SKalle Valo {
3342c0e077dSGustavo A. R. Silva 	struct iw_point *erq = &wrqu->encoding;
3352be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
3362be45b66SKalle Valo 	int index = (erq->flags & IW_ENCODE_INDEX) - 1;
3372be45b66SKalle Valo 	unsigned long flags;
3382be45b66SKalle Valo 
3392be45b66SKalle Valo 	if (!priv->has_wep)
3402be45b66SKalle Valo 		return -EOPNOTSUPP;
3412be45b66SKalle Valo 
3422be45b66SKalle Valo 	if (orinoco_lock(priv, &flags) != 0)
3432be45b66SKalle Valo 		return -EBUSY;
3442be45b66SKalle Valo 
3452be45b66SKalle Valo 	if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
3462be45b66SKalle Valo 		index = priv->tx_key;
3472be45b66SKalle Valo 
3482be45b66SKalle Valo 	erq->flags = 0;
3492be45b66SKalle Valo 	if (!priv->encode_alg)
3502be45b66SKalle Valo 		erq->flags |= IW_ENCODE_DISABLED;
3512be45b66SKalle Valo 	erq->flags |= index + 1;
3522be45b66SKalle Valo 
3532be45b66SKalle Valo 	if (priv->wep_restrict)
3542be45b66SKalle Valo 		erq->flags |= IW_ENCODE_RESTRICTED;
3552be45b66SKalle Valo 	else
3562be45b66SKalle Valo 		erq->flags |= IW_ENCODE_OPEN;
3572be45b66SKalle Valo 
3582be45b66SKalle Valo 	erq->length = priv->keys[index].key_len;
3592be45b66SKalle Valo 
3602be45b66SKalle Valo 	memcpy(keybuf, priv->keys[index].key, erq->length);
3612be45b66SKalle Valo 
3622be45b66SKalle Valo 	orinoco_unlock(priv, &flags);
3632be45b66SKalle Valo 	return 0;
3642be45b66SKalle Valo }
3652be45b66SKalle Valo 
orinoco_ioctl_setessid(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * essidbuf)3662be45b66SKalle Valo static int orinoco_ioctl_setessid(struct net_device *dev,
3672be45b66SKalle Valo 				  struct iw_request_info *info,
3682c0e077dSGustavo A. R. Silva 				  union iwreq_data *wrqu,
3692be45b66SKalle Valo 				  char *essidbuf)
3702be45b66SKalle Valo {
3712c0e077dSGustavo A. R. Silva 	struct iw_point *erq = &wrqu->essid;
3722be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
3732be45b66SKalle Valo 	unsigned long flags;
3742be45b66SKalle Valo 
3752be45b66SKalle Valo 	/* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it
3762be45b66SKalle Valo 	 * anyway... - Jean II */
3772be45b66SKalle Valo 
3782be45b66SKalle Valo 	/* Hum... Should not use Wireless Extension constant (may change),
3792be45b66SKalle Valo 	 * should use our own... - Jean II */
3802be45b66SKalle Valo 	if (erq->length > IW_ESSID_MAX_SIZE)
3812be45b66SKalle Valo 		return -E2BIG;
3822be45b66SKalle Valo 
3832be45b66SKalle Valo 	if (orinoco_lock(priv, &flags) != 0)
3842be45b66SKalle Valo 		return -EBUSY;
3852be45b66SKalle Valo 
3862be45b66SKalle Valo 	/* NULL the string (for NULL termination & ESSID = ANY) - Jean II */
3872be45b66SKalle Valo 	memset(priv->desired_essid, 0, sizeof(priv->desired_essid));
3882be45b66SKalle Valo 
3892be45b66SKalle Valo 	/* If not ANY, get the new ESSID */
3902be45b66SKalle Valo 	if (erq->flags)
3912be45b66SKalle Valo 		memcpy(priv->desired_essid, essidbuf, erq->length);
3922be45b66SKalle Valo 
3932be45b66SKalle Valo 	orinoco_unlock(priv, &flags);
3942be45b66SKalle Valo 
3952be45b66SKalle Valo 	return -EINPROGRESS;		/* Call commit handler */
3962be45b66SKalle Valo }
3972be45b66SKalle Valo 
orinoco_ioctl_getessid(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * essidbuf)3982be45b66SKalle Valo static int orinoco_ioctl_getessid(struct net_device *dev,
3992be45b66SKalle Valo 				  struct iw_request_info *info,
4002c0e077dSGustavo A. R. Silva 				  union iwreq_data *wrqu,
4012be45b66SKalle Valo 				  char *essidbuf)
4022be45b66SKalle Valo {
4032c0e077dSGustavo A. R. Silva 	struct iw_point *erq = &wrqu->essid;
4042be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
4052be45b66SKalle Valo 	int active;
4062be45b66SKalle Valo 	int err = 0;
4072be45b66SKalle Valo 	unsigned long flags;
4082be45b66SKalle Valo 
4092be45b66SKalle Valo 	if (netif_running(dev)) {
4102be45b66SKalle Valo 		err = orinoco_hw_get_essid(priv, &active, essidbuf);
4112be45b66SKalle Valo 		if (err < 0)
4122be45b66SKalle Valo 			return err;
4132be45b66SKalle Valo 		erq->length = err;
4142be45b66SKalle Valo 	} else {
4152be45b66SKalle Valo 		if (orinoco_lock(priv, &flags) != 0)
4162be45b66SKalle Valo 			return -EBUSY;
4172be45b66SKalle Valo 		memcpy(essidbuf, priv->desired_essid, IW_ESSID_MAX_SIZE);
4182be45b66SKalle Valo 		erq->length = strlen(priv->desired_essid);
4192be45b66SKalle Valo 		orinoco_unlock(priv, &flags);
4202be45b66SKalle Valo 	}
4212be45b66SKalle Valo 
4222be45b66SKalle Valo 	erq->flags = 1;
4232be45b66SKalle Valo 
4242be45b66SKalle Valo 	return 0;
4252be45b66SKalle Valo }
4262be45b66SKalle Valo 
orinoco_ioctl_setfreq(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)4272be45b66SKalle Valo static int orinoco_ioctl_setfreq(struct net_device *dev,
4282be45b66SKalle Valo 				 struct iw_request_info *info,
4292c0e077dSGustavo A. R. Silva 				 union iwreq_data *wrqu,
4302be45b66SKalle Valo 				 char *extra)
4312be45b66SKalle Valo {
4322c0e077dSGustavo A. R. Silva 	struct iw_freq *frq = &wrqu->freq;
4332be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
4342be45b66SKalle Valo 	int chan = -1;
4352be45b66SKalle Valo 	unsigned long flags;
4362be45b66SKalle Valo 	int err = -EINPROGRESS;		/* Call commit handler */
4372be45b66SKalle Valo 
4382be45b66SKalle Valo 	/* In infrastructure mode the AP sets the channel */
4392be45b66SKalle Valo 	if (priv->iw_mode == NL80211_IFTYPE_STATION)
4402be45b66SKalle Valo 		return -EBUSY;
4412be45b66SKalle Valo 
4422be45b66SKalle Valo 	if ((frq->e == 0) && (frq->m <= 1000)) {
4432be45b66SKalle Valo 		/* Setting by channel number */
4442be45b66SKalle Valo 		chan = frq->m;
4452be45b66SKalle Valo 	} else {
4462be45b66SKalle Valo 		/* Setting by frequency */
4472be45b66SKalle Valo 		int denom = 1;
4482be45b66SKalle Valo 		int i;
4492be45b66SKalle Valo 
4502be45b66SKalle Valo 		/* Calculate denominator to rescale to MHz */
4512be45b66SKalle Valo 		for (i = 0; i < (6 - frq->e); i++)
4522be45b66SKalle Valo 			denom *= 10;
4532be45b66SKalle Valo 
4542be45b66SKalle Valo 		chan = ieee80211_frequency_to_channel(frq->m / denom);
4552be45b66SKalle Valo 	}
4562be45b66SKalle Valo 
4572be45b66SKalle Valo 	if ((chan < 1) || (chan > NUM_CHANNELS) ||
4582be45b66SKalle Valo 	     !(priv->channel_mask & (1 << (chan - 1))))
4592be45b66SKalle Valo 		return -EINVAL;
4602be45b66SKalle Valo 
4612be45b66SKalle Valo 	if (orinoco_lock(priv, &flags) != 0)
4622be45b66SKalle Valo 		return -EBUSY;
4632be45b66SKalle Valo 
4642be45b66SKalle Valo 	priv->channel = chan;
4652be45b66SKalle Valo 	if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
4662be45b66SKalle Valo 		/* Fast channel change - no commit if successful */
4672be45b66SKalle Valo 		struct hermes *hw = &priv->hw;
4682be45b66SKalle Valo 		err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST |
4692be45b66SKalle Valo 					    HERMES_TEST_SET_CHANNEL,
4702be45b66SKalle Valo 					chan, NULL);
4712be45b66SKalle Valo 	}
4722be45b66SKalle Valo 	orinoco_unlock(priv, &flags);
4732be45b66SKalle Valo 
4742be45b66SKalle Valo 	return err;
4752be45b66SKalle Valo }
4762be45b66SKalle Valo 
orinoco_ioctl_getfreq(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)4772be45b66SKalle Valo static int orinoco_ioctl_getfreq(struct net_device *dev,
4782be45b66SKalle Valo 				 struct iw_request_info *info,
4792c0e077dSGustavo A. R. Silva 				 union iwreq_data *wrqu,
4802be45b66SKalle Valo 				 char *extra)
4812be45b66SKalle Valo {
4822c0e077dSGustavo A. R. Silva 	struct iw_freq *frq = &wrqu->freq;
4832be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
4842be45b66SKalle Valo 	int tmp;
4852be45b66SKalle Valo 
4862be45b66SKalle Valo 	/* Locking done in there */
4872be45b66SKalle Valo 	tmp = orinoco_hw_get_freq(priv);
4882be45b66SKalle Valo 	if (tmp < 0)
4892be45b66SKalle Valo 		return tmp;
4902be45b66SKalle Valo 
4912be45b66SKalle Valo 	frq->m = tmp * 100000;
4922be45b66SKalle Valo 	frq->e = 1;
4932be45b66SKalle Valo 
4942be45b66SKalle Valo 	return 0;
4952be45b66SKalle Valo }
4962be45b66SKalle Valo 
orinoco_ioctl_getsens(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)4972be45b66SKalle Valo static int orinoco_ioctl_getsens(struct net_device *dev,
4982be45b66SKalle Valo 				 struct iw_request_info *info,
4992c0e077dSGustavo A. R. Silva 				 union iwreq_data *wrqu,
5002be45b66SKalle Valo 				 char *extra)
5012be45b66SKalle Valo {
5022c0e077dSGustavo A. R. Silva 	struct iw_param *srq = &wrqu->sens;
5032be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
5042be45b66SKalle Valo 	struct hermes *hw = &priv->hw;
5052be45b66SKalle Valo 	u16 val;
5062be45b66SKalle Valo 	int err;
5072be45b66SKalle Valo 	unsigned long flags;
5082be45b66SKalle Valo 
5092be45b66SKalle Valo 	if (!priv->has_sensitivity)
5102be45b66SKalle Valo 		return -EOPNOTSUPP;
5112be45b66SKalle Valo 
5122be45b66SKalle Valo 	if (orinoco_lock(priv, &flags) != 0)
5132be45b66SKalle Valo 		return -EBUSY;
5142be45b66SKalle Valo 	err = hermes_read_wordrec(hw, USER_BAP,
5152be45b66SKalle Valo 				  HERMES_RID_CNFSYSTEMSCALE, &val);
5162be45b66SKalle Valo 	orinoco_unlock(priv, &flags);
5172be45b66SKalle Valo 
5182be45b66SKalle Valo 	if (err)
5192be45b66SKalle Valo 		return err;
5202be45b66SKalle Valo 
5212be45b66SKalle Valo 	srq->value = val;
5222be45b66SKalle Valo 	srq->fixed = 0; /* auto */
5232be45b66SKalle Valo 
5242be45b66SKalle Valo 	return 0;
5252be45b66SKalle Valo }
5262be45b66SKalle Valo 
orinoco_ioctl_setsens(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)5272be45b66SKalle Valo static int orinoco_ioctl_setsens(struct net_device *dev,
5282be45b66SKalle Valo 				 struct iw_request_info *info,
5292c0e077dSGustavo A. R. Silva 				 union iwreq_data *wrqu,
5302be45b66SKalle Valo 				 char *extra)
5312be45b66SKalle Valo {
5322c0e077dSGustavo A. R. Silva 	struct iw_param *srq = &wrqu->sens;
5332be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
5342be45b66SKalle Valo 	int val = srq->value;
5352be45b66SKalle Valo 	unsigned long flags;
5362be45b66SKalle Valo 
5372be45b66SKalle Valo 	if (!priv->has_sensitivity)
5382be45b66SKalle Valo 		return -EOPNOTSUPP;
5392be45b66SKalle Valo 
5402be45b66SKalle Valo 	if ((val < 1) || (val > 3))
5412be45b66SKalle Valo 		return -EINVAL;
5422be45b66SKalle Valo 
5432be45b66SKalle Valo 	if (orinoco_lock(priv, &flags) != 0)
5442be45b66SKalle Valo 		return -EBUSY;
5452be45b66SKalle Valo 	priv->ap_density = val;
5462be45b66SKalle Valo 	orinoco_unlock(priv, &flags);
5472be45b66SKalle Valo 
5482be45b66SKalle Valo 	return -EINPROGRESS;		/* Call commit handler */
5492be45b66SKalle Valo }
5502be45b66SKalle Valo 
orinoco_ioctl_setrate(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)5512be45b66SKalle Valo static int orinoco_ioctl_setrate(struct net_device *dev,
5522be45b66SKalle Valo 				 struct iw_request_info *info,
5532c0e077dSGustavo A. R. Silva 				 union iwreq_data *wrqu,
5542be45b66SKalle Valo 				 char *extra)
5552be45b66SKalle Valo {
5562c0e077dSGustavo A. R. Silva 	struct iw_param *rrq = &wrqu->bitrate;
5572be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
5582be45b66SKalle Valo 	int ratemode;
5592be45b66SKalle Valo 	int bitrate; /* 100s of kilobits */
5602be45b66SKalle Valo 	unsigned long flags;
5612be45b66SKalle Valo 
5622be45b66SKalle Valo 	/* As the user space doesn't know our highest rate, it uses -1
5632be45b66SKalle Valo 	 * to ask us to set the highest rate.  Test it using "iwconfig
5642be45b66SKalle Valo 	 * ethX rate auto" - Jean II */
5652be45b66SKalle Valo 	if (rrq->value == -1)
5662be45b66SKalle Valo 		bitrate = 110;
5672be45b66SKalle Valo 	else {
5682be45b66SKalle Valo 		if (rrq->value % 100000)
5692be45b66SKalle Valo 			return -EINVAL;
5702be45b66SKalle Valo 		bitrate = rrq->value / 100000;
5712be45b66SKalle Valo 	}
5722be45b66SKalle Valo 
5732be45b66SKalle Valo 	ratemode = orinoco_get_bitratemode(bitrate, !rrq->fixed);
5742be45b66SKalle Valo 
5752be45b66SKalle Valo 	if (ratemode == -1)
5762be45b66SKalle Valo 		return -EINVAL;
5772be45b66SKalle Valo 
5782be45b66SKalle Valo 	if (orinoco_lock(priv, &flags) != 0)
5792be45b66SKalle Valo 		return -EBUSY;
5802be45b66SKalle Valo 	priv->bitratemode = ratemode;
5812be45b66SKalle Valo 	orinoco_unlock(priv, &flags);
5822be45b66SKalle Valo 
5832be45b66SKalle Valo 	return -EINPROGRESS;
5842be45b66SKalle Valo }
5852be45b66SKalle Valo 
orinoco_ioctl_getrate(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)5862be45b66SKalle Valo static int orinoco_ioctl_getrate(struct net_device *dev,
5872be45b66SKalle Valo 				 struct iw_request_info *info,
5882c0e077dSGustavo A. R. Silva 				 union iwreq_data *wrqu,
5892be45b66SKalle Valo 				 char *extra)
5902be45b66SKalle Valo {
5912c0e077dSGustavo A. R. Silva 	struct iw_param *rrq = &wrqu->bitrate;
5922be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
5932be45b66SKalle Valo 	int err = 0;
5942be45b66SKalle Valo 	int bitrate, automatic;
5952be45b66SKalle Valo 	unsigned long flags;
5962be45b66SKalle Valo 
5972be45b66SKalle Valo 	if (orinoco_lock(priv, &flags) != 0)
5982be45b66SKalle Valo 		return -EBUSY;
5992be45b66SKalle Valo 
6002be45b66SKalle Valo 	orinoco_get_ratemode_cfg(priv->bitratemode, &bitrate, &automatic);
6012be45b66SKalle Valo 
6022be45b66SKalle Valo 	/* If the interface is running we try to find more about the
6032be45b66SKalle Valo 	   current mode */
6042be45b66SKalle Valo 	if (netif_running(dev)) {
6052be45b66SKalle Valo 		int act_bitrate;
6062be45b66SKalle Valo 		int lerr;
6072be45b66SKalle Valo 
6082be45b66SKalle Valo 		/* Ignore errors if we can't get the actual bitrate */
6092be45b66SKalle Valo 		lerr = orinoco_hw_get_act_bitrate(priv, &act_bitrate);
6102be45b66SKalle Valo 		if (!lerr)
6112be45b66SKalle Valo 			bitrate = act_bitrate;
6122be45b66SKalle Valo 	}
6132be45b66SKalle Valo 
6142be45b66SKalle Valo 	orinoco_unlock(priv, &flags);
6152be45b66SKalle Valo 
6162be45b66SKalle Valo 	rrq->value = bitrate;
6172be45b66SKalle Valo 	rrq->fixed = !automatic;
6182be45b66SKalle Valo 	rrq->disabled = 0;
6192be45b66SKalle Valo 
6202be45b66SKalle Valo 	return err;
6212be45b66SKalle Valo }
6222be45b66SKalle Valo 
orinoco_ioctl_setpower(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)6232be45b66SKalle Valo static int orinoco_ioctl_setpower(struct net_device *dev,
6242be45b66SKalle Valo 				  struct iw_request_info *info,
6252c0e077dSGustavo A. R. Silva 				  union iwreq_data *wrqu,
6262be45b66SKalle Valo 				  char *extra)
6272be45b66SKalle Valo {
6282c0e077dSGustavo A. R. Silva 	struct iw_param *prq = &wrqu->power;
6292be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
6302be45b66SKalle Valo 	int err = -EINPROGRESS;		/* Call commit handler */
6312be45b66SKalle Valo 	unsigned long flags;
6322be45b66SKalle Valo 
6332be45b66SKalle Valo 	if (orinoco_lock(priv, &flags) != 0)
6342be45b66SKalle Valo 		return -EBUSY;
6352be45b66SKalle Valo 
6362be45b66SKalle Valo 	if (prq->disabled) {
6372be45b66SKalle Valo 		priv->pm_on = 0;
6382be45b66SKalle Valo 	} else {
6392be45b66SKalle Valo 		switch (prq->flags & IW_POWER_MODE) {
6402be45b66SKalle Valo 		case IW_POWER_UNICAST_R:
6412be45b66SKalle Valo 			priv->pm_mcast = 0;
6422be45b66SKalle Valo 			priv->pm_on = 1;
6432be45b66SKalle Valo 			break;
6442be45b66SKalle Valo 		case IW_POWER_ALL_R:
6452be45b66SKalle Valo 			priv->pm_mcast = 1;
6462be45b66SKalle Valo 			priv->pm_on = 1;
6472be45b66SKalle Valo 			break;
6482be45b66SKalle Valo 		case IW_POWER_ON:
6492be45b66SKalle Valo 			/* No flags : but we may have a value - Jean II */
6502be45b66SKalle Valo 			break;
6512be45b66SKalle Valo 		default:
6522be45b66SKalle Valo 			err = -EINVAL;
6532be45b66SKalle Valo 			goto out;
6542be45b66SKalle Valo 		}
6552be45b66SKalle Valo 
6562be45b66SKalle Valo 		if (prq->flags & IW_POWER_TIMEOUT) {
6572be45b66SKalle Valo 			priv->pm_on = 1;
6582be45b66SKalle Valo 			priv->pm_timeout = prq->value / 1000;
6592be45b66SKalle Valo 		}
6602be45b66SKalle Valo 		if (prq->flags & IW_POWER_PERIOD) {
6612be45b66SKalle Valo 			priv->pm_on = 1;
6622be45b66SKalle Valo 			priv->pm_period = prq->value / 1000;
6632be45b66SKalle Valo 		}
6642be45b66SKalle Valo 		/* It's valid to not have a value if we are just toggling
6652be45b66SKalle Valo 		 * the flags... Jean II */
6662be45b66SKalle Valo 		if (!priv->pm_on) {
6672be45b66SKalle Valo 			err = -EINVAL;
6682be45b66SKalle Valo 			goto out;
6692be45b66SKalle Valo 		}
6702be45b66SKalle Valo 	}
6712be45b66SKalle Valo 
6722be45b66SKalle Valo  out:
6732be45b66SKalle Valo 	orinoco_unlock(priv, &flags);
6742be45b66SKalle Valo 
6752be45b66SKalle Valo 	return err;
6762be45b66SKalle Valo }
6772be45b66SKalle Valo 
orinoco_ioctl_getpower(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)6782be45b66SKalle Valo static int orinoco_ioctl_getpower(struct net_device *dev,
6792be45b66SKalle Valo 				  struct iw_request_info *info,
6802c0e077dSGustavo A. R. Silva 				  union iwreq_data *wrqu,
6812be45b66SKalle Valo 				  char *extra)
6822be45b66SKalle Valo {
6832c0e077dSGustavo A. R. Silva 	struct iw_param *prq = &wrqu->power;
6842be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
6852be45b66SKalle Valo 	struct hermes *hw = &priv->hw;
6862be45b66SKalle Valo 	int err = 0;
6872be45b66SKalle Valo 	u16 enable, period, timeout, mcast;
6882be45b66SKalle Valo 	unsigned long flags;
6892be45b66SKalle Valo 
6902be45b66SKalle Valo 	if (orinoco_lock(priv, &flags) != 0)
6912be45b66SKalle Valo 		return -EBUSY;
6922be45b66SKalle Valo 
6932be45b66SKalle Valo 	err = hermes_read_wordrec(hw, USER_BAP,
6942be45b66SKalle Valo 				  HERMES_RID_CNFPMENABLED, &enable);
6952be45b66SKalle Valo 	if (err)
6962be45b66SKalle Valo 		goto out;
6972be45b66SKalle Valo 
6982be45b66SKalle Valo 	err = hermes_read_wordrec(hw, USER_BAP,
6992be45b66SKalle Valo 				  HERMES_RID_CNFMAXSLEEPDURATION, &period);
7002be45b66SKalle Valo 	if (err)
7012be45b66SKalle Valo 		goto out;
7022be45b66SKalle Valo 
7032be45b66SKalle Valo 	err = hermes_read_wordrec(hw, USER_BAP,
7042be45b66SKalle Valo 				  HERMES_RID_CNFPMHOLDOVERDURATION, &timeout);
7052be45b66SKalle Valo 	if (err)
7062be45b66SKalle Valo 		goto out;
7072be45b66SKalle Valo 
7082be45b66SKalle Valo 	err = hermes_read_wordrec(hw, USER_BAP,
7092be45b66SKalle Valo 				  HERMES_RID_CNFMULTICASTRECEIVE, &mcast);
7102be45b66SKalle Valo 	if (err)
7112be45b66SKalle Valo 		goto out;
7122be45b66SKalle Valo 
7132be45b66SKalle Valo 	prq->disabled = !enable;
7142be45b66SKalle Valo 	/* Note : by default, display the period */
7152be45b66SKalle Valo 	if ((prq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
7162be45b66SKalle Valo 		prq->flags = IW_POWER_TIMEOUT;
7172be45b66SKalle Valo 		prq->value = timeout * 1000;
7182be45b66SKalle Valo 	} else {
7192be45b66SKalle Valo 		prq->flags = IW_POWER_PERIOD;
7202be45b66SKalle Valo 		prq->value = period * 1000;
7212be45b66SKalle Valo 	}
7222be45b66SKalle Valo 	if (mcast)
7232be45b66SKalle Valo 		prq->flags |= IW_POWER_ALL_R;
7242be45b66SKalle Valo 	else
7252be45b66SKalle Valo 		prq->flags |= IW_POWER_UNICAST_R;
7262be45b66SKalle Valo 
7272be45b66SKalle Valo  out:
7282be45b66SKalle Valo 	orinoco_unlock(priv, &flags);
7292be45b66SKalle Valo 
7302be45b66SKalle Valo 	return err;
7312be45b66SKalle Valo }
7322be45b66SKalle Valo 
orinoco_ioctl_set_encodeext(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)7332be45b66SKalle Valo static int orinoco_ioctl_set_encodeext(struct net_device *dev,
7342be45b66SKalle Valo 				       struct iw_request_info *info,
7352be45b66SKalle Valo 				       union iwreq_data *wrqu,
7362be45b66SKalle Valo 				       char *extra)
7372be45b66SKalle Valo {
7382be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
7392be45b66SKalle Valo 	struct iw_point *encoding = &wrqu->encoding;
7402be45b66SKalle Valo 	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
7412be45b66SKalle Valo 	int idx, alg = ext->alg, set_key = 1;
7422be45b66SKalle Valo 	unsigned long flags;
7432be45b66SKalle Valo 	int err = -EINVAL;
7442be45b66SKalle Valo 
7452be45b66SKalle Valo 	if (orinoco_lock(priv, &flags) != 0)
7462be45b66SKalle Valo 		return -EBUSY;
7472be45b66SKalle Valo 
7482be45b66SKalle Valo 	/* Determine and validate the key index */
7492be45b66SKalle Valo 	idx = encoding->flags & IW_ENCODE_INDEX;
7502be45b66SKalle Valo 	if (idx) {
7512be45b66SKalle Valo 		if ((idx < 1) || (idx > 4))
7522be45b66SKalle Valo 			goto out;
7532be45b66SKalle Valo 		idx--;
7542be45b66SKalle Valo 	} else
7552be45b66SKalle Valo 		idx = priv->tx_key;
7562be45b66SKalle Valo 
7572be45b66SKalle Valo 	if (encoding->flags & IW_ENCODE_DISABLED)
7582be45b66SKalle Valo 		alg = IW_ENCODE_ALG_NONE;
7592be45b66SKalle Valo 
7602be45b66SKalle Valo 	if (priv->has_wpa && (alg != IW_ENCODE_ALG_TKIP)) {
7612be45b66SKalle Valo 		/* Clear any TKIP TX key we had */
7622be45b66SKalle Valo 		(void) orinoco_clear_tkip_key(priv, priv->tx_key);
7632be45b66SKalle Valo 	}
7642be45b66SKalle Valo 
7652be45b66SKalle Valo 	if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
7662be45b66SKalle Valo 		priv->tx_key = idx;
7672be45b66SKalle Valo 		set_key = ((alg == IW_ENCODE_ALG_TKIP) ||
7682be45b66SKalle Valo 			   (ext->key_len > 0)) ? 1 : 0;
7692be45b66SKalle Valo 	}
7702be45b66SKalle Valo 
7712be45b66SKalle Valo 	if (set_key) {
7722be45b66SKalle Valo 		/* Set the requested key first */
7732be45b66SKalle Valo 		switch (alg) {
7742be45b66SKalle Valo 		case IW_ENCODE_ALG_NONE:
7752be45b66SKalle Valo 			priv->encode_alg = ORINOCO_ALG_NONE;
7762be45b66SKalle Valo 			err = orinoco_set_key(priv, idx, ORINOCO_ALG_NONE,
7772be45b66SKalle Valo 					      NULL, 0, NULL, 0);
7782be45b66SKalle Valo 			break;
7792be45b66SKalle Valo 
7802be45b66SKalle Valo 		case IW_ENCODE_ALG_WEP:
7812be45b66SKalle Valo 			if (ext->key_len <= 0)
7822be45b66SKalle Valo 				goto out;
7832be45b66SKalle Valo 
7842be45b66SKalle Valo 			priv->encode_alg = ORINOCO_ALG_WEP;
7852be45b66SKalle Valo 			err = orinoco_set_key(priv, idx, ORINOCO_ALG_WEP,
7862be45b66SKalle Valo 					      ext->key, ext->key_len, NULL, 0);
7872be45b66SKalle Valo 			break;
7882be45b66SKalle Valo 
7892be45b66SKalle Valo 		case IW_ENCODE_ALG_TKIP:
7902be45b66SKalle Valo 		{
7912be45b66SKalle Valo 			u8 *tkip_iv = NULL;
7922be45b66SKalle Valo 
7932be45b66SKalle Valo 			if (!priv->has_wpa ||
7942be45b66SKalle Valo 			    (ext->key_len > sizeof(struct orinoco_tkip_key)))
7952be45b66SKalle Valo 				goto out;
7962be45b66SKalle Valo 
7972be45b66SKalle Valo 			priv->encode_alg = ORINOCO_ALG_TKIP;
7982be45b66SKalle Valo 
7992be45b66SKalle Valo 			if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
8002be45b66SKalle Valo 				tkip_iv = &ext->rx_seq[0];
8012be45b66SKalle Valo 
8022be45b66SKalle Valo 			err = orinoco_set_key(priv, idx, ORINOCO_ALG_TKIP,
8032be45b66SKalle Valo 					      ext->key, ext->key_len, tkip_iv,
8042be45b66SKalle Valo 					      ORINOCO_SEQ_LEN);
8052be45b66SKalle Valo 
8062be45b66SKalle Valo 			err = __orinoco_hw_set_tkip_key(priv, idx,
8072be45b66SKalle Valo 				 ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY,
80870ca8441SKees Cook 				 priv->keys[idx].key, priv->keys[idx].key_len,
8092be45b66SKalle Valo 				 tkip_iv, ORINOCO_SEQ_LEN, NULL, 0);
8102be45b66SKalle Valo 			if (err)
8112be45b66SKalle Valo 				printk(KERN_ERR "%s: Error %d setting TKIP key"
8122be45b66SKalle Valo 				       "\n", dev->name, err);
8132be45b66SKalle Valo 
8142be45b66SKalle Valo 			goto out;
8152be45b66SKalle Valo 		}
8162be45b66SKalle Valo 		default:
8172be45b66SKalle Valo 			goto out;
8182be45b66SKalle Valo 		}
8192be45b66SKalle Valo 	}
8202be45b66SKalle Valo 	err = -EINPROGRESS;
8212be45b66SKalle Valo  out:
8222be45b66SKalle Valo 	orinoco_unlock(priv, &flags);
8232be45b66SKalle Valo 
8242be45b66SKalle Valo 	return err;
8252be45b66SKalle Valo }
8262be45b66SKalle Valo 
orinoco_ioctl_get_encodeext(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)8272be45b66SKalle Valo static int orinoco_ioctl_get_encodeext(struct net_device *dev,
8282be45b66SKalle Valo 				       struct iw_request_info *info,
8292be45b66SKalle Valo 				       union iwreq_data *wrqu,
8302be45b66SKalle Valo 				       char *extra)
8312be45b66SKalle Valo {
8322be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
8332be45b66SKalle Valo 	struct iw_point *encoding = &wrqu->encoding;
8342be45b66SKalle Valo 	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
8352be45b66SKalle Valo 	int idx, max_key_len;
8362be45b66SKalle Valo 	unsigned long flags;
8372be45b66SKalle Valo 	int err;
8382be45b66SKalle Valo 
8392be45b66SKalle Valo 	if (orinoco_lock(priv, &flags) != 0)
8402be45b66SKalle Valo 		return -EBUSY;
8412be45b66SKalle Valo 
8422be45b66SKalle Valo 	err = -EINVAL;
8432be45b66SKalle Valo 	max_key_len = encoding->length - sizeof(*ext);
8442be45b66SKalle Valo 	if (max_key_len < 0)
8452be45b66SKalle Valo 		goto out;
8462be45b66SKalle Valo 
8472be45b66SKalle Valo 	idx = encoding->flags & IW_ENCODE_INDEX;
8482be45b66SKalle Valo 	if (idx) {
8492be45b66SKalle Valo 		if ((idx < 1) || (idx > 4))
8502be45b66SKalle Valo 			goto out;
8512be45b66SKalle Valo 		idx--;
8522be45b66SKalle Valo 	} else
8532be45b66SKalle Valo 		idx = priv->tx_key;
8542be45b66SKalle Valo 
8552be45b66SKalle Valo 	encoding->flags = idx + 1;
8562be45b66SKalle Valo 	memset(ext, 0, sizeof(*ext));
8572be45b66SKalle Valo 
8582be45b66SKalle Valo 	switch (priv->encode_alg) {
8592be45b66SKalle Valo 	case ORINOCO_ALG_NONE:
8602be45b66SKalle Valo 		ext->alg = IW_ENCODE_ALG_NONE;
8612be45b66SKalle Valo 		ext->key_len = 0;
8622be45b66SKalle Valo 		encoding->flags |= IW_ENCODE_DISABLED;
8632be45b66SKalle Valo 		break;
8642be45b66SKalle Valo 	case ORINOCO_ALG_WEP:
8652be45b66SKalle Valo 		ext->alg = IW_ENCODE_ALG_WEP;
8662be45b66SKalle Valo 		ext->key_len = min(priv->keys[idx].key_len, max_key_len);
8672be45b66SKalle Valo 		memcpy(ext->key, priv->keys[idx].key, ext->key_len);
8682be45b66SKalle Valo 		encoding->flags |= IW_ENCODE_ENABLED;
8692be45b66SKalle Valo 		break;
8702be45b66SKalle Valo 	case ORINOCO_ALG_TKIP:
8712be45b66SKalle Valo 		ext->alg = IW_ENCODE_ALG_TKIP;
8722be45b66SKalle Valo 		ext->key_len = min(priv->keys[idx].key_len, max_key_len);
8732be45b66SKalle Valo 		memcpy(ext->key, priv->keys[idx].key, ext->key_len);
8742be45b66SKalle Valo 		encoding->flags |= IW_ENCODE_ENABLED;
8752be45b66SKalle Valo 		break;
8762be45b66SKalle Valo 	}
8772be45b66SKalle Valo 
8782be45b66SKalle Valo 	err = 0;
8792be45b66SKalle Valo  out:
8802be45b66SKalle Valo 	orinoco_unlock(priv, &flags);
8812be45b66SKalle Valo 
8822be45b66SKalle Valo 	return err;
8832be45b66SKalle Valo }
8842be45b66SKalle Valo 
orinoco_ioctl_set_auth(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)8852be45b66SKalle Valo static int orinoco_ioctl_set_auth(struct net_device *dev,
8862be45b66SKalle Valo 				  struct iw_request_info *info,
8872be45b66SKalle Valo 				  union iwreq_data *wrqu, char *extra)
8882be45b66SKalle Valo {
8892be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
8902be45b66SKalle Valo 	struct hermes *hw = &priv->hw;
8912be45b66SKalle Valo 	struct iw_param *param = &wrqu->param;
8922be45b66SKalle Valo 	unsigned long flags;
8932be45b66SKalle Valo 	int ret = -EINPROGRESS;
8942be45b66SKalle Valo 
8952be45b66SKalle Valo 	if (orinoco_lock(priv, &flags) != 0)
8962be45b66SKalle Valo 		return -EBUSY;
8972be45b66SKalle Valo 
8982be45b66SKalle Valo 	switch (param->flags & IW_AUTH_INDEX) {
8992be45b66SKalle Valo 	case IW_AUTH_WPA_VERSION:
9002be45b66SKalle Valo 	case IW_AUTH_CIPHER_PAIRWISE:
9012be45b66SKalle Valo 	case IW_AUTH_CIPHER_GROUP:
9022be45b66SKalle Valo 	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
9032be45b66SKalle Valo 	case IW_AUTH_PRIVACY_INVOKED:
9042be45b66SKalle Valo 	case IW_AUTH_DROP_UNENCRYPTED:
9052be45b66SKalle Valo 		/*
9062be45b66SKalle Valo 		 * orinoco does not use these parameters
9072be45b66SKalle Valo 		 */
9082be45b66SKalle Valo 		break;
9092be45b66SKalle Valo 
9102be45b66SKalle Valo 	case IW_AUTH_MFP:
9112be45b66SKalle Valo 		/* Management Frame Protection not supported.
9122be45b66SKalle Valo 		 * Only fail if set to required.
9132be45b66SKalle Valo 		 */
9142be45b66SKalle Valo 		if (param->value == IW_AUTH_MFP_REQUIRED)
9152be45b66SKalle Valo 			ret = -EINVAL;
9162be45b66SKalle Valo 		break;
9172be45b66SKalle Valo 
9182be45b66SKalle Valo 	case IW_AUTH_KEY_MGMT:
9192be45b66SKalle Valo 		/* wl_lkm implies value 2 == PSK for Hermes I
9202be45b66SKalle Valo 		 * which ties in with WEXT
9212be45b66SKalle Valo 		 * no other hints tho :(
9222be45b66SKalle Valo 		 */
9232be45b66SKalle Valo 		priv->key_mgmt = param->value;
9242be45b66SKalle Valo 		break;
9252be45b66SKalle Valo 
9262be45b66SKalle Valo 	case IW_AUTH_TKIP_COUNTERMEASURES:
9272be45b66SKalle Valo 		/* When countermeasures are enabled, shut down the
9282be45b66SKalle Valo 		 * card; when disabled, re-enable the card. This must
9292be45b66SKalle Valo 		 * take effect immediately.
9302be45b66SKalle Valo 		 *
9312be45b66SKalle Valo 		 * TODO: Make sure that the EAPOL message is getting
9322be45b66SKalle Valo 		 *       out before card disabled
9332be45b66SKalle Valo 		 */
9342be45b66SKalle Valo 		if (param->value) {
9352be45b66SKalle Valo 			priv->tkip_cm_active = 1;
9362be45b66SKalle Valo 			ret = hermes_disable_port(hw, 0);
9372be45b66SKalle Valo 		} else {
9382be45b66SKalle Valo 			priv->tkip_cm_active = 0;
9392be45b66SKalle Valo 			ret = hermes_enable_port(hw, 0);
9402be45b66SKalle Valo 		}
9412be45b66SKalle Valo 		break;
9422be45b66SKalle Valo 
9432be45b66SKalle Valo 	case IW_AUTH_80211_AUTH_ALG:
9442be45b66SKalle Valo 		if (param->value & IW_AUTH_ALG_SHARED_KEY)
9452be45b66SKalle Valo 			priv->wep_restrict = 1;
9462be45b66SKalle Valo 		else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM)
9472be45b66SKalle Valo 			priv->wep_restrict = 0;
9482be45b66SKalle Valo 		else
9492be45b66SKalle Valo 			ret = -EINVAL;
9502be45b66SKalle Valo 		break;
9512be45b66SKalle Valo 
9522be45b66SKalle Valo 	case IW_AUTH_WPA_ENABLED:
9532be45b66SKalle Valo 		if (priv->has_wpa) {
9542be45b66SKalle Valo 			priv->wpa_enabled = param->value ? 1 : 0;
9552be45b66SKalle Valo 		} else {
9562be45b66SKalle Valo 			if (param->value)
9572be45b66SKalle Valo 				ret = -EOPNOTSUPP;
9582be45b66SKalle Valo 			/* else silently accept disable of WPA */
9592be45b66SKalle Valo 			priv->wpa_enabled = 0;
9602be45b66SKalle Valo 		}
9612be45b66SKalle Valo 		break;
9622be45b66SKalle Valo 
9632be45b66SKalle Valo 	default:
9642be45b66SKalle Valo 		ret = -EOPNOTSUPP;
9652be45b66SKalle Valo 	}
9662be45b66SKalle Valo 
9672be45b66SKalle Valo 	orinoco_unlock(priv, &flags);
9682be45b66SKalle Valo 	return ret;
9692be45b66SKalle Valo }
9702be45b66SKalle Valo 
orinoco_ioctl_get_auth(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)9712be45b66SKalle Valo static int orinoco_ioctl_get_auth(struct net_device *dev,
9722be45b66SKalle Valo 				  struct iw_request_info *info,
9732be45b66SKalle Valo 				  union iwreq_data *wrqu, char *extra)
9742be45b66SKalle Valo {
9752be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
9762be45b66SKalle Valo 	struct iw_param *param = &wrqu->param;
9772be45b66SKalle Valo 	unsigned long flags;
9782be45b66SKalle Valo 	int ret = 0;
9792be45b66SKalle Valo 
9802be45b66SKalle Valo 	if (orinoco_lock(priv, &flags) != 0)
9812be45b66SKalle Valo 		return -EBUSY;
9822be45b66SKalle Valo 
9832be45b66SKalle Valo 	switch (param->flags & IW_AUTH_INDEX) {
9842be45b66SKalle Valo 	case IW_AUTH_KEY_MGMT:
9852be45b66SKalle Valo 		param->value = priv->key_mgmt;
9862be45b66SKalle Valo 		break;
9872be45b66SKalle Valo 
9882be45b66SKalle Valo 	case IW_AUTH_TKIP_COUNTERMEASURES:
9892be45b66SKalle Valo 		param->value = priv->tkip_cm_active;
9902be45b66SKalle Valo 		break;
9912be45b66SKalle Valo 
9922be45b66SKalle Valo 	case IW_AUTH_80211_AUTH_ALG:
9932be45b66SKalle Valo 		if (priv->wep_restrict)
9942be45b66SKalle Valo 			param->value = IW_AUTH_ALG_SHARED_KEY;
9952be45b66SKalle Valo 		else
9962be45b66SKalle Valo 			param->value = IW_AUTH_ALG_OPEN_SYSTEM;
9972be45b66SKalle Valo 		break;
9982be45b66SKalle Valo 
9992be45b66SKalle Valo 	case IW_AUTH_WPA_ENABLED:
10002be45b66SKalle Valo 		param->value = priv->wpa_enabled;
10012be45b66SKalle Valo 		break;
10022be45b66SKalle Valo 
10032be45b66SKalle Valo 	default:
10042be45b66SKalle Valo 		ret = -EOPNOTSUPP;
10052be45b66SKalle Valo 	}
10062be45b66SKalle Valo 
10072be45b66SKalle Valo 	orinoco_unlock(priv, &flags);
10082be45b66SKalle Valo 	return ret;
10092be45b66SKalle Valo }
10102be45b66SKalle Valo 
orinoco_ioctl_set_genie(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)10112be45b66SKalle Valo static int orinoco_ioctl_set_genie(struct net_device *dev,
10122be45b66SKalle Valo 				   struct iw_request_info *info,
10132be45b66SKalle Valo 				   union iwreq_data *wrqu, char *extra)
10142be45b66SKalle Valo {
10152be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
10162be45b66SKalle Valo 	u8 *buf;
10172be45b66SKalle Valo 	unsigned long flags;
10182be45b66SKalle Valo 
10192be45b66SKalle Valo 	/* cut off at IEEE80211_MAX_DATA_LEN */
10202be45b66SKalle Valo 	if ((wrqu->data.length > IEEE80211_MAX_DATA_LEN) ||
10212be45b66SKalle Valo 	    (wrqu->data.length && (extra == NULL)))
10222be45b66SKalle Valo 		return -EINVAL;
10232be45b66SKalle Valo 
10242be45b66SKalle Valo 	if (wrqu->data.length) {
10252be45b66SKalle Valo 		buf = kmemdup(extra, wrqu->data.length, GFP_KERNEL);
10262be45b66SKalle Valo 		if (buf == NULL)
10272be45b66SKalle Valo 			return -ENOMEM;
10282be45b66SKalle Valo 	} else
10292be45b66SKalle Valo 		buf = NULL;
10302be45b66SKalle Valo 
10312be45b66SKalle Valo 	if (orinoco_lock(priv, &flags) != 0) {
10322be45b66SKalle Valo 		kfree(buf);
10332be45b66SKalle Valo 		return -EBUSY;
10342be45b66SKalle Valo 	}
10352be45b66SKalle Valo 
10362be45b66SKalle Valo 	kfree(priv->wpa_ie);
10372be45b66SKalle Valo 	priv->wpa_ie = buf;
10382be45b66SKalle Valo 	priv->wpa_ie_len = wrqu->data.length;
10392be45b66SKalle Valo 
10402be45b66SKalle Valo 	if (priv->wpa_ie) {
10412be45b66SKalle Valo 		/* Looks like wl_lkm wants to check the auth alg, and
10422be45b66SKalle Valo 		 * somehow pass it to the firmware.
10432be45b66SKalle Valo 		 * Instead it just calls the key mgmt rid
10442be45b66SKalle Valo 		 *   - we do this in set auth.
10452be45b66SKalle Valo 		 */
10462be45b66SKalle Valo 	}
10472be45b66SKalle Valo 
10482be45b66SKalle Valo 	orinoco_unlock(priv, &flags);
10492be45b66SKalle Valo 	return 0;
10502be45b66SKalle Valo }
10512be45b66SKalle Valo 
orinoco_ioctl_get_genie(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)10522be45b66SKalle Valo static int orinoco_ioctl_get_genie(struct net_device *dev,
10532be45b66SKalle Valo 				   struct iw_request_info *info,
10542be45b66SKalle Valo 				   union iwreq_data *wrqu, char *extra)
10552be45b66SKalle Valo {
10562be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
10572be45b66SKalle Valo 	unsigned long flags;
10582be45b66SKalle Valo 	int err = 0;
10592be45b66SKalle Valo 
10602be45b66SKalle Valo 	if (orinoco_lock(priv, &flags) != 0)
10612be45b66SKalle Valo 		return -EBUSY;
10622be45b66SKalle Valo 
10632be45b66SKalle Valo 	if ((priv->wpa_ie_len == 0) || (priv->wpa_ie == NULL)) {
10642be45b66SKalle Valo 		wrqu->data.length = 0;
10652be45b66SKalle Valo 		goto out;
10662be45b66SKalle Valo 	}
10672be45b66SKalle Valo 
10682be45b66SKalle Valo 	if (wrqu->data.length < priv->wpa_ie_len) {
10692be45b66SKalle Valo 		err = -E2BIG;
10702be45b66SKalle Valo 		goto out;
10712be45b66SKalle Valo 	}
10722be45b66SKalle Valo 
10732be45b66SKalle Valo 	wrqu->data.length = priv->wpa_ie_len;
10742be45b66SKalle Valo 	memcpy(extra, priv->wpa_ie, priv->wpa_ie_len);
10752be45b66SKalle Valo 
10762be45b66SKalle Valo out:
10772be45b66SKalle Valo 	orinoco_unlock(priv, &flags);
10782be45b66SKalle Valo 	return err;
10792be45b66SKalle Valo }
10802be45b66SKalle Valo 
orinoco_ioctl_set_mlme(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)10812be45b66SKalle Valo static int orinoco_ioctl_set_mlme(struct net_device *dev,
10822be45b66SKalle Valo 				  struct iw_request_info *info,
10832be45b66SKalle Valo 				  union iwreq_data *wrqu, char *extra)
10842be45b66SKalle Valo {
10852be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
10862be45b66SKalle Valo 	struct iw_mlme *mlme = (struct iw_mlme *)extra;
10872be45b66SKalle Valo 	unsigned long flags;
10882be45b66SKalle Valo 	int ret = 0;
10892be45b66SKalle Valo 
10902be45b66SKalle Valo 	if (orinoco_lock(priv, &flags) != 0)
10912be45b66SKalle Valo 		return -EBUSY;
10922be45b66SKalle Valo 
10932be45b66SKalle Valo 	switch (mlme->cmd) {
10942be45b66SKalle Valo 	case IW_MLME_DEAUTH:
10952be45b66SKalle Valo 		/* silently ignore */
10962be45b66SKalle Valo 		break;
10972be45b66SKalle Valo 
10982be45b66SKalle Valo 	case IW_MLME_DISASSOC:
10992be45b66SKalle Valo 
11002be45b66SKalle Valo 		ret = orinoco_hw_disassociate(priv, mlme->addr.sa_data,
11012be45b66SKalle Valo 					      mlme->reason_code);
11022be45b66SKalle Valo 		break;
11032be45b66SKalle Valo 
11042be45b66SKalle Valo 	default:
11052be45b66SKalle Valo 		ret = -EOPNOTSUPP;
11062be45b66SKalle Valo 	}
11072be45b66SKalle Valo 
11082be45b66SKalle Valo 	orinoco_unlock(priv, &flags);
11092be45b66SKalle Valo 	return ret;
11102be45b66SKalle Valo }
11112be45b66SKalle Valo 
orinoco_ioctl_reset(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)11122be45b66SKalle Valo static int orinoco_ioctl_reset(struct net_device *dev,
11132be45b66SKalle Valo 			       struct iw_request_info *info,
11142c0e077dSGustavo A. R. Silva 			       union iwreq_data *wrqu,
11152be45b66SKalle Valo 			       char *extra)
11162be45b66SKalle Valo {
11172be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
11182be45b66SKalle Valo 
11192be45b66SKalle Valo 	if (!capable(CAP_NET_ADMIN))
11202be45b66SKalle Valo 		return -EPERM;
11212be45b66SKalle Valo 
11222be45b66SKalle Valo 	if (info->cmd == (SIOCIWFIRSTPRIV + 0x1)) {
11232be45b66SKalle Valo 		printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name);
11242be45b66SKalle Valo 
11252be45b66SKalle Valo 		/* Firmware reset */
11262be45b66SKalle Valo 		orinoco_reset(&priv->reset_work);
11272be45b66SKalle Valo 	} else {
11282be45b66SKalle Valo 		printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name);
11292be45b66SKalle Valo 
11302be45b66SKalle Valo 		schedule_work(&priv->reset_work);
11312be45b66SKalle Valo 	}
11322be45b66SKalle Valo 
11332be45b66SKalle Valo 	return 0;
11342be45b66SKalle Valo }
11352be45b66SKalle Valo 
orinoco_ioctl_setibssport(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)11362be45b66SKalle Valo static int orinoco_ioctl_setibssport(struct net_device *dev,
11372be45b66SKalle Valo 				     struct iw_request_info *info,
11382c0e077dSGustavo A. R. Silva 				     union iwreq_data *wrqu,
11392be45b66SKalle Valo 				     char *extra)
11402be45b66SKalle Valo 
11412be45b66SKalle Valo {
11422be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
11432be45b66SKalle Valo 	int val = *((int *) extra);
11442be45b66SKalle Valo 	unsigned long flags;
11452be45b66SKalle Valo 
11462be45b66SKalle Valo 	if (orinoco_lock(priv, &flags) != 0)
11472be45b66SKalle Valo 		return -EBUSY;
11482be45b66SKalle Valo 
11492be45b66SKalle Valo 	priv->ibss_port = val;
11502be45b66SKalle Valo 
11512be45b66SKalle Valo 	/* Actually update the mode we are using */
11522be45b66SKalle Valo 	set_port_type(priv);
11532be45b66SKalle Valo 
11542be45b66SKalle Valo 	orinoco_unlock(priv, &flags);
11552be45b66SKalle Valo 	return -EINPROGRESS;		/* Call commit handler */
11562be45b66SKalle Valo }
11572be45b66SKalle Valo 
orinoco_ioctl_getibssport(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)11582be45b66SKalle Valo static int orinoco_ioctl_getibssport(struct net_device *dev,
11592be45b66SKalle Valo 				     struct iw_request_info *info,
11602c0e077dSGustavo A. R. Silva 				     union iwreq_data *wrqu,
11612be45b66SKalle Valo 				     char *extra)
11622be45b66SKalle Valo {
11632be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
11642be45b66SKalle Valo 	int *val = (int *) extra;
11652be45b66SKalle Valo 
11662be45b66SKalle Valo 	*val = priv->ibss_port;
11672be45b66SKalle Valo 	return 0;
11682be45b66SKalle Valo }
11692be45b66SKalle Valo 
orinoco_ioctl_setport3(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)11702be45b66SKalle Valo static int orinoco_ioctl_setport3(struct net_device *dev,
11712be45b66SKalle Valo 				  struct iw_request_info *info,
11722c0e077dSGustavo A. R. Silva 				  union iwreq_data *wrqu,
11732be45b66SKalle Valo 				  char *extra)
11742be45b66SKalle Valo {
11752be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
11762be45b66SKalle Valo 	int val = *((int *) extra);
11772be45b66SKalle Valo 	int err = 0;
11782be45b66SKalle Valo 	unsigned long flags;
11792be45b66SKalle Valo 
11802be45b66SKalle Valo 	if (orinoco_lock(priv, &flags) != 0)
11812be45b66SKalle Valo 		return -EBUSY;
11822be45b66SKalle Valo 
11832be45b66SKalle Valo 	switch (val) {
11842be45b66SKalle Valo 	case 0: /* Try to do IEEE ad-hoc mode */
11852be45b66SKalle Valo 		if (!priv->has_ibss) {
11862be45b66SKalle Valo 			err = -EINVAL;
11872be45b66SKalle Valo 			break;
11882be45b66SKalle Valo 		}
11892be45b66SKalle Valo 		priv->prefer_port3 = 0;
11902be45b66SKalle Valo 
11912be45b66SKalle Valo 		break;
11922be45b66SKalle Valo 
11932be45b66SKalle Valo 	case 1: /* Try to do Lucent proprietary ad-hoc mode */
11942be45b66SKalle Valo 		if (!priv->has_port3) {
11952be45b66SKalle Valo 			err = -EINVAL;
11962be45b66SKalle Valo 			break;
11972be45b66SKalle Valo 		}
11982be45b66SKalle Valo 		priv->prefer_port3 = 1;
11992be45b66SKalle Valo 		break;
12002be45b66SKalle Valo 
12012be45b66SKalle Valo 	default:
12022be45b66SKalle Valo 		err = -EINVAL;
12032be45b66SKalle Valo 	}
12042be45b66SKalle Valo 
12052be45b66SKalle Valo 	if (!err) {
12062be45b66SKalle Valo 		/* Actually update the mode we are using */
12072be45b66SKalle Valo 		set_port_type(priv);
12082be45b66SKalle Valo 		err = -EINPROGRESS;
12092be45b66SKalle Valo 	}
12102be45b66SKalle Valo 
12112be45b66SKalle Valo 	orinoco_unlock(priv, &flags);
12122be45b66SKalle Valo 
12132be45b66SKalle Valo 	return err;
12142be45b66SKalle Valo }
12152be45b66SKalle Valo 
orinoco_ioctl_getport3(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)12162be45b66SKalle Valo static int orinoco_ioctl_getport3(struct net_device *dev,
12172be45b66SKalle Valo 				  struct iw_request_info *info,
12182c0e077dSGustavo A. R. Silva 				  union iwreq_data *wrqu,
12192be45b66SKalle Valo 				  char *extra)
12202be45b66SKalle Valo {
12212be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
12222be45b66SKalle Valo 	int *val = (int *) extra;
12232be45b66SKalle Valo 
12242be45b66SKalle Valo 	*val = priv->prefer_port3;
12252be45b66SKalle Valo 	return 0;
12262be45b66SKalle Valo }
12272be45b66SKalle Valo 
orinoco_ioctl_setpreamble(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)12282be45b66SKalle Valo static int orinoco_ioctl_setpreamble(struct net_device *dev,
12292be45b66SKalle Valo 				     struct iw_request_info *info,
12302c0e077dSGustavo A. R. Silva 				     union iwreq_data *wrqu,
12312be45b66SKalle Valo 				     char *extra)
12322be45b66SKalle Valo {
12332be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
12342be45b66SKalle Valo 	unsigned long flags;
12352be45b66SKalle Valo 	int val;
12362be45b66SKalle Valo 
12372be45b66SKalle Valo 	if (!priv->has_preamble)
12382be45b66SKalle Valo 		return -EOPNOTSUPP;
12392be45b66SKalle Valo 
12402be45b66SKalle Valo 	/* 802.11b has recently defined some short preamble.
12412be45b66SKalle Valo 	 * Basically, the Phy header has been reduced in size.
12422be45b66SKalle Valo 	 * This increase performance, especially at high rates
12432be45b66SKalle Valo 	 * (the preamble is transmitted at 1Mb/s), unfortunately
12442be45b66SKalle Valo 	 * this give compatibility troubles... - Jean II */
12452be45b66SKalle Valo 	val = *((int *) extra);
12462be45b66SKalle Valo 
12472be45b66SKalle Valo 	if (orinoco_lock(priv, &flags) != 0)
12482be45b66SKalle Valo 		return -EBUSY;
12492be45b66SKalle Valo 
12502be45b66SKalle Valo 	if (val)
12512be45b66SKalle Valo 		priv->preamble = 1;
12522be45b66SKalle Valo 	else
12532be45b66SKalle Valo 		priv->preamble = 0;
12542be45b66SKalle Valo 
12552be45b66SKalle Valo 	orinoco_unlock(priv, &flags);
12562be45b66SKalle Valo 
12572be45b66SKalle Valo 	return -EINPROGRESS;		/* Call commit handler */
12582be45b66SKalle Valo }
12592be45b66SKalle Valo 
orinoco_ioctl_getpreamble(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)12602be45b66SKalle Valo static int orinoco_ioctl_getpreamble(struct net_device *dev,
12612be45b66SKalle Valo 				     struct iw_request_info *info,
12622c0e077dSGustavo A. R. Silva 				     union iwreq_data *wrqu,
12632be45b66SKalle Valo 				     char *extra)
12642be45b66SKalle Valo {
12652be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
12662be45b66SKalle Valo 	int *val = (int *) extra;
12672be45b66SKalle Valo 
12682be45b66SKalle Valo 	if (!priv->has_preamble)
12692be45b66SKalle Valo 		return -EOPNOTSUPP;
12702be45b66SKalle Valo 
12712be45b66SKalle Valo 	*val = priv->preamble;
12722be45b66SKalle Valo 	return 0;
12732be45b66SKalle Valo }
12742be45b66SKalle Valo 
12752be45b66SKalle Valo /* ioctl interface to hermes_read_ltv()
12762be45b66SKalle Valo  * To use with iwpriv, pass the RID as the token argument, e.g.
12772be45b66SKalle Valo  * iwpriv get_rid [0xfc00]
12782be45b66SKalle Valo  * At least Wireless Tools 25 is required to use iwpriv.
12792be45b66SKalle Valo  * For Wireless Tools 25 and 26 append "dummy" are the end. */
orinoco_ioctl_getrid(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)12802be45b66SKalle Valo static int orinoco_ioctl_getrid(struct net_device *dev,
12812be45b66SKalle Valo 				struct iw_request_info *info,
12822c0e077dSGustavo A. R. Silva 				union iwreq_data *wrqu,
12832be45b66SKalle Valo 				char *extra)
12842be45b66SKalle Valo {
12852c0e077dSGustavo A. R. Silva 	struct iw_point *data = &wrqu->data;
12862be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
12872be45b66SKalle Valo 	struct hermes *hw = &priv->hw;
12882be45b66SKalle Valo 	int rid = data->flags;
12892be45b66SKalle Valo 	u16 length;
12902be45b66SKalle Valo 	int err;
12912be45b66SKalle Valo 	unsigned long flags;
12922be45b66SKalle Valo 
12932be45b66SKalle Valo 	/* It's a "get" function, but we don't want users to access the
12942be45b66SKalle Valo 	 * WEP key and other raw firmware data */
12952be45b66SKalle Valo 	if (!capable(CAP_NET_ADMIN))
12962be45b66SKalle Valo 		return -EPERM;
12972be45b66SKalle Valo 
12982be45b66SKalle Valo 	if (rid < 0xfc00 || rid > 0xffff)
12992be45b66SKalle Valo 		return -EINVAL;
13002be45b66SKalle Valo 
13012be45b66SKalle Valo 	if (orinoco_lock(priv, &flags) != 0)
13022be45b66SKalle Valo 		return -EBUSY;
13032be45b66SKalle Valo 
13042be45b66SKalle Valo 	err = hw->ops->read_ltv(hw, USER_BAP, rid, MAX_RID_LEN, &length,
13052be45b66SKalle Valo 				extra);
13062be45b66SKalle Valo 	if (err)
13072be45b66SKalle Valo 		goto out;
13082be45b66SKalle Valo 
13092be45b66SKalle Valo 	data->length = min_t(u16, HERMES_RECLEN_TO_BYTES(length),
13102be45b66SKalle Valo 			     MAX_RID_LEN);
13112be45b66SKalle Valo 
13122be45b66SKalle Valo  out:
13132be45b66SKalle Valo 	orinoco_unlock(priv, &flags);
13142be45b66SKalle Valo 	return err;
13152be45b66SKalle Valo }
13162be45b66SKalle Valo 
13172be45b66SKalle Valo 
13182be45b66SKalle Valo /* Commit handler, called after set operations */
orinoco_ioctl_commit(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)13192be45b66SKalle Valo static int orinoco_ioctl_commit(struct net_device *dev,
13202be45b66SKalle Valo 				struct iw_request_info *info,
13212c0e077dSGustavo A. R. Silva 				union iwreq_data *wrqu,
13222be45b66SKalle Valo 				char *extra)
13232be45b66SKalle Valo {
13242be45b66SKalle Valo 	struct orinoco_private *priv = ndev_priv(dev);
13252be45b66SKalle Valo 	unsigned long flags;
13262be45b66SKalle Valo 	int err = 0;
13272be45b66SKalle Valo 
13282be45b66SKalle Valo 	if (!priv->open)
13292be45b66SKalle Valo 		return 0;
13302be45b66SKalle Valo 
13312be45b66SKalle Valo 	if (orinoco_lock(priv, &flags) != 0)
13322be45b66SKalle Valo 		return err;
13332be45b66SKalle Valo 
13342be45b66SKalle Valo 	err = orinoco_commit(priv);
13352be45b66SKalle Valo 
13362be45b66SKalle Valo 	orinoco_unlock(priv, &flags);
13372be45b66SKalle Valo 	return err;
13382be45b66SKalle Valo }
13392be45b66SKalle Valo 
13402be45b66SKalle Valo static const struct iw_priv_args orinoco_privtab[] = {
13412be45b66SKalle Valo 	{ SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" },
13422be45b66SKalle Valo 	{ SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" },
13432be45b66SKalle Valo 	{ SIOCIWFIRSTPRIV + 0x2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
13442be45b66SKalle Valo 	  0, "set_port3" },
13452be45b66SKalle Valo 	{ SIOCIWFIRSTPRIV + 0x3, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
13462be45b66SKalle Valo 	  "get_port3" },
13472be45b66SKalle Valo 	{ SIOCIWFIRSTPRIV + 0x4, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
13482be45b66SKalle Valo 	  0, "set_preamble" },
13492be45b66SKalle Valo 	{ SIOCIWFIRSTPRIV + 0x5, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
13502be45b66SKalle Valo 	  "get_preamble" },
13512be45b66SKalle Valo 	{ SIOCIWFIRSTPRIV + 0x6, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
13522be45b66SKalle Valo 	  0, "set_ibssport" },
13532be45b66SKalle Valo 	{ SIOCIWFIRSTPRIV + 0x7, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
13542be45b66SKalle Valo 	  "get_ibssport" },
13552be45b66SKalle Valo 	{ SIOCIWFIRSTPRIV + 0x9, 0, IW_PRIV_TYPE_BYTE | MAX_RID_LEN,
13562be45b66SKalle Valo 	  "get_rid" },
13572be45b66SKalle Valo };
13582be45b66SKalle Valo 
13592be45b66SKalle Valo 
13602be45b66SKalle Valo /*
13612be45b66SKalle Valo  * Structures to export the Wireless Handlers
13622be45b66SKalle Valo  */
13632be45b66SKalle Valo 
13642be45b66SKalle Valo static const iw_handler	orinoco_handler[] = {
13652c0e077dSGustavo A. R. Silva 	IW_HANDLER(SIOCSIWCOMMIT,	orinoco_ioctl_commit),
1366*02ae6a70SGustavo A. R. Silva 	IW_HANDLER(SIOCGIWNAME,		cfg80211_wext_giwname),
13672c0e077dSGustavo A. R. Silva 	IW_HANDLER(SIOCSIWFREQ,		orinoco_ioctl_setfreq),
13682c0e077dSGustavo A. R. Silva 	IW_HANDLER(SIOCGIWFREQ,		orinoco_ioctl_getfreq),
1369*02ae6a70SGustavo A. R. Silva 	IW_HANDLER(SIOCSIWMODE,		cfg80211_wext_siwmode),
1370*02ae6a70SGustavo A. R. Silva 	IW_HANDLER(SIOCGIWMODE,		cfg80211_wext_giwmode),
13712c0e077dSGustavo A. R. Silva 	IW_HANDLER(SIOCSIWSENS,		orinoco_ioctl_setsens),
13722c0e077dSGustavo A. R. Silva 	IW_HANDLER(SIOCGIWSENS,		orinoco_ioctl_getsens),
1373*02ae6a70SGustavo A. R. Silva 	IW_HANDLER(SIOCGIWRANGE,	cfg80211_wext_giwrange),
13742be45b66SKalle Valo 	IW_HANDLER(SIOCSIWSPY,		iw_handler_set_spy),
13752be45b66SKalle Valo 	IW_HANDLER(SIOCGIWSPY,		iw_handler_get_spy),
13762be45b66SKalle Valo 	IW_HANDLER(SIOCSIWTHRSPY,	iw_handler_set_thrspy),
13772be45b66SKalle Valo 	IW_HANDLER(SIOCGIWTHRSPY,	iw_handler_get_thrspy),
13782c0e077dSGustavo A. R. Silva 	IW_HANDLER(SIOCSIWAP,		orinoco_ioctl_setwap),
13792c0e077dSGustavo A. R. Silva 	IW_HANDLER(SIOCGIWAP,		orinoco_ioctl_getwap),
1380*02ae6a70SGustavo A. R. Silva 	IW_HANDLER(SIOCSIWSCAN,		cfg80211_wext_siwscan),
1381*02ae6a70SGustavo A. R. Silva 	IW_HANDLER(SIOCGIWSCAN,		cfg80211_wext_giwscan),
13822c0e077dSGustavo A. R. Silva 	IW_HANDLER(SIOCSIWESSID,	orinoco_ioctl_setessid),
13832c0e077dSGustavo A. R. Silva 	IW_HANDLER(SIOCGIWESSID,	orinoco_ioctl_getessid),
13842c0e077dSGustavo A. R. Silva 	IW_HANDLER(SIOCSIWRATE,		orinoco_ioctl_setrate),
13852c0e077dSGustavo A. R. Silva 	IW_HANDLER(SIOCGIWRATE,		orinoco_ioctl_getrate),
1386*02ae6a70SGustavo A. R. Silva 	IW_HANDLER(SIOCSIWRTS,		cfg80211_wext_siwrts),
1387*02ae6a70SGustavo A. R. Silva 	IW_HANDLER(SIOCGIWRTS,		cfg80211_wext_giwrts),
1388*02ae6a70SGustavo A. R. Silva 	IW_HANDLER(SIOCSIWFRAG,		cfg80211_wext_siwfrag),
1389*02ae6a70SGustavo A. R. Silva 	IW_HANDLER(SIOCGIWFRAG,		cfg80211_wext_giwfrag),
1390*02ae6a70SGustavo A. R. Silva 	IW_HANDLER(SIOCGIWRETRY,	cfg80211_wext_giwretry),
13912c0e077dSGustavo A. R. Silva 	IW_HANDLER(SIOCSIWENCODE,	orinoco_ioctl_setiwencode),
13922c0e077dSGustavo A. R. Silva 	IW_HANDLER(SIOCGIWENCODE,	orinoco_ioctl_getiwencode),
13932c0e077dSGustavo A. R. Silva 	IW_HANDLER(SIOCSIWPOWER,	orinoco_ioctl_setpower),
13942c0e077dSGustavo A. R. Silva 	IW_HANDLER(SIOCGIWPOWER,	orinoco_ioctl_getpower),
13952be45b66SKalle Valo 	IW_HANDLER(SIOCSIWGENIE,	orinoco_ioctl_set_genie),
13962be45b66SKalle Valo 	IW_HANDLER(SIOCGIWGENIE,	orinoco_ioctl_get_genie),
13972be45b66SKalle Valo 	IW_HANDLER(SIOCSIWMLME,		orinoco_ioctl_set_mlme),
13982be45b66SKalle Valo 	IW_HANDLER(SIOCSIWAUTH,		orinoco_ioctl_set_auth),
13992be45b66SKalle Valo 	IW_HANDLER(SIOCGIWAUTH,		orinoco_ioctl_get_auth),
14002be45b66SKalle Valo 	IW_HANDLER(SIOCSIWENCODEEXT,	orinoco_ioctl_set_encodeext),
14012be45b66SKalle Valo 	IW_HANDLER(SIOCGIWENCODEEXT,	orinoco_ioctl_get_encodeext),
14022be45b66SKalle Valo };
14032be45b66SKalle Valo 
14042be45b66SKalle Valo 
14052be45b66SKalle Valo /*
14062be45b66SKalle Valo   Added typecasting since we no longer use iwreq_data -- Moustafa
14072be45b66SKalle Valo  */
14082be45b66SKalle Valo static const iw_handler	orinoco_private_handler[] = {
14092c0e077dSGustavo A. R. Silva 	[0] = orinoco_ioctl_reset,
14102c0e077dSGustavo A. R. Silva 	[1] = orinoco_ioctl_reset,
14112c0e077dSGustavo A. R. Silva 	[2] = orinoco_ioctl_setport3,
14122c0e077dSGustavo A. R. Silva 	[3] = orinoco_ioctl_getport3,
14132c0e077dSGustavo A. R. Silva 	[4] = orinoco_ioctl_setpreamble,
14142c0e077dSGustavo A. R. Silva 	[5] = orinoco_ioctl_getpreamble,
14152c0e077dSGustavo A. R. Silva 	[6] = orinoco_ioctl_setibssport,
14162c0e077dSGustavo A. R. Silva 	[7] = orinoco_ioctl_getibssport,
14172c0e077dSGustavo A. R. Silva 	[9] = orinoco_ioctl_getrid,
14182be45b66SKalle Valo };
14192be45b66SKalle Valo 
14202be45b66SKalle Valo const struct iw_handler_def orinoco_handler_def = {
14212be45b66SKalle Valo 	.num_standard = ARRAY_SIZE(orinoco_handler),
14222be45b66SKalle Valo 	.num_private = ARRAY_SIZE(orinoco_private_handler),
14232be45b66SKalle Valo 	.num_private_args = ARRAY_SIZE(orinoco_privtab),
14242be45b66SKalle Valo 	.standard = orinoco_handler,
14252be45b66SKalle Valo 	.private = orinoco_private_handler,
14262be45b66SKalle Valo 	.private_args = orinoco_privtab,
14272be45b66SKalle Valo 	.get_wireless_stats = orinoco_get_wireless_stats,
14282be45b66SKalle Valo };
1429