r8192U_wx.c revision 2808a02332b8249324a78565421abf1059b4be9d
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
520	//u32 TargetContent;
521	u32 hwkey[4] = {0, 0, 0, 0};
522	u8 mask = 0xff;
523	u32 key_idx = 0;
524	//u8 broadcast_addr[6] ={	0xff,0xff,0xff,0xff,0xff,0xff};
525	u8 zero_addr[4][6] = {	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
526				{0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
527				{0x00, 0x00, 0x00, 0x00, 0x00, 0x02},
528				{0x00, 0x00, 0x00, 0x00, 0x00, 0x03} };
529	int i;
530
531	if (!priv->up)
532		return -ENETDOWN;
533
534	down(&priv->wx_sem);
535
536	RT_TRACE(COMP_SEC, "Setting SW wep key");
537	ret = ieee80211_wx_set_encode(priv->ieee80211, info, wrqu, key);
538
539	up(&priv->wx_sem);
540
541
542
543	//sometimes, the length is zero while we do not type key value
544	if (wrqu->encoding.length != 0) {
545
546		for (i = 0; i < 4; i++) {
547			hwkey[i] |=  key[4*i+0]&mask;
548			if (i == 1 && (4*i+1) == wrqu->encoding.length)
549				mask = 0x00;
550			if (i == 3 && (4*i+1) == wrqu->encoding.length)
551				mask = 0x00;
552			hwkey[i] |= (key[4*i+1]&mask)<<8;
553			hwkey[i] |= (key[4*i+2]&mask)<<16;
554			hwkey[i] |= (key[4*i+3]&mask)<<24;
555		}
556
557		#define CONF_WEP40  0x4
558		#define CONF_WEP104 0x14
559
560		switch (wrqu->encoding.flags & IW_ENCODE_INDEX) {
561		case 0:
562			key_idx = ieee->tx_keyidx;
563			break;
564		case 1:
565			key_idx = 0;
566			break;
567		case 2:
568			key_idx = 1;
569			break;
570		case 3:
571			key_idx = 2;
572			break;
573		case 4:
574			key_idx	= 3;
575			break;
576		default:
577			break;
578		}
579
580		if (wrqu->encoding.length == 0x5) {
581				ieee->pairwise_key_type = KEY_TYPE_WEP40;
582			EnableHWSecurityConfig8192(dev);
583
584			setKey(dev,
585				key_idx,                //EntryNo
586				key_idx,                //KeyIndex
587				KEY_TYPE_WEP40,         //KeyType
588				zero_addr[key_idx],
589				0,                      //DefaultKey
590				hwkey);                 //KeyContent
591
592		}
593
594		else if (wrqu->encoding.length == 0xd) {
595				ieee->pairwise_key_type = KEY_TYPE_WEP104;
596				EnableHWSecurityConfig8192(dev);
597
598			setKey(dev,
599				key_idx,                //EntryNo
600				key_idx,                //KeyIndex
601				KEY_TYPE_WEP104,        //KeyType
602				zero_addr[key_idx],
603				0,                      //DefaultKey
604				hwkey);                 //KeyContent
605
606		} else {
607			printk("wrong type in WEP, not WEP40 and WEP104\n");
608		}
609
610	}
611
612	return ret;
613}
614
615
616static int r8192_wx_set_scan_type(struct net_device *dev, struct iw_request_info *aa,
617					union iwreq_data *wrqu, char *p)
618{
619
620	struct r8192_priv *priv = ieee80211_priv(dev);
621	int *parms = (int *)p;
622	int mode = parms[0];
623
624	priv->ieee80211->active_scan = mode;
625
626	return 1;
627}
628
629
630
631static int r8192_wx_set_retry(struct net_device *dev,
632				struct iw_request_info *info,
633				union iwreq_data *wrqu, char *extra)
634{
635	struct r8192_priv *priv = ieee80211_priv(dev);
636	int err = 0;
637
638	down(&priv->wx_sem);
639
640	if (wrqu->retry.flags & IW_RETRY_LIFETIME ||
641	    wrqu->retry.disabled){
642		err = -EINVAL;
643		goto exit;
644	}
645	if (!(wrqu->retry.flags & IW_RETRY_LIMIT)) {
646		err = -EINVAL;
647		goto exit;
648	}
649
650	if (wrqu->retry.value > R8180_MAX_RETRY) {
651		err = -EINVAL;
652		goto exit;
653	}
654	if (wrqu->retry.flags & IW_RETRY_MAX) {
655		priv->retry_rts = wrqu->retry.value;
656		DMESG("Setting retry for RTS/CTS data to %d", wrqu->retry.value);
657
658	} else {
659		priv->retry_data = wrqu->retry.value;
660		DMESG("Setting retry for non RTS/CTS data to %d", wrqu->retry.value);
661	}
662
663	/* FIXME !
664	 * We might try to write directly the TX config register
665	 * or to restart just the (R)TX process.
666	 * I'm unsure if whole reset is really needed
667	 */
668
669	rtl8192_commit(dev);
670	/*
671	if(priv->up){
672		rtl8180_rtx_disable(dev);
673		rtl8180_rx_enable(dev);
674		rtl8180_tx_enable(dev);
675
676	}
677	*/
678exit:
679	up(&priv->wx_sem);
680
681	return err;
682}
683
684static int r8192_wx_get_retry(struct net_device *dev,
685				struct iw_request_info *info,
686				union iwreq_data *wrqu, char *extra)
687{
688	struct r8192_priv *priv = ieee80211_priv(dev);
689
690
691	wrqu->retry.disabled = 0; /* can't be disabled */
692
693	if ((wrqu->retry.flags & IW_RETRY_TYPE) ==
694	    IW_RETRY_LIFETIME)
695		return -EINVAL;
696
697	if (wrqu->retry.flags & IW_RETRY_MAX) {
698		wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
699		wrqu->retry.value = priv->retry_rts;
700	} else {
701		wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN;
702		wrqu->retry.value = priv->retry_data;
703	}
704
705
706	return 0;
707}
708
709static int r8192_wx_get_sens(struct net_device *dev,
710				struct iw_request_info *info,
711				union iwreq_data *wrqu, char *extra)
712{
713	struct r8192_priv *priv = ieee80211_priv(dev);
714	if (priv->rf_set_sens == NULL)
715		return -1; /* we have not this support for this radio */
716	wrqu->sens.value = priv->sens;
717	return 0;
718}
719
720
721static int r8192_wx_set_sens(struct net_device *dev,
722				struct iw_request_info *info,
723				union iwreq_data *wrqu, char *extra)
724{
725
726	struct r8192_priv *priv = ieee80211_priv(dev);
727
728	short err = 0;
729	down(&priv->wx_sem);
730	if (priv->rf_set_sens == NULL) {
731		err = -1; /* we have not this support for this radio */
732		goto exit;
733	}
734	if (priv->rf_set_sens(dev, wrqu->sens.value) == 0)
735		priv->sens = wrqu->sens.value;
736	else
737		err = -EINVAL;
738
739exit:
740	up(&priv->wx_sem);
741
742	return err;
743}
744
745//hw security need to reorganized.
746static int r8192_wx_set_enc_ext(struct net_device *dev,
747					struct iw_request_info *info,
748					union iwreq_data *wrqu, char *extra)
749{
750	int ret = 0;
751	struct r8192_priv *priv = ieee80211_priv(dev);
752	struct ieee80211_device *ieee = priv->ieee80211;
753
754
755	down(&priv->wx_sem);
756	ret = ieee80211_wx_set_encode_ext(priv->ieee80211, info, wrqu, extra);
757
758	{
759		u8 broadcast_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
760		u8 zero[6] = {0};
761		u32 key[4] = {0};
762		struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
763		struct iw_point *encoding = &wrqu->encoding;
764		u8 idx = 0, alg = 0, group = 0;
765		if ((encoding->flags & IW_ENCODE_DISABLED) || ext->alg == IW_ENCODE_ALG_NONE)
766			//none is not allowed to use hwsec WB 2008.07.01
767			goto end_hw_sec;
768
769		// as IW_ENCODE_ALG_CCMP is defined to be 3 and KEY_TYPE_CCMP is defined to 4;
770		alg =  (ext->alg == IW_ENCODE_ALG_CCMP)?KEY_TYPE_CCMP:ext->alg;
771		idx = encoding->flags & IW_ENCODE_INDEX;
772		if (idx)
773			idx--;
774		group = ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY;
775
776		if ((!group) || (IW_MODE_ADHOC == ieee->iw_mode) || (alg ==  KEY_TYPE_WEP40)) {
777			if ((ext->key_len == 13) && (alg == KEY_TYPE_WEP40))
778				alg = KEY_TYPE_WEP104;
779			ieee->pairwise_key_type = alg;
780			EnableHWSecurityConfig8192(dev);
781		}
782		memcpy((u8 *)key, ext->key, 16); //we only get 16 bytes key.why? WB 2008.7.1
783
784		if ((alg & KEY_TYPE_WEP40) && (ieee->auth_mode != 2)) {
785
786			setKey(dev,
787					idx,//EntryNo
788					idx, //KeyIndex
789					alg,  //KeyType
790					zero, //MacAddr
791					0,              //DefaultKey
792					key);           //KeyContent
793		} else if (group) {
794			ieee->group_key_type = alg;
795			setKey(dev,
796					idx,//EntryNo
797					idx, //KeyIndex
798					alg,  //KeyType
799					broadcast_addr, //MacAddr
800					0,              //DefaultKey
801					key);           //KeyContent
802		} else {//pairwise key
803			setKey(dev,
804					4,//EntryNo
805					idx, //KeyIndex
806					alg,  //KeyType
807					(u8 *)ieee->ap_mac_addr, //MacAddr
808					0,              //DefaultKey
809					key);           //KeyContent
810		}
811
812
813	}
814
815end_hw_sec:
816
817	up(&priv->wx_sem);
818	return ret;
819
820}
821static int r8192_wx_set_auth(struct net_device *dev,
822					struct iw_request_info *info,
823					union iwreq_data *data, char *extra)
824{
825	int ret = 0;
826	struct r8192_priv *priv = ieee80211_priv(dev);
827	down(&priv->wx_sem);
828	ret = ieee80211_wx_set_auth(priv->ieee80211, info, &(data->param), extra);
829	up(&priv->wx_sem);
830	return ret;
831}
832
833static int r8192_wx_set_mlme(struct net_device *dev,
834					struct iw_request_info *info,
835					union iwreq_data *wrqu, char *extra)
836{
837
838	int ret = 0;
839	struct r8192_priv *priv = ieee80211_priv(dev);
840	down(&priv->wx_sem);
841	ret = ieee80211_wx_set_mlme(priv->ieee80211, info, wrqu, extra);
842
843	up(&priv->wx_sem);
844	return ret;
845}
846
847static int r8192_wx_set_gen_ie(struct net_device *dev,
848					struct iw_request_info *info,
849					union iwreq_data *data, char *extra)
850{
851	int ret = 0;
852	struct r8192_priv *priv = ieee80211_priv(dev);
853	down(&priv->wx_sem);
854	ret = ieee80211_wx_set_gen_ie(priv->ieee80211, extra, data->data.length);
855	up(&priv->wx_sem);
856	return ret;
857
858
859}
860
861static int dummy(struct net_device *dev, struct iw_request_info *a,
862		 union iwreq_data *wrqu, char *b)
863{
864	return -1;
865}
866
867
868static iw_handler r8192_wx_handlers[] = {
869	NULL,                     /* SIOCSIWCOMMIT */
870	r8192_wx_get_name,	  /* SIOCGIWNAME */
871	dummy,                    /* SIOCSIWNWID */
872	dummy,                    /* SIOCGIWNWID */
873	r8192_wx_set_freq,        /* SIOCSIWFREQ */
874	r8192_wx_get_freq,        /* SIOCGIWFREQ */
875	r8192_wx_set_mode,        /* SIOCSIWMODE */
876	r8192_wx_get_mode,        /* SIOCGIWMODE */
877	r8192_wx_set_sens,        /* SIOCSIWSENS */
878	r8192_wx_get_sens,        /* SIOCGIWSENS */
879	NULL,                     /* SIOCSIWRANGE */
880	rtl8180_wx_get_range,	  /* SIOCGIWRANGE */
881	NULL,                     /* SIOCSIWPRIV */
882	NULL,                     /* SIOCGIWPRIV */
883	NULL,                     /* SIOCSIWSTATS */
884	NULL,                     /* SIOCGIWSTATS */
885	dummy,                    /* SIOCSIWSPY */
886	dummy,                    /* SIOCGIWSPY */
887	NULL,                     /* SIOCGIWTHRSPY */
888	NULL,                     /* SIOCWIWTHRSPY */
889	r8192_wx_set_wap,	  /* SIOCSIWAP */
890	r8192_wx_get_wap,         /* SIOCGIWAP */
891	r8192_wx_set_mlme,                     /* MLME-- */
892	dummy,                     /* SIOCGIWAPLIST -- deprecated */
893	r8192_wx_set_scan,        /* SIOCSIWSCAN */
894	r8192_wx_get_scan,        /* SIOCGIWSCAN */
895	r8192_wx_set_essid,       /* SIOCSIWESSID */
896	r8192_wx_get_essid,       /* SIOCGIWESSID */
897	dummy,                    /* SIOCSIWNICKN */
898	dummy,                    /* SIOCGIWNICKN */
899	NULL,                     /* -- hole -- */
900	NULL,                     /* -- hole -- */
901	r8192_wx_set_rate,        /* SIOCSIWRATE */
902	r8192_wx_get_rate,        /* SIOCGIWRATE */
903	r8192_wx_set_rts,                    /* SIOCSIWRTS */
904	r8192_wx_get_rts,                    /* SIOCGIWRTS */
905	r8192_wx_set_frag,        /* SIOCSIWFRAG */
906	r8192_wx_get_frag,        /* SIOCGIWFRAG */
907	dummy,                    /* SIOCSIWTXPOW */
908	dummy,                    /* SIOCGIWTXPOW */
909	r8192_wx_set_retry,       /* SIOCSIWRETRY */
910	r8192_wx_get_retry,       /* SIOCGIWRETRY */
911	r8192_wx_set_enc,         /* SIOCSIWENCODE */
912	r8192_wx_get_enc,         /* SIOCGIWENCODE */
913	r8192_wx_set_power,                    /* SIOCSIWPOWER */
914	r8192_wx_get_power,                    /* SIOCGIWPOWER */
915	NULL,			/*---hole---*/
916	NULL,			/*---hole---*/
917	r8192_wx_set_gen_ie,//NULL,			/* SIOCSIWGENIE */
918	NULL,			/* SIOCSIWGENIE */
919
920	r8192_wx_set_auth,//NULL,			/* SIOCSIWAUTH */
921	NULL,//r8192_wx_get_auth,//NULL,			/* SIOCSIWAUTH */
922	r8192_wx_set_enc_ext,			/* SIOCSIWENCODEEXT */
923	NULL,//r8192_wx_get_enc_ext,//NULL,			/* SIOCSIWENCODEEXT */
924	NULL,			/* SIOCSIWPMKSA */
925	NULL,			 /*---hole---*/
926
927};
928
929
930static const struct iw_priv_args r8192_private_args[] = {
931
932	{
933		SIOCIWFIRSTPRIV + 0x0,
934		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "badcrc"
935	},
936
937	{
938		SIOCIWFIRSTPRIV + 0x1,
939		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "activescan"
940
941	},
942	{
943		SIOCIWFIRSTPRIV + 0x2,
944		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "rawtx"
945	},
946	{
947		SIOCIWFIRSTPRIV + 0x3,
948		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "forcereset"
949
950	}
951
952};
953
954
955static iw_handler r8192_private_handler[] = {
956//	r8192_wx_set_monitor,  /* SIOCIWFIRSTPRIV */
957	r8192_wx_set_crcmon,   /*SIOCIWSECONDPRIV*/
958//	r8192_wx_set_forceassociate,
959//	r8192_wx_set_beaconinterval,
960//	r8192_wx_set_monitor_type,
961	r8192_wx_set_scan_type,
962	r8192_wx_set_rawtx,
963	//r8192_wx_null,
964	r8192_wx_force_reset,
965};
966
967struct iw_statistics *r8192_get_wireless_stats(struct net_device *dev)
968{
969	struct r8192_priv *priv = ieee80211_priv(dev);
970	struct ieee80211_device *ieee = priv->ieee80211;
971	struct iw_statistics *wstats = &priv->wstats;
972	int tmp_level = 0;
973	int tmp_qual = 0;
974	int tmp_noise = 0;
975	if (ieee->state < IEEE80211_LINKED) {
976		wstats->qual.qual = 0;
977		wstats->qual.level = 0;
978		wstats->qual.noise = 0;
979		wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
980		return wstats;
981	}
982
983	tmp_level = (&ieee->current_network)->stats.rssi;
984	tmp_qual = (&ieee->current_network)->stats.signal;
985	tmp_noise = (&ieee->current_network)->stats.noise;
986
987	wstats->qual.level = tmp_level;
988	wstats->qual.qual = tmp_qual;
989	wstats->qual.noise = tmp_noise;
990	wstats->qual.updated = IW_QUAL_ALL_UPDATED| IW_QUAL_DBM;
991	return wstats;
992}
993
994
995struct iw_handler_def  r8192_wx_handlers_def = {
996	.standard = r8192_wx_handlers,
997	.num_standard = ARRAY_SIZE(r8192_wx_handlers),
998	.private = r8192_private_handler,
999	.num_private = ARRAY_SIZE(r8192_private_handler),
1000	.num_private_args = sizeof(r8192_private_args) / sizeof(struct iw_priv_args),
1001	.get_wireless_stats = r8192_get_wireless_stats,
1002	.private_args = (struct iw_priv_args *)r8192_private_args,
1003};
1004