[PATCH] ipw2200: Disable hwcrypto by default
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / net / ieee80211 / ieee80211_wx.c
CommitLineData
b453872c
JG
1/******************************************************************************
2
ebeaddcc 3 Copyright(c) 2004-2005 Intel Corporation. All rights reserved.
b453872c
JG
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******************************************************************************/
bbeec90b 32
b453872c
JG
33#include <linux/kmod.h>
34#include <linux/module.h>
42e349fd 35#include <linux/jiffies.h>
b453872c
JG
36
37#include <net/ieee80211.h>
bbeec90b
JG
38#include <linux/wireless.h>
39
b453872c
JG
40static const char *ieee80211_modes[] = {
41 "?", "a", "b", "ab", "g", "ag", "bg", "abg"
42};
43
44#define MAX_CUSTOM_LEN 64
858119e1 45static char *ipw2100_translate_scan(struct ieee80211_device *ieee,
0edd5b44 46 char *start, char *stop,
b453872c
JG
47 struct ieee80211_network *network)
48{
49 char custom[MAX_CUSTOM_LEN];
50 char *p;
51 struct iw_event iwe;
52 int i, j;
53 u8 max_rate, rate;
54
55 /* First entry *MUST* be the AP MAC address */
56 iwe.cmd = SIOCGIWAP;
57 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
58 memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
59 start = iwe_stream_add_event(start, stop, &iwe, IW_EV_ADDR_LEN);
60
61 /* Remaining entries will be displayed in the order we provide them */
62
63 /* Add the ESSID */
64 iwe.cmd = SIOCGIWESSID;
65 iwe.u.data.flags = 1;
66 if (network->flags & NETWORK_EMPTY_ESSID) {
67 iwe.u.data.length = sizeof("<hidden>");
68 start = iwe_stream_add_point(start, stop, &iwe, "<hidden>");
69 } else {
0edd5b44 70 iwe.u.data.length = min(network->ssid_len, (u8) 32);
b453872c
JG
71 start = iwe_stream_add_point(start, stop, &iwe, network->ssid);
72 }
73
74 /* Add the protocol name */
75 iwe.cmd = SIOCGIWNAME;
0edd5b44
JG
76 snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s",
77 ieee80211_modes[network->mode]);
b453872c
JG
78 start = iwe_stream_add_event(start, stop, &iwe, IW_EV_CHAR_LEN);
79
0edd5b44
JG
80 /* Add mode */
81 iwe.cmd = SIOCGIWMODE;
82 if (network->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
1b5cca3a 83 if (network->capability & WLAN_CAPABILITY_ESS)
b453872c
JG
84 iwe.u.mode = IW_MODE_MASTER;
85 else
86 iwe.u.mode = IW_MODE_ADHOC;
87
0edd5b44 88 start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN);
b453872c
JG
89 }
90
0edd5b44 91 /* Add frequency/channel */
b453872c
JG
92 iwe.cmd = SIOCGIWFREQ;
93/* iwe.u.freq.m = ieee80211_frequency(network->channel, network->mode);
94 iwe.u.freq.e = 3; */
95 iwe.u.freq.m = network->channel;
96 iwe.u.freq.e = 0;
97 iwe.u.freq.i = 0;
98 start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN);
99
100 /* Add encryption capability */
101 iwe.cmd = SIOCGIWENCODE;
102 if (network->capability & WLAN_CAPABILITY_PRIVACY)
103 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
104 else
105 iwe.u.data.flags = IW_ENCODE_DISABLED;
106 iwe.u.data.length = 0;
107 start = iwe_stream_add_point(start, stop, &iwe, network->ssid);
108
109 /* Add basic and extended rates */
110 max_rate = 0;
111 p = custom;
112 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): ");
0edd5b44 113 for (i = 0, j = 0; i < network->rates_len;) {
b453872c
JG
114 if (j < network->rates_ex_len &&
115 ((network->rates_ex[j] & 0x7F) <
116 (network->rates[i] & 0x7F)))
117 rate = network->rates_ex[j++] & 0x7F;
118 else
119 rate = network->rates[i++] & 0x7F;
120 if (rate > max_rate)
121 max_rate = rate;
122 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
123 "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
124 }
125 for (; j < network->rates_ex_len; j++) {
126 rate = network->rates_ex[j] & 0x7F;
127 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
128 "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
129 if (rate > max_rate)
130 max_rate = rate;
131 }
132
133 iwe.cmd = SIOCGIWRATE;
134 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
135 iwe.u.bitrate.value = max_rate * 500000;
0edd5b44 136 start = iwe_stream_add_event(start, stop, &iwe, IW_EV_PARAM_LEN);
b453872c
JG
137
138 iwe.cmd = IWEVCUSTOM;
139 iwe.u.data.length = p - custom;
140 if (iwe.u.data.length)
141 start = iwe_stream_add_point(start, stop, &iwe, custom);
142
143 /* Add quality statistics */
b453872c 144 iwe.cmd = IWEVQUAL;
b1b508e1
JK
145 iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
146 IW_QUAL_NOISE_UPDATED;
147
148 if (!(network->stats.mask & IEEE80211_STATMASK_RSSI)) {
149 iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID |
150 IW_QUAL_LEVEL_INVALID;
151 iwe.u.qual.qual = 0;
b1b508e1 152 } else {
757d18fa
JB
153 if (ieee->perfect_rssi == ieee->worst_rssi)
154 iwe.u.qual.qual = 100;
155 else
156 iwe.u.qual.qual =
157 (100 *
158 (ieee->perfect_rssi - ieee->worst_rssi) *
159 (ieee->perfect_rssi - ieee->worst_rssi) -
160 (ieee->perfect_rssi - network->stats.rssi) *
161 (15 * (ieee->perfect_rssi - ieee->worst_rssi) +
81f87520
JK
162 62 * (ieee->perfect_rssi -
163 network->stats.rssi))) /
164 ((ieee->perfect_rssi -
165 ieee->worst_rssi) * (ieee->perfect_rssi -
166 ieee->worst_rssi));
b1b508e1
JK
167 if (iwe.u.qual.qual > 100)
168 iwe.u.qual.qual = 100;
169 else if (iwe.u.qual.qual < 1)
170 iwe.u.qual.qual = 0;
171 }
172
173 if (!(network->stats.mask & IEEE80211_STATMASK_NOISE)) {
b453872c 174 iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
b1b508e1
JK
175 iwe.u.qual.noise = 0;
176 } else {
177 iwe.u.qual.noise = network->stats.noise;
178 }
b453872c 179
7bd64366
ZY
180 if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL)) {
181 iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
182 iwe.u.qual.level = 0;
183 } else {
184 iwe.u.qual.level = network->stats.signal;
185 }
186
b453872c
JG
187 start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN);
188
189 iwe.cmd = IWEVCUSTOM;
190 p = custom;
191
192 iwe.u.data.length = p - custom;
193 if (iwe.u.data.length)
194 start = iwe_stream_add_point(start, stop, &iwe, custom);
195
20d64713 196 if (network->wpa_ie_len) {
b453872c
JG
197 char buf[MAX_WPA_IE_LEN * 2 + 30];
198
199 u8 *p = buf;
200 p += sprintf(p, "wpa_ie=");
201 for (i = 0; i < network->wpa_ie_len; i++) {
202 p += sprintf(p, "%02x", network->wpa_ie[i]);
203 }
204
205 memset(&iwe, 0, sizeof(iwe));
206 iwe.cmd = IWEVCUSTOM;
207 iwe.u.data.length = strlen(buf);
208 start = iwe_stream_add_point(start, stop, &iwe, buf);
209 }
210
20d64713 211 if (network->rsn_ie_len) {
b453872c
JG
212 char buf[MAX_WPA_IE_LEN * 2 + 30];
213
214 u8 *p = buf;
215 p += sprintf(p, "rsn_ie=");
216 for (i = 0; i < network->rsn_ie_len; i++) {
217 p += sprintf(p, "%02x", network->rsn_ie[i]);
218 }
219
220 memset(&iwe, 0, sizeof(iwe));
221 iwe.cmd = IWEVCUSTOM;
222 iwe.u.data.length = strlen(buf);
223 start = iwe_stream_add_point(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),
42e349fd
JK
231 " Last beacon: %dms ago",
232 jiffies_to_msecs(jiffies - network->last_scanned));
b453872c
JG
233 iwe.u.data.length = p - custom;
234 if (iwe.u.data.length)
235 start = iwe_stream_add_point(start, stop, &iwe, custom);
236
7bd64366
ZY
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 (ieee80211_get_channel_flags(ieee, network->channel) &
243 IEEE80211_CH_INVALID) {
244 iwe.cmd = IWEVCUSTOM;
245 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "INVALID ");
246 }
247
248 if (ieee80211_get_channel_flags(ieee, network->channel) &
249 IEEE80211_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(start, stop, &iwe, custom);
257 }
258
b453872c
JG
259 return start;
260}
261
55cd94aa
ZY
262#define SCAN_ITEM_SIZE 128
263
b453872c
JG
264int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
265 struct iw_request_info *info,
266 union iwreq_data *wrqu, char *extra)
267{
268 struct ieee80211_network *network;
269 unsigned long flags;
55cd94aa 270 int err = 0;
b453872c
JG
271
272 char *ev = extra;
55cd94aa 273 char *stop = ev + wrqu->data.length;
b453872c
JG
274 int i = 0;
275
276 IEEE80211_DEBUG_WX("Getting scan\n");
277
278 spin_lock_irqsave(&ieee->lock, flags);
279
280 list_for_each_entry(network, &ieee->network_list, list) {
281 i++;
55cd94aa
ZY
282 if (stop - ev < SCAN_ITEM_SIZE) {
283 err = -E2BIG;
284 break;
285 }
286
b453872c
JG
287 if (ieee->scan_age == 0 ||
288 time_after(network->last_scanned + ieee->scan_age, jiffies))
289 ev = ipw2100_translate_scan(ieee, ev, stop, network);
290 else
0edd5b44 291 IEEE80211_DEBUG_SCAN("Not showing network '%s ("
42e349fd 292 MAC_FMT ")' due to age (%dms).\n",
0edd5b44
JG
293 escape_essid(network->ssid,
294 network->ssid_len),
295 MAC_ARG(network->bssid),
42e349fd
JK
296 jiffies_to_msecs(jiffies -
297 network->
298 last_scanned));
b453872c
JG
299 }
300
301 spin_unlock_irqrestore(&ieee->lock, flags);
302
0edd5b44 303 wrqu->data.length = ev - extra;
b453872c
JG
304 wrqu->data.flags = 0;
305
306 IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
307
55cd94aa 308 return err;
b453872c
JG
309}
310
311int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
312 struct iw_request_info *info,
313 union iwreq_data *wrqu, char *keybuf)
314{
315 struct iw_point *erq = &(wrqu->encoding);
316 struct net_device *dev = ieee->dev;
317 struct ieee80211_security sec = {
318 .flags = 0
319 };
320 int i, key, key_provided, len;
321 struct ieee80211_crypt_data **crypt;
a4bf26f3 322 int host_crypto = ieee->host_encrypt || ieee->host_decrypt || ieee->host_build_iv;
b453872c
JG
323
324 IEEE80211_DEBUG_WX("SET_ENCODE\n");
325
326 key = erq->flags & IW_ENCODE_INDEX;
327 if (key) {
328 if (key > WEP_KEYS)
329 return -EINVAL;
330 key--;
331 key_provided = 1;
332 } else {
333 key_provided = 0;
334 key = ieee->tx_keyidx;
335 }
336
337 IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
338 "provided" : "default");
339
340 crypt = &ieee->crypt[key];
341
342 if (erq->flags & IW_ENCODE_DISABLED) {
343 if (key_provided && *crypt) {
344 IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n",
345 key);
346 ieee80211_crypt_delayed_deinit(ieee, crypt);
347 } else
348 IEEE80211_DEBUG_WX("Disabling encryption.\n");
349
350 /* Check all the keys to see if any are still configured,
351 * and if no key index was provided, de-init them all */
352 for (i = 0; i < WEP_KEYS; i++) {
353 if (ieee->crypt[i] != NULL) {
354 if (key_provided)
355 break;
0edd5b44
JG
356 ieee80211_crypt_delayed_deinit(ieee,
357 &ieee->crypt[i]);
b453872c
JG
358 }
359 }
360
361 if (i == WEP_KEYS) {
362 sec.enabled = 0;
f1bf6638 363 sec.encrypt = 0;
b453872c 364 sec.level = SEC_LEVEL_0;
259bf1fd 365 sec.flags |= SEC_ENABLED | SEC_LEVEL | SEC_ENCRYPT;
b453872c
JG
366 }
367
368 goto done;
369 }
370
b453872c 371 sec.enabled = 1;
f1bf6638 372 sec.encrypt = 1;
259bf1fd 373 sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
b453872c
JG
374
375 if (*crypt != NULL && (*crypt)->ops != NULL &&
376 strcmp((*crypt)->ops->name, "WEP") != 0) {
377 /* changing to use WEP; deinit previously used algorithm
378 * on this key */
379 ieee80211_crypt_delayed_deinit(ieee, crypt);
380 }
381
f1bf6638 382 if (*crypt == NULL && host_crypto) {
b453872c
JG
383 struct ieee80211_crypt_data *new_crypt;
384
385 /* take WEP into use */
386 new_crypt = kmalloc(sizeof(struct ieee80211_crypt_data),
387 GFP_KERNEL);
388 if (new_crypt == NULL)
389 return -ENOMEM;
390 memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
391 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
392 if (!new_crypt->ops) {
393 request_module("ieee80211_crypt_wep");
394 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
395 }
396
397 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
6eb6edf0 398 new_crypt->priv = new_crypt->ops->init(key);
b453872c
JG
399
400 if (!new_crypt->ops || !new_crypt->priv) {
401 kfree(new_crypt);
402 new_crypt = NULL;
403
404 printk(KERN_WARNING "%s: could not initialize WEP: "
0edd5b44 405 "load module ieee80211_crypt_wep\n", dev->name);
b453872c
JG
406 return -EOPNOTSUPP;
407 }
408 *crypt = new_crypt;
409 }
410
411 /* If a new key was provided, set it up */
412 if (erq->length > 0) {
413 len = erq->length <= 5 ? 5 : 13;
414 memcpy(sec.keys[key], keybuf, erq->length);
415 if (len > erq->length)
416 memset(sec.keys[key] + erq->length, 0,
417 len - erq->length);
418 IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
419 key, escape_essid(sec.keys[key], len),
420 erq->length, len);
421 sec.key_sizes[key] = len;
f1bf6638
JK
422 if (*crypt)
423 (*crypt)->ops->set_key(sec.keys[key], len, NULL,
424 (*crypt)->priv);
b453872c
JG
425 sec.flags |= (1 << key);
426 /* This ensures a key will be activated if no key is
427 * explicitely set */
428 if (key == sec.active_key)
429 sec.flags |= SEC_ACTIVE_KEY;
f1bf6638 430
b453872c 431 } else {
f1bf6638
JK
432 if (host_crypto) {
433 len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
434 NULL, (*crypt)->priv);
435 if (len == 0) {
436 /* Set a default key of all 0 */
437 IEEE80211_DEBUG_WX("Setting key %d to all "
438 "zero.\n", key);
439 memset(sec.keys[key], 0, 13);
440 (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
441 (*crypt)->priv);
442 sec.key_sizes[key] = 13;
443 sec.flags |= (1 << key);
444 }
b453872c 445 }
b453872c
JG
446 /* No key data - just set the default TX key index */
447 if (key_provided) {
f1bf6638
JK
448 IEEE80211_DEBUG_WX("Setting key %d to default Tx "
449 "key.\n", key);
b453872c
JG
450 ieee->tx_keyidx = key;
451 sec.active_key = key;
452 sec.flags |= SEC_ACTIVE_KEY;
453 }
454 }
7dc888fe
JK
455 if (erq->flags & (IW_ENCODE_OPEN | IW_ENCODE_RESTRICTED)) {
456 ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
457 sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN :
458 WLAN_AUTH_SHARED_KEY;
459 sec.flags |= SEC_AUTH_MODE;
460 IEEE80211_DEBUG_WX("Auth: %s\n",
461 sec.auth_mode == WLAN_AUTH_OPEN ?
462 "OPEN" : "SHARED KEY");
463 }
b453872c
JG
464
465 /* For now we just support WEP, so only set that security level...
466 * TODO: When WPA is added this is one place that needs to change */
467 sec.flags |= SEC_LEVEL;
0edd5b44 468 sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
e0d369d1 469 sec.encode_alg[key] = SEC_ALG_WEP;
b453872c 470
259bf1fd 471 done:
b453872c
JG
472 if (ieee->set_security)
473 ieee->set_security(dev, &sec);
474
475 /* Do not reset port if card is in Managed mode since resetting will
476 * generate new IEEE 802.11 authentication which may end up in looping
477 * with IEEE 802.1X. If your hardware requires a reset after WEP
478 * configuration (for example... Prism2), implement the reset_port in
479 * the callbacks structures used to initialize the 802.11 stack. */
480 if (ieee->reset_on_keychange &&
481 ieee->iw_mode != IW_MODE_INFRA &&
482 ieee->reset_port && ieee->reset_port(dev)) {
483 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
484 return -EINVAL;
485 }
486 return 0;
487}
488
489int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
490 struct iw_request_info *info,
491 union iwreq_data *wrqu, char *keybuf)
492{
493 struct iw_point *erq = &(wrqu->encoding);
494 int len, key;
495 struct ieee80211_crypt_data *crypt;
f1bf6638 496 struct ieee80211_security *sec = &ieee->sec;
b453872c
JG
497
498 IEEE80211_DEBUG_WX("GET_ENCODE\n");
499
500 key = erq->flags & IW_ENCODE_INDEX;
501 if (key) {
502 if (key > WEP_KEYS)
503 return -EINVAL;
504 key--;
505 } else
506 key = ieee->tx_keyidx;
507
508 crypt = ieee->crypt[key];
509 erq->flags = key + 1;
510
f1bf6638 511 if (!sec->enabled) {
b453872c
JG
512 erq->length = 0;
513 erq->flags |= IW_ENCODE_DISABLED;
514 return 0;
515 }
516
f1bf6638
JK
517 len = sec->key_sizes[key];
518 memcpy(keybuf, sec->keys[key], len);
b453872c 519
f1bf6638 520 erq->length = (len >= 0 ? len : 0);
b453872c
JG
521 erq->flags |= IW_ENCODE_ENABLED;
522
523 if (ieee->open_wep)
524 erq->flags |= IW_ENCODE_OPEN;
525 else
526 erq->flags |= IW_ENCODE_RESTRICTED;
527
528 return 0;
529}
530
e0d369d1
JK
531int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee,
532 struct iw_request_info *info,
533 union iwreq_data *wrqu, char *extra)
534{
535 struct net_device *dev = ieee->dev;
536 struct iw_point *encoding = &wrqu->encoding;
537 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
538 int i, idx, ret = 0;
ccd0fda3 539 int group_key = 0;
e0d369d1
JK
540 const char *alg, *module;
541 struct ieee80211_crypto_ops *ops;
542 struct ieee80211_crypt_data **crypt;
543
544 struct ieee80211_security sec = {
545 .flags = 0,
546 };
547
548 idx = encoding->flags & IW_ENCODE_INDEX;
549 if (idx) {
550 if (idx < 1 || idx > WEP_KEYS)
551 return -EINVAL;
552 idx--;
553 } else
554 idx = ieee->tx_keyidx;
555
ccd0fda3 556 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
e0d369d1 557 crypt = &ieee->crypt[idx];
ccd0fda3
JK
558 group_key = 1;
559 } else {
e189277a
VB
560 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
561 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
e0d369d1
JK
562 return -EINVAL;
563 if (ieee->iw_mode == IW_MODE_INFRA)
564 crypt = &ieee->crypt[idx];
565 else
566 return -EINVAL;
567 }
568
569 sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
570 if ((encoding->flags & IW_ENCODE_DISABLED) ||
571 ext->alg == IW_ENCODE_ALG_NONE) {
572 if (*crypt)
573 ieee80211_crypt_delayed_deinit(ieee, crypt);
574
575 for (i = 0; i < WEP_KEYS; i++)
576 if (ieee->crypt[i] != NULL)
577 break;
578
579 if (i == WEP_KEYS) {
580 sec.enabled = 0;
581 sec.encrypt = 0;
582 sec.level = SEC_LEVEL_0;
583 sec.flags |= SEC_LEVEL;
584 }
585 goto done;
586 }
587
588 sec.enabled = 1;
589 sec.encrypt = 1;
590
ccd0fda3
JK
591 if (group_key ? !ieee->host_mc_decrypt :
592 !(ieee->host_encrypt || ieee->host_decrypt ||
593 ieee->host_encrypt_msdu))
e0d369d1
JK
594 goto skip_host_crypt;
595
596 switch (ext->alg) {
597 case IW_ENCODE_ALG_WEP:
598 alg = "WEP";
599 module = "ieee80211_crypt_wep";
600 break;
601 case IW_ENCODE_ALG_TKIP:
602 alg = "TKIP";
603 module = "ieee80211_crypt_tkip";
604 break;
605 case IW_ENCODE_ALG_CCMP:
606 alg = "CCMP";
607 module = "ieee80211_crypt_ccmp";
608 break;
609 default:
610 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
611 dev->name, ext->alg);
612 ret = -EINVAL;
613 goto done;
614 }
615
616 ops = ieee80211_get_crypto_ops(alg);
617 if (ops == NULL) {
618 request_module(module);
619 ops = ieee80211_get_crypto_ops(alg);
620 }
621 if (ops == NULL) {
622 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
623 dev->name, ext->alg);
624 ret = -EINVAL;
625 goto done;
626 }
627
628 if (*crypt == NULL || (*crypt)->ops != ops) {
629 struct ieee80211_crypt_data *new_crypt;
630
631 ieee80211_crypt_delayed_deinit(ieee, crypt);
632
633 new_crypt = (struct ieee80211_crypt_data *)
634 kmalloc(sizeof(*new_crypt), GFP_KERNEL);
635 if (new_crypt == NULL) {
636 ret = -ENOMEM;
637 goto done;
638 }
639 memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
640 new_crypt->ops = ops;
641 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
6eb6edf0 642 new_crypt->priv = new_crypt->ops->init(idx);
e0d369d1
JK
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 IEEE80211_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->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 }
ccd0fda3
JK
683 /* Don't set sec level for group keys. */
684 if (group_key)
685 sec.flags &= ~SEC_LEVEL;
e0d369d1
JK
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 IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
702 return -EINVAL;
703 }
704
705 return ret;
706}
707
708int ieee80211_wx_get_encodeext(struct ieee80211_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 ieee80211_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->tx_keyidx;
728
e189277a
VB
729 if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY &&
730 ext->alg != IW_ENCODE_ALG_WEP)
e0d369d1
JK
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(ieee80211_wx_set_encodeext);
765EXPORT_SYMBOL(ieee80211_wx_get_encodeext);
e0d369d1 766
b453872c
JG
767EXPORT_SYMBOL(ieee80211_wx_get_scan);
768EXPORT_SYMBOL(ieee80211_wx_set_encode);
769EXPORT_SYMBOL(ieee80211_wx_get_encode);