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