[PATCH] w1: Userspace communication protocol over connector.
[linux-2.6/verdex.git] / net / ieee80211 / ieee80211_wx.c
bloba78c4f845f66a88f3a2f95fb59adc8790c6af723
1 /******************************************************************************
3 Copyright(c) 2004-2005 Intel Corporation. All rights reserved.
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>
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.
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.
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.
24 The full GNU General Public License is included in this distribution in the
25 file called LICENSE.
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
31 ******************************************************************************/
33 #include <linux/kmod.h>
34 #include <linux/module.h>
35 #include <linux/jiffies.h>
37 #include <net/ieee80211.h>
38 #include <linux/wireless.h>
40 static const char *ieee80211_modes[] = {
41 "?", "a", "b", "ab", "g", "ag", "bg", "abg"
44 #define MAX_CUSTOM_LEN 64
45 static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
46 char *start, char *stop,
47 struct ieee80211_network *network)
49 char custom[MAX_CUSTOM_LEN];
50 char *p;
51 struct iw_event iwe;
52 int i, j;
53 char *current_val; /* For rates */
54 u8 rate;
56 /* First entry *MUST* be the AP MAC address */
57 iwe.cmd = SIOCGIWAP;
58 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
59 memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
60 start = iwe_stream_add_event(start, stop, &iwe, IW_EV_ADDR_LEN);
62 /* Remaining entries will be displayed in the order we provide them */
64 /* Add the ESSID */
65 iwe.cmd = SIOCGIWESSID;
66 iwe.u.data.flags = 1;
67 if (network->flags & NETWORK_EMPTY_ESSID) {
68 iwe.u.data.length = sizeof("<hidden>");
69 start = iwe_stream_add_point(start, stop, &iwe, "<hidden>");
70 } else {
71 iwe.u.data.length = min(network->ssid_len, (u8) 32);
72 start = iwe_stream_add_point(start, stop, &iwe, network->ssid);
75 /* Add the protocol name */
76 iwe.cmd = SIOCGIWNAME;
77 snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s",
78 ieee80211_modes[network->mode]);
79 start = iwe_stream_add_event(start, stop, &iwe, IW_EV_CHAR_LEN);
81 /* Add mode */
82 iwe.cmd = SIOCGIWMODE;
83 if (network->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
84 if (network->capability & WLAN_CAPABILITY_ESS)
85 iwe.u.mode = IW_MODE_MASTER;
86 else
87 iwe.u.mode = IW_MODE_ADHOC;
89 start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN);
92 /* Add frequency/channel */
93 iwe.cmd = SIOCGIWFREQ;
94 /* iwe.u.freq.m = ieee80211_frequency(network->channel, network->mode);
95 iwe.u.freq.e = 3; */
96 iwe.u.freq.m = network->channel;
97 iwe.u.freq.e = 0;
98 iwe.u.freq.i = 0;
99 start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN);
101 /* Add encryption capability */
102 iwe.cmd = SIOCGIWENCODE;
103 if (network->capability & WLAN_CAPABILITY_PRIVACY)
104 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
105 else
106 iwe.u.data.flags = IW_ENCODE_DISABLED;
107 iwe.u.data.length = 0;
108 start = iwe_stream_add_point(start, stop, &iwe, network->ssid);
110 /* Add basic and extended rates */
111 /* Rate : stuffing multiple values in a single event require a bit
112 * more of magic - Jean II */
113 current_val = start + IW_EV_LCP_LEN;
114 iwe.cmd = SIOCGIWRATE;
115 /* Those two flags are ignored... */
116 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
118 for (i = 0, j = 0; i < network->rates_len;) {
119 if (j < network->rates_ex_len &&
120 ((network->rates_ex[j] & 0x7F) <
121 (network->rates[i] & 0x7F)))
122 rate = network->rates_ex[j++] & 0x7F;
123 else
124 rate = network->rates[i++] & 0x7F;
125 /* Bit rate given in 500 kb/s units (+ 0x80) */
126 iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
127 /* Add new value to event */
128 current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN);
130 for (; j < network->rates_ex_len; j++) {
131 rate = network->rates_ex[j] & 0x7F;
132 /* Bit rate given in 500 kb/s units (+ 0x80) */
133 iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
134 /* Add new value to event */
135 current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN);
137 /* Check if we added any rate */
138 if((current_val - start) > IW_EV_LCP_LEN)
139 start = current_val;
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;
146 if (!(network->stats.mask & IEEE80211_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;
171 if (!(network->stats.mask & IEEE80211_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;
178 if (!(network->stats.mask & IEEE80211_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;
185 start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN);
187 iwe.cmd = IWEVCUSTOM;
188 p = custom;
190 iwe.u.data.length = p - custom;
191 if (iwe.u.data.length)
192 start = iwe_stream_add_point(start, stop, &iwe, custom);
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(start, stop, &iwe, buf);
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(start, stop, &iwe, buf);
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 += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
217 " Last beacon: %dms ago",
218 jiffies_to_msecs(jiffies - network->last_scanned));
219 iwe.u.data.length = p - custom;
220 if (iwe.u.data.length)
221 start = iwe_stream_add_point(start, stop, &iwe, custom);
223 /* Add spectrum management information */
224 iwe.cmd = -1;
225 p = custom;
226 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Channel flags: ");
228 if (ieee80211_get_channel_flags(ieee, network->channel) &
229 IEEE80211_CH_INVALID) {
230 iwe.cmd = IWEVCUSTOM;
231 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "INVALID ");
234 if (ieee80211_get_channel_flags(ieee, network->channel) &
235 IEEE80211_CH_RADAR_DETECT) {
236 iwe.cmd = IWEVCUSTOM;
237 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "DFS ");
240 if (iwe.cmd == IWEVCUSTOM) {
241 iwe.u.data.length = p - custom;
242 start = iwe_stream_add_point(start, stop, &iwe, custom);
245 return start;
248 #define SCAN_ITEM_SIZE 128
250 int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
251 struct iw_request_info *info,
252 union iwreq_data *wrqu, char *extra)
254 struct ieee80211_network *network;
255 unsigned long flags;
256 int err = 0;
258 char *ev = extra;
259 char *stop = ev + wrqu->data.length;
260 int i = 0;
262 IEEE80211_DEBUG_WX("Getting scan\n");
264 spin_lock_irqsave(&ieee->lock, flags);
266 list_for_each_entry(network, &ieee->network_list, list) {
267 i++;
268 if (stop - ev < SCAN_ITEM_SIZE) {
269 err = -E2BIG;
270 break;
273 if (ieee->scan_age == 0 ||
274 time_after(network->last_scanned + ieee->scan_age, jiffies))
275 ev = ieee80211_translate_scan(ieee, ev, stop, network);
276 else
277 IEEE80211_DEBUG_SCAN("Not showing network '%s ("
278 MAC_FMT ")' due to age (%dms).\n",
279 escape_essid(network->ssid,
280 network->ssid_len),
281 MAC_ARG(network->bssid),
282 jiffies_to_msecs(jiffies -
283 network->
284 last_scanned));
287 spin_unlock_irqrestore(&ieee->lock, flags);
289 wrqu->data.length = ev - extra;
290 wrqu->data.flags = 0;
292 IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
294 return err;
297 int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
298 struct iw_request_info *info,
299 union iwreq_data *wrqu, char *keybuf)
301 struct iw_point *erq = &(wrqu->encoding);
302 struct net_device *dev = ieee->dev;
303 struct ieee80211_security sec = {
304 .flags = 0
306 int i, key, key_provided, len;
307 struct ieee80211_crypt_data **crypt;
308 int host_crypto = ieee->host_encrypt || ieee->host_decrypt || ieee->host_build_iv;
310 IEEE80211_DEBUG_WX("SET_ENCODE\n");
312 key = erq->flags & IW_ENCODE_INDEX;
313 if (key) {
314 if (key > WEP_KEYS)
315 return -EINVAL;
316 key--;
317 key_provided = 1;
318 } else {
319 key_provided = 0;
320 key = ieee->tx_keyidx;
323 IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
324 "provided" : "default");
326 crypt = &ieee->crypt[key];
328 if (erq->flags & IW_ENCODE_DISABLED) {
329 if (key_provided && *crypt) {
330 IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n",
331 key);
332 ieee80211_crypt_delayed_deinit(ieee, crypt);
333 } else
334 IEEE80211_DEBUG_WX("Disabling encryption.\n");
336 /* Check all the keys to see if any are still configured,
337 * and if no key index was provided, de-init them all */
338 for (i = 0; i < WEP_KEYS; i++) {
339 if (ieee->crypt[i] != NULL) {
340 if (key_provided)
341 break;
342 ieee80211_crypt_delayed_deinit(ieee,
343 &ieee->crypt[i]);
347 if (i == WEP_KEYS) {
348 sec.enabled = 0;
349 sec.encrypt = 0;
350 sec.level = SEC_LEVEL_0;
351 sec.flags |= SEC_ENABLED | SEC_LEVEL | SEC_ENCRYPT;
354 goto done;
357 sec.enabled = 1;
358 sec.encrypt = 1;
359 sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
361 if (*crypt != NULL && (*crypt)->ops != NULL &&
362 strcmp((*crypt)->ops->name, "WEP") != 0) {
363 /* changing to use WEP; deinit previously used algorithm
364 * on this key */
365 ieee80211_crypt_delayed_deinit(ieee, crypt);
368 if (*crypt == NULL && host_crypto) {
369 struct ieee80211_crypt_data *new_crypt;
371 /* take WEP into use */
372 new_crypt = kmalloc(sizeof(struct ieee80211_crypt_data),
373 GFP_KERNEL);
374 if (new_crypt == NULL)
375 return -ENOMEM;
376 memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
377 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
378 if (!new_crypt->ops) {
379 request_module("ieee80211_crypt_wep");
380 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
383 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
384 new_crypt->priv = new_crypt->ops->init(key);
386 if (!new_crypt->ops || !new_crypt->priv) {
387 kfree(new_crypt);
388 new_crypt = NULL;
390 printk(KERN_WARNING "%s: could not initialize WEP: "
391 "load module ieee80211_crypt_wep\n", dev->name);
392 return -EOPNOTSUPP;
394 *crypt = new_crypt;
397 /* If a new key was provided, set it up */
398 if (erq->length > 0) {
399 len = erq->length <= 5 ? 5 : 13;
400 memcpy(sec.keys[key], keybuf, erq->length);
401 if (len > erq->length)
402 memset(sec.keys[key] + erq->length, 0,
403 len - erq->length);
404 IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
405 key, escape_essid(sec.keys[key], len),
406 erq->length, len);
407 sec.key_sizes[key] = len;
408 if (*crypt)
409 (*crypt)->ops->set_key(sec.keys[key], len, NULL,
410 (*crypt)->priv);
411 sec.flags |= (1 << key);
412 /* This ensures a key will be activated if no key is
413 * explicitely set */
414 if (key == sec.active_key)
415 sec.flags |= SEC_ACTIVE_KEY;
417 } else {
418 if (host_crypto) {
419 len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
420 NULL, (*crypt)->priv);
421 if (len == 0) {
422 /* Set a default key of all 0 */
423 IEEE80211_DEBUG_WX("Setting key %d to all "
424 "zero.\n", key);
425 memset(sec.keys[key], 0, 13);
426 (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
427 (*crypt)->priv);
428 sec.key_sizes[key] = 13;
429 sec.flags |= (1 << key);
432 /* No key data - just set the default TX key index */
433 if (key_provided) {
434 IEEE80211_DEBUG_WX("Setting key %d to default Tx "
435 "key.\n", key);
436 ieee->tx_keyidx = key;
437 sec.active_key = key;
438 sec.flags |= SEC_ACTIVE_KEY;
441 if (erq->flags & (IW_ENCODE_OPEN | IW_ENCODE_RESTRICTED)) {
442 ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
443 sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN :
444 WLAN_AUTH_SHARED_KEY;
445 sec.flags |= SEC_AUTH_MODE;
446 IEEE80211_DEBUG_WX("Auth: %s\n",
447 sec.auth_mode == WLAN_AUTH_OPEN ?
448 "OPEN" : "SHARED KEY");
451 /* For now we just support WEP, so only set that security level...
452 * TODO: When WPA is added this is one place that needs to change */
453 sec.flags |= SEC_LEVEL;
454 sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
455 sec.encode_alg[key] = SEC_ALG_WEP;
457 done:
458 if (ieee->set_security)
459 ieee->set_security(dev, &sec);
461 /* Do not reset port if card is in Managed mode since resetting will
462 * generate new IEEE 802.11 authentication which may end up in looping
463 * with IEEE 802.1X. If your hardware requires a reset after WEP
464 * configuration (for example... Prism2), implement the reset_port in
465 * the callbacks structures used to initialize the 802.11 stack. */
466 if (ieee->reset_on_keychange &&
467 ieee->iw_mode != IW_MODE_INFRA &&
468 ieee->reset_port && ieee->reset_port(dev)) {
469 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
470 return -EINVAL;
472 return 0;
475 int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
476 struct iw_request_info *info,
477 union iwreq_data *wrqu, char *keybuf)
479 struct iw_point *erq = &(wrqu->encoding);
480 int len, key;
481 struct ieee80211_crypt_data *crypt;
482 struct ieee80211_security *sec = &ieee->sec;
484 IEEE80211_DEBUG_WX("GET_ENCODE\n");
486 key = erq->flags & IW_ENCODE_INDEX;
487 if (key) {
488 if (key > WEP_KEYS)
489 return -EINVAL;
490 key--;
491 } else
492 key = ieee->tx_keyidx;
494 crypt = ieee->crypt[key];
495 erq->flags = key + 1;
497 if (!sec->enabled) {
498 erq->length = 0;
499 erq->flags |= IW_ENCODE_DISABLED;
500 return 0;
503 len = sec->key_sizes[key];
504 memcpy(keybuf, sec->keys[key], len);
506 erq->length = len;
507 erq->flags |= IW_ENCODE_ENABLED;
509 if (ieee->open_wep)
510 erq->flags |= IW_ENCODE_OPEN;
511 else
512 erq->flags |= IW_ENCODE_RESTRICTED;
514 return 0;
517 int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee,
518 struct iw_request_info *info,
519 union iwreq_data *wrqu, char *extra)
521 struct net_device *dev = ieee->dev;
522 struct iw_point *encoding = &wrqu->encoding;
523 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
524 int i, idx, ret = 0;
525 int group_key = 0;
526 const char *alg, *module;
527 struct ieee80211_crypto_ops *ops;
528 struct ieee80211_crypt_data **crypt;
530 struct ieee80211_security sec = {
531 .flags = 0,
534 idx = encoding->flags & IW_ENCODE_INDEX;
535 if (idx) {
536 if (idx < 1 || idx > WEP_KEYS)
537 return -EINVAL;
538 idx--;
539 } else
540 idx = ieee->tx_keyidx;
542 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
543 crypt = &ieee->crypt[idx];
544 group_key = 1;
545 } else {
546 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
547 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
548 return -EINVAL;
549 if (ieee->iw_mode == IW_MODE_INFRA)
550 crypt = &ieee->crypt[idx];
551 else
552 return -EINVAL;
555 sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
556 if ((encoding->flags & IW_ENCODE_DISABLED) ||
557 ext->alg == IW_ENCODE_ALG_NONE) {
558 if (*crypt)
559 ieee80211_crypt_delayed_deinit(ieee, crypt);
561 for (i = 0; i < WEP_KEYS; i++)
562 if (ieee->crypt[i] != NULL)
563 break;
565 if (i == WEP_KEYS) {
566 sec.enabled = 0;
567 sec.encrypt = 0;
568 sec.level = SEC_LEVEL_0;
569 sec.flags |= SEC_LEVEL;
571 goto done;
574 sec.enabled = 1;
575 sec.encrypt = 1;
577 if (group_key ? !ieee->host_mc_decrypt :
578 !(ieee->host_encrypt || ieee->host_decrypt ||
579 ieee->host_encrypt_msdu))
580 goto skip_host_crypt;
582 switch (ext->alg) {
583 case IW_ENCODE_ALG_WEP:
584 alg = "WEP";
585 module = "ieee80211_crypt_wep";
586 break;
587 case IW_ENCODE_ALG_TKIP:
588 alg = "TKIP";
589 module = "ieee80211_crypt_tkip";
590 break;
591 case IW_ENCODE_ALG_CCMP:
592 alg = "CCMP";
593 module = "ieee80211_crypt_ccmp";
594 break;
595 default:
596 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
597 dev->name, ext->alg);
598 ret = -EINVAL;
599 goto done;
602 ops = ieee80211_get_crypto_ops(alg);
603 if (ops == NULL) {
604 request_module(module);
605 ops = ieee80211_get_crypto_ops(alg);
607 if (ops == NULL) {
608 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
609 dev->name, ext->alg);
610 ret = -EINVAL;
611 goto done;
614 if (*crypt == NULL || (*crypt)->ops != ops) {
615 struct ieee80211_crypt_data *new_crypt;
617 ieee80211_crypt_delayed_deinit(ieee, crypt);
619 new_crypt = (struct ieee80211_crypt_data *)
620 kmalloc(sizeof(*new_crypt), GFP_KERNEL);
621 if (new_crypt == NULL) {
622 ret = -ENOMEM;
623 goto done;
625 memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
626 new_crypt->ops = ops;
627 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
628 new_crypt->priv = new_crypt->ops->init(idx);
629 if (new_crypt->priv == NULL) {
630 kfree(new_crypt);
631 ret = -EINVAL;
632 goto done;
634 *crypt = new_crypt;
637 if (ext->key_len > 0 && (*crypt)->ops->set_key &&
638 (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
639 (*crypt)->priv) < 0) {
640 IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
641 ret = -EINVAL;
642 goto done;
645 skip_host_crypt:
646 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
647 ieee->tx_keyidx = idx;
648 sec.active_key = idx;
649 sec.flags |= SEC_ACTIVE_KEY;
652 if (ext->alg != IW_ENCODE_ALG_NONE) {
653 memcpy(sec.keys[idx], ext->key, ext->key_len);
654 sec.key_sizes[idx] = ext->key_len;
655 sec.flags |= (1 << idx);
656 if (ext->alg == IW_ENCODE_ALG_WEP) {
657 sec.encode_alg[idx] = SEC_ALG_WEP;
658 sec.flags |= SEC_LEVEL;
659 sec.level = SEC_LEVEL_1;
660 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
661 sec.encode_alg[idx] = SEC_ALG_TKIP;
662 sec.flags |= SEC_LEVEL;
663 sec.level = SEC_LEVEL_2;
664 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
665 sec.encode_alg[idx] = SEC_ALG_CCMP;
666 sec.flags |= SEC_LEVEL;
667 sec.level = SEC_LEVEL_3;
669 /* Don't set sec level for group keys. */
670 if (group_key)
671 sec.flags &= ~SEC_LEVEL;
673 done:
674 if (ieee->set_security)
675 ieee->set_security(ieee->dev, &sec);
678 * Do not reset port if card is in Managed mode since resetting will
679 * generate new IEEE 802.11 authentication which may end up in looping
680 * with IEEE 802.1X. If your hardware requires a reset after WEP
681 * configuration (for example... Prism2), implement the reset_port in
682 * the callbacks structures used to initialize the 802.11 stack.
684 if (ieee->reset_on_keychange &&
685 ieee->iw_mode != IW_MODE_INFRA &&
686 ieee->reset_port && ieee->reset_port(dev)) {
687 IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
688 return -EINVAL;
691 return ret;
694 int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee,
695 struct iw_request_info *info,
696 union iwreq_data *wrqu, char *extra)
698 struct iw_point *encoding = &wrqu->encoding;
699 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
700 struct ieee80211_security *sec = &ieee->sec;
701 int idx, max_key_len;
703 max_key_len = encoding->length - sizeof(*ext);
704 if (max_key_len < 0)
705 return -EINVAL;
707 idx = encoding->flags & IW_ENCODE_INDEX;
708 if (idx) {
709 if (idx < 1 || idx > WEP_KEYS)
710 return -EINVAL;
711 idx--;
712 } else
713 idx = ieee->tx_keyidx;
715 if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY &&
716 ext->alg != IW_ENCODE_ALG_WEP)
717 if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
718 return -EINVAL;
720 encoding->flags = idx + 1;
721 memset(ext, 0, sizeof(*ext));
723 if (!sec->enabled) {
724 ext->alg = IW_ENCODE_ALG_NONE;
725 ext->key_len = 0;
726 encoding->flags |= IW_ENCODE_DISABLED;
727 } else {
728 if (sec->encode_alg[idx] == SEC_ALG_WEP)
729 ext->alg = IW_ENCODE_ALG_WEP;
730 else if (sec->encode_alg[idx] == SEC_ALG_TKIP)
731 ext->alg = IW_ENCODE_ALG_TKIP;
732 else if (sec->encode_alg[idx] == SEC_ALG_CCMP)
733 ext->alg = IW_ENCODE_ALG_CCMP;
734 else
735 return -EINVAL;
737 ext->key_len = sec->key_sizes[idx];
738 memcpy(ext->key, sec->keys[idx], ext->key_len);
739 encoding->flags |= IW_ENCODE_ENABLED;
740 if (ext->key_len &&
741 (ext->alg == IW_ENCODE_ALG_TKIP ||
742 ext->alg == IW_ENCODE_ALG_CCMP))
743 ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
747 return 0;
750 int ieee80211_wx_set_auth(struct net_device *dev,
751 struct iw_request_info *info,
752 union iwreq_data *wrqu,
753 char *extra)
755 struct ieee80211_device *ieee = netdev_priv(dev);
756 unsigned long flags;
757 int err = 0;
759 spin_lock_irqsave(&ieee->lock, flags);
761 switch (wrqu->param.flags & IW_AUTH_INDEX) {
762 case IW_AUTH_WPA_VERSION:
763 case IW_AUTH_CIPHER_PAIRWISE:
764 case IW_AUTH_CIPHER_GROUP:
765 case IW_AUTH_KEY_MGMT:
767 * Host AP driver does not use these parameters and allows
768 * wpa_supplicant to control them internally.
770 break;
771 case IW_AUTH_TKIP_COUNTERMEASURES:
772 break; /* FIXME */
773 case IW_AUTH_DROP_UNENCRYPTED:
774 ieee->drop_unencrypted = !!wrqu->param.value;
775 break;
776 case IW_AUTH_80211_AUTH_ALG:
777 break; /* FIXME */
778 case IW_AUTH_WPA_ENABLED:
779 ieee->privacy_invoked = ieee->wpa_enabled = !!wrqu->param.value;
780 break;
781 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
782 ieee->ieee802_1x = !!wrqu->param.value;
783 break;
784 case IW_AUTH_PRIVACY_INVOKED:
785 ieee->privacy_invoked = !!wrqu->param.value;
786 break;
787 default:
788 err = -EOPNOTSUPP;
789 break;
791 spin_unlock_irqrestore(&ieee->lock, flags);
792 return err;
795 int ieee80211_wx_get_auth(struct net_device *dev,
796 struct iw_request_info *info,
797 union iwreq_data *wrqu,
798 char *extra)
800 struct ieee80211_device *ieee = netdev_priv(dev);
801 unsigned long flags;
802 int err = 0;
804 spin_lock_irqsave(&ieee->lock, flags);
806 switch (wrqu->param.flags & IW_AUTH_INDEX) {
807 case IW_AUTH_WPA_VERSION:
808 case IW_AUTH_CIPHER_PAIRWISE:
809 case IW_AUTH_CIPHER_GROUP:
810 case IW_AUTH_KEY_MGMT:
811 case IW_AUTH_TKIP_COUNTERMEASURES: /* FIXME */
812 case IW_AUTH_80211_AUTH_ALG: /* FIXME */
814 * Host AP driver does not use these parameters and allows
815 * wpa_supplicant to control them internally.
817 err = -EOPNOTSUPP;
818 break;
819 case IW_AUTH_DROP_UNENCRYPTED:
820 wrqu->param.value = ieee->drop_unencrypted;
821 break;
822 case IW_AUTH_WPA_ENABLED:
823 wrqu->param.value = ieee->wpa_enabled;
824 break;
825 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
826 wrqu->param.value = ieee->ieee802_1x;
827 break;
828 default:
829 err = -EOPNOTSUPP;
830 break;
832 spin_unlock_irqrestore(&ieee->lock, flags);
833 return err;
836 EXPORT_SYMBOL(ieee80211_wx_set_encodeext);
837 EXPORT_SYMBOL(ieee80211_wx_get_encodeext);
839 EXPORT_SYMBOL(ieee80211_wx_get_scan);
840 EXPORT_SYMBOL(ieee80211_wx_set_encode);
841 EXPORT_SYMBOL(ieee80211_wx_get_encode);
843 EXPORT_SYMBOL_GPL(ieee80211_wx_set_auth);
844 EXPORT_SYMBOL_GPL(ieee80211_wx_get_auth);