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