[IPV6] NDISC: Add proxy_ndp sysctl.
[hh.org.git] / net / ieee80211 / ieee80211_wx.c
blob5cb9cfd35397dadc60c66a0048945ec88a57d8a0
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 = kzalloc(sizeof(struct ieee80211_crypt_data),
373 GFP_KERNEL);
374 if (new_crypt == NULL)
375 return -ENOMEM;
376 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
377 if (!new_crypt->ops) {
378 request_module("ieee80211_crypt_wep");
379 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
382 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
383 new_crypt->priv = new_crypt->ops->init(key);
385 if (!new_crypt->ops || !new_crypt->priv) {
386 kfree(new_crypt);
387 new_crypt = NULL;
389 printk(KERN_WARNING "%s: could not initialize WEP: "
390 "load module ieee80211_crypt_wep\n", dev->name);
391 return -EOPNOTSUPP;
393 *crypt = new_crypt;
396 /* If a new key was provided, set it up */
397 if (erq->length > 0) {
398 len = erq->length <= 5 ? 5 : 13;
399 memcpy(sec.keys[key], keybuf, erq->length);
400 if (len > erq->length)
401 memset(sec.keys[key] + erq->length, 0,
402 len - erq->length);
403 IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
404 key, escape_essid(sec.keys[key], len),
405 erq->length, len);
406 sec.key_sizes[key] = len;
407 if (*crypt)
408 (*crypt)->ops->set_key(sec.keys[key], len, NULL,
409 (*crypt)->priv);
410 sec.flags |= (1 << key);
411 /* This ensures a key will be activated if no key is
412 * explicitely set */
413 if (key == sec.active_key)
414 sec.flags |= SEC_ACTIVE_KEY;
416 } else {
417 if (host_crypto) {
418 len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
419 NULL, (*crypt)->priv);
420 if (len == 0) {
421 /* Set a default key of all 0 */
422 IEEE80211_DEBUG_WX("Setting key %d to all "
423 "zero.\n", key);
424 memset(sec.keys[key], 0, 13);
425 (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
426 (*crypt)->priv);
427 sec.key_sizes[key] = 13;
428 sec.flags |= (1 << key);
431 /* No key data - just set the default TX key index */
432 if (key_provided) {
433 IEEE80211_DEBUG_WX("Setting key %d to default Tx "
434 "key.\n", key);
435 ieee->tx_keyidx = key;
436 sec.active_key = key;
437 sec.flags |= SEC_ACTIVE_KEY;
440 if (erq->flags & (IW_ENCODE_OPEN | IW_ENCODE_RESTRICTED)) {
441 ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
442 sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN :
443 WLAN_AUTH_SHARED_KEY;
444 sec.flags |= SEC_AUTH_MODE;
445 IEEE80211_DEBUG_WX("Auth: %s\n",
446 sec.auth_mode == WLAN_AUTH_OPEN ?
447 "OPEN" : "SHARED KEY");
450 /* For now we just support WEP, so only set that security level...
451 * TODO: When WPA is added this is one place that needs to change */
452 sec.flags |= SEC_LEVEL;
453 sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
454 sec.encode_alg[key] = SEC_ALG_WEP;
456 done:
457 if (ieee->set_security)
458 ieee->set_security(dev, &sec);
460 /* Do not reset port if card is in Managed mode since resetting will
461 * generate new IEEE 802.11 authentication which may end up in looping
462 * with IEEE 802.1X. If your hardware requires a reset after WEP
463 * configuration (for example... Prism2), implement the reset_port in
464 * the callbacks structures used to initialize the 802.11 stack. */
465 if (ieee->reset_on_keychange &&
466 ieee->iw_mode != IW_MODE_INFRA &&
467 ieee->reset_port && ieee->reset_port(dev)) {
468 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
469 return -EINVAL;
471 return 0;
474 int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
475 struct iw_request_info *info,
476 union iwreq_data *wrqu, char *keybuf)
478 struct iw_point *erq = &(wrqu->encoding);
479 int len, key;
480 struct ieee80211_crypt_data *crypt;
481 struct ieee80211_security *sec = &ieee->sec;
483 IEEE80211_DEBUG_WX("GET_ENCODE\n");
485 key = erq->flags & IW_ENCODE_INDEX;
486 if (key) {
487 if (key > WEP_KEYS)
488 return -EINVAL;
489 key--;
490 } else
491 key = ieee->tx_keyidx;
493 crypt = ieee->crypt[key];
494 erq->flags = key + 1;
496 if (!sec->enabled) {
497 erq->length = 0;
498 erq->flags |= IW_ENCODE_DISABLED;
499 return 0;
502 len = sec->key_sizes[key];
503 memcpy(keybuf, sec->keys[key], len);
505 erq->length = len;
506 erq->flags |= IW_ENCODE_ENABLED;
508 if (ieee->open_wep)
509 erq->flags |= IW_ENCODE_OPEN;
510 else
511 erq->flags |= IW_ENCODE_RESTRICTED;
513 return 0;
516 int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee,
517 struct iw_request_info *info,
518 union iwreq_data *wrqu, char *extra)
520 struct net_device *dev = ieee->dev;
521 struct iw_point *encoding = &wrqu->encoding;
522 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
523 int i, idx, ret = 0;
524 int group_key = 0;
525 const char *alg, *module;
526 struct ieee80211_crypto_ops *ops;
527 struct ieee80211_crypt_data **crypt;
529 struct ieee80211_security sec = {
530 .flags = 0,
533 idx = encoding->flags & IW_ENCODE_INDEX;
534 if (idx) {
535 if (idx < 1 || idx > WEP_KEYS)
536 return -EINVAL;
537 idx--;
538 } else
539 idx = ieee->tx_keyidx;
541 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
542 crypt = &ieee->crypt[idx];
543 group_key = 1;
544 } else {
545 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
546 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
547 return -EINVAL;
548 if (ieee->iw_mode == IW_MODE_INFRA)
549 crypt = &ieee->crypt[idx];
550 else
551 return -EINVAL;
554 sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
555 if ((encoding->flags & IW_ENCODE_DISABLED) ||
556 ext->alg == IW_ENCODE_ALG_NONE) {
557 if (*crypt)
558 ieee80211_crypt_delayed_deinit(ieee, crypt);
560 for (i = 0; i < WEP_KEYS; i++)
561 if (ieee->crypt[i] != NULL)
562 break;
564 if (i == WEP_KEYS) {
565 sec.enabled = 0;
566 sec.encrypt = 0;
567 sec.level = SEC_LEVEL_0;
568 sec.flags |= SEC_LEVEL;
570 goto done;
573 sec.enabled = 1;
574 sec.encrypt = 1;
576 if (group_key ? !ieee->host_mc_decrypt :
577 !(ieee->host_encrypt || ieee->host_decrypt ||
578 ieee->host_encrypt_msdu))
579 goto skip_host_crypt;
581 switch (ext->alg) {
582 case IW_ENCODE_ALG_WEP:
583 alg = "WEP";
584 module = "ieee80211_crypt_wep";
585 break;
586 case IW_ENCODE_ALG_TKIP:
587 alg = "TKIP";
588 module = "ieee80211_crypt_tkip";
589 break;
590 case IW_ENCODE_ALG_CCMP:
591 alg = "CCMP";
592 module = "ieee80211_crypt_ccmp";
593 break;
594 default:
595 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
596 dev->name, ext->alg);
597 ret = -EINVAL;
598 goto done;
601 ops = ieee80211_get_crypto_ops(alg);
602 if (ops == NULL) {
603 request_module(module);
604 ops = ieee80211_get_crypto_ops(alg);
606 if (ops == NULL) {
607 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
608 dev->name, ext->alg);
609 ret = -EINVAL;
610 goto done;
613 if (*crypt == NULL || (*crypt)->ops != ops) {
614 struct ieee80211_crypt_data *new_crypt;
616 ieee80211_crypt_delayed_deinit(ieee, crypt);
618 new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
619 if (new_crypt == NULL) {
620 ret = -ENOMEM;
621 goto done;
623 new_crypt->ops = ops;
624 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
625 new_crypt->priv = new_crypt->ops->init(idx);
626 if (new_crypt->priv == NULL) {
627 kfree(new_crypt);
628 ret = -EINVAL;
629 goto done;
631 *crypt = new_crypt;
634 if (ext->key_len > 0 && (*crypt)->ops->set_key &&
635 (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
636 (*crypt)->priv) < 0) {
637 IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
638 ret = -EINVAL;
639 goto done;
642 skip_host_crypt:
643 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
644 ieee->tx_keyidx = idx;
645 sec.active_key = idx;
646 sec.flags |= SEC_ACTIVE_KEY;
649 if (ext->alg != IW_ENCODE_ALG_NONE) {
650 memcpy(sec.keys[idx], ext->key, ext->key_len);
651 sec.key_sizes[idx] = ext->key_len;
652 sec.flags |= (1 << idx);
653 if (ext->alg == IW_ENCODE_ALG_WEP) {
654 sec.encode_alg[idx] = SEC_ALG_WEP;
655 sec.flags |= SEC_LEVEL;
656 sec.level = SEC_LEVEL_1;
657 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
658 sec.encode_alg[idx] = SEC_ALG_TKIP;
659 sec.flags |= SEC_LEVEL;
660 sec.level = SEC_LEVEL_2;
661 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
662 sec.encode_alg[idx] = SEC_ALG_CCMP;
663 sec.flags |= SEC_LEVEL;
664 sec.level = SEC_LEVEL_3;
666 /* Don't set sec level for group keys. */
667 if (group_key)
668 sec.flags &= ~SEC_LEVEL;
670 done:
671 if (ieee->set_security)
672 ieee->set_security(ieee->dev, &sec);
675 * Do not reset port if card is in Managed mode since resetting will
676 * generate new IEEE 802.11 authentication which may end up in looping
677 * with IEEE 802.1X. If your hardware requires a reset after WEP
678 * configuration (for example... Prism2), implement the reset_port in
679 * the callbacks structures used to initialize the 802.11 stack.
681 if (ieee->reset_on_keychange &&
682 ieee->iw_mode != IW_MODE_INFRA &&
683 ieee->reset_port && ieee->reset_port(dev)) {
684 IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
685 return -EINVAL;
688 return ret;
691 int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee,
692 struct iw_request_info *info,
693 union iwreq_data *wrqu, char *extra)
695 struct iw_point *encoding = &wrqu->encoding;
696 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
697 struct ieee80211_security *sec = &ieee->sec;
698 int idx, max_key_len;
700 max_key_len = encoding->length - sizeof(*ext);
701 if (max_key_len < 0)
702 return -EINVAL;
704 idx = encoding->flags & IW_ENCODE_INDEX;
705 if (idx) {
706 if (idx < 1 || idx > WEP_KEYS)
707 return -EINVAL;
708 idx--;
709 } else
710 idx = ieee->tx_keyidx;
712 if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY &&
713 ext->alg != IW_ENCODE_ALG_WEP)
714 if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
715 return -EINVAL;
717 encoding->flags = idx + 1;
718 memset(ext, 0, sizeof(*ext));
720 if (!sec->enabled) {
721 ext->alg = IW_ENCODE_ALG_NONE;
722 ext->key_len = 0;
723 encoding->flags |= IW_ENCODE_DISABLED;
724 } else {
725 if (sec->encode_alg[idx] == SEC_ALG_WEP)
726 ext->alg = IW_ENCODE_ALG_WEP;
727 else if (sec->encode_alg[idx] == SEC_ALG_TKIP)
728 ext->alg = IW_ENCODE_ALG_TKIP;
729 else if (sec->encode_alg[idx] == SEC_ALG_CCMP)
730 ext->alg = IW_ENCODE_ALG_CCMP;
731 else
732 return -EINVAL;
734 ext->key_len = sec->key_sizes[idx];
735 memcpy(ext->key, sec->keys[idx], ext->key_len);
736 encoding->flags |= IW_ENCODE_ENABLED;
737 if (ext->key_len &&
738 (ext->alg == IW_ENCODE_ALG_TKIP ||
739 ext->alg == IW_ENCODE_ALG_CCMP))
740 ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
744 return 0;
747 int ieee80211_wx_set_auth(struct net_device *dev,
748 struct iw_request_info *info,
749 union iwreq_data *wrqu,
750 char *extra)
752 struct ieee80211_device *ieee = netdev_priv(dev);
753 unsigned long flags;
754 int err = 0;
756 spin_lock_irqsave(&ieee->lock, flags);
758 switch (wrqu->param.flags & IW_AUTH_INDEX) {
759 case IW_AUTH_WPA_VERSION:
760 case IW_AUTH_CIPHER_PAIRWISE:
761 case IW_AUTH_CIPHER_GROUP:
762 case IW_AUTH_KEY_MGMT:
764 * Host AP driver does not use these parameters and allows
765 * wpa_supplicant to control them internally.
767 break;
768 case IW_AUTH_TKIP_COUNTERMEASURES:
769 break; /* FIXME */
770 case IW_AUTH_DROP_UNENCRYPTED:
771 ieee->drop_unencrypted = !!wrqu->param.value;
772 break;
773 case IW_AUTH_80211_AUTH_ALG:
774 break; /* FIXME */
775 case IW_AUTH_WPA_ENABLED:
776 ieee->privacy_invoked = ieee->wpa_enabled = !!wrqu->param.value;
777 break;
778 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
779 ieee->ieee802_1x = !!wrqu->param.value;
780 break;
781 case IW_AUTH_PRIVACY_INVOKED:
782 ieee->privacy_invoked = !!wrqu->param.value;
783 break;
784 default:
785 err = -EOPNOTSUPP;
786 break;
788 spin_unlock_irqrestore(&ieee->lock, flags);
789 return err;
792 int ieee80211_wx_get_auth(struct net_device *dev,
793 struct iw_request_info *info,
794 union iwreq_data *wrqu,
795 char *extra)
797 struct ieee80211_device *ieee = netdev_priv(dev);
798 unsigned long flags;
799 int err = 0;
801 spin_lock_irqsave(&ieee->lock, flags);
803 switch (wrqu->param.flags & IW_AUTH_INDEX) {
804 case IW_AUTH_WPA_VERSION:
805 case IW_AUTH_CIPHER_PAIRWISE:
806 case IW_AUTH_CIPHER_GROUP:
807 case IW_AUTH_KEY_MGMT:
808 case IW_AUTH_TKIP_COUNTERMEASURES: /* FIXME */
809 case IW_AUTH_80211_AUTH_ALG: /* FIXME */
811 * Host AP driver does not use these parameters and allows
812 * wpa_supplicant to control them internally.
814 err = -EOPNOTSUPP;
815 break;
816 case IW_AUTH_DROP_UNENCRYPTED:
817 wrqu->param.value = ieee->drop_unencrypted;
818 break;
819 case IW_AUTH_WPA_ENABLED:
820 wrqu->param.value = ieee->wpa_enabled;
821 break;
822 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
823 wrqu->param.value = ieee->ieee802_1x;
824 break;
825 default:
826 err = -EOPNOTSUPP;
827 break;
829 spin_unlock_irqrestore(&ieee->lock, flags);
830 return err;
833 EXPORT_SYMBOL(ieee80211_wx_set_encodeext);
834 EXPORT_SYMBOL(ieee80211_wx_get_encodeext);
836 EXPORT_SYMBOL(ieee80211_wx_get_scan);
837 EXPORT_SYMBOL(ieee80211_wx_set_encode);
838 EXPORT_SYMBOL(ieee80211_wx_get_encode);
840 EXPORT_SYMBOL_GPL(ieee80211_wx_set_auth);
841 EXPORT_SYMBOL_GPL(ieee80211_wx_get_auth);