xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/intersil/orinoco/wext.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /* Wireless extensions support.
2*4882a593Smuzhiyun  *
3*4882a593Smuzhiyun  * See copyright notice in main.c
4*4882a593Smuzhiyun  */
5*4882a593Smuzhiyun #include <linux/slab.h>
6*4882a593Smuzhiyun #include <linux/kernel.h>
7*4882a593Smuzhiyun #include <linux/if_arp.h>
8*4882a593Smuzhiyun #include <linux/wireless.h>
9*4882a593Smuzhiyun #include <linux/ieee80211.h>
10*4882a593Smuzhiyun #include <linux/etherdevice.h>
11*4882a593Smuzhiyun #include <net/iw_handler.h>
12*4882a593Smuzhiyun #include <net/cfg80211.h>
13*4882a593Smuzhiyun #include <net/cfg80211-wext.h>
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #include "hermes.h"
16*4882a593Smuzhiyun #include "hermes_rid.h"
17*4882a593Smuzhiyun #include "orinoco.h"
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #include "hw.h"
20*4882a593Smuzhiyun #include "mic.h"
21*4882a593Smuzhiyun #include "scan.h"
22*4882a593Smuzhiyun #include "main.h"
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun #include "wext.h"
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #define MAX_RID_LEN 1024
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun /* Helper routine to record keys
29*4882a593Smuzhiyun  * 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)30*4882a593Smuzhiyun static int orinoco_set_key(struct orinoco_private *priv, int index,
31*4882a593Smuzhiyun 			   enum orinoco_alg alg, const u8 *key, int key_len,
32*4882a593Smuzhiyun 			   const u8 *seq, int seq_len)
33*4882a593Smuzhiyun {
34*4882a593Smuzhiyun 	kfree_sensitive(priv->keys[index].key);
35*4882a593Smuzhiyun 	kfree_sensitive(priv->keys[index].seq);
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 	if (key_len) {
38*4882a593Smuzhiyun 		priv->keys[index].key = kzalloc(key_len, GFP_ATOMIC);
39*4882a593Smuzhiyun 		if (!priv->keys[index].key)
40*4882a593Smuzhiyun 			goto nomem;
41*4882a593Smuzhiyun 	} else
42*4882a593Smuzhiyun 		priv->keys[index].key = NULL;
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun 	if (seq_len) {
45*4882a593Smuzhiyun 		priv->keys[index].seq = kzalloc(seq_len, GFP_ATOMIC);
46*4882a593Smuzhiyun 		if (!priv->keys[index].seq)
47*4882a593Smuzhiyun 			goto free_key;
48*4882a593Smuzhiyun 	} else
49*4882a593Smuzhiyun 		priv->keys[index].seq = NULL;
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 	priv->keys[index].key_len = key_len;
52*4882a593Smuzhiyun 	priv->keys[index].seq_len = seq_len;
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 	if (key_len)
55*4882a593Smuzhiyun 		memcpy((void *)priv->keys[index].key, key, key_len);
56*4882a593Smuzhiyun 	if (seq_len)
57*4882a593Smuzhiyun 		memcpy((void *)priv->keys[index].seq, seq, seq_len);
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun 	switch (alg) {
60*4882a593Smuzhiyun 	case ORINOCO_ALG_TKIP:
61*4882a593Smuzhiyun 		priv->keys[index].cipher = WLAN_CIPHER_SUITE_TKIP;
62*4882a593Smuzhiyun 		break;
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun 	case ORINOCO_ALG_WEP:
65*4882a593Smuzhiyun 		priv->keys[index].cipher = (key_len > SMALL_KEY_SIZE) ?
66*4882a593Smuzhiyun 			WLAN_CIPHER_SUITE_WEP104 : WLAN_CIPHER_SUITE_WEP40;
67*4882a593Smuzhiyun 		break;
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	case ORINOCO_ALG_NONE:
70*4882a593Smuzhiyun 	default:
71*4882a593Smuzhiyun 		priv->keys[index].cipher = 0;
72*4882a593Smuzhiyun 		break;
73*4882a593Smuzhiyun 	}
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun 	return 0;
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun free_key:
78*4882a593Smuzhiyun 	kfree(priv->keys[index].key);
79*4882a593Smuzhiyun 	priv->keys[index].key = NULL;
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun nomem:
82*4882a593Smuzhiyun 	priv->keys[index].key_len = 0;
83*4882a593Smuzhiyun 	priv->keys[index].seq_len = 0;
84*4882a593Smuzhiyun 	priv->keys[index].cipher = 0;
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 	return -ENOMEM;
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun 
orinoco_get_wireless_stats(struct net_device * dev)89*4882a593Smuzhiyun static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun 	struct orinoco_private *priv = ndev_priv(dev);
92*4882a593Smuzhiyun 	struct hermes *hw = &priv->hw;
93*4882a593Smuzhiyun 	struct iw_statistics *wstats = &priv->wstats;
94*4882a593Smuzhiyun 	int err;
95*4882a593Smuzhiyun 	unsigned long flags;
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	if (!netif_device_present(dev)) {
98*4882a593Smuzhiyun 		printk(KERN_WARNING "%s: get_wireless_stats() called while device not present\n",
99*4882a593Smuzhiyun 		       dev->name);
100*4882a593Smuzhiyun 		return NULL; /* FIXME: Can we do better than this? */
101*4882a593Smuzhiyun 	}
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	/* If busy, return the old stats.  Returning NULL may cause
104*4882a593Smuzhiyun 	 * the interface to disappear from /proc/net/wireless */
105*4882a593Smuzhiyun 	if (orinoco_lock(priv, &flags) != 0)
106*4882a593Smuzhiyun 		return wstats;
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	/* We can't really wait for the tallies inquiry command to
109*4882a593Smuzhiyun 	 * complete, so we just use the previous results and trigger
110*4882a593Smuzhiyun 	 * a new tallies inquiry command for next time - Jean II */
111*4882a593Smuzhiyun 	/* FIXME: Really we should wait for the inquiry to come back -
112*4882a593Smuzhiyun 	 * as it is the stats we give don't make a whole lot of sense.
113*4882a593Smuzhiyun 	 * Unfortunately, it's not clear how to do that within the
114*4882a593Smuzhiyun 	 * wireless extensions framework: I think we're in user
115*4882a593Smuzhiyun 	 * context, but a lock seems to be held by the time we get in
116*4882a593Smuzhiyun 	 * here so we're not safe to sleep here. */
117*4882a593Smuzhiyun 	hermes_inquire(hw, HERMES_INQ_TALLIES);
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	if (priv->iw_mode == NL80211_IFTYPE_ADHOC) {
120*4882a593Smuzhiyun 		memset(&wstats->qual, 0, sizeof(wstats->qual));
121*4882a593Smuzhiyun 		/* If a spy address is defined, we report stats of the
122*4882a593Smuzhiyun 		 * first spy address - Jean II */
123*4882a593Smuzhiyun 		if (SPY_NUMBER(priv)) {
124*4882a593Smuzhiyun 			wstats->qual.qual = priv->spy_data.spy_stat[0].qual;
125*4882a593Smuzhiyun 			wstats->qual.level = priv->spy_data.spy_stat[0].level;
126*4882a593Smuzhiyun 			wstats->qual.noise = priv->spy_data.spy_stat[0].noise;
127*4882a593Smuzhiyun 			wstats->qual.updated =
128*4882a593Smuzhiyun 				priv->spy_data.spy_stat[0].updated;
129*4882a593Smuzhiyun 		}
130*4882a593Smuzhiyun 	} else {
131*4882a593Smuzhiyun 		struct {
132*4882a593Smuzhiyun 			__le16 qual, signal, noise, unused;
133*4882a593Smuzhiyun 		} __packed cq;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 		err = HERMES_READ_RECORD(hw, USER_BAP,
136*4882a593Smuzhiyun 					 HERMES_RID_COMMSQUALITY, &cq);
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 		if (!err) {
139*4882a593Smuzhiyun 			wstats->qual.qual = (int)le16_to_cpu(cq.qual);
140*4882a593Smuzhiyun 			wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95;
141*4882a593Smuzhiyun 			wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95;
142*4882a593Smuzhiyun 			wstats->qual.updated =
143*4882a593Smuzhiyun 				IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
144*4882a593Smuzhiyun 		}
145*4882a593Smuzhiyun 	}
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	orinoco_unlock(priv, &flags);
148*4882a593Smuzhiyun 	return wstats;
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun /********************************************************************/
152*4882a593Smuzhiyun /* Wireless extensions                                              */
153*4882a593Smuzhiyun /********************************************************************/
154*4882a593Smuzhiyun 
orinoco_ioctl_setwap(struct net_device * dev,struct iw_request_info * info,struct sockaddr * ap_addr,char * extra)155*4882a593Smuzhiyun static int orinoco_ioctl_setwap(struct net_device *dev,
156*4882a593Smuzhiyun 				struct iw_request_info *info,
157*4882a593Smuzhiyun 				struct sockaddr *ap_addr,
158*4882a593Smuzhiyun 				char *extra)
159*4882a593Smuzhiyun {
160*4882a593Smuzhiyun 	struct orinoco_private *priv = ndev_priv(dev);
161*4882a593Smuzhiyun 	int err = -EINPROGRESS;		/* Call commit handler */
162*4882a593Smuzhiyun 	unsigned long flags;
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	if (orinoco_lock(priv, &flags) != 0)
165*4882a593Smuzhiyun 		return -EBUSY;
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	/* Enable automatic roaming - no sanity checks are needed */
168*4882a593Smuzhiyun 	if (is_zero_ether_addr(ap_addr->sa_data) ||
169*4882a593Smuzhiyun 	    is_broadcast_ether_addr(ap_addr->sa_data)) {
170*4882a593Smuzhiyun 		priv->bssid_fixed = 0;
171*4882a593Smuzhiyun 		eth_zero_addr(priv->desired_bssid);
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 		/* "off" means keep existing connection */
174*4882a593Smuzhiyun 		if (ap_addr->sa_data[0] == 0) {
175*4882a593Smuzhiyun 			__orinoco_hw_set_wap(priv);
176*4882a593Smuzhiyun 			err = 0;
177*4882a593Smuzhiyun 		}
178*4882a593Smuzhiyun 		goto out;
179*4882a593Smuzhiyun 	}
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	if (priv->firmware_type == FIRMWARE_TYPE_AGERE) {
182*4882a593Smuzhiyun 		printk(KERN_WARNING "%s: Lucent/Agere firmware doesn't "
183*4882a593Smuzhiyun 		       "support manual roaming\n",
184*4882a593Smuzhiyun 		       dev->name);
185*4882a593Smuzhiyun 		err = -EOPNOTSUPP;
186*4882a593Smuzhiyun 		goto out;
187*4882a593Smuzhiyun 	}
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	if (priv->iw_mode != NL80211_IFTYPE_STATION) {
190*4882a593Smuzhiyun 		printk(KERN_WARNING "%s: Manual roaming supported only in "
191*4882a593Smuzhiyun 		       "managed mode\n", dev->name);
192*4882a593Smuzhiyun 		err = -EOPNOTSUPP;
193*4882a593Smuzhiyun 		goto out;
194*4882a593Smuzhiyun 	}
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	/* Intersil firmware hangs without Desired ESSID */
197*4882a593Smuzhiyun 	if (priv->firmware_type == FIRMWARE_TYPE_INTERSIL &&
198*4882a593Smuzhiyun 	    strlen(priv->desired_essid) == 0) {
199*4882a593Smuzhiyun 		printk(KERN_WARNING "%s: Desired ESSID must be set for "
200*4882a593Smuzhiyun 		       "manual roaming\n", dev->name);
201*4882a593Smuzhiyun 		err = -EOPNOTSUPP;
202*4882a593Smuzhiyun 		goto out;
203*4882a593Smuzhiyun 	}
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	/* Finally, enable manual roaming */
206*4882a593Smuzhiyun 	priv->bssid_fixed = 1;
207*4882a593Smuzhiyun 	memcpy(priv->desired_bssid, &ap_addr->sa_data, ETH_ALEN);
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun  out:
210*4882a593Smuzhiyun 	orinoco_unlock(priv, &flags);
211*4882a593Smuzhiyun 	return err;
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun 
orinoco_ioctl_getwap(struct net_device * dev,struct iw_request_info * info,struct sockaddr * ap_addr,char * extra)214*4882a593Smuzhiyun static int orinoco_ioctl_getwap(struct net_device *dev,
215*4882a593Smuzhiyun 				struct iw_request_info *info,
216*4882a593Smuzhiyun 				struct sockaddr *ap_addr,
217*4882a593Smuzhiyun 				char *extra)
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun 	struct orinoco_private *priv = ndev_priv(dev);
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	int err = 0;
222*4882a593Smuzhiyun 	unsigned long flags;
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	if (orinoco_lock(priv, &flags) != 0)
225*4882a593Smuzhiyun 		return -EBUSY;
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	ap_addr->sa_family = ARPHRD_ETHER;
228*4882a593Smuzhiyun 	err = orinoco_hw_get_current_bssid(priv, ap_addr->sa_data);
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	orinoco_unlock(priv, &flags);
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	return err;
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun 
orinoco_ioctl_setiwencode(struct net_device * dev,struct iw_request_info * info,struct iw_point * erq,char * keybuf)235*4882a593Smuzhiyun static int orinoco_ioctl_setiwencode(struct net_device *dev,
236*4882a593Smuzhiyun 				     struct iw_request_info *info,
237*4882a593Smuzhiyun 				     struct iw_point *erq,
238*4882a593Smuzhiyun 				     char *keybuf)
239*4882a593Smuzhiyun {
240*4882a593Smuzhiyun 	struct orinoco_private *priv = ndev_priv(dev);
241*4882a593Smuzhiyun 	int index = (erq->flags & IW_ENCODE_INDEX) - 1;
242*4882a593Smuzhiyun 	int setindex = priv->tx_key;
243*4882a593Smuzhiyun 	enum orinoco_alg encode_alg = priv->encode_alg;
244*4882a593Smuzhiyun 	int restricted = priv->wep_restrict;
245*4882a593Smuzhiyun 	int err = -EINPROGRESS;		/* Call commit handler */
246*4882a593Smuzhiyun 	unsigned long flags;
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	if (!priv->has_wep)
249*4882a593Smuzhiyun 		return -EOPNOTSUPP;
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	if (erq->pointer) {
252*4882a593Smuzhiyun 		/* We actually have a key to set - check its length */
253*4882a593Smuzhiyun 		if (erq->length > LARGE_KEY_SIZE)
254*4882a593Smuzhiyun 			return -E2BIG;
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 		if ((erq->length > SMALL_KEY_SIZE) && !priv->has_big_wep)
257*4882a593Smuzhiyun 			return -E2BIG;
258*4882a593Smuzhiyun 	}
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 	if (orinoco_lock(priv, &flags) != 0)
261*4882a593Smuzhiyun 		return -EBUSY;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	/* Clear any TKIP key we have */
264*4882a593Smuzhiyun 	if ((priv->has_wpa) && (priv->encode_alg == ORINOCO_ALG_TKIP))
265*4882a593Smuzhiyun 		(void) orinoco_clear_tkip_key(priv, setindex);
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	if (erq->length > 0) {
268*4882a593Smuzhiyun 		if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
269*4882a593Smuzhiyun 			index = priv->tx_key;
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 		/* Switch on WEP if off */
272*4882a593Smuzhiyun 		if (encode_alg != ORINOCO_ALG_WEP) {
273*4882a593Smuzhiyun 			setindex = index;
274*4882a593Smuzhiyun 			encode_alg = ORINOCO_ALG_WEP;
275*4882a593Smuzhiyun 		}
276*4882a593Smuzhiyun 	} else {
277*4882a593Smuzhiyun 		/* Important note : if the user do "iwconfig eth0 enc off",
278*4882a593Smuzhiyun 		 * we will arrive there with an index of -1. This is valid
279*4882a593Smuzhiyun 		 * but need to be taken care off... Jean II */
280*4882a593Smuzhiyun 		if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) {
281*4882a593Smuzhiyun 			if ((index != -1) || (erq->flags == 0)) {
282*4882a593Smuzhiyun 				err = -EINVAL;
283*4882a593Smuzhiyun 				goto out;
284*4882a593Smuzhiyun 			}
285*4882a593Smuzhiyun 		} else {
286*4882a593Smuzhiyun 			/* Set the index : Check that the key is valid */
287*4882a593Smuzhiyun 			if (priv->keys[index].key_len == 0) {
288*4882a593Smuzhiyun 				err = -EINVAL;
289*4882a593Smuzhiyun 				goto out;
290*4882a593Smuzhiyun 			}
291*4882a593Smuzhiyun 			setindex = index;
292*4882a593Smuzhiyun 		}
293*4882a593Smuzhiyun 	}
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	if (erq->flags & IW_ENCODE_DISABLED)
296*4882a593Smuzhiyun 		encode_alg = ORINOCO_ALG_NONE;
297*4882a593Smuzhiyun 	if (erq->flags & IW_ENCODE_OPEN)
298*4882a593Smuzhiyun 		restricted = 0;
299*4882a593Smuzhiyun 	if (erq->flags & IW_ENCODE_RESTRICTED)
300*4882a593Smuzhiyun 		restricted = 1;
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	if (erq->pointer && erq->length > 0) {
303*4882a593Smuzhiyun 		err = orinoco_set_key(priv, index, ORINOCO_ALG_WEP, keybuf,
304*4882a593Smuzhiyun 				      erq->length, NULL, 0);
305*4882a593Smuzhiyun 	}
306*4882a593Smuzhiyun 	priv->tx_key = setindex;
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	/* Try fast key change if connected and only keys are changed */
309*4882a593Smuzhiyun 	if ((priv->encode_alg == encode_alg) &&
310*4882a593Smuzhiyun 	    (priv->wep_restrict == restricted) &&
311*4882a593Smuzhiyun 	    netif_carrier_ok(dev)) {
312*4882a593Smuzhiyun 		err = __orinoco_hw_setup_wepkeys(priv);
313*4882a593Smuzhiyun 		/* No need to commit if successful */
314*4882a593Smuzhiyun 		goto out;
315*4882a593Smuzhiyun 	}
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	priv->encode_alg = encode_alg;
318*4882a593Smuzhiyun 	priv->wep_restrict = restricted;
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun  out:
321*4882a593Smuzhiyun 	orinoco_unlock(priv, &flags);
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 	return err;
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun 
orinoco_ioctl_getiwencode(struct net_device * dev,struct iw_request_info * info,struct iw_point * erq,char * keybuf)326*4882a593Smuzhiyun static int orinoco_ioctl_getiwencode(struct net_device *dev,
327*4882a593Smuzhiyun 				     struct iw_request_info *info,
328*4882a593Smuzhiyun 				     struct iw_point *erq,
329*4882a593Smuzhiyun 				     char *keybuf)
330*4882a593Smuzhiyun {
331*4882a593Smuzhiyun 	struct orinoco_private *priv = ndev_priv(dev);
332*4882a593Smuzhiyun 	int index = (erq->flags & IW_ENCODE_INDEX) - 1;
333*4882a593Smuzhiyun 	unsigned long flags;
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	if (!priv->has_wep)
336*4882a593Smuzhiyun 		return -EOPNOTSUPP;
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun 	if (orinoco_lock(priv, &flags) != 0)
339*4882a593Smuzhiyun 		return -EBUSY;
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 	if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
342*4882a593Smuzhiyun 		index = priv->tx_key;
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 	erq->flags = 0;
345*4882a593Smuzhiyun 	if (!priv->encode_alg)
346*4882a593Smuzhiyun 		erq->flags |= IW_ENCODE_DISABLED;
347*4882a593Smuzhiyun 	erq->flags |= index + 1;
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun 	if (priv->wep_restrict)
350*4882a593Smuzhiyun 		erq->flags |= IW_ENCODE_RESTRICTED;
351*4882a593Smuzhiyun 	else
352*4882a593Smuzhiyun 		erq->flags |= IW_ENCODE_OPEN;
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 	erq->length = priv->keys[index].key_len;
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	memcpy(keybuf, priv->keys[index].key, erq->length);
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun 	orinoco_unlock(priv, &flags);
359*4882a593Smuzhiyun 	return 0;
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun 
orinoco_ioctl_setessid(struct net_device * dev,struct iw_request_info * info,struct iw_point * erq,char * essidbuf)362*4882a593Smuzhiyun static int orinoco_ioctl_setessid(struct net_device *dev,
363*4882a593Smuzhiyun 				  struct iw_request_info *info,
364*4882a593Smuzhiyun 				  struct iw_point *erq,
365*4882a593Smuzhiyun 				  char *essidbuf)
366*4882a593Smuzhiyun {
367*4882a593Smuzhiyun 	struct orinoco_private *priv = ndev_priv(dev);
368*4882a593Smuzhiyun 	unsigned long flags;
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 	/* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it
371*4882a593Smuzhiyun 	 * anyway... - Jean II */
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun 	/* Hum... Should not use Wireless Extension constant (may change),
374*4882a593Smuzhiyun 	 * should use our own... - Jean II */
375*4882a593Smuzhiyun 	if (erq->length > IW_ESSID_MAX_SIZE)
376*4882a593Smuzhiyun 		return -E2BIG;
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	if (orinoco_lock(priv, &flags) != 0)
379*4882a593Smuzhiyun 		return -EBUSY;
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	/* NULL the string (for NULL termination & ESSID = ANY) - Jean II */
382*4882a593Smuzhiyun 	memset(priv->desired_essid, 0, sizeof(priv->desired_essid));
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	/* If not ANY, get the new ESSID */
385*4882a593Smuzhiyun 	if (erq->flags)
386*4882a593Smuzhiyun 		memcpy(priv->desired_essid, essidbuf, erq->length);
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 	orinoco_unlock(priv, &flags);
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 	return -EINPROGRESS;		/* Call commit handler */
391*4882a593Smuzhiyun }
392*4882a593Smuzhiyun 
orinoco_ioctl_getessid(struct net_device * dev,struct iw_request_info * info,struct iw_point * erq,char * essidbuf)393*4882a593Smuzhiyun static int orinoco_ioctl_getessid(struct net_device *dev,
394*4882a593Smuzhiyun 				  struct iw_request_info *info,
395*4882a593Smuzhiyun 				  struct iw_point *erq,
396*4882a593Smuzhiyun 				  char *essidbuf)
397*4882a593Smuzhiyun {
398*4882a593Smuzhiyun 	struct orinoco_private *priv = ndev_priv(dev);
399*4882a593Smuzhiyun 	int active;
400*4882a593Smuzhiyun 	int err = 0;
401*4882a593Smuzhiyun 	unsigned long flags;
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 	if (netif_running(dev)) {
404*4882a593Smuzhiyun 		err = orinoco_hw_get_essid(priv, &active, essidbuf);
405*4882a593Smuzhiyun 		if (err < 0)
406*4882a593Smuzhiyun 			return err;
407*4882a593Smuzhiyun 		erq->length = err;
408*4882a593Smuzhiyun 	} else {
409*4882a593Smuzhiyun 		if (orinoco_lock(priv, &flags) != 0)
410*4882a593Smuzhiyun 			return -EBUSY;
411*4882a593Smuzhiyun 		memcpy(essidbuf, priv->desired_essid, IW_ESSID_MAX_SIZE);
412*4882a593Smuzhiyun 		erq->length = strlen(priv->desired_essid);
413*4882a593Smuzhiyun 		orinoco_unlock(priv, &flags);
414*4882a593Smuzhiyun 	}
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	erq->flags = 1;
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 	return 0;
419*4882a593Smuzhiyun }
420*4882a593Smuzhiyun 
orinoco_ioctl_setfreq(struct net_device * dev,struct iw_request_info * info,struct iw_freq * frq,char * extra)421*4882a593Smuzhiyun static int orinoco_ioctl_setfreq(struct net_device *dev,
422*4882a593Smuzhiyun 				 struct iw_request_info *info,
423*4882a593Smuzhiyun 				 struct iw_freq *frq,
424*4882a593Smuzhiyun 				 char *extra)
425*4882a593Smuzhiyun {
426*4882a593Smuzhiyun 	struct orinoco_private *priv = ndev_priv(dev);
427*4882a593Smuzhiyun 	int chan = -1;
428*4882a593Smuzhiyun 	unsigned long flags;
429*4882a593Smuzhiyun 	int err = -EINPROGRESS;		/* Call commit handler */
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun 	/* In infrastructure mode the AP sets the channel */
432*4882a593Smuzhiyun 	if (priv->iw_mode == NL80211_IFTYPE_STATION)
433*4882a593Smuzhiyun 		return -EBUSY;
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun 	if ((frq->e == 0) && (frq->m <= 1000)) {
436*4882a593Smuzhiyun 		/* Setting by channel number */
437*4882a593Smuzhiyun 		chan = frq->m;
438*4882a593Smuzhiyun 	} else {
439*4882a593Smuzhiyun 		/* Setting by frequency */
440*4882a593Smuzhiyun 		int denom = 1;
441*4882a593Smuzhiyun 		int i;
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun 		/* Calculate denominator to rescale to MHz */
444*4882a593Smuzhiyun 		for (i = 0; i < (6 - frq->e); i++)
445*4882a593Smuzhiyun 			denom *= 10;
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun 		chan = ieee80211_frequency_to_channel(frq->m / denom);
448*4882a593Smuzhiyun 	}
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun 	if ((chan < 1) || (chan > NUM_CHANNELS) ||
451*4882a593Smuzhiyun 	     !(priv->channel_mask & (1 << (chan - 1))))
452*4882a593Smuzhiyun 		return -EINVAL;
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	if (orinoco_lock(priv, &flags) != 0)
455*4882a593Smuzhiyun 		return -EBUSY;
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 	priv->channel = chan;
458*4882a593Smuzhiyun 	if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
459*4882a593Smuzhiyun 		/* Fast channel change - no commit if successful */
460*4882a593Smuzhiyun 		struct hermes *hw = &priv->hw;
461*4882a593Smuzhiyun 		err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST |
462*4882a593Smuzhiyun 					    HERMES_TEST_SET_CHANNEL,
463*4882a593Smuzhiyun 					chan, NULL);
464*4882a593Smuzhiyun 	}
465*4882a593Smuzhiyun 	orinoco_unlock(priv, &flags);
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun 	return err;
468*4882a593Smuzhiyun }
469*4882a593Smuzhiyun 
orinoco_ioctl_getfreq(struct net_device * dev,struct iw_request_info * info,struct iw_freq * frq,char * extra)470*4882a593Smuzhiyun static int orinoco_ioctl_getfreq(struct net_device *dev,
471*4882a593Smuzhiyun 				 struct iw_request_info *info,
472*4882a593Smuzhiyun 				 struct iw_freq *frq,
473*4882a593Smuzhiyun 				 char *extra)
474*4882a593Smuzhiyun {
475*4882a593Smuzhiyun 	struct orinoco_private *priv = ndev_priv(dev);
476*4882a593Smuzhiyun 	int tmp;
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun 	/* Locking done in there */
479*4882a593Smuzhiyun 	tmp = orinoco_hw_get_freq(priv);
480*4882a593Smuzhiyun 	if (tmp < 0)
481*4882a593Smuzhiyun 		return tmp;
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun 	frq->m = tmp * 100000;
484*4882a593Smuzhiyun 	frq->e = 1;
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 	return 0;
487*4882a593Smuzhiyun }
488*4882a593Smuzhiyun 
orinoco_ioctl_getsens(struct net_device * dev,struct iw_request_info * info,struct iw_param * srq,char * extra)489*4882a593Smuzhiyun static int orinoco_ioctl_getsens(struct net_device *dev,
490*4882a593Smuzhiyun 				 struct iw_request_info *info,
491*4882a593Smuzhiyun 				 struct iw_param *srq,
492*4882a593Smuzhiyun 				 char *extra)
493*4882a593Smuzhiyun {
494*4882a593Smuzhiyun 	struct orinoco_private *priv = ndev_priv(dev);
495*4882a593Smuzhiyun 	struct hermes *hw = &priv->hw;
496*4882a593Smuzhiyun 	u16 val;
497*4882a593Smuzhiyun 	int err;
498*4882a593Smuzhiyun 	unsigned long flags;
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 	if (!priv->has_sensitivity)
501*4882a593Smuzhiyun 		return -EOPNOTSUPP;
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun 	if (orinoco_lock(priv, &flags) != 0)
504*4882a593Smuzhiyun 		return -EBUSY;
505*4882a593Smuzhiyun 	err = hermes_read_wordrec(hw, USER_BAP,
506*4882a593Smuzhiyun 				  HERMES_RID_CNFSYSTEMSCALE, &val);
507*4882a593Smuzhiyun 	orinoco_unlock(priv, &flags);
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun 	if (err)
510*4882a593Smuzhiyun 		return err;
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun 	srq->value = val;
513*4882a593Smuzhiyun 	srq->fixed = 0; /* auto */
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun 	return 0;
516*4882a593Smuzhiyun }
517*4882a593Smuzhiyun 
orinoco_ioctl_setsens(struct net_device * dev,struct iw_request_info * info,struct iw_param * srq,char * extra)518*4882a593Smuzhiyun static int orinoco_ioctl_setsens(struct net_device *dev,
519*4882a593Smuzhiyun 				 struct iw_request_info *info,
520*4882a593Smuzhiyun 				 struct iw_param *srq,
521*4882a593Smuzhiyun 				 char *extra)
522*4882a593Smuzhiyun {
523*4882a593Smuzhiyun 	struct orinoco_private *priv = ndev_priv(dev);
524*4882a593Smuzhiyun 	int val = srq->value;
525*4882a593Smuzhiyun 	unsigned long flags;
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun 	if (!priv->has_sensitivity)
528*4882a593Smuzhiyun 		return -EOPNOTSUPP;
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun 	if ((val < 1) || (val > 3))
531*4882a593Smuzhiyun 		return -EINVAL;
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun 	if (orinoco_lock(priv, &flags) != 0)
534*4882a593Smuzhiyun 		return -EBUSY;
535*4882a593Smuzhiyun 	priv->ap_density = val;
536*4882a593Smuzhiyun 	orinoco_unlock(priv, &flags);
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun 	return -EINPROGRESS;		/* Call commit handler */
539*4882a593Smuzhiyun }
540*4882a593Smuzhiyun 
orinoco_ioctl_setrate(struct net_device * dev,struct iw_request_info * info,struct iw_param * rrq,char * extra)541*4882a593Smuzhiyun static int orinoco_ioctl_setrate(struct net_device *dev,
542*4882a593Smuzhiyun 				 struct iw_request_info *info,
543*4882a593Smuzhiyun 				 struct iw_param *rrq,
544*4882a593Smuzhiyun 				 char *extra)
545*4882a593Smuzhiyun {
546*4882a593Smuzhiyun 	struct orinoco_private *priv = ndev_priv(dev);
547*4882a593Smuzhiyun 	int ratemode;
548*4882a593Smuzhiyun 	int bitrate; /* 100s of kilobits */
549*4882a593Smuzhiyun 	unsigned long flags;
550*4882a593Smuzhiyun 
551*4882a593Smuzhiyun 	/* As the user space doesn't know our highest rate, it uses -1
552*4882a593Smuzhiyun 	 * to ask us to set the highest rate.  Test it using "iwconfig
553*4882a593Smuzhiyun 	 * ethX rate auto" - Jean II */
554*4882a593Smuzhiyun 	if (rrq->value == -1)
555*4882a593Smuzhiyun 		bitrate = 110;
556*4882a593Smuzhiyun 	else {
557*4882a593Smuzhiyun 		if (rrq->value % 100000)
558*4882a593Smuzhiyun 			return -EINVAL;
559*4882a593Smuzhiyun 		bitrate = rrq->value / 100000;
560*4882a593Smuzhiyun 	}
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun 	ratemode = orinoco_get_bitratemode(bitrate, !rrq->fixed);
563*4882a593Smuzhiyun 
564*4882a593Smuzhiyun 	if (ratemode == -1)
565*4882a593Smuzhiyun 		return -EINVAL;
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 	if (orinoco_lock(priv, &flags) != 0)
568*4882a593Smuzhiyun 		return -EBUSY;
569*4882a593Smuzhiyun 	priv->bitratemode = ratemode;
570*4882a593Smuzhiyun 	orinoco_unlock(priv, &flags);
571*4882a593Smuzhiyun 
572*4882a593Smuzhiyun 	return -EINPROGRESS;
573*4882a593Smuzhiyun }
574*4882a593Smuzhiyun 
orinoco_ioctl_getrate(struct net_device * dev,struct iw_request_info * info,struct iw_param * rrq,char * extra)575*4882a593Smuzhiyun static int orinoco_ioctl_getrate(struct net_device *dev,
576*4882a593Smuzhiyun 				 struct iw_request_info *info,
577*4882a593Smuzhiyun 				 struct iw_param *rrq,
578*4882a593Smuzhiyun 				 char *extra)
579*4882a593Smuzhiyun {
580*4882a593Smuzhiyun 	struct orinoco_private *priv = ndev_priv(dev);
581*4882a593Smuzhiyun 	int err = 0;
582*4882a593Smuzhiyun 	int bitrate, automatic;
583*4882a593Smuzhiyun 	unsigned long flags;
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun 	if (orinoco_lock(priv, &flags) != 0)
586*4882a593Smuzhiyun 		return -EBUSY;
587*4882a593Smuzhiyun 
588*4882a593Smuzhiyun 	orinoco_get_ratemode_cfg(priv->bitratemode, &bitrate, &automatic);
589*4882a593Smuzhiyun 
590*4882a593Smuzhiyun 	/* If the interface is running we try to find more about the
591*4882a593Smuzhiyun 	   current mode */
592*4882a593Smuzhiyun 	if (netif_running(dev)) {
593*4882a593Smuzhiyun 		int act_bitrate;
594*4882a593Smuzhiyun 		int lerr;
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun 		/* Ignore errors if we can't get the actual bitrate */
597*4882a593Smuzhiyun 		lerr = orinoco_hw_get_act_bitrate(priv, &act_bitrate);
598*4882a593Smuzhiyun 		if (!lerr)
599*4882a593Smuzhiyun 			bitrate = act_bitrate;
600*4882a593Smuzhiyun 	}
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 	orinoco_unlock(priv, &flags);
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun 	rrq->value = bitrate;
605*4882a593Smuzhiyun 	rrq->fixed = !automatic;
606*4882a593Smuzhiyun 	rrq->disabled = 0;
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun 	return err;
609*4882a593Smuzhiyun }
610*4882a593Smuzhiyun 
orinoco_ioctl_setpower(struct net_device * dev,struct iw_request_info * info,struct iw_param * prq,char * extra)611*4882a593Smuzhiyun static int orinoco_ioctl_setpower(struct net_device *dev,
612*4882a593Smuzhiyun 				  struct iw_request_info *info,
613*4882a593Smuzhiyun 				  struct iw_param *prq,
614*4882a593Smuzhiyun 				  char *extra)
615*4882a593Smuzhiyun {
616*4882a593Smuzhiyun 	struct orinoco_private *priv = ndev_priv(dev);
617*4882a593Smuzhiyun 	int err = -EINPROGRESS;		/* Call commit handler */
618*4882a593Smuzhiyun 	unsigned long flags;
619*4882a593Smuzhiyun 
620*4882a593Smuzhiyun 	if (orinoco_lock(priv, &flags) != 0)
621*4882a593Smuzhiyun 		return -EBUSY;
622*4882a593Smuzhiyun 
623*4882a593Smuzhiyun 	if (prq->disabled) {
624*4882a593Smuzhiyun 		priv->pm_on = 0;
625*4882a593Smuzhiyun 	} else {
626*4882a593Smuzhiyun 		switch (prq->flags & IW_POWER_MODE) {
627*4882a593Smuzhiyun 		case IW_POWER_UNICAST_R:
628*4882a593Smuzhiyun 			priv->pm_mcast = 0;
629*4882a593Smuzhiyun 			priv->pm_on = 1;
630*4882a593Smuzhiyun 			break;
631*4882a593Smuzhiyun 		case IW_POWER_ALL_R:
632*4882a593Smuzhiyun 			priv->pm_mcast = 1;
633*4882a593Smuzhiyun 			priv->pm_on = 1;
634*4882a593Smuzhiyun 			break;
635*4882a593Smuzhiyun 		case IW_POWER_ON:
636*4882a593Smuzhiyun 			/* No flags : but we may have a value - Jean II */
637*4882a593Smuzhiyun 			break;
638*4882a593Smuzhiyun 		default:
639*4882a593Smuzhiyun 			err = -EINVAL;
640*4882a593Smuzhiyun 			goto out;
641*4882a593Smuzhiyun 		}
642*4882a593Smuzhiyun 
643*4882a593Smuzhiyun 		if (prq->flags & IW_POWER_TIMEOUT) {
644*4882a593Smuzhiyun 			priv->pm_on = 1;
645*4882a593Smuzhiyun 			priv->pm_timeout = prq->value / 1000;
646*4882a593Smuzhiyun 		}
647*4882a593Smuzhiyun 		if (prq->flags & IW_POWER_PERIOD) {
648*4882a593Smuzhiyun 			priv->pm_on = 1;
649*4882a593Smuzhiyun 			priv->pm_period = prq->value / 1000;
650*4882a593Smuzhiyun 		}
651*4882a593Smuzhiyun 		/* It's valid to not have a value if we are just toggling
652*4882a593Smuzhiyun 		 * the flags... Jean II */
653*4882a593Smuzhiyun 		if (!priv->pm_on) {
654*4882a593Smuzhiyun 			err = -EINVAL;
655*4882a593Smuzhiyun 			goto out;
656*4882a593Smuzhiyun 		}
657*4882a593Smuzhiyun 	}
658*4882a593Smuzhiyun 
659*4882a593Smuzhiyun  out:
660*4882a593Smuzhiyun 	orinoco_unlock(priv, &flags);
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 	return err;
663*4882a593Smuzhiyun }
664*4882a593Smuzhiyun 
orinoco_ioctl_getpower(struct net_device * dev,struct iw_request_info * info,struct iw_param * prq,char * extra)665*4882a593Smuzhiyun static int orinoco_ioctl_getpower(struct net_device *dev,
666*4882a593Smuzhiyun 				  struct iw_request_info *info,
667*4882a593Smuzhiyun 				  struct iw_param *prq,
668*4882a593Smuzhiyun 				  char *extra)
669*4882a593Smuzhiyun {
670*4882a593Smuzhiyun 	struct orinoco_private *priv = ndev_priv(dev);
671*4882a593Smuzhiyun 	struct hermes *hw = &priv->hw;
672*4882a593Smuzhiyun 	int err = 0;
673*4882a593Smuzhiyun 	u16 enable, period, timeout, mcast;
674*4882a593Smuzhiyun 	unsigned long flags;
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun 	if (orinoco_lock(priv, &flags) != 0)
677*4882a593Smuzhiyun 		return -EBUSY;
678*4882a593Smuzhiyun 
679*4882a593Smuzhiyun 	err = hermes_read_wordrec(hw, USER_BAP,
680*4882a593Smuzhiyun 				  HERMES_RID_CNFPMENABLED, &enable);
681*4882a593Smuzhiyun 	if (err)
682*4882a593Smuzhiyun 		goto out;
683*4882a593Smuzhiyun 
684*4882a593Smuzhiyun 	err = hermes_read_wordrec(hw, USER_BAP,
685*4882a593Smuzhiyun 				  HERMES_RID_CNFMAXSLEEPDURATION, &period);
686*4882a593Smuzhiyun 	if (err)
687*4882a593Smuzhiyun 		goto out;
688*4882a593Smuzhiyun 
689*4882a593Smuzhiyun 	err = hermes_read_wordrec(hw, USER_BAP,
690*4882a593Smuzhiyun 				  HERMES_RID_CNFPMHOLDOVERDURATION, &timeout);
691*4882a593Smuzhiyun 	if (err)
692*4882a593Smuzhiyun 		goto out;
693*4882a593Smuzhiyun 
694*4882a593Smuzhiyun 	err = hermes_read_wordrec(hw, USER_BAP,
695*4882a593Smuzhiyun 				  HERMES_RID_CNFMULTICASTRECEIVE, &mcast);
696*4882a593Smuzhiyun 	if (err)
697*4882a593Smuzhiyun 		goto out;
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun 	prq->disabled = !enable;
700*4882a593Smuzhiyun 	/* Note : by default, display the period */
701*4882a593Smuzhiyun 	if ((prq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
702*4882a593Smuzhiyun 		prq->flags = IW_POWER_TIMEOUT;
703*4882a593Smuzhiyun 		prq->value = timeout * 1000;
704*4882a593Smuzhiyun 	} else {
705*4882a593Smuzhiyun 		prq->flags = IW_POWER_PERIOD;
706*4882a593Smuzhiyun 		prq->value = period * 1000;
707*4882a593Smuzhiyun 	}
708*4882a593Smuzhiyun 	if (mcast)
709*4882a593Smuzhiyun 		prq->flags |= IW_POWER_ALL_R;
710*4882a593Smuzhiyun 	else
711*4882a593Smuzhiyun 		prq->flags |= IW_POWER_UNICAST_R;
712*4882a593Smuzhiyun 
713*4882a593Smuzhiyun  out:
714*4882a593Smuzhiyun 	orinoco_unlock(priv, &flags);
715*4882a593Smuzhiyun 
716*4882a593Smuzhiyun 	return err;
717*4882a593Smuzhiyun }
718*4882a593Smuzhiyun 
orinoco_ioctl_set_encodeext(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)719*4882a593Smuzhiyun static int orinoco_ioctl_set_encodeext(struct net_device *dev,
720*4882a593Smuzhiyun 				       struct iw_request_info *info,
721*4882a593Smuzhiyun 				       union iwreq_data *wrqu,
722*4882a593Smuzhiyun 				       char *extra)
723*4882a593Smuzhiyun {
724*4882a593Smuzhiyun 	struct orinoco_private *priv = ndev_priv(dev);
725*4882a593Smuzhiyun 	struct iw_point *encoding = &wrqu->encoding;
726*4882a593Smuzhiyun 	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
727*4882a593Smuzhiyun 	int idx, alg = ext->alg, set_key = 1;
728*4882a593Smuzhiyun 	unsigned long flags;
729*4882a593Smuzhiyun 	int err = -EINVAL;
730*4882a593Smuzhiyun 
731*4882a593Smuzhiyun 	if (orinoco_lock(priv, &flags) != 0)
732*4882a593Smuzhiyun 		return -EBUSY;
733*4882a593Smuzhiyun 
734*4882a593Smuzhiyun 	/* Determine and validate the key index */
735*4882a593Smuzhiyun 	idx = encoding->flags & IW_ENCODE_INDEX;
736*4882a593Smuzhiyun 	if (idx) {
737*4882a593Smuzhiyun 		if ((idx < 1) || (idx > 4))
738*4882a593Smuzhiyun 			goto out;
739*4882a593Smuzhiyun 		idx--;
740*4882a593Smuzhiyun 	} else
741*4882a593Smuzhiyun 		idx = priv->tx_key;
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun 	if (encoding->flags & IW_ENCODE_DISABLED)
744*4882a593Smuzhiyun 		alg = IW_ENCODE_ALG_NONE;
745*4882a593Smuzhiyun 
746*4882a593Smuzhiyun 	if (priv->has_wpa && (alg != IW_ENCODE_ALG_TKIP)) {
747*4882a593Smuzhiyun 		/* Clear any TKIP TX key we had */
748*4882a593Smuzhiyun 		(void) orinoco_clear_tkip_key(priv, priv->tx_key);
749*4882a593Smuzhiyun 	}
750*4882a593Smuzhiyun 
751*4882a593Smuzhiyun 	if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
752*4882a593Smuzhiyun 		priv->tx_key = idx;
753*4882a593Smuzhiyun 		set_key = ((alg == IW_ENCODE_ALG_TKIP) ||
754*4882a593Smuzhiyun 			   (ext->key_len > 0)) ? 1 : 0;
755*4882a593Smuzhiyun 	}
756*4882a593Smuzhiyun 
757*4882a593Smuzhiyun 	if (set_key) {
758*4882a593Smuzhiyun 		/* Set the requested key first */
759*4882a593Smuzhiyun 		switch (alg) {
760*4882a593Smuzhiyun 		case IW_ENCODE_ALG_NONE:
761*4882a593Smuzhiyun 			priv->encode_alg = ORINOCO_ALG_NONE;
762*4882a593Smuzhiyun 			err = orinoco_set_key(priv, idx, ORINOCO_ALG_NONE,
763*4882a593Smuzhiyun 					      NULL, 0, NULL, 0);
764*4882a593Smuzhiyun 			break;
765*4882a593Smuzhiyun 
766*4882a593Smuzhiyun 		case IW_ENCODE_ALG_WEP:
767*4882a593Smuzhiyun 			if (ext->key_len <= 0)
768*4882a593Smuzhiyun 				goto out;
769*4882a593Smuzhiyun 
770*4882a593Smuzhiyun 			priv->encode_alg = ORINOCO_ALG_WEP;
771*4882a593Smuzhiyun 			err = orinoco_set_key(priv, idx, ORINOCO_ALG_WEP,
772*4882a593Smuzhiyun 					      ext->key, ext->key_len, NULL, 0);
773*4882a593Smuzhiyun 			break;
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun 		case IW_ENCODE_ALG_TKIP:
776*4882a593Smuzhiyun 		{
777*4882a593Smuzhiyun 			u8 *tkip_iv = NULL;
778*4882a593Smuzhiyun 
779*4882a593Smuzhiyun 			if (!priv->has_wpa ||
780*4882a593Smuzhiyun 			    (ext->key_len > sizeof(struct orinoco_tkip_key)))
781*4882a593Smuzhiyun 				goto out;
782*4882a593Smuzhiyun 
783*4882a593Smuzhiyun 			priv->encode_alg = ORINOCO_ALG_TKIP;
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun 			if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
786*4882a593Smuzhiyun 				tkip_iv = &ext->rx_seq[0];
787*4882a593Smuzhiyun 
788*4882a593Smuzhiyun 			err = orinoco_set_key(priv, idx, ORINOCO_ALG_TKIP,
789*4882a593Smuzhiyun 					      ext->key, ext->key_len, tkip_iv,
790*4882a593Smuzhiyun 					      ORINOCO_SEQ_LEN);
791*4882a593Smuzhiyun 
792*4882a593Smuzhiyun 			err = __orinoco_hw_set_tkip_key(priv, idx,
793*4882a593Smuzhiyun 				 ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY,
794*4882a593Smuzhiyun 				 priv->keys[idx].key,
795*4882a593Smuzhiyun 				 tkip_iv, ORINOCO_SEQ_LEN, NULL, 0);
796*4882a593Smuzhiyun 			if (err)
797*4882a593Smuzhiyun 				printk(KERN_ERR "%s: Error %d setting TKIP key"
798*4882a593Smuzhiyun 				       "\n", dev->name, err);
799*4882a593Smuzhiyun 
800*4882a593Smuzhiyun 			goto out;
801*4882a593Smuzhiyun 		}
802*4882a593Smuzhiyun 		default:
803*4882a593Smuzhiyun 			goto out;
804*4882a593Smuzhiyun 		}
805*4882a593Smuzhiyun 	}
806*4882a593Smuzhiyun 	err = -EINPROGRESS;
807*4882a593Smuzhiyun  out:
808*4882a593Smuzhiyun 	orinoco_unlock(priv, &flags);
809*4882a593Smuzhiyun 
810*4882a593Smuzhiyun 	return err;
811*4882a593Smuzhiyun }
812*4882a593Smuzhiyun 
orinoco_ioctl_get_encodeext(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)813*4882a593Smuzhiyun static int orinoco_ioctl_get_encodeext(struct net_device *dev,
814*4882a593Smuzhiyun 				       struct iw_request_info *info,
815*4882a593Smuzhiyun 				       union iwreq_data *wrqu,
816*4882a593Smuzhiyun 				       char *extra)
817*4882a593Smuzhiyun {
818*4882a593Smuzhiyun 	struct orinoco_private *priv = ndev_priv(dev);
819*4882a593Smuzhiyun 	struct iw_point *encoding = &wrqu->encoding;
820*4882a593Smuzhiyun 	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
821*4882a593Smuzhiyun 	int idx, max_key_len;
822*4882a593Smuzhiyun 	unsigned long flags;
823*4882a593Smuzhiyun 	int err;
824*4882a593Smuzhiyun 
825*4882a593Smuzhiyun 	if (orinoco_lock(priv, &flags) != 0)
826*4882a593Smuzhiyun 		return -EBUSY;
827*4882a593Smuzhiyun 
828*4882a593Smuzhiyun 	err = -EINVAL;
829*4882a593Smuzhiyun 	max_key_len = encoding->length - sizeof(*ext);
830*4882a593Smuzhiyun 	if (max_key_len < 0)
831*4882a593Smuzhiyun 		goto out;
832*4882a593Smuzhiyun 
833*4882a593Smuzhiyun 	idx = encoding->flags & IW_ENCODE_INDEX;
834*4882a593Smuzhiyun 	if (idx) {
835*4882a593Smuzhiyun 		if ((idx < 1) || (idx > 4))
836*4882a593Smuzhiyun 			goto out;
837*4882a593Smuzhiyun 		idx--;
838*4882a593Smuzhiyun 	} else
839*4882a593Smuzhiyun 		idx = priv->tx_key;
840*4882a593Smuzhiyun 
841*4882a593Smuzhiyun 	encoding->flags = idx + 1;
842*4882a593Smuzhiyun 	memset(ext, 0, sizeof(*ext));
843*4882a593Smuzhiyun 
844*4882a593Smuzhiyun 	switch (priv->encode_alg) {
845*4882a593Smuzhiyun 	case ORINOCO_ALG_NONE:
846*4882a593Smuzhiyun 		ext->alg = IW_ENCODE_ALG_NONE;
847*4882a593Smuzhiyun 		ext->key_len = 0;
848*4882a593Smuzhiyun 		encoding->flags |= IW_ENCODE_DISABLED;
849*4882a593Smuzhiyun 		break;
850*4882a593Smuzhiyun 	case ORINOCO_ALG_WEP:
851*4882a593Smuzhiyun 		ext->alg = IW_ENCODE_ALG_WEP;
852*4882a593Smuzhiyun 		ext->key_len = min(priv->keys[idx].key_len, max_key_len);
853*4882a593Smuzhiyun 		memcpy(ext->key, priv->keys[idx].key, ext->key_len);
854*4882a593Smuzhiyun 		encoding->flags |= IW_ENCODE_ENABLED;
855*4882a593Smuzhiyun 		break;
856*4882a593Smuzhiyun 	case ORINOCO_ALG_TKIP:
857*4882a593Smuzhiyun 		ext->alg = IW_ENCODE_ALG_TKIP;
858*4882a593Smuzhiyun 		ext->key_len = min(priv->keys[idx].key_len, max_key_len);
859*4882a593Smuzhiyun 		memcpy(ext->key, priv->keys[idx].key, ext->key_len);
860*4882a593Smuzhiyun 		encoding->flags |= IW_ENCODE_ENABLED;
861*4882a593Smuzhiyun 		break;
862*4882a593Smuzhiyun 	}
863*4882a593Smuzhiyun 
864*4882a593Smuzhiyun 	err = 0;
865*4882a593Smuzhiyun  out:
866*4882a593Smuzhiyun 	orinoco_unlock(priv, &flags);
867*4882a593Smuzhiyun 
868*4882a593Smuzhiyun 	return err;
869*4882a593Smuzhiyun }
870*4882a593Smuzhiyun 
orinoco_ioctl_set_auth(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)871*4882a593Smuzhiyun static int orinoco_ioctl_set_auth(struct net_device *dev,
872*4882a593Smuzhiyun 				  struct iw_request_info *info,
873*4882a593Smuzhiyun 				  union iwreq_data *wrqu, char *extra)
874*4882a593Smuzhiyun {
875*4882a593Smuzhiyun 	struct orinoco_private *priv = ndev_priv(dev);
876*4882a593Smuzhiyun 	struct hermes *hw = &priv->hw;
877*4882a593Smuzhiyun 	struct iw_param *param = &wrqu->param;
878*4882a593Smuzhiyun 	unsigned long flags;
879*4882a593Smuzhiyun 	int ret = -EINPROGRESS;
880*4882a593Smuzhiyun 
881*4882a593Smuzhiyun 	if (orinoco_lock(priv, &flags) != 0)
882*4882a593Smuzhiyun 		return -EBUSY;
883*4882a593Smuzhiyun 
884*4882a593Smuzhiyun 	switch (param->flags & IW_AUTH_INDEX) {
885*4882a593Smuzhiyun 	case IW_AUTH_WPA_VERSION:
886*4882a593Smuzhiyun 	case IW_AUTH_CIPHER_PAIRWISE:
887*4882a593Smuzhiyun 	case IW_AUTH_CIPHER_GROUP:
888*4882a593Smuzhiyun 	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
889*4882a593Smuzhiyun 	case IW_AUTH_PRIVACY_INVOKED:
890*4882a593Smuzhiyun 	case IW_AUTH_DROP_UNENCRYPTED:
891*4882a593Smuzhiyun 		/*
892*4882a593Smuzhiyun 		 * orinoco does not use these parameters
893*4882a593Smuzhiyun 		 */
894*4882a593Smuzhiyun 		break;
895*4882a593Smuzhiyun 
896*4882a593Smuzhiyun 	case IW_AUTH_MFP:
897*4882a593Smuzhiyun 		/* Management Frame Protection not supported.
898*4882a593Smuzhiyun 		 * Only fail if set to required.
899*4882a593Smuzhiyun 		 */
900*4882a593Smuzhiyun 		if (param->value == IW_AUTH_MFP_REQUIRED)
901*4882a593Smuzhiyun 			ret = -EINVAL;
902*4882a593Smuzhiyun 		break;
903*4882a593Smuzhiyun 
904*4882a593Smuzhiyun 	case IW_AUTH_KEY_MGMT:
905*4882a593Smuzhiyun 		/* wl_lkm implies value 2 == PSK for Hermes I
906*4882a593Smuzhiyun 		 * which ties in with WEXT
907*4882a593Smuzhiyun 		 * no other hints tho :(
908*4882a593Smuzhiyun 		 */
909*4882a593Smuzhiyun 		priv->key_mgmt = param->value;
910*4882a593Smuzhiyun 		break;
911*4882a593Smuzhiyun 
912*4882a593Smuzhiyun 	case IW_AUTH_TKIP_COUNTERMEASURES:
913*4882a593Smuzhiyun 		/* When countermeasures are enabled, shut down the
914*4882a593Smuzhiyun 		 * card; when disabled, re-enable the card. This must
915*4882a593Smuzhiyun 		 * take effect immediately.
916*4882a593Smuzhiyun 		 *
917*4882a593Smuzhiyun 		 * TODO: Make sure that the EAPOL message is getting
918*4882a593Smuzhiyun 		 *       out before card disabled
919*4882a593Smuzhiyun 		 */
920*4882a593Smuzhiyun 		if (param->value) {
921*4882a593Smuzhiyun 			priv->tkip_cm_active = 1;
922*4882a593Smuzhiyun 			ret = hermes_disable_port(hw, 0);
923*4882a593Smuzhiyun 		} else {
924*4882a593Smuzhiyun 			priv->tkip_cm_active = 0;
925*4882a593Smuzhiyun 			ret = hermes_enable_port(hw, 0);
926*4882a593Smuzhiyun 		}
927*4882a593Smuzhiyun 		break;
928*4882a593Smuzhiyun 
929*4882a593Smuzhiyun 	case IW_AUTH_80211_AUTH_ALG:
930*4882a593Smuzhiyun 		if (param->value & IW_AUTH_ALG_SHARED_KEY)
931*4882a593Smuzhiyun 			priv->wep_restrict = 1;
932*4882a593Smuzhiyun 		else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM)
933*4882a593Smuzhiyun 			priv->wep_restrict = 0;
934*4882a593Smuzhiyun 		else
935*4882a593Smuzhiyun 			ret = -EINVAL;
936*4882a593Smuzhiyun 		break;
937*4882a593Smuzhiyun 
938*4882a593Smuzhiyun 	case IW_AUTH_WPA_ENABLED:
939*4882a593Smuzhiyun 		if (priv->has_wpa) {
940*4882a593Smuzhiyun 			priv->wpa_enabled = param->value ? 1 : 0;
941*4882a593Smuzhiyun 		} else {
942*4882a593Smuzhiyun 			if (param->value)
943*4882a593Smuzhiyun 				ret = -EOPNOTSUPP;
944*4882a593Smuzhiyun 			/* else silently accept disable of WPA */
945*4882a593Smuzhiyun 			priv->wpa_enabled = 0;
946*4882a593Smuzhiyun 		}
947*4882a593Smuzhiyun 		break;
948*4882a593Smuzhiyun 
949*4882a593Smuzhiyun 	default:
950*4882a593Smuzhiyun 		ret = -EOPNOTSUPP;
951*4882a593Smuzhiyun 	}
952*4882a593Smuzhiyun 
953*4882a593Smuzhiyun 	orinoco_unlock(priv, &flags);
954*4882a593Smuzhiyun 	return ret;
955*4882a593Smuzhiyun }
956*4882a593Smuzhiyun 
orinoco_ioctl_get_auth(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)957*4882a593Smuzhiyun static int orinoco_ioctl_get_auth(struct net_device *dev,
958*4882a593Smuzhiyun 				  struct iw_request_info *info,
959*4882a593Smuzhiyun 				  union iwreq_data *wrqu, char *extra)
960*4882a593Smuzhiyun {
961*4882a593Smuzhiyun 	struct orinoco_private *priv = ndev_priv(dev);
962*4882a593Smuzhiyun 	struct iw_param *param = &wrqu->param;
963*4882a593Smuzhiyun 	unsigned long flags;
964*4882a593Smuzhiyun 	int ret = 0;
965*4882a593Smuzhiyun 
966*4882a593Smuzhiyun 	if (orinoco_lock(priv, &flags) != 0)
967*4882a593Smuzhiyun 		return -EBUSY;
968*4882a593Smuzhiyun 
969*4882a593Smuzhiyun 	switch (param->flags & IW_AUTH_INDEX) {
970*4882a593Smuzhiyun 	case IW_AUTH_KEY_MGMT:
971*4882a593Smuzhiyun 		param->value = priv->key_mgmt;
972*4882a593Smuzhiyun 		break;
973*4882a593Smuzhiyun 
974*4882a593Smuzhiyun 	case IW_AUTH_TKIP_COUNTERMEASURES:
975*4882a593Smuzhiyun 		param->value = priv->tkip_cm_active;
976*4882a593Smuzhiyun 		break;
977*4882a593Smuzhiyun 
978*4882a593Smuzhiyun 	case IW_AUTH_80211_AUTH_ALG:
979*4882a593Smuzhiyun 		if (priv->wep_restrict)
980*4882a593Smuzhiyun 			param->value = IW_AUTH_ALG_SHARED_KEY;
981*4882a593Smuzhiyun 		else
982*4882a593Smuzhiyun 			param->value = IW_AUTH_ALG_OPEN_SYSTEM;
983*4882a593Smuzhiyun 		break;
984*4882a593Smuzhiyun 
985*4882a593Smuzhiyun 	case IW_AUTH_WPA_ENABLED:
986*4882a593Smuzhiyun 		param->value = priv->wpa_enabled;
987*4882a593Smuzhiyun 		break;
988*4882a593Smuzhiyun 
989*4882a593Smuzhiyun 	default:
990*4882a593Smuzhiyun 		ret = -EOPNOTSUPP;
991*4882a593Smuzhiyun 	}
992*4882a593Smuzhiyun 
993*4882a593Smuzhiyun 	orinoco_unlock(priv, &flags);
994*4882a593Smuzhiyun 	return ret;
995*4882a593Smuzhiyun }
996*4882a593Smuzhiyun 
orinoco_ioctl_set_genie(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)997*4882a593Smuzhiyun static int orinoco_ioctl_set_genie(struct net_device *dev,
998*4882a593Smuzhiyun 				   struct iw_request_info *info,
999*4882a593Smuzhiyun 				   union iwreq_data *wrqu, char *extra)
1000*4882a593Smuzhiyun {
1001*4882a593Smuzhiyun 	struct orinoco_private *priv = ndev_priv(dev);
1002*4882a593Smuzhiyun 	u8 *buf;
1003*4882a593Smuzhiyun 	unsigned long flags;
1004*4882a593Smuzhiyun 
1005*4882a593Smuzhiyun 	/* cut off at IEEE80211_MAX_DATA_LEN */
1006*4882a593Smuzhiyun 	if ((wrqu->data.length > IEEE80211_MAX_DATA_LEN) ||
1007*4882a593Smuzhiyun 	    (wrqu->data.length && (extra == NULL)))
1008*4882a593Smuzhiyun 		return -EINVAL;
1009*4882a593Smuzhiyun 
1010*4882a593Smuzhiyun 	if (wrqu->data.length) {
1011*4882a593Smuzhiyun 		buf = kmemdup(extra, wrqu->data.length, GFP_KERNEL);
1012*4882a593Smuzhiyun 		if (buf == NULL)
1013*4882a593Smuzhiyun 			return -ENOMEM;
1014*4882a593Smuzhiyun 	} else
1015*4882a593Smuzhiyun 		buf = NULL;
1016*4882a593Smuzhiyun 
1017*4882a593Smuzhiyun 	if (orinoco_lock(priv, &flags) != 0) {
1018*4882a593Smuzhiyun 		kfree(buf);
1019*4882a593Smuzhiyun 		return -EBUSY;
1020*4882a593Smuzhiyun 	}
1021*4882a593Smuzhiyun 
1022*4882a593Smuzhiyun 	kfree(priv->wpa_ie);
1023*4882a593Smuzhiyun 	priv->wpa_ie = buf;
1024*4882a593Smuzhiyun 	priv->wpa_ie_len = wrqu->data.length;
1025*4882a593Smuzhiyun 
1026*4882a593Smuzhiyun 	if (priv->wpa_ie) {
1027*4882a593Smuzhiyun 		/* Looks like wl_lkm wants to check the auth alg, and
1028*4882a593Smuzhiyun 		 * somehow pass it to the firmware.
1029*4882a593Smuzhiyun 		 * Instead it just calls the key mgmt rid
1030*4882a593Smuzhiyun 		 *   - we do this in set auth.
1031*4882a593Smuzhiyun 		 */
1032*4882a593Smuzhiyun 	}
1033*4882a593Smuzhiyun 
1034*4882a593Smuzhiyun 	orinoco_unlock(priv, &flags);
1035*4882a593Smuzhiyun 	return 0;
1036*4882a593Smuzhiyun }
1037*4882a593Smuzhiyun 
orinoco_ioctl_get_genie(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1038*4882a593Smuzhiyun static int orinoco_ioctl_get_genie(struct net_device *dev,
1039*4882a593Smuzhiyun 				   struct iw_request_info *info,
1040*4882a593Smuzhiyun 				   union iwreq_data *wrqu, char *extra)
1041*4882a593Smuzhiyun {
1042*4882a593Smuzhiyun 	struct orinoco_private *priv = ndev_priv(dev);
1043*4882a593Smuzhiyun 	unsigned long flags;
1044*4882a593Smuzhiyun 	int err = 0;
1045*4882a593Smuzhiyun 
1046*4882a593Smuzhiyun 	if (orinoco_lock(priv, &flags) != 0)
1047*4882a593Smuzhiyun 		return -EBUSY;
1048*4882a593Smuzhiyun 
1049*4882a593Smuzhiyun 	if ((priv->wpa_ie_len == 0) || (priv->wpa_ie == NULL)) {
1050*4882a593Smuzhiyun 		wrqu->data.length = 0;
1051*4882a593Smuzhiyun 		goto out;
1052*4882a593Smuzhiyun 	}
1053*4882a593Smuzhiyun 
1054*4882a593Smuzhiyun 	if (wrqu->data.length < priv->wpa_ie_len) {
1055*4882a593Smuzhiyun 		err = -E2BIG;
1056*4882a593Smuzhiyun 		goto out;
1057*4882a593Smuzhiyun 	}
1058*4882a593Smuzhiyun 
1059*4882a593Smuzhiyun 	wrqu->data.length = priv->wpa_ie_len;
1060*4882a593Smuzhiyun 	memcpy(extra, priv->wpa_ie, priv->wpa_ie_len);
1061*4882a593Smuzhiyun 
1062*4882a593Smuzhiyun out:
1063*4882a593Smuzhiyun 	orinoco_unlock(priv, &flags);
1064*4882a593Smuzhiyun 	return err;
1065*4882a593Smuzhiyun }
1066*4882a593Smuzhiyun 
orinoco_ioctl_set_mlme(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1067*4882a593Smuzhiyun static int orinoco_ioctl_set_mlme(struct net_device *dev,
1068*4882a593Smuzhiyun 				  struct iw_request_info *info,
1069*4882a593Smuzhiyun 				  union iwreq_data *wrqu, char *extra)
1070*4882a593Smuzhiyun {
1071*4882a593Smuzhiyun 	struct orinoco_private *priv = ndev_priv(dev);
1072*4882a593Smuzhiyun 	struct iw_mlme *mlme = (struct iw_mlme *)extra;
1073*4882a593Smuzhiyun 	unsigned long flags;
1074*4882a593Smuzhiyun 	int ret = 0;
1075*4882a593Smuzhiyun 
1076*4882a593Smuzhiyun 	if (orinoco_lock(priv, &flags) != 0)
1077*4882a593Smuzhiyun 		return -EBUSY;
1078*4882a593Smuzhiyun 
1079*4882a593Smuzhiyun 	switch (mlme->cmd) {
1080*4882a593Smuzhiyun 	case IW_MLME_DEAUTH:
1081*4882a593Smuzhiyun 		/* silently ignore */
1082*4882a593Smuzhiyun 		break;
1083*4882a593Smuzhiyun 
1084*4882a593Smuzhiyun 	case IW_MLME_DISASSOC:
1085*4882a593Smuzhiyun 
1086*4882a593Smuzhiyun 		ret = orinoco_hw_disassociate(priv, mlme->addr.sa_data,
1087*4882a593Smuzhiyun 					      mlme->reason_code);
1088*4882a593Smuzhiyun 		break;
1089*4882a593Smuzhiyun 
1090*4882a593Smuzhiyun 	default:
1091*4882a593Smuzhiyun 		ret = -EOPNOTSUPP;
1092*4882a593Smuzhiyun 	}
1093*4882a593Smuzhiyun 
1094*4882a593Smuzhiyun 	orinoco_unlock(priv, &flags);
1095*4882a593Smuzhiyun 	return ret;
1096*4882a593Smuzhiyun }
1097*4882a593Smuzhiyun 
orinoco_ioctl_reset(struct net_device * dev,struct iw_request_info * info,void * wrqu,char * extra)1098*4882a593Smuzhiyun static int orinoco_ioctl_reset(struct net_device *dev,
1099*4882a593Smuzhiyun 			       struct iw_request_info *info,
1100*4882a593Smuzhiyun 			       void *wrqu,
1101*4882a593Smuzhiyun 			       char *extra)
1102*4882a593Smuzhiyun {
1103*4882a593Smuzhiyun 	struct orinoco_private *priv = ndev_priv(dev);
1104*4882a593Smuzhiyun 
1105*4882a593Smuzhiyun 	if (!capable(CAP_NET_ADMIN))
1106*4882a593Smuzhiyun 		return -EPERM;
1107*4882a593Smuzhiyun 
1108*4882a593Smuzhiyun 	if (info->cmd == (SIOCIWFIRSTPRIV + 0x1)) {
1109*4882a593Smuzhiyun 		printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name);
1110*4882a593Smuzhiyun 
1111*4882a593Smuzhiyun 		/* Firmware reset */
1112*4882a593Smuzhiyun 		orinoco_reset(&priv->reset_work);
1113*4882a593Smuzhiyun 	} else {
1114*4882a593Smuzhiyun 		printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name);
1115*4882a593Smuzhiyun 
1116*4882a593Smuzhiyun 		schedule_work(&priv->reset_work);
1117*4882a593Smuzhiyun 	}
1118*4882a593Smuzhiyun 
1119*4882a593Smuzhiyun 	return 0;
1120*4882a593Smuzhiyun }
1121*4882a593Smuzhiyun 
orinoco_ioctl_setibssport(struct net_device * dev,struct iw_request_info * info,void * wrqu,char * extra)1122*4882a593Smuzhiyun static int orinoco_ioctl_setibssport(struct net_device *dev,
1123*4882a593Smuzhiyun 				     struct iw_request_info *info,
1124*4882a593Smuzhiyun 				     void *wrqu,
1125*4882a593Smuzhiyun 				     char *extra)
1126*4882a593Smuzhiyun 
1127*4882a593Smuzhiyun {
1128*4882a593Smuzhiyun 	struct orinoco_private *priv = ndev_priv(dev);
1129*4882a593Smuzhiyun 	int val = *((int *) extra);
1130*4882a593Smuzhiyun 	unsigned long flags;
1131*4882a593Smuzhiyun 
1132*4882a593Smuzhiyun 	if (orinoco_lock(priv, &flags) != 0)
1133*4882a593Smuzhiyun 		return -EBUSY;
1134*4882a593Smuzhiyun 
1135*4882a593Smuzhiyun 	priv->ibss_port = val;
1136*4882a593Smuzhiyun 
1137*4882a593Smuzhiyun 	/* Actually update the mode we are using */
1138*4882a593Smuzhiyun 	set_port_type(priv);
1139*4882a593Smuzhiyun 
1140*4882a593Smuzhiyun 	orinoco_unlock(priv, &flags);
1141*4882a593Smuzhiyun 	return -EINPROGRESS;		/* Call commit handler */
1142*4882a593Smuzhiyun }
1143*4882a593Smuzhiyun 
orinoco_ioctl_getibssport(struct net_device * dev,struct iw_request_info * info,void * wrqu,char * extra)1144*4882a593Smuzhiyun static int orinoco_ioctl_getibssport(struct net_device *dev,
1145*4882a593Smuzhiyun 				     struct iw_request_info *info,
1146*4882a593Smuzhiyun 				     void *wrqu,
1147*4882a593Smuzhiyun 				     char *extra)
1148*4882a593Smuzhiyun {
1149*4882a593Smuzhiyun 	struct orinoco_private *priv = ndev_priv(dev);
1150*4882a593Smuzhiyun 	int *val = (int *) extra;
1151*4882a593Smuzhiyun 
1152*4882a593Smuzhiyun 	*val = priv->ibss_port;
1153*4882a593Smuzhiyun 	return 0;
1154*4882a593Smuzhiyun }
1155*4882a593Smuzhiyun 
orinoco_ioctl_setport3(struct net_device * dev,struct iw_request_info * info,void * wrqu,char * extra)1156*4882a593Smuzhiyun static int orinoco_ioctl_setport3(struct net_device *dev,
1157*4882a593Smuzhiyun 				  struct iw_request_info *info,
1158*4882a593Smuzhiyun 				  void *wrqu,
1159*4882a593Smuzhiyun 				  char *extra)
1160*4882a593Smuzhiyun {
1161*4882a593Smuzhiyun 	struct orinoco_private *priv = ndev_priv(dev);
1162*4882a593Smuzhiyun 	int val = *((int *) extra);
1163*4882a593Smuzhiyun 	int err = 0;
1164*4882a593Smuzhiyun 	unsigned long flags;
1165*4882a593Smuzhiyun 
1166*4882a593Smuzhiyun 	if (orinoco_lock(priv, &flags) != 0)
1167*4882a593Smuzhiyun 		return -EBUSY;
1168*4882a593Smuzhiyun 
1169*4882a593Smuzhiyun 	switch (val) {
1170*4882a593Smuzhiyun 	case 0: /* Try to do IEEE ad-hoc mode */
1171*4882a593Smuzhiyun 		if (!priv->has_ibss) {
1172*4882a593Smuzhiyun 			err = -EINVAL;
1173*4882a593Smuzhiyun 			break;
1174*4882a593Smuzhiyun 		}
1175*4882a593Smuzhiyun 		priv->prefer_port3 = 0;
1176*4882a593Smuzhiyun 
1177*4882a593Smuzhiyun 		break;
1178*4882a593Smuzhiyun 
1179*4882a593Smuzhiyun 	case 1: /* Try to do Lucent proprietary ad-hoc mode */
1180*4882a593Smuzhiyun 		if (!priv->has_port3) {
1181*4882a593Smuzhiyun 			err = -EINVAL;
1182*4882a593Smuzhiyun 			break;
1183*4882a593Smuzhiyun 		}
1184*4882a593Smuzhiyun 		priv->prefer_port3 = 1;
1185*4882a593Smuzhiyun 		break;
1186*4882a593Smuzhiyun 
1187*4882a593Smuzhiyun 	default:
1188*4882a593Smuzhiyun 		err = -EINVAL;
1189*4882a593Smuzhiyun 	}
1190*4882a593Smuzhiyun 
1191*4882a593Smuzhiyun 	if (!err) {
1192*4882a593Smuzhiyun 		/* Actually update the mode we are using */
1193*4882a593Smuzhiyun 		set_port_type(priv);
1194*4882a593Smuzhiyun 		err = -EINPROGRESS;
1195*4882a593Smuzhiyun 	}
1196*4882a593Smuzhiyun 
1197*4882a593Smuzhiyun 	orinoco_unlock(priv, &flags);
1198*4882a593Smuzhiyun 
1199*4882a593Smuzhiyun 	return err;
1200*4882a593Smuzhiyun }
1201*4882a593Smuzhiyun 
orinoco_ioctl_getport3(struct net_device * dev,struct iw_request_info * info,void * wrqu,char * extra)1202*4882a593Smuzhiyun static int orinoco_ioctl_getport3(struct net_device *dev,
1203*4882a593Smuzhiyun 				  struct iw_request_info *info,
1204*4882a593Smuzhiyun 				  void *wrqu,
1205*4882a593Smuzhiyun 				  char *extra)
1206*4882a593Smuzhiyun {
1207*4882a593Smuzhiyun 	struct orinoco_private *priv = ndev_priv(dev);
1208*4882a593Smuzhiyun 	int *val = (int *) extra;
1209*4882a593Smuzhiyun 
1210*4882a593Smuzhiyun 	*val = priv->prefer_port3;
1211*4882a593Smuzhiyun 	return 0;
1212*4882a593Smuzhiyun }
1213*4882a593Smuzhiyun 
orinoco_ioctl_setpreamble(struct net_device * dev,struct iw_request_info * info,void * wrqu,char * extra)1214*4882a593Smuzhiyun static int orinoco_ioctl_setpreamble(struct net_device *dev,
1215*4882a593Smuzhiyun 				     struct iw_request_info *info,
1216*4882a593Smuzhiyun 				     void *wrqu,
1217*4882a593Smuzhiyun 				     char *extra)
1218*4882a593Smuzhiyun {
1219*4882a593Smuzhiyun 	struct orinoco_private *priv = ndev_priv(dev);
1220*4882a593Smuzhiyun 	unsigned long flags;
1221*4882a593Smuzhiyun 	int val;
1222*4882a593Smuzhiyun 
1223*4882a593Smuzhiyun 	if (!priv->has_preamble)
1224*4882a593Smuzhiyun 		return -EOPNOTSUPP;
1225*4882a593Smuzhiyun 
1226*4882a593Smuzhiyun 	/* 802.11b has recently defined some short preamble.
1227*4882a593Smuzhiyun 	 * Basically, the Phy header has been reduced in size.
1228*4882a593Smuzhiyun 	 * This increase performance, especially at high rates
1229*4882a593Smuzhiyun 	 * (the preamble is transmitted at 1Mb/s), unfortunately
1230*4882a593Smuzhiyun 	 * this give compatibility troubles... - Jean II */
1231*4882a593Smuzhiyun 	val = *((int *) extra);
1232*4882a593Smuzhiyun 
1233*4882a593Smuzhiyun 	if (orinoco_lock(priv, &flags) != 0)
1234*4882a593Smuzhiyun 		return -EBUSY;
1235*4882a593Smuzhiyun 
1236*4882a593Smuzhiyun 	if (val)
1237*4882a593Smuzhiyun 		priv->preamble = 1;
1238*4882a593Smuzhiyun 	else
1239*4882a593Smuzhiyun 		priv->preamble = 0;
1240*4882a593Smuzhiyun 
1241*4882a593Smuzhiyun 	orinoco_unlock(priv, &flags);
1242*4882a593Smuzhiyun 
1243*4882a593Smuzhiyun 	return -EINPROGRESS;		/* Call commit handler */
1244*4882a593Smuzhiyun }
1245*4882a593Smuzhiyun 
orinoco_ioctl_getpreamble(struct net_device * dev,struct iw_request_info * info,void * wrqu,char * extra)1246*4882a593Smuzhiyun static int orinoco_ioctl_getpreamble(struct net_device *dev,
1247*4882a593Smuzhiyun 				     struct iw_request_info *info,
1248*4882a593Smuzhiyun 				     void *wrqu,
1249*4882a593Smuzhiyun 				     char *extra)
1250*4882a593Smuzhiyun {
1251*4882a593Smuzhiyun 	struct orinoco_private *priv = ndev_priv(dev);
1252*4882a593Smuzhiyun 	int *val = (int *) extra;
1253*4882a593Smuzhiyun 
1254*4882a593Smuzhiyun 	if (!priv->has_preamble)
1255*4882a593Smuzhiyun 		return -EOPNOTSUPP;
1256*4882a593Smuzhiyun 
1257*4882a593Smuzhiyun 	*val = priv->preamble;
1258*4882a593Smuzhiyun 	return 0;
1259*4882a593Smuzhiyun }
1260*4882a593Smuzhiyun 
1261*4882a593Smuzhiyun /* ioctl interface to hermes_read_ltv()
1262*4882a593Smuzhiyun  * To use with iwpriv, pass the RID as the token argument, e.g.
1263*4882a593Smuzhiyun  * iwpriv get_rid [0xfc00]
1264*4882a593Smuzhiyun  * At least Wireless Tools 25 is required to use iwpriv.
1265*4882a593Smuzhiyun  * For Wireless Tools 25 and 26 append "dummy" are the end. */
orinoco_ioctl_getrid(struct net_device * dev,struct iw_request_info * info,struct iw_point * data,char * extra)1266*4882a593Smuzhiyun static int orinoco_ioctl_getrid(struct net_device *dev,
1267*4882a593Smuzhiyun 				struct iw_request_info *info,
1268*4882a593Smuzhiyun 				struct iw_point *data,
1269*4882a593Smuzhiyun 				char *extra)
1270*4882a593Smuzhiyun {
1271*4882a593Smuzhiyun 	struct orinoco_private *priv = ndev_priv(dev);
1272*4882a593Smuzhiyun 	struct hermes *hw = &priv->hw;
1273*4882a593Smuzhiyun 	int rid = data->flags;
1274*4882a593Smuzhiyun 	u16 length;
1275*4882a593Smuzhiyun 	int err;
1276*4882a593Smuzhiyun 	unsigned long flags;
1277*4882a593Smuzhiyun 
1278*4882a593Smuzhiyun 	/* It's a "get" function, but we don't want users to access the
1279*4882a593Smuzhiyun 	 * WEP key and other raw firmware data */
1280*4882a593Smuzhiyun 	if (!capable(CAP_NET_ADMIN))
1281*4882a593Smuzhiyun 		return -EPERM;
1282*4882a593Smuzhiyun 
1283*4882a593Smuzhiyun 	if (rid < 0xfc00 || rid > 0xffff)
1284*4882a593Smuzhiyun 		return -EINVAL;
1285*4882a593Smuzhiyun 
1286*4882a593Smuzhiyun 	if (orinoco_lock(priv, &flags) != 0)
1287*4882a593Smuzhiyun 		return -EBUSY;
1288*4882a593Smuzhiyun 
1289*4882a593Smuzhiyun 	err = hw->ops->read_ltv(hw, USER_BAP, rid, MAX_RID_LEN, &length,
1290*4882a593Smuzhiyun 				extra);
1291*4882a593Smuzhiyun 	if (err)
1292*4882a593Smuzhiyun 		goto out;
1293*4882a593Smuzhiyun 
1294*4882a593Smuzhiyun 	data->length = min_t(u16, HERMES_RECLEN_TO_BYTES(length),
1295*4882a593Smuzhiyun 			     MAX_RID_LEN);
1296*4882a593Smuzhiyun 
1297*4882a593Smuzhiyun  out:
1298*4882a593Smuzhiyun 	orinoco_unlock(priv, &flags);
1299*4882a593Smuzhiyun 	return err;
1300*4882a593Smuzhiyun }
1301*4882a593Smuzhiyun 
1302*4882a593Smuzhiyun 
1303*4882a593Smuzhiyun /* Commit handler, called after set operations */
orinoco_ioctl_commit(struct net_device * dev,struct iw_request_info * info,void * wrqu,char * extra)1304*4882a593Smuzhiyun static int orinoco_ioctl_commit(struct net_device *dev,
1305*4882a593Smuzhiyun 				struct iw_request_info *info,
1306*4882a593Smuzhiyun 				void *wrqu,
1307*4882a593Smuzhiyun 				char *extra)
1308*4882a593Smuzhiyun {
1309*4882a593Smuzhiyun 	struct orinoco_private *priv = ndev_priv(dev);
1310*4882a593Smuzhiyun 	unsigned long flags;
1311*4882a593Smuzhiyun 	int err = 0;
1312*4882a593Smuzhiyun 
1313*4882a593Smuzhiyun 	if (!priv->open)
1314*4882a593Smuzhiyun 		return 0;
1315*4882a593Smuzhiyun 
1316*4882a593Smuzhiyun 	if (orinoco_lock(priv, &flags) != 0)
1317*4882a593Smuzhiyun 		return err;
1318*4882a593Smuzhiyun 
1319*4882a593Smuzhiyun 	err = orinoco_commit(priv);
1320*4882a593Smuzhiyun 
1321*4882a593Smuzhiyun 	orinoco_unlock(priv, &flags);
1322*4882a593Smuzhiyun 	return err;
1323*4882a593Smuzhiyun }
1324*4882a593Smuzhiyun 
1325*4882a593Smuzhiyun static const struct iw_priv_args orinoco_privtab[] = {
1326*4882a593Smuzhiyun 	{ SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" },
1327*4882a593Smuzhiyun 	{ SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" },
1328*4882a593Smuzhiyun 	{ SIOCIWFIRSTPRIV + 0x2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1329*4882a593Smuzhiyun 	  0, "set_port3" },
1330*4882a593Smuzhiyun 	{ SIOCIWFIRSTPRIV + 0x3, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1331*4882a593Smuzhiyun 	  "get_port3" },
1332*4882a593Smuzhiyun 	{ SIOCIWFIRSTPRIV + 0x4, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1333*4882a593Smuzhiyun 	  0, "set_preamble" },
1334*4882a593Smuzhiyun 	{ SIOCIWFIRSTPRIV + 0x5, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1335*4882a593Smuzhiyun 	  "get_preamble" },
1336*4882a593Smuzhiyun 	{ SIOCIWFIRSTPRIV + 0x6, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1337*4882a593Smuzhiyun 	  0, "set_ibssport" },
1338*4882a593Smuzhiyun 	{ SIOCIWFIRSTPRIV + 0x7, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1339*4882a593Smuzhiyun 	  "get_ibssport" },
1340*4882a593Smuzhiyun 	{ SIOCIWFIRSTPRIV + 0x9, 0, IW_PRIV_TYPE_BYTE | MAX_RID_LEN,
1341*4882a593Smuzhiyun 	  "get_rid" },
1342*4882a593Smuzhiyun };
1343*4882a593Smuzhiyun 
1344*4882a593Smuzhiyun 
1345*4882a593Smuzhiyun /*
1346*4882a593Smuzhiyun  * Structures to export the Wireless Handlers
1347*4882a593Smuzhiyun  */
1348*4882a593Smuzhiyun 
1349*4882a593Smuzhiyun static const iw_handler	orinoco_handler[] = {
1350*4882a593Smuzhiyun 	IW_HANDLER(SIOCSIWCOMMIT,	(iw_handler)orinoco_ioctl_commit),
1351*4882a593Smuzhiyun 	IW_HANDLER(SIOCGIWNAME,		(iw_handler)cfg80211_wext_giwname),
1352*4882a593Smuzhiyun 	IW_HANDLER(SIOCSIWFREQ,		(iw_handler)orinoco_ioctl_setfreq),
1353*4882a593Smuzhiyun 	IW_HANDLER(SIOCGIWFREQ,		(iw_handler)orinoco_ioctl_getfreq),
1354*4882a593Smuzhiyun 	IW_HANDLER(SIOCSIWMODE,		(iw_handler)cfg80211_wext_siwmode),
1355*4882a593Smuzhiyun 	IW_HANDLER(SIOCGIWMODE,		(iw_handler)cfg80211_wext_giwmode),
1356*4882a593Smuzhiyun 	IW_HANDLER(SIOCSIWSENS,		(iw_handler)orinoco_ioctl_setsens),
1357*4882a593Smuzhiyun 	IW_HANDLER(SIOCGIWSENS,		(iw_handler)orinoco_ioctl_getsens),
1358*4882a593Smuzhiyun 	IW_HANDLER(SIOCGIWRANGE,	(iw_handler)cfg80211_wext_giwrange),
1359*4882a593Smuzhiyun 	IW_HANDLER(SIOCSIWSPY,		iw_handler_set_spy),
1360*4882a593Smuzhiyun 	IW_HANDLER(SIOCGIWSPY,		iw_handler_get_spy),
1361*4882a593Smuzhiyun 	IW_HANDLER(SIOCSIWTHRSPY,	iw_handler_set_thrspy),
1362*4882a593Smuzhiyun 	IW_HANDLER(SIOCGIWTHRSPY,	iw_handler_get_thrspy),
1363*4882a593Smuzhiyun 	IW_HANDLER(SIOCSIWAP,		(iw_handler)orinoco_ioctl_setwap),
1364*4882a593Smuzhiyun 	IW_HANDLER(SIOCGIWAP,		(iw_handler)orinoco_ioctl_getwap),
1365*4882a593Smuzhiyun 	IW_HANDLER(SIOCSIWSCAN,		(iw_handler)cfg80211_wext_siwscan),
1366*4882a593Smuzhiyun 	IW_HANDLER(SIOCGIWSCAN,		(iw_handler)cfg80211_wext_giwscan),
1367*4882a593Smuzhiyun 	IW_HANDLER(SIOCSIWESSID,	(iw_handler)orinoco_ioctl_setessid),
1368*4882a593Smuzhiyun 	IW_HANDLER(SIOCGIWESSID,	(iw_handler)orinoco_ioctl_getessid),
1369*4882a593Smuzhiyun 	IW_HANDLER(SIOCSIWRATE,		(iw_handler)orinoco_ioctl_setrate),
1370*4882a593Smuzhiyun 	IW_HANDLER(SIOCGIWRATE,		(iw_handler)orinoco_ioctl_getrate),
1371*4882a593Smuzhiyun 	IW_HANDLER(SIOCSIWRTS,		(iw_handler)cfg80211_wext_siwrts),
1372*4882a593Smuzhiyun 	IW_HANDLER(SIOCGIWRTS,		(iw_handler)cfg80211_wext_giwrts),
1373*4882a593Smuzhiyun 	IW_HANDLER(SIOCSIWFRAG,		(iw_handler)cfg80211_wext_siwfrag),
1374*4882a593Smuzhiyun 	IW_HANDLER(SIOCGIWFRAG,		(iw_handler)cfg80211_wext_giwfrag),
1375*4882a593Smuzhiyun 	IW_HANDLER(SIOCGIWRETRY,	(iw_handler)cfg80211_wext_giwretry),
1376*4882a593Smuzhiyun 	IW_HANDLER(SIOCSIWENCODE,	(iw_handler)orinoco_ioctl_setiwencode),
1377*4882a593Smuzhiyun 	IW_HANDLER(SIOCGIWENCODE,	(iw_handler)orinoco_ioctl_getiwencode),
1378*4882a593Smuzhiyun 	IW_HANDLER(SIOCSIWPOWER,	(iw_handler)orinoco_ioctl_setpower),
1379*4882a593Smuzhiyun 	IW_HANDLER(SIOCGIWPOWER,	(iw_handler)orinoco_ioctl_getpower),
1380*4882a593Smuzhiyun 	IW_HANDLER(SIOCSIWGENIE,	orinoco_ioctl_set_genie),
1381*4882a593Smuzhiyun 	IW_HANDLER(SIOCGIWGENIE,	orinoco_ioctl_get_genie),
1382*4882a593Smuzhiyun 	IW_HANDLER(SIOCSIWMLME,		orinoco_ioctl_set_mlme),
1383*4882a593Smuzhiyun 	IW_HANDLER(SIOCSIWAUTH,		orinoco_ioctl_set_auth),
1384*4882a593Smuzhiyun 	IW_HANDLER(SIOCGIWAUTH,		orinoco_ioctl_get_auth),
1385*4882a593Smuzhiyun 	IW_HANDLER(SIOCSIWENCODEEXT,	orinoco_ioctl_set_encodeext),
1386*4882a593Smuzhiyun 	IW_HANDLER(SIOCGIWENCODEEXT,	orinoco_ioctl_get_encodeext),
1387*4882a593Smuzhiyun };
1388*4882a593Smuzhiyun 
1389*4882a593Smuzhiyun 
1390*4882a593Smuzhiyun /*
1391*4882a593Smuzhiyun   Added typecasting since we no longer use iwreq_data -- Moustafa
1392*4882a593Smuzhiyun  */
1393*4882a593Smuzhiyun static const iw_handler	orinoco_private_handler[] = {
1394*4882a593Smuzhiyun 	[0] = (iw_handler)orinoco_ioctl_reset,
1395*4882a593Smuzhiyun 	[1] = (iw_handler)orinoco_ioctl_reset,
1396*4882a593Smuzhiyun 	[2] = (iw_handler)orinoco_ioctl_setport3,
1397*4882a593Smuzhiyun 	[3] = (iw_handler)orinoco_ioctl_getport3,
1398*4882a593Smuzhiyun 	[4] = (iw_handler)orinoco_ioctl_setpreamble,
1399*4882a593Smuzhiyun 	[5] = (iw_handler)orinoco_ioctl_getpreamble,
1400*4882a593Smuzhiyun 	[6] = (iw_handler)orinoco_ioctl_setibssport,
1401*4882a593Smuzhiyun 	[7] = (iw_handler)orinoco_ioctl_getibssport,
1402*4882a593Smuzhiyun 	[9] = (iw_handler)orinoco_ioctl_getrid,
1403*4882a593Smuzhiyun };
1404*4882a593Smuzhiyun 
1405*4882a593Smuzhiyun const struct iw_handler_def orinoco_handler_def = {
1406*4882a593Smuzhiyun 	.num_standard = ARRAY_SIZE(orinoco_handler),
1407*4882a593Smuzhiyun 	.num_private = ARRAY_SIZE(orinoco_private_handler),
1408*4882a593Smuzhiyun 	.num_private_args = ARRAY_SIZE(orinoco_privtab),
1409*4882a593Smuzhiyun 	.standard = orinoco_handler,
1410*4882a593Smuzhiyun 	.private = orinoco_private_handler,
1411*4882a593Smuzhiyun 	.private_args = orinoco_privtab,
1412*4882a593Smuzhiyun 	.get_wireless_stats = orinoco_get_wireless_stats,
1413*4882a593Smuzhiyun };
1414