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