Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.13.7.
  1/******************************************************************************
  2
  3  Copyright(c) 2004-2005 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  <j@w1.fi>
  9  Copyright (c) 2002-2003, Jouni Malinen <j@w1.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  Intel Linux Wireless <ilw@linux.intel.com>
 29  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 30
 31******************************************************************************/
 32
 33#include <linux/hardirq.h>
 34#include <linux/kmod.h>
 35#include <linux/slab.h>
 36#include <linux/module.h>
 37#include <linux/jiffies.h>
 38
 39#include <net/lib80211.h>
 40#include <linux/wireless.h>
 41
 42#include "libipw.h"
 43
 44static const char *libipw_modes[] = {
 45	"?", "a", "b", "ab", "g", "ag", "bg", "abg"
 46};
 47
 48static inline unsigned int elapsed_jiffies_msecs(unsigned long start)
 49{
 50	unsigned long end = jiffies;
 51
 52	if (end >= start)
 53		return jiffies_to_msecs(end - start);
 54
 55	return jiffies_to_msecs(end + (MAX_JIFFY_OFFSET - start) + 1);
 56}
 57
 58#define MAX_CUSTOM_LEN 64
 59static char *libipw_translate_scan(struct libipw_device *ieee,
 60				      char *start, char *stop,
 61				      struct libipw_network *network,
 62				      struct iw_request_info *info)
 63{
 64	char custom[MAX_CUSTOM_LEN];
 65	char *p;
 66	struct iw_event iwe;
 67	int i, j;
 68	char *current_val;	/* For rates */
 69	u8 rate;
 70
 71	/* First entry *MUST* be the AP MAC address */
 72	iwe.cmd = SIOCGIWAP;
 73	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
 74	memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
 75	start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN);
 76
 77	/* Remaining entries will be displayed in the order we provide them */
 78
 79	/* Add the ESSID */
 80	iwe.cmd = SIOCGIWESSID;
 81	iwe.u.data.flags = 1;
 82	iwe.u.data.length = min(network->ssid_len, (u8) 32);
 83	start = iwe_stream_add_point(info, start, stop,
 84				     &iwe, network->ssid);
 85
 86	/* Add the protocol name */
 87	iwe.cmd = SIOCGIWNAME;
 88	snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s",
 89		 libipw_modes[network->mode]);
 90	start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN);
 91
 92	/* Add mode */
 93	iwe.cmd = SIOCGIWMODE;
 94	if (network->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
 95		if (network->capability & WLAN_CAPABILITY_ESS)
 96			iwe.u.mode = IW_MODE_MASTER;
 97		else
 98			iwe.u.mode = IW_MODE_ADHOC;
 99
100		start = iwe_stream_add_event(info, start, stop,
101					     &iwe, IW_EV_UINT_LEN);
102	}
103
104	/* Add channel and frequency */
105	/* Note : userspace automatically computes channel using iwrange */
106	iwe.cmd = SIOCGIWFREQ;
107	iwe.u.freq.m = libipw_channel_to_freq(ieee, network->channel);
108	iwe.u.freq.e = 6;
109	iwe.u.freq.i = 0;
110	start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN);
111
112	/* Add encryption capability */
113	iwe.cmd = SIOCGIWENCODE;
114	if (network->capability & WLAN_CAPABILITY_PRIVACY)
115		iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
116	else
117		iwe.u.data.flags = IW_ENCODE_DISABLED;
118	iwe.u.data.length = 0;
119	start = iwe_stream_add_point(info, start, stop,
120				     &iwe, network->ssid);
121
122	/* Add basic and extended rates */
123	/* Rate : stuffing multiple values in a single event require a bit
124	 * more of magic - Jean II */
125	current_val = start + iwe_stream_lcp_len(info);
126	iwe.cmd = SIOCGIWRATE;
127	/* Those two flags are ignored... */
128	iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
129
130	for (i = 0, j = 0; i < network->rates_len;) {
131		if (j < network->rates_ex_len &&
132		    ((network->rates_ex[j] & 0x7F) <
133		     (network->rates[i] & 0x7F)))
134			rate = network->rates_ex[j++] & 0x7F;
135		else
136			rate = network->rates[i++] & 0x7F;
137		/* Bit rate given in 500 kb/s units (+ 0x80) */
138		iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
139		/* Add new value to event */
140		current_val = iwe_stream_add_value(info, start, current_val,
141						   stop, &iwe, IW_EV_PARAM_LEN);
142	}
143	for (; j < network->rates_ex_len; j++) {
144		rate = network->rates_ex[j] & 0x7F;
145		/* Bit rate given in 500 kb/s units (+ 0x80) */
146		iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
147		/* Add new value to event */
148		current_val = iwe_stream_add_value(info, start, current_val,
149						   stop, &iwe, IW_EV_PARAM_LEN);
150	}
151	/* Check if we added any rate */
152	if ((current_val - start) > iwe_stream_lcp_len(info))
153		start = current_val;
154
155	/* Add quality statistics */
156	iwe.cmd = IWEVQUAL;
157	iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
158	    IW_QUAL_NOISE_UPDATED;
159
160	if (!(network->stats.mask & LIBIPW_STATMASK_RSSI)) {
161		iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID |
162		    IW_QUAL_LEVEL_INVALID;
163		iwe.u.qual.qual = 0;
164	} else {
165		if (ieee->perfect_rssi == ieee->worst_rssi)
166			iwe.u.qual.qual = 100;
167		else
168			iwe.u.qual.qual =
169			    (100 *
170			     (ieee->perfect_rssi - ieee->worst_rssi) *
171			     (ieee->perfect_rssi - ieee->worst_rssi) -
172			     (ieee->perfect_rssi - network->stats.rssi) *
173			     (15 * (ieee->perfect_rssi - ieee->worst_rssi) +
174			      62 * (ieee->perfect_rssi -
175				    network->stats.rssi))) /
176			    ((ieee->perfect_rssi -
177			      ieee->worst_rssi) * (ieee->perfect_rssi -
178						   ieee->worst_rssi));
179		if (iwe.u.qual.qual > 100)
180			iwe.u.qual.qual = 100;
181		else if (iwe.u.qual.qual < 1)
182			iwe.u.qual.qual = 0;
183	}
184
185	if (!(network->stats.mask & LIBIPW_STATMASK_NOISE)) {
186		iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
187		iwe.u.qual.noise = 0;
188	} else {
189		iwe.u.qual.noise = network->stats.noise;
190	}
191
192	if (!(network->stats.mask & LIBIPW_STATMASK_SIGNAL)) {
193		iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
194		iwe.u.qual.level = 0;
195	} else {
196		iwe.u.qual.level = network->stats.signal;
197	}
198
199	start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN);
200
201	iwe.cmd = IWEVCUSTOM;
202	p = custom;
203
204	iwe.u.data.length = p - custom;
205	if (iwe.u.data.length)
206		start = iwe_stream_add_point(info, start, stop, &iwe, custom);
207
208	memset(&iwe, 0, sizeof(iwe));
209	if (network->wpa_ie_len) {
210		char buf[MAX_WPA_IE_LEN];
211		memcpy(buf, network->wpa_ie, network->wpa_ie_len);
212		iwe.cmd = IWEVGENIE;
213		iwe.u.data.length = network->wpa_ie_len;
214		start = iwe_stream_add_point(info, start, stop, &iwe, buf);
215	}
216
217	memset(&iwe, 0, sizeof(iwe));
218	if (network->rsn_ie_len) {
219		char buf[MAX_WPA_IE_LEN];
220		memcpy(buf, network->rsn_ie, network->rsn_ie_len);
221		iwe.cmd = IWEVGENIE;
222		iwe.u.data.length = network->rsn_ie_len;
223		start = iwe_stream_add_point(info, start, stop, &iwe, buf);
224	}
225
226	/* Add EXTRA: Age to display seconds since last beacon/probe response
227	 * for given network. */
228	iwe.cmd = IWEVCUSTOM;
229	p = custom;
230	p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
231		      " Last beacon: %ums ago",
232		      elapsed_jiffies_msecs(network->last_scanned));
233	iwe.u.data.length = p - custom;
234	if (iwe.u.data.length)
235		start = iwe_stream_add_point(info, start, stop, &iwe, custom);
236
237	/* Add spectrum management information */
238	iwe.cmd = -1;
239	p = custom;
240	p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Channel flags: ");
241
242	if (libipw_get_channel_flags(ieee, network->channel) &
243	    LIBIPW_CH_INVALID) {
244		iwe.cmd = IWEVCUSTOM;
245		p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "INVALID ");
246	}
247
248	if (libipw_get_channel_flags(ieee, network->channel) &
249	    LIBIPW_CH_RADAR_DETECT) {
250		iwe.cmd = IWEVCUSTOM;
251		p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "DFS ");
252	}
253
254	if (iwe.cmd == IWEVCUSTOM) {
255		iwe.u.data.length = p - custom;
256		start = iwe_stream_add_point(info, start, stop, &iwe, custom);
257	}
258
259	return start;
260}
261
262#define SCAN_ITEM_SIZE 128
263
264int libipw_wx_get_scan(struct libipw_device *ieee,
265			  struct iw_request_info *info,
266			  union iwreq_data *wrqu, char *extra)
267{
268	struct libipw_network *network;
269	unsigned long flags;
270	int err = 0;
271
272	char *ev = extra;
273	char *stop = ev + wrqu->data.length;
274	int i = 0;
275	DECLARE_SSID_BUF(ssid);
276
277	LIBIPW_DEBUG_WX("Getting scan\n");
278
279	spin_lock_irqsave(&ieee->lock, flags);
280
281	list_for_each_entry(network, &ieee->network_list, list) {
282		i++;
283		if (stop - ev < SCAN_ITEM_SIZE) {
284			err = -E2BIG;
285			break;
286		}
287
288		if (ieee->scan_age == 0 ||
289		    time_after(network->last_scanned + ieee->scan_age, jiffies))
290			ev = libipw_translate_scan(ieee, ev, stop, network,
291						      info);
292		else {
293			LIBIPW_DEBUG_SCAN("Not showing network '%s ("
294					     "%pM)' due to age (%ums).\n",
295					     print_ssid(ssid, network->ssid,
296							 network->ssid_len),
297					     network->bssid,
298					     elapsed_jiffies_msecs(
299					               network->last_scanned));
300		}
301	}
302
303	spin_unlock_irqrestore(&ieee->lock, flags);
304
305	wrqu->data.length = ev - extra;
306	wrqu->data.flags = 0;
307
308	LIBIPW_DEBUG_WX("exit: %d networks returned.\n", i);
309
310	return err;
311}
312
313int libipw_wx_set_encode(struct libipw_device *ieee,
314			    struct iw_request_info *info,
315			    union iwreq_data *wrqu, char *keybuf)
316{
317	struct iw_point *erq = &(wrqu->encoding);
318	struct net_device *dev = ieee->dev;
319	struct libipw_security sec = {
320		.flags = 0
321	};
322	int i, key, key_provided, len;
323	struct lib80211_crypt_data **crypt;
324	int host_crypto = ieee->host_encrypt || ieee->host_decrypt;
325	DECLARE_SSID_BUF(ssid);
326
327	LIBIPW_DEBUG_WX("SET_ENCODE\n");
328
329	key = erq->flags & IW_ENCODE_INDEX;
330	if (key) {
331		if (key > WEP_KEYS)
332			return -EINVAL;
333		key--;
334		key_provided = 1;
335	} else {
336		key_provided = 0;
337		key = ieee->crypt_info.tx_keyidx;
338	}
339
340	LIBIPW_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
341			   "provided" : "default");
342
343	crypt = &ieee->crypt_info.crypt[key];
344
345	if (erq->flags & IW_ENCODE_DISABLED) {
346		if (key_provided && *crypt) {
347			LIBIPW_DEBUG_WX("Disabling encryption on key %d.\n",
348					   key);
349			lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
350		} else
351			LIBIPW_DEBUG_WX("Disabling encryption.\n");
352
353		/* Check all the keys to see if any are still configured,
354		 * and if no key index was provided, de-init them all */
355		for (i = 0; i < WEP_KEYS; i++) {
356			if (ieee->crypt_info.crypt[i] != NULL) {
357				if (key_provided)
358					break;
359				lib80211_crypt_delayed_deinit(&ieee->crypt_info,
360							       &ieee->crypt_info.crypt[i]);
361			}
362		}
363
364		if (i == WEP_KEYS) {
365			sec.enabled = 0;
366			sec.encrypt = 0;
367			sec.level = SEC_LEVEL_0;
368			sec.flags |= SEC_ENABLED | SEC_LEVEL | SEC_ENCRYPT;
369		}
370
371		goto done;
372	}
373
374	sec.enabled = 1;
375	sec.encrypt = 1;
376	sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
377
378	if (*crypt != NULL && (*crypt)->ops != NULL &&
379	    strcmp((*crypt)->ops->name, "WEP") != 0) {
380		/* changing to use WEP; deinit previously used algorithm
381		 * on this key */
382		lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
383	}
384
385	if (*crypt == NULL && host_crypto) {
386		struct lib80211_crypt_data *new_crypt;
387
388		/* take WEP into use */
389		new_crypt = kzalloc(sizeof(struct lib80211_crypt_data),
390				    GFP_KERNEL);
391		if (new_crypt == NULL)
392			return -ENOMEM;
393		new_crypt->ops = lib80211_get_crypto_ops("WEP");
394		if (!new_crypt->ops) {
395			request_module("lib80211_crypt_wep");
396			new_crypt->ops = lib80211_get_crypto_ops("WEP");
397		}
398
399		if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
400			new_crypt->priv = new_crypt->ops->init(key);
401
402		if (!new_crypt->ops || !new_crypt->priv) {
403			kfree(new_crypt);
404			new_crypt = NULL;
405
406			printk(KERN_WARNING "%s: could not initialize WEP: "
407			       "load module lib80211_crypt_wep\n", dev->name);
408			return -EOPNOTSUPP;
409		}
410		*crypt = new_crypt;
411	}
412
413	/* If a new key was provided, set it up */
414	if (erq->length > 0) {
415		len = erq->length <= 5 ? 5 : 13;
416		memcpy(sec.keys[key], keybuf, erq->length);
417		if (len > erq->length)
418			memset(sec.keys[key] + erq->length, 0,
419			       len - erq->length);
420		LIBIPW_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
421				   key, print_ssid(ssid, sec.keys[key], len),
422				   erq->length, len);
423		sec.key_sizes[key] = len;
424		if (*crypt)
425			(*crypt)->ops->set_key(sec.keys[key], len, NULL,
426					       (*crypt)->priv);
427		sec.flags |= (1 << key);
428		/* This ensures a key will be activated if no key is
429		 * explicitly set */
430		if (key == sec.active_key)
431			sec.flags |= SEC_ACTIVE_KEY;
432
433	} else {
434		if (host_crypto) {
435			len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
436						     NULL, (*crypt)->priv);
437			if (len == 0) {
438				/* Set a default key of all 0 */
439				LIBIPW_DEBUG_WX("Setting key %d to all "
440						   "zero.\n", key);
441				memset(sec.keys[key], 0, 13);
442				(*crypt)->ops->set_key(sec.keys[key], 13, NULL,
443						       (*crypt)->priv);
444				sec.key_sizes[key] = 13;
445				sec.flags |= (1 << key);
446			}
447		}
448		/* No key data - just set the default TX key index */
449		if (key_provided) {
450			LIBIPW_DEBUG_WX("Setting key %d to default Tx "
451					   "key.\n", key);
452			ieee->crypt_info.tx_keyidx = key;
453			sec.active_key = key;
454			sec.flags |= SEC_ACTIVE_KEY;
455		}
456	}
457	if (erq->flags & (IW_ENCODE_OPEN | IW_ENCODE_RESTRICTED)) {
458		ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
459		sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN :
460		    WLAN_AUTH_SHARED_KEY;
461		sec.flags |= SEC_AUTH_MODE;
462		LIBIPW_DEBUG_WX("Auth: %s\n",
463				   sec.auth_mode == WLAN_AUTH_OPEN ?
464				   "OPEN" : "SHARED KEY");
465	}
466
467	/* For now we just support WEP, so only set that security level...
468	 * TODO: When WPA is added this is one place that needs to change */
469	sec.flags |= SEC_LEVEL;
470	sec.level = SEC_LEVEL_1;	/* 40 and 104 bit WEP */
471	sec.encode_alg[key] = SEC_ALG_WEP;
472
473      done:
474	if (ieee->set_security)
475		ieee->set_security(dev, &sec);
476
477	/* Do not reset port if card is in Managed mode since resetting will
478	 * generate new IEEE 802.11 authentication which may end up in looping
479	 * with IEEE 802.1X.  If your hardware requires a reset after WEP
480	 * configuration (for example... Prism2), implement the reset_port in
481	 * the callbacks structures used to initialize the 802.11 stack. */
482	if (ieee->reset_on_keychange &&
483	    ieee->iw_mode != IW_MODE_INFRA &&
484	    ieee->reset_port && ieee->reset_port(dev)) {
485		printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
486		return -EINVAL;
487	}
488	return 0;
489}
490
491int libipw_wx_get_encode(struct libipw_device *ieee,
492			    struct iw_request_info *info,
493			    union iwreq_data *wrqu, char *keybuf)
494{
495	struct iw_point *erq = &(wrqu->encoding);
496	int len, key;
497	struct lib80211_crypt_data *crypt;
498	struct libipw_security *sec = &ieee->sec;
499
500	LIBIPW_DEBUG_WX("GET_ENCODE\n");
501
502	key = erq->flags & IW_ENCODE_INDEX;
503	if (key) {
504		if (key > WEP_KEYS)
505			return -EINVAL;
506		key--;
507	} else
508		key = ieee->crypt_info.tx_keyidx;
509
510	crypt = ieee->crypt_info.crypt[key];
511	erq->flags = key + 1;
512
513	if (!sec->enabled) {
514		erq->length = 0;
515		erq->flags |= IW_ENCODE_DISABLED;
516		return 0;
517	}
518
519	len = sec->key_sizes[key];
520	memcpy(keybuf, sec->keys[key], len);
521
522	erq->length = len;
523	erq->flags |= IW_ENCODE_ENABLED;
524
525	if (ieee->open_wep)
526		erq->flags |= IW_ENCODE_OPEN;
527	else
528		erq->flags |= IW_ENCODE_RESTRICTED;
529
530	return 0;
531}
532
533int libipw_wx_set_encodeext(struct libipw_device *ieee,
534			       struct iw_request_info *info,
535			       union iwreq_data *wrqu, char *extra)
536{
537	struct net_device *dev = ieee->dev;
538	struct iw_point *encoding = &wrqu->encoding;
539	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
540	int i, idx, ret = 0;
541	int group_key = 0;
542	const char *alg, *module;
543	struct lib80211_crypto_ops *ops;
544	struct lib80211_crypt_data **crypt;
545
546	struct libipw_security sec = {
547		.flags = 0,
548	};
549
550	idx = encoding->flags & IW_ENCODE_INDEX;
551	if (idx) {
552		if (idx < 1 || idx > WEP_KEYS)
553			return -EINVAL;
554		idx--;
555	} else
556		idx = ieee->crypt_info.tx_keyidx;
557
558	if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
559		crypt = &ieee->crypt_info.crypt[idx];
560		group_key = 1;
561	} else {
562		/* some Cisco APs use idx>0 for unicast in dynamic WEP */
563		if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
564			return -EINVAL;
565		if (ieee->iw_mode == IW_MODE_INFRA)
566			crypt = &ieee->crypt_info.crypt[idx];
567		else
568			return -EINVAL;
569	}
570
571	sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
572	if ((encoding->flags & IW_ENCODE_DISABLED) ||
573	    ext->alg == IW_ENCODE_ALG_NONE) {
574		if (*crypt)
575			lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
576
577		for (i = 0; i < WEP_KEYS; i++)
578			if (ieee->crypt_info.crypt[i] != NULL)
579				break;
580
581		if (i == WEP_KEYS) {
582			sec.enabled = 0;
583			sec.encrypt = 0;
584			sec.level = SEC_LEVEL_0;
585			sec.flags |= SEC_LEVEL;
586		}
587		goto done;
588	}
589
590	sec.enabled = 1;
591	sec.encrypt = 1;
592
593	if (group_key ? !ieee->host_mc_decrypt :
594	    !(ieee->host_encrypt || ieee->host_decrypt ||
595	      ieee->host_encrypt_msdu))
596		goto skip_host_crypt;
597
598	switch (ext->alg) {
599	case IW_ENCODE_ALG_WEP:
600		alg = "WEP";
601		module = "lib80211_crypt_wep";
602		break;
603	case IW_ENCODE_ALG_TKIP:
604		alg = "TKIP";
605		module = "lib80211_crypt_tkip";
606		break;
607	case IW_ENCODE_ALG_CCMP:
608		alg = "CCMP";
609		module = "lib80211_crypt_ccmp";
610		break;
611	default:
612		LIBIPW_DEBUG_WX("%s: unknown crypto alg %d\n",
613				   dev->name, ext->alg);
614		ret = -EINVAL;
615		goto done;
616	}
617
618	ops = lib80211_get_crypto_ops(alg);
619	if (ops == NULL) {
620		request_module(module);
621		ops = lib80211_get_crypto_ops(alg);
622	}
623	if (ops == NULL) {
624		LIBIPW_DEBUG_WX("%s: unknown crypto alg %d\n",
625				   dev->name, ext->alg);
626		ret = -EINVAL;
627		goto done;
628	}
629
630	if (*crypt == NULL || (*crypt)->ops != ops) {
631		struct lib80211_crypt_data *new_crypt;
632
633		lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
634
635		new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
636		if (new_crypt == NULL) {
637			ret = -ENOMEM;
638			goto done;
639		}
640		new_crypt->ops = ops;
641		if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
642			new_crypt->priv = new_crypt->ops->init(idx);
643		if (new_crypt->priv == NULL) {
644			kfree(new_crypt);
645			ret = -EINVAL;
646			goto done;
647		}
648		*crypt = new_crypt;
649	}
650
651	if (ext->key_len > 0 && (*crypt)->ops->set_key &&
652	    (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
653				   (*crypt)->priv) < 0) {
654		LIBIPW_DEBUG_WX("%s: key setting failed\n", dev->name);
655		ret = -EINVAL;
656		goto done;
657	}
658
659      skip_host_crypt:
660	if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
661		ieee->crypt_info.tx_keyidx = idx;
662		sec.active_key = idx;
663		sec.flags |= SEC_ACTIVE_KEY;
664	}
665
666	if (ext->alg != IW_ENCODE_ALG_NONE) {
667		memcpy(sec.keys[idx], ext->key, ext->key_len);
668		sec.key_sizes[idx] = ext->key_len;
669		sec.flags |= (1 << idx);
670		if (ext->alg == IW_ENCODE_ALG_WEP) {
671			sec.encode_alg[idx] = SEC_ALG_WEP;
672			sec.flags |= SEC_LEVEL;
673			sec.level = SEC_LEVEL_1;
674		} else if (ext->alg == IW_ENCODE_ALG_TKIP) {
675			sec.encode_alg[idx] = SEC_ALG_TKIP;
676			sec.flags |= SEC_LEVEL;
677			sec.level = SEC_LEVEL_2;
678		} else if (ext->alg == IW_ENCODE_ALG_CCMP) {
679			sec.encode_alg[idx] = SEC_ALG_CCMP;
680			sec.flags |= SEC_LEVEL;
681			sec.level = SEC_LEVEL_3;
682		}
683		/* Don't set sec level for group keys. */
684		if (group_key)
685			sec.flags &= ~SEC_LEVEL;
686	}
687      done:
688	if (ieee->set_security)
689		ieee->set_security(ieee->dev, &sec);
690
691	/*
692	 * Do not reset port if card is in Managed mode since resetting will
693	 * generate new IEEE 802.11 authentication which may end up in looping
694	 * with IEEE 802.1X. If your hardware requires a reset after WEP
695	 * configuration (for example... Prism2), implement the reset_port in
696	 * the callbacks structures used to initialize the 802.11 stack.
697	 */
698	if (ieee->reset_on_keychange &&
699	    ieee->iw_mode != IW_MODE_INFRA &&
700	    ieee->reset_port && ieee->reset_port(dev)) {
701		LIBIPW_DEBUG_WX("%s: reset_port failed\n", dev->name);
702		return -EINVAL;
703	}
704
705	return ret;
706}
707
708int libipw_wx_get_encodeext(struct libipw_device *ieee,
709			       struct iw_request_info *info,
710			       union iwreq_data *wrqu, char *extra)
711{
712	struct iw_point *encoding = &wrqu->encoding;
713	struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
714	struct libipw_security *sec = &ieee->sec;
715	int idx, max_key_len;
716
717	max_key_len = encoding->length - sizeof(*ext);
718	if (max_key_len < 0)
719		return -EINVAL;
720
721	idx = encoding->flags & IW_ENCODE_INDEX;
722	if (idx) {
723		if (idx < 1 || idx > WEP_KEYS)
724			return -EINVAL;
725		idx--;
726	} else
727		idx = ieee->crypt_info.tx_keyidx;
728
729	if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
730	    ext->alg != IW_ENCODE_ALG_WEP)
731		if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
732			return -EINVAL;
733
734	encoding->flags = idx + 1;
735	memset(ext, 0, sizeof(*ext));
736
737	if (!sec->enabled) {
738		ext->alg = IW_ENCODE_ALG_NONE;
739		ext->key_len = 0;
740		encoding->flags |= IW_ENCODE_DISABLED;
741	} else {
742		if (sec->encode_alg[idx] == SEC_ALG_WEP)
743			ext->alg = IW_ENCODE_ALG_WEP;
744		else if (sec->encode_alg[idx] == SEC_ALG_TKIP)
745			ext->alg = IW_ENCODE_ALG_TKIP;
746		else if (sec->encode_alg[idx] == SEC_ALG_CCMP)
747			ext->alg = IW_ENCODE_ALG_CCMP;
748		else
749			return -EINVAL;
750
751		ext->key_len = sec->key_sizes[idx];
752		memcpy(ext->key, sec->keys[idx], ext->key_len);
753		encoding->flags |= IW_ENCODE_ENABLED;
754		if (ext->key_len &&
755		    (ext->alg == IW_ENCODE_ALG_TKIP ||
756		     ext->alg == IW_ENCODE_ALG_CCMP))
757			ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
758
759	}
760
761	return 0;
762}
763
764EXPORT_SYMBOL(libipw_wx_set_encodeext);
765EXPORT_SYMBOL(libipw_wx_get_encodeext);
766
767EXPORT_SYMBOL(libipw_wx_get_scan);
768EXPORT_SYMBOL(libipw_wx_set_encode);
769EXPORT_SYMBOL(libipw_wx_get_encode);