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/kmod.h>
34 #include <linux/module.h>
36 #include "ieee80211.h"
37 static const char *ieee80211_modes[] = {
38 "?", "a", "b", "ab", "g", "ag", "bg", "abg"
41 #define MAX_CUSTOM_LEN 64
42 static inline char *rtl818x_translate_scan(struct ieee80211_device *ieee,
43 char *start, char *stop,
44 struct ieee80211_network *network,
45 struct iw_request_info *info)
47 char custom[MAX_CUSTOM_LEN];
53 /* First entry *MUST* be the AP MAC address */
55 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
56 memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
57 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN);
59 /* Remaining entries will be displayed in the order we provide them */
62 iwe.cmd = SIOCGIWESSID;
64 //YJ,modified,080903,for hidden ap
65 //if (network->flags & NETWORK_EMPTY_ESSID) {
66 if (network->ssid_len == 0) {
67 //YJ,modified,080903,end
68 iwe.u.data.length = sizeof("<hidden>");
69 start = iwe_stream_add_point(info, start, stop, &iwe, "<hidden>");
71 iwe.u.data.length = min(network->ssid_len, (u8)32);
72 start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid);
74 //printk("ESSID: %s\n",network->ssid);
75 /* Add the protocol name */
76 iwe.cmd = SIOCGIWNAME;
77 snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s", ieee80211_modes[network->mode]);
78 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN);
81 iwe.cmd = SIOCGIWMODE;
82 if (network->capability &
83 (WLAN_CAPABILITY_BSS | WLAN_CAPABILITY_IBSS)) {
84 if (network->capability & WLAN_CAPABILITY_BSS)
85 iwe.u.mode = IW_MODE_MASTER;
87 iwe.u.mode = IW_MODE_ADHOC;
89 start = iwe_stream_add_event(info, 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);
96 iwe.u.freq.m = network->channel;
99 start = iwe_stream_add_event(info, 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;
106 iwe.u.data.flags = IW_ENCODE_DISABLED;
107 iwe.u.data.length = 0;
108 start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid);
110 /* Add basic and extended rates */
113 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): ");
114 for (i = 0, j = 0; i < network->rates_len; ) {
115 if (j < network->rates_ex_len &&
116 ((network->rates_ex[j] & 0x7F) <
117 (network->rates[i] & 0x7F)))
118 rate = network->rates_ex[j++] & 0x7F;
120 rate = network->rates[i++] & 0x7F;
123 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
124 "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
126 for (; j < network->rates_ex_len; j++) {
127 rate = network->rates_ex[j] & 0x7F;
128 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
129 "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
134 iwe.cmd = SIOCGIWRATE;
135 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
136 iwe.u.bitrate.value = max_rate * 500000;
137 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_PARAM_LEN);
139 iwe.cmd = IWEVCUSTOM;
140 iwe.u.data.length = p - custom;
141 if (iwe.u.data.length)
142 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
144 /* Add quality statistics */
145 /* TODO: Fix these values... */
146 if (network->stats.signal == 0 || network->stats.rssi == 0)
147 printk("========>signal:%d, rssi:%d\n", network->stats.signal, network->stats.rssi);
149 // printk("SIGNAL: %d,RSSI: %d,NOISE: %d\n",network->stats.signal,network->stats.rssi,network->stats.noise);
150 iwe.u.qual.qual = network->stats.signalstrength;
151 iwe.u.qual.level = network->stats.signal;
152 iwe.u.qual.noise = network->stats.noise;
153 iwe.u.qual.updated = network->stats.mask & IEEE80211_STATMASK_WEMASK;
154 if (!(network->stats.mask & IEEE80211_STATMASK_RSSI))
155 iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
156 if (!(network->stats.mask & IEEE80211_STATMASK_NOISE))
157 iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
158 if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL))
159 iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID;
160 iwe.u.qual.updated = 7;
161 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN);
163 iwe.cmd = IWEVCUSTOM;
166 iwe.u.data.length = p - custom;
167 if (iwe.u.data.length)
168 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
170 memset(&iwe, 0, sizeof(iwe));
171 if (network->wpa_ie_len) {
172 // printk("wpa_ie_len:%d\n", network->wpa_ie_len);
173 char buf[MAX_WPA_IE_LEN];
174 memcpy(buf, network->wpa_ie, network->wpa_ie_len);
176 iwe.u.data.length = network->wpa_ie_len;
177 start = iwe_stream_add_point(info, start, stop, &iwe, buf);
180 memset(&iwe, 0, sizeof(iwe));
181 if (network->rsn_ie_len) {
182 // printk("=====>rsn_ie_len:\n", network->rsn_ie_len);
183 char buf[MAX_WPA_IE_LEN];
184 memcpy(buf, network->rsn_ie, network->rsn_ie_len);
186 iwe.u.data.length = network->rsn_ie_len;
187 start = iwe_stream_add_point(info, start, stop, &iwe, buf);
190 /* Add EXTRA: Age to display seconds since last beacon/probe response
191 * for given network. */
192 iwe.cmd = IWEVCUSTOM;
194 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
195 " Last beacon: %lums ago", (jiffies - network->last_scanned) / (HZ / 100));
196 iwe.u.data.length = p - custom;
197 if (iwe.u.data.length)
198 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
203 int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
204 struct iw_request_info *info,
205 union iwreq_data *wrqu, char *extra)
207 struct ieee80211_network *network;
211 char *stop = ev + wrqu->data.length;//IW_SCAN_MAX_DATA;
212 //char *stop = ev + IW_SCAN_MAX_DATA;
215 IEEE80211_DEBUG_WX("Getting scan\n");
217 spin_lock_irqsave(&ieee->lock, flags);
219 if(!ieee->bHwRadioOff)
221 list_for_each_entry(network, &ieee->network_list, list) {
229 if (ieee->scan_age == 0 ||
230 time_after(network->last_scanned + ieee->scan_age, jiffies))
232 ev = rtl818x_translate_scan(ieee, ev, stop, network, info);
235 IEEE80211_DEBUG_SCAN(
236 "Not showing network '%s ("
237 "%pM)' due to age (%lums).\n",
238 escape_essid(network->ssid,
241 (jiffies - network->last_scanned) / (HZ / 100));
244 spin_unlock_irqrestore(&ieee->lock, flags);
246 wrqu->data.length = ev - extra;
247 wrqu->data.flags = 0;
248 IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
253 int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
254 struct iw_request_info *info,
255 union iwreq_data *wrqu, char *keybuf)
257 struct iw_point *erq = &(wrqu->encoding);
258 struct net_device *dev = ieee->dev;
259 struct ieee80211_security sec = {
262 int i, key, key_provided, len;
263 struct ieee80211_crypt_data **crypt;
265 IEEE80211_DEBUG_WX("SET_ENCODE\n");
267 key = erq->flags & IW_ENCODE_INDEX;
275 key = ieee->tx_keyidx;
278 IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
279 "provided" : "default");
281 crypt = &ieee->crypt[key];
283 if (erq->flags & IW_ENCODE_DISABLED) {
284 if (key_provided && *crypt) {
285 IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n",
287 ieee80211_crypt_delayed_deinit(ieee, crypt);
289 IEEE80211_DEBUG_WX("Disabling encryption.\n");
291 /* Check all the keys to see if any are still configured,
292 * and if no key index was provided, de-init them all */
293 for (i = 0; i < WEP_KEYS; i++) {
294 if (ieee->crypt[i] != NULL) {
297 ieee80211_crypt_delayed_deinit(
298 ieee, &ieee->crypt[i]);
304 sec.level = SEC_LEVEL_0;
305 sec.flags |= SEC_ENABLED | SEC_LEVEL;
314 sec.flags |= SEC_ENABLED;
316 if (*crypt != NULL && (*crypt)->ops != NULL &&
317 strcmp((*crypt)->ops->name, "WEP") != 0) {
318 /* changing to use WEP; deinit previously used algorithm
320 ieee80211_crypt_delayed_deinit(ieee, crypt);
323 if (*crypt == NULL) {
324 struct ieee80211_crypt_data *new_crypt;
326 /* take WEP into use */
327 new_crypt = kmalloc(sizeof(struct ieee80211_crypt_data),
329 if (new_crypt == NULL)
331 memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
332 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
334 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
337 new_crypt->priv = new_crypt->ops->init(key);
339 if (!new_crypt->ops || !new_crypt->priv) {
343 printk(KERN_WARNING "%s: could not initialize WEP: "
344 "load module ieee80211_crypt_wep\n",
351 /* If a new key was provided, set it up */
352 if (erq->length > 0) {
353 len = erq->length <= 5 ? 5 : 13;
354 memcpy(sec.keys[key], keybuf, erq->length);
355 if (len > erq->length)
356 memset(sec.keys[key] + erq->length, 0,
358 IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
359 key, escape_essid(sec.keys[key], len),
361 sec.key_sizes[key] = len;
362 (*crypt)->ops->set_key(sec.keys[key], len, NULL,
364 sec.flags |= (1 << key);
365 /* This ensures a key will be activated if no key is
367 if (key == sec.active_key)
368 sec.flags |= SEC_ACTIVE_KEY;
369 ieee->tx_keyidx = key;//by wb 080312
371 len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
372 NULL, (*crypt)->priv);
374 /* Set a default key of all 0 */
375 IEEE80211_DEBUG_WX("Setting key %d to all zero.\n",
377 memset(sec.keys[key], 0, 13);
378 (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
380 sec.key_sizes[key] = 13;
381 sec.flags |= (1 << key);
384 /* No key data - just set the default TX key index */
387 "Setting key %d to default Tx key.\n", key);
388 ieee->tx_keyidx = key;
389 sec.active_key = key;
390 sec.flags |= SEC_ACTIVE_KEY;
395 ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
396 sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
397 sec.flags |= SEC_AUTH_MODE;
398 IEEE80211_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ?
399 "OPEN" : "SHARED KEY");
401 /* For now we just support WEP, so only set that security level...
402 * TODO: When WPA is added this is one place that needs to change */
403 sec.flags |= SEC_LEVEL;
404 sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
406 if (ieee->set_security)
407 ieee->set_security(dev, &sec);
409 /* Do not reset port if card is in Managed mode since resetting will
410 * generate new IEEE 802.11 authentication which may end up in looping
411 * with IEEE 802.1X. If your hardware requires a reset after WEP
412 * configuration (for example... Prism2), implement the reset_port in
413 * the callbacks structures used to initialize the 802.11 stack. */
414 if (ieee->reset_on_keychange &&
415 ieee->iw_mode != IW_MODE_INFRA &&
416 ieee->reset_port && ieee->reset_port(dev)) {
417 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
423 int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
424 struct iw_request_info *info,
425 union iwreq_data *wrqu, char *keybuf)
427 struct iw_point *erq = &(wrqu->encoding);
429 struct ieee80211_crypt_data *crypt;
431 IEEE80211_DEBUG_WX("GET_ENCODE\n");
433 if(ieee->iw_mode == IW_MODE_MONITOR)
436 key = erq->flags & IW_ENCODE_INDEX;
442 key = ieee->tx_keyidx;
444 crypt = ieee->crypt[key];
445 erq->flags = key + 1;
447 if (crypt == NULL || crypt->ops == NULL) {
449 erq->flags |= IW_ENCODE_DISABLED;
453 if (strcmp(crypt->ops->name, "WEP") != 0) {
454 /* only WEP is supported with wireless extensions, so just
455 * report that encryption is used */
457 erq->flags |= IW_ENCODE_ENABLED;
461 len = crypt->ops->get_key(keybuf, WEP_KEY_LEN, NULL, crypt->priv);
462 erq->length = (len >= 0 ? len : 0);
464 erq->flags |= IW_ENCODE_ENABLED;
467 erq->flags |= IW_ENCODE_OPEN;
469 erq->flags |= IW_ENCODE_RESTRICTED;
474 int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
475 struct iw_request_info *info,
476 union iwreq_data *wrqu, char *extra)
478 struct net_device *dev = ieee->dev;
479 struct iw_point *encoding = &wrqu->encoding;
480 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
484 struct ieee80211_crypto_ops *ops;
485 struct ieee80211_crypt_data **crypt;
487 struct ieee80211_security sec = {
490 //printk("======>encoding flag:%x,ext flag:%x, ext alg:%d\n", encoding->flags,ext->ext_flags, ext->alg);
491 idx = encoding->flags & IW_ENCODE_INDEX;
493 if (idx < 1 || idx > WEP_KEYS)
497 idx = ieee->tx_keyidx;
499 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
500 crypt = &ieee->crypt[idx];
503 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
504 //printk("not group key, flags:%x, ext->alg:%d\n", ext->ext_flags, ext->alg);
505 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
507 if (ieee->iw_mode == IW_MODE_INFRA)
508 crypt = &ieee->crypt[idx];
513 sec.flags |= SEC_ENABLED;// | SEC_ENCRYPT;
514 if ((encoding->flags & IW_ENCODE_DISABLED) ||
515 ext->alg == IW_ENCODE_ALG_NONE) {
517 ieee80211_crypt_delayed_deinit(ieee, crypt);
519 for (i = 0; i < WEP_KEYS; i++)
520 if (ieee->crypt[i] != NULL)
526 sec.level = SEC_LEVEL_0;
527 sec.flags |= SEC_LEVEL;
529 //printk("disabled: flag:%x\n", encoding->flags);
537 case IW_ENCODE_ALG_WEP:
540 case IW_ENCODE_ALG_TKIP:
543 case IW_ENCODE_ALG_CCMP:
547 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
548 dev->name, ext->alg);
552 // printk("8-09-08-9=====>%s, alg name:%s\n",__func__, alg);
554 ops = ieee80211_get_crypto_ops(alg);
556 ops = ieee80211_get_crypto_ops(alg);
558 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
559 dev->name, ext->alg);
560 printk("========>unknown crypto alg %d\n", ext->alg);
565 if (*crypt == NULL || (*crypt)->ops != ops) {
566 struct ieee80211_crypt_data *new_crypt;
568 ieee80211_crypt_delayed_deinit(ieee, crypt);
570 new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
571 if (new_crypt == NULL) {
575 new_crypt->ops = ops;
577 new_crypt->priv = new_crypt->ops->init(idx);
578 if (new_crypt->priv == NULL) {
587 if (ext->key_len > 0 && (*crypt)->ops->set_key &&
588 (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
589 (*crypt)->priv) < 0) {
590 IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
591 printk("key setting failed\n");
597 //printk("skip_host_crypt:ext_flags:%x\n", ext->ext_flags);
598 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
599 ieee->tx_keyidx = idx;
600 sec.active_key = idx;
601 sec.flags |= SEC_ACTIVE_KEY;
604 if (ext->alg != IW_ENCODE_ALG_NONE) {
605 memcpy(sec.keys[idx], ext->key, ext->key_len);
606 sec.key_sizes[idx] = ext->key_len;
607 sec.flags |= (1 << idx);
608 if (ext->alg == IW_ENCODE_ALG_WEP) {
609 // sec.encode_alg[idx] = SEC_ALG_WEP;
610 sec.flags |= SEC_LEVEL;
611 sec.level = SEC_LEVEL_1;
612 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
613 // sec.encode_alg[idx] = SEC_ALG_TKIP;
614 sec.flags |= SEC_LEVEL;
615 sec.level = SEC_LEVEL_2;
616 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
617 // sec.encode_alg[idx] = SEC_ALG_CCMP;
618 sec.flags |= SEC_LEVEL;
619 sec.level = SEC_LEVEL_3;
621 /* Don't set sec level for group keys. */
623 sec.flags &= ~SEC_LEVEL;
627 if (ieee->set_security)
628 ieee->set_security(ieee->dev, &sec);
630 if (ieee->reset_on_keychange &&
631 ieee->iw_mode != IW_MODE_INFRA &&
632 ieee->reset_port && ieee->reset_port(dev)) {
633 IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
639 int ieee80211_wx_set_mlme(struct ieee80211_device *ieee,
640 struct iw_request_info *info,
641 union iwreq_data *wrqu, char *extra)
643 struct iw_mlme *mlme = (struct iw_mlme *) extra;
644 // printk("\ndkgadfslkdjgalskdf===============>%s(), cmd:%x\n", __func__, mlme->cmd);
648 case IW_MLME_DISASSOC:
649 // printk("disassoc now\n");
650 ieee80211_disassociate(ieee);
659 int ieee80211_wx_set_auth(struct ieee80211_device *ieee,
660 struct iw_request_info *info,
661 struct iw_param *data, char *extra)
664 struct ieee80211_security sec = {
665 .flags = SEC_AUTH_MODE,
668 //printk("set auth:flag:%x, data value:%x\n", data->flags, data->value);
669 switch (data->flags & IW_AUTH_INDEX) {
670 case IW_AUTH_WPA_VERSION:
671 /*need to support wpa2 here*/
672 //printk("wpa version:%x\n", data->value);
674 case IW_AUTH_CIPHER_PAIRWISE:
675 case IW_AUTH_CIPHER_GROUP:
676 case IW_AUTH_KEY_MGMT:
678 * * Host AP driver does not use these parameters and allows
679 * * wpa_supplicant to control them internally.
682 case IW_AUTH_TKIP_COUNTERMEASURES:
683 ieee->tkip_countermeasures = data->value;
685 case IW_AUTH_DROP_UNENCRYPTED:
686 ieee->drop_unencrypted = data->value;
689 case IW_AUTH_80211_AUTH_ALG:
690 ieee->open_wep = (data->value&IW_AUTH_ALG_OPEN_SYSTEM)?1:0;
691 //printk("open_wep:%d\n", ieee->open_wep);
695 case IW_AUTH_WPA_ENABLED:
696 ieee->wpa_enabled = (data->value)?1:0;
697 //printk("enable wpa:%d\n", ieee->wpa_enabled);
701 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
702 ieee->ieee802_1x = data->value;
704 case IW_AUTH_PRIVACY_INVOKED:
705 ieee->privacy_invoked = data->value;
714 int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len)
718 if (len>MAX_WPA_IE_LEN || (len && ie == NULL))
720 printk("return error out, len:%zu\n", len);
727 printk("len:%zu, ie:%d\n", len, ie[1]);
730 buf = kmalloc(len, GFP_KERNEL);
733 memcpy(buf, ie, len);
736 ieee->wpa_ie_len = len;
742 ieee->wpa_ie_len = 0;
744 // printk("<=====out %s()\n", __func__);