[PATCH] ieee80211: Mixed PTK/GTK CCMP/TKIP support
[deliverable/linux.git] / net / ieee80211 / ieee80211_wx.c
CommitLineData
b453872c
JG
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******************************************************************************/
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
45static inline 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;
152 iwe.u.qual.level = 0;
153 } else {
154 iwe.u.qual.level = network->stats.rssi;
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 - network->stats.rssi))) /
162 ((ieee->perfect_rssi - ieee->worst_rssi) *
163 (ieee->perfect_rssi - ieee->worst_rssi));
164 if (iwe.u.qual.qual > 100)
165 iwe.u.qual.qual = 100;
166 else if (iwe.u.qual.qual < 1)
167 iwe.u.qual.qual = 0;
168 }
169
170 if (!(network->stats.mask & IEEE80211_STATMASK_NOISE)) {
b453872c 171 iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
b1b508e1
JK
172 iwe.u.qual.noise = 0;
173 } else {
174 iwe.u.qual.noise = network->stats.noise;
175 }
b453872c
JG
176
177 start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN);
178
179 iwe.cmd = IWEVCUSTOM;
180 p = custom;
181
182 iwe.u.data.length = p - custom;
183 if (iwe.u.data.length)
184 start = iwe_stream_add_point(start, stop, &iwe, custom);
185
20d64713 186 if (network->wpa_ie_len) {
b453872c
JG
187 char buf[MAX_WPA_IE_LEN * 2 + 30];
188
189 u8 *p = buf;
190 p += sprintf(p, "wpa_ie=");
191 for (i = 0; i < network->wpa_ie_len; i++) {
192 p += sprintf(p, "%02x", network->wpa_ie[i]);
193 }
194
195 memset(&iwe, 0, sizeof(iwe));
196 iwe.cmd = IWEVCUSTOM;
197 iwe.u.data.length = strlen(buf);
198 start = iwe_stream_add_point(start, stop, &iwe, buf);
199 }
200
20d64713 201 if (network->rsn_ie_len) {
b453872c
JG
202 char buf[MAX_WPA_IE_LEN * 2 + 30];
203
204 u8 *p = buf;
205 p += sprintf(p, "rsn_ie=");
206 for (i = 0; i < network->rsn_ie_len; i++) {
207 p += sprintf(p, "%02x", network->rsn_ie[i]);
208 }
209
210 memset(&iwe, 0, sizeof(iwe));
211 iwe.cmd = IWEVCUSTOM;
212 iwe.u.data.length = strlen(buf);
213 start = iwe_stream_add_point(start, stop, &iwe, buf);
214 }
215
216 /* Add EXTRA: Age to display seconds since last beacon/probe response
217 * for given network. */
218 iwe.cmd = IWEVCUSTOM;
219 p = custom;
220 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
42e349fd
JK
221 " Last beacon: %dms ago",
222 jiffies_to_msecs(jiffies - network->last_scanned));
b453872c
JG
223 iwe.u.data.length = p - custom;
224 if (iwe.u.data.length)
225 start = iwe_stream_add_point(start, stop, &iwe, custom);
226
b453872c
JG
227 return start;
228}
229
230int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
231 struct iw_request_info *info,
232 union iwreq_data *wrqu, char *extra)
233{
234 struct ieee80211_network *network;
235 unsigned long flags;
236
237 char *ev = extra;
238 char *stop = ev + IW_SCAN_MAX_DATA;
239 int i = 0;
240
241 IEEE80211_DEBUG_WX("Getting scan\n");
242
243 spin_lock_irqsave(&ieee->lock, flags);
244
245 list_for_each_entry(network, &ieee->network_list, list) {
246 i++;
247 if (ieee->scan_age == 0 ||
248 time_after(network->last_scanned + ieee->scan_age, jiffies))
249 ev = ipw2100_translate_scan(ieee, ev, stop, network);
250 else
0edd5b44 251 IEEE80211_DEBUG_SCAN("Not showing network '%s ("
42e349fd 252 MAC_FMT ")' due to age (%dms).\n",
0edd5b44
JG
253 escape_essid(network->ssid,
254 network->ssid_len),
255 MAC_ARG(network->bssid),
42e349fd
JK
256 jiffies_to_msecs(jiffies -
257 network->
258 last_scanned));
b453872c
JG
259 }
260
261 spin_unlock_irqrestore(&ieee->lock, flags);
262
0edd5b44 263 wrqu->data.length = ev - extra;
b453872c
JG
264 wrqu->data.flags = 0;
265
266 IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
267
268 return 0;
269}
270
271int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
272 struct iw_request_info *info,
273 union iwreq_data *wrqu, char *keybuf)
274{
275 struct iw_point *erq = &(wrqu->encoding);
276 struct net_device *dev = ieee->dev;
277 struct ieee80211_security sec = {
278 .flags = 0
279 };
280 int i, key, key_provided, len;
281 struct ieee80211_crypt_data **crypt;
f1bf6638 282 int host_crypto = ieee->host_encrypt || ieee->host_decrypt;
b453872c
JG
283
284 IEEE80211_DEBUG_WX("SET_ENCODE\n");
285
286 key = erq->flags & IW_ENCODE_INDEX;
287 if (key) {
288 if (key > WEP_KEYS)
289 return -EINVAL;
290 key--;
291 key_provided = 1;
292 } else {
293 key_provided = 0;
294 key = ieee->tx_keyidx;
295 }
296
297 IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
298 "provided" : "default");
299
300 crypt = &ieee->crypt[key];
301
302 if (erq->flags & IW_ENCODE_DISABLED) {
303 if (key_provided && *crypt) {
304 IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n",
305 key);
306 ieee80211_crypt_delayed_deinit(ieee, crypt);
307 } else
308 IEEE80211_DEBUG_WX("Disabling encryption.\n");
309
310 /* Check all the keys to see if any are still configured,
311 * and if no key index was provided, de-init them all */
312 for (i = 0; i < WEP_KEYS; i++) {
313 if (ieee->crypt[i] != NULL) {
314 if (key_provided)
315 break;
0edd5b44
JG
316 ieee80211_crypt_delayed_deinit(ieee,
317 &ieee->crypt[i]);
b453872c
JG
318 }
319 }
320
321 if (i == WEP_KEYS) {
322 sec.enabled = 0;
f1bf6638 323 sec.encrypt = 0;
b453872c 324 sec.level = SEC_LEVEL_0;
259bf1fd 325 sec.flags |= SEC_ENABLED | SEC_LEVEL | SEC_ENCRYPT;
b453872c
JG
326 }
327
328 goto done;
329 }
330
b453872c 331 sec.enabled = 1;
f1bf6638 332 sec.encrypt = 1;
259bf1fd 333 sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
b453872c
JG
334
335 if (*crypt != NULL && (*crypt)->ops != NULL &&
336 strcmp((*crypt)->ops->name, "WEP") != 0) {
337 /* changing to use WEP; deinit previously used algorithm
338 * on this key */
339 ieee80211_crypt_delayed_deinit(ieee, crypt);
340 }
341
f1bf6638 342 if (*crypt == NULL && host_crypto) {
b453872c
JG
343 struct ieee80211_crypt_data *new_crypt;
344
345 /* take WEP into use */
346 new_crypt = kmalloc(sizeof(struct ieee80211_crypt_data),
347 GFP_KERNEL);
348 if (new_crypt == NULL)
349 return -ENOMEM;
350 memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
351 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
352 if (!new_crypt->ops) {
353 request_module("ieee80211_crypt_wep");
354 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
355 }
356
357 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
20d64713 358 new_crypt->priv = new_crypt->ops->init(ieee, key);
b453872c
JG
359
360 if (!new_crypt->ops || !new_crypt->priv) {
361 kfree(new_crypt);
362 new_crypt = NULL;
363
364 printk(KERN_WARNING "%s: could not initialize WEP: "
0edd5b44 365 "load module ieee80211_crypt_wep\n", dev->name);
b453872c
JG
366 return -EOPNOTSUPP;
367 }
368 *crypt = new_crypt;
369 }
370
371 /* If a new key was provided, set it up */
372 if (erq->length > 0) {
373 len = erq->length <= 5 ? 5 : 13;
374 memcpy(sec.keys[key], keybuf, erq->length);
375 if (len > erq->length)
376 memset(sec.keys[key] + erq->length, 0,
377 len - erq->length);
378 IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
379 key, escape_essid(sec.keys[key], len),
380 erq->length, len);
381 sec.key_sizes[key] = len;
f1bf6638
JK
382 if (*crypt)
383 (*crypt)->ops->set_key(sec.keys[key], len, NULL,
384 (*crypt)->priv);
b453872c
JG
385 sec.flags |= (1 << key);
386 /* This ensures a key will be activated if no key is
387 * explicitely set */
388 if (key == sec.active_key)
389 sec.flags |= SEC_ACTIVE_KEY;
f1bf6638 390
b453872c 391 } else {
f1bf6638
JK
392 if (host_crypto) {
393 len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
394 NULL, (*crypt)->priv);
395 if (len == 0) {
396 /* Set a default key of all 0 */
397 IEEE80211_DEBUG_WX("Setting key %d to all "
398 "zero.\n", key);
399 memset(sec.keys[key], 0, 13);
400 (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
401 (*crypt)->priv);
402 sec.key_sizes[key] = 13;
403 sec.flags |= (1 << key);
404 }
b453872c 405 }
b453872c
JG
406 /* No key data - just set the default TX key index */
407 if (key_provided) {
f1bf6638
JK
408 IEEE80211_DEBUG_WX("Setting key %d to default Tx "
409 "key.\n", key);
b453872c
JG
410 ieee->tx_keyidx = key;
411 sec.active_key = key;
412 sec.flags |= SEC_ACTIVE_KEY;
413 }
414 }
b453872c
JG
415 ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
416 sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
417 sec.flags |= SEC_AUTH_MODE;
418 IEEE80211_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ?
419 "OPEN" : "SHARED KEY");
420
421 /* For now we just support WEP, so only set that security level...
422 * TODO: When WPA is added this is one place that needs to change */
423 sec.flags |= SEC_LEVEL;
0edd5b44 424 sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
e0d369d1 425 sec.encode_alg[key] = SEC_ALG_WEP;
b453872c 426
259bf1fd 427 done:
b453872c
JG
428 if (ieee->set_security)
429 ieee->set_security(dev, &sec);
430
431 /* Do not reset port if card is in Managed mode since resetting will
432 * generate new IEEE 802.11 authentication which may end up in looping
433 * with IEEE 802.1X. If your hardware requires a reset after WEP
434 * configuration (for example... Prism2), implement the reset_port in
435 * the callbacks structures used to initialize the 802.11 stack. */
436 if (ieee->reset_on_keychange &&
437 ieee->iw_mode != IW_MODE_INFRA &&
438 ieee->reset_port && ieee->reset_port(dev)) {
439 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
440 return -EINVAL;
441 }
442 return 0;
443}
444
445int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
446 struct iw_request_info *info,
447 union iwreq_data *wrqu, char *keybuf)
448{
449 struct iw_point *erq = &(wrqu->encoding);
450 int len, key;
451 struct ieee80211_crypt_data *crypt;
f1bf6638 452 struct ieee80211_security *sec = &ieee->sec;
b453872c
JG
453
454 IEEE80211_DEBUG_WX("GET_ENCODE\n");
455
456 key = erq->flags & IW_ENCODE_INDEX;
457 if (key) {
458 if (key > WEP_KEYS)
459 return -EINVAL;
460 key--;
461 } else
462 key = ieee->tx_keyidx;
463
464 crypt = ieee->crypt[key];
465 erq->flags = key + 1;
466
f1bf6638 467 if (!sec->enabled) {
b453872c
JG
468 erq->length = 0;
469 erq->flags |= IW_ENCODE_DISABLED;
470 return 0;
471 }
472
f1bf6638
JK
473 len = sec->key_sizes[key];
474 memcpy(keybuf, sec->keys[key], len);
b453872c 475
f1bf6638 476 erq->length = (len >= 0 ? len : 0);
b453872c
JG
477 erq->flags |= IW_ENCODE_ENABLED;
478
479 if (ieee->open_wep)
480 erq->flags |= IW_ENCODE_OPEN;
481 else
482 erq->flags |= IW_ENCODE_RESTRICTED;
483
484 return 0;
485}
486
e0d369d1
JK
487#if WIRELESS_EXT > 17
488int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee,
489 struct iw_request_info *info,
490 union iwreq_data *wrqu, char *extra)
491{
492 struct net_device *dev = ieee->dev;
493 struct iw_point *encoding = &wrqu->encoding;
494 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
495 int i, idx, ret = 0;
ccd0fda3 496 int group_key = 0;
e0d369d1
JK
497 const char *alg, *module;
498 struct ieee80211_crypto_ops *ops;
499 struct ieee80211_crypt_data **crypt;
500
501 struct ieee80211_security sec = {
502 .flags = 0,
503 };
504
505 idx = encoding->flags & IW_ENCODE_INDEX;
506 if (idx) {
507 if (idx < 1 || idx > WEP_KEYS)
508 return -EINVAL;
509 idx--;
510 } else
511 idx = ieee->tx_keyidx;
512
ccd0fda3 513 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
e0d369d1 514 crypt = &ieee->crypt[idx];
ccd0fda3
JK
515 group_key = 1;
516 } else {
e0d369d1
JK
517 if (idx != 0)
518 return -EINVAL;
519 if (ieee->iw_mode == IW_MODE_INFRA)
520 crypt = &ieee->crypt[idx];
521 else
522 return -EINVAL;
523 }
524
525 sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
526 if ((encoding->flags & IW_ENCODE_DISABLED) ||
527 ext->alg == IW_ENCODE_ALG_NONE) {
528 if (*crypt)
529 ieee80211_crypt_delayed_deinit(ieee, crypt);
530
531 for (i = 0; i < WEP_KEYS; i++)
532 if (ieee->crypt[i] != NULL)
533 break;
534
535 if (i == WEP_KEYS) {
536 sec.enabled = 0;
537 sec.encrypt = 0;
538 sec.level = SEC_LEVEL_0;
539 sec.flags |= SEC_LEVEL;
540 }
541 goto done;
542 }
543
544 sec.enabled = 1;
545 sec.encrypt = 1;
546
ccd0fda3
JK
547 if (group_key ? !ieee->host_mc_decrypt :
548 !(ieee->host_encrypt || ieee->host_decrypt ||
549 ieee->host_encrypt_msdu))
e0d369d1
JK
550 goto skip_host_crypt;
551
552 switch (ext->alg) {
553 case IW_ENCODE_ALG_WEP:
554 alg = "WEP";
555 module = "ieee80211_crypt_wep";
556 break;
557 case IW_ENCODE_ALG_TKIP:
558 alg = "TKIP";
559 module = "ieee80211_crypt_tkip";
560 break;
561 case IW_ENCODE_ALG_CCMP:
562 alg = "CCMP";
563 module = "ieee80211_crypt_ccmp";
564 break;
565 default:
566 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
567 dev->name, ext->alg);
568 ret = -EINVAL;
569 goto done;
570 }
571
572 ops = ieee80211_get_crypto_ops(alg);
573 if (ops == NULL) {
574 request_module(module);
575 ops = ieee80211_get_crypto_ops(alg);
576 }
577 if (ops == NULL) {
578 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
579 dev->name, ext->alg);
580 ret = -EINVAL;
581 goto done;
582 }
583
584 if (*crypt == NULL || (*crypt)->ops != ops) {
585 struct ieee80211_crypt_data *new_crypt;
586
587 ieee80211_crypt_delayed_deinit(ieee, crypt);
588
589 new_crypt = (struct ieee80211_crypt_data *)
590 kmalloc(sizeof(*new_crypt), GFP_KERNEL);
591 if (new_crypt == NULL) {
592 ret = -ENOMEM;
593 goto done;
594 }
595 memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
596 new_crypt->ops = ops;
597 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
598 new_crypt->priv = new_crypt->ops->init(ieee, idx);
599 if (new_crypt->priv == NULL) {
600 kfree(new_crypt);
601 ret = -EINVAL;
602 goto done;
603 }
604 *crypt = new_crypt;
605 }
606
607 if (ext->key_len > 0 && (*crypt)->ops->set_key &&
608 (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
609 (*crypt)->priv) < 0) {
610 IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
611 ret = -EINVAL;
612 goto done;
613 }
614
615 skip_host_crypt:
616 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
617 ieee->tx_keyidx = idx;
618 sec.active_key = idx;
619 sec.flags |= SEC_ACTIVE_KEY;
620 }
621
622 if (ext->alg != IW_ENCODE_ALG_NONE) {
623 memcpy(sec.keys[idx], ext->key, ext->key_len);
624 sec.key_sizes[idx] = ext->key_len;
625 sec.flags |= (1 << idx);
626 if (ext->alg == IW_ENCODE_ALG_WEP) {
627 sec.encode_alg[idx] = SEC_ALG_WEP;
628 sec.flags |= SEC_LEVEL;
629 sec.level = SEC_LEVEL_1;
630 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
631 sec.encode_alg[idx] = SEC_ALG_TKIP;
632 sec.flags |= SEC_LEVEL;
633 sec.level = SEC_LEVEL_2;
634 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
635 sec.encode_alg[idx] = SEC_ALG_CCMP;
636 sec.flags |= SEC_LEVEL;
637 sec.level = SEC_LEVEL_3;
638 }
ccd0fda3
JK
639 /* Don't set sec level for group keys. */
640 if (group_key)
641 sec.flags &= ~SEC_LEVEL;
e0d369d1
JK
642 }
643 done:
644 if (ieee->set_security)
645 ieee->set_security(ieee->dev, &sec);
646
647 /*
648 * Do not reset port if card is in Managed mode since resetting will
649 * generate new IEEE 802.11 authentication which may end up in looping
650 * with IEEE 802.1X. If your hardware requires a reset after WEP
651 * configuration (for example... Prism2), implement the reset_port in
652 * the callbacks structures used to initialize the 802.11 stack.
653 */
654 if (ieee->reset_on_keychange &&
655 ieee->iw_mode != IW_MODE_INFRA &&
656 ieee->reset_port && ieee->reset_port(dev)) {
657 IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
658 return -EINVAL;
659 }
660
661 return ret;
662}
663
664int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee,
665 struct iw_request_info *info,
666 union iwreq_data *wrqu, char *extra)
667{
668 struct iw_point *encoding = &wrqu->encoding;
669 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
670 struct ieee80211_security *sec = &ieee->sec;
671 int idx, max_key_len;
672
673 max_key_len = encoding->length - sizeof(*ext);
674 if (max_key_len < 0)
675 return -EINVAL;
676
677 idx = encoding->flags & IW_ENCODE_INDEX;
678 if (idx) {
679 if (idx < 1 || idx > WEP_KEYS)
680 return -EINVAL;
681 idx--;
682 } else
683 idx = ieee->tx_keyidx;
684
685 if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
686 if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
687 return -EINVAL;
688
689 encoding->flags = idx + 1;
690 memset(ext, 0, sizeof(*ext));
691
692 if (!sec->enabled) {
693 ext->alg = IW_ENCODE_ALG_NONE;
694 ext->key_len = 0;
695 encoding->flags |= IW_ENCODE_DISABLED;
696 } else {
697 if (sec->encode_alg[idx] == SEC_ALG_WEP)
698 ext->alg = IW_ENCODE_ALG_WEP;
699 else if (sec->encode_alg[idx] == SEC_ALG_TKIP)
700 ext->alg = IW_ENCODE_ALG_TKIP;
701 else if (sec->encode_alg[idx] == SEC_ALG_CCMP)
702 ext->alg = IW_ENCODE_ALG_CCMP;
703 else
704 return -EINVAL;
705
706 ext->key_len = sec->key_sizes[idx];
707 memcpy(ext->key, sec->keys[idx], ext->key_len);
708 encoding->flags |= IW_ENCODE_ENABLED;
709 if (ext->key_len &&
710 (ext->alg == IW_ENCODE_ALG_TKIP ||
711 ext->alg == IW_ENCODE_ALG_CCMP))
712 ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
713
714 }
715
716 return 0;
717}
718
719EXPORT_SYMBOL(ieee80211_wx_set_encodeext);
720EXPORT_SYMBOL(ieee80211_wx_get_encodeext);
721#endif
722
b453872c
JG
723EXPORT_SYMBOL(ieee80211_wx_get_scan);
724EXPORT_SYMBOL(ieee80211_wx_set_encode);
725EXPORT_SYMBOL(ieee80211_wx_get_encode);
This page took 0.095005 seconds and 5 git commands to generate.