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