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