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