1 /******************************************************************************
3 Copyright(c) 2004 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 ******************************************************************************/
32 #include <linux/wireless.h>
33 #include <linux/version.h>
34 #include <linux/kmod.h>
35 #include <linux/module.h>
37 #include "ieee80211.h"
38 static const char *ieee80211_modes[] = {
39 "?", "a", "b", "ab", "g", "ag", "bg", "abg"
42 #define MAX_CUSTOM_LEN 64
43 static inline char *rtl818x_translate_scan(struct ieee80211_device *ieee,
44 char *start, char *stop,
45 struct ieee80211_network *network,
46 struct iw_request_info *info)
48 char custom[MAX_CUSTOM_LEN];
54 /* First entry *MUST* be the AP MAC address */
56 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
57 memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
58 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN);
60 /* Remaining entries will be displayed in the order we provide them */
63 iwe.cmd = SIOCGIWESSID;
65 //YJ,modified,080903,for hidden ap
66 //if (network->flags & NETWORK_EMPTY_ESSID) {
67 if (network->ssid_len == 0) {
68 //YJ,modified,080903,end
69 iwe.u.data.length = sizeof("<hidden>");
70 start = iwe_stream_add_point(info, start, stop, &iwe, "<hidden>");
72 iwe.u.data.length = min(network->ssid_len, (u8)32);
73 start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid);
75 //printk("ESSID: %s\n",network->ssid);
76 /* Add the protocol name */
77 iwe.cmd = SIOCGIWNAME;
78 snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s", ieee80211_modes[network->mode]);
79 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN);
82 iwe.cmd = SIOCGIWMODE;
83 if (network->capability &
84 (WLAN_CAPABILITY_BSS | WLAN_CAPABILITY_IBSS)) {
85 if (network->capability & WLAN_CAPABILITY_BSS)
86 iwe.u.mode = IW_MODE_MASTER;
88 iwe.u.mode = IW_MODE_ADHOC;
90 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_UINT_LEN);
93 /* Add frequency/channel */
94 iwe.cmd = SIOCGIWFREQ;
95 /* iwe.u.freq.m = ieee80211_frequency(network->channel, network->mode);
97 iwe.u.freq.m = network->channel;
100 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN);
102 /* Add encryption capability */
103 iwe.cmd = SIOCGIWENCODE;
104 if (network->capability & WLAN_CAPABILITY_PRIVACY)
105 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
107 iwe.u.data.flags = IW_ENCODE_DISABLED;
108 iwe.u.data.length = 0;
109 start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid);
111 /* Add basic and extended rates */
114 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): ");
115 for (i = 0, j = 0; i < network->rates_len; ) {
116 if (j < network->rates_ex_len &&
117 ((network->rates_ex[j] & 0x7F) <
118 (network->rates[i] & 0x7F)))
119 rate = network->rates_ex[j++] & 0x7F;
121 rate = network->rates[i++] & 0x7F;
124 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
125 "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
127 for (; j < network->rates_ex_len; j++) {
128 rate = network->rates_ex[j] & 0x7F;
129 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
130 "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
135 iwe.cmd = SIOCGIWRATE;
136 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
137 iwe.u.bitrate.value = max_rate * 500000;
138 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_PARAM_LEN);
140 iwe.cmd = IWEVCUSTOM;
141 iwe.u.data.length = p - custom;
142 if (iwe.u.data.length)
143 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
145 /* Add quality statistics */
146 /* TODO: Fix these values... */
147 if (network->stats.signal == 0 || network->stats.rssi == 0)
148 printk("========>signal:%d, rssi:%d\n", network->stats.signal, network->stats.rssi);
150 // printk("SIGNAL: %d,RSSI: %d,NOISE: %d\n",network->stats.signal,network->stats.rssi,network->stats.noise);
151 iwe.u.qual.qual = network->stats.signalstrength;
152 iwe.u.qual.level = network->stats.signal;
153 iwe.u.qual.noise = network->stats.noise;
154 iwe.u.qual.updated = network->stats.mask & IEEE80211_STATMASK_WEMASK;
155 if (!(network->stats.mask & IEEE80211_STATMASK_RSSI))
156 iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
157 if (!(network->stats.mask & IEEE80211_STATMASK_NOISE))
158 iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
159 if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL))
160 iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID;
161 iwe.u.qual.updated = 7;
162 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN);
164 iwe.cmd = IWEVCUSTOM;
167 iwe.u.data.length = p - custom;
168 if (iwe.u.data.length)
169 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
171 memset(&iwe, 0, sizeof(iwe));
172 if (network->wpa_ie_len) {
173 // printk("wpa_ie_len:%d\n", network->wpa_ie_len);
174 char buf[MAX_WPA_IE_LEN];
175 memcpy(buf, network->wpa_ie, network->wpa_ie_len);
177 iwe.u.data.length = network->wpa_ie_len;
178 start = iwe_stream_add_point(info, start, stop, &iwe, buf);
181 memset(&iwe, 0, sizeof(iwe));
182 if (network->rsn_ie_len) {
183 // printk("=====>rsn_ie_len:\n", network->rsn_ie_len);
184 char buf[MAX_WPA_IE_LEN];
185 memcpy(buf, network->rsn_ie, network->rsn_ie_len);
187 iwe.u.data.length = network->rsn_ie_len;
188 start = iwe_stream_add_point(info, start, stop, &iwe, buf);
191 /* Add EXTRA: Age to display seconds since last beacon/probe response
192 * for given network. */
193 iwe.cmd = IWEVCUSTOM;
195 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
196 " Last beacon: %lums ago", (jiffies - network->last_scanned) / (HZ / 100));
197 iwe.u.data.length = p - custom;
198 if (iwe.u.data.length)
199 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
204 int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
205 struct iw_request_info *info,
206 union iwreq_data *wrqu, char *extra)
208 struct ieee80211_network *network;
212 char *stop = ev + wrqu->data.length;//IW_SCAN_MAX_DATA;
213 //char *stop = ev + IW_SCAN_MAX_DATA;
216 IEEE80211_DEBUG_WX("Getting scan\n");
218 spin_lock_irqsave(&ieee->lock, flags);
220 if(!ieee->bHwRadioOff)
222 list_for_each_entry(network, &ieee->network_list, list) {
230 if (ieee->scan_age == 0 ||
231 time_after(network->last_scanned + ieee->scan_age, jiffies))
233 ev = rtl818x_translate_scan(ieee, ev, stop, network, info);
236 IEEE80211_DEBUG_SCAN(
237 "Not showing network '%s ("
238 MAC_FMT ")' due to age (%lums).\n",
239 escape_essid(network->ssid,
241 MAC_ARG(network->bssid),
242 (jiffies - network->last_scanned) / (HZ / 100));
245 spin_unlock_irqrestore(&ieee->lock, flags);
247 wrqu->data.length = ev - extra;
248 wrqu->data.flags = 0;
249 IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
254 int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
255 struct iw_request_info *info,
256 union iwreq_data *wrqu, char *keybuf)
258 struct iw_point *erq = &(wrqu->encoding);
259 struct net_device *dev = ieee->dev;
260 struct ieee80211_security sec = {
263 int i, key, key_provided, len;
264 struct ieee80211_crypt_data **crypt;
266 IEEE80211_DEBUG_WX("SET_ENCODE\n");
268 key = erq->flags & IW_ENCODE_INDEX;
276 key = ieee->tx_keyidx;
279 IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
280 "provided" : "default");
282 crypt = &ieee->crypt[key];
284 if (erq->flags & IW_ENCODE_DISABLED) {
285 if (key_provided && *crypt) {
286 IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n",
288 ieee80211_crypt_delayed_deinit(ieee, crypt);
290 IEEE80211_DEBUG_WX("Disabling encryption.\n");
292 /* Check all the keys to see if any are still configured,
293 * and if no key index was provided, de-init them all */
294 for (i = 0; i < WEP_KEYS; i++) {
295 if (ieee->crypt[i] != NULL) {
298 ieee80211_crypt_delayed_deinit(
299 ieee, &ieee->crypt[i]);
305 sec.level = SEC_LEVEL_0;
306 sec.flags |= SEC_ENABLED | SEC_LEVEL;
315 sec.flags |= SEC_ENABLED;
317 if (*crypt != NULL && (*crypt)->ops != NULL &&
318 strcmp((*crypt)->ops->name, "WEP") != 0) {
319 /* changing to use WEP; deinit previously used algorithm
321 ieee80211_crypt_delayed_deinit(ieee, crypt);
324 if (*crypt == NULL) {
325 struct ieee80211_crypt_data *new_crypt;
327 /* take WEP into use */
328 new_crypt = kmalloc(sizeof(struct ieee80211_crypt_data),
330 if (new_crypt == NULL)
332 memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
333 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
334 if (!new_crypt->ops) {
335 request_module("ieee80211_crypt_wep");
336 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
339 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
340 new_crypt->priv = new_crypt->ops->init(key);
342 if (!new_crypt->ops || !new_crypt->priv) {
346 printk(KERN_WARNING "%s: could not initialize WEP: "
347 "load module ieee80211_crypt_wep\n",
354 /* If a new key was provided, set it up */
355 if (erq->length > 0) {
356 len = erq->length <= 5 ? 5 : 13;
357 memcpy(sec.keys[key], keybuf, erq->length);
358 if (len > erq->length)
359 memset(sec.keys[key] + erq->length, 0,
361 IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
362 key, escape_essid(sec.keys[key], len),
364 sec.key_sizes[key] = len;
365 (*crypt)->ops->set_key(sec.keys[key], len, NULL,
367 sec.flags |= (1 << key);
368 /* This ensures a key will be activated if no key is
370 if (key == sec.active_key)
371 sec.flags |= SEC_ACTIVE_KEY;
372 ieee->tx_keyidx = key;//by wb 080312
374 len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
375 NULL, (*crypt)->priv);
377 /* Set a default key of all 0 */
378 IEEE80211_DEBUG_WX("Setting key %d to all zero.\n",
380 memset(sec.keys[key], 0, 13);
381 (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
383 sec.key_sizes[key] = 13;
384 sec.flags |= (1 << key);
387 /* No key data - just set the default TX key index */
390 "Setting key %d to default Tx key.\n", key);
391 ieee->tx_keyidx = key;
392 sec.active_key = key;
393 sec.flags |= SEC_ACTIVE_KEY;
398 ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
399 sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
400 sec.flags |= SEC_AUTH_MODE;
401 IEEE80211_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ?
402 "OPEN" : "SHARED KEY");
404 /* For now we just support WEP, so only set that security level...
405 * TODO: When WPA is added this is one place that needs to change */
406 sec.flags |= SEC_LEVEL;
407 sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
409 if (ieee->set_security)
410 ieee->set_security(dev, &sec);
412 /* Do not reset port if card is in Managed mode since resetting will
413 * generate new IEEE 802.11 authentication which may end up in looping
414 * with IEEE 802.1X. If your hardware requires a reset after WEP
415 * configuration (for example... Prism2), implement the reset_port in
416 * the callbacks structures used to initialize the 802.11 stack. */
417 if (ieee->reset_on_keychange &&
418 ieee->iw_mode != IW_MODE_INFRA &&
419 ieee->reset_port && ieee->reset_port(dev)) {
420 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
426 int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
427 struct iw_request_info *info,
428 union iwreq_data *wrqu, char *keybuf)
430 struct iw_point *erq = &(wrqu->encoding);
432 struct ieee80211_crypt_data *crypt;
434 IEEE80211_DEBUG_WX("GET_ENCODE\n");
436 if(ieee->iw_mode == IW_MODE_MONITOR)
439 key = erq->flags & IW_ENCODE_INDEX;
445 key = ieee->tx_keyidx;
447 crypt = ieee->crypt[key];
448 erq->flags = key + 1;
450 if (crypt == NULL || crypt->ops == NULL) {
452 erq->flags |= IW_ENCODE_DISABLED;
456 if (strcmp(crypt->ops->name, "WEP") != 0) {
457 /* only WEP is supported with wireless extensions, so just
458 * report that encryption is used */
460 erq->flags |= IW_ENCODE_ENABLED;
464 len = crypt->ops->get_key(keybuf, WEP_KEY_LEN, NULL, crypt->priv);
465 erq->length = (len >= 0 ? len : 0);
467 erq->flags |= IW_ENCODE_ENABLED;
470 erq->flags |= IW_ENCODE_OPEN;
472 erq->flags |= IW_ENCODE_RESTRICTED;
477 int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
478 struct iw_request_info *info,
479 union iwreq_data *wrqu, char *extra)
481 struct net_device *dev = ieee->dev;
482 struct iw_point *encoding = &wrqu->encoding;
483 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
486 const char *alg, *module;
487 struct ieee80211_crypto_ops *ops;
488 struct ieee80211_crypt_data **crypt;
490 struct ieee80211_security sec = {
493 //printk("======>encoding flag:%x,ext flag:%x, ext alg:%d\n", encoding->flags,ext->ext_flags, ext->alg);
494 idx = encoding->flags & IW_ENCODE_INDEX;
496 if (idx < 1 || idx > WEP_KEYS)
500 idx = ieee->tx_keyidx;
502 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
503 crypt = &ieee->crypt[idx];
506 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
507 //printk("not group key, flags:%x, ext->alg:%d\n", ext->ext_flags, ext->alg);
508 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
510 if (ieee->iw_mode == IW_MODE_INFRA)
511 crypt = &ieee->crypt[idx];
516 sec.flags |= SEC_ENABLED;// | SEC_ENCRYPT;
517 if ((encoding->flags & IW_ENCODE_DISABLED) ||
518 ext->alg == IW_ENCODE_ALG_NONE) {
520 ieee80211_crypt_delayed_deinit(ieee, crypt);
522 for (i = 0; i < WEP_KEYS; i++)
523 if (ieee->crypt[i] != NULL)
529 sec.level = SEC_LEVEL_0;
530 sec.flags |= SEC_LEVEL;
532 //printk("disabled: flag:%x\n", encoding->flags);
540 case IW_ENCODE_ALG_WEP:
542 module = "ieee80211_crypt_wep";
544 case IW_ENCODE_ALG_TKIP:
546 module = "ieee80211_crypt_tkip";
548 case IW_ENCODE_ALG_CCMP:
550 module = "ieee80211_crypt_ccmp";
553 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
554 dev->name, ext->alg);
558 // printk("8-09-08-9=====>%s, alg name:%s\n",__func__, alg);
560 ops = ieee80211_get_crypto_ops(alg);
562 request_module(module);
563 ops = ieee80211_get_crypto_ops(alg);
566 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
567 dev->name, ext->alg);
568 printk("========>unknown crypto alg %d\n", ext->alg);
573 if (*crypt == NULL || (*crypt)->ops != ops) {
574 struct ieee80211_crypt_data *new_crypt;
576 ieee80211_crypt_delayed_deinit(ieee, crypt);
578 new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
579 if (new_crypt == NULL) {
583 new_crypt->ops = ops;
584 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
585 new_crypt->priv = new_crypt->ops->init(idx);
586 if (new_crypt->priv == NULL) {
595 if (ext->key_len > 0 && (*crypt)->ops->set_key &&
596 (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
597 (*crypt)->priv) < 0) {
598 IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
599 printk("key setting failed\n");
605 //printk("skip_host_crypt:ext_flags:%x\n", ext->ext_flags);
606 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
607 ieee->tx_keyidx = idx;
608 sec.active_key = idx;
609 sec.flags |= SEC_ACTIVE_KEY;
612 if (ext->alg != IW_ENCODE_ALG_NONE) {
613 memcpy(sec.keys[idx], ext->key, ext->key_len);
614 sec.key_sizes[idx] = ext->key_len;
615 sec.flags |= (1 << idx);
616 if (ext->alg == IW_ENCODE_ALG_WEP) {
617 // sec.encode_alg[idx] = SEC_ALG_WEP;
618 sec.flags |= SEC_LEVEL;
619 sec.level = SEC_LEVEL_1;
620 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
621 // sec.encode_alg[idx] = SEC_ALG_TKIP;
622 sec.flags |= SEC_LEVEL;
623 sec.level = SEC_LEVEL_2;
624 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
625 // sec.encode_alg[idx] = SEC_ALG_CCMP;
626 sec.flags |= SEC_LEVEL;
627 sec.level = SEC_LEVEL_3;
629 /* Don't set sec level for group keys. */
631 sec.flags &= ~SEC_LEVEL;
635 if (ieee->set_security)
636 ieee->set_security(ieee->dev, &sec);
638 if (ieee->reset_on_keychange &&
639 ieee->iw_mode != IW_MODE_INFRA &&
640 ieee->reset_port && ieee->reset_port(dev)) {
641 IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
647 int ieee80211_wx_set_mlme(struct ieee80211_device *ieee,
648 struct iw_request_info *info,
649 union iwreq_data *wrqu, char *extra)
651 struct iw_mlme *mlme = (struct iw_mlme *) extra;
652 // printk("\ndkgadfslkdjgalskdf===============>%s(), cmd:%x\n", __func__, mlme->cmd);
656 case IW_MLME_DISASSOC:
657 // printk("disassoc now\n");
658 ieee80211_disassociate(ieee);
667 int ieee80211_wx_set_auth(struct ieee80211_device *ieee,
668 struct iw_request_info *info,
669 struct iw_param *data, char *extra)
672 struct ieee80211_security sec = {
673 .flags = SEC_AUTH_MODE,
676 //printk("set auth:flag:%x, data value:%x\n", data->flags, data->value);
677 switch (data->flags & IW_AUTH_INDEX) {
678 case IW_AUTH_WPA_VERSION:
679 /*need to support wpa2 here*/
680 //printk("wpa version:%x\n", data->value);
682 case IW_AUTH_CIPHER_PAIRWISE:
683 case IW_AUTH_CIPHER_GROUP:
684 case IW_AUTH_KEY_MGMT:
686 * * Host AP driver does not use these parameters and allows
687 * * wpa_supplicant to control them internally.
690 case IW_AUTH_TKIP_COUNTERMEASURES:
691 ieee->tkip_countermeasures = data->value;
693 case IW_AUTH_DROP_UNENCRYPTED:
694 ieee->drop_unencrypted = data->value;
697 case IW_AUTH_80211_AUTH_ALG:
698 ieee->open_wep = (data->value&IW_AUTH_ALG_OPEN_SYSTEM)?1:0;
699 //printk("open_wep:%d\n", ieee->open_wep);
703 case IW_AUTH_WPA_ENABLED:
704 ieee->wpa_enabled = (data->value)?1:0;
705 //printk("enalbe wpa:%d\n", ieee->wpa_enabled);
709 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
710 ieee->ieee802_1x = data->value;
712 case IW_AUTH_PRIVACY_INVOKED:
713 ieee->privacy_invoked = data->value;
722 int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len)
726 if (len>MAX_WPA_IE_LEN || (len && ie == NULL))
728 printk("return error out, len:%zu\n", len);
735 printk("len:%zu, ie:%d\n", len, ie[1]);
738 buf = kmalloc(len, GFP_KERNEL);
741 memcpy(buf, ie, len);
744 ieee->wpa_ie_len = len;
750 ieee->wpa_ie_len = 0;
752 // printk("<=====out %s()\n", __func__);