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