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
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
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
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 inline char *ipw2100_translate_scan(struct ieee80211_device *ieee,
46 char *start, char *stop,
47 struct ieee80211_network *network)
49 char custom[MAX_CUSTOM_LEN];
55 /* First entry *MUST* be the AP MAC address */
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);
61 /* Remaining entries will be displayed in the order we provide them */
64 iwe.cmd = SIOCGIWESSID;
66 if (network->flags & NETWORK_EMPTY_ESSID) {
67 iwe.u.data.length = sizeof("<hidden>");
68 start = iwe_stream_add_point(start, stop, &iwe, "<hidden>");
70 iwe.u.data.length = min(network->ssid_len, (u8) 32);
71 start = iwe_stream_add_point(start, stop, &iwe, network->ssid);
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);
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;
86 iwe.u.mode = IW_MODE_ADHOC;
88 start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN);
91 /* Add frequency/channel */
92 iwe.cmd = SIOCGIWFREQ;
93 /* iwe.u.freq.m = ieee80211_frequency(network->channel, network->mode);
95 iwe.u.freq.m = network->channel;
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;
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 */
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;
119 rate = network->rates[i++] & 0x7F;
122 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
123 "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
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" : "");
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);
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);
143 /* Add quality statistics */
145 iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
146 IW_QUAL_NOISE_UPDATED;
148 if (!(network->stats.mask & IEEE80211_STATMASK_RSSI)) {
149 iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID |
150 IW_QUAL_LEVEL_INVALID;
152 iwe.u.qual.level = 0;
154 iwe.u.qual.level = network->stats.rssi;
155 if (ieee->perfect_rssi == ieee->worst_rssi)
156 iwe.u.qual.qual = 100;
160 (ieee->perfect_rssi - ieee->worst_rssi) *
161 (ieee->perfect_rssi - ieee->worst_rssi) -
162 (ieee->perfect_rssi - network->stats.rssi) *
163 (15 * (ieee->perfect_rssi - ieee->worst_rssi) +
164 62 * (ieee->perfect_rssi - network->stats.rssi))) /
165 ((ieee->perfect_rssi - ieee->worst_rssi) *
166 (ieee->perfect_rssi - ieee->worst_rssi));
167 if (iwe.u.qual.qual > 100)
168 iwe.u.qual.qual = 100;
169 else if (iwe.u.qual.qual < 1)
173 if (!(network->stats.mask & IEEE80211_STATMASK_NOISE)) {
174 iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
175 iwe.u.qual.noise = 0;
177 iwe.u.qual.noise = network->stats.noise;
180 start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN);
182 iwe.cmd = IWEVCUSTOM;
185 iwe.u.data.length = p - custom;
186 if (iwe.u.data.length)
187 start = iwe_stream_add_point(start, stop, &iwe, custom);
189 if (network->wpa_ie_len) {
190 char buf[MAX_WPA_IE_LEN * 2 + 30];
193 p += sprintf(p, "wpa_ie=");
194 for (i = 0; i < network->wpa_ie_len; i++) {
195 p += sprintf(p, "%02x", network->wpa_ie[i]);
198 memset(&iwe, 0, sizeof(iwe));
199 iwe.cmd = IWEVCUSTOM;
200 iwe.u.data.length = strlen(buf);
201 start = iwe_stream_add_point(start, stop, &iwe, buf);
204 if (network->rsn_ie_len) {
205 char buf[MAX_WPA_IE_LEN * 2 + 30];
208 p += sprintf(p, "rsn_ie=");
209 for (i = 0; i < network->rsn_ie_len; i++) {
210 p += sprintf(p, "%02x", network->rsn_ie[i]);
213 memset(&iwe, 0, sizeof(iwe));
214 iwe.cmd = IWEVCUSTOM;
215 iwe.u.data.length = strlen(buf);
216 start = iwe_stream_add_point(start, stop, &iwe, buf);
219 /* Add EXTRA: Age to display seconds since last beacon/probe response
220 * for given network. */
221 iwe.cmd = IWEVCUSTOM;
223 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
224 " Last beacon: %dms ago",
225 jiffies_to_msecs(jiffies - network->last_scanned));
226 iwe.u.data.length = p - custom;
227 if (iwe.u.data.length)
228 start = iwe_stream_add_point(start, stop, &iwe, custom);
233 int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
234 struct iw_request_info *info,
235 union iwreq_data *wrqu, char *extra)
237 struct ieee80211_network *network;
241 char *stop = ev + IW_SCAN_MAX_DATA;
244 IEEE80211_DEBUG_WX("Getting scan\n");
246 spin_lock_irqsave(&ieee->lock, flags);
248 list_for_each_entry(network, &ieee->network_list, list) {
250 if (ieee->scan_age == 0 ||
251 time_after(network->last_scanned + ieee->scan_age, jiffies))
252 ev = ipw2100_translate_scan(ieee, ev, stop, network);
254 IEEE80211_DEBUG_SCAN("Not showing network '%s ("
255 MAC_FMT ")' due to age (%dms).\n",
256 escape_essid(network->ssid,
258 MAC_ARG(network->bssid),
259 jiffies_to_msecs(jiffies -
264 spin_unlock_irqrestore(&ieee->lock, flags);
266 wrqu->data.length = ev - extra;
267 wrqu->data.flags = 0;
269 IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
274 int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
275 struct iw_request_info *info,
276 union iwreq_data *wrqu, char *keybuf)
278 struct iw_point *erq = &(wrqu->encoding);
279 struct net_device *dev = ieee->dev;
280 struct ieee80211_security sec = {
283 int i, key, key_provided, len;
284 struct ieee80211_crypt_data **crypt;
285 int host_crypto = ieee->host_encrypt || ieee->host_decrypt;
287 IEEE80211_DEBUG_WX("SET_ENCODE\n");
289 key = erq->flags & IW_ENCODE_INDEX;
297 key = ieee->tx_keyidx;
300 IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
301 "provided" : "default");
303 crypt = &ieee->crypt[key];
305 if (erq->flags & IW_ENCODE_DISABLED) {
306 if (key_provided && *crypt) {
307 IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n",
309 ieee80211_crypt_delayed_deinit(ieee, crypt);
311 IEEE80211_DEBUG_WX("Disabling encryption.\n");
313 /* Check all the keys to see if any are still configured,
314 * and if no key index was provided, de-init them all */
315 for (i = 0; i < WEP_KEYS; i++) {
316 if (ieee->crypt[i] != NULL) {
319 ieee80211_crypt_delayed_deinit(ieee,
327 sec.level = SEC_LEVEL_0;
328 sec.flags |= SEC_ENABLED | SEC_LEVEL | SEC_ENCRYPT;
336 sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
338 if (*crypt != NULL && (*crypt)->ops != NULL &&
339 strcmp((*crypt)->ops->name, "WEP") != 0) {
340 /* changing to use WEP; deinit previously used algorithm
342 ieee80211_crypt_delayed_deinit(ieee, crypt);
345 if (*crypt == NULL && host_crypto) {
346 struct ieee80211_crypt_data *new_crypt;
348 /* take WEP into use */
349 new_crypt = kmalloc(sizeof(struct ieee80211_crypt_data),
351 if (new_crypt == NULL)
353 memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
354 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
355 if (!new_crypt->ops) {
356 request_module("ieee80211_crypt_wep");
357 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
360 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
361 new_crypt->priv = new_crypt->ops->init(key);
363 if (!new_crypt->ops || !new_crypt->priv) {
367 printk(KERN_WARNING "%s: could not initialize WEP: "
368 "load module ieee80211_crypt_wep\n", dev->name);
374 /* If a new key was provided, set it up */
375 if (erq->length > 0) {
376 len = erq->length <= 5 ? 5 : 13;
377 memcpy(sec.keys[key], keybuf, erq->length);
378 if (len > erq->length)
379 memset(sec.keys[key] + erq->length, 0,
381 IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
382 key, escape_essid(sec.keys[key], len),
384 sec.key_sizes[key] = len;
386 (*crypt)->ops->set_key(sec.keys[key], len, NULL,
388 sec.flags |= (1 << key);
389 /* This ensures a key will be activated if no key is
391 if (key == sec.active_key)
392 sec.flags |= SEC_ACTIVE_KEY;
396 len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
397 NULL, (*crypt)->priv);
399 /* Set a default key of all 0 */
400 IEEE80211_DEBUG_WX("Setting key %d to all "
402 memset(sec.keys[key], 0, 13);
403 (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
405 sec.key_sizes[key] = 13;
406 sec.flags |= (1 << key);
409 /* No key data - just set the default TX key index */
411 IEEE80211_DEBUG_WX("Setting key %d to default Tx "
413 ieee->tx_keyidx = key;
414 sec.active_key = key;
415 sec.flags |= SEC_ACTIVE_KEY;
418 if (erq->flags & (IW_ENCODE_OPEN | IW_ENCODE_RESTRICTED)) {
419 ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
420 sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN :
421 WLAN_AUTH_SHARED_KEY;
422 sec.flags |= SEC_AUTH_MODE;
423 IEEE80211_DEBUG_WX("Auth: %s\n",
424 sec.auth_mode == WLAN_AUTH_OPEN ?
425 "OPEN" : "SHARED KEY");
428 /* For now we just support WEP, so only set that security level...
429 * TODO: When WPA is added this is one place that needs to change */
430 sec.flags |= SEC_LEVEL;
431 sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
432 sec.encode_alg[key] = SEC_ALG_WEP;
435 if (ieee->set_security)
436 ieee->set_security(dev, &sec);
438 /* Do not reset port if card is in Managed mode since resetting will
439 * generate new IEEE 802.11 authentication which may end up in looping
440 * with IEEE 802.1X. If your hardware requires a reset after WEP
441 * configuration (for example... Prism2), implement the reset_port in
442 * the callbacks structures used to initialize the 802.11 stack. */
443 if (ieee->reset_on_keychange &&
444 ieee->iw_mode != IW_MODE_INFRA &&
445 ieee->reset_port && ieee->reset_port(dev)) {
446 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
452 int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
453 struct iw_request_info *info,
454 union iwreq_data *wrqu, char *keybuf)
456 struct iw_point *erq = &(wrqu->encoding);
458 struct ieee80211_crypt_data *crypt;
459 struct ieee80211_security *sec = &ieee->sec;
461 IEEE80211_DEBUG_WX("GET_ENCODE\n");
463 key = erq->flags & IW_ENCODE_INDEX;
469 key = ieee->tx_keyidx;
471 crypt = ieee->crypt[key];
472 erq->flags = key + 1;
476 erq->flags |= IW_ENCODE_DISABLED;
480 len = sec->key_sizes[key];
481 memcpy(keybuf, sec->keys[key], len);
483 erq->length = (len >= 0 ? len : 0);
484 erq->flags |= IW_ENCODE_ENABLED;
487 erq->flags |= IW_ENCODE_OPEN;
489 erq->flags |= IW_ENCODE_RESTRICTED;
494 int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee,
495 struct iw_request_info *info,
496 union iwreq_data *wrqu, char *extra)
498 struct net_device *dev = ieee->dev;
499 struct iw_point *encoding = &wrqu->encoding;
500 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
503 const char *alg, *module;
504 struct ieee80211_crypto_ops *ops;
505 struct ieee80211_crypt_data **crypt;
507 struct ieee80211_security sec = {
511 idx = encoding->flags & IW_ENCODE_INDEX;
513 if (idx < 1 || idx > WEP_KEYS)
517 idx = ieee->tx_keyidx;
519 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
520 crypt = &ieee->crypt[idx];
525 if (ieee->iw_mode == IW_MODE_INFRA)
526 crypt = &ieee->crypt[idx];
531 sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
532 if ((encoding->flags & IW_ENCODE_DISABLED) ||
533 ext->alg == IW_ENCODE_ALG_NONE) {
535 ieee80211_crypt_delayed_deinit(ieee, crypt);
537 for (i = 0; i < WEP_KEYS; i++)
538 if (ieee->crypt[i] != NULL)
544 sec.level = SEC_LEVEL_0;
545 sec.flags |= SEC_LEVEL;
553 if (group_key ? !ieee->host_mc_decrypt :
554 !(ieee->host_encrypt || ieee->host_decrypt ||
555 ieee->host_encrypt_msdu))
556 goto skip_host_crypt;
559 case IW_ENCODE_ALG_WEP:
561 module = "ieee80211_crypt_wep";
563 case IW_ENCODE_ALG_TKIP:
565 module = "ieee80211_crypt_tkip";
567 case IW_ENCODE_ALG_CCMP:
569 module = "ieee80211_crypt_ccmp";
572 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
573 dev->name, ext->alg);
578 ops = ieee80211_get_crypto_ops(alg);
580 request_module(module);
581 ops = ieee80211_get_crypto_ops(alg);
584 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
585 dev->name, ext->alg);
590 if (*crypt == NULL || (*crypt)->ops != ops) {
591 struct ieee80211_crypt_data *new_crypt;
593 ieee80211_crypt_delayed_deinit(ieee, crypt);
595 new_crypt = (struct ieee80211_crypt_data *)
596 kmalloc(sizeof(*new_crypt), GFP_KERNEL);
597 if (new_crypt == NULL) {
601 memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
602 new_crypt->ops = ops;
603 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
604 new_crypt->priv = new_crypt->ops->init(idx);
605 if (new_crypt->priv == NULL) {
613 if (ext->key_len > 0 && (*crypt)->ops->set_key &&
614 (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
615 (*crypt)->priv) < 0) {
616 IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
622 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
623 ieee->tx_keyidx = idx;
624 sec.active_key = idx;
625 sec.flags |= SEC_ACTIVE_KEY;
628 if (ext->alg != IW_ENCODE_ALG_NONE) {
629 memcpy(sec.keys[idx], ext->key, ext->key_len);
630 sec.key_sizes[idx] = ext->key_len;
631 sec.flags |= (1 << idx);
632 if (ext->alg == IW_ENCODE_ALG_WEP) {
633 sec.encode_alg[idx] = SEC_ALG_WEP;
634 sec.flags |= SEC_LEVEL;
635 sec.level = SEC_LEVEL_1;
636 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
637 sec.encode_alg[idx] = SEC_ALG_TKIP;
638 sec.flags |= SEC_LEVEL;
639 sec.level = SEC_LEVEL_2;
640 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
641 sec.encode_alg[idx] = SEC_ALG_CCMP;
642 sec.flags |= SEC_LEVEL;
643 sec.level = SEC_LEVEL_3;
645 /* Don't set sec level for group keys. */
647 sec.flags &= ~SEC_LEVEL;
650 if (ieee->set_security)
651 ieee->set_security(ieee->dev, &sec);
654 * Do not reset port if card is in Managed mode since resetting will
655 * generate new IEEE 802.11 authentication which may end up in looping
656 * with IEEE 802.1X. If your hardware requires a reset after WEP
657 * configuration (for example... Prism2), implement the reset_port in
658 * the callbacks structures used to initialize the 802.11 stack.
660 if (ieee->reset_on_keychange &&
661 ieee->iw_mode != IW_MODE_INFRA &&
662 ieee->reset_port && ieee->reset_port(dev)) {
663 IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
670 int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee,
671 struct iw_request_info *info,
672 union iwreq_data *wrqu, char *extra)
674 struct iw_point *encoding = &wrqu->encoding;
675 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
676 struct ieee80211_security *sec = &ieee->sec;
677 int idx, max_key_len;
679 max_key_len = encoding->length - sizeof(*ext);
683 idx = encoding->flags & IW_ENCODE_INDEX;
685 if (idx < 1 || idx > WEP_KEYS)
689 idx = ieee->tx_keyidx;
691 if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
692 if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
695 encoding->flags = idx + 1;
696 memset(ext, 0, sizeof(*ext));
699 ext->alg = IW_ENCODE_ALG_NONE;
701 encoding->flags |= IW_ENCODE_DISABLED;
703 if (sec->encode_alg[idx] == SEC_ALG_WEP)
704 ext->alg = IW_ENCODE_ALG_WEP;
705 else if (sec->encode_alg[idx] == SEC_ALG_TKIP)
706 ext->alg = IW_ENCODE_ALG_TKIP;
707 else if (sec->encode_alg[idx] == SEC_ALG_CCMP)
708 ext->alg = IW_ENCODE_ALG_CCMP;
712 ext->key_len = sec->key_sizes[idx];
713 memcpy(ext->key, sec->keys[idx], ext->key_len);
714 encoding->flags |= IW_ENCODE_ENABLED;
716 (ext->alg == IW_ENCODE_ALG_TKIP ||
717 ext->alg == IW_ENCODE_ALG_CCMP))
718 ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
725 EXPORT_SYMBOL(ieee80211_wx_set_encodeext);
726 EXPORT_SYMBOL(ieee80211_wx_get_encodeext);
728 EXPORT_SYMBOL(ieee80211_wx_get_scan);
729 EXPORT_SYMBOL(ieee80211_wx_set_encode);
730 EXPORT_SYMBOL(ieee80211_wx_get_encode);