Linux Audio

Check our new training course

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