Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland...
[wrt350n-kernel.git] / net / ieee80211 / ieee80211_wx.c
blob623489afa62c223e3f4b9d3ee1963c5aea2c1479
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 <j@w1.fi>
9 Copyright (c) 2002-2003, Jouni Malinen <j@w1.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 channel and frequency */
93 /* Note : userspace automatically computes channel using iwrange */
94 iwe.cmd = SIOCGIWFREQ;
95 iwe.u.freq.m = ieee80211_channel_to_freq(ieee, network->channel);
96 iwe.u.freq.e = 6;
97 iwe.u.freq.i = 0;
98 start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN);
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);
109 /* Add basic and extended rates */
110 /* Rate : stuffing multiple values in a single event require a bit
111 * more of magic - Jean II */
112 current_val = start + IW_EV_LCP_LEN;
113 iwe.cmd = SIOCGIWRATE;
114 /* Those two flags are ignored... */
115 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
117 for (i = 0, j = 0; i < network->rates_len;) {
118 if (j < network->rates_ex_len &&
119 ((network->rates_ex[j] & 0x7F) <
120 (network->rates[i] & 0x7F)))
121 rate = network->rates_ex[j++] & 0x7F;
122 else
123 rate = network->rates[i++] & 0x7F;
124 /* Bit rate given in 500 kb/s units (+ 0x80) */
125 iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
126 /* Add new value to event */
127 current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN);
129 for (; j < network->rates_ex_len; j++) {
130 rate = network->rates_ex[j] & 0x7F;
131 /* Bit rate given in 500 kb/s units (+ 0x80) */
132 iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
133 /* Add new value to event */
134 current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN);
136 /* Check if we added any rate */
137 if((current_val - start) > IW_EV_LCP_LEN)
138 start = current_val;
140 /* Add quality statistics */
141 iwe.cmd = IWEVQUAL;
142 iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
143 IW_QUAL_NOISE_UPDATED;
145 if (!(network->stats.mask & IEEE80211_STATMASK_RSSI)) {
146 iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID |
147 IW_QUAL_LEVEL_INVALID;
148 iwe.u.qual.qual = 0;
149 } else {
150 if (ieee->perfect_rssi == ieee->worst_rssi)
151 iwe.u.qual.qual = 100;
152 else
153 iwe.u.qual.qual =
154 (100 *
155 (ieee->perfect_rssi - ieee->worst_rssi) *
156 (ieee->perfect_rssi - ieee->worst_rssi) -
157 (ieee->perfect_rssi - network->stats.rssi) *
158 (15 * (ieee->perfect_rssi - ieee->worst_rssi) +
159 62 * (ieee->perfect_rssi -
160 network->stats.rssi))) /
161 ((ieee->perfect_rssi -
162 ieee->worst_rssi) * (ieee->perfect_rssi -
163 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;
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;
177 if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL)) {
178 iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
179 iwe.u.qual.level = 0;
180 } else {
181 iwe.u.qual.level = network->stats.signal;
184 start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN);
186 iwe.cmd = IWEVCUSTOM;
187 p = custom;
189 iwe.u.data.length = p - custom;
190 if (iwe.u.data.length)
191 start = iwe_stream_add_point(start, stop, &iwe, custom);
193 memset(&iwe, 0, sizeof(iwe));
194 if (network->wpa_ie_len) {
195 char buf[MAX_WPA_IE_LEN];
196 memcpy(buf, network->wpa_ie, network->wpa_ie_len);
197 iwe.cmd = IWEVGENIE;
198 iwe.u.data.length = network->wpa_ie_len;
199 start = iwe_stream_add_point(start, stop, &iwe, buf);
202 memset(&iwe, 0, sizeof(iwe));
203 if (network->rsn_ie_len) {
204 char buf[MAX_WPA_IE_LEN];
205 memcpy(buf, network->rsn_ie, network->rsn_ie_len);
206 iwe.cmd = IWEVGENIE;
207 iwe.u.data.length = network->rsn_ie_len;
208 start = iwe_stream_add_point(start, stop, &iwe, buf);
211 /* Add EXTRA: Age to display seconds since last beacon/probe response
212 * for given network. */
213 iwe.cmd = IWEVCUSTOM;
214 p = custom;
215 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
216 " Last beacon: %dms ago",
217 jiffies_to_msecs(jiffies - network->last_scanned));
218 iwe.u.data.length = p - custom;
219 if (iwe.u.data.length)
220 start = iwe_stream_add_point(start, stop, &iwe, custom);
222 /* Add spectrum management information */
223 iwe.cmd = -1;
224 p = custom;
225 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Channel flags: ");
227 if (ieee80211_get_channel_flags(ieee, network->channel) &
228 IEEE80211_CH_INVALID) {
229 iwe.cmd = IWEVCUSTOM;
230 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "INVALID ");
233 if (ieee80211_get_channel_flags(ieee, network->channel) &
234 IEEE80211_CH_RADAR_DETECT) {
235 iwe.cmd = IWEVCUSTOM;
236 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "DFS ");
239 if (iwe.cmd == IWEVCUSTOM) {
240 iwe.u.data.length = p - custom;
241 start = iwe_stream_add_point(start, stop, &iwe, custom);
244 return start;
247 #define SCAN_ITEM_SIZE 128
249 int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
250 struct iw_request_info *info,
251 union iwreq_data *wrqu, char *extra)
253 struct ieee80211_network *network;
254 unsigned long flags;
255 int err = 0;
257 char *ev = extra;
258 char *stop = ev + wrqu->data.length;
259 int i = 0;
260 DECLARE_MAC_BUF(mac);
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 "%s)' due to age (%dms).\n",
279 escape_essid(network->ssid,
280 network->ssid_len),
281 print_mac(mac, 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 * explicitly 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);