[go: nahoru, domu]

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