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/slab.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) {
221 list_for_each_entry(network, &ieee->network_list, list) {
224 if ((stop-ev) < 200) {
228 if (ieee->scan_age == 0 ||
229 time_after(network->last_scanned + ieee->scan_age, jiffies)) {
230 ev = rtl818x_translate_scan(ieee, ev, stop, network, info);
232 IEEE80211_DEBUG_SCAN(
233 "Not showing network '%s ("
234 "%pM)' due to age (%lums).\n",
235 escape_essid(network->ssid,
238 (jiffies - network->last_scanned) / (HZ / 100));
241 spin_unlock_irqrestore(&ieee->lock, flags);
243 wrqu->data.length = ev - extra;
244 wrqu->data.flags = 0;
245 IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
250 int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
251 struct iw_request_info *info,
252 union iwreq_data *wrqu, char *keybuf)
254 struct iw_point *erq = &(wrqu->encoding);
255 struct net_device *dev = ieee->dev;
256 struct ieee80211_security sec = {
259 int i, key, key_provided, len;
260 struct ieee80211_crypt_data **crypt;
262 IEEE80211_DEBUG_WX("SET_ENCODE\n");
264 key = erq->flags & IW_ENCODE_INDEX;
272 key = ieee->tx_keyidx;
275 IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
276 "provided" : "default");
278 crypt = &ieee->crypt[key];
280 if (erq->flags & IW_ENCODE_DISABLED) {
281 if (key_provided && *crypt) {
282 IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n",
284 ieee80211_crypt_delayed_deinit(ieee, crypt);
286 IEEE80211_DEBUG_WX("Disabling encryption.\n");
288 /* Check all the keys to see if any are still configured,
289 * and if no key index was provided, de-init them all */
290 for (i = 0; i < WEP_KEYS; i++) {
291 if (ieee->crypt[i] != NULL) {
294 ieee80211_crypt_delayed_deinit(
295 ieee, &ieee->crypt[i]);
301 sec.level = SEC_LEVEL_0;
302 sec.flags |= SEC_ENABLED | SEC_LEVEL;
311 sec.flags |= SEC_ENABLED;
313 if (*crypt != NULL && (*crypt)->ops != NULL &&
314 strcmp((*crypt)->ops->name, "WEP") != 0) {
315 /* changing to use WEP; deinit previously used algorithm
317 ieee80211_crypt_delayed_deinit(ieee, crypt);
320 if (*crypt == NULL) {
321 struct ieee80211_crypt_data *new_crypt;
323 /* take WEP into use */
324 new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data),
326 if (new_crypt == NULL)
328 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
330 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
333 new_crypt->priv = new_crypt->ops->init(key);
335 if (!new_crypt->ops || !new_crypt->priv) {
339 netdev_warn(ieee->dev,
340 "could not initialize WEP: load module ieee80211_crypt_wep\n");
346 /* If a new key was provided, set it up */
347 if (erq->length > 0) {
348 len = erq->length <= 5 ? 5 : 13;
349 memcpy(sec.keys[key], keybuf, erq->length);
350 if (len > erq->length)
351 memset(sec.keys[key] + erq->length, 0,
353 IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
354 key, escape_essid(sec.keys[key], len),
356 sec.key_sizes[key] = len;
357 (*crypt)->ops->set_key(sec.keys[key], len, NULL,
359 sec.flags |= (1 << key);
360 /* This ensures a key will be activated if no key is
362 if (key == sec.active_key)
363 sec.flags |= SEC_ACTIVE_KEY;
364 ieee->tx_keyidx = key;//by wb 080312
366 len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
367 NULL, (*crypt)->priv);
369 /* Set a default key of all 0 */
370 IEEE80211_DEBUG_WX("Setting key %d to all zero.\n",
372 memset(sec.keys[key], 0, 13);
373 (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
375 sec.key_sizes[key] = 13;
376 sec.flags |= (1 << key);
379 /* No key data - just set the default TX key index */
382 "Setting key %d to default Tx key.\n", key);
383 ieee->tx_keyidx = key;
384 sec.active_key = key;
385 sec.flags |= SEC_ACTIVE_KEY;
390 ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
391 sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
392 sec.flags |= SEC_AUTH_MODE;
393 IEEE80211_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ?
394 "OPEN" : "SHARED KEY");
396 /* For now we just support WEP, so only set that security level...
397 * TODO: When WPA is added this is one place that needs to change */
398 sec.flags |= SEC_LEVEL;
399 sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
401 if (ieee->set_security)
402 ieee->set_security(dev, &sec);
404 /* Do not reset port if card is in Managed mode since resetting will
405 * generate new IEEE 802.11 authentication which may end up in looping
406 * with IEEE 802.1X. If your hardware requires a reset after WEP
407 * configuration (for example... Prism2), implement the reset_port in
408 * the callbacks structures used to initialize the 802.11 stack. */
409 if (ieee->reset_on_keychange &&
410 ieee->iw_mode != IW_MODE_INFRA &&
411 ieee->reset_port && ieee->reset_port(dev)) {
412 netdev_dbg(ieee->dev, "reset_port failed\n");
418 int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
419 struct iw_request_info *info,
420 union iwreq_data *wrqu, char *keybuf)
422 struct iw_point *erq = &(wrqu->encoding);
424 struct ieee80211_crypt_data *crypt;
426 IEEE80211_DEBUG_WX("GET_ENCODE\n");
428 if (ieee->iw_mode == IW_MODE_MONITOR)
431 key = erq->flags & IW_ENCODE_INDEX;
437 key = ieee->tx_keyidx;
439 crypt = ieee->crypt[key];
440 erq->flags = key + 1;
442 if (crypt == NULL || crypt->ops == NULL) {
444 erq->flags |= IW_ENCODE_DISABLED;
448 if (strcmp(crypt->ops->name, "WEP") != 0) {
449 /* only WEP is supported with wireless extensions, so just
450 * report that encryption is used */
452 erq->flags |= IW_ENCODE_ENABLED;
456 len = crypt->ops->get_key(keybuf, WEP_KEY_LEN, NULL, crypt->priv);
457 erq->length = (len >= 0 ? len : 0);
459 erq->flags |= IW_ENCODE_ENABLED;
462 erq->flags |= IW_ENCODE_OPEN;
464 erq->flags |= IW_ENCODE_RESTRICTED;
469 int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
470 struct iw_request_info *info,
471 union iwreq_data *wrqu, char *extra)
473 struct net_device *dev = ieee->dev;
474 struct iw_point *encoding = &wrqu->encoding;
475 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
479 struct ieee80211_crypto_ops *ops;
480 struct ieee80211_crypt_data **crypt;
482 struct ieee80211_security sec = {
485 //printk("======>encoding flag:%x,ext flag:%x, ext alg:%d\n", encoding->flags,ext->ext_flags, ext->alg);
486 idx = encoding->flags & IW_ENCODE_INDEX;
488 if (idx < 1 || idx > WEP_KEYS)
492 idx = ieee->tx_keyidx;
494 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
495 crypt = &ieee->crypt[idx];
498 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
499 //printk("not group key, flags:%x, ext->alg:%d\n", ext->ext_flags, ext->alg);
500 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
502 if (ieee->iw_mode == IW_MODE_INFRA)
503 crypt = &ieee->crypt[idx];
508 sec.flags |= SEC_ENABLED;// | SEC_ENCRYPT;
509 if ((encoding->flags & IW_ENCODE_DISABLED) ||
510 ext->alg == IW_ENCODE_ALG_NONE) {
512 ieee80211_crypt_delayed_deinit(ieee, crypt);
514 for (i = 0; i < WEP_KEYS; i++)
515 if (ieee->crypt[i] != NULL)
521 sec.level = SEC_LEVEL_0;
522 sec.flags |= SEC_LEVEL;
524 //printk("disabled: flag:%x\n", encoding->flags);
532 case IW_ENCODE_ALG_WEP:
535 case IW_ENCODE_ALG_TKIP:
538 case IW_ENCODE_ALG_CCMP:
542 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
543 dev->name, ext->alg);
547 // printk("8-09-08-9=====>%s, alg name:%s\n",__func__, alg);
549 ops = ieee80211_get_crypto_ops(alg);
551 ops = ieee80211_get_crypto_ops(alg);
553 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
554 dev->name, ext->alg);
555 printk("========>unknown crypto alg %d\n", ext->alg);
560 if (*crypt == NULL || (*crypt)->ops != ops) {
561 struct ieee80211_crypt_data *new_crypt;
563 ieee80211_crypt_delayed_deinit(ieee, crypt);
565 new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
566 if (new_crypt == NULL) {
570 new_crypt->ops = ops;
572 new_crypt->priv = new_crypt->ops->init(idx);
573 if (new_crypt->priv == NULL) {
582 if (ext->key_len > 0 && (*crypt)->ops->set_key &&
583 (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
584 (*crypt)->priv) < 0) {
585 IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
586 printk("key setting failed\n");
592 //printk("skip_host_crypt:ext_flags:%x\n", ext->ext_flags);
593 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
594 ieee->tx_keyidx = idx;
595 sec.active_key = idx;
596 sec.flags |= SEC_ACTIVE_KEY;
599 if (ext->alg != IW_ENCODE_ALG_NONE) {
600 memcpy(sec.keys[idx], ext->key, ext->key_len);
601 sec.key_sizes[idx] = ext->key_len;
602 sec.flags |= (1 << idx);
603 if (ext->alg == IW_ENCODE_ALG_WEP) {
604 // sec.encode_alg[idx] = SEC_ALG_WEP;
605 sec.flags |= SEC_LEVEL;
606 sec.level = SEC_LEVEL_1;
607 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
608 // sec.encode_alg[idx] = SEC_ALG_TKIP;
609 sec.flags |= SEC_LEVEL;
610 sec.level = SEC_LEVEL_2;
611 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
612 // sec.encode_alg[idx] = SEC_ALG_CCMP;
613 sec.flags |= SEC_LEVEL;
614 sec.level = SEC_LEVEL_3;
616 /* Don't set sec level for group keys. */
618 sec.flags &= ~SEC_LEVEL;
622 if (ieee->set_security)
623 ieee->set_security(ieee->dev, &sec);
625 if (ieee->reset_on_keychange &&
626 ieee->iw_mode != IW_MODE_INFRA &&
627 ieee->reset_port && ieee->reset_port(dev)) {
628 IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
634 int ieee80211_wx_set_mlme(struct ieee80211_device *ieee,
635 struct iw_request_info *info,
636 union iwreq_data *wrqu, char *extra)
638 struct iw_mlme *mlme = (struct iw_mlme *) extra;
639 // printk("\ndkgadfslkdjgalskdf===============>%s(), cmd:%x\n", __func__, mlme->cmd);
643 case IW_MLME_DISASSOC:
644 // printk("disassoc now\n");
645 ieee80211_disassociate(ieee);
654 int ieee80211_wx_set_auth(struct ieee80211_device *ieee,
655 struct iw_request_info *info,
656 struct iw_param *data, char *extra)
659 struct ieee80211_security sec = {
660 .flags = SEC_AUTH_MODE,
663 //printk("set auth:flag:%x, data value:%x\n", data->flags, data->value);
664 switch (data->flags & IW_AUTH_INDEX) {
665 case IW_AUTH_WPA_VERSION:
666 /*need to support wpa2 here*/
667 //printk("wpa version:%x\n", data->value);
669 case IW_AUTH_CIPHER_PAIRWISE:
670 case IW_AUTH_CIPHER_GROUP:
671 case IW_AUTH_KEY_MGMT:
673 * * Host AP driver does not use these parameters and allows
674 * * wpa_supplicant to control them internally.
677 case IW_AUTH_TKIP_COUNTERMEASURES:
678 ieee->tkip_countermeasures = data->value;
680 case IW_AUTH_DROP_UNENCRYPTED:
681 ieee->drop_unencrypted = data->value;
684 case IW_AUTH_80211_AUTH_ALG:
685 ieee->open_wep = (data->value&IW_AUTH_ALG_OPEN_SYSTEM) ? 1 : 0;
686 //printk("open_wep:%d\n", ieee->open_wep);
690 case IW_AUTH_WPA_ENABLED:
691 ieee->wpa_enabled = (data->value) ? 1 : 0;
692 //printk("enable wpa:%d\n", ieee->wpa_enabled);
696 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
697 ieee->ieee802_1x = data->value;
699 case IW_AUTH_PRIVACY_INVOKED:
700 ieee->privacy_invoked = data->value;
709 int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len)
713 if (len > MAX_WPA_IE_LEN || (len && ie == NULL)) {
714 printk("return error out, len:%zu\n", len);
719 if (len != ie[1]+2) {
720 printk("len:%zu, ie:%d\n", len, ie[1]);
723 buf = kmemdup(ie, len, GFP_KERNEL);
728 ieee->wpa_ie_len = len;
732 ieee->wpa_ie_len = 0;
734 // printk("<=====out %s()\n", __func__);