Merge branch 'master'
[deliverable/linux.git] / net / ieee80211 / ieee80211_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 <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 ******************************************************************************/
32
33 #include <linux/kmod.h>
34 #include <linux/module.h>
35 #include <linux/jiffies.h>
36
37 #include <net/ieee80211.h>
38 #include <linux/wireless.h>
39
40 static const char *ieee80211_modes[] = {
41 "?", "a", "b", "ab", "g", "ag", "bg", "abg"
42 };
43
44 #define MAX_CUSTOM_LEN 64
45 static inline char *ipw2100_translate_scan(struct ieee80211_device *ieee,
46 char *start, char *stop,
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 {
70 iwe.u.data.length = min(network->ssid_len, (u8) 32);
71 start = iwe_stream_add_point(start, stop, &iwe, network->ssid);
72 }
73
74 /* Add the protocol name */
75 iwe.cmd = SIOCGIWNAME;
76 snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s",
77 ieee80211_modes[network->mode]);
78 start = iwe_stream_add_event(start, stop, &iwe, IW_EV_CHAR_LEN);
79
80 /* Add mode */
81 iwe.cmd = SIOCGIWMODE;
82 if (network->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
83 if (network->capability & WLAN_CAPABILITY_ESS)
84 iwe.u.mode = IW_MODE_MASTER;
85 else
86 iwe.u.mode = IW_MODE_ADHOC;
87
88 start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN);
89 }
90
91 /* Add frequency/channel */
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): ");
113 for (i = 0, j = 0; i < network->rates_len;) {
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;
136 start = iwe_stream_add_event(start, stop, &iwe, IW_EV_PARAM_LEN);
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 */
144 iwe.cmd = IWEVQUAL;
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)) {
171 iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
172 iwe.u.qual.noise = 0;
173 } else {
174 iwe.u.qual.noise = network->stats.noise;
175 }
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
186 if (network->wpa_ie_len) {
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
201 if (network->rsn_ie_len) {
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),
221 " Last beacon: %dms ago",
222 jiffies_to_msecs(jiffies - network->last_scanned));
223 iwe.u.data.length = p - custom;
224 if (iwe.u.data.length)
225 start = iwe_stream_add_point(start, stop, &iwe, custom);
226
227 return start;
228 }
229
230 int 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
251 IEEE80211_DEBUG_SCAN("Not showing network '%s ("
252 MAC_FMT ")' due to age (%dms).\n",
253 escape_essid(network->ssid,
254 network->ssid_len),
255 MAC_ARG(network->bssid),
256 jiffies_to_msecs(jiffies -
257 network->
258 last_scanned));
259 }
260
261 spin_unlock_irqrestore(&ieee->lock, flags);
262
263 wrqu->data.length = ev - extra;
264 wrqu->data.flags = 0;
265
266 IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
267
268 return 0;
269 }
270
271 int 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;
282 int host_crypto = ieee->host_encrypt || ieee->host_decrypt;
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;
316 ieee80211_crypt_delayed_deinit(ieee,
317 &ieee->crypt[i]);
318 }
319 }
320
321 if (i == WEP_KEYS) {
322 sec.enabled = 0;
323 sec.encrypt = 0;
324 sec.level = SEC_LEVEL_0;
325 sec.flags |= SEC_ENABLED | SEC_LEVEL | SEC_ENCRYPT;
326 }
327
328 goto done;
329 }
330
331 sec.enabled = 1;
332 sec.encrypt = 1;
333 sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
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
342 if (*crypt == NULL && host_crypto) {
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))
358 new_crypt->priv = new_crypt->ops->init(key);
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: "
365 "load module ieee80211_crypt_wep\n", dev->name);
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;
382 if (*crypt)
383 (*crypt)->ops->set_key(sec.keys[key], len, NULL,
384 (*crypt)->priv);
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;
390
391 } else {
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 }
405 }
406 /* No key data - just set the default TX key index */
407 if (key_provided) {
408 IEEE80211_DEBUG_WX("Setting key %d to default Tx "
409 "key.\n", key);
410 ieee->tx_keyidx = key;
411 sec.active_key = key;
412 sec.flags |= SEC_ACTIVE_KEY;
413 }
414 }
415 if (erq->flags & (IW_ENCODE_OPEN | IW_ENCODE_RESTRICTED)) {
416 ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
417 sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN :
418 WLAN_AUTH_SHARED_KEY;
419 sec.flags |= SEC_AUTH_MODE;
420 IEEE80211_DEBUG_WX("Auth: %s\n",
421 sec.auth_mode == WLAN_AUTH_OPEN ?
422 "OPEN" : "SHARED KEY");
423 }
424
425 /* For now we just support WEP, so only set that security level...
426 * TODO: When WPA is added this is one place that needs to change */
427 sec.flags |= SEC_LEVEL;
428 sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
429 sec.encode_alg[key] = SEC_ALG_WEP;
430
431 done:
432 if (ieee->set_security)
433 ieee->set_security(dev, &sec);
434
435 /* Do not reset port if card is in Managed mode since resetting will
436 * generate new IEEE 802.11 authentication which may end up in looping
437 * with IEEE 802.1X. If your hardware requires a reset after WEP
438 * configuration (for example... Prism2), implement the reset_port in
439 * the callbacks structures used to initialize the 802.11 stack. */
440 if (ieee->reset_on_keychange &&
441 ieee->iw_mode != IW_MODE_INFRA &&
442 ieee->reset_port && ieee->reset_port(dev)) {
443 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
444 return -EINVAL;
445 }
446 return 0;
447 }
448
449 int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
450 struct iw_request_info *info,
451 union iwreq_data *wrqu, char *keybuf)
452 {
453 struct iw_point *erq = &(wrqu->encoding);
454 int len, key;
455 struct ieee80211_crypt_data *crypt;
456 struct ieee80211_security *sec = &ieee->sec;
457
458 IEEE80211_DEBUG_WX("GET_ENCODE\n");
459
460 key = erq->flags & IW_ENCODE_INDEX;
461 if (key) {
462 if (key > WEP_KEYS)
463 return -EINVAL;
464 key--;
465 } else
466 key = ieee->tx_keyidx;
467
468 crypt = ieee->crypt[key];
469 erq->flags = key + 1;
470
471 if (!sec->enabled) {
472 erq->length = 0;
473 erq->flags |= IW_ENCODE_DISABLED;
474 return 0;
475 }
476
477 len = sec->key_sizes[key];
478 memcpy(keybuf, sec->keys[key], len);
479
480 erq->length = (len >= 0 ? len : 0);
481 erq->flags |= IW_ENCODE_ENABLED;
482
483 if (ieee->open_wep)
484 erq->flags |= IW_ENCODE_OPEN;
485 else
486 erq->flags |= IW_ENCODE_RESTRICTED;
487
488 return 0;
489 }
490
491 int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee,
492 struct iw_request_info *info,
493 union iwreq_data *wrqu, char *extra)
494 {
495 struct net_device *dev = ieee->dev;
496 struct iw_point *encoding = &wrqu->encoding;
497 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
498 int i, idx, ret = 0;
499 int group_key = 0;
500 const char *alg, *module;
501 struct ieee80211_crypto_ops *ops;
502 struct ieee80211_crypt_data **crypt;
503
504 struct ieee80211_security sec = {
505 .flags = 0,
506 };
507
508 idx = encoding->flags & IW_ENCODE_INDEX;
509 if (idx) {
510 if (idx < 1 || idx > WEP_KEYS)
511 return -EINVAL;
512 idx--;
513 } else
514 idx = ieee->tx_keyidx;
515
516 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
517 crypt = &ieee->crypt[idx];
518 group_key = 1;
519 } else {
520 if (idx != 0)
521 return -EINVAL;
522 if (ieee->iw_mode == IW_MODE_INFRA)
523 crypt = &ieee->crypt[idx];
524 else
525 return -EINVAL;
526 }
527
528 sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
529 if ((encoding->flags & IW_ENCODE_DISABLED) ||
530 ext->alg == IW_ENCODE_ALG_NONE) {
531 if (*crypt)
532 ieee80211_crypt_delayed_deinit(ieee, crypt);
533
534 for (i = 0; i < WEP_KEYS; i++)
535 if (ieee->crypt[i] != NULL)
536 break;
537
538 if (i == WEP_KEYS) {
539 sec.enabled = 0;
540 sec.encrypt = 0;
541 sec.level = SEC_LEVEL_0;
542 sec.flags |= SEC_LEVEL;
543 }
544 goto done;
545 }
546
547 sec.enabled = 1;
548 sec.encrypt = 1;
549
550 if (group_key ? !ieee->host_mc_decrypt :
551 !(ieee->host_encrypt || ieee->host_decrypt ||
552 ieee->host_encrypt_msdu))
553 goto skip_host_crypt;
554
555 switch (ext->alg) {
556 case IW_ENCODE_ALG_WEP:
557 alg = "WEP";
558 module = "ieee80211_crypt_wep";
559 break;
560 case IW_ENCODE_ALG_TKIP:
561 alg = "TKIP";
562 module = "ieee80211_crypt_tkip";
563 break;
564 case IW_ENCODE_ALG_CCMP:
565 alg = "CCMP";
566 module = "ieee80211_crypt_ccmp";
567 break;
568 default:
569 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
570 dev->name, ext->alg);
571 ret = -EINVAL;
572 goto done;
573 }
574
575 ops = ieee80211_get_crypto_ops(alg);
576 if (ops == NULL) {
577 request_module(module);
578 ops = ieee80211_get_crypto_ops(alg);
579 }
580 if (ops == NULL) {
581 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
582 dev->name, ext->alg);
583 ret = -EINVAL;
584 goto done;
585 }
586
587 if (*crypt == NULL || (*crypt)->ops != ops) {
588 struct ieee80211_crypt_data *new_crypt;
589
590 ieee80211_crypt_delayed_deinit(ieee, crypt);
591
592 new_crypt = (struct ieee80211_crypt_data *)
593 kmalloc(sizeof(*new_crypt), GFP_KERNEL);
594 if (new_crypt == NULL) {
595 ret = -ENOMEM;
596 goto done;
597 }
598 memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
599 new_crypt->ops = ops;
600 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
601 new_crypt->priv = new_crypt->ops->init(idx);
602 if (new_crypt->priv == NULL) {
603 kfree(new_crypt);
604 ret = -EINVAL;
605 goto done;
606 }
607 *crypt = new_crypt;
608 }
609
610 if (ext->key_len > 0 && (*crypt)->ops->set_key &&
611 (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
612 (*crypt)->priv) < 0) {
613 IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
614 ret = -EINVAL;
615 goto done;
616 }
617
618 skip_host_crypt:
619 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
620 ieee->tx_keyidx = idx;
621 sec.active_key = idx;
622 sec.flags |= SEC_ACTIVE_KEY;
623 }
624
625 if (ext->alg != IW_ENCODE_ALG_NONE) {
626 memcpy(sec.keys[idx], ext->key, ext->key_len);
627 sec.key_sizes[idx] = ext->key_len;
628 sec.flags |= (1 << idx);
629 if (ext->alg == IW_ENCODE_ALG_WEP) {
630 sec.encode_alg[idx] = SEC_ALG_WEP;
631 sec.flags |= SEC_LEVEL;
632 sec.level = SEC_LEVEL_1;
633 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
634 sec.encode_alg[idx] = SEC_ALG_TKIP;
635 sec.flags |= SEC_LEVEL;
636 sec.level = SEC_LEVEL_2;
637 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
638 sec.encode_alg[idx] = SEC_ALG_CCMP;
639 sec.flags |= SEC_LEVEL;
640 sec.level = SEC_LEVEL_3;
641 }
642 /* Don't set sec level for group keys. */
643 if (group_key)
644 sec.flags &= ~SEC_LEVEL;
645 }
646 done:
647 if (ieee->set_security)
648 ieee->set_security(ieee->dev, &sec);
649
650 /*
651 * Do not reset port if card is in Managed mode since resetting will
652 * generate new IEEE 802.11 authentication which may end up in looping
653 * with IEEE 802.1X. If your hardware requires a reset after WEP
654 * configuration (for example... Prism2), implement the reset_port in
655 * the callbacks structures used to initialize the 802.11 stack.
656 */
657 if (ieee->reset_on_keychange &&
658 ieee->iw_mode != IW_MODE_INFRA &&
659 ieee->reset_port && ieee->reset_port(dev)) {
660 IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
661 return -EINVAL;
662 }
663
664 return ret;
665 }
666
667 int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee,
668 struct iw_request_info *info,
669 union iwreq_data *wrqu, char *extra)
670 {
671 struct iw_point *encoding = &wrqu->encoding;
672 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
673 struct ieee80211_security *sec = &ieee->sec;
674 int idx, max_key_len;
675
676 max_key_len = encoding->length - sizeof(*ext);
677 if (max_key_len < 0)
678 return -EINVAL;
679
680 idx = encoding->flags & IW_ENCODE_INDEX;
681 if (idx) {
682 if (idx < 1 || idx > WEP_KEYS)
683 return -EINVAL;
684 idx--;
685 } else
686 idx = ieee->tx_keyidx;
687
688 if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
689 if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
690 return -EINVAL;
691
692 encoding->flags = idx + 1;
693 memset(ext, 0, sizeof(*ext));
694
695 if (!sec->enabled) {
696 ext->alg = IW_ENCODE_ALG_NONE;
697 ext->key_len = 0;
698 encoding->flags |= IW_ENCODE_DISABLED;
699 } else {
700 if (sec->encode_alg[idx] == SEC_ALG_WEP)
701 ext->alg = IW_ENCODE_ALG_WEP;
702 else if (sec->encode_alg[idx] == SEC_ALG_TKIP)
703 ext->alg = IW_ENCODE_ALG_TKIP;
704 else if (sec->encode_alg[idx] == SEC_ALG_CCMP)
705 ext->alg = IW_ENCODE_ALG_CCMP;
706 else
707 return -EINVAL;
708
709 ext->key_len = sec->key_sizes[idx];
710 memcpy(ext->key, sec->keys[idx], ext->key_len);
711 encoding->flags |= IW_ENCODE_ENABLED;
712 if (ext->key_len &&
713 (ext->alg == IW_ENCODE_ALG_TKIP ||
714 ext->alg == IW_ENCODE_ALG_CCMP))
715 ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
716
717 }
718
719 return 0;
720 }
721
722 EXPORT_SYMBOL(ieee80211_wx_set_encodeext);
723 EXPORT_SYMBOL(ieee80211_wx_get_encodeext);
724
725 EXPORT_SYMBOL(ieee80211_wx_get_scan);
726 EXPORT_SYMBOL(ieee80211_wx_set_encode);
727 EXPORT_SYMBOL(ieee80211_wx_get_encode);
This page took 0.082954 seconds and 5 git commands to generate.