• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/staging/rtl8192su/ieee80211/
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/kmod.h>
34#include <linux/slab.h>
35#include <linux/module.h>
36
37#include "ieee80211.h"
38
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
75	/* Remaining entries will be displayed in the order we provide them */
76
77	/* Add the ESSID */
78	iwe.cmd = SIOCGIWESSID;
79	iwe.u.data.flags = 1;
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<ARRAY_SIZE(ieee80211_modes); 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
169	iwe.cmd = SIOCGIWRATE;
170	iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
171	iwe.u.bitrate.value = max_rate * 500000;
172        start = iwe_stream_add_event_rsl(info, start, stop, &iwe,
173				     IW_EV_PARAM_LEN);
174
175	iwe.cmd = IWEVCUSTOM;
176	iwe.u.data.length = p - custom;
177	if (iwe.u.data.length)
178        start = iwe_stream_add_point(info, start, stop, &iwe, custom);
179
180	/* Add quality statistics */
181	/* TODO: Fix these values... */
182	iwe.cmd = IWEVQUAL;
183	iwe.u.qual.qual = network->stats.signal;
184	iwe.u.qual.level = network->stats.rssi;
185	iwe.u.qual.noise = network->stats.noise;
186	iwe.u.qual.updated = network->stats.mask & IEEE80211_STATMASK_WEMASK;
187	if (!(network->stats.mask & IEEE80211_STATMASK_RSSI))
188		iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
189	if (!(network->stats.mask & IEEE80211_STATMASK_NOISE))
190		iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
191	if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL))
192		iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID;
193	iwe.u.qual.updated = 7;
194        start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_QUAL_LEN);
195	iwe.cmd = IWEVCUSTOM;
196	p = custom;
197
198	iwe.u.data.length = p - custom;
199	if (iwe.u.data.length)
200            start = iwe_stream_add_point(info, start, stop, &iwe, custom);
201
202	memset(&iwe, 0, sizeof(iwe));
203	if (network->wpa_ie_len)
204	{
205		char buf[MAX_WPA_IE_LEN];
206		memcpy(buf, network->wpa_ie, network->wpa_ie_len);
207		iwe.cmd = IWEVGENIE;
208		iwe.u.data.length = network->wpa_ie_len;
209                start = iwe_stream_add_point(info, start, stop, &iwe, buf);
210        }
211	memset(&iwe, 0, sizeof(iwe));
212	if (network->rsn_ie_len)
213	{
214		char buf[MAX_WPA_IE_LEN];
215		memcpy(buf, network->rsn_ie, network->rsn_ie_len);
216		iwe.cmd = IWEVGENIE;
217		iwe.u.data.length = network->rsn_ie_len;
218                start = iwe_stream_add_point(info, start, stop, &iwe, buf);
219        }
220
221	/* Add EXTRA: Age to display seconds since last beacon/probe response
222	 * for given network. */
223	iwe.cmd = IWEVCUSTOM;
224	p = custom;
225	p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
226		      " Last beacon: %lums ago", (jiffies - network->last_scanned) / (HZ / 100));
227	iwe.u.data.length = p - custom;
228	if (iwe.u.data.length)
229            start = iwe_stream_add_point(info, start, stop, &iwe, custom);
230
231	return start;
232}
233
234int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
235			  struct iw_request_info *info,
236			  union iwreq_data *wrqu, char *extra)
237{
238	struct ieee80211_network *network;
239	unsigned long flags;
240
241	char *ev = extra;
242	char *stop = ev + wrqu->data.length;//IW_SCAN_MAX_DATA;
243	int i = 0;
244	int err = 0;
245	IEEE80211_DEBUG_WX("Getting scan\n");
246	down(&ieee->wx_sem);
247	spin_lock_irqsave(&ieee->lock, flags);
248
249	list_for_each_entry(network, &ieee->network_list, list) {
250		i++;
251		if((stop-ev)<200)
252		{
253			err = -E2BIG;
254			break;
255												}
256		if (ieee->scan_age == 0 ||
257		    time_after(network->last_scanned + ieee->scan_age, jiffies))
258			ev = rtl819x_translate_scan(ieee, ev, stop, network, info);
259		else
260			IEEE80211_DEBUG_SCAN(
261				"Not showing network '%s ("
262				"%pM)' due to age (%lums).\n",
263				escape_essid(network->ssid,
264					     network->ssid_len),
265				network->bssid,
266				(jiffies - network->last_scanned) / (HZ / 100));
267	}
268
269	spin_unlock_irqrestore(&ieee->lock, flags);
270	up(&ieee->wx_sem);
271	wrqu->data.length = ev -  extra;
272	wrqu->data.flags = 0;
273
274	IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
275
276	return err;
277}
278
279int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
280			    struct iw_request_info *info,
281			    union iwreq_data *wrqu, char *keybuf)
282{
283	struct iw_point *erq = &(wrqu->encoding);
284	struct net_device *dev = ieee->dev;
285	struct ieee80211_security sec = {
286		.flags = 0
287	};
288	int i, key, key_provided, len;
289	struct ieee80211_crypt_data **crypt;
290
291	IEEE80211_DEBUG_WX("SET_ENCODE\n");
292
293	key = erq->flags & IW_ENCODE_INDEX;
294	if (key) {
295		if (key > WEP_KEYS)
296			return -EINVAL;
297		key--;
298		key_provided = 1;
299	} else {
300		key_provided = 0;
301		key = ieee->tx_keyidx;
302	}
303
304	IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
305			   "provided" : "default");
306	crypt = &ieee->crypt[key];
307
308	if (erq->flags & IW_ENCODE_DISABLED) {
309		if (key_provided && *crypt) {
310			IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n",
311					   key);
312			ieee80211_crypt_delayed_deinit(ieee, crypt);
313		} else
314			IEEE80211_DEBUG_WX("Disabling encryption.\n");
315
316		/* Check all the keys to see if any are still configured,
317		 * and if no key index was provided, de-init them all */
318		for (i = 0; i < WEP_KEYS; i++) {
319			if (ieee->crypt[i] != NULL) {
320				if (key_provided)
321					break;
322				ieee80211_crypt_delayed_deinit(
323					ieee, &ieee->crypt[i]);
324			}
325		}
326
327		if (i == WEP_KEYS) {
328			sec.enabled = 0;
329			sec.level = SEC_LEVEL_0;
330			sec.flags |= SEC_ENABLED | SEC_LEVEL;
331		}
332
333		goto done;
334	}
335
336
337
338	sec.enabled = 1;
339	sec.flags |= SEC_ENABLED;
340
341	if (*crypt != NULL && (*crypt)->ops != NULL &&
342	    strcmp((*crypt)->ops->name, "WEP") != 0) {
343		/* changing to use WEP; deinit previously used algorithm
344		 * on this key */
345		ieee80211_crypt_delayed_deinit(ieee, crypt);
346	}
347
348	if (*crypt == NULL) {
349		struct ieee80211_crypt_data *new_crypt;
350
351		/* take WEP into use */
352		new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data),
353				    GFP_KERNEL);
354		if (new_crypt == NULL)
355			return -ENOMEM;
356		new_crypt->ops = ieee80211_get_crypto_ops("WEP");
357		if (!new_crypt->ops)
358			new_crypt->ops = ieee80211_get_crypto_ops("WEP");
359		if (new_crypt->ops)
360			new_crypt->priv = new_crypt->ops->init(key);
361
362		if (!new_crypt->ops || !new_crypt->priv) {
363			kfree(new_crypt);
364			new_crypt = NULL;
365
366			printk(KERN_WARNING "%s: could not initialize WEP: "
367			       "load module ieee80211_crypt_wep\n",
368			       dev->name);
369			return -EOPNOTSUPP;
370		}
371		*crypt = new_crypt;
372	}
373
374	/* If a new key was provided, set it up */
375	if (erq->length > 0) {
376		len = erq->length <= 5 ? 5 : 13;
377		memcpy(sec.keys[key], keybuf, erq->length);
378		if (len > erq->length)
379			memset(sec.keys[key] + erq->length, 0,
380			       len - erq->length);
381		IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
382				   key, escape_essid(sec.keys[key], len),
383				   erq->length, len);
384		sec.key_sizes[key] = len;
385 		(*crypt)->ops->set_key(sec.keys[key], len, NULL,
386				       (*crypt)->priv);
387		sec.flags |= (1 << key);
388		/* This ensures a key will be activated if no key is
389		 * explicitely set */
390		if (key == sec.active_key)
391			sec.flags |= SEC_ACTIVE_KEY;
392		ieee->tx_keyidx = key;
393
394	} else {
395		len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
396					     NULL, (*crypt)->priv);
397		if (len == 0) {
398			/* Set a default key of all 0 */
399			printk("Setting key %d to all zero.\n",
400					   key);
401
402			IEEE80211_DEBUG_WX("Setting key %d to all zero.\n",
403					   key);
404			memset(sec.keys[key], 0, 13);
405			(*crypt)->ops->set_key(sec.keys[key], 13, NULL,
406					       (*crypt)->priv);
407			sec.key_sizes[key] = 13;
408			sec.flags |= (1 << key);
409		}
410
411		/* No key data - just set the default TX key index */
412		if (key_provided) {
413			IEEE80211_DEBUG_WX(
414				"Setting key %d to default Tx key.\n", key);
415			ieee->tx_keyidx = key;
416			sec.active_key = key;
417			sec.flags |= SEC_ACTIVE_KEY;
418		}
419	}
420
421 done:
422	ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
423	ieee->auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
424	sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
425	sec.flags |= SEC_AUTH_MODE;
426	IEEE80211_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ?
427			   "OPEN" : "SHARED KEY");
428
429	/* For now we just support WEP, so only set that security level...
430	 * TODO: When WPA is added this is one place that needs to change */
431	sec.flags |= SEC_LEVEL;
432	sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
433
434	if (ieee->set_security)
435		ieee->set_security(dev, &sec);
436
437	/* Do not reset port if card is in Managed mode since resetting will
438	 * generate new IEEE 802.11 authentication which may end up in looping
439	 * with IEEE 802.1X.  If your hardware requires a reset after WEP
440	 * configuration (for example... Prism2), implement the reset_port in
441	 * the callbacks structures used to initialize the 802.11 stack. */
442	if (ieee->reset_on_keychange &&
443	    ieee->iw_mode != IW_MODE_INFRA &&
444	    ieee->reset_port && ieee->reset_port(dev)) {
445		printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
446		return -EINVAL;
447	}
448	return 0;
449}
450
451int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
452			    struct iw_request_info *info,
453			    union iwreq_data *wrqu, char *keybuf)
454{
455	struct iw_point *erq = &(wrqu->encoding);
456	int len, key;
457	struct ieee80211_crypt_data *crypt;
458
459	IEEE80211_DEBUG_WX("GET_ENCODE\n");
460
461	if(ieee->iw_mode == IW_MODE_MONITOR)
462		return -1;
463
464	key = erq->flags & IW_ENCODE_INDEX;
465	if (key) {
466		if (key > WEP_KEYS)
467			return -EINVAL;
468		key--;
469	} else
470		key = ieee->tx_keyidx;
471
472	crypt = ieee->crypt[key];
473	erq->flags = key + 1;
474
475	if (crypt == NULL || crypt->ops == NULL) {
476		erq->length = 0;
477		erq->flags |= IW_ENCODE_DISABLED;
478		return 0;
479	}
480
481	len = crypt->ops->get_key(keybuf, SCM_KEY_LEN, NULL, crypt->priv);
482	erq->length = (len >= 0 ? len : 0);
483
484	erq->flags |= IW_ENCODE_ENABLED;
485
486	if (ieee->open_wep)
487		erq->flags |= IW_ENCODE_OPEN;
488	else
489		erq->flags |= IW_ENCODE_RESTRICTED;
490
491	return 0;
492}
493
494int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
495                               struct iw_request_info *info,
496                               union iwreq_data *wrqu, char *extra)
497{
498	int ret = 0;
499	struct net_device *dev = ieee->dev;
500        struct iw_point *encoding = &wrqu->encoding;
501        struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
502        int i, idx;
503        int group_key = 0;
504        const char *alg;
505        struct ieee80211_crypto_ops *ops;
506        struct ieee80211_crypt_data **crypt;
507
508        struct ieee80211_security sec = {
509                .flags = 0,
510        };
511        idx = encoding->flags & IW_ENCODE_INDEX;
512        if (idx) {
513                if (idx < 1 || idx > WEP_KEYS)
514                        return -EINVAL;
515                idx--;
516        } else
517                idx = ieee->tx_keyidx;
518
519        if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
520
521                crypt = &ieee->crypt[idx];
522
523                group_key = 1;
524        } else {
525                /* some Cisco APs use idx>0 for unicast in dynamic WEP */
526		//printk("not group key, flags:%x, ext->alg:%d\n", ext->ext_flags, ext->alg);
527                if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
528                        return -EINVAL;
529                if (ieee->iw_mode == IW_MODE_INFRA)
530
531                        crypt = &ieee->crypt[idx];
532
533                else
534                        return -EINVAL;
535        }
536
537	sec.flags |= SEC_ENABLED;
538
539        if ((encoding->flags & IW_ENCODE_DISABLED) ||
540            ext->alg == IW_ENCODE_ALG_NONE) {
541                if (*crypt)
542                        ieee80211_crypt_delayed_deinit(ieee, crypt);
543
544                for (i = 0; i < WEP_KEYS; i++)
545
546			if (ieee->crypt[i] != NULL)
547
548                                break;
549
550                if (i == WEP_KEYS) {
551                        sec.enabled = 0;
552                      //  sec.encrypt = 0;
553                        sec.level = SEC_LEVEL_0;
554                        sec.flags |= SEC_LEVEL;
555                }
556		//printk("disabled: flag:%x\n", encoding->flags);
557                goto done;
558        }
559
560	sec.enabled = 1;
561
562        switch (ext->alg) {
563        case IW_ENCODE_ALG_WEP:
564                alg = "WEP";
565                break;
566        case IW_ENCODE_ALG_TKIP:
567                alg = "TKIP";
568                break;
569        case IW_ENCODE_ALG_CCMP:
570                alg = "CCMP";
571                break;
572        default:
573                IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
574                                   dev->name, ext->alg);
575                ret = -EINVAL;
576                goto done;
577        }
578	IEEE80211_DEBUG_WX("alg name: %s\n", alg);
579
580	 ops = ieee80211_get_crypto_ops(alg);
581        if (ops == NULL)
582                ops = ieee80211_get_crypto_ops(alg);
583        if (ops == NULL) {
584                IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
585                                   dev->name, ext->alg);
586		printk("========>unknown crypto alg %d\n", ext->alg);
587                ret = -EINVAL;
588                goto done;
589        }
590
591        if (*crypt == NULL || (*crypt)->ops != ops) {
592                struct ieee80211_crypt_data *new_crypt;
593
594                ieee80211_crypt_delayed_deinit(ieee, crypt);
595
596                new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
597                if (new_crypt == NULL) {
598                        ret = -ENOMEM;
599                        goto done;
600                }
601                new_crypt->ops = ops;
602                if (new_crypt->ops)
603                        new_crypt->priv = new_crypt->ops->init(idx);
604                if (new_crypt->priv == NULL) {
605                        kfree(new_crypt);
606                        ret = -EINVAL;
607                        goto done;
608                }
609                *crypt = new_crypt;
610
611 	}
612
613        if (ext->key_len > 0 && (*crypt)->ops->set_key &&
614            (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
615                                   (*crypt)->priv) < 0) {
616                IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
617		printk("key setting failed\n");
618                ret = -EINVAL;
619                goto done;
620        }
621        if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
622                ieee->tx_keyidx = idx;
623                sec.active_key = idx;
624                sec.flags |= SEC_ACTIVE_KEY;
625        }
626
627        if (ext->alg != IW_ENCODE_ALG_NONE) {
628                sec.key_sizes[idx] = ext->key_len;
629                sec.flags |= (1 << idx);
630                if (ext->alg == IW_ENCODE_ALG_WEP) {
631                        sec.flags |= SEC_LEVEL;
632                        sec.level = SEC_LEVEL_1;
633                } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
634                        sec.flags |= SEC_LEVEL;
635                        sec.level = SEC_LEVEL_2;
636                } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
637                        sec.flags |= SEC_LEVEL;
638                        sec.level = SEC_LEVEL_3;
639                }
640                /* Don't set sec level for group keys. */
641                if (group_key)
642                        sec.flags &= ~SEC_LEVEL;
643        }
644done:
645        if (ieee->set_security)
646                ieee->set_security(ieee->dev, &sec);
647
648	 if (ieee->reset_on_keychange &&
649            ieee->iw_mode != IW_MODE_INFRA &&
650            ieee->reset_port && ieee->reset_port(dev)) {
651                IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
652                return -EINVAL;
653        }
654
655        return ret;
656}
657
658int ieee80211_wx_set_mlme(struct ieee80211_device *ieee,
659                               struct iw_request_info *info,
660                               union iwreq_data *wrqu, char *extra)
661{
662	struct iw_mlme *mlme = (struct iw_mlme *) extra;
663
664	switch (mlme->cmd) {
665        case IW_MLME_DEAUTH:
666	case IW_MLME_DISASSOC:
667		ieee80211_disassociate(ieee);
668		break;
669	 default:
670                return -EOPNOTSUPP;
671        }
672
673	return 0;
674}
675
676int ieee80211_wx_set_auth(struct ieee80211_device *ieee,
677                               struct iw_request_info *info,
678                               struct iw_param *data, char *extra)
679{
680	switch (data->flags & IW_AUTH_INDEX) {
681        case IW_AUTH_WPA_VERSION:
682	     /*need to support wpa2 here*/
683		break;
684        case IW_AUTH_CIPHER_PAIRWISE:
685        case IW_AUTH_CIPHER_GROUP:
686        case IW_AUTH_KEY_MGMT:
687                /*
688 *                  * Host AP driver does not use these parameters and allows
689 *                                   * wpa_supplicant to control them internally.
690 *                                                    */
691                break;
692        case IW_AUTH_TKIP_COUNTERMEASURES:
693                ieee->tkip_countermeasures = data->value;
694                break;
695        case IW_AUTH_DROP_UNENCRYPTED:
696                ieee->drop_unencrypted = data->value;
697		break;
698
699	case IW_AUTH_80211_AUTH_ALG:
700		if(data->value & IW_AUTH_ALG_SHARED_KEY){
701			ieee->open_wep = 0;
702			ieee->auth_mode = 1;
703		}
704		else if(data->value & IW_AUTH_ALG_OPEN_SYSTEM){
705			ieee->open_wep = 1;
706			ieee->auth_mode = 0;
707		}
708		else if(data->value & IW_AUTH_ALG_LEAP){
709			ieee->open_wep = 1;
710			ieee->auth_mode = 2;
711		}
712		else
713			return -EINVAL;
714		break;
715
716	case IW_AUTH_WPA_ENABLED:
717		ieee->wpa_enabled = (data->value)?1:0;
718		break;
719	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
720                ieee->ieee802_1x = data->value;
721		break;
722	case IW_AUTH_PRIVACY_INVOKED:
723		ieee->privacy_invoked = data->value;
724		break;
725	default:
726                return -EOPNOTSUPP;
727	}
728
729	return 0;
730}
731
732int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len)
733{
734	u8 *buf;
735
736	if (len>MAX_WPA_IE_LEN || (len && ie == NULL))
737	{
738	return -EINVAL;
739	}
740
741
742	if (len)
743	{
744		if (len != ie[1]+2)
745		{
746			printk("len: %Zd, ie:%d\n", len, ie[1]);
747			return -EINVAL;
748		}
749		buf = kmemdup(ie, len, GFP_KERNEL);
750		if (buf == NULL)
751			return -ENOMEM;
752		kfree(ieee->wpa_ie);
753		ieee->wpa_ie = buf;
754		ieee->wpa_ie_len = len;
755	}
756	else{
757		if (ieee->wpa_ie)
758		kfree(ieee->wpa_ie);
759		ieee->wpa_ie = NULL;
760		ieee->wpa_ie_len = 0;
761	}
762
763	return 0;
764
765}
766