📄 ieee80211_wx.c
字号:
/****************************************************************************** Copyright(c) 2004-2005 Intel Corporation. All rights reserved. Portions of this file are based on the WEP enablement code provided by the Host AP project hostap-drivers v0.1.3 Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen <j@w1.fi> Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi> This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. The full GNU General Public License is included in this distribution in the file called LICENSE. Contact Information: James P. Ketrenos <ipw2100-admin@linux.intel.com> Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497******************************************************************************/#include <linux/kmod.h>#include <linux/module.h>#include <linux/jiffies.h>#include "compat.h"#include <net/ieee80211.h>#include <linux/wireless.h>static const char *ieee80211_modes[] = { "?", "a", "b", "ab", "g", "ag", "bg", "abg"};#define MAX_CUSTOM_LEN 64static char *ieee80211_translate_scan(struct ieee80211_device *ieee, char *start, char *stop, struct ieee80211_network *network){ char custom[MAX_CUSTOM_LEN]; char *p; struct iw_event iwe; int i, j; char *current_val; /* For rates */ u8 rate; /* First entry *MUST* be the AP MAC address */ iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN); start = iwe_stream_add_event(start, stop, &iwe, IW_EV_ADDR_LEN); /* Remaining entries will be displayed in the order we provide them */ /* Add the ESSID */ iwe.cmd = SIOCGIWESSID; iwe.u.data.flags = 1; if (network->flags & NETWORK_EMPTY_ESSID) { iwe.u.data.length = sizeof("<hidden>"); start = iwe_stream_add_point(start, stop, &iwe, "<hidden>"); } else { iwe.u.data.length = min(network->ssid_len, (u8) 32); start = iwe_stream_add_point(start, stop, &iwe, network->ssid); } /* Add the protocol name */ iwe.cmd = SIOCGIWNAME; snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s", ieee80211_modes[network->mode]); start = iwe_stream_add_event(start, stop, &iwe, IW_EV_CHAR_LEN); /* Add mode */ iwe.cmd = SIOCGIWMODE; if (network->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) { if (network->capability & WLAN_CAPABILITY_ESS) iwe.u.mode = IW_MODE_MASTER; else iwe.u.mode = IW_MODE_ADHOC; start = iwe_stream_add_event(start, stop, &iwe, IW_EV_UINT_LEN); } /* Add channel and frequency */ iwe.cmd = SIOCGIWFREQ; iwe.u.freq.m = network->channel; iwe.u.freq.e = 0; iwe.u.freq.i = 0; start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN); iwe.u.freq.m = ieee80211_channel_to_freq(ieee, network->channel); iwe.u.freq.e = 6; start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN); /* Add encryption capability */ iwe.cmd = SIOCGIWENCODE; if (network->capability & WLAN_CAPABILITY_PRIVACY) iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; else iwe.u.data.flags = IW_ENCODE_DISABLED; iwe.u.data.length = 0; start = iwe_stream_add_point(start, stop, &iwe, network->ssid); /* Add basic and extended rates */ /* Rate : stuffing multiple values in a single event require a bit * more of magic - Jean II */ current_val = start + IW_EV_LCP_LEN; iwe.cmd = SIOCGIWRATE; /* Those two flags are ignored... */ iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; for (i = 0, j = 0; i < network->rates_len;) { if (j < network->rates_ex_len && ((network->rates_ex[j] & 0x7F) < (network->rates[i] & 0x7F))) rate = network->rates_ex[j++] & 0x7F; else rate = network->rates[i++] & 0x7F; /* Bit rate given in 500 kb/s units (+ 0x80) */ iwe.u.bitrate.value = ((rate & 0x7f) * 500000); /* Add new value to event */ current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN); } for (; j < network->rates_ex_len; j++) { rate = network->rates_ex[j] & 0x7F; /* Bit rate given in 500 kb/s units (+ 0x80) */ iwe.u.bitrate.value = ((rate & 0x7f) * 500000); /* Add new value to event */ current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN); } /* Check if we added any rate */ if((current_val - start) > IW_EV_LCP_LEN) start = current_val; /* Add quality statistics */ iwe.cmd = IWEVQUAL; iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_UPDATED; if (!(network->stats.mask & IEEE80211_STATMASK_RSSI)) { iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID; iwe.u.qual.qual = 0; } else { if (ieee->perfect_rssi == ieee->worst_rssi) iwe.u.qual.qual = 100; else iwe.u.qual.qual = (100 * (ieee->perfect_rssi - ieee->worst_rssi) * (ieee->perfect_rssi - ieee->worst_rssi) - (ieee->perfect_rssi - network->stats.rssi) * (15 * (ieee->perfect_rssi - ieee->worst_rssi) + 62 * (ieee->perfect_rssi - network->stats.rssi))) / ((ieee->perfect_rssi - ieee->worst_rssi) * (ieee->perfect_rssi - ieee->worst_rssi)); if (iwe.u.qual.qual > 100) iwe.u.qual.qual = 100; else if (iwe.u.qual.qual < 1) iwe.u.qual.qual = 0; } if (!(network->stats.mask & IEEE80211_STATMASK_NOISE)) { iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID; iwe.u.qual.noise = 0; } else { iwe.u.qual.noise = network->stats.noise; } if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL)) { iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID; iwe.u.qual.level = 0; } else { iwe.u.qual.level = network->stats.signal; } start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN); iwe.cmd = IWEVCUSTOM; p = custom; iwe.u.data.length = p - custom; if (iwe.u.data.length) start = iwe_stream_add_point(start, stop, &iwe, custom); memset(&iwe, 0, sizeof(iwe)); if (network->wpa_ie_len) {#ifdef IWEVGENIE char buf[MAX_WPA_IE_LEN]; memcpy(buf, network->wpa_ie, network->wpa_ie_len); iwe.cmd = IWEVGENIE; iwe.u.data.length = network->wpa_ie_len;#else char buf[MAX_WPA_IE_LEN * 2 + 30]; u8 *p = buf; p += sprintf(p, "wpa_ie="); for (i = 0; i < network->wpa_ie_len; i++) { p += sprintf(p, "%02x", network->wpa_ie[i]); } iwe.cmd = IWEVCUSTOM; iwe.u.data.length = strlen(buf);#endif start = iwe_stream_add_point(start, stop, &iwe, buf); } memset(&iwe, 0, sizeof(iwe)); if (network->rsn_ie_len) {#ifdef IWEVGENIE char buf[MAX_WPA_IE_LEN]; memcpy(buf, network->rsn_ie, network->rsn_ie_len); iwe.cmd = IWEVGENIE; iwe.u.data.length = network->rsn_ie_len;#else char buf[MAX_WPA_IE_LEN * 2 + 30]; u8 *p = buf; p += sprintf(p, "rsn_ie="); for (i = 0; i < network->rsn_ie_len; i++) { p += sprintf(p, "%02x", network->rsn_ie[i]); } iwe.cmd = IWEVCUSTOM; iwe.u.data.length = strlen(buf);#endif start = iwe_stream_add_point(start, stop, &iwe, buf); } /* Add EXTRA: Age to display seconds since last beacon/probe response * for given network. */ iwe.cmd = IWEVCUSTOM; p = custom; p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Last beacon: %dms ago", jiffies_to_msecs(jiffies - network->last_scanned)); iwe.u.data.length = p - custom; if (iwe.u.data.length) start = iwe_stream_add_point(start, stop, &iwe, custom); /* Add spectrum management information */ iwe.cmd = -1; p = custom; p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Channel flags: "); if (ieee80211_get_channel_flags(ieee, network->channel) & IEEE80211_CH_INVALID) { iwe.cmd = IWEVCUSTOM; p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "INVALID "); } if (ieee80211_get_channel_flags(ieee, network->channel) & IEEE80211_CH_RADAR_DETECT) { iwe.cmd = IWEVCUSTOM; p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "DFS "); } if (iwe.cmd == IWEVCUSTOM) { iwe.u.data.length = p - custom; start = iwe_stream_add_point(start, stop, &iwe, custom); } return start;}#define SCAN_ITEM_SIZE 128int ieee80211_wx_get_scan(struct ieee80211_device *ieee, struct iw_request_info *info, union iwreq_data *wrqu, char *extra){ struct ieee80211_network *network; unsigned long flags; int err = 0; char *ev = extra; char *stop = ev + wrqu->data.length; int i = 0; IEEE80211_DEBUG_WX("Getting scan\n"); spin_lock_irqsave(&ieee->lock, flags); list_for_each_entry(network, &ieee->network_list, list) { i++; if (stop - ev < SCAN_ITEM_SIZE) { err = -E2BIG; break; } if (ieee->scan_age == 0 || time_after(network->last_scanned + ieee->scan_age, jiffies)) ev = ieee80211_translate_scan(ieee, ev, stop, network); else IEEE80211_DEBUG_SCAN("Not showing network '%s (" MAC_FMT ")' due to age (%dms).\n", escape_essid(network->ssid, network->ssid_len), MAC_ARG(network->bssid), jiffies_to_msecs(jiffies - network-> last_scanned)); } spin_unlock_irqrestore(&ieee->lock, flags); wrqu->data.length = ev - extra; wrqu->data.flags = 0; IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i); return err;}int ieee80211_wx_set_encode(struct ieee80211_device *ieee, struct iw_request_info *info, union iwreq_data *wrqu, char *keybuf){ struct iw_point *erq = &(wrqu->encoding); struct net_device *dev = ieee->dev; struct ieee80211_security sec = { .flags = 0 }; int i, key, key_provided, len; struct ieee80211_crypt_data **crypt; int host_crypto = ieee->host_encrypt || ieee->host_decrypt || ieee->host_build_iv; IEEE80211_DEBUG_WX("SET_ENCODE\n"); key = erq->flags & IW_ENCODE_INDEX; if (key) { if (key > WEP_KEYS) return -EINVAL; key--; key_provided = 1; } else { key_provided = 0; key = ieee->tx_keyidx; } IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ? "provided" : "default"); crypt = &ieee->crypt[key]; if (erq->flags & IW_ENCODE_DISABLED) { if (key_provided && *crypt) { IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n", key); ieee80211_crypt_delayed_deinit(ieee, crypt); } else IEEE80211_DEBUG_WX("Disabling encryption.\n"); /* Check all the keys to see if any are still configured, * and if no key index was provided, de-init them all */ for (i = 0; i < WEP_KEYS; i++) { if (ieee->crypt[i] != NULL) { if (key_provided) break; ieee80211_crypt_delayed_deinit(ieee, &ieee->crypt[i]); } } if (i == WEP_KEYS) { sec.enabled = 0; sec.encrypt = 0; sec.level = SEC_LEVEL_0; sec.flags |= SEC_ENABLED | SEC_LEVEL | SEC_ENCRYPT; } goto done; } sec.enabled = 1; sec.encrypt = 1; sec.flags |= SEC_ENABLED | SEC_ENCRYPT; if (*crypt != NULL && (*crypt)->ops != NULL && strcmp((*crypt)->ops->name, "WEP") != 0) { /* changing to use WEP; deinit previously used algorithm * on this key */ ieee80211_crypt_delayed_deinit(ieee, crypt); } if (*crypt == NULL && host_crypto) { struct ieee80211_crypt_data *new_crypt; /* take WEP into use */ new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data), GFP_KERNEL); if (new_crypt == NULL) return -ENOMEM; new_crypt->ops = ieee80211_get_crypto_ops("WEP"); if (!new_crypt->ops) { request_module("ieee80211_crypt_wep"); new_crypt->ops = ieee80211_get_crypto_ops("WEP"); } if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) new_crypt->priv = new_crypt->ops->init(key); if (!new_crypt->ops || !new_crypt->priv) { kfree(new_crypt); new_crypt = NULL; printk(KERN_WARNING "%s: could not initialize WEP: " "load module ieee80211_crypt_wep\n", dev->name); return -EOPNOTSUPP; } *crypt = new_crypt; } /* If a new key was provided, set it up */ if (erq->length > 0) { len = erq->length <= 5 ? 5 : 13; memcpy(sec.keys[key], keybuf, erq->length); if (len > erq->length) memset(sec.keys[key] + erq->length, 0, len - erq->length); IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n", key, escape_essid(sec.keys[key], len), erq->length, len); sec.key_sizes[key] = len; if (*crypt) (*crypt)->ops->set_key(sec.keys[key], len, NULL,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -