ieee80211_wx.c revision 5a0e3ad6af8660be21ca98a971cd00f331318c05
1/******************************************************************************
2
3  Copyright(c) 2004 Intel Corporation. All rights reserved.
4
5  Portions of this file are based on the WEP enablement code provided by the
6  Host AP project hostap-drivers v0.1.3
7  Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
8  <jkmaline@cc.hut.fi>
9  Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
10
11  This program is free software; you can redistribute it and/or modify it
12  under the terms of version 2 of the GNU General Public License as
13  published by the Free Software Foundation.
14
15  This program is distributed in the hope that it will be useful, but WITHOUT
16  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
18  more details.
19
20  You should have received a copy of the GNU General Public License along with
21  this program; if not, write to the Free Software Foundation, Inc., 59
22  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23
24  The full GNU General Public License is included in this distribution in the
25  file called LICENSE.
26
27  Contact Information:
28  James P. Ketrenos <ipw2100-admin@linux.intel.com>
29  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
30
31******************************************************************************/
32#include <linux/wireless.h>
33#include <linux/version.h>
34#include <linux/kmod.h>
35#include <linux/slab.h>
36#include <linux/module.h>
37
38#include "ieee80211.h"
39struct modes_unit {
40	char *mode_string;
41	int mode_size;
42};
43struct modes_unit ieee80211_modes[] = {
44	{"a",1},
45	{"b",1},
46	{"g",1},
47	{"?",1},
48	{"N-24G",5},
49	{"N-5G",4},
50};
51
52#define iwe_stream_add_event_rsl iwe_stream_add_event
53
54#define MAX_CUSTOM_LEN 64
55static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee,
56					   char *start, char *stop,
57					   struct ieee80211_network *network,
58					   struct iw_request_info *info)
59{
60	char custom[MAX_CUSTOM_LEN];
61	char proto_name[IFNAMSIZ];
62	char *pname = proto_name;
63	char *p;
64	struct iw_event iwe;
65	int i, j;
66	u16 max_rate, rate;
67	static u8	EWC11NHTCap[] = {0x00, 0x90, 0x4c, 0x33};
68
69	/* First entry *MUST* be the AP MAC address */
70	iwe.cmd = SIOCGIWAP;
71	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
72	memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
73	start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_ADDR_LEN);
74	/* Remaining entries will be displayed in the order we provide them */
75
76	/* Add the ESSID */
77	iwe.cmd = SIOCGIWESSID;
78	iwe.u.data.flags = 1;
79//	if (network->flags & NETWORK_EMPTY_ESSID) {
80	if (network->ssid_len == 0) {
81		iwe.u.data.length = sizeof("<hidden>");
82		start = iwe_stream_add_point(info, start, stop, &iwe, "<hidden>");
83	} else {
84		iwe.u.data.length = min(network->ssid_len, (u8)32);
85		start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid);
86	}
87	/* Add the protocol name */
88	iwe.cmd = SIOCGIWNAME;
89	for(i=0; i<(sizeof(ieee80211_modes)/sizeof(ieee80211_modes[0])); i++) {
90		if(network->mode&(1<<i)) {
91			sprintf(pname,ieee80211_modes[i].mode_string,ieee80211_modes[i].mode_size);
92			pname +=ieee80211_modes[i].mode_size;
93		}
94	}
95	*pname = '\0';
96	snprintf(iwe.u.name, IFNAMSIZ, "IEEE802.11%s", proto_name);
97	start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_CHAR_LEN);
98	/* Add mode */
99	iwe.cmd = SIOCGIWMODE;
100	if (network->capability &
101	    (WLAN_CAPABILITY_BSS | WLAN_CAPABILITY_IBSS)) {
102		if (network->capability & WLAN_CAPABILITY_BSS)
103			iwe.u.mode = IW_MODE_MASTER;
104		else
105			iwe.u.mode = IW_MODE_ADHOC;
106		start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_UINT_LEN);
107	}
108
109	/* Add frequency/channel */
110	iwe.cmd = SIOCGIWFREQ;
111/*	iwe.u.freq.m = ieee80211_frequency(network->channel, network->mode);
112	iwe.u.freq.e = 3; */
113	iwe.u.freq.m = network->channel;
114	iwe.u.freq.e = 0;
115	iwe.u.freq.i = 0;
116	start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_FREQ_LEN);
117	/* Add encryption capability */
118	iwe.cmd = SIOCGIWENCODE;
119	if (network->capability & WLAN_CAPABILITY_PRIVACY)
120		iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
121	else
122		iwe.u.data.flags = IW_ENCODE_DISABLED;
123	iwe.u.data.length = 0;
124	start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid);
125	/* Add basic and extended rates */
126	max_rate = 0;
127	p = custom;
128	p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): ");
129	for (i = 0, j = 0; i < network->rates_len; ) {
130		if (j < network->rates_ex_len &&
131		    ((network->rates_ex[j] & 0x7F) <
132		     (network->rates[i] & 0x7F)))
133			rate = network->rates_ex[j++] & 0x7F;
134		else
135			rate = network->rates[i++] & 0x7F;
136		if (rate > max_rate)
137			max_rate = rate;
138		p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
139			      "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
140	}
141	for (; j < network->rates_ex_len; j++) {
142		rate = network->rates_ex[j] & 0x7F;
143		p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
144			      "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
145		if (rate > max_rate)
146			max_rate = rate;
147	}
148
149	if (network->mode >= IEEE_N_24G)//add N rate here;
150	{
151		PHT_CAPABILITY_ELE ht_cap = NULL;
152		bool is40M = false, isShortGI = false;
153		u8 max_mcs = 0;
154		if (!memcmp(network->bssht.bdHTCapBuf, EWC11NHTCap, 4))
155			ht_cap = (PHT_CAPABILITY_ELE)&network->bssht.bdHTCapBuf[4];
156		else
157			ht_cap = (PHT_CAPABILITY_ELE)&network->bssht.bdHTCapBuf[0];
158		is40M = (ht_cap->ChlWidth)?1:0;
159		isShortGI = (ht_cap->ChlWidth)?
160						((ht_cap->ShortGI40Mhz)?1:0):
161						((ht_cap->ShortGI20Mhz)?1:0);
162
163		max_mcs = HTGetHighestMCSRate(ieee, ht_cap->MCS, MCS_FILTER_ALL);
164		rate = MCS_DATA_RATE[is40M][isShortGI][max_mcs&0x7f];
165		if (rate > max_rate)
166			max_rate = rate;
167	}
168	iwe.cmd = SIOCGIWRATE;
169	iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
170	iwe.u.bitrate.value = max_rate * 500000;
171	start = iwe_stream_add_event_rsl(info, start, stop, &iwe,
172				     IW_EV_PARAM_LEN);
173	iwe.cmd = IWEVCUSTOM;
174	iwe.u.data.length = p - custom;
175	if (iwe.u.data.length)
176	start = iwe_stream_add_point(info, start, stop, &iwe, custom);
177	/* Add quality statistics */
178	/* TODO: Fix these values... */
179	iwe.cmd = IWEVQUAL;
180	iwe.u.qual.qual = network->stats.signal;
181	iwe.u.qual.level = network->stats.rssi;
182	iwe.u.qual.noise = network->stats.noise;
183	iwe.u.qual.updated = network->stats.mask & IEEE80211_STATMASK_WEMASK;
184	if (!(network->stats.mask & IEEE80211_STATMASK_RSSI))
185		iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
186	if (!(network->stats.mask & IEEE80211_STATMASK_NOISE))
187		iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
188	if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL))
189		iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID;
190	iwe.u.qual.updated = 7;
191	start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_QUAL_LEN);
192	iwe.cmd = IWEVCUSTOM;
193	p = custom;
194
195	iwe.u.data.length = p - custom;
196	if (iwe.u.data.length)
197	    start = iwe_stream_add_point(info, start, stop, &iwe, custom);
198#if (WIRELESS_EXT < 18)
199	if (ieee->wpa_enabled && network->wpa_ie_len){
200		char buf[MAX_WPA_IE_LEN * 2 + 30];
201	//	printk("WPA IE\n");
202		u8 *p = buf;
203		p += sprintf(p, "wpa_ie=");
204		for (i = 0; i < network->wpa_ie_len; i++) {
205			p += sprintf(p, "%02x", network->wpa_ie[i]);
206		}
207
208		memset(&iwe, 0, sizeof(iwe));
209		iwe.cmd = IWEVCUSTOM;
210		iwe.u.data.length = strlen(buf);
211		start = iwe_stream_add_point(info, start, stop, &iwe, buf);
212	}
213
214	if (ieee->wpa_enabled && network->rsn_ie_len){
215		char buf[MAX_WPA_IE_LEN * 2 + 30];
216
217		u8 *p = buf;
218		p += sprintf(p, "rsn_ie=");
219		for (i = 0; i < network->rsn_ie_len; i++) {
220			p += sprintf(p, "%02x", network->rsn_ie[i]);
221		}
222
223		memset(&iwe, 0, sizeof(iwe));
224		iwe.cmd = IWEVCUSTOM;
225		iwe.u.data.length = strlen(buf);
226		start = iwe_stream_add_point(info, start, stop, &iwe, buf);
227	}
228#else
229	memset(&iwe, 0, sizeof(iwe));
230	if (network->wpa_ie_len)
231	{
232		char buf[MAX_WPA_IE_LEN];
233		memcpy(buf, network->wpa_ie, network->wpa_ie_len);
234		iwe.cmd = IWEVGENIE;
235		iwe.u.data.length = network->wpa_ie_len;
236		start = iwe_stream_add_point(info, start, stop, &iwe, buf);
237	}
238	memset(&iwe, 0, sizeof(iwe));
239	if (network->rsn_ie_len)
240	{
241		char buf[MAX_WPA_IE_LEN];
242		memcpy(buf, network->rsn_ie, network->rsn_ie_len);
243		iwe.cmd = IWEVGENIE;
244		iwe.u.data.length = network->rsn_ie_len;
245		start = iwe_stream_add_point(info, start, stop, &iwe, buf);
246	}
247#endif
248
249
250	/* Add EXTRA: Age to display seconds since last beacon/probe response
251	 * for given network. */
252	iwe.cmd = IWEVCUSTOM;
253	p = custom;
254	p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
255		      " Last beacon: %lums ago", (jiffies - network->last_scanned) / (HZ / 100));
256	iwe.u.data.length = p - custom;
257	if (iwe.u.data.length)
258	    start = iwe_stream_add_point(info, start, stop, &iwe, custom);
259
260	return start;
261}
262
263int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
264			  struct iw_request_info *info,
265			  union iwreq_data *wrqu, char *extra)
266{
267	struct ieee80211_network *network;
268	unsigned long flags;
269
270	char *ev = extra;
271//	char *stop = ev + IW_SCAN_MAX_DATA;
272	char *stop = ev + wrqu->data.length;//IW_SCAN_MAX_DATA;
273	//char *stop = ev + IW_SCAN_MAX_DATA;
274	int i = 0;
275	int err = 0;
276	IEEE80211_DEBUG_WX("Getting scan\n");
277	down(&ieee->wx_sem);
278	spin_lock_irqsave(&ieee->lock, flags);
279
280	list_for_each_entry(network, &ieee->network_list, list) {
281		i++;
282		if((stop-ev)<200)
283		{
284			err = -E2BIG;
285			break;
286												}
287		if (ieee->scan_age == 0 ||
288		    time_after(network->last_scanned + ieee->scan_age, jiffies))
289			ev = rtl819x_translate_scan(ieee, ev, stop, network, info);
290		else
291			IEEE80211_DEBUG_SCAN(
292				"Not showing network '%s ("
293				"%pM)' due to age (%lums).\n",
294				escape_essid(network->ssid,
295					     network->ssid_len),
296				network->bssid,
297				(jiffies - network->last_scanned) / (HZ / 100));
298	}
299
300	spin_unlock_irqrestore(&ieee->lock, flags);
301	up(&ieee->wx_sem);
302	wrqu->data.length = ev -  extra;
303	wrqu->data.flags = 0;
304
305	IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
306
307	return err;
308}
309
310int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
311			    struct iw_request_info *info,
312			    union iwreq_data *wrqu, char *keybuf)
313{
314	struct iw_point *erq = &(wrqu->encoding);
315	struct net_device *dev = ieee->dev;
316	struct ieee80211_security sec = {
317		.flags = 0
318	};
319	int i, key, key_provided, len;
320	struct ieee80211_crypt_data **crypt;
321
322	IEEE80211_DEBUG_WX("SET_ENCODE\n");
323
324	key = erq->flags & IW_ENCODE_INDEX;
325	if (key) {
326		if (key > WEP_KEYS)
327			return -EINVAL;
328		key--;
329		key_provided = 1;
330	} else {
331		key_provided = 0;
332		key = ieee->tx_keyidx;
333	}
334
335	IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
336			   "provided" : "default");
337	crypt = &ieee->crypt[key];
338
339	if (erq->flags & IW_ENCODE_DISABLED) {
340		if (key_provided && *crypt) {
341			IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n",
342					   key);
343			ieee80211_crypt_delayed_deinit(ieee, crypt);
344		} else
345			IEEE80211_DEBUG_WX("Disabling encryption.\n");
346
347		/* Check all the keys to see if any are still configured,
348		 * and if no key index was provided, de-init them all */
349		for (i = 0; i < WEP_KEYS; i++) {
350			if (ieee->crypt[i] != NULL) {
351				if (key_provided)
352					break;
353				ieee80211_crypt_delayed_deinit(
354					ieee, &ieee->crypt[i]);
355			}
356		}
357
358		if (i == WEP_KEYS) {
359			sec.enabled = 0;
360			sec.level = SEC_LEVEL_0;
361			sec.flags |= SEC_ENABLED | SEC_LEVEL;
362		}
363
364		goto done;
365	}
366
367
368
369	sec.enabled = 1;
370	sec.flags |= SEC_ENABLED;
371
372	if (*crypt != NULL && (*crypt)->ops != NULL &&
373	    strcmp((*crypt)->ops->name, "WEP") != 0) {
374		/* changing to use WEP; deinit previously used algorithm
375		 * on this key */
376		ieee80211_crypt_delayed_deinit(ieee, crypt);
377	}
378
379	if (*crypt == NULL) {
380		struct ieee80211_crypt_data *new_crypt;
381
382		/* take WEP into use */
383		new_crypt = kmalloc(sizeof(struct ieee80211_crypt_data),
384				    GFP_KERNEL);
385		if (new_crypt == NULL)
386			return -ENOMEM;
387		memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
388		new_crypt->ops = ieee80211_get_crypto_ops("WEP");
389		if (!new_crypt->ops) {
390			request_module("ieee80211_crypt_wep");
391			new_crypt->ops = ieee80211_get_crypto_ops("WEP");
392		}
393		if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
394			new_crypt->priv = new_crypt->ops->init(key);
395
396		if (!new_crypt->ops || !new_crypt->priv) {
397			kfree(new_crypt);
398			new_crypt = NULL;
399
400			printk(KERN_WARNING "%s: could not initialize WEP: "
401			       "load module ieee80211_crypt_wep\n",
402			       dev->name);
403			return -EOPNOTSUPP;
404		}
405		*crypt = new_crypt;
406	}
407
408	/* If a new key was provided, set it up */
409	if (erq->length > 0) {
410		len = erq->length <= 5 ? 5 : 13;
411		memcpy(sec.keys[key], keybuf, erq->length);
412		if (len > erq->length)
413			memset(sec.keys[key] + erq->length, 0,
414			       len - erq->length);
415		IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
416				   key, escape_essid(sec.keys[key], len),
417				   erq->length, len);
418		sec.key_sizes[key] = len;
419		(*crypt)->ops->set_key(sec.keys[key], len, NULL,
420				       (*crypt)->priv);
421		sec.flags |= (1 << key);
422		/* This ensures a key will be activated if no key is
423		 * explicitely set */
424		if (key == sec.active_key)
425			sec.flags |= SEC_ACTIVE_KEY;
426		ieee->tx_keyidx = key;
427
428	} else {
429		len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
430					     NULL, (*crypt)->priv);
431		if (len == 0) {
432			/* Set a default key of all 0 */
433			printk("Setting key %d to all zero.\n",
434					   key);
435
436			IEEE80211_DEBUG_WX("Setting key %d to all zero.\n",
437					   key);
438			memset(sec.keys[key], 0, 13);
439			(*crypt)->ops->set_key(sec.keys[key], 13, NULL,
440					       (*crypt)->priv);
441			sec.key_sizes[key] = 13;
442			sec.flags |= (1 << key);
443		}
444
445		/* No key data - just set the default TX key index */
446		if (key_provided) {
447			IEEE80211_DEBUG_WX(
448				"Setting key %d to default Tx key.\n", key);
449			ieee->tx_keyidx = key;
450			sec.active_key = key;
451			sec.flags |= SEC_ACTIVE_KEY;
452		}
453	}
454
455 done:
456	ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
457	ieee->auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
458	sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
459	sec.flags |= SEC_AUTH_MODE;
460	IEEE80211_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ?
461			   "OPEN" : "SHARED KEY");
462
463	/* For now we just support WEP, so only set that security level...
464	 * TODO: When WPA is added this is one place that needs to change */
465	sec.flags |= SEC_LEVEL;
466	sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
467
468	if (ieee->set_security)
469		ieee->set_security(dev, &sec);
470
471	/* Do not reset port if card is in Managed mode since resetting will
472	 * generate new IEEE 802.11 authentication which may end up in looping
473	 * with IEEE 802.1X.  If your hardware requires a reset after WEP
474	 * configuration (for example... Prism2), implement the reset_port in
475	 * the callbacks structures used to initialize the 802.11 stack. */
476	if (ieee->reset_on_keychange &&
477	    ieee->iw_mode != IW_MODE_INFRA &&
478	    ieee->reset_port && ieee->reset_port(dev)) {
479		printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
480		return -EINVAL;
481	}
482	return 0;
483}
484
485int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
486			    struct iw_request_info *info,
487			    union iwreq_data *wrqu, char *keybuf)
488{
489	struct iw_point *erq = &(wrqu->encoding);
490	int len, key;
491	struct ieee80211_crypt_data *crypt;
492
493	IEEE80211_DEBUG_WX("GET_ENCODE\n");
494
495	if(ieee->iw_mode == IW_MODE_MONITOR)
496		return -1;
497
498	key = erq->flags & IW_ENCODE_INDEX;
499	if (key) {
500		if (key > WEP_KEYS)
501			return -EINVAL;
502		key--;
503	} else
504		key = ieee->tx_keyidx;
505
506	crypt = ieee->crypt[key];
507	erq->flags = key + 1;
508
509	if (crypt == NULL || crypt->ops == NULL) {
510		erq->length = 0;
511		erq->flags |= IW_ENCODE_DISABLED;
512		return 0;
513	}
514	len = crypt->ops->get_key(keybuf, SCM_KEY_LEN, NULL, crypt->priv);
515	erq->length = (len >= 0 ? len : 0);
516
517	erq->flags |= IW_ENCODE_ENABLED;
518
519	if (ieee->open_wep)
520		erq->flags |= IW_ENCODE_OPEN;
521	else
522		erq->flags |= IW_ENCODE_RESTRICTED;
523
524	return 0;
525}
526#if (WIRELESS_EXT >= 18)
527int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
528			       struct iw_request_info *info,
529			       union iwreq_data *wrqu, char *extra)
530{
531	int ret = 0;
532	struct net_device *dev = ieee->dev;
533	struct iw_point *encoding = &wrqu->encoding;
534	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
535	int i, idx;
536	int group_key = 0;
537	const char *alg, *module;
538	struct ieee80211_crypto_ops *ops;
539	struct ieee80211_crypt_data **crypt;
540
541	struct ieee80211_security sec = {
542		.flags = 0,
543	};
544	//printk("======>encoding flag:%x,ext flag:%x, ext alg:%d\n", encoding->flags,ext->ext_flags, ext->alg);
545	idx = encoding->flags & IW_ENCODE_INDEX;
546	if (idx) {
547		if (idx < 1 || idx > WEP_KEYS)
548			return -EINVAL;
549		idx--;
550	} else
551		idx = ieee->tx_keyidx;
552
553	if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
554
555		crypt = &ieee->crypt[idx];
556
557		group_key = 1;
558	} else {
559		/* some Cisco APs use idx>0 for unicast in dynamic WEP */
560		//printk("not group key, flags:%x, ext->alg:%d\n", ext->ext_flags, ext->alg);
561		if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
562			return -EINVAL;
563		if (ieee->iw_mode == IW_MODE_INFRA)
564
565			crypt = &ieee->crypt[idx];
566
567		else
568			return -EINVAL;
569	}
570
571	sec.flags |= SEC_ENABLED;// | SEC_ENCRYPT;
572	if ((encoding->flags & IW_ENCODE_DISABLED) ||
573	    ext->alg == IW_ENCODE_ALG_NONE) {
574		if (*crypt)
575			ieee80211_crypt_delayed_deinit(ieee, crypt);
576
577		for (i = 0; i < WEP_KEYS; i++)
578
579			if (ieee->crypt[i] != NULL)
580
581				break;
582
583		if (i == WEP_KEYS) {
584			sec.enabled = 0;
585		      //  sec.encrypt = 0;
586			sec.level = SEC_LEVEL_0;
587			sec.flags |= SEC_LEVEL;
588		}
589		//printk("disabled: flag:%x\n", encoding->flags);
590		goto done;
591	}
592
593	sec.enabled = 1;
594    //    sec.encrypt = 1;
595	switch (ext->alg) {
596	case IW_ENCODE_ALG_WEP:
597		alg = "WEP";
598		module = "ieee80211_crypt_wep";
599		break;
600	case IW_ENCODE_ALG_TKIP:
601		alg = "TKIP";
602		module = "ieee80211_crypt_tkip";
603		break;
604	case IW_ENCODE_ALG_CCMP:
605		alg = "CCMP";
606		module = "ieee80211_crypt_ccmp";
607		break;
608	default:
609		IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
610				   dev->name, ext->alg);
611		ret = -EINVAL;
612		goto done;
613	}
614	printk("alg name:%s\n",alg);
615
616	 ops = ieee80211_get_crypto_ops(alg);
617	if (ops == NULL) {
618		request_module(module);
619		ops = ieee80211_get_crypto_ops(alg);
620	}
621	if (ops == NULL) {
622		IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
623				   dev->name, ext->alg);
624		printk("========>unknown crypto alg %d\n", ext->alg);
625		ret = -EINVAL;
626		goto done;
627	}
628
629	if (*crypt == NULL || (*crypt)->ops != ops) {
630		struct ieee80211_crypt_data *new_crypt;
631
632		ieee80211_crypt_delayed_deinit(ieee, crypt);
633
634		new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
635		if (new_crypt == NULL) {
636			ret = -ENOMEM;
637			goto done;
638		}
639		new_crypt->ops = ops;
640		if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
641			new_crypt->priv = new_crypt->ops->init(idx);
642		if (new_crypt->priv == NULL) {
643			kfree(new_crypt);
644			ret = -EINVAL;
645			goto done;
646		}
647		*crypt = new_crypt;
648
649	}
650
651	if (ext->key_len > 0 && (*crypt)->ops->set_key &&
652	    (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
653				   (*crypt)->priv) < 0) {
654		IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
655		printk("key setting failed\n");
656		ret = -EINVAL;
657		goto done;
658	}
659 //skip_host_crypt:
660	//printk("skip_host_crypt:ext_flags:%x\n", ext->ext_flags);
661	if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
662		ieee->tx_keyidx = idx;
663		sec.active_key = idx;
664		sec.flags |= SEC_ACTIVE_KEY;
665	}
666
667	if (ext->alg != IW_ENCODE_ALG_NONE) {
668		//memcpy(sec.keys[idx], ext->key, ext->key_len);
669		sec.key_sizes[idx] = ext->key_len;
670		sec.flags |= (1 << idx);
671		if (ext->alg == IW_ENCODE_ALG_WEP) {
672		      //  sec.encode_alg[idx] = SEC_ALG_WEP;
673			sec.flags |= SEC_LEVEL;
674			sec.level = SEC_LEVEL_1;
675		} else if (ext->alg == IW_ENCODE_ALG_TKIP) {
676		      //  sec.encode_alg[idx] = SEC_ALG_TKIP;
677			sec.flags |= SEC_LEVEL;
678			sec.level = SEC_LEVEL_2;
679		} else if (ext->alg == IW_ENCODE_ALG_CCMP) {
680		       // sec.encode_alg[idx] = SEC_ALG_CCMP;
681			sec.flags |= SEC_LEVEL;
682			sec.level = SEC_LEVEL_3;
683		}
684		/* Don't set sec level for group keys. */
685		if (group_key)
686			sec.flags &= ~SEC_LEVEL;
687	}
688done:
689	if (ieee->set_security)
690		ieee->set_security(ieee->dev, &sec);
691
692	 if (ieee->reset_on_keychange &&
693	    ieee->iw_mode != IW_MODE_INFRA &&
694	    ieee->reset_port && ieee->reset_port(dev)) {
695		IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
696		return -EINVAL;
697	}
698	return ret;
699}
700
701int ieee80211_wx_get_encode_ext(struct ieee80211_device *ieee,
702			       struct iw_request_info *info,
703			       union iwreq_data *wrqu, char *extra)
704{
705	struct iw_point *encoding = &wrqu->encoding;
706	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
707	struct ieee80211_crypt_data *crypt;
708	int idx, max_key_len;
709
710	max_key_len = encoding->length - sizeof(*ext);
711	if (max_key_len < 0)
712		return -EINVAL;
713
714	idx = encoding->flags & IW_ENCODE_INDEX;
715	if (idx) {
716		if (idx < 1 || idx > WEP_KEYS)
717			return -EINVAL;
718		idx--;
719	} else
720		idx = ieee->tx_keyidx;
721
722	if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
723	    ext->alg != IW_ENCODE_ALG_WEP)
724		if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
725			return -EINVAL;
726
727	crypt = ieee->crypt[idx];
728	encoding->flags = idx + 1;
729	memset(ext, 0, sizeof(*ext));
730
731	if (crypt == NULL || crypt->ops == NULL ) {
732		ext->alg = IW_ENCODE_ALG_NONE;
733		ext->key_len = 0;
734		encoding->flags |= IW_ENCODE_DISABLED;
735	} else {
736		if (strcmp(crypt->ops->name, "WEP") == 0 )
737			ext->alg = IW_ENCODE_ALG_WEP;
738		else if (strcmp(crypt->ops->name, "TKIP"))
739			ext->alg = IW_ENCODE_ALG_TKIP;
740		else if (strcmp(crypt->ops->name, "CCMP"))
741			ext->alg = IW_ENCODE_ALG_CCMP;
742		else
743			return -EINVAL;
744		ext->key_len = crypt->ops->get_key(ext->key, SCM_KEY_LEN, NULL, crypt->priv);
745		encoding->flags |= IW_ENCODE_ENABLED;
746		if (ext->key_len &&
747		    (ext->alg == IW_ENCODE_ALG_TKIP ||
748		     ext->alg == IW_ENCODE_ALG_CCMP))
749			ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
750
751	}
752
753	return 0;
754}
755
756int ieee80211_wx_set_mlme(struct ieee80211_device *ieee,
757			       struct iw_request_info *info,
758			       union iwreq_data *wrqu, char *extra)
759{
760	struct iw_mlme *mlme = (struct iw_mlme *) extra;
761	switch (mlme->cmd) {
762	case IW_MLME_DEAUTH:
763	case IW_MLME_DISASSOC:
764		ieee80211_disassociate(ieee);
765		break;
766	 default:
767		return -EOPNOTSUPP;
768	}
769	return 0;
770}
771
772int ieee80211_wx_set_auth(struct ieee80211_device *ieee,
773			       struct iw_request_info *info,
774			       struct iw_param *data, char *extra)
775{
776	switch (data->flags & IW_AUTH_INDEX) {
777	case IW_AUTH_WPA_VERSION:
778	     /*need to support wpa2 here*/
779		//printk("wpa version:%x\n", data->value);
780		break;
781	case IW_AUTH_CIPHER_PAIRWISE:
782	case IW_AUTH_CIPHER_GROUP:
783	case IW_AUTH_KEY_MGMT:
784		/*
785 *                  * Host AP driver does not use these parameters and allows
786 *                                   * wpa_supplicant to control them internally.
787 *                                                    */
788		break;
789	case IW_AUTH_TKIP_COUNTERMEASURES:
790		ieee->tkip_countermeasures = data->value;
791		break;
792	case IW_AUTH_DROP_UNENCRYPTED:
793		ieee->drop_unencrypted = data->value;
794		break;
795
796	case IW_AUTH_80211_AUTH_ALG:
797		//printk("======>%s():data->value is %d\n",__FUNCTION__,data->value);
798	//	ieee->open_wep = (data->value&IW_AUTH_ALG_OPEN_SYSTEM)?1:0;
799		if(data->value & IW_AUTH_ALG_SHARED_KEY){
800			ieee->open_wep = 0;
801			ieee->auth_mode = 1;
802		}
803		else if(data->value & IW_AUTH_ALG_OPEN_SYSTEM){
804			ieee->open_wep = 1;
805			ieee->auth_mode = 0;
806		}
807		else if(data->value & IW_AUTH_ALG_LEAP){
808			ieee->open_wep = 1;
809			ieee->auth_mode = 2;
810			//printk("hahahaa:LEAP\n");
811		}
812		else
813			return -EINVAL;
814		//printk("open_wep:%d\n", ieee->open_wep);
815		break;
816
817	case IW_AUTH_WPA_ENABLED:
818		ieee->wpa_enabled = (data->value)?1:0;
819		//printk("enalbe wpa:%d\n", ieee->wpa_enabled);
820		break;
821
822	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
823		ieee->ieee802_1x = data->value;
824		break;
825	case IW_AUTH_PRIVACY_INVOKED:
826		ieee->privacy_invoked = data->value;
827		break;
828	default:
829		return -EOPNOTSUPP;
830	}
831	return 0;
832}
833#endif
834int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len)
835{
836	u8 *buf;
837
838	if (len>MAX_WPA_IE_LEN || (len && ie == NULL))
839	{
840	//	printk("return error out, len:%d\n", len);
841	return -EINVAL;
842	}
843
844
845	if (len)
846	{
847		if (len != ie[1]+2)
848		{
849			printk("len:%zu, ie:%d\n", len, ie[1]);
850			return -EINVAL;
851		}
852		buf = kmalloc(len, GFP_KERNEL);
853		if (buf == NULL)
854			return -ENOMEM;
855		memcpy(buf, ie, len);
856		kfree(ieee->wpa_ie);
857		ieee->wpa_ie = buf;
858		ieee->wpa_ie_len = len;
859	}
860	else{
861		if (ieee->wpa_ie)
862		kfree(ieee->wpa_ie);
863		ieee->wpa_ie = NULL;
864		ieee->wpa_ie_len = 0;
865	}
866	return 0;
867
868}
869
870EXPORT_SYMBOL(ieee80211_wx_set_gen_ie);
871#if (WIRELESS_EXT >= 18)
872EXPORT_SYMBOL(ieee80211_wx_set_mlme);
873EXPORT_SYMBOL(ieee80211_wx_set_auth);
874EXPORT_SYMBOL(ieee80211_wx_set_encode_ext);
875EXPORT_SYMBOL(ieee80211_wx_get_encode_ext);
876#endif
877EXPORT_SYMBOL(ieee80211_wx_get_scan);
878EXPORT_SYMBOL(ieee80211_wx_set_encode);
879EXPORT_SYMBOL(ieee80211_wx_get_encode);
880