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