1/*
2   This file contains wireless extension handlers.
3
4   This is part of rtl8180 OpenSource driver.
5   Copyright (C) Andrea Merello 2004-2005  <andrea.merello@gmail.com>
6   Released under the terms of GPL (General Public Licence)
7
8   Parts of this driver are based on the GPL part
9   of the official realtek driver.
10
11   Parts of this driver are based on the rtl8180 driver skeleton
12   from Patric Schenke & Andres Salomon.
13
14   Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver.
15
16   We want to thank the Authors of those projects and the Ndiswrapper
17   project Authors.
18*/
19
20#include <linux/string.h>
21#include "r8192U.h"
22#include "r8192U_hw.h"
23
24#include "dot11d.h"
25#include "r8192U_wx.h"
26
27#define RATE_COUNT 12
28static const u32 rtl8180_rates[] = {1000000, 2000000, 5500000, 11000000,
29	6000000, 9000000, 12000000, 18000000, 24000000, 36000000, 48000000, 54000000};
30
31
32#ifndef ENETDOWN
33#define ENETDOWN 1
34#endif
35
36static int r8192_wx_get_freq(struct net_device *dev,
37			     struct iw_request_info *a,
38			     union iwreq_data *wrqu, char *b)
39{
40	struct r8192_priv *priv = ieee80211_priv(dev);
41
42	return ieee80211_wx_get_freq(priv->ieee80211, a, wrqu, b);
43}
44
45
46static int r8192_wx_get_mode(struct net_device *dev, struct iw_request_info *a,
47			     union iwreq_data *wrqu, char *b)
48{
49	struct r8192_priv *priv = ieee80211_priv(dev);
50
51	return ieee80211_wx_get_mode(priv->ieee80211, a, wrqu, b);
52}
53
54
55
56static int r8192_wx_get_rate(struct net_device *dev,
57			     struct iw_request_info *info,
58			     union iwreq_data *wrqu, char *extra)
59{
60	struct r8192_priv *priv = ieee80211_priv(dev);
61
62	return ieee80211_wx_get_rate(priv->ieee80211, info, wrqu, extra);
63}
64
65
66
67static int r8192_wx_set_rate(struct net_device *dev,
68			     struct iw_request_info *info,
69			     union iwreq_data *wrqu, char *extra)
70{
71	int ret;
72	struct r8192_priv *priv = ieee80211_priv(dev);
73
74	down(&priv->wx_sem);
75
76	ret = ieee80211_wx_set_rate(priv->ieee80211, info, wrqu, extra);
77
78	up(&priv->wx_sem);
79
80	return ret;
81}
82
83
84static int r8192_wx_set_rts(struct net_device *dev,
85			     struct iw_request_info *info,
86			     union iwreq_data *wrqu, char *extra)
87{
88	int ret;
89	struct r8192_priv *priv = ieee80211_priv(dev);
90
91	down(&priv->wx_sem);
92
93	ret = ieee80211_wx_set_rts(priv->ieee80211, info, wrqu, extra);
94
95	up(&priv->wx_sem);
96
97	return ret;
98}
99
100static int r8192_wx_get_rts(struct net_device *dev,
101			     struct iw_request_info *info,
102			     union iwreq_data *wrqu, char *extra)
103{
104	struct r8192_priv *priv = ieee80211_priv(dev);
105
106	return ieee80211_wx_get_rts(priv->ieee80211, info, wrqu, extra);
107}
108
109static int r8192_wx_set_power(struct net_device *dev,
110			     struct iw_request_info *info,
111			     union iwreq_data *wrqu, char *extra)
112{
113	int ret;
114	struct r8192_priv *priv = ieee80211_priv(dev);
115
116	down(&priv->wx_sem);
117
118	ret = ieee80211_wx_set_power(priv->ieee80211, info, wrqu, extra);
119
120	up(&priv->wx_sem);
121
122	return ret;
123}
124
125static int r8192_wx_get_power(struct net_device *dev,
126			     struct iw_request_info *info,
127			     union iwreq_data *wrqu, char *extra)
128{
129	struct r8192_priv *priv = ieee80211_priv(dev);
130
131	return ieee80211_wx_get_power(priv->ieee80211, info, wrqu, extra);
132}
133
134static int r8192_wx_force_reset(struct net_device *dev,
135		struct iw_request_info *info,
136		union iwreq_data *wrqu, char *extra)
137{
138	struct r8192_priv *priv = ieee80211_priv(dev);
139
140	down(&priv->wx_sem);
141
142	netdev_dbg(dev, "%s(): force reset ! extra is %d\n", __func__, *extra);
143	priv->force_reset = *extra;
144	up(&priv->wx_sem);
145	return 0;
146
147}
148
149
150static int r8192_wx_set_rawtx(struct net_device *dev,
151			       struct iw_request_info *info,
152			       union iwreq_data *wrqu, char *extra)
153{
154	struct r8192_priv *priv = ieee80211_priv(dev);
155	int ret;
156
157	down(&priv->wx_sem);
158
159	ret = ieee80211_wx_set_rawtx(priv->ieee80211, info, wrqu, extra);
160
161	up(&priv->wx_sem);
162
163	return ret;
164
165}
166
167static int r8192_wx_set_crcmon(struct net_device *dev,
168			       struct iw_request_info *info,
169			       union iwreq_data *wrqu, char *extra)
170{
171	struct r8192_priv *priv = ieee80211_priv(dev);
172	int *parms = (int *)extra;
173	int enable = (parms[0] > 0);
174
175	down(&priv->wx_sem);
176
177	if (enable)
178		priv->crcmon = 1;
179	else
180		priv->crcmon = 0;
181
182	DMESG("bad CRC in monitor mode are %s",
183	      priv->crcmon ? "accepted" : "rejected");
184
185	up(&priv->wx_sem);
186
187	return 0;
188}
189
190static int r8192_wx_set_mode(struct net_device *dev, struct iw_request_info *a,
191			     union iwreq_data *wrqu, char *b)
192{
193	struct r8192_priv *priv = ieee80211_priv(dev);
194	int ret;
195
196	down(&priv->wx_sem);
197
198	ret = ieee80211_wx_set_mode(priv->ieee80211, a, wrqu, b);
199
200	rtl8192_set_rxconf(dev);
201
202	up(&priv->wx_sem);
203	return ret;
204}
205
206struct  iw_range_with_scan_capa {
207	/* Informative stuff (to choose between different interface) */
208	__u32           throughput;     /* To give an idea... */
209	/* In theory this value should be the maximum benchmarked
210	 * TCP/IP throughput, because with most of these devices the
211	 * bit rate is meaningless (overhead an co) to estimate how
212	 * fast the connection will go and pick the fastest one.
213	 * I suggest people to play with Netperf or any benchmark...
214	 */
215
216	/* NWID (or domain id) */
217	__u32           min_nwid;       /* Minimal NWID we are able to set */
218	__u32           max_nwid;       /* Maximal NWID we are able to set */
219
220	/* Old Frequency (backward compat - moved lower ) */
221	__u16           old_num_channels;
222	__u8            old_num_frequency;
223
224	/* Scan capabilities */
225	__u8            scan_capa;
226};
227static int rtl8180_wx_get_range(struct net_device *dev,
228				struct iw_request_info *info,
229				union iwreq_data *wrqu, char *extra)
230{
231	struct iw_range *range = (struct iw_range *)extra;
232	struct iw_range_with_scan_capa *tmp = (struct iw_range_with_scan_capa *)range;
233	struct r8192_priv *priv = ieee80211_priv(dev);
234	u16 val;
235	int i;
236
237	wrqu->data.length = sizeof(*range);
238	memset(range, 0, sizeof(*range));
239
240	/* Let's try to keep this struct in the same order as in
241	 * linux/include/wireless.h
242	 */
243
244	/* TODO: See what values we can set, and remove the ones we can't
245	 * set, or fill them with some default data.
246	 */
247
248	/* ~5 Mb/s real (802.11b) */
249	range->throughput = 5 * 1000 * 1000;
250
251	/* TODO: Not used in 802.11b? */
252	/* range->min_nwid; */	/* Minimal NWID we are able to set */
253	/* TODO: Not used in 802.11b? */
254	/* range->max_nwid; */	/* Maximal NWID we are able to set */
255
256	/* Old Frequency (backward compat - moved lower ) */
257	/* range->old_num_channels; */
258	/* range->old_num_frequency; */
259	/* range->old_freq[6]; */ /* Filler to keep "version" at the same offset */
260	if (priv->rf_set_sens != NULL)
261		range->sensitivity = priv->max_sens;	/* signal level threshold range */
262
263	range->max_qual.qual = 100;
264	/* TODO: Find real max RSSI and stick here */
265	range->max_qual.level = 0;
266	range->max_qual.noise = -98;
267	range->max_qual.updated = 7; /* Updated all three */
268
269	range->avg_qual.qual = 92; /* > 8% missed beacons is 'bad' */
270	/* TODO: Find real 'good' to 'bad' threshold value for RSSI */
271	range->avg_qual.level = 20 + -98;
272	range->avg_qual.noise = 0;
273	range->avg_qual.updated = 7; /* Updated all three */
274
275	range->num_bitrates = RATE_COUNT;
276
277	for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++)
278		range->bitrate[i] = rtl8180_rates[i];
279
280	range->min_frag = MIN_FRAG_THRESHOLD;
281	range->max_frag = MAX_FRAG_THRESHOLD;
282
283	range->min_pmp = 0;
284	range->max_pmp = 5000000;
285	range->min_pmt = 0;
286	range->max_pmt = 65535*1000;
287	range->pmp_flags = IW_POWER_PERIOD;
288	range->pmt_flags = IW_POWER_TIMEOUT;
289	range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
290
291	range->we_version_compiled = WIRELESS_EXT;
292	range->we_version_source = 16;
293
294	/* range->retry_capa; */	/* What retry options are supported */
295	/* range->retry_flags; */	/* How to decode max/min retry limit */
296	/* range->r_time_flags; */	/* How to decode max/min retry life */
297	/* range->min_retry; */		/* Minimal number of retries */
298	/* range->max_retry; */		/* Maximal number of retries */
299	/* range->min_r_time; */	/* Minimal retry lifetime */
300	/* range->max_r_time; */	/* Maximal retry lifetime */
301
302
303	for (i = 0, val = 0; i < 14; i++) {
304
305		/* Include only legal frequencies for some countries */
306		if ((GET_DOT11D_INFO(priv->ieee80211)->channel_map)[i+1]) {
307			range->freq[val].i = i + 1;
308			range->freq[val].m = ieee80211_wlan_frequencies[i] * 100000;
309			range->freq[val].e = 1;
310			val++;
311		} else {
312			/* FIXME: do we need to set anything for channels */
313			/* we don't use ? */
314		}
315
316		if (val == IW_MAX_FREQUENCIES)
317			break;
318	}
319	range->num_frequency = val;
320	range->num_channels = val;
321	range->enc_capa = IW_ENC_CAPA_WPA|IW_ENC_CAPA_WPA2|
322			  IW_ENC_CAPA_CIPHER_TKIP|IW_ENC_CAPA_CIPHER_CCMP;
323	tmp->scan_capa = 0x01;
324	return 0;
325}
326
327
328static int r8192_wx_set_scan(struct net_device *dev, struct iw_request_info *a,
329			     union iwreq_data *wrqu, char *b)
330{
331	struct r8192_priv *priv = ieee80211_priv(dev);
332	struct ieee80211_device *ieee = priv->ieee80211;
333	int ret = 0;
334
335	if (!priv->up)
336		return -ENETDOWN;
337
338	if (priv->ieee80211->LinkDetectInfo.bBusyTraffic)
339		return -EAGAIN;
340	if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
341		struct iw_scan_req *req = (struct iw_scan_req *)b;
342
343		if (req->essid_len) {
344			ieee->current_network.ssid_len = req->essid_len;
345			memcpy(ieee->current_network.ssid, req->essid, req->essid_len);
346		}
347	}
348
349	down(&priv->wx_sem);
350	if (priv->ieee80211->state != IEEE80211_LINKED) {
351		priv->ieee80211->scanning = 0;
352		ieee80211_softmac_scan_syncro(priv->ieee80211);
353		ret = 0;
354	} else {
355		ret = ieee80211_wx_set_scan(priv->ieee80211, a, wrqu, b);
356	}
357	up(&priv->wx_sem);
358	return ret;
359}
360
361
362static int r8192_wx_get_scan(struct net_device *dev, struct iw_request_info *a,
363			     union iwreq_data *wrqu, char *b)
364{
365
366	int ret;
367	struct r8192_priv *priv = ieee80211_priv(dev);
368
369	if (!priv->up)
370		return -ENETDOWN;
371
372	down(&priv->wx_sem);
373
374	ret = ieee80211_wx_get_scan(priv->ieee80211, a, wrqu, b);
375
376	up(&priv->wx_sem);
377
378	return ret;
379}
380
381static int r8192_wx_set_essid(struct net_device *dev,
382			      struct iw_request_info *a,
383			      union iwreq_data *wrqu, char *b)
384{
385	struct r8192_priv *priv = ieee80211_priv(dev);
386	int ret;
387
388	down(&priv->wx_sem);
389
390	ret = ieee80211_wx_set_essid(priv->ieee80211, a, wrqu, b);
391
392	up(&priv->wx_sem);
393
394	return ret;
395}
396
397
398
399
400static int r8192_wx_get_essid(struct net_device *dev,
401			      struct iw_request_info *a,
402			      union iwreq_data *wrqu, char *b)
403{
404	int ret;
405	struct r8192_priv *priv = ieee80211_priv(dev);
406
407	down(&priv->wx_sem);
408
409	ret = ieee80211_wx_get_essid(priv->ieee80211, a, wrqu, b);
410
411	up(&priv->wx_sem);
412
413	return ret;
414}
415
416
417static int r8192_wx_set_freq(struct net_device *dev, struct iw_request_info *a,
418			     union iwreq_data *wrqu, char *b)
419{
420	int ret;
421	struct r8192_priv *priv = ieee80211_priv(dev);
422
423	down(&priv->wx_sem);
424
425	ret = ieee80211_wx_set_freq(priv->ieee80211, a, wrqu, b);
426
427	up(&priv->wx_sem);
428	return ret;
429}
430
431static int r8192_wx_get_name(struct net_device *dev,
432			     struct iw_request_info *info,
433			     union iwreq_data *wrqu, char *extra)
434{
435	struct r8192_priv *priv = ieee80211_priv(dev);
436
437	return ieee80211_wx_get_name(priv->ieee80211, info, wrqu, extra);
438}
439
440
441static int r8192_wx_set_frag(struct net_device *dev,
442			     struct iw_request_info *info,
443			     union iwreq_data *wrqu, char *extra)
444{
445	struct r8192_priv *priv = ieee80211_priv(dev);
446
447	if (wrqu->frag.disabled)
448		priv->ieee80211->fts = DEFAULT_FRAG_THRESHOLD;
449	else {
450		if (wrqu->frag.value < MIN_FRAG_THRESHOLD ||
451		    wrqu->frag.value > MAX_FRAG_THRESHOLD)
452			return -EINVAL;
453
454		priv->ieee80211->fts = wrqu->frag.value & ~0x1;
455	}
456
457	return 0;
458}
459
460
461static int r8192_wx_get_frag(struct net_device *dev,
462			     struct iw_request_info *info,
463			     union iwreq_data *wrqu, char *extra)
464{
465	struct r8192_priv *priv = ieee80211_priv(dev);
466
467	wrqu->frag.value = priv->ieee80211->fts;
468	wrqu->frag.fixed = 0;	/* no auto select */
469	wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FRAG_THRESHOLD);
470
471	return 0;
472}
473
474
475static int r8192_wx_set_wap(struct net_device *dev,
476			 struct iw_request_info *info,
477			 union iwreq_data *awrq,
478			 char *extra)
479{
480
481	int ret;
482	struct r8192_priv *priv = ieee80211_priv(dev);
483	/* struct sockaddr *temp = (struct sockaddr *)awrq; */
484	down(&priv->wx_sem);
485
486	ret = ieee80211_wx_set_wap(priv->ieee80211, info, awrq, extra);
487
488	up(&priv->wx_sem);
489
490	return ret;
491
492}
493
494
495static int r8192_wx_get_wap(struct net_device *dev,
496			    struct iw_request_info *info,
497			    union iwreq_data *wrqu, char *extra)
498{
499	struct r8192_priv *priv = ieee80211_priv(dev);
500
501	return ieee80211_wx_get_wap(priv->ieee80211, info, wrqu, extra);
502}
503
504
505static int r8192_wx_get_enc(struct net_device *dev,
506			    struct iw_request_info *info,
507			    union iwreq_data *wrqu, char *key)
508{
509	struct r8192_priv *priv = ieee80211_priv(dev);
510
511	return ieee80211_wx_get_encode(priv->ieee80211, info, wrqu, key);
512}
513
514static int r8192_wx_set_enc(struct net_device *dev,
515			    struct iw_request_info *info,
516			    union iwreq_data *wrqu, char *key)
517{
518	struct r8192_priv *priv = ieee80211_priv(dev);
519	struct ieee80211_device *ieee = priv->ieee80211;
520	int ret;
521	u32 hwkey[4] = {0, 0, 0, 0};
522	u8 mask = 0xff;
523	u32 key_idx = 0;
524	u8 zero_addr[4][6] = {	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
525				{0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
526				{0x00, 0x00, 0x00, 0x00, 0x00, 0x02},
527				{0x00, 0x00, 0x00, 0x00, 0x00, 0x03} };
528	int i;
529
530	if (!priv->up)
531		return -ENETDOWN;
532
533	down(&priv->wx_sem);
534
535	RT_TRACE(COMP_SEC, "Setting SW wep key");
536	ret = ieee80211_wx_set_encode(priv->ieee80211, info, wrqu, key);
537
538	up(&priv->wx_sem);
539
540
541
542	/* sometimes, the length is zero while we do not type key value */
543	if (wrqu->encoding.length != 0) {
544
545		for (i = 0; i < 4; i++) {
546			hwkey[i] |=  key[4*i+0]&mask;
547			if (i == 1 && (4*i+1) == wrqu->encoding.length)
548				mask = 0x00;
549			if (i == 3 && (4*i+1) == wrqu->encoding.length)
550				mask = 0x00;
551			hwkey[i] |= (key[4*i+1]&mask)<<8;
552			hwkey[i] |= (key[4*i+2]&mask)<<16;
553			hwkey[i] |= (key[4*i+3]&mask)<<24;
554		}
555
556		#define CONF_WEP40  0x4
557		#define CONF_WEP104 0x14
558
559		switch (wrqu->encoding.flags & IW_ENCODE_INDEX) {
560		case 0:
561			key_idx = ieee->tx_keyidx;
562			break;
563		case 1:
564			key_idx = 0;
565			break;
566		case 2:
567			key_idx = 1;
568			break;
569		case 3:
570			key_idx = 2;
571			break;
572		case 4:
573			key_idx	= 3;
574			break;
575		default:
576			break;
577		}
578
579		if (wrqu->encoding.length == 0x5) {
580				ieee->pairwise_key_type = KEY_TYPE_WEP40;
581			EnableHWSecurityConfig8192(dev);
582
583			setKey(dev,
584				key_idx,                /* EntryNo */
585				key_idx,                /* KeyIndex */
586				KEY_TYPE_WEP40,         /* KeyType */
587				zero_addr[key_idx],
588				0,                      /* DefaultKey */
589				hwkey);                 /* KeyContent */
590
591		}
592
593		else if (wrqu->encoding.length == 0xd) {
594				ieee->pairwise_key_type = KEY_TYPE_WEP104;
595				EnableHWSecurityConfig8192(dev);
596
597			setKey(dev,
598				key_idx,                /* EntryNo */
599				key_idx,                /* KeyIndex */
600				KEY_TYPE_WEP104,        /* KeyType */
601				zero_addr[key_idx],
602				0,                      /* DefaultKey */
603				hwkey);                 /* KeyContent */
604
605		} else {
606			printk("wrong type in WEP, not WEP40 and WEP104\n");
607		}
608
609	}
610
611	return ret;
612}
613
614
615static int r8192_wx_set_scan_type(struct net_device *dev, struct iw_request_info *aa,
616					union iwreq_data *wrqu, char *p)
617{
618
619	struct r8192_priv *priv = ieee80211_priv(dev);
620	int *parms = (int *)p;
621	int mode = parms[0];
622
623	priv->ieee80211->active_scan = mode;
624
625	return 1;
626}
627
628
629
630static int r8192_wx_set_retry(struct net_device *dev,
631				struct iw_request_info *info,
632				union iwreq_data *wrqu, char *extra)
633{
634	struct r8192_priv *priv = ieee80211_priv(dev);
635	int err = 0;
636
637	down(&priv->wx_sem);
638
639	if (wrqu->retry.flags & IW_RETRY_LIFETIME ||
640	    wrqu->retry.disabled){
641		err = -EINVAL;
642		goto exit;
643	}
644	if (!(wrqu->retry.flags & IW_RETRY_LIMIT)) {
645		err = -EINVAL;
646		goto exit;
647	}
648
649	if (wrqu->retry.value > R8180_MAX_RETRY) {
650		err = -EINVAL;
651		goto exit;
652	}
653	if (wrqu->retry.flags & IW_RETRY_MAX) {
654		priv->retry_rts = wrqu->retry.value;
655		DMESG("Setting retry for RTS/CTS data to %d", wrqu->retry.value);
656
657	} else {
658		priv->retry_data = wrqu->retry.value;
659		DMESG("Setting retry for non RTS/CTS data to %d", wrqu->retry.value);
660	}
661
662	/* FIXME !
663	 * We might try to write directly the TX config register
664	 * or to restart just the (R)TX process.
665	 * I'm unsure if whole reset is really needed
666	 */
667
668	rtl8192_commit(dev);
669exit:
670	up(&priv->wx_sem);
671
672	return err;
673}
674
675static int r8192_wx_get_retry(struct net_device *dev,
676				struct iw_request_info *info,
677				union iwreq_data *wrqu, char *extra)
678{
679	struct r8192_priv *priv = ieee80211_priv(dev);
680
681
682	wrqu->retry.disabled = 0; /* can't be disabled */
683
684	if ((wrqu->retry.flags & IW_RETRY_TYPE) ==
685	    IW_RETRY_LIFETIME)
686		return -EINVAL;
687
688	if (wrqu->retry.flags & IW_RETRY_MAX) {
689		wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
690		wrqu->retry.value = priv->retry_rts;
691	} else {
692		wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN;
693		wrqu->retry.value = priv->retry_data;
694	}
695
696
697	return 0;
698}
699
700static int r8192_wx_get_sens(struct net_device *dev,
701				struct iw_request_info *info,
702				union iwreq_data *wrqu, char *extra)
703{
704	struct r8192_priv *priv = ieee80211_priv(dev);
705
706	if (priv->rf_set_sens == NULL)
707		return -1; /* we have not this support for this radio */
708	wrqu->sens.value = priv->sens;
709	return 0;
710}
711
712
713static int r8192_wx_set_sens(struct net_device *dev,
714				struct iw_request_info *info,
715				union iwreq_data *wrqu, char *extra)
716{
717
718	struct r8192_priv *priv = ieee80211_priv(dev);
719	short err = 0;
720
721	down(&priv->wx_sem);
722	if (priv->rf_set_sens == NULL) {
723		err = -1; /* we have not this support for this radio */
724		goto exit;
725	}
726	if (priv->rf_set_sens(dev, wrqu->sens.value) == 0)
727		priv->sens = wrqu->sens.value;
728	else
729		err = -EINVAL;
730
731exit:
732	up(&priv->wx_sem);
733
734	return err;
735}
736
737/* hw security need to reorganized. */
738static int r8192_wx_set_enc_ext(struct net_device *dev,
739					struct iw_request_info *info,
740					union iwreq_data *wrqu, char *extra)
741{
742	int ret = 0;
743	struct r8192_priv *priv = ieee80211_priv(dev);
744	struct ieee80211_device *ieee = priv->ieee80211;
745
746
747	down(&priv->wx_sem);
748	ret = ieee80211_wx_set_encode_ext(priv->ieee80211, info, wrqu, extra);
749
750	{
751		u8 broadcast_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
752		u8 zero[6] = {0};
753		u32 key[4] = {0};
754		struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
755		struct iw_point *encoding = &wrqu->encoding;
756		u8 idx = 0, alg = 0, group = 0;
757
758		if ((encoding->flags & IW_ENCODE_DISABLED) || ext->alg == IW_ENCODE_ALG_NONE)
759			/* none is not allowed to use hwsec WB 2008.07.01 */
760			goto end_hw_sec;
761
762		/* as IW_ENCODE_ALG_CCMP is defined to be 3 and KEY_TYPE_CCMP is defined to 4; */
763		alg =  (ext->alg == IW_ENCODE_ALG_CCMP)?KEY_TYPE_CCMP:ext->alg;
764		idx = encoding->flags & IW_ENCODE_INDEX;
765		if (idx)
766			idx--;
767		group = ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY;
768
769		if ((!group) || (IW_MODE_ADHOC == ieee->iw_mode) || (alg ==  KEY_TYPE_WEP40)) {
770			if ((ext->key_len == 13) && (alg == KEY_TYPE_WEP40))
771				alg = KEY_TYPE_WEP104;
772			ieee->pairwise_key_type = alg;
773			EnableHWSecurityConfig8192(dev);
774		}
775		memcpy((u8 *)key, ext->key, 16); /* we only get 16 bytes key.why? WB 2008.7.1 */
776
777		if ((alg & KEY_TYPE_WEP40) && (ieee->auth_mode != 2)) {
778
779			setKey(dev,
780					idx,	/* EntryNao */
781					idx,	/* KeyIndex */
782					alg,	/* KeyType */
783					zero,	/* MacAddr */
784					0,	/* DefaultKey */
785					key);	/* KeyContent */
786		} else if (group) {
787			ieee->group_key_type = alg;
788			setKey(dev,
789					idx,	/* EntryNo */
790					idx,	/* KeyIndex */
791					alg,	/* KeyType */
792					broadcast_addr,	/* MacAddr */
793					0,		/* DefaultKey */
794					key);		/* KeyContent */
795		} else {	/* pairwise key */
796			setKey(dev,
797					4,	/* EntryNo */
798					idx,	/* KeyIndex */
799					alg,	/* KeyType */
800					(u8 *)ieee->ap_mac_addr,/* MacAddr */
801					0,			/* DefaultKey */
802					key);			/* KeyContent */
803		}
804
805
806	}
807
808end_hw_sec:
809
810	up(&priv->wx_sem);
811	return ret;
812
813}
814static int r8192_wx_set_auth(struct net_device *dev,
815					struct iw_request_info *info,
816					union iwreq_data *data, char *extra)
817{
818	int ret = 0;
819	struct r8192_priv *priv = ieee80211_priv(dev);
820
821	down(&priv->wx_sem);
822	ret = ieee80211_wx_set_auth(priv->ieee80211, info, &(data->param), extra);
823	up(&priv->wx_sem);
824	return ret;
825}
826
827static int r8192_wx_set_mlme(struct net_device *dev,
828					struct iw_request_info *info,
829					union iwreq_data *wrqu, char *extra)
830{
831
832	int ret = 0;
833	struct r8192_priv *priv = ieee80211_priv(dev);
834
835	down(&priv->wx_sem);
836	ret = ieee80211_wx_set_mlme(priv->ieee80211, info, wrqu, extra);
837
838	up(&priv->wx_sem);
839	return ret;
840}
841
842static int r8192_wx_set_gen_ie(struct net_device *dev,
843					struct iw_request_info *info,
844					union iwreq_data *data, char *extra)
845{
846	int ret = 0;
847	struct r8192_priv *priv = ieee80211_priv(dev);
848
849	down(&priv->wx_sem);
850	ret = ieee80211_wx_set_gen_ie(priv->ieee80211, extra, data->data.length);
851	up(&priv->wx_sem);
852	return ret;
853
854
855}
856
857static int dummy(struct net_device *dev, struct iw_request_info *a,
858		 union iwreq_data *wrqu, char *b)
859{
860	return -1;
861}
862
863
864static iw_handler r8192_wx_handlers[] = {
865	NULL,                     /* SIOCSIWCOMMIT */
866	r8192_wx_get_name,	  /* SIOCGIWNAME */
867	dummy,                    /* SIOCSIWNWID */
868	dummy,                    /* SIOCGIWNWID */
869	r8192_wx_set_freq,        /* SIOCSIWFREQ */
870	r8192_wx_get_freq,        /* SIOCGIWFREQ */
871	r8192_wx_set_mode,        /* SIOCSIWMODE */
872	r8192_wx_get_mode,        /* SIOCGIWMODE */
873	r8192_wx_set_sens,        /* SIOCSIWSENS */
874	r8192_wx_get_sens,        /* SIOCGIWSENS */
875	NULL,                     /* SIOCSIWRANGE */
876	rtl8180_wx_get_range,	  /* SIOCGIWRANGE */
877	NULL,                     /* SIOCSIWPRIV */
878	NULL,                     /* SIOCGIWPRIV */
879	NULL,                     /* SIOCSIWSTATS */
880	NULL,                     /* SIOCGIWSTATS */
881	dummy,                    /* SIOCSIWSPY */
882	dummy,                    /* SIOCGIWSPY */
883	NULL,                     /* SIOCGIWTHRSPY */
884	NULL,                     /* SIOCWIWTHRSPY */
885	r8192_wx_set_wap,	  /* SIOCSIWAP */
886	r8192_wx_get_wap,         /* SIOCGIWAP */
887	r8192_wx_set_mlme,                     /* MLME-- */
888	dummy,                     /* SIOCGIWAPLIST -- deprecated */
889	r8192_wx_set_scan,        /* SIOCSIWSCAN */
890	r8192_wx_get_scan,        /* SIOCGIWSCAN */
891	r8192_wx_set_essid,       /* SIOCSIWESSID */
892	r8192_wx_get_essid,       /* SIOCGIWESSID */
893	dummy,                    /* SIOCSIWNICKN */
894	dummy,                    /* SIOCGIWNICKN */
895	NULL,                     /* -- hole -- */
896	NULL,                     /* -- hole -- */
897	r8192_wx_set_rate,        /* SIOCSIWRATE */
898	r8192_wx_get_rate,        /* SIOCGIWRATE */
899	r8192_wx_set_rts,                    /* SIOCSIWRTS */
900	r8192_wx_get_rts,                    /* SIOCGIWRTS */
901	r8192_wx_set_frag,        /* SIOCSIWFRAG */
902	r8192_wx_get_frag,        /* SIOCGIWFRAG */
903	dummy,                    /* SIOCSIWTXPOW */
904	dummy,                    /* SIOCGIWTXPOW */
905	r8192_wx_set_retry,       /* SIOCSIWRETRY */
906	r8192_wx_get_retry,       /* SIOCGIWRETRY */
907	r8192_wx_set_enc,         /* SIOCSIWENCODE */
908	r8192_wx_get_enc,         /* SIOCGIWENCODE */
909	r8192_wx_set_power,                    /* SIOCSIWPOWER */
910	r8192_wx_get_power,                    /* SIOCGIWPOWER */
911	NULL,			/*---hole---*/
912	NULL,			/*---hole---*/
913	r8192_wx_set_gen_ie, /* NULL, */		/* SIOCSIWGENIE */
914	NULL,			/* SIOCSIWGENIE */
915
916	r8192_wx_set_auth,/* NULL, */			/* SIOCSIWAUTH */
917	NULL,/* r8192_wx_get_auth, */ /* NULL, */	/* SIOCSIWAUTH */
918	r8192_wx_set_enc_ext,			/* SIOCSIWENCODEEXT */
919	NULL,/* r8192_wx_get_enc_ext, *//* NULL, */			/* SIOCSIWENCODEEXT */
920	NULL,			/* SIOCSIWPMKSA */
921	NULL,			 /*---hole---*/
922
923};
924
925
926static const struct iw_priv_args r8192_private_args[] = {
927
928	{
929		SIOCIWFIRSTPRIV + 0x0,
930		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "badcrc"
931	},
932
933	{
934		SIOCIWFIRSTPRIV + 0x1,
935		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "activescan"
936
937	},
938	{
939		SIOCIWFIRSTPRIV + 0x2,
940		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "rawtx"
941	},
942	{
943		SIOCIWFIRSTPRIV + 0x3,
944		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "forcereset"
945
946	}
947
948};
949
950
951static iw_handler r8192_private_handler[] = {
952	r8192_wx_set_crcmon,
953	r8192_wx_set_scan_type,
954	r8192_wx_set_rawtx,
955	r8192_wx_force_reset,
956};
957
958struct iw_statistics *r8192_get_wireless_stats(struct net_device *dev)
959{
960	struct r8192_priv *priv = ieee80211_priv(dev);
961	struct ieee80211_device *ieee = priv->ieee80211;
962	struct iw_statistics *wstats = &priv->wstats;
963	int tmp_level = 0;
964	int tmp_qual = 0;
965	int tmp_noise = 0;
966
967	if (ieee->state < IEEE80211_LINKED) {
968		wstats->qual.qual = 0;
969		wstats->qual.level = 0;
970		wstats->qual.noise = 0;
971		wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
972		return wstats;
973	}
974
975	tmp_level = (&ieee->current_network)->stats.rssi;
976	tmp_qual = (&ieee->current_network)->stats.signal;
977	tmp_noise = (&ieee->current_network)->stats.noise;
978
979	wstats->qual.level = tmp_level;
980	wstats->qual.qual = tmp_qual;
981	wstats->qual.noise = tmp_noise;
982	wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
983	return wstats;
984}
985
986
987struct iw_handler_def  r8192_wx_handlers_def = {
988	.standard = r8192_wx_handlers,
989	.num_standard = ARRAY_SIZE(r8192_wx_handlers),
990	.private = r8192_private_handler,
991	.num_private = ARRAY_SIZE(r8192_private_handler),
992	.num_private_args = sizeof(r8192_private_args) / sizeof(struct iw_priv_args),
993	.get_wireless_stats = r8192_get_wireless_stats,
994	.private_args = (struct iw_priv_args *)r8192_private_args,
995};
996