diff options
Diffstat (limited to 'net/mac80211')
38 files changed, 5795 insertions, 6096 deletions
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index a9c2d07..219cd9f 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_MAC80211) += mac80211.o rc80211_simple.o mac80211-objs-$(CONFIG_MAC80211_LEDS) += ieee80211_led.o mac80211-objs-$(CONFIG_MAC80211_DEBUGFS) += debugfs.o debugfs_sta.o debugfs_netdev.o debugfs_key.o +mac80211-objs-$(CONFIG_NET_SCHED) += wme.o mac80211-objs := \ ieee80211.o \ @@ -16,6 +17,10 @@ mac80211-objs := \ regdomain.o \ tkip.o \ aes_ccm.o \ - wme.o \ - ieee80211_cfg.o \ + cfg.o \ + rx.o \ + tx.o \ + key.o \ + util.o \ + event.o \ $(mac80211-objs-y) diff --git a/net/mac80211/aes_ccm.c b/net/mac80211/aes_ccm.c index e55569b..bf7ba12 100644 --- a/net/mac80211/aes_ccm.c +++ b/net/mac80211/aes_ccm.c @@ -7,6 +7,7 @@ * published by the Free Software Foundation. */ +#include <linux/kernel.h> #include <linux/types.h> #include <linux/crypto.h> #include <linux/err.h> @@ -63,7 +64,7 @@ void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch, s_0 = scratch + AES_BLOCK_LEN; e = scratch + 2 * AES_BLOCK_LEN; - num_blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN; + num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN); last_len = data_len % AES_BLOCK_LEN; aes_ccm_prepare(tfm, b_0, aad, b, s_0, b); @@ -102,7 +103,7 @@ int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch, s_0 = scratch + AES_BLOCK_LEN; a = scratch + 2 * AES_BLOCK_LEN; - num_blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN; + num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN); last_len = data_len % AES_BLOCK_LEN; aes_ccm_prepare(tfm, b_0, aad, b, s_0, a); diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c new file mode 100644 index 0000000..9e2bc1f --- /dev/null +++ b/net/mac80211/cfg.c @@ -0,0 +1,106 @@ +/* + * mac80211 configuration hooks for cfg80211 + * + * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> + * + * This file is GPLv2 as found in COPYING. + */ + +#include <linux/nl80211.h> +#include <linux/rtnetlink.h> +#include <net/net_namespace.h> +#include <net/cfg80211.h> +#include "ieee80211_i.h" +#include "cfg.h" + +static enum ieee80211_if_types +nl80211_type_to_mac80211_type(enum nl80211_iftype type) +{ + switch (type) { + case NL80211_IFTYPE_UNSPECIFIED: + return IEEE80211_IF_TYPE_STA; + case NL80211_IFTYPE_ADHOC: + return IEEE80211_IF_TYPE_IBSS; + case NL80211_IFTYPE_STATION: + return IEEE80211_IF_TYPE_STA; + case NL80211_IFTYPE_MONITOR: + return IEEE80211_IF_TYPE_MNTR; + default: + return IEEE80211_IF_TYPE_INVALID; + } +} + +static int ieee80211_add_iface(struct wiphy *wiphy, char *name, + enum nl80211_iftype type) +{ + struct ieee80211_local *local = wiphy_priv(wiphy); + enum ieee80211_if_types itype; + + if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED)) + return -ENODEV; + + itype = nl80211_type_to_mac80211_type(type); + if (itype == IEEE80211_IF_TYPE_INVALID) + return -EINVAL; + + return ieee80211_if_add(local->mdev, name, NULL, itype); +} + +static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex) +{ + struct ieee80211_local *local = wiphy_priv(wiphy); + struct net_device *dev; + char *name; + + if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED)) + return -ENODEV; + + /* we're under RTNL */ + dev = __dev_get_by_index(&init_net, ifindex); + if (!dev) + return 0; + + name = dev->name; + + return ieee80211_if_remove(local->mdev, name, -1); +} + +static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, + enum nl80211_iftype type) +{ + struct ieee80211_local *local = wiphy_priv(wiphy); + struct net_device *dev; + enum ieee80211_if_types itype; + struct ieee80211_sub_if_data *sdata; + + if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED)) + return -ENODEV; + + /* we're under RTNL */ + dev = __dev_get_by_index(&init_net, ifindex); + if (!dev) + return -ENODEV; + + if (netif_running(dev)) + return -EBUSY; + + itype = nl80211_type_to_mac80211_type(type); + if (itype == IEEE80211_IF_TYPE_INVALID) + return -EINVAL; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + if (sdata->type == IEEE80211_IF_TYPE_VLAN) + return -EOPNOTSUPP; + + ieee80211_if_reinit(dev); + ieee80211_if_set_type(dev, itype); + + return 0; +} + +struct cfg80211_ops mac80211_config_ops = { + .add_virtual_intf = ieee80211_add_iface, + .del_virtual_intf = ieee80211_del_iface, + .change_virtual_intf = ieee80211_change_iface, +}; diff --git a/net/mac80211/ieee80211_cfg.h b/net/mac80211/cfg.h index 85ed2c9..7d7879f 100644 --- a/net/mac80211/ieee80211_cfg.h +++ b/net/mac80211/cfg.h @@ -1,9 +1,9 @@ /* * mac80211 configuration hooks for cfg80211 */ -#ifndef __IEEE80211_CFG_H -#define __IEEE80211_CFG_H +#ifndef __CFG_H +#define __CFG_H extern struct cfg80211_ops mac80211_config_ops; -#endif /* __IEEE80211_CFG_H */ +#endif /* __CFG_H */ diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 476c848..60514b2 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -28,8 +28,6 @@ static const char *ieee80211_mode_str(int mode) return "IEEE 802.11b"; case MODE_IEEE80211G: return "IEEE 802.11g"; - case MODE_ATHEROS_TURBO: - return "Atheros Turbo (5 GHz)"; default: return "UNKNOWN"; } @@ -86,16 +84,12 @@ DEBUGFS_READONLY_FILE(channel, 20, "%d", local->hw.conf.channel); DEBUGFS_READONLY_FILE(frequency, 20, "%d", local->hw.conf.freq); -DEBUGFS_READONLY_FILE(radar_detect, 20, "%d", - local->hw.conf.radar_detect); DEBUGFS_READONLY_FILE(antenna_sel_tx, 20, "%d", local->hw.conf.antenna_sel_tx); DEBUGFS_READONLY_FILE(antenna_sel_rx, 20, "%d", local->hw.conf.antenna_sel_rx); DEBUGFS_READONLY_FILE(bridge_packets, 20, "%d", local->bridge_packets); -DEBUGFS_READONLY_FILE(key_tx_rx_threshold, 20, "%d", - local->key_tx_rx_threshold); DEBUGFS_READONLY_FILE(rts_threshold, 20, "%d", local->rts_threshold); DEBUGFS_READONLY_FILE(fragmentation_threshold, 20, "%d", @@ -110,9 +104,6 @@ DEBUGFS_READONLY_FILE(mode, 20, "%s", ieee80211_mode_str(local->hw.conf.phymode)); DEBUGFS_READONLY_FILE(wep_iv, 20, "%#06x", local->wep_iv & 0xffffff); -DEBUGFS_READONLY_FILE(tx_power_reduction, 20, "%d.%d dBm", - local->hw.conf.tx_power_reduction / 10, - local->hw.conf.tx_power_reduction % 10); DEBUGFS_READONLY_FILE(rate_ctrl_alg, 100, "%s", local->rate_ctrl ? local->rate_ctrl->ops->name : "<unset>"); @@ -305,11 +296,9 @@ void debugfs_hw_add(struct ieee80211_local *local) DEBUGFS_ADD(channel); DEBUGFS_ADD(frequency); - DEBUGFS_ADD(radar_detect); DEBUGFS_ADD(antenna_sel_tx); DEBUGFS_ADD(antenna_sel_rx); DEBUGFS_ADD(bridge_packets); - DEBUGFS_ADD(key_tx_rx_threshold); DEBUGFS_ADD(rts_threshold); DEBUGFS_ADD(fragmentation_threshold); DEBUGFS_ADD(short_retry_limit); @@ -317,7 +306,6 @@ void debugfs_hw_add(struct ieee80211_local *local) DEBUGFS_ADD(total_ps_buffered); DEBUGFS_ADD(mode); DEBUGFS_ADD(wep_iv); - DEBUGFS_ADD(tx_power_reduction); DEBUGFS_ADD(modes); statsd = debugfs_create_dir("statistics", phyd); @@ -370,11 +358,9 @@ void debugfs_hw_del(struct ieee80211_local *local) { DEBUGFS_DEL(channel); DEBUGFS_DEL(frequency); - DEBUGFS_DEL(radar_detect); DEBUGFS_DEL(antenna_sel_tx); DEBUGFS_DEL(antenna_sel_rx); DEBUGFS_DEL(bridge_packets); - DEBUGFS_DEL(key_tx_rx_threshold); DEBUGFS_DEL(rts_threshold); DEBUGFS_DEL(fragmentation_threshold); DEBUGFS_DEL(short_retry_limit); @@ -382,7 +368,6 @@ void debugfs_hw_del(struct ieee80211_local *local) DEBUGFS_DEL(total_ps_buffered); DEBUGFS_DEL(mode); DEBUGFS_DEL(wep_iv); - DEBUGFS_DEL(tx_power_reduction); DEBUGFS_DEL(modes); DEBUGFS_STATS_DEL(transmitted_fragment_count); diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 7d56dc9..c881524 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c @@ -14,17 +14,18 @@ #include "debugfs.h" #include "debugfs_key.h" -#define KEY_READ(name, buflen, format_string) \ +#define KEY_READ(name, prop, buflen, format_string) \ static ssize_t key_##name##_read(struct file *file, \ char __user *userbuf, \ size_t count, loff_t *ppos) \ { \ char buf[buflen]; \ struct ieee80211_key *key = file->private_data; \ - int res = scnprintf(buf, buflen, format_string, key->name); \ + int res = scnprintf(buf, buflen, format_string, key->prop); \ return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ } -#define KEY_READ_D(name) KEY_READ(name, 20, "%d\n") +#define KEY_READ_D(name) KEY_READ(name, name, 20, "%d\n") +#define KEY_READ_X(name) KEY_READ(name, name, 20, "0x%x\n") #define KEY_OPS(name) \ static const struct file_operations key_ ##name## _ops = { \ @@ -36,11 +37,27 @@ static const struct file_operations key_ ##name## _ops = { \ KEY_READ_##format(name) \ KEY_OPS(name) -KEY_FILE(keylen, D); -KEY_FILE(force_sw_encrypt, D); -KEY_FILE(keyidx, D); -KEY_FILE(hw_key_idx, D); +#define KEY_CONF_READ(name, buflen, format_string) \ + KEY_READ(conf_##name, conf.name, buflen, format_string) +#define KEY_CONF_READ_D(name) KEY_CONF_READ(name, 20, "%d\n") + +#define KEY_CONF_OPS(name) \ +static const struct file_operations key_ ##name## _ops = { \ + .read = key_conf_##name##_read, \ + .open = mac80211_open_file_generic, \ +} + +#define KEY_CONF_FILE(name, format) \ + KEY_CONF_READ_##format(name) \ + KEY_CONF_OPS(name) + +KEY_CONF_FILE(keylen, D); +KEY_CONF_FILE(keyidx, D); +KEY_CONF_FILE(hw_key_idx, D); +KEY_FILE(flags, X); KEY_FILE(tx_rx_count, D); +KEY_READ(ifindex, sdata->dev->ifindex, 20, "%d\n"); +KEY_OPS(ifindex); static ssize_t key_algorithm_read(struct file *file, char __user *userbuf, @@ -49,7 +66,7 @@ static ssize_t key_algorithm_read(struct file *file, char *alg; struct ieee80211_key *key = file->private_data; - switch (key->alg) { + switch (key->conf.alg) { case ALG_WEP: alg = "WEP\n"; break; @@ -74,17 +91,20 @@ static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf, int len; struct ieee80211_key *key = file->private_data; - switch (key->alg) { + switch (key->conf.alg) { case ALG_WEP: len = scnprintf(buf, sizeof(buf), "\n"); + break; case ALG_TKIP: len = scnprintf(buf, sizeof(buf), "%08x %04x\n", key->u.tkip.iv32, key->u.tkip.iv16); + break; case ALG_CCMP: tpn = key->u.ccmp.tx_pn; len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n", tpn[0], tpn[1], tpn[2], tpn[3], tpn[4], tpn[5]); + break; default: return 0; } @@ -100,9 +120,10 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf, int i, len; const u8 *rpn; - switch (key->alg) { + switch (key->conf.alg) { case ALG_WEP: len = scnprintf(buf, sizeof(buf), "\n"); + break; case ALG_TKIP: for (i = 0; i < NUM_RX_DATA_QUEUES; i++) p += scnprintf(p, sizeof(buf)+buf-p, @@ -110,6 +131,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf, key->u.tkip.iv32_rx[i], key->u.tkip.iv16_rx[i]); len = p - buf; + break; case ALG_CCMP: for (i = 0; i < NUM_RX_DATA_QUEUES; i++) { rpn = key->u.ccmp.rx_pn[i]; @@ -119,6 +141,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf, rpn[3], rpn[4], rpn[5]); } len = p - buf; + break; default: return 0; } @@ -133,7 +156,7 @@ static ssize_t key_replays_read(struct file *file, char __user *userbuf, char buf[20]; int len; - if (key->alg != ALG_CCMP) + if (key->conf.alg != ALG_CCMP) return 0; len = scnprintf(buf, sizeof(buf), "%u\n", key->u.ccmp.replays); return simple_read_from_buffer(userbuf, count, ppos, buf, len); @@ -144,12 +167,12 @@ static ssize_t key_key_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { struct ieee80211_key *key = file->private_data; - int i, res, bufsize = 2*key->keylen+2; + int i, res, bufsize = 2 * key->conf.keylen + 2; char *buf = kmalloc(bufsize, GFP_KERNEL); char *p = buf; - for (i = 0; i < key->keylen; i++) - p += scnprintf(p, bufsize+buf-p, "%02x", key->key[i]); + for (i = 0; i < key->conf.keylen; i++) + p += scnprintf(p, bufsize + buf - p, "%02x", key->conf.key[i]); p += scnprintf(p, bufsize+buf-p, "\n"); res = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); kfree(buf); @@ -164,12 +187,14 @@ KEY_OPS(key); void ieee80211_debugfs_key_add(struct ieee80211_local *local, struct ieee80211_key *key) { + static int keycount; char buf[20]; if (!local->debugfs.keys) return; - sprintf(buf, "%d", key->keyidx); + sprintf(buf, "%d", keycount); + keycount++; key->debugfs.dir = debugfs_create_dir(buf, local->debugfs.keys); @@ -177,7 +202,7 @@ void ieee80211_debugfs_key_add(struct ieee80211_local *local, return; DEBUGFS_ADD(keylen); - DEBUGFS_ADD(force_sw_encrypt); + DEBUGFS_ADD(flags); DEBUGFS_ADD(keyidx); DEBUGFS_ADD(hw_key_idx); DEBUGFS_ADD(tx_rx_count); @@ -186,6 +211,7 @@ void ieee80211_debugfs_key_add(struct ieee80211_local *local, DEBUGFS_ADD(rx_spec); DEBUGFS_ADD(replays); DEBUGFS_ADD(key); + DEBUGFS_ADD(ifindex); }; #define DEBUGFS_DEL(name) \ @@ -197,7 +223,7 @@ void ieee80211_debugfs_key_remove(struct ieee80211_key *key) return; DEBUGFS_DEL(keylen); - DEBUGFS_DEL(force_sw_encrypt); + DEBUGFS_DEL(flags); DEBUGFS_DEL(keyidx); DEBUGFS_DEL(hw_key_idx); DEBUGFS_DEL(tx_rx_count); @@ -206,6 +232,7 @@ void ieee80211_debugfs_key_remove(struct ieee80211_key *key) DEBUGFS_DEL(rx_spec); DEBUGFS_DEL(replays); DEBUGFS_DEL(key); + DEBUGFS_DEL(ifindex); debugfs_remove(key->debugfs.stalink); key->debugfs.stalink = NULL; @@ -219,7 +246,7 @@ void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata) if (!sdata->debugfsdir) return; - sprintf(buf, "../keys/%d", sdata->default_key->keyidx); + sprintf(buf, "../keys/%d", sdata->default_key->conf.keyidx); sdata->debugfs.default_key = debugfs_create_symlink("default_key", sdata->debugfsdir, buf); } @@ -235,11 +262,12 @@ void ieee80211_debugfs_key_sta_link(struct ieee80211_key *key, struct sta_info *sta) { char buf[50]; + DECLARE_MAC_BUF(mac); if (!key->debugfs.dir) return; - sprintf(buf, "../sta/" MAC_FMT, MAC_ARG(sta->addr)); + sprintf(buf, "../../stations/%s", print_mac(mac, sta->addr)); key->debugfs.stalink = debugfs_create_symlink("station", key->debugfs.dir, buf); } diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 095be91..f0e6ab7 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -66,7 +66,8 @@ static ssize_t ieee80211_if_fmt_##name( \ const struct ieee80211_sub_if_data *sdata, char *buf, \ int buflen) \ { \ - return scnprintf(buf, buflen, MAC_FMT "\n", MAC_ARG(sdata->field));\ + DECLARE_MAC_BUF(mac); \ + return scnprintf(buf, buflen, "%s\n", print_mac(mac, sdata->field));\ } #define __IEEE80211_IF_FILE(name) \ @@ -112,13 +113,13 @@ static ssize_t ieee80211_if_fmt_flags( const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) { return scnprintf(buf, buflen, "%s%s%s%s%s%s%s\n", - sdata->u.sta.ssid_set ? "SSID\n" : "", - sdata->u.sta.bssid_set ? "BSSID\n" : "", - sdata->u.sta.prev_bssid_set ? "prev BSSID\n" : "", - sdata->u.sta.authenticated ? "AUTH\n" : "", - sdata->u.sta.associated ? "ASSOC\n" : "", - sdata->u.sta.probereq_poll ? "PROBEREQ POLL\n" : "", - sdata->use_protection ? "CTS prot\n" : ""); + sdata->u.sta.flags & IEEE80211_STA_SSID_SET ? "SSID\n" : "", + sdata->u.sta.flags & IEEE80211_STA_BSSID_SET ? "BSSID\n" : "", + sdata->u.sta.flags & IEEE80211_STA_PREV_BSSID_SET ? "prev BSSID\n" : "", + sdata->u.sta.flags & IEEE80211_STA_AUTHENTICATED ? "AUTH\n" : "", + sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED ? "ASSOC\n" : "", + sdata->u.sta.flags & IEEE80211_STA_PROBEREQ_POLL ? "PROBEREQ POLL\n" : "", + sdata->flags & IEEE80211_SDATA_USE_PROTECTION ? "CTS prot\n" : ""); } __IEEE80211_IF_FILE(flags); @@ -161,23 +162,6 @@ __IEEE80211_IF_FILE(beacon_tail_len); /* WDS attributes */ IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); -/* VLAN attributes */ -IEEE80211_IF_FILE(vlan_id, u.vlan.id, DEC); - -/* MONITOR attributes */ -static ssize_t ieee80211_if_fmt_mode( - const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) -{ - struct ieee80211_local *local = sdata->local; - - return scnprintf(buf, buflen, "%s\n", - ((local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) || - local->open_count == local->monitors) ? - "hard" : "soft"); -} -__IEEE80211_IF_FILE(mode); - - #define DEBUGFS_ADD(name, type)\ sdata->debugfs.type.name = debugfs_create_file(#name, 0444,\ sdata->debugfsdir, sdata, &name##_ops); @@ -236,12 +220,10 @@ static void add_vlan_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_ADD(drop_unencrypted, vlan); DEBUGFS_ADD(eapol, vlan); DEBUGFS_ADD(ieee8021_x, vlan); - DEBUGFS_ADD(vlan_id, vlan); } static void add_monitor_files(struct ieee80211_sub_if_data *sdata) { - DEBUGFS_ADD(mode, monitor); } static void add_files(struct ieee80211_sub_if_data *sdata) @@ -331,12 +313,10 @@ static void del_vlan_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_DEL(drop_unencrypted, vlan); DEBUGFS_DEL(eapol, vlan); DEBUGFS_DEL(ieee8021_x, vlan); - DEBUGFS_DEL(vlan_id, vlan); } static void del_monitor_files(struct ieee80211_sub_if_data *sdata) { - DEBUGFS_DEL(mode, monitor); } static void del_files(struct ieee80211_sub_if_data *sdata, int type) diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index da34ea7..8f5944c 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -60,9 +60,7 @@ static const struct file_operations sta_ ##name## _ops = { \ STA_OPS(name) STA_FILE(aid, aid, D); -STA_FILE(key_idx_compression, key_idx_compression, D); STA_FILE(dev, dev->name, S); -STA_FILE(vlan_id, vlan_id, D); STA_FILE(rx_packets, rx_packets, LU); STA_FILE(tx_packets, tx_packets, LU); STA_FILE(rx_bytes, rx_bytes, LU); @@ -204,15 +202,15 @@ STA_OPS(wme_tx_queue); void ieee80211_sta_debugfs_add(struct sta_info *sta) { - char buf[3*6]; struct dentry *stations_dir = sta->local->debugfs.stations; + DECLARE_MAC_BUF(mac); if (!stations_dir) return; - sprintf(buf, MAC_FMT, MAC_ARG(sta->addr)); + print_mac(mac, sta->addr); - sta->debugfs.dir = debugfs_create_dir(buf, stations_dir); + sta->debugfs.dir = debugfs_create_dir(mac, stations_dir); if (!sta->debugfs.dir) return; diff --git a/net/mac80211/event.c b/net/mac80211/event.c new file mode 100644 index 0000000..2280f40 --- /dev/null +++ b/net/mac80211/event.c @@ -0,0 +1,43 @@ +/* + * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * mac80211 - events + */ + +#include <linux/netdevice.h> +#include <net/iw_handler.h> +#include "ieee80211_i.h" + +/* + * indicate a failed Michael MIC to userspace; the passed packet + * (in the variable hdr) must be long enough to extract the TKIP + * fields like TSC + */ +void mac80211_ev_michael_mic_failure(struct net_device *dev, int keyidx, + struct ieee80211_hdr *hdr) +{ + union iwreq_data wrqu; + char *buf = kmalloc(128, GFP_ATOMIC); + DECLARE_MAC_BUF(mac); + + if (buf) { + /* TODO: needed parameters: count, key type, TSC */ + sprintf(buf, "MLME-MICHAELMICFAILURE.indication(" + "keyid=%d %scast addr=%s)", + keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni", + print_mac(mac, hdr->addr2)); + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = strlen(buf); + wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf); + kfree(buf); + } + + /* + * TODO: re-add support for sending MIC failure indication + * with all info via nl80211 + */ +} diff --git a/net/mac80211/hostapd_ioctl.h b/net/mac80211/hostapd_ioctl.h deleted file mode 100644 index 52da513..0000000 --- a/net/mac80211/hostapd_ioctl.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Host AP (software wireless LAN access point) user space daemon for - * Host AP kernel driver - * Copyright 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi> - * Copyright 2002-2004, Instant802 Networks, Inc. - * Copyright 2005, Devicescape Software, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef HOSTAPD_IOCTL_H -#define HOSTAPD_IOCTL_H - -#ifdef __KERNEL__ -#include <linux/types.h> -#endif /* __KERNEL__ */ - -#define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0) -#define PRISM2_IOCTL_GET_PRISM2_PARAM (SIOCIWFIRSTPRIV + 1) -#define PRISM2_IOCTL_HOSTAPD (SIOCIWFIRSTPRIV + 3) - -/* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes: - * This table is no longer added to, the whole sub-ioctl - * mess shall be deleted completely. */ -enum { - PRISM2_PARAM_IEEE_802_1X = 23, - - /* Instant802 additions */ - PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES = 1001, - PRISM2_PARAM_PREAMBLE = 1003, - PRISM2_PARAM_SHORT_SLOT_TIME = 1006, - PRISM2_PARAM_NEXT_MODE = 1008, - PRISM2_PARAM_RADIO_ENABLED = 1010, - PRISM2_PARAM_ANTENNA_MODE = 1013, - PRISM2_PARAM_STAT_TIME = 1016, - PRISM2_PARAM_STA_ANTENNA_SEL = 1017, - PRISM2_PARAM_TX_POWER_REDUCTION = 1022, - PRISM2_PARAM_KEY_TX_RX_THRESHOLD = 1024, - PRISM2_PARAM_DEFAULT_WEP_ONLY = 1026, - PRISM2_PARAM_WIFI_WME_NOACK_TEST = 1033, - PRISM2_PARAM_SCAN_FLAGS = 1035, - PRISM2_PARAM_HW_MODES = 1036, - PRISM2_PARAM_CREATE_IBSS = 1037, - PRISM2_PARAM_WMM_ENABLED = 1038, - PRISM2_PARAM_MIXED_CELL = 1039, - PRISM2_PARAM_RADAR_DETECT = 1043, - PRISM2_PARAM_SPECTRUM_MGMT = 1044, -}; - -enum { - IEEE80211_KEY_MGMT_NONE = 0, - IEEE80211_KEY_MGMT_IEEE8021X = 1, - IEEE80211_KEY_MGMT_WPA_PSK = 2, - IEEE80211_KEY_MGMT_WPA_EAP = 3, -}; - - -/* Data structures used for get_hw_features ioctl */ -struct hostapd_ioctl_hw_modes_hdr { - int mode; - int num_channels; - int num_rates; -}; - -struct ieee80211_channel_data { - short chan; /* channel number (IEEE 802.11) */ - short freq; /* frequency in MHz */ - int flag; /* flag for hostapd use (IEEE80211_CHAN_*) */ -}; - -struct ieee80211_rate_data { - int rate; /* rate in 100 kbps */ - int flags; /* IEEE80211_RATE_ flags */ -}; - - -/* ADD_IF, REMOVE_IF, and UPDATE_IF 'type' argument */ -enum { - HOSTAP_IF_WDS = 1, HOSTAP_IF_VLAN = 2, HOSTAP_IF_BSS = 3, - HOSTAP_IF_STA = 4 -}; - -struct hostapd_if_wds { - u8 remote_addr[ETH_ALEN]; -}; - -struct hostapd_if_vlan { - u8 id; -}; - -struct hostapd_if_bss { - u8 bssid[ETH_ALEN]; -}; - -struct hostapd_if_sta { -}; - -#endif /* HOSTAPD_IOCTL_H */ diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index ff2172f..f484ca7 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -20,42 +20,19 @@ #include <linux/if_arp.h> #include <linux/wireless.h> #include <linux/rtnetlink.h> -#include <net/iw_handler.h> -#include <linux/compiler.h> #include <linux/bitmap.h> +#include <net/net_namespace.h> #include <net/cfg80211.h> -#include <asm/unaligned.h> -#include "ieee80211_common.h" #include "ieee80211_i.h" #include "ieee80211_rate.h" #include "wep.h" -#include "wpa.h" -#include "tkip.h" #include "wme.h" #include "aes_ccm.h" #include "ieee80211_led.h" -#include "ieee80211_cfg.h" +#include "cfg.h" #include "debugfs.h" #include "debugfs_netdev.h" -#include "debugfs_key.h" - -/* privid for wiphys to determine whether they belong to us or not */ -void *mac80211_wiphy_privid = &mac80211_wiphy_privid; - -/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ -/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ -static const unsigned char rfc1042_header[] = - { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; - -/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ -static const unsigned char bridge_tunnel_header[] = - { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; - -/* No encapsulation header if EtherType < 0x600 (=length) */ -static const unsigned char eapol_header[] = - { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8e }; - /* * For seeing transmitted packets on monitor interfaces @@ -67,2217 +44,408 @@ struct ieee80211_tx_status_rtap_hdr { u8 data_retries; } __attribute__ ((packed)); +/* common interface routines */ -static inline void ieee80211_include_sequence(struct ieee80211_sub_if_data *sdata, - struct ieee80211_hdr *hdr) -{ - /* Set the sequence number for this frame. */ - hdr->seq_ctrl = cpu_to_le16(sdata->sequence); - - /* Increase the sequence number. */ - sdata->sequence = (sdata->sequence + 0x10) & IEEE80211_SCTL_SEQ; -} - -struct ieee80211_key_conf * -ieee80211_key_data2conf(struct ieee80211_local *local, - const struct ieee80211_key *data) +static int header_parse_80211(const struct sk_buff *skb, unsigned char *haddr) { - struct ieee80211_key_conf *conf; - - conf = kmalloc(sizeof(*conf) + data->keylen, GFP_ATOMIC); - if (!conf) - return NULL; - - conf->hw_key_idx = data->hw_key_idx; - conf->alg = data->alg; - conf->keylen = data->keylen; - conf->flags = 0; - if (data->force_sw_encrypt) - conf->flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT; - conf->keyidx = data->keyidx; - if (data->default_tx_key) - conf->flags |= IEEE80211_KEY_DEFAULT_TX_KEY; - if (local->default_wep_only) - conf->flags |= IEEE80211_KEY_DEFAULT_WEP_ONLY; - memcpy(conf->key, data->key, data->keylen); - - return conf; + memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */ + return ETH_ALEN; } -struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, - int idx, size_t key_len, gfp_t flags) +/* must be called under mdev tx lock */ +static void ieee80211_configure_filter(struct ieee80211_local *local) { - struct ieee80211_key *key; + unsigned int changed_flags; + unsigned int new_flags = 0; - key = kzalloc(sizeof(struct ieee80211_key) + key_len, flags); - if (!key) - return NULL; - kref_init(&key->kref); - return key; -} + if (atomic_read(&local->iff_promiscs)) + new_flags |= FIF_PROMISC_IN_BSS; -static void ieee80211_key_release(struct kref *kref) -{ - struct ieee80211_key *key; + if (atomic_read(&local->iff_allmultis)) + new_flags |= FIF_ALLMULTI; - key = container_of(kref, struct ieee80211_key, kref); - if (key->alg == ALG_CCMP) - ieee80211_aes_key_free(key->u.ccmp.tfm); - ieee80211_debugfs_key_remove(key); - kfree(key); -} + if (local->monitors) + new_flags |= FIF_CONTROL | + FIF_OTHER_BSS | + FIF_BCN_PRBRESP_PROMISC; -void ieee80211_key_free(struct ieee80211_key *key) -{ - if (key) - kref_put(&key->kref, ieee80211_key_release); -} + changed_flags = local->filter_flags ^ new_flags; -static int rate_list_match(const int *rate_list, int rate) -{ - int i; + /* be a bit nasty */ + new_flags |= (1<<31); - if (!rate_list) - return 0; + local->ops->configure_filter(local_to_hw(local), + changed_flags, &new_flags, + local->mdev->mc_count, + local->mdev->mc_list); - for (i = 0; rate_list[i] >= 0; i++) - if (rate_list[i] == rate) - return 1; + WARN_ON(new_flags & (1<<31)); - return 0; + local->filter_flags = new_flags & ~(1<<31); } +/* master interface */ -void ieee80211_prepare_rates(struct ieee80211_local *local, - struct ieee80211_hw_mode *mode) +static int ieee80211_master_open(struct net_device *dev) { - int i; - - for (i = 0; i < mode->num_rates; i++) { - struct ieee80211_rate *rate = &mode->rates[i]; - - rate->flags &= ~(IEEE80211_RATE_SUPPORTED | - IEEE80211_RATE_BASIC); - - if (local->supp_rates[mode->mode]) { - if (!rate_list_match(local->supp_rates[mode->mode], - rate->rate)) - continue; - } - - rate->flags |= IEEE80211_RATE_SUPPORTED; - - /* Use configured basic rate set if it is available. If not, - * use defaults that are sane for most cases. */ - if (local->basic_rates[mode->mode]) { - if (rate_list_match(local->basic_rates[mode->mode], - rate->rate)) - rate->flags |= IEEE80211_RATE_BASIC; - } else switch (mode->mode) { - case MODE_IEEE80211A: - if (rate->rate == 60 || rate->rate == 120 || - rate->rate == 240) - rate->flags |= IEEE80211_RATE_BASIC; - break; - case MODE_IEEE80211B: - if (rate->rate == 10 || rate->rate == 20) - rate->flags |= IEEE80211_RATE_BASIC; - break; - case MODE_ATHEROS_TURBO: - if (rate->rate == 120 || rate->rate == 240 || - rate->rate == 480) - rate->flags |= IEEE80211_RATE_BASIC; - break; - case MODE_IEEE80211G: - if (rate->rate == 10 || rate->rate == 20 || - rate->rate == 55 || rate->rate == 110) - rate->flags |= IEEE80211_RATE_BASIC; - break; - } + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata; + int res = -EOPNOTSUPP; - /* Set ERP and MANDATORY flags based on phymode */ - switch (mode->mode) { - case MODE_IEEE80211A: - if (rate->rate == 60 || rate->rate == 120 || - rate->rate == 240) - rate->flags |= IEEE80211_RATE_MANDATORY; - break; - case MODE_IEEE80211B: - if (rate->rate == 10) - rate->flags |= IEEE80211_RATE_MANDATORY; - break; - case MODE_ATHEROS_TURBO: - break; - case MODE_IEEE80211G: - if (rate->rate == 10 || rate->rate == 20 || - rate->rate == 55 || rate->rate == 110 || - rate->rate == 60 || rate->rate == 120 || - rate->rate == 240) - rate->flags |= IEEE80211_RATE_MANDATORY; + /* we hold the RTNL here so can safely walk the list */ + list_for_each_entry(sdata, &local->interfaces, list) { + if (sdata->dev != dev && netif_running(sdata->dev)) { + res = 0; break; } - if (ieee80211_is_erp_rate(mode->mode, rate->rate)) - rate->flags |= IEEE80211_RATE_ERP; } + return res; } - -static void ieee80211_key_threshold_notify(struct net_device *dev, - struct ieee80211_key *key, - struct sta_info *sta) +static int ieee80211_master_stop(struct net_device *dev) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct sk_buff *skb; - struct ieee80211_msg_key_notification *msg; - - /* if no one will get it anyway, don't even allocate it. - * unlikely because this is only relevant for APs - * where the device must be open... */ - if (unlikely(!local->apdev)) - return; - - skb = dev_alloc_skb(sizeof(struct ieee80211_frame_info) + - sizeof(struct ieee80211_msg_key_notification)); - if (!skb) - return; - - skb_reserve(skb, sizeof(struct ieee80211_frame_info)); - msg = (struct ieee80211_msg_key_notification *) - skb_put(skb, sizeof(struct ieee80211_msg_key_notification)); - msg->tx_rx_count = key->tx_rx_count; - memcpy(msg->ifname, dev->name, IFNAMSIZ); - if (sta) - memcpy(msg->addr, sta->addr, ETH_ALEN); - else - memset(msg->addr, 0xff, ETH_ALEN); - - key->tx_rx_count = 0; - - ieee80211_rx_mgmt(local, skb, NULL, - ieee80211_msg_key_threshold_notification); -} - - -static u8 * ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len) -{ - u16 fc; - - if (len < 24) - return NULL; - - fc = le16_to_cpu(hdr->frame_control); - - switch (fc & IEEE80211_FCTL_FTYPE) { - case IEEE80211_FTYPE_DATA: - switch (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { - case IEEE80211_FCTL_TODS: - return hdr->addr1; - case (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): - return NULL; - case IEEE80211_FCTL_FROMDS: - return hdr->addr2; - case 0: - return hdr->addr3; - } - break; - case IEEE80211_FTYPE_MGMT: - return hdr->addr3; - case IEEE80211_FTYPE_CTL: - if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL) - return hdr->addr1; - else - return NULL; - } - - return NULL; -} - -int ieee80211_get_hdrlen(u16 fc) -{ - int hdrlen = 24; - - switch (fc & IEEE80211_FCTL_FTYPE) { - case IEEE80211_FTYPE_DATA: - if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS)) - hdrlen = 30; /* Addr4 */ - /* - * The QoS Control field is two bytes and its presence is - * indicated by the IEEE80211_STYPE_QOS_DATA bit. Add 2 to - * hdrlen if that bit is set. - * This works by masking out the bit and shifting it to - * bit position 1 so the result has the value 0 or 2. - */ - hdrlen += (fc & IEEE80211_STYPE_QOS_DATA) - >> (ilog2(IEEE80211_STYPE_QOS_DATA)-1); - break; - case IEEE80211_FTYPE_CTL: - /* - * ACK and CTS are 10 bytes, all others 16. To see how - * to get this condition consider - * subtype mask: 0b0000000011110000 (0x00F0) - * ACK subtype: 0b0000000011010000 (0x00D0) - * CTS subtype: 0b0000000011000000 (0x00C0) - * bits that matter: ^^^ (0x00E0) - * value of those: 0b0000000011000000 (0x00C0) - */ - if ((fc & 0xE0) == 0xC0) - hdrlen = 10; - else - hdrlen = 16; - break; - } - - return hdrlen; -} -EXPORT_SYMBOL(ieee80211_get_hdrlen); - -int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb) -{ - const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *) skb->data; - int hdrlen; - - if (unlikely(skb->len < 10)) - return 0; - hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)); - if (unlikely(hdrlen > skb->len)) - return 0; - return hdrlen; -} -EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); - -static int ieee80211_get_radiotap_len(struct sk_buff *skb) -{ - struct ieee80211_radiotap_header *hdr = - (struct ieee80211_radiotap_header *) skb->data; - - return le16_to_cpu(hdr->it_len); -} - -#ifdef CONFIG_MAC80211_LOWTX_FRAME_DUMP -static void ieee80211_dump_frame(const char *ifname, const char *title, - const struct sk_buff *skb) -{ - const struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - u16 fc; - int hdrlen; - - printk(KERN_DEBUG "%s: %s (len=%d)", ifname, title, skb->len); - if (skb->len < 4) { - printk("\n"); - return; - } - - fc = le16_to_cpu(hdr->frame_control); - hdrlen = ieee80211_get_hdrlen(fc); - if (hdrlen > skb->len) - hdrlen = skb->len; - if (hdrlen >= 4) - printk(" FC=0x%04x DUR=0x%04x", - fc, le16_to_cpu(hdr->duration_id)); - if (hdrlen >= 10) - printk(" A1=" MAC_FMT, MAC_ARG(hdr->addr1)); - if (hdrlen >= 16) - printk(" A2=" MAC_FMT, MAC_ARG(hdr->addr2)); - if (hdrlen >= 24) - printk(" A3=" MAC_FMT, MAC_ARG(hdr->addr3)); - if (hdrlen >= 30) - printk(" A4=" MAC_FMT, MAC_ARG(hdr->addr4)); - printk("\n"); -} -#else /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */ -static inline void ieee80211_dump_frame(const char *ifname, const char *title, - struct sk_buff *skb) -{ -} -#endif /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */ - - -static int ieee80211_is_eapol(const struct sk_buff *skb) -{ - const struct ieee80211_hdr *hdr; - u16 fc; - int hdrlen; - - if (unlikely(skb->len < 10)) - return 0; - - hdr = (const struct ieee80211_hdr *) skb->data; - fc = le16_to_cpu(hdr->frame_control); - - if (unlikely(!WLAN_FC_DATA_PRESENT(fc))) - return 0; - - hdrlen = ieee80211_get_hdrlen(fc); + struct ieee80211_sub_if_data *sdata; - if (unlikely(skb->len >= hdrlen + sizeof(eapol_header) && - memcmp(skb->data + hdrlen, eapol_header, - sizeof(eapol_header)) == 0)) - return 1; + /* we hold the RTNL here so can safely walk the list */ + list_for_each_entry(sdata, &local->interfaces, list) + if (sdata->dev != dev && netif_running(sdata->dev)) + dev_close(sdata->dev); return 0; } - -static ieee80211_txrx_result -ieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx) -{ - struct rate_control_extra extra; - - memset(&extra, 0, sizeof(extra)); - extra.mode = tx->u.tx.mode; - extra.mgmt_data = tx->sdata && - tx->sdata->type == IEEE80211_IF_TYPE_MGMT; - extra.ethertype = tx->ethertype; - - tx->u.tx.rate = rate_control_get_rate(tx->local, tx->dev, tx->skb, - &extra); - if (unlikely(extra.probe != NULL)) { - tx->u.tx.control->flags |= IEEE80211_TXCTL_RATE_CTRL_PROBE; - tx->u.tx.probe_last_frag = 1; - tx->u.tx.control->alt_retry_rate = tx->u.tx.rate->val; - tx->u.tx.rate = extra.probe; - } else { - tx->u.tx.control->alt_retry_rate = -1; - } - if (!tx->u.tx.rate) - return TXRX_DROP; - if (tx->u.tx.mode->mode == MODE_IEEE80211G && - tx->sdata->use_protection && tx->fragmented && - extra.nonerp) { - tx->u.tx.last_frag_rate = tx->u.tx.rate; - tx->u.tx.probe_last_frag = extra.probe ? 1 : 0; - - tx->u.tx.rate = extra.nonerp; - tx->u.tx.control->rate = extra.nonerp; - tx->u.tx.control->flags &= ~IEEE80211_TXCTL_RATE_CTRL_PROBE; - } else { - tx->u.tx.last_frag_rate = tx->u.tx.rate; - tx->u.tx.control->rate = tx->u.tx.rate; - } - tx->u.tx.control->tx_rate = tx->u.tx.rate->val; - if ((tx->u.tx.rate->flags & IEEE80211_RATE_PREAMBLE2) && - tx->local->short_preamble && - (!tx->sta || (tx->sta->flags & WLAN_STA_SHORT_PREAMBLE))) { - tx->u.tx.short_preamble = 1; - tx->u.tx.control->tx_rate = tx->u.tx.rate->val2; - } - - return TXRX_CONTINUE; -} - - -static ieee80211_txrx_result -ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx) +static void ieee80211_master_set_multicast_list(struct net_device *dev) { - if (tx->sta) - tx->u.tx.control->key_idx = tx->sta->key_idx_compression; - else - tx->u.tx.control->key_idx = HW_KEY_IDX_INVALID; - - if (unlikely(tx->u.tx.control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) - tx->key = NULL; - else if (tx->sta && tx->sta->key) - tx->key = tx->sta->key; - else if (tx->sdata->default_key) - tx->key = tx->sdata->default_key; - else if (tx->sdata->drop_unencrypted && - !(tx->sdata->eapol && ieee80211_is_eapol(tx->skb))) { - I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); - return TXRX_DROP; - } else - tx->key = NULL; - - if (tx->key) { - tx->key->tx_rx_count++; - if (unlikely(tx->local->key_tx_rx_threshold && - tx->key->tx_rx_count > - tx->local->key_tx_rx_threshold)) { - ieee80211_key_threshold_notify(tx->dev, tx->key, - tx->sta); - } - } + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - return TXRX_CONTINUE; + ieee80211_configure_filter(local); } +/* regular interfaces */ -static ieee80211_txrx_result -ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx) +static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; - size_t hdrlen, per_fragm, num_fragm, payload_len, left; - struct sk_buff **frags, *first, *frag; - int i; - u16 seq; - u8 *pos; - int frag_threshold = tx->local->fragmentation_threshold; - - if (!tx->fragmented) - return TXRX_CONTINUE; - - first = tx->skb; - - hdrlen = ieee80211_get_hdrlen(tx->fc); - payload_len = first->len - hdrlen; - per_fragm = frag_threshold - hdrlen - FCS_LEN; - num_fragm = (payload_len + per_fragm - 1) / per_fragm; - - frags = kzalloc(num_fragm * sizeof(struct sk_buff *), GFP_ATOMIC); - if (!frags) - goto fail; - - hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREFRAGS); - seq = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ; - pos = first->data + hdrlen + per_fragm; - left = payload_len - per_fragm; - for (i = 0; i < num_fragm - 1; i++) { - struct ieee80211_hdr *fhdr; - size_t copylen; - - if (left <= 0) - goto fail; - - /* reserve enough extra head and tail room for possible - * encryption */ - frag = frags[i] = - dev_alloc_skb(tx->local->tx_headroom + - frag_threshold + - IEEE80211_ENCRYPT_HEADROOM + - IEEE80211_ENCRYPT_TAILROOM); - if (!frag) - goto fail; - /* Make sure that all fragments use the same priority so - * that they end up using the same TX queue */ - frag->priority = first->priority; - skb_reserve(frag, tx->local->tx_headroom + - IEEE80211_ENCRYPT_HEADROOM); - fhdr = (struct ieee80211_hdr *) skb_put(frag, hdrlen); - memcpy(fhdr, first->data, hdrlen); - if (i == num_fragm - 2) - fhdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREFRAGS); - fhdr->seq_ctrl = cpu_to_le16(seq | ((i + 1) & IEEE80211_SCTL_FRAG)); - copylen = left > per_fragm ? per_fragm : left; - memcpy(skb_put(frag, copylen), pos, copylen); - - pos += copylen; - left -= copylen; - } - skb_trim(first, hdrlen + per_fragm); - - tx->u.tx.num_extra_frag = num_fragm - 1; - tx->u.tx.extra_frag = frags; - - return TXRX_CONTINUE; - - fail: - printk(KERN_DEBUG "%s: failed to fragment frame\n", tx->dev->name); - if (frags) { - for (i = 0; i < num_fragm - 1; i++) - if (frags[i]) - dev_kfree_skb(frags[i]); - kfree(frags); + /* FIX: what would be proper limits for MTU? + * This interface uses 802.3 frames. */ + if (new_mtu < 256 || new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6) { + printk(KERN_WARNING "%s: invalid MTU %d\n", + dev->name, new_mtu); + return -EINVAL; } - I802_DEBUG_INC(tx->local->tx_handlers_drop_fragment); - return TXRX_DROP; -} - -static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb) -{ - if (tx->key->force_sw_encrypt) { - if (ieee80211_wep_encrypt(tx->local, skb, tx->key)) - return -1; - } else { - tx->u.tx.control->key_idx = tx->key->hw_key_idx; - if (tx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) { - if (ieee80211_wep_add_iv(tx->local, skb, tx->key) == - NULL) - return -1; - } - } +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu); +#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + dev->mtu = new_mtu; return 0; } - -void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; - - hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); - if (tx->u.tx.extra_frag) { - struct ieee80211_hdr *fhdr; - int i; - for (i = 0; i < tx->u.tx.num_extra_frag; i++) { - fhdr = (struct ieee80211_hdr *) - tx->u.tx.extra_frag[i]->data; - fhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); - } - } -} - - -static ieee80211_txrx_result -ieee80211_tx_h_wep_encrypt(struct ieee80211_txrx_data *tx) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; - u16 fc; - - fc = le16_to_cpu(hdr->frame_control); - - if (!tx->key || tx->key->alg != ALG_WEP || - ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA && - ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || - (fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH))) - return TXRX_CONTINUE; - - tx->u.tx.control->iv_len = WEP_IV_LEN; - tx->u.tx.control->icv_len = WEP_ICV_LEN; - ieee80211_tx_set_iswep(tx); - - if (wep_encrypt_skb(tx, tx->skb) < 0) { - I802_DEBUG_INC(tx->local->tx_handlers_drop_wep); - return TXRX_DROP; - } - - if (tx->u.tx.extra_frag) { - int i; - for (i = 0; i < tx->u.tx.num_extra_frag; i++) { - if (wep_encrypt_skb(tx, tx->u.tx.extra_frag[i]) < 0) { - I802_DEBUG_INC(tx->local-> - tx_handlers_drop_wep); - return TXRX_DROP; - } - } - } - - return TXRX_CONTINUE; -} - - -static int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, - int rate, int erp, int short_preamble) -{ - int dur; - - /* calculate duration (in microseconds, rounded up to next higher - * integer if it includes a fractional microsecond) to send frame of - * len bytes (does not include FCS) at the given rate. Duration will - * also include SIFS. - * - * rate is in 100 kbps, so divident is multiplied by 10 in the - * DIV_ROUND_UP() operations. - */ - - if (local->hw.conf.phymode == MODE_IEEE80211A || erp || - local->hw.conf.phymode == MODE_ATHEROS_TURBO) { - /* - * OFDM: - * - * N_DBPS = DATARATE x 4 - * N_SYM = Ceiling((16+8xLENGTH+6) / N_DBPS) - * (16 = SIGNAL time, 6 = tail bits) - * TXTIME = T_PREAMBLE + T_SIGNAL + T_SYM x N_SYM + Signal Ext - * - * T_SYM = 4 usec - * 802.11a - 17.5.2: aSIFSTime = 16 usec - * 802.11g - 19.8.4: aSIFSTime = 10 usec + - * signal ext = 6 usec - */ - /* FIX: Atheros Turbo may have different (shorter) duration? */ - dur = 16; /* SIFS + signal ext */ - dur += 16; /* 17.3.2.3: T_PREAMBLE = 16 usec */ - dur += 4; /* 17.3.2.3: T_SIGNAL = 4 usec */ - dur += 4 * DIV_ROUND_UP((16 + 8 * (len + 4) + 6) * 10, - 4 * rate); /* T_SYM x N_SYM */ - } else { - /* - * 802.11b or 802.11g with 802.11b compatibility: - * 18.3.4: TXTIME = PreambleLength + PLCPHeaderTime + - * Ceiling(((LENGTH+PBCC)x8)/DATARATE). PBCC=0. - * - * 802.11 (DS): 15.3.3, 802.11b: 18.3.4 - * aSIFSTime = 10 usec - * aPreambleLength = 144 usec or 72 usec with short preamble - * aPLCPHeaderLength = 48 usec or 24 usec with short preamble - */ - dur = 10; /* aSIFSTime = 10 usec */ - dur += short_preamble ? (72 + 24) : (144 + 48); - - dur += DIV_ROUND_UP(8 * (len + 4) * 10, rate); - } - - return dur; -} - - -/* Exported duration function for driver use */ -__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, - size_t frame_len, int rate) -{ - struct ieee80211_local *local = hw_to_local(hw); - u16 dur; - int erp; - - erp = ieee80211_is_erp_rate(hw->conf.phymode, rate); - dur = ieee80211_frame_duration(local, frame_len, rate, - erp, local->short_preamble); - - return cpu_to_le16(dur); -} -EXPORT_SYMBOL(ieee80211_generic_frame_duration); - - -static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr, - int next_frag_len) -{ - int rate, mrate, erp, dur, i; - struct ieee80211_rate *txrate = tx->u.tx.rate; - struct ieee80211_local *local = tx->local; - struct ieee80211_hw_mode *mode = tx->u.tx.mode; - - erp = txrate->flags & IEEE80211_RATE_ERP; - - /* - * data and mgmt (except PS Poll): - * - during CFP: 32768 - * - during contention period: - * if addr1 is group address: 0 - * if more fragments = 0 and addr1 is individual address: time to - * transmit one ACK plus SIFS - * if more fragments = 1 and addr1 is individual address: time to - * transmit next fragment plus 2 x ACK plus 3 x SIFS - * - * IEEE 802.11, 9.6: - * - control response frame (CTS or ACK) shall be transmitted using the - * same rate as the immediately previous frame in the frame exchange - * sequence, if this rate belongs to the PHY mandatory rates, or else - * at the highest possible rate belonging to the PHY rates in the - * BSSBasicRateSet - */ - - if ((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) { - /* TODO: These control frames are not currently sent by - * 80211.o, but should they be implemented, this function - * needs to be updated to support duration field calculation. - * - * RTS: time needed to transmit pending data/mgmt frame plus - * one CTS frame plus one ACK frame plus 3 x SIFS - * CTS: duration of immediately previous RTS minus time - * required to transmit CTS and its SIFS - * ACK: 0 if immediately previous directed data/mgmt had - * more=0, with more=1 duration in ACK frame is duration - * from previous frame minus time needed to transmit ACK - * and its SIFS - * PS Poll: BIT(15) | BIT(14) | aid - */ - return 0; - } - - /* data/mgmt */ - if (0 /* FIX: data/mgmt during CFP */) - return 32768; - - if (group_addr) /* Group address as the destination - no ACK */ - return 0; - - /* Individual destination address: - * IEEE 802.11, Ch. 9.6 (after IEEE 802.11g changes) - * CTS and ACK frames shall be transmitted using the highest rate in - * basic rate set that is less than or equal to the rate of the - * immediately previous frame and that is using the same modulation - * (CCK or OFDM). If no basic rate set matches with these requirements, - * the highest mandatory rate of the PHY that is less than or equal to - * the rate of the previous frame is used. - * Mandatory rates for IEEE 802.11g PHY: 1, 2, 5.5, 11, 6, 12, 24 Mbps - */ - rate = -1; - mrate = 10; /* use 1 Mbps if everything fails */ - for (i = 0; i < mode->num_rates; i++) { - struct ieee80211_rate *r = &mode->rates[i]; - if (r->rate > txrate->rate) - break; - - if (IEEE80211_RATE_MODULATION(txrate->flags) != - IEEE80211_RATE_MODULATION(r->flags)) - continue; - - if (r->flags & IEEE80211_RATE_BASIC) - rate = r->rate; - else if (r->flags & IEEE80211_RATE_MANDATORY) - mrate = r->rate; - } - if (rate == -1) { - /* No matching basic rate found; use highest suitable mandatory - * PHY rate */ - rate = mrate; - } - - /* Time needed to transmit ACK - * (10 bytes + 4-byte FCS = 112 bits) plus SIFS; rounded up - * to closest integer */ - - dur = ieee80211_frame_duration(local, 10, rate, erp, - local->short_preamble); - - if (next_frag_len) { - /* Frame is fragmented: duration increases with time needed to - * transmit next fragment plus ACK and 2 x SIFS. */ - dur *= 2; /* ACK + SIFS */ - /* next fragment */ - dur += ieee80211_frame_duration(local, next_frag_len, - txrate->rate, erp, - local->short_preamble); - } - - return dur; -} - - -static ieee80211_txrx_result -ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) +static inline int identical_mac_addr_allowed(int type1, int type2) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; - u16 dur; - struct ieee80211_tx_control *control = tx->u.tx.control; - struct ieee80211_hw_mode *mode = tx->u.tx.mode; - - if (!is_multicast_ether_addr(hdr->addr1)) { - if (tx->skb->len + FCS_LEN > tx->local->rts_threshold && - tx->local->rts_threshold < IEEE80211_MAX_RTS_THRESHOLD) { - control->flags |= IEEE80211_TXCTL_USE_RTS_CTS; - control->retry_limit = - tx->local->long_retry_limit; - } else { - control->retry_limit = - tx->local->short_retry_limit; - } - } else { - control->retry_limit = 1; - } - - if (tx->fragmented) { - /* Do not use multiple retry rates when sending fragmented - * frames. - * TODO: The last fragment could still use multiple retry - * rates. */ - control->alt_retry_rate = -1; - } - - /* Use CTS protection for unicast frames sent using extended rates if - * there are associated non-ERP stations and RTS/CTS is not configured - * for the frame. */ - if (mode->mode == MODE_IEEE80211G && - (tx->u.tx.rate->flags & IEEE80211_RATE_ERP) && - tx->u.tx.unicast && tx->sdata->use_protection && - !(control->flags & IEEE80211_TXCTL_USE_RTS_CTS)) - control->flags |= IEEE80211_TXCTL_USE_CTS_PROTECT; - - /* Setup duration field for the first fragment of the frame. Duration - * for remaining fragments will be updated when they are being sent - * to low-level driver in ieee80211_tx(). */ - dur = ieee80211_duration(tx, is_multicast_ether_addr(hdr->addr1), - tx->fragmented ? tx->u.tx.extra_frag[0]->len : - 0); - hdr->duration_id = cpu_to_le16(dur); - - if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) || - (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) { - struct ieee80211_rate *rate; - - /* Do not use multiple retry rates when using RTS/CTS */ - control->alt_retry_rate = -1; - - /* Use min(data rate, max base rate) as CTS/RTS rate */ - rate = tx->u.tx.rate; - while (rate > mode->rates && - !(rate->flags & IEEE80211_RATE_BASIC)) - rate--; - - control->rts_cts_rate = rate->val; - control->rts_rate = rate; - } - - if (tx->sta) { - tx->sta->tx_packets++; - tx->sta->tx_fragments++; - tx->sta->tx_bytes += tx->skb->len; - if (tx->u.tx.extra_frag) { - int i; - tx->sta->tx_fragments += tx->u.tx.num_extra_frag; - for (i = 0; i < tx->u.tx.num_extra_frag; i++) { - tx->sta->tx_bytes += - tx->u.tx.extra_frag[i]->len; - } - } - } - - return TXRX_CONTINUE; + return (type1 == IEEE80211_IF_TYPE_MNTR || + type2 == IEEE80211_IF_TYPE_MNTR || + (type1 == IEEE80211_IF_TYPE_AP && + type2 == IEEE80211_IF_TYPE_WDS) || + (type1 == IEEE80211_IF_TYPE_WDS && + (type2 == IEEE80211_IF_TYPE_WDS || + type2 == IEEE80211_IF_TYPE_AP)) || + (type1 == IEEE80211_IF_TYPE_AP && + type2 == IEEE80211_IF_TYPE_VLAN) || + (type1 == IEEE80211_IF_TYPE_VLAN && + (type2 == IEEE80211_IF_TYPE_AP || + type2 == IEEE80211_IF_TYPE_VLAN))); } - -static ieee80211_txrx_result -ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) +static int ieee80211_open(struct net_device *dev) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - struct sk_buff *skb = tx->skb; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ - u32 sta_flags; - - if (unlikely(tx->local->sta_scanning != 0) && - ((tx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || - (tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ)) - return TXRX_DROP; + struct ieee80211_sub_if_data *sdata, *nsdata; + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_if_init_conf conf; + int res; - if (tx->u.tx.ps_buffered) - return TXRX_CONTINUE; + sdata = IEEE80211_DEV_TO_SUB_IF(dev); - sta_flags = tx->sta ? tx->sta->flags : 0; + /* we hold the RTNL here so can safely walk the list */ + list_for_each_entry(nsdata, &local->interfaces, list) { + struct net_device *ndev = nsdata->dev; - if (likely(tx->u.tx.unicast)) { - if (unlikely(!(sta_flags & WLAN_STA_ASSOC) && - tx->sdata->type != IEEE80211_IF_TYPE_IBSS && - (tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: dropped data frame to not " - "associated station " MAC_FMT "\n", - tx->dev->name, MAC_ARG(hdr->addr1)); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ - I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc); - return TXRX_DROP; - } - } else { - if (unlikely((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && - tx->local->num_sta == 0 && - !tx->local->allow_broadcast_always && - tx->sdata->type != IEEE80211_IF_TYPE_IBSS)) { + if (ndev != dev && ndev != local->mdev && netif_running(ndev) && + compare_ether_addr(dev->dev_addr, ndev->dev_addr) == 0) { /* - * No associated STAs - no need to send multicast - * frames. + * check whether it may have the same address */ - return TXRX_DROP; - } - return TXRX_CONTINUE; - } - - if (unlikely(!tx->u.tx.mgmt_interface && tx->sdata->ieee802_1x && - !(sta_flags & WLAN_STA_AUTHORIZED))) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: dropped frame to " MAC_FMT - " (unauthorized port)\n", tx->dev->name, - MAC_ARG(hdr->addr1)); -#endif - I802_DEBUG_INC(tx->local->tx_handlers_drop_unauth_port); - return TXRX_DROP; - } - - return TXRX_CONTINUE; -} - -static ieee80211_txrx_result -ieee80211_tx_h_sequence(struct ieee80211_txrx_data *tx) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; + if (!identical_mac_addr_allowed(sdata->type, + nsdata->type)) + return -ENOTUNIQ; - if (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)) >= 24) - ieee80211_include_sequence(tx->sdata, hdr); - - return TXRX_CONTINUE; -} - -/* This function is called whenever the AP is about to exceed the maximum limit - * of buffered frames for power saving STAs. This situation should not really - * happen often during normal operation, so dropping the oldest buffered packet - * from each queue should be OK to make some room for new frames. */ -static void purge_old_ps_buffers(struct ieee80211_local *local) -{ - int total = 0, purged = 0; - struct sk_buff *skb; - struct ieee80211_sub_if_data *sdata; - struct sta_info *sta; - - read_lock(&local->sub_if_lock); - list_for_each_entry(sdata, &local->sub_if_list, list) { - struct ieee80211_if_ap *ap; - if (sdata->dev == local->mdev || - sdata->type != IEEE80211_IF_TYPE_AP) - continue; - ap = &sdata->u.ap; - skb = skb_dequeue(&ap->ps_bc_buf); - if (skb) { - purged++; - dev_kfree_skb(skb); + /* + * can only add VLANs to enabled APs + */ + if (sdata->type == IEEE80211_IF_TYPE_VLAN && + nsdata->type == IEEE80211_IF_TYPE_AP && + netif_running(nsdata->dev)) + sdata->u.vlan.ap = nsdata; } - total += skb_queue_len(&ap->ps_bc_buf); } - read_unlock(&local->sub_if_lock); - spin_lock_bh(&local->sta_lock); - list_for_each_entry(sta, &local->sta_list, list) { - skb = skb_dequeue(&sta->ps_tx_buf); - if (skb) { - purged++; - dev_kfree_skb(skb); - } - total += skb_queue_len(&sta->ps_tx_buf); + switch (sdata->type) { + case IEEE80211_IF_TYPE_WDS: + if (is_zero_ether_addr(sdata->u.wds.remote_addr)) + return -ENOLINK; + break; + case IEEE80211_IF_TYPE_VLAN: + if (!sdata->u.vlan.ap) + return -ENOLINK; + break; + case IEEE80211_IF_TYPE_AP: + case IEEE80211_IF_TYPE_STA: + case IEEE80211_IF_TYPE_MNTR: + case IEEE80211_IF_TYPE_IBSS: + /* no special treatment */ + break; + case IEEE80211_IF_TYPE_INVALID: + /* cannot happen */ + WARN_ON(1); + break; } - spin_unlock_bh(&local->sta_lock); - - local->total_ps_buffered = total; - printk(KERN_DEBUG "%s: PS buffers full - purged %d frames\n", - local->mdev->name, purged); -} - -static inline ieee80211_txrx_result -ieee80211_tx_h_multicast_ps_buf(struct ieee80211_txrx_data *tx) -{ - /* broadcast/multicast frame */ - /* If any of the associated stations is in power save mode, - * the frame is buffered to be sent after DTIM beacon frame */ - if ((tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING) && - tx->sdata->type != IEEE80211_IF_TYPE_WDS && - tx->sdata->bss && atomic_read(&tx->sdata->bss->num_sta_ps) && - !(tx->fc & IEEE80211_FCTL_ORDER)) { - if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) - purge_old_ps_buffers(tx->local); - if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >= - AP_MAX_BC_BUFFER) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: BC TX buffer full - " - "dropping the oldest frame\n", - tx->dev->name); - } - dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf)); - } else - tx->local->total_ps_buffered++; - skb_queue_tail(&tx->sdata->bss->ps_bc_buf, tx->skb); - return TXRX_QUEUED; + if (local->open_count == 0) { + res = 0; + if (local->ops->start) + res = local->ops->start(local_to_hw(local)); + if (res) + return res; } - return TXRX_CONTINUE; -} - + switch (sdata->type) { + case IEEE80211_IF_TYPE_VLAN: + list_add(&sdata->u.vlan.list, &sdata->u.vlan.ap->u.ap.vlans); + /* no need to tell driver */ + break; + case IEEE80211_IF_TYPE_MNTR: + /* must be before the call to ieee80211_configure_filter */ + local->monitors++; + if (local->monitors == 1) { + netif_tx_lock_bh(local->mdev); + ieee80211_configure_filter(local); + netif_tx_unlock_bh(local->mdev); -static inline ieee80211_txrx_result -ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) -{ - struct sta_info *sta = tx->sta; - - if (unlikely(!sta || - ((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT && - (tx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP))) - return TXRX_CONTINUE; - - if (unlikely((sta->flags & WLAN_STA_PS) && !sta->pspoll)) { - struct ieee80211_tx_packet_data *pkt_data; -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "STA " MAC_FMT " aid %d: PS buffer (entries " - "before %d)\n", - MAC_ARG(sta->addr), sta->aid, - skb_queue_len(&sta->ps_tx_buf)); -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - sta->flags |= WLAN_STA_TIM; - if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) - purge_old_ps_buffers(tx->local); - if (skb_queue_len(&sta->ps_tx_buf) >= STA_MAX_TX_BUFFER) { - struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf); - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: STA " MAC_FMT " TX " - "buffer full - dropping oldest frame\n", - tx->dev->name, MAC_ARG(sta->addr)); - } - dev_kfree_skb(old); - } else - tx->local->total_ps_buffered++; - /* Queue frame to be sent after STA sends an PS Poll frame */ - if (skb_queue_empty(&sta->ps_tx_buf)) { - if (tx->local->ops->set_tim) - tx->local->ops->set_tim(local_to_hw(tx->local), - sta->aid, 1); - if (tx->sdata->bss) - bss_tim_set(tx->local, tx->sdata->bss, sta->aid); + local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; + ieee80211_hw_config(local); } - pkt_data = (struct ieee80211_tx_packet_data *)tx->skb->cb; - pkt_data->jiffies = jiffies; - skb_queue_tail(&sta->ps_tx_buf, tx->skb); - return TXRX_QUEUED; - } -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - else if (unlikely(sta->flags & WLAN_STA_PS)) { - printk(KERN_DEBUG "%s: STA " MAC_FMT " in PS mode, but pspoll " - "set -> send frame\n", tx->dev->name, - MAC_ARG(sta->addr)); - } -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - sta->pspoll = 0; - - return TXRX_CONTINUE; -} - - -static ieee80211_txrx_result -ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx) -{ - if (unlikely(tx->u.tx.ps_buffered)) - return TXRX_CONTINUE; - - if (tx->u.tx.unicast) - return ieee80211_tx_h_unicast_ps_buf(tx); - else - return ieee80211_tx_h_multicast_ps_buf(tx); -} - - -/* - * deal with packet injection down monitor interface - * with Radiotap Header -- only called for monitor mode interface - */ - -static ieee80211_txrx_result -__ieee80211_parse_tx_radiotap( - struct ieee80211_txrx_data *tx, - struct sk_buff *skb, struct ieee80211_tx_control *control) -{ - /* - * this is the moment to interpret and discard the radiotap header that - * must be at the start of the packet injected in Monitor mode - * - * Need to take some care with endian-ness since radiotap - * args are little-endian - */ - - struct ieee80211_radiotap_iterator iterator; - struct ieee80211_radiotap_header *rthdr = - (struct ieee80211_radiotap_header *) skb->data; - struct ieee80211_hw_mode *mode = tx->local->hw.conf.mode; - int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len); - - /* - * default control situation for all injected packets - * FIXME: this does not suit all usage cases, expand to allow control - */ - - control->retry_limit = 1; /* no retry */ - control->key_idx = -1; /* no encryption key */ - control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS | - IEEE80211_TXCTL_USE_CTS_PROTECT); - control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT | - IEEE80211_TXCTL_NO_ACK; - control->antenna_sel_tx = 0; /* default to default antenna */ - - /* - * for every radiotap entry that is present - * (ieee80211_radiotap_iterator_next returns -ENOENT when no more - * entries present, or -EINVAL on error) - */ - - while (!ret) { - int i, target_rate; - - ret = ieee80211_radiotap_iterator_next(&iterator); - - if (ret) - continue; - - /* see if this argument is something we can use */ - switch (iterator.this_arg_index) { - /* - * You must take care when dereferencing iterator.this_arg - * for multibyte types... the pointer is not aligned. Use - * get_unaligned((type *)iterator.this_arg) to dereference - * iterator.this_arg for type "type" safely on all arches. - */ - case IEEE80211_RADIOTAP_RATE: - /* - * radiotap rate u8 is in 500kbps units eg, 0x02=1Mbps - * ieee80211 rate int is in 100kbps units eg, 0x0a=1Mbps - */ - target_rate = (*iterator.this_arg) * 5; - for (i = 0; i < mode->num_rates; i++) { - struct ieee80211_rate *r = &mode->rates[i]; - - if (r->rate > target_rate) - continue; - - control->rate = r; - - if (r->flags & IEEE80211_RATE_PREAMBLE2) - control->tx_rate = r->val2; - else - control->tx_rate = r->val; - - /* end on exact match */ - if (r->rate == target_rate) - i = mode->num_rates; - } - break; - - case IEEE80211_RADIOTAP_ANTENNA: - /* - * radiotap uses 0 for 1st ant, mac80211 is 1 for - * 1st ant - */ - control->antenna_sel_tx = (*iterator.this_arg) + 1; - break; - - case IEEE80211_RADIOTAP_DBM_TX_POWER: - control->power_level = *iterator.this_arg; - break; + break; + case IEEE80211_IF_TYPE_STA: + case IEEE80211_IF_TYPE_IBSS: + sdata->u.sta.flags &= ~IEEE80211_STA_PREV_BSSID_SET; + /* fall through */ + default: + conf.if_id = dev->ifindex; + conf.type = sdata->type; + conf.mac_addr = dev->dev_addr; + res = local->ops->add_interface(local_to_hw(local), &conf); + if (res && !local->open_count && local->ops->stop) + local->ops->stop(local_to_hw(local)); + if (res) + return res; - case IEEE80211_RADIOTAP_FLAGS: - if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FCS) { - /* - * this indicates that the skb we have been - * handed has the 32-bit FCS CRC at the end... - * we should react to that by snipping it off - * because it will be recomputed and added - * on transmission - */ - if (skb->len < (iterator.max_length + FCS_LEN)) - return TXRX_DROP; + ieee80211_if_config(dev); + ieee80211_reset_erp_info(dev); + ieee80211_enable_keys(sdata); - skb_trim(skb, skb->len - FCS_LEN); - } - break; + if (sdata->type == IEEE80211_IF_TYPE_STA && + !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)) + netif_carrier_off(dev); + else + netif_carrier_on(dev); + } - default: - break; - } + if (local->open_count == 0) { + res = dev_open(local->mdev); + WARN_ON(res); + tasklet_enable(&local->tx_pending_tasklet); + tasklet_enable(&local->tasklet); } - if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */ - return TXRX_DROP; + local->open_count++; - /* - * remove the radiotap header - * iterator->max_length was sanity-checked against - * skb->len by iterator init - */ - skb_pull(skb, iterator.max_length); + netif_start_queue(dev); - return TXRX_CONTINUE; + return 0; } - -static ieee80211_txrx_result inline -__ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, - struct sk_buff *skb, - struct net_device *dev, - struct ieee80211_tx_control *control) +static int ieee80211_stop(struct net_device *dev) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_sub_if_data *sdata; - ieee80211_txrx_result res = TXRX_CONTINUE; - - int hdrlen; - - memset(tx, 0, sizeof(*tx)); - tx->skb = skb; - tx->dev = dev; /* use original interface */ - tx->local = local; - tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev); - tx->sta = sta_info_get(local, hdr->addr1); - tx->fc = le16_to_cpu(hdr->frame_control); - - /* - * set defaults for things that can be set by - * injected radiotap headers - */ - control->power_level = local->hw.conf.power_level; - control->antenna_sel_tx = local->hw.conf.antenna_sel_tx; - if (local->sta_antenna_sel != STA_ANTENNA_SEL_AUTO && tx->sta) - control->antenna_sel_tx = tx->sta->antenna_sel_tx; + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_if_init_conf conf; - /* process and remove the injection radiotap header */ sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (unlikely(sdata->type == IEEE80211_IF_TYPE_MNTR)) { - if (__ieee80211_parse_tx_radiotap(tx, skb, control) == - TXRX_DROP) { - return TXRX_DROP; - } - /* - * we removed the radiotap header after this point, - * we filled control with what we could use - * set to the actual ieee header now - */ - hdr = (struct ieee80211_hdr *) skb->data; - res = TXRX_QUEUED; /* indication it was monitor packet */ - } - - tx->u.tx.control = control; - tx->u.tx.unicast = !is_multicast_ether_addr(hdr->addr1); - if (is_multicast_ether_addr(hdr->addr1)) - control->flags |= IEEE80211_TXCTL_NO_ACK; - else - control->flags &= ~IEEE80211_TXCTL_NO_ACK; - tx->fragmented = local->fragmentation_threshold < - IEEE80211_MAX_FRAG_THRESHOLD && tx->u.tx.unicast && - skb->len + FCS_LEN > local->fragmentation_threshold && - (!local->ops->set_frag_threshold); - if (!tx->sta) - control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK; - else if (tx->sta->clear_dst_mask) { - control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK; - tx->sta->clear_dst_mask = 0; - } - hdrlen = ieee80211_get_hdrlen(tx->fc); - if (skb->len > hdrlen + sizeof(rfc1042_header) + 2) { - u8 *pos = &skb->data[hdrlen + sizeof(rfc1042_header)]; - tx->ethertype = (pos[0] << 8) | pos[1]; - } - control->flags |= IEEE80211_TXCTL_FIRST_FRAGMENT; - return res; -} + netif_stop_queue(dev); -static int inline is_ieee80211_device(struct net_device *dev, - struct net_device *master) -{ - return (wdev_priv(dev->ieee80211_ptr) == - wdev_priv(master->ieee80211_ptr)); -} + dev_mc_unsync(local->mdev, dev); -/* Device in tx->dev has a reference added; use dev_put(tx->dev) when - * finished with it. */ -static int inline ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, - struct sk_buff *skb, - struct net_device *mdev, - struct ieee80211_tx_control *control) -{ - struct ieee80211_tx_packet_data *pkt_data; - struct net_device *dev; + /* down all dependent devices, that is VLANs */ + if (sdata->type == IEEE80211_IF_TYPE_AP) { + struct ieee80211_sub_if_data *vlan, *tmp; - pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; - dev = dev_get_by_index(pkt_data->ifindex); - if (unlikely(dev && !is_ieee80211_device(dev, mdev))) { - dev_put(dev); - dev = NULL; + list_for_each_entry_safe(vlan, tmp, &sdata->u.ap.vlans, + u.vlan.list) + dev_close(vlan->dev); + WARN_ON(!list_empty(&sdata->u.ap.vlans)); } - if (unlikely(!dev)) - return -ENODEV; - __ieee80211_tx_prepare(tx, skb, dev, control); - return 0; -} - -static inline int __ieee80211_queue_stopped(const struct ieee80211_local *local, - int queue) -{ - return test_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]); -} - -static inline int __ieee80211_queue_pending(const struct ieee80211_local *local, - int queue) -{ - return test_bit(IEEE80211_LINK_STATE_PENDING, &local->state[queue]); -} - -#define IEEE80211_TX_OK 0 -#define IEEE80211_TX_AGAIN 1 -#define IEEE80211_TX_FRAG_AGAIN 2 -static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, - struct ieee80211_txrx_data *tx) -{ - struct ieee80211_tx_control *control = tx->u.tx.control; - int ret, i; + local->open_count--; - if (!ieee80211_qdisc_installed(local->mdev) && - __ieee80211_queue_stopped(local, 0)) { - netif_stop_queue(local->mdev); - return IEEE80211_TX_AGAIN; - } - if (skb) { - ieee80211_dump_frame(local->mdev->name, "TX to low-level driver", skb); - ret = local->ops->tx(local_to_hw(local), skb, control); - if (ret) - return IEEE80211_TX_AGAIN; - local->mdev->trans_start = jiffies; - ieee80211_led_tx(local, 1); - } - if (tx->u.tx.extra_frag) { - control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS | - IEEE80211_TXCTL_USE_CTS_PROTECT | - IEEE80211_TXCTL_CLEAR_DST_MASK | - IEEE80211_TXCTL_FIRST_FRAGMENT); - for (i = 0; i < tx->u.tx.num_extra_frag; i++) { - if (!tx->u.tx.extra_frag[i]) - continue; - if (__ieee80211_queue_stopped(local, control->queue)) - return IEEE80211_TX_FRAG_AGAIN; - if (i == tx->u.tx.num_extra_frag) { - control->tx_rate = tx->u.tx.last_frag_hwrate; - control->rate = tx->u.tx.last_frag_rate; - if (tx->u.tx.probe_last_frag) - control->flags |= - IEEE80211_TXCTL_RATE_CTRL_PROBE; - else - control->flags &= - ~IEEE80211_TXCTL_RATE_CTRL_PROBE; - } + switch (sdata->type) { + case IEEE80211_IF_TYPE_VLAN: + list_del(&sdata->u.vlan.list); + sdata->u.vlan.ap = NULL; + /* no need to tell driver */ + break; + case IEEE80211_IF_TYPE_MNTR: + local->monitors--; + if (local->monitors == 0) { + netif_tx_lock_bh(local->mdev); + ieee80211_configure_filter(local); + netif_tx_unlock_bh(local->mdev); - ieee80211_dump_frame(local->mdev->name, - "TX to low-level driver", - tx->u.tx.extra_frag[i]); - ret = local->ops->tx(local_to_hw(local), - tx->u.tx.extra_frag[i], - control); - if (ret) - return IEEE80211_TX_FRAG_AGAIN; - local->mdev->trans_start = jiffies; - ieee80211_led_tx(local, 1); - tx->u.tx.extra_frag[i] = NULL; + local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; + ieee80211_hw_config(local); } - kfree(tx->u.tx.extra_frag); - tx->u.tx.extra_frag = NULL; - } - return IEEE80211_TX_OK; -} - -static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, - struct ieee80211_tx_control *control, int mgmt) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct sta_info *sta; - ieee80211_tx_handler *handler; - struct ieee80211_txrx_data tx; - ieee80211_txrx_result res = TXRX_DROP, res_prepare; - int ret, i; - - WARN_ON(__ieee80211_queue_pending(local, control->queue)); - - if (unlikely(skb->len < 10)) { - dev_kfree_skb(skb); - return 0; - } - - res_prepare = __ieee80211_tx_prepare(&tx, skb, dev, control); - - if (res_prepare == TXRX_DROP) { - dev_kfree_skb(skb); - return 0; - } - - sta = tx.sta; - tx.u.tx.mgmt_interface = mgmt; - tx.u.tx.mode = local->hw.conf.mode; + break; + case IEEE80211_IF_TYPE_STA: + case IEEE80211_IF_TYPE_IBSS: + sdata->u.sta.state = IEEE80211_DISABLED; + del_timer_sync(&sdata->u.sta.timer); + /* + * When we get here, the interface is marked down. + * Call synchronize_rcu() to wait for the RX path + * should it be using the interface and enqueuing + * frames at this very time on another CPU. + */ + synchronize_rcu(); + skb_queue_purge(&sdata->u.sta.skb_queue); - if (res_prepare == TXRX_QUEUED) { /* if it was an injected packet */ - res = TXRX_CONTINUE; - } else { - for (handler = local->tx_handlers; *handler != NULL; - handler++) { - res = (*handler)(&tx); - if (res != TXRX_CONTINUE) - break; + if (!local->ops->hw_scan && + local->scan_dev == sdata->dev) { + local->sta_scanning = 0; + cancel_delayed_work(&local->scan_work); } + flush_workqueue(local->hw.workqueue); + /* fall through */ + default: + conf.if_id = dev->ifindex; + conf.type = sdata->type; + conf.mac_addr = dev->dev_addr; + /* disable all keys for as long as this netdev is down */ + ieee80211_disable_keys(sdata); + local->ops->remove_interface(local_to_hw(local), &conf); } - skb = tx.skb; /* handlers are allowed to change skb */ - - if (sta) - sta_info_put(sta); - - if (unlikely(res == TXRX_DROP)) { - I802_DEBUG_INC(local->tx_handlers_drop); - goto drop; - } - - if (unlikely(res == TXRX_QUEUED)) { - I802_DEBUG_INC(local->tx_handlers_queued); - return 0; - } - - if (tx.u.tx.extra_frag) { - for (i = 0; i < tx.u.tx.num_extra_frag; i++) { - int next_len, dur; - struct ieee80211_hdr *hdr = - (struct ieee80211_hdr *) - tx.u.tx.extra_frag[i]->data; + if (local->open_count == 0) { + if (netif_running(local->mdev)) + dev_close(local->mdev); - if (i + 1 < tx.u.tx.num_extra_frag) { - next_len = tx.u.tx.extra_frag[i + 1]->len; - } else { - next_len = 0; - tx.u.tx.rate = tx.u.tx.last_frag_rate; - tx.u.tx.last_frag_hwrate = tx.u.tx.rate->val; - } - dur = ieee80211_duration(&tx, 0, next_len); - hdr->duration_id = cpu_to_le16(dur); - } - } + if (local->ops->stop) + local->ops->stop(local_to_hw(local)); -retry: - ret = __ieee80211_tx(local, skb, &tx); - if (ret) { - struct ieee80211_tx_stored_packet *store = - &local->pending_packet[control->queue]; - - if (ret == IEEE80211_TX_FRAG_AGAIN) - skb = NULL; - set_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[control->queue]); - smp_mb(); - /* When the driver gets out of buffers during sending of - * fragments and calls ieee80211_stop_queue, there is - * a small window between IEEE80211_LINK_STATE_XOFF and - * IEEE80211_LINK_STATE_PENDING flags are set. If a buffer - * gets available in that window (i.e. driver calls - * ieee80211_wake_queue), we would end up with ieee80211_tx - * called with IEEE80211_LINK_STATE_PENDING. Prevent this by - * continuing transmitting here when that situation is - * possible to have happened. */ - if (!__ieee80211_queue_stopped(local, control->queue)) { - clear_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[control->queue]); - goto retry; - } - memcpy(&store->control, control, - sizeof(struct ieee80211_tx_control)); - store->skb = skb; - store->extra_frag = tx.u.tx.extra_frag; - store->num_extra_frag = tx.u.tx.num_extra_frag; - store->last_frag_hwrate = tx.u.tx.last_frag_hwrate; - store->last_frag_rate = tx.u.tx.last_frag_rate; - store->last_frag_rate_ctrl_probe = tx.u.tx.probe_last_frag; + tasklet_disable(&local->tx_pending_tasklet); + tasklet_disable(&local->tasklet); } - return 0; - drop: - if (skb) - dev_kfree_skb(skb); - for (i = 0; i < tx.u.tx.num_extra_frag; i++) - if (tx.u.tx.extra_frag[i]) - dev_kfree_skb(tx.u.tx.extra_frag[i]); - kfree(tx.u.tx.extra_frag); return 0; } -static void ieee80211_tx_pending(unsigned long data) -{ - struct ieee80211_local *local = (struct ieee80211_local *)data; - struct net_device *dev = local->mdev; - struct ieee80211_tx_stored_packet *store; - struct ieee80211_txrx_data tx; - int i, ret, reschedule = 0; - - netif_tx_lock_bh(dev); - for (i = 0; i < local->hw.queues; i++) { - if (__ieee80211_queue_stopped(local, i)) - continue; - if (!__ieee80211_queue_pending(local, i)) { - reschedule = 1; - continue; - } - store = &local->pending_packet[i]; - tx.u.tx.control = &store->control; - tx.u.tx.extra_frag = store->extra_frag; - tx.u.tx.num_extra_frag = store->num_extra_frag; - tx.u.tx.last_frag_hwrate = store->last_frag_hwrate; - tx.u.tx.last_frag_rate = store->last_frag_rate; - tx.u.tx.probe_last_frag = store->last_frag_rate_ctrl_probe; - ret = __ieee80211_tx(local, store->skb, &tx); - if (ret) { - if (ret == IEEE80211_TX_FRAG_AGAIN) - store->skb = NULL; - } else { - clear_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[i]); - reschedule = 1; - } - } - netif_tx_unlock_bh(dev); - if (reschedule) { - if (!ieee80211_qdisc_installed(dev)) { - if (!__ieee80211_queue_stopped(local, 0)) - netif_wake_queue(dev); - } else - netif_schedule(dev); - } -} - -static void ieee80211_clear_tx_pending(struct ieee80211_local *local) -{ - int i, j; - struct ieee80211_tx_stored_packet *store; - - for (i = 0; i < local->hw.queues; i++) { - if (!__ieee80211_queue_pending(local, i)) - continue; - store = &local->pending_packet[i]; - kfree_skb(store->skb); - for (j = 0; j < store->num_extra_frag; j++) - kfree_skb(store->extra_frag[j]); - kfree(store->extra_frag); - clear_bit(IEEE80211_LINK_STATE_PENDING, &local->state[i]); - } -} - -static int ieee80211_master_start_xmit(struct sk_buff *skb, - struct net_device *dev) +static void ieee80211_set_multicast_list(struct net_device *dev) { - struct ieee80211_tx_control control; - struct ieee80211_tx_packet_data *pkt_data; - struct net_device *odev = NULL; - struct ieee80211_sub_if_data *osdata; - int headroom; - int ret; + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + int allmulti, promisc, sdata_allmulti, sdata_promisc; - /* - * copy control out of the skb so other people can use skb->cb - */ - pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; - memset(&control, 0, sizeof(struct ieee80211_tx_control)); + allmulti = !!(dev->flags & IFF_ALLMULTI); + promisc = !!(dev->flags & IFF_PROMISC); + sdata_allmulti = sdata->flags & IEEE80211_SDATA_ALLMULTI; + sdata_promisc = sdata->flags & IEEE80211_SDATA_PROMISC; - if (pkt_data->ifindex) - odev = dev_get_by_index(pkt_data->ifindex); - if (unlikely(odev && !is_ieee80211_device(odev, dev))) { - dev_put(odev); - odev = NULL; - } - if (unlikely(!odev)) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: Discarded packet with nonexistent " - "originating device\n", dev->name); -#endif - dev_kfree_skb(skb); - return 0; + if (allmulti != sdata_allmulti) { + if (dev->flags & IFF_ALLMULTI) + atomic_inc(&local->iff_allmultis); + else + atomic_dec(&local->iff_allmultis); + sdata->flags ^= IEEE80211_SDATA_ALLMULTI; } - osdata = IEEE80211_DEV_TO_SUB_IF(odev); - headroom = osdata->local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM; - if (skb_headroom(skb) < headroom) { - if (pskb_expand_head(skb, headroom, 0, GFP_ATOMIC)) { - dev_kfree_skb(skb); - dev_put(odev); - return 0; - } + if (promisc != sdata_promisc) { + if (dev->flags & IFF_PROMISC) + atomic_inc(&local->iff_promiscs); + else + atomic_dec(&local->iff_promiscs); + sdata->flags ^= IEEE80211_SDATA_PROMISC; } - control.ifindex = odev->ifindex; - control.type = osdata->type; - if (pkt_data->req_tx_status) - control.flags |= IEEE80211_TXCTL_REQ_TX_STATUS; - if (pkt_data->do_not_encrypt) - control.flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; - if (pkt_data->requeue) - control.flags |= IEEE80211_TXCTL_REQUEUE; - control.queue = pkt_data->queue; - - ret = ieee80211_tx(odev, skb, &control, - control.type == IEEE80211_IF_TYPE_MGMT); - dev_put(odev); - - return ret; + dev_mc_sync(local->mdev, dev); } +static const struct header_ops ieee80211_header_ops = { + .create = eth_header, + .parse = header_parse_80211, + .rebuild = eth_rebuild_header, + .cache = eth_header_cache, + .cache_update = eth_header_cache_update, +}; -int ieee80211_monitor_start_xmit(struct sk_buff *skb, - struct net_device *dev) +/* Must not be called for mdev */ +void ieee80211_if_setup(struct net_device *dev) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_tx_packet_data *pkt_data; - struct ieee80211_radiotap_header *prthdr = - (struct ieee80211_radiotap_header *)skb->data; - u16 len; - - /* - * there must be a radiotap header at the - * start in this case - */ - if (unlikely(prthdr->it_version)) { - /* only version 0 is supported */ - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - - skb->dev = local->mdev; - - pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; - memset(pkt_data, 0, sizeof(*pkt_data)); - pkt_data->ifindex = dev->ifindex; - pkt_data->mgmt_iface = 0; - pkt_data->do_not_encrypt = 1; - - /* above needed because we set skb device to master */ - - /* - * fix up the pointers accounting for the radiotap - * header still being in there. We are being given - * a precooked IEEE80211 header so no need for - * normal processing - */ - len = le16_to_cpu(get_unaligned(&prthdr->it_len)); - skb_set_mac_header(skb, len); - skb_set_network_header(skb, len + sizeof(struct ieee80211_hdr)); - skb_set_transport_header(skb, len + sizeof(struct ieee80211_hdr)); - - /* - * pass the radiotap header up to - * the next stage intact - */ - dev_queue_xmit(skb); - - return NETDEV_TX_OK; + ether_setup(dev); + dev->header_ops = &ieee80211_header_ops; + dev->hard_start_xmit = ieee80211_subif_start_xmit; + dev->wireless_handlers = &ieee80211_iw_handler_def; + dev->set_multicast_list = ieee80211_set_multicast_list; + dev->change_mtu = ieee80211_change_mtu; + dev->open = ieee80211_open; + dev->stop = ieee80211_stop; + dev->destructor = ieee80211_if_free; } +/* WDS specialties */ -/** - * ieee80211_subif_start_xmit - netif start_xmit function for Ethernet-type - * subinterfaces (wlan#, WDS, and VLAN interfaces) - * @skb: packet to be sent - * @dev: incoming interface - * - * Returns: 0 on success (and frees skb in this case) or 1 on failure (skb will - * not be freed, and caller is responsible for either retrying later or freeing - * skb). - * - * This function takes in an Ethernet header and encapsulates it with suitable - * IEEE 802.11 header based on which interface the packet is coming in. The - * encapsulated packet will then be passed to master interface, wlan#.11, for - * transmission (through low-level driver). - */ -int ieee80211_subif_start_xmit(struct sk_buff *skb, - struct net_device *dev) +int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_tx_packet_data *pkt_data; - struct ieee80211_sub_if_data *sdata; - int ret = 1, head_need; - u16 ethertype, hdrlen, fc; - struct ieee80211_hdr hdr; - const u8 *encaps_data; - int encaps_len, skip_header_bytes; - int nh_pos, h_pos, no_encrypt = 0; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct sta_info *sta; + DECLARE_MAC_BUF(mac); - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (unlikely(skb->len < ETH_HLEN)) { - printk(KERN_DEBUG "%s: short skb (len=%d)\n", - dev->name, skb->len); - ret = 0; - goto fail; - } + if (compare_ether_addr(remote_addr, sdata->u.wds.remote_addr) == 0) + return 0; - nh_pos = skb_network_header(skb) - skb->data; - h_pos = skb_transport_header(skb) - skb->data; - - /* convert Ethernet header to proper 802.11 header (based on - * operation mode) */ - ethertype = (skb->data[12] << 8) | skb->data[13]; - /* TODO: handling for 802.1x authorized/unauthorized port */ - fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA; - - if (likely(sdata->type == IEEE80211_IF_TYPE_AP || - sdata->type == IEEE80211_IF_TYPE_VLAN)) { - fc |= IEEE80211_FCTL_FROMDS; - /* DA BSSID SA */ - memcpy(hdr.addr1, skb->data, ETH_ALEN); - memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); - memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN); - hdrlen = 24; - } else if (sdata->type == IEEE80211_IF_TYPE_WDS) { - fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS; - /* RA TA DA SA */ - memcpy(hdr.addr1, sdata->u.wds.remote_addr, ETH_ALEN); - memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); - memcpy(hdr.addr3, skb->data, ETH_ALEN); - memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); - hdrlen = 30; - } else if (sdata->type == IEEE80211_IF_TYPE_STA) { - fc |= IEEE80211_FCTL_TODS; - /* BSSID SA DA */ - memcpy(hdr.addr1, sdata->u.sta.bssid, ETH_ALEN); - memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); - memcpy(hdr.addr3, skb->data, ETH_ALEN); - hdrlen = 24; - } else if (sdata->type == IEEE80211_IF_TYPE_IBSS) { - /* DA SA BSSID */ - memcpy(hdr.addr1, skb->data, ETH_ALEN); - memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); - memcpy(hdr.addr3, sdata->u.sta.bssid, ETH_ALEN); - hdrlen = 24; - } else { - ret = 0; - goto fail; - } + /* Create STA entry for the new peer */ + sta = sta_info_add(local, dev, remote_addr, GFP_KERNEL); + if (!sta) + return -ENOMEM; + sta_info_put(sta); - /* receiver is QoS enabled, use a QoS type frame */ - sta = sta_info_get(local, hdr.addr1); + /* Remove STA entry for the old peer */ + sta = sta_info_get(local, sdata->u.wds.remote_addr); if (sta) { - if (sta->flags & WLAN_STA_WME) { - fc |= IEEE80211_STYPE_QOS_DATA; - hdrlen += 2; - } + sta_info_free(sta); sta_info_put(sta); - } - - hdr.frame_control = cpu_to_le16(fc); - hdr.duration_id = 0; - hdr.seq_ctrl = 0; - - skip_header_bytes = ETH_HLEN; - if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) { - encaps_data = bridge_tunnel_header; - encaps_len = sizeof(bridge_tunnel_header); - skip_header_bytes -= 2; - } else if (ethertype >= 0x600) { - encaps_data = rfc1042_header; - encaps_len = sizeof(rfc1042_header); - skip_header_bytes -= 2; } else { - encaps_data = NULL; - encaps_len = 0; - } - - skb_pull(skb, skip_header_bytes); - nh_pos -= skip_header_bytes; - h_pos -= skip_header_bytes; - - /* TODO: implement support for fragments so that there is no need to - * reallocate and copy payload; it might be enough to support one - * extra fragment that would be copied in the beginning of the frame - * data.. anyway, it would be nice to include this into skb structure - * somehow - * - * There are few options for this: - * use skb->cb as an extra space for 802.11 header - * allocate new buffer if not enough headroom - * make sure that there is enough headroom in every skb by increasing - * build in headroom in __dev_alloc_skb() (linux/skbuff.h) and - * alloc_skb() (net/core/skbuff.c) - */ - head_need = hdrlen + encaps_len + local->tx_headroom; - head_need -= skb_headroom(skb); - - /* We are going to modify skb data, so make a copy of it if happens to - * be cloned. This could happen, e.g., with Linux bridge code passing - * us broadcast frames. */ - - if (head_need > 0 || skb_cloned(skb)) { -#if 0 - printk(KERN_DEBUG "%s: need to reallocate buffer for %d bytes " - "of headroom\n", dev->name, head_need); -#endif - - if (skb_cloned(skb)) - I802_DEBUG_INC(local->tx_expand_skb_head_cloned); - else - I802_DEBUG_INC(local->tx_expand_skb_head); - /* Since we have to reallocate the buffer, make sure that there - * is enough room for possible WEP IV/ICV and TKIP (8 bytes - * before payload and 12 after). */ - if (pskb_expand_head(skb, (head_need > 0 ? head_need + 8 : 8), - 12, GFP_ATOMIC)) { - printk(KERN_DEBUG "%s: failed to reallocate TX buffer" - "\n", dev->name); - goto fail; - } - } - - if (encaps_data) { - memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len); - nh_pos += encaps_len; - h_pos += encaps_len; - } - memcpy(skb_push(skb, hdrlen), &hdr, hdrlen); - nh_pos += hdrlen; - h_pos += hdrlen; - - pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; - memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data)); - pkt_data->ifindex = dev->ifindex; - pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT); - pkt_data->do_not_encrypt = no_encrypt; - - skb->dev = local->mdev; - sdata->stats.tx_packets++; - sdata->stats.tx_bytes += skb->len; - - /* Update skb pointers to various headers since this modified frame - * is going to go through Linux networking code that may potentially - * need things like pointer to IP header. */ - skb_set_mac_header(skb, 0); - skb_set_network_header(skb, nh_pos); - skb_set_transport_header(skb, h_pos); - - dev->trans_start = jiffies; - dev_queue_xmit(skb); - - return 0; - - fail: - if (!ret) - dev_kfree_skb(skb); - - return ret; -} - - -/* - * This is the transmit routine for the 802.11 type interfaces - * called by upper layers of the linux networking - * stack when it has a frame to transmit - */ -static int -ieee80211_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct ieee80211_sub_if_data *sdata; - struct ieee80211_tx_packet_data *pkt_data; - struct ieee80211_hdr *hdr; - u16 fc; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (skb->len < 10) { - dev_kfree_skb(skb); - return 0; - } - - if (skb_headroom(skb) < sdata->local->tx_headroom) { - if (pskb_expand_head(skb, sdata->local->tx_headroom, - 0, GFP_ATOMIC)) { - dev_kfree_skb(skb); - return 0; - } - } - - hdr = (struct ieee80211_hdr *) skb->data; - fc = le16_to_cpu(hdr->frame_control); - - pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; - memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data)); - pkt_data->ifindex = sdata->dev->ifindex; - pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT); - - skb->priority = 20; /* use hardcoded priority for mgmt TX queue */ - skb->dev = sdata->local->mdev; - - /* - * We're using the protocol field of the the frame control header - * to request TX callback for hostapd. BIT(1) is checked. - */ - if ((fc & BIT(1)) == BIT(1)) { - pkt_data->req_tx_status = 1; - fc &= ~BIT(1); - hdr->frame_control = cpu_to_le16(fc); + printk(KERN_DEBUG "%s: could not find STA entry for WDS link " + "peer %s\n", + dev->name, print_mac(mac, sdata->u.wds.remote_addr)); } - pkt_data->do_not_encrypt = !(fc & IEEE80211_FCTL_PROTECTED); - - sdata->stats.tx_packets++; - sdata->stats.tx_bytes += skb->len; - - dev_queue_xmit(skb); + /* Update WDS link data */ + memcpy(&sdata->u.wds.remote_addr, remote_addr, ETH_ALEN); return 0; } - -static void ieee80211_beacon_add_tim(struct ieee80211_local *local, - struct ieee80211_if_ap *bss, - struct sk_buff *skb) -{ - u8 *pos, *tim; - int aid0 = 0; - int i, have_bits = 0, n1, n2; - - /* Generate bitmap for TIM only if there are any STAs in power save - * mode. */ - spin_lock_bh(&local->sta_lock); - if (atomic_read(&bss->num_sta_ps) > 0) - /* in the hope that this is faster than - * checking byte-for-byte */ - have_bits = !bitmap_empty((unsigned long*)bss->tim, - IEEE80211_MAX_AID+1); - - if (bss->dtim_count == 0) - bss->dtim_count = bss->dtim_period - 1; - else - bss->dtim_count--; - - tim = pos = (u8 *) skb_put(skb, 6); - *pos++ = WLAN_EID_TIM; - *pos++ = 4; - *pos++ = bss->dtim_count; - *pos++ = bss->dtim_period; - - if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf)) - aid0 = 1; - - if (have_bits) { - /* Find largest even number N1 so that bits numbered 1 through - * (N1 x 8) - 1 in the bitmap are 0 and number N2 so that bits - * (N2 + 1) x 8 through 2007 are 0. */ - n1 = 0; - for (i = 0; i < IEEE80211_MAX_TIM_LEN; i++) { - if (bss->tim[i]) { - n1 = i & 0xfe; - break; - } - } - n2 = n1; - for (i = IEEE80211_MAX_TIM_LEN - 1; i >= n1; i--) { - if (bss->tim[i]) { - n2 = i; - break; - } - } - - /* Bitmap control */ - *pos++ = n1 | aid0; - /* Part Virt Bitmap */ - memcpy(pos, bss->tim + n1, n2 - n1 + 1); - - tim[1] = n2 - n1 + 4; - skb_put(skb, n2 - n1); - } else { - *pos++ = aid0; /* Bitmap control */ - *pos++ = 0; /* Part Virt Bitmap */ - } - spin_unlock_bh(&local->sta_lock); -} - - -struct sk_buff * ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id, - struct ieee80211_tx_control *control) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct sk_buff *skb; - struct net_device *bdev; - struct ieee80211_sub_if_data *sdata = NULL; - struct ieee80211_if_ap *ap = NULL; - struct ieee80211_rate *rate; - struct rate_control_extra extra; - u8 *b_head, *b_tail; - int bh_len, bt_len; - - bdev = dev_get_by_index(if_id); - if (bdev) { - sdata = IEEE80211_DEV_TO_SUB_IF(bdev); - ap = &sdata->u.ap; - dev_put(bdev); - } - - if (!ap || sdata->type != IEEE80211_IF_TYPE_AP || - !ap->beacon_head) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - if (net_ratelimit()) - printk(KERN_DEBUG "no beacon data avail for idx=%d " - "(%s)\n", if_id, bdev ? bdev->name : "N/A"); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ - return NULL; - } - - /* Assume we are generating the normal beacon locally */ - b_head = ap->beacon_head; - b_tail = ap->beacon_tail; - bh_len = ap->beacon_head_len; - bt_len = ap->beacon_tail_len; - - skb = dev_alloc_skb(local->tx_headroom + - bh_len + bt_len + 256 /* maximum TIM len */); - if (!skb) - return NULL; - - skb_reserve(skb, local->tx_headroom); - memcpy(skb_put(skb, bh_len), b_head, bh_len); - - ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data); - - ieee80211_beacon_add_tim(local, ap, skb); - - if (b_tail) { - memcpy(skb_put(skb, bt_len), b_tail, bt_len); - } - - if (control) { - memset(&extra, 0, sizeof(extra)); - extra.mode = local->oper_hw_mode; - - rate = rate_control_get_rate(local, local->mdev, skb, &extra); - if (!rate) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: ieee80211_beacon_get: no rate " - "found\n", local->mdev->name); - } - dev_kfree_skb(skb); - return NULL; - } - - control->tx_rate = (local->short_preamble && - (rate->flags & IEEE80211_RATE_PREAMBLE2)) ? - rate->val2 : rate->val; - control->antenna_sel_tx = local->hw.conf.antenna_sel_tx; - control->power_level = local->hw.conf.power_level; - control->flags |= IEEE80211_TXCTL_NO_ACK; - control->retry_limit = 1; - control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK; - } - - ap->num_beacons++; - return skb; -} -EXPORT_SYMBOL(ieee80211_beacon_get); - -__le16 ieee80211_rts_duration(struct ieee80211_hw *hw, - size_t frame_len, - const struct ieee80211_tx_control *frame_txctl) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct ieee80211_rate *rate; - int short_preamble = local->short_preamble; - int erp; - u16 dur; - - rate = frame_txctl->rts_rate; - erp = !!(rate->flags & IEEE80211_RATE_ERP); - - /* CTS duration */ - dur = ieee80211_frame_duration(local, 10, rate->rate, - erp, short_preamble); - /* Data frame duration */ - dur += ieee80211_frame_duration(local, frame_len, rate->rate, - erp, short_preamble); - /* ACK duration */ - dur += ieee80211_frame_duration(local, 10, rate->rate, - erp, short_preamble); - - return cpu_to_le16(dur); -} -EXPORT_SYMBOL(ieee80211_rts_duration); - - -__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, - size_t frame_len, - const struct ieee80211_tx_control *frame_txctl) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct ieee80211_rate *rate; - int short_preamble = local->short_preamble; - int erp; - u16 dur; - - rate = frame_txctl->rts_rate; - erp = !!(rate->flags & IEEE80211_RATE_ERP); - - /* Data frame duration */ - dur = ieee80211_frame_duration(local, frame_len, rate->rate, - erp, short_preamble); - if (!(frame_txctl->flags & IEEE80211_TXCTL_NO_ACK)) { - /* ACK duration */ - dur += ieee80211_frame_duration(local, 10, rate->rate, - erp, short_preamble); - } - - return cpu_to_le16(dur); -} -EXPORT_SYMBOL(ieee80211_ctstoself_duration); - -void ieee80211_rts_get(struct ieee80211_hw *hw, - const void *frame, size_t frame_len, - const struct ieee80211_tx_control *frame_txctl, - struct ieee80211_rts *rts) -{ - const struct ieee80211_hdr *hdr = frame; - u16 fctl; - - fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS; - rts->frame_control = cpu_to_le16(fctl); - rts->duration = ieee80211_rts_duration(hw, frame_len, frame_txctl); - memcpy(rts->ra, hdr->addr1, sizeof(rts->ra)); - memcpy(rts->ta, hdr->addr2, sizeof(rts->ta)); -} -EXPORT_SYMBOL(ieee80211_rts_get); - -void ieee80211_ctstoself_get(struct ieee80211_hw *hw, - const void *frame, size_t frame_len, - const struct ieee80211_tx_control *frame_txctl, - struct ieee80211_cts *cts) -{ - const struct ieee80211_hdr *hdr = frame; - u16 fctl; - - fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS; - cts->frame_control = cpu_to_le16(fctl); - cts->duration = ieee80211_ctstoself_duration(hw, frame_len, frame_txctl); - memcpy(cts->ra, hdr->addr1, sizeof(cts->ra)); -} -EXPORT_SYMBOL(ieee80211_ctstoself_get); - -struct sk_buff * -ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id, - struct ieee80211_tx_control *control) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct sk_buff *skb; - struct sta_info *sta; - ieee80211_tx_handler *handler; - struct ieee80211_txrx_data tx; - ieee80211_txrx_result res = TXRX_DROP; - struct net_device *bdev; - struct ieee80211_sub_if_data *sdata; - struct ieee80211_if_ap *bss = NULL; - - bdev = dev_get_by_index(if_id); - if (bdev) { - sdata = IEEE80211_DEV_TO_SUB_IF(bdev); - bss = &sdata->u.ap; - dev_put(bdev); - } - if (!bss || sdata->type != IEEE80211_IF_TYPE_AP || !bss->beacon_head) - return NULL; - - if (bss->dtim_count != 0) - return NULL; /* send buffered bc/mc only after DTIM beacon */ - memset(control, 0, sizeof(*control)); - while (1) { - skb = skb_dequeue(&bss->ps_bc_buf); - if (!skb) - return NULL; - local->total_ps_buffered--; - - if (!skb_queue_empty(&bss->ps_bc_buf) && skb->len >= 2) { - struct ieee80211_hdr *hdr = - (struct ieee80211_hdr *) skb->data; - /* more buffered multicast/broadcast frames ==> set - * MoreData flag in IEEE 802.11 header to inform PS - * STAs */ - hdr->frame_control |= - cpu_to_le16(IEEE80211_FCTL_MOREDATA); - } - - if (ieee80211_tx_prepare(&tx, skb, local->mdev, control) == 0) - break; - dev_kfree_skb_any(skb); - } - sta = tx.sta; - tx.u.tx.ps_buffered = 1; - - for (handler = local->tx_handlers; *handler != NULL; handler++) { - res = (*handler)(&tx); - if (res == TXRX_DROP || res == TXRX_QUEUED) - break; - } - dev_put(tx.dev); - skb = tx.skb; /* handlers are allowed to change skb */ - - if (res == TXRX_DROP) { - I802_DEBUG_INC(local->tx_handlers_drop); - dev_kfree_skb(skb); - skb = NULL; - } else if (res == TXRX_QUEUED) { - I802_DEBUG_INC(local->tx_handlers_queued); - skb = NULL; - } - - if (sta) - sta_info_put(sta); - - return skb; -} -EXPORT_SYMBOL(ieee80211_get_buffered_bc); +/* everything else */ static int __ieee80211_if_config(struct net_device *dev, struct sk_buff *beacon, @@ -2286,7 +454,6 @@ static int __ieee80211_if_config(struct net_device *dev, struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_if_conf conf; - static u8 scan_bssid[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; if (!local->ops->config_interface || !netif_running(dev)) return 0; @@ -2295,20 +462,12 @@ static int __ieee80211_if_config(struct net_device *dev, conf.type = sdata->type; if (sdata->type == IEEE80211_IF_TYPE_STA || sdata->type == IEEE80211_IF_TYPE_IBSS) { - if (local->sta_scanning && - local->scan_dev == dev) - conf.bssid = scan_bssid; - else - conf.bssid = sdata->u.sta.bssid; + conf.bssid = sdata->u.sta.bssid; conf.ssid = sdata->u.sta.ssid; conf.ssid_len = sdata->u.sta.ssid_len; - conf.generic_elem = sdata->u.sta.extra_ie; - conf.generic_elem_len = sdata->u.sta.extra_ie_len; } else if (sdata->type == IEEE80211_IF_TYPE_AP) { conf.ssid = sdata->u.ap.ssid; conf.ssid_len = sdata->u.ap.ssid_len; - conf.generic_elem = sdata->u.ap.generic_elem; - conf.generic_elem_len = sdata->u.ap.generic_elem_len; conf.beacon = beacon; conf.beacon_control = control; } @@ -2351,7 +510,12 @@ int ieee80211_hw_config(struct ieee80211_local *local) local->hw.conf.channel = chan->chan; local->hw.conf.channel_val = chan->val; - local->hw.conf.power_level = chan->power_level; + if (!local->hw.conf.power_level) { + local->hw.conf.power_level = chan->power_level; + } else { + local->hw.conf.power_level = min(chan->power_level, + local->hw.conf.power_level); + } local->hw.conf.freq = chan->freq; local->hw.conf.phymode = mode->mode; local->hw.conf.antenna_max = chan->antenna_max; @@ -2364,1971 +528,33 @@ int ieee80211_hw_config(struct ieee80211_local *local) local->hw.conf.phymode); #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ - if (local->ops->config) + if (local->open_count) ret = local->ops->config(local_to_hw(local), &local->hw.conf); return ret; } - -static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) -{ - /* FIX: what would be proper limits for MTU? - * This interface uses 802.3 frames. */ - if (new_mtu < 256 || new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6) { - printk(KERN_WARNING "%s: invalid MTU %d\n", - dev->name, new_mtu); - return -EINVAL; - } - -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ - dev->mtu = new_mtu; - return 0; -} - - -static int ieee80211_change_mtu_apdev(struct net_device *dev, int new_mtu) -{ - /* FIX: what would be proper limits for MTU? - * This interface uses 802.11 frames. */ - if (new_mtu < 256 || new_mtu > IEEE80211_MAX_DATA_LEN) { - printk(KERN_WARNING "%s: invalid MTU %d\n", - dev->name, new_mtu); - return -EINVAL; - } - -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ - dev->mtu = new_mtu; - return 0; -} - -enum netif_tx_lock_class { - TX_LOCK_NORMAL, - TX_LOCK_MASTER, -}; - -static inline void netif_tx_lock_nested(struct net_device *dev, int subclass) -{ - spin_lock_nested(&dev->_xmit_lock, subclass); - dev->xmit_lock_owner = smp_processor_id(); -} - -static void ieee80211_set_multicast_list(struct net_device *dev) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - unsigned short flags; - - netif_tx_lock_nested(local->mdev, TX_LOCK_MASTER); - if (((dev->flags & IFF_ALLMULTI) != 0) ^ (sdata->allmulti != 0)) { - if (sdata->allmulti) { - sdata->allmulti = 0; - local->iff_allmultis--; - } else { - sdata->allmulti = 1; - local->iff_allmultis++; - } - } - if (((dev->flags & IFF_PROMISC) != 0) ^ (sdata->promisc != 0)) { - if (sdata->promisc) { - sdata->promisc = 0; - local->iff_promiscs--; - } else { - sdata->promisc = 1; - local->iff_promiscs++; - } - } - if (dev->mc_count != sdata->mc_count) { - local->mc_count = local->mc_count - sdata->mc_count + - dev->mc_count; - sdata->mc_count = dev->mc_count; - } - if (local->ops->set_multicast_list) { - flags = local->mdev->flags; - if (local->iff_allmultis) - flags |= IFF_ALLMULTI; - if (local->iff_promiscs) - flags |= IFF_PROMISC; - read_lock(&local->sub_if_lock); - local->ops->set_multicast_list(local_to_hw(local), flags, - local->mc_count); - read_unlock(&local->sub_if_lock); - } - netif_tx_unlock(local->mdev); -} - -struct dev_mc_list *ieee80211_get_mc_list_item(struct ieee80211_hw *hw, - struct dev_mc_list *prev, - void **ptr) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct ieee80211_sub_if_data *sdata = *ptr; - struct dev_mc_list *mc; - - if (!prev) { - WARN_ON(sdata); - sdata = NULL; - } - if (!prev || !prev->next) { - if (sdata) - sdata = list_entry(sdata->list.next, - struct ieee80211_sub_if_data, list); - else - sdata = list_entry(local->sub_if_list.next, - struct ieee80211_sub_if_data, list); - if (&sdata->list != &local->sub_if_list) - mc = sdata->dev->mc_list; - else - mc = NULL; - } else - mc = prev->next; - - *ptr = sdata; - return mc; -} -EXPORT_SYMBOL(ieee80211_get_mc_list_item); - -static struct net_device_stats *ieee80211_get_stats(struct net_device *dev) -{ - struct ieee80211_sub_if_data *sdata; - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - return &(sdata->stats); -} - -static void ieee80211_if_shutdown(struct net_device *dev) +void ieee80211_erp_info_change_notify(struct net_device *dev, u8 changes) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - ASSERT_RTNL(); - switch (sdata->type) { - case IEEE80211_IF_TYPE_STA: - case IEEE80211_IF_TYPE_IBSS: - sdata->u.sta.state = IEEE80211_DISABLED; - del_timer_sync(&sdata->u.sta.timer); - skb_queue_purge(&sdata->u.sta.skb_queue); - if (!local->ops->hw_scan && - local->scan_dev == sdata->dev) { - local->sta_scanning = 0; - cancel_delayed_work(&local->scan_work); - } - flush_workqueue(local->hw.workqueue); - break; - } -} - -static inline int identical_mac_addr_allowed(int type1, int type2) -{ - return (type1 == IEEE80211_IF_TYPE_MNTR || - type2 == IEEE80211_IF_TYPE_MNTR || - (type1 == IEEE80211_IF_TYPE_AP && - type2 == IEEE80211_IF_TYPE_WDS) || - (type1 == IEEE80211_IF_TYPE_WDS && - (type2 == IEEE80211_IF_TYPE_WDS || - type2 == IEEE80211_IF_TYPE_AP)) || - (type1 == IEEE80211_IF_TYPE_AP && - type2 == IEEE80211_IF_TYPE_VLAN) || - (type1 == IEEE80211_IF_TYPE_VLAN && - (type2 == IEEE80211_IF_TYPE_AP || - type2 == IEEE80211_IF_TYPE_VLAN))); -} - -static int ieee80211_master_open(struct net_device *dev) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata; - int res = -EOPNOTSUPP; - - read_lock(&local->sub_if_lock); - list_for_each_entry(sdata, &local->sub_if_list, list) { - if (sdata->dev != dev && netif_running(sdata->dev)) { - res = 0; - break; - } - } - read_unlock(&local->sub_if_lock); - return res; -} - -static int ieee80211_master_stop(struct net_device *dev) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata; - - read_lock(&local->sub_if_lock); - list_for_each_entry(sdata, &local->sub_if_list, list) - if (sdata->dev != dev && netif_running(sdata->dev)) - dev_close(sdata->dev); - read_unlock(&local->sub_if_lock); - - return 0; -} - -static int ieee80211_mgmt_open(struct net_device *dev) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - if (!netif_running(local->mdev)) - return -EOPNOTSUPP; - return 0; -} - -static int ieee80211_mgmt_stop(struct net_device *dev) -{ - return 0; -} - -/* Check if running monitor interfaces should go to a "soft monitor" mode - * and switch them if necessary. */ -static inline void ieee80211_start_soft_monitor(struct ieee80211_local *local) -{ - struct ieee80211_if_init_conf conf; - - if (local->open_count && local->open_count == local->monitors && - !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) && - local->ops->remove_interface) { - conf.if_id = -1; - conf.type = IEEE80211_IF_TYPE_MNTR; - conf.mac_addr = NULL; - local->ops->remove_interface(local_to_hw(local), &conf); - } -} - -/* Check if running monitor interfaces should go to a "hard monitor" mode - * and switch them if necessary. */ -static void ieee80211_start_hard_monitor(struct ieee80211_local *local) -{ - struct ieee80211_if_init_conf conf; - - if (local->open_count && local->open_count == local->monitors && - !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) { - conf.if_id = -1; - conf.type = IEEE80211_IF_TYPE_MNTR; - conf.mac_addr = NULL; - local->ops->add_interface(local_to_hw(local), &conf); - } -} - -static int ieee80211_open(struct net_device *dev) -{ - struct ieee80211_sub_if_data *sdata, *nsdata; - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_if_init_conf conf; - int res; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - read_lock(&local->sub_if_lock); - list_for_each_entry(nsdata, &local->sub_if_list, list) { - struct net_device *ndev = nsdata->dev; - - if (ndev != dev && ndev != local->mdev && netif_running(ndev) && - compare_ether_addr(dev->dev_addr, ndev->dev_addr) == 0 && - !identical_mac_addr_allowed(sdata->type, nsdata->type)) { - read_unlock(&local->sub_if_lock); - return -ENOTUNIQ; - } - } - read_unlock(&local->sub_if_lock); - - if (sdata->type == IEEE80211_IF_TYPE_WDS && - is_zero_ether_addr(sdata->u.wds.remote_addr)) - return -ENOLINK; - - if (sdata->type == IEEE80211_IF_TYPE_MNTR && local->open_count && - !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) { - /* run the interface in a "soft monitor" mode */ - local->monitors++; - local->open_count++; - local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; - return 0; - } - ieee80211_start_soft_monitor(local); - - conf.if_id = dev->ifindex; - conf.type = sdata->type; - conf.mac_addr = dev->dev_addr; - res = local->ops->add_interface(local_to_hw(local), &conf); - if (res) { - if (sdata->type == IEEE80211_IF_TYPE_MNTR) - ieee80211_start_hard_monitor(local); - return res; - } - - if (local->open_count == 0) { - res = 0; - tasklet_enable(&local->tx_pending_tasklet); - tasklet_enable(&local->tasklet); - if (local->ops->open) - res = local->ops->open(local_to_hw(local)); - if (res == 0) { - res = dev_open(local->mdev); - if (res) { - if (local->ops->stop) - local->ops->stop(local_to_hw(local)); - } else { - res = ieee80211_hw_config(local); - if (res && local->ops->stop) - local->ops->stop(local_to_hw(local)); - else if (!res && local->apdev) - dev_open(local->apdev); - } - } - if (res) { - if (local->ops->remove_interface) - local->ops->remove_interface(local_to_hw(local), - &conf); - return res; - } - } - local->open_count++; - - if (sdata->type == IEEE80211_IF_TYPE_MNTR) { - local->monitors++; - local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; - } else - ieee80211_if_config(dev); - - if (sdata->type == IEEE80211_IF_TYPE_STA && - !local->user_space_mlme) - netif_carrier_off(dev); - else - netif_carrier_on(dev); - - netif_start_queue(dev); - return 0; -} - - -static int ieee80211_stop(struct net_device *dev) -{ - struct ieee80211_sub_if_data *sdata; - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (sdata->type == IEEE80211_IF_TYPE_MNTR && - local->open_count > 1 && - !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) { - /* remove "soft monitor" interface */ - local->open_count--; - local->monitors--; - if (!local->monitors) - local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP; - return 0; - } - - netif_stop_queue(dev); - ieee80211_if_shutdown(dev); - - if (sdata->type == IEEE80211_IF_TYPE_MNTR) { - local->monitors--; - if (!local->monitors) - local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP; - } - - local->open_count--; - if (local->open_count == 0) { - if (netif_running(local->mdev)) - dev_close(local->mdev); - if (local->apdev) - dev_close(local->apdev); - if (local->ops->stop) - local->ops->stop(local_to_hw(local)); - tasklet_disable(&local->tx_pending_tasklet); - tasklet_disable(&local->tasklet); - } - if (local->ops->remove_interface) { - struct ieee80211_if_init_conf conf; - - conf.if_id = dev->ifindex; - conf.type = sdata->type; - conf.mac_addr = dev->dev_addr; - local->ops->remove_interface(local_to_hw(local), &conf); - } - - ieee80211_start_hard_monitor(local); - - return 0; -} - - -static int header_parse_80211(struct sk_buff *skb, unsigned char *haddr) -{ - memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */ - return ETH_ALEN; -} - -static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) -{ - return compare_ether_addr(raddr, addr) == 0 || - is_broadcast_ether_addr(raddr); + if (local->ops->erp_ie_changed) + local->ops->erp_ie_changed(local_to_hw(local), changes, + !!(sdata->flags & IEEE80211_SDATA_USE_PROTECTION), + !(sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE)); } - -static ieee80211_txrx_result -ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) +void ieee80211_reset_erp_info(struct net_device *dev) { - struct net_device *dev = rx->dev; - struct ieee80211_local *local = rx->local; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; - u16 fc, hdrlen, ethertype; - u8 *payload; - u8 dst[ETH_ALEN]; - u8 src[ETH_ALEN]; - struct sk_buff *skb = rx->skb, *skb2; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - fc = rx->fc; - if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)) - return TXRX_CONTINUE; - - if (unlikely(!WLAN_FC_DATA_PRESENT(fc))) - return TXRX_DROP; - - hdrlen = ieee80211_get_hdrlen(fc); - - /* convert IEEE 802.11 header + possible LLC headers into Ethernet - * header - * IEEE 802.11 address fields: - * ToDS FromDS Addr1 Addr2 Addr3 Addr4 - * 0 0 DA SA BSSID n/a - * 0 1 DA BSSID SA n/a - * 1 0 BSSID SA DA n/a - * 1 1 RA TA DA SA - */ - - switch (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { - case IEEE80211_FCTL_TODS: - /* BSSID SA DA */ - memcpy(dst, hdr->addr3, ETH_ALEN); - memcpy(src, hdr->addr2, ETH_ALEN); - - if (unlikely(sdata->type != IEEE80211_IF_TYPE_AP && - sdata->type != IEEE80211_IF_TYPE_VLAN)) { - printk(KERN_DEBUG "%s: dropped ToDS frame (BSSID=" - MAC_FMT " SA=" MAC_FMT " DA=" MAC_FMT ")\n", - dev->name, MAC_ARG(hdr->addr1), - MAC_ARG(hdr->addr2), MAC_ARG(hdr->addr3)); - return TXRX_DROP; - } - break; - case (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): - /* RA TA DA SA */ - memcpy(dst, hdr->addr3, ETH_ALEN); - memcpy(src, hdr->addr4, ETH_ALEN); - - if (unlikely(sdata->type != IEEE80211_IF_TYPE_WDS)) { - printk(KERN_DEBUG "%s: dropped FromDS&ToDS frame (RA=" - MAC_FMT " TA=" MAC_FMT " DA=" MAC_FMT " SA=" - MAC_FMT ")\n", - rx->dev->name, MAC_ARG(hdr->addr1), - MAC_ARG(hdr->addr2), MAC_ARG(hdr->addr3), - MAC_ARG(hdr->addr4)); - return TXRX_DROP; - } - break; - case IEEE80211_FCTL_FROMDS: - /* DA BSSID SA */ - memcpy(dst, hdr->addr1, ETH_ALEN); - memcpy(src, hdr->addr3, ETH_ALEN); - - if (sdata->type != IEEE80211_IF_TYPE_STA) { - return TXRX_DROP; - } - break; - case 0: - /* DA SA BSSID */ - memcpy(dst, hdr->addr1, ETH_ALEN); - memcpy(src, hdr->addr2, ETH_ALEN); - - if (sdata->type != IEEE80211_IF_TYPE_IBSS) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: dropped IBSS frame (DA=" - MAC_FMT " SA=" MAC_FMT " BSSID=" MAC_FMT - ")\n", - dev->name, MAC_ARG(hdr->addr1), - MAC_ARG(hdr->addr2), - MAC_ARG(hdr->addr3)); - } - return TXRX_DROP; - } - break; - } - - payload = skb->data + hdrlen; - - if (unlikely(skb->len - hdrlen < 8)) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: RX too short data frame " - "payload\n", dev->name); - } - return TXRX_DROP; - } - - ethertype = (payload[6] << 8) | payload[7]; - - if (likely((compare_ether_addr(payload, rfc1042_header) == 0 && - ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || - compare_ether_addr(payload, bridge_tunnel_header) == 0)) { - /* remove RFC1042 or Bridge-Tunnel encapsulation and - * replace EtherType */ - skb_pull(skb, hdrlen + 6); - memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); - memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); - } else { - struct ethhdr *ehdr; - __be16 len; - skb_pull(skb, hdrlen); - len = htons(skb->len); - ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr)); - memcpy(ehdr->h_dest, dst, ETH_ALEN); - memcpy(ehdr->h_source, src, ETH_ALEN); - ehdr->h_proto = len; - } - skb->dev = dev; - - skb2 = NULL; - - sdata->stats.rx_packets++; - sdata->stats.rx_bytes += skb->len; - - if (local->bridge_packets && (sdata->type == IEEE80211_IF_TYPE_AP - || sdata->type == IEEE80211_IF_TYPE_VLAN) && rx->u.rx.ra_match) { - if (is_multicast_ether_addr(skb->data)) { - /* send multicast frames both to higher layers in - * local net stack and back to the wireless media */ - skb2 = skb_copy(skb, GFP_ATOMIC); - if (!skb2) - printk(KERN_DEBUG "%s: failed to clone " - "multicast frame\n", dev->name); - } else { - struct sta_info *dsta; - dsta = sta_info_get(local, skb->data); - if (dsta && !dsta->dev) { - printk(KERN_DEBUG "Station with null dev " - "structure!\n"); - } else if (dsta && dsta->dev == dev) { - /* Destination station is associated to this - * AP, so send the frame directly to it and - * do not pass the frame to local net stack. - */ - skb2 = skb; - skb = NULL; - } - if (dsta) - sta_info_put(dsta); - } - } - - if (skb) { - /* deliver to local stack */ - skb->protocol = eth_type_trans(skb, dev); - memset(skb->cb, 0, sizeof(skb->cb)); - netif_rx(skb); - } - - if (skb2) { - /* send to wireless media */ - skb2->protocol = __constant_htons(ETH_P_802_3); - skb_set_network_header(skb2, 0); - skb_set_mac_header(skb2, 0); - dev_queue_xmit(skb2); - } - - return TXRX_QUEUED; -} - - -static struct ieee80211_rate * -ieee80211_get_rate(struct ieee80211_local *local, int phymode, int hw_rate) -{ - struct ieee80211_hw_mode *mode; - int r; - - list_for_each_entry(mode, &local->modes_list, list) { - if (mode->mode != phymode) - continue; - for (r = 0; r < mode->num_rates; r++) { - struct ieee80211_rate *rate = &mode->rates[r]; - if (rate->val == hw_rate || - (rate->flags & IEEE80211_RATE_PREAMBLE2 && - rate->val2 == hw_rate)) - return rate; - } - } - - return NULL; -} - -static void -ieee80211_fill_frame_info(struct ieee80211_local *local, - struct ieee80211_frame_info *fi, - struct ieee80211_rx_status *status) -{ - if (status) { - struct timespec ts; - struct ieee80211_rate *rate; - - jiffies_to_timespec(jiffies, &ts); - fi->hosttime = cpu_to_be64((u64) ts.tv_sec * 1000000 + - ts.tv_nsec / 1000); - fi->mactime = cpu_to_be64(status->mactime); - switch (status->phymode) { - case MODE_IEEE80211A: - fi->phytype = htonl(ieee80211_phytype_ofdm_dot11_a); - break; - case MODE_IEEE80211B: - fi->phytype = htonl(ieee80211_phytype_dsss_dot11_b); - break; - case MODE_IEEE80211G: - fi->phytype = htonl(ieee80211_phytype_pbcc_dot11_g); - break; - case MODE_ATHEROS_TURBO: - fi->phytype = - htonl(ieee80211_phytype_dsss_dot11_turbo); - break; - default: - fi->phytype = htonl(0xAAAAAAAA); - break; - } - fi->channel = htonl(status->channel); - rate = ieee80211_get_rate(local, status->phymode, - status->rate); - if (rate) { - fi->datarate = htonl(rate->rate); - if (rate->flags & IEEE80211_RATE_PREAMBLE2) { - if (status->rate == rate->val) - fi->preamble = htonl(2); /* long */ - else if (status->rate == rate->val2) - fi->preamble = htonl(1); /* short */ - } else - fi->preamble = htonl(0); - } else { - fi->datarate = htonl(0); - fi->preamble = htonl(0); - } - - fi->antenna = htonl(status->antenna); - fi->priority = htonl(0xffffffff); /* no clue */ - fi->ssi_type = htonl(ieee80211_ssi_raw); - fi->ssi_signal = htonl(status->ssi); - fi->ssi_noise = 0x00000000; - fi->encoding = 0; - } else { - /* clear everything because we really don't know. - * the msg_type field isn't present on monitor frames - * so we don't know whether it will be present or not, - * but it's ok to not clear it since it'll be assigned - * anyway */ - memset(fi, 0, sizeof(*fi) - sizeof(fi->msg_type)); - - fi->ssi_type = htonl(ieee80211_ssi_none); - } - fi->version = htonl(IEEE80211_FI_VERSION); - fi->length = cpu_to_be32(sizeof(*fi) - sizeof(fi->msg_type)); -} - -/* this routine is actually not just for this, but also - * for pushing fake 'management' frames into userspace. - * it shall be replaced by a netlink-based system. */ -void -ieee80211_rx_mgmt(struct ieee80211_local *local, struct sk_buff *skb, - struct ieee80211_rx_status *status, u32 msg_type) -{ - struct ieee80211_frame_info *fi; - const size_t hlen = sizeof(struct ieee80211_frame_info); - struct ieee80211_sub_if_data *sdata; - - skb->dev = local->apdev; - - sdata = IEEE80211_DEV_TO_SUB_IF(local->apdev); - - if (skb_headroom(skb) < hlen) { - I802_DEBUG_INC(local->rx_expand_skb_head); - if (pskb_expand_head(skb, hlen, 0, GFP_ATOMIC)) { - dev_kfree_skb(skb); - return; - } - } - - fi = (struct ieee80211_frame_info *) skb_push(skb, hlen); - - ieee80211_fill_frame_info(local, fi, status); - fi->msg_type = htonl(msg_type); - - sdata->stats.rx_packets++; - sdata->stats.rx_bytes += skb->len; - - skb_set_mac_header(skb, 0); - skb->ip_summed = CHECKSUM_UNNECESSARY; - skb->pkt_type = PACKET_OTHERHOST; - skb->protocol = htons(ETH_P_802_2); - memset(skb->cb, 0, sizeof(skb->cb)); - netif_rx(skb); -} - -static void -ieee80211_rx_monitor(struct net_device *dev, struct sk_buff *skb, - struct ieee80211_rx_status *status) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata; - struct ieee80211_rate *rate; - struct ieee80211_rtap_hdr { - struct ieee80211_radiotap_header hdr; - u8 flags; - u8 rate; - __le16 chan_freq; - __le16 chan_flags; - u8 antsignal; - } __attribute__ ((packed)) *rthdr; - - skb->dev = dev; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (status->flag & RX_FLAG_RADIOTAP) - goto out; - - if (skb_headroom(skb) < sizeof(*rthdr)) { - I802_DEBUG_INC(local->rx_expand_skb_head); - if (pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC)) { - dev_kfree_skb(skb); - return; - } - } - - rthdr = (struct ieee80211_rtap_hdr *) skb_push(skb, sizeof(*rthdr)); - memset(rthdr, 0, sizeof(*rthdr)); - rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr)); - rthdr->hdr.it_present = - cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | - (1 << IEEE80211_RADIOTAP_RATE) | - (1 << IEEE80211_RADIOTAP_CHANNEL) | - (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL)); - rthdr->flags = local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS ? - IEEE80211_RADIOTAP_F_FCS : 0; - rate = ieee80211_get_rate(local, status->phymode, status->rate); - if (rate) - rthdr->rate = rate->rate / 5; - rthdr->chan_freq = cpu_to_le16(status->freq); - rthdr->chan_flags = - status->phymode == MODE_IEEE80211A ? - cpu_to_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ) : - cpu_to_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ); - rthdr->antsignal = status->ssi; - - out: - sdata->stats.rx_packets++; - sdata->stats.rx_bytes += skb->len; - - skb_set_mac_header(skb, 0); - skb->ip_summed = CHECKSUM_UNNECESSARY; - skb->pkt_type = PACKET_OTHERHOST; - skb->protocol = htons(ETH_P_802_2); - memset(skb->cb, 0, sizeof(skb->cb)); - netif_rx(skb); -} - -int ieee80211_radar_status(struct ieee80211_hw *hw, int channel, - int radar, int radar_type) -{ - struct sk_buff *skb; - struct ieee80211_radar_info *msg; - struct ieee80211_local *local = hw_to_local(hw); - - if (!local->apdev) - return 0; - - skb = dev_alloc_skb(sizeof(struct ieee80211_frame_info) + - sizeof(struct ieee80211_radar_info)); - - if (!skb) - return -ENOMEM; - skb_reserve(skb, sizeof(struct ieee80211_frame_info)); - - msg = (struct ieee80211_radar_info *) - skb_put(skb, sizeof(struct ieee80211_radar_info)); - msg->channel = channel; - msg->radar = radar; - msg->radar_type = radar_type; - - ieee80211_rx_mgmt(local, skb, NULL, ieee80211_msg_radar); - return 0; -} -EXPORT_SYMBOL(ieee80211_radar_status); - - -static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta) -{ - struct ieee80211_sub_if_data *sdata; - sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); - - if (sdata->bss) - atomic_inc(&sdata->bss->num_sta_ps); - sta->flags |= WLAN_STA_PS; - sta->pspoll = 0; -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d enters power " - "save mode\n", dev->name, MAC_ARG(sta->addr), sta->aid); -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ -} - - -static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct sk_buff *skb; - int sent = 0; - struct ieee80211_sub_if_data *sdata; - struct ieee80211_tx_packet_data *pkt_data; - - sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); - if (sdata->bss) - atomic_dec(&sdata->bss->num_sta_ps); - sta->flags &= ~(WLAN_STA_PS | WLAN_STA_TIM); - sta->pspoll = 0; - if (!skb_queue_empty(&sta->ps_tx_buf)) { - if (local->ops->set_tim) - local->ops->set_tim(local_to_hw(local), sta->aid, 0); - if (sdata->bss) - bss_tim_clear(local, sdata->bss, sta->aid); - } -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d exits power " - "save mode\n", dev->name, MAC_ARG(sta->addr), sta->aid); -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - /* Send all buffered frames to the station */ - while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { - pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; - sent++; - pkt_data->requeue = 1; - dev_queue_xmit(skb); - } - while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { - pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; - local->total_ps_buffered--; - sent++; -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d send PS frame " - "since STA not sleeping anymore\n", dev->name, - MAC_ARG(sta->addr), sta->aid); -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - pkt_data->requeue = 1; - dev_queue_xmit(skb); - } - - return sent; -} - - -static ieee80211_txrx_result -ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) -{ - struct sk_buff *skb; - int no_pending_pkts; - - if (likely(!rx->sta || - (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_CTL || - (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PSPOLL || - !rx->u.rx.ra_match)) - return TXRX_CONTINUE; - - skb = skb_dequeue(&rx->sta->tx_filtered); - if (!skb) { - skb = skb_dequeue(&rx->sta->ps_tx_buf); - if (skb) - rx->local->total_ps_buffered--; - } - no_pending_pkts = skb_queue_empty(&rx->sta->tx_filtered) && - skb_queue_empty(&rx->sta->ps_tx_buf); - - if (skb) { - struct ieee80211_hdr *hdr = - (struct ieee80211_hdr *) skb->data; - - /* tell TX path to send one frame even though the STA may - * still remain is PS mode after this frame exchange */ - rx->sta->pspoll = 1; - -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "STA " MAC_FMT " aid %d: PS Poll (entries " - "after %d)\n", - MAC_ARG(rx->sta->addr), rx->sta->aid, - skb_queue_len(&rx->sta->ps_tx_buf)); -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - - /* Use MoreData flag to indicate whether there are more - * buffered frames for this STA */ - if (no_pending_pkts) { - hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREDATA); - rx->sta->flags &= ~WLAN_STA_TIM; - } else - hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); - - dev_queue_xmit(skb); - - if (no_pending_pkts) { - if (rx->local->ops->set_tim) - rx->local->ops->set_tim(local_to_hw(rx->local), - rx->sta->aid, 0); - if (rx->sdata->bss) - bss_tim_clear(rx->local, rx->sdata->bss, rx->sta->aid); - } -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - } else if (!rx->u.rx.sent_ps_buffered) { - printk(KERN_DEBUG "%s: STA " MAC_FMT " sent PS Poll even " - "though there is no buffered frames for it\n", - rx->dev->name, MAC_ARG(rx->sta->addr)); -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - - } - - /* Free PS Poll skb here instead of returning TXRX_DROP that would - * count as an dropped frame. */ - dev_kfree_skb(rx->skb); - - return TXRX_QUEUED; -} - - -static inline struct ieee80211_fragment_entry * -ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata, - unsigned int frag, unsigned int seq, int rx_queue, - struct sk_buff **skb) -{ - struct ieee80211_fragment_entry *entry; - int idx; - - idx = sdata->fragment_next; - entry = &sdata->fragments[sdata->fragment_next++]; - if (sdata->fragment_next >= IEEE80211_FRAGMENT_MAX) - sdata->fragment_next = 0; - - if (!skb_queue_empty(&entry->skb_list)) { -#ifdef CONFIG_MAC80211_DEBUG - struct ieee80211_hdr *hdr = - (struct ieee80211_hdr *) entry->skb_list.next->data; - printk(KERN_DEBUG "%s: RX reassembly removed oldest " - "fragment entry (idx=%d age=%lu seq=%d last_frag=%d " - "addr1=" MAC_FMT " addr2=" MAC_FMT "\n", - sdata->dev->name, idx, - jiffies - entry->first_frag_time, entry->seq, - entry->last_frag, MAC_ARG(hdr->addr1), - MAC_ARG(hdr->addr2)); -#endif /* CONFIG_MAC80211_DEBUG */ - __skb_queue_purge(&entry->skb_list); - } - - __skb_queue_tail(&entry->skb_list, *skb); /* no need for locking */ - *skb = NULL; - entry->first_frag_time = jiffies; - entry->seq = seq; - entry->rx_queue = rx_queue; - entry->last_frag = frag; - entry->ccmp = 0; - entry->extra_len = 0; - - return entry; -} - - -static inline struct ieee80211_fragment_entry * -ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata, - u16 fc, unsigned int frag, unsigned int seq, - int rx_queue, struct ieee80211_hdr *hdr) -{ - struct ieee80211_fragment_entry *entry; - int i, idx; - - idx = sdata->fragment_next; - for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) { - struct ieee80211_hdr *f_hdr; - u16 f_fc; - - idx--; - if (idx < 0) - idx = IEEE80211_FRAGMENT_MAX - 1; - - entry = &sdata->fragments[idx]; - if (skb_queue_empty(&entry->skb_list) || entry->seq != seq || - entry->rx_queue != rx_queue || - entry->last_frag + 1 != frag) - continue; - - f_hdr = (struct ieee80211_hdr *) entry->skb_list.next->data; - f_fc = le16_to_cpu(f_hdr->frame_control); - - if ((fc & IEEE80211_FCTL_FTYPE) != (f_fc & IEEE80211_FCTL_FTYPE) || - compare_ether_addr(hdr->addr1, f_hdr->addr1) != 0 || - compare_ether_addr(hdr->addr2, f_hdr->addr2) != 0) - continue; - - if (entry->first_frag_time + 2 * HZ < jiffies) { - __skb_queue_purge(&entry->skb_list); - continue; - } - return entry; - } - - return NULL; -} - - -static ieee80211_txrx_result -ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) -{ - struct ieee80211_hdr *hdr; - u16 sc; - unsigned int frag, seq; - struct ieee80211_fragment_entry *entry; - struct sk_buff *skb; - - hdr = (struct ieee80211_hdr *) rx->skb->data; - sc = le16_to_cpu(hdr->seq_ctrl); - frag = sc & IEEE80211_SCTL_FRAG; - - if (likely((!(rx->fc & IEEE80211_FCTL_MOREFRAGS) && frag == 0) || - (rx->skb)->len < 24 || - is_multicast_ether_addr(hdr->addr1))) { - /* not fragmented */ - goto out; - } - I802_DEBUG_INC(rx->local->rx_handlers_fragments); - - seq = (sc & IEEE80211_SCTL_SEQ) >> 4; - - if (frag == 0) { - /* This is the first fragment of a new frame. */ - entry = ieee80211_reassemble_add(rx->sdata, frag, seq, - rx->u.rx.queue, &(rx->skb)); - if (rx->key && rx->key->alg == ALG_CCMP && - (rx->fc & IEEE80211_FCTL_PROTECTED)) { - /* Store CCMP PN so that we can verify that the next - * fragment has a sequential PN value. */ - entry->ccmp = 1; - memcpy(entry->last_pn, - rx->key->u.ccmp.rx_pn[rx->u.rx.queue], - CCMP_PN_LEN); - } - return TXRX_QUEUED; - } - - /* This is a fragment for a frame that should already be pending in - * fragment cache. Add this fragment to the end of the pending entry. - */ - entry = ieee80211_reassemble_find(rx->sdata, rx->fc, frag, seq, - rx->u.rx.queue, hdr); - if (!entry) { - I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag); - return TXRX_DROP; - } - - /* Verify that MPDUs within one MSDU have sequential PN values. - * (IEEE 802.11i, 8.3.3.4.5) */ - if (entry->ccmp) { - int i; - u8 pn[CCMP_PN_LEN], *rpn; - if (!rx->key || rx->key->alg != ALG_CCMP) - return TXRX_DROP; - memcpy(pn, entry->last_pn, CCMP_PN_LEN); - for (i = CCMP_PN_LEN - 1; i >= 0; i--) { - pn[i]++; - if (pn[i]) - break; - } - rpn = rx->key->u.ccmp.rx_pn[rx->u.rx.queue]; - if (memcmp(pn, rpn, CCMP_PN_LEN) != 0) { - printk(KERN_DEBUG "%s: defrag: CCMP PN not sequential" - " A2=" MAC_FMT " PN=%02x%02x%02x%02x%02x%02x " - "(expected %02x%02x%02x%02x%02x%02x)\n", - rx->dev->name, MAC_ARG(hdr->addr2), - rpn[0], rpn[1], rpn[2], rpn[3], rpn[4], rpn[5], - pn[0], pn[1], pn[2], pn[3], pn[4], pn[5]); - return TXRX_DROP; - } - memcpy(entry->last_pn, pn, CCMP_PN_LEN); - } - - skb_pull(rx->skb, ieee80211_get_hdrlen(rx->fc)); - __skb_queue_tail(&entry->skb_list, rx->skb); - entry->last_frag = frag; - entry->extra_len += rx->skb->len; - if (rx->fc & IEEE80211_FCTL_MOREFRAGS) { - rx->skb = NULL; - return TXRX_QUEUED; - } - - rx->skb = __skb_dequeue(&entry->skb_list); - if (skb_tailroom(rx->skb) < entry->extra_len) { - I802_DEBUG_INC(rx->local->rx_expand_skb_head2); - if (unlikely(pskb_expand_head(rx->skb, 0, entry->extra_len, - GFP_ATOMIC))) { - I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag); - __skb_queue_purge(&entry->skb_list); - return TXRX_DROP; - } - } - while ((skb = __skb_dequeue(&entry->skb_list))) { - memcpy(skb_put(rx->skb, skb->len), skb->data, skb->len); - dev_kfree_skb(skb); - } - - /* Complete frame has been reassembled - process it now */ - rx->fragmented = 1; - - out: - if (rx->sta) - rx->sta->rx_packets++; - if (is_multicast_ether_addr(hdr->addr1)) - rx->local->dot11MulticastReceivedFrameCount++; - else - ieee80211_led_rx(rx->local); - return TXRX_CONTINUE; -} - - -static ieee80211_txrx_result -ieee80211_rx_h_monitor(struct ieee80211_txrx_data *rx) -{ - if (rx->sdata->type == IEEE80211_IF_TYPE_MNTR) { - ieee80211_rx_monitor(rx->dev, rx->skb, rx->u.rx.status); - return TXRX_QUEUED; - } - - if (rx->u.rx.status->flag & RX_FLAG_RADIOTAP) - skb_pull(rx->skb, ieee80211_get_radiotap_len(rx->skb)); - - return TXRX_CONTINUE; -} - - -static ieee80211_txrx_result -ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) -{ - struct ieee80211_hdr *hdr; - int always_sta_key; - hdr = (struct ieee80211_hdr *) rx->skb->data; - - /* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */ - if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) { - if (unlikely(rx->fc & IEEE80211_FCTL_RETRY && - rx->sta->last_seq_ctrl[rx->u.rx.queue] == - hdr->seq_ctrl)) { - if (rx->u.rx.ra_match) { - rx->local->dot11FrameDuplicateCount++; - rx->sta->num_duplicates++; - } - return TXRX_DROP; - } else - rx->sta->last_seq_ctrl[rx->u.rx.queue] = hdr->seq_ctrl; - } - - if ((rx->local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) && - rx->skb->len > FCS_LEN) - skb_trim(rx->skb, rx->skb->len - FCS_LEN); - - if (unlikely(rx->skb->len < 16)) { - I802_DEBUG_INC(rx->local->rx_handlers_drop_short); - return TXRX_DROP; - } - - if (!rx->u.rx.ra_match) - rx->skb->pkt_type = PACKET_OTHERHOST; - else if (compare_ether_addr(rx->dev->dev_addr, hdr->addr1) == 0) - rx->skb->pkt_type = PACKET_HOST; - else if (is_multicast_ether_addr(hdr->addr1)) { - if (is_broadcast_ether_addr(hdr->addr1)) - rx->skb->pkt_type = PACKET_BROADCAST; - else - rx->skb->pkt_type = PACKET_MULTICAST; - } else - rx->skb->pkt_type = PACKET_OTHERHOST; - - /* Drop disallowed frame classes based on STA auth/assoc state; - * IEEE 802.11, Chap 5.5. - * - * 80211.o does filtering only based on association state, i.e., it - * drops Class 3 frames from not associated stations. hostapd sends - * deauth/disassoc frames when needed. In addition, hostapd is - * responsible for filtering on both auth and assoc states. - */ - if (unlikely(((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA || - ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL && - (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)) && - rx->sdata->type != IEEE80211_IF_TYPE_IBSS && - (!rx->sta || !(rx->sta->flags & WLAN_STA_ASSOC)))) { - if ((!(rx->fc & IEEE80211_FCTL_FROMDS) && - !(rx->fc & IEEE80211_FCTL_TODS) && - (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) - || !rx->u.rx.ra_match) { - /* Drop IBSS frames and frames for other hosts - * silently. */ - return TXRX_DROP; - } - - if (!rx->local->apdev) - return TXRX_DROP; - - ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status, - ieee80211_msg_sta_not_assoc); - return TXRX_QUEUED; - } - - if (rx->sdata->type == IEEE80211_IF_TYPE_STA) - always_sta_key = 0; - else - always_sta_key = 1; - - if (rx->sta && rx->sta->key && always_sta_key) { - rx->key = rx->sta->key; - } else { - if (rx->sta && rx->sta->key) - rx->key = rx->sta->key; - else - rx->key = rx->sdata->default_key; - - if ((rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) && - rx->fc & IEEE80211_FCTL_PROTECTED) { - int keyidx = ieee80211_wep_get_keyidx(rx->skb); - - if (keyidx >= 0 && keyidx < NUM_DEFAULT_KEYS && - (!rx->sta || !rx->sta->key || keyidx > 0)) - rx->key = rx->sdata->keys[keyidx]; - - if (!rx->key) { - if (!rx->u.rx.ra_match) - return TXRX_DROP; - printk(KERN_DEBUG "%s: RX WEP frame with " - "unknown keyidx %d (A1=" MAC_FMT " A2=" - MAC_FMT " A3=" MAC_FMT ")\n", - rx->dev->name, keyidx, - MAC_ARG(hdr->addr1), - MAC_ARG(hdr->addr2), - MAC_ARG(hdr->addr3)); - if (!rx->local->apdev) - return TXRX_DROP; - ieee80211_rx_mgmt( - rx->local, rx->skb, rx->u.rx.status, - ieee80211_msg_wep_frame_unknown_key); - return TXRX_QUEUED; - } - } - } - - if (rx->fc & IEEE80211_FCTL_PROTECTED && rx->key && rx->u.rx.ra_match) { - rx->key->tx_rx_count++; - if (unlikely(rx->local->key_tx_rx_threshold && - rx->key->tx_rx_count > - rx->local->key_tx_rx_threshold)) { - ieee80211_key_threshold_notify(rx->dev, rx->key, - rx->sta); - } - } - - return TXRX_CONTINUE; -} - - -static ieee80211_txrx_result -ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx) -{ - struct sta_info *sta = rx->sta; - struct net_device *dev = rx->dev; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; - - if (!sta) - return TXRX_CONTINUE; - - /* Update last_rx only for IBSS packets which are for the current - * BSSID to avoid keeping the current IBSS network alive in cases where - * other STAs are using different BSSID. */ - if (rx->sdata->type == IEEE80211_IF_TYPE_IBSS) { - u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len); - if (compare_ether_addr(bssid, rx->sdata->u.sta.bssid) == 0) - sta->last_rx = jiffies; - } else - if (!is_multicast_ether_addr(hdr->addr1) || - rx->sdata->type == IEEE80211_IF_TYPE_STA) { - /* Update last_rx only for unicast frames in order to prevent - * the Probe Request frames (the only broadcast frames from a - * STA in infrastructure mode) from keeping a connection alive. - */ - sta->last_rx = jiffies; - } - - if (!rx->u.rx.ra_match) - return TXRX_CONTINUE; - - sta->rx_fragments++; - sta->rx_bytes += rx->skb->len; - sta->last_rssi = (sta->last_rssi * 15 + - rx->u.rx.status->ssi) / 16; - sta->last_signal = (sta->last_signal * 15 + - rx->u.rx.status->signal) / 16; - sta->last_noise = (sta->last_noise * 15 + - rx->u.rx.status->noise) / 16; - - if (!(rx->fc & IEEE80211_FCTL_MOREFRAGS)) { - /* Change STA power saving mode only in the end of a frame - * exchange sequence */ - if ((sta->flags & WLAN_STA_PS) && !(rx->fc & IEEE80211_FCTL_PM)) - rx->u.rx.sent_ps_buffered += ap_sta_ps_end(dev, sta); - else if (!(sta->flags & WLAN_STA_PS) && - (rx->fc & IEEE80211_FCTL_PM)) - ap_sta_ps_start(dev, sta); - } - - /* Drop data::nullfunc frames silently, since they are used only to - * control station power saving mode. */ - if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && - (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_NULLFUNC) { - I802_DEBUG_INC(rx->local->rx_handlers_drop_nullfunc); - /* Update counter and free packet here to avoid counting this - * as a dropped packed. */ - sta->rx_packets++; - dev_kfree_skb(rx->skb); - return TXRX_QUEUED; - } - - return TXRX_CONTINUE; -} /* ieee80211_rx_h_sta_process */ - - -static ieee80211_txrx_result -ieee80211_rx_h_wep_weak_iv_detection(struct ieee80211_txrx_data *rx) -{ - if (!rx->sta || !(rx->fc & IEEE80211_FCTL_PROTECTED) || - (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || - !rx->key || rx->key->alg != ALG_WEP || !rx->u.rx.ra_match) - return TXRX_CONTINUE; - - /* Check for weak IVs, if hwaccel did not remove IV from the frame */ - if ((rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) || - rx->key->force_sw_encrypt) { - u8 *iv = ieee80211_wep_is_weak_iv(rx->skb, rx->key); - if (iv) { - rx->sta->wep_weak_iv_count++; - } - } - - return TXRX_CONTINUE; -} - - -static ieee80211_txrx_result -ieee80211_rx_h_wep_decrypt(struct ieee80211_txrx_data *rx) -{ - /* If the device handles decryption totally, skip this test */ - if (rx->local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP) - return TXRX_CONTINUE; - - if ((rx->key && rx->key->alg != ALG_WEP) || - !(rx->fc & IEEE80211_FCTL_PROTECTED) || - ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA && - ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || - (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH))) - return TXRX_CONTINUE; - - if (!rx->key) { - printk(KERN_DEBUG "%s: RX WEP frame, but no key set\n", - rx->dev->name); - return TXRX_DROP; - } - - if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED) || - rx->key->force_sw_encrypt) { - if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) { - printk(KERN_DEBUG "%s: RX WEP frame, decrypt " - "failed\n", rx->dev->name); - return TXRX_DROP; - } - } else if (rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) { - ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key); - /* remove ICV */ - skb_trim(rx->skb, rx->skb->len - 4); - } - - return TXRX_CONTINUE; -} - - -static ieee80211_txrx_result -ieee80211_rx_h_802_1x_pae(struct ieee80211_txrx_data *rx) -{ - if (rx->sdata->eapol && ieee80211_is_eapol(rx->skb) && - rx->sdata->type != IEEE80211_IF_TYPE_STA && rx->u.rx.ra_match) { - /* Pass both encrypted and unencrypted EAPOL frames to user - * space for processing. */ - if (!rx->local->apdev) - return TXRX_DROP; - ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status, - ieee80211_msg_normal); - return TXRX_QUEUED; - } - - if (unlikely(rx->sdata->ieee802_1x && - (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && - (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_NULLFUNC && - (!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED)) && - !ieee80211_is_eapol(rx->skb))) { -#ifdef CONFIG_MAC80211_DEBUG - struct ieee80211_hdr *hdr = - (struct ieee80211_hdr *) rx->skb->data; - printk(KERN_DEBUG "%s: dropped frame from " MAC_FMT - " (unauthorized port)\n", rx->dev->name, - MAC_ARG(hdr->addr2)); -#endif /* CONFIG_MAC80211_DEBUG */ - return TXRX_DROP; - } - - return TXRX_CONTINUE; -} - - -static ieee80211_txrx_result -ieee80211_rx_h_drop_unencrypted(struct ieee80211_txrx_data *rx) -{ - /* If the device handles decryption totally, skip this test */ - if (rx->local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP) - return TXRX_CONTINUE; - - /* Drop unencrypted frames if key is set. */ - if (unlikely(!(rx->fc & IEEE80211_FCTL_PROTECTED) && - (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && - (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_NULLFUNC && - (rx->key || rx->sdata->drop_unencrypted) && - (rx->sdata->eapol == 0 || - !ieee80211_is_eapol(rx->skb)))) { - printk(KERN_DEBUG "%s: RX non-WEP frame, but expected " - "encryption\n", rx->dev->name); - return TXRX_DROP; - } - return TXRX_CONTINUE; -} - - -static ieee80211_txrx_result -ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx) -{ - struct ieee80211_sub_if_data *sdata; - - if (!rx->u.rx.ra_match) - return TXRX_DROP; - - sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); - if ((sdata->type == IEEE80211_IF_TYPE_STA || - sdata->type == IEEE80211_IF_TYPE_IBSS) && - !rx->local->user_space_mlme) { - ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status); - } else { - /* Management frames are sent to hostapd for processing */ - if (!rx->local->apdev) - return TXRX_DROP; - ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status, - ieee80211_msg_normal); - } - return TXRX_QUEUED; -} - - -static ieee80211_txrx_result -ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx) -{ - struct ieee80211_local *local = rx->local; - struct sk_buff *skb = rx->skb; - - if (unlikely(local->sta_scanning != 0)) { - ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status); - return TXRX_QUEUED; - } - - if (unlikely(rx->u.rx.in_scan)) { - /* scanning finished during invoking of handlers */ - I802_DEBUG_INC(local->rx_handlers_drop_passive_scan); - return TXRX_DROP; - } - - return TXRX_CONTINUE; -} - - -static void ieee80211_rx_michael_mic_report(struct net_device *dev, - struct ieee80211_hdr *hdr, - struct sta_info *sta, - struct ieee80211_txrx_data *rx) -{ - int keyidx, hdrlen; - - hdrlen = ieee80211_get_hdrlen_from_skb(rx->skb); - if (rx->skb->len >= hdrlen + 4) - keyidx = rx->skb->data[hdrlen + 3] >> 6; - else - keyidx = -1; - - /* TODO: verify that this is not triggered by fragmented - * frames (hw does not verify MIC for them). */ - printk(KERN_DEBUG "%s: TKIP hwaccel reported Michael MIC " - "failure from " MAC_FMT " to " MAC_FMT " keyidx=%d\n", - dev->name, MAC_ARG(hdr->addr2), MAC_ARG(hdr->addr1), keyidx); - - if (!sta) { - /* Some hardware versions seem to generate incorrect - * Michael MIC reports; ignore them to avoid triggering - * countermeasures. */ - printk(KERN_DEBUG "%s: ignored spurious Michael MIC " - "error for unknown address " MAC_FMT "\n", - dev->name, MAC_ARG(hdr->addr2)); - goto ignore; - } - - if (!(rx->fc & IEEE80211_FCTL_PROTECTED)) { - printk(KERN_DEBUG "%s: ignored spurious Michael MIC " - "error for a frame with no ISWEP flag (src " - MAC_FMT ")\n", dev->name, MAC_ARG(hdr->addr2)); - goto ignore; - } - - if ((rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) && - rx->sdata->type == IEEE80211_IF_TYPE_AP) { - keyidx = ieee80211_wep_get_keyidx(rx->skb); - /* AP with Pairwise keys support should never receive Michael - * MIC errors for non-zero keyidx because these are reserved - * for group keys and only the AP is sending real multicast - * frames in BSS. */ - if (keyidx) { - printk(KERN_DEBUG "%s: ignored Michael MIC error for " - "a frame with non-zero keyidx (%d) (src " MAC_FMT - ")\n", dev->name, keyidx, MAC_ARG(hdr->addr2)); - goto ignore; - } - } - - if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA && - ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || - (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH)) { - printk(KERN_DEBUG "%s: ignored spurious Michael MIC " - "error for a frame that cannot be encrypted " - "(fc=0x%04x) (src " MAC_FMT ")\n", - dev->name, rx->fc, MAC_ARG(hdr->addr2)); - goto ignore; - } - - do { - union iwreq_data wrqu; - char *buf = kmalloc(128, GFP_ATOMIC); - if (!buf) - break; - - /* TODO: needed parameters: count, key type, TSC */ - sprintf(buf, "MLME-MICHAELMICFAILURE.indication(" - "keyid=%d %scast addr=" MAC_FMT ")", - keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni", - MAC_ARG(hdr->addr2)); - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = strlen(buf); - wireless_send_event(rx->dev, IWEVCUSTOM, &wrqu, buf); - kfree(buf); - } while (0); - - /* TODO: consider verifying the MIC error report with software - * implementation if we get too many spurious reports from the - * hardware. */ - if (!rx->local->apdev) - goto ignore; - ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status, - ieee80211_msg_michael_mic_failure); - return; - - ignore: - dev_kfree_skb(rx->skb); - rx->skb = NULL; -} - -static inline ieee80211_txrx_result __ieee80211_invoke_rx_handlers( - struct ieee80211_local *local, - ieee80211_rx_handler *handlers, - struct ieee80211_txrx_data *rx, - struct sta_info *sta) -{ - ieee80211_rx_handler *handler; - ieee80211_txrx_result res = TXRX_DROP; - - for (handler = handlers; *handler != NULL; handler++) { - res = (*handler)(rx); - if (res != TXRX_CONTINUE) { - if (res == TXRX_DROP) { - I802_DEBUG_INC(local->rx_handlers_drop); - if (sta) - sta->rx_dropped++; - } - if (res == TXRX_QUEUED) - I802_DEBUG_INC(local->rx_handlers_queued); - break; - } - } - - if (res == TXRX_DROP) { - dev_kfree_skb(rx->skb); - } - return res; -} - -static inline void ieee80211_invoke_rx_handlers(struct ieee80211_local *local, - ieee80211_rx_handler *handlers, - struct ieee80211_txrx_data *rx, - struct sta_info *sta) -{ - if (__ieee80211_invoke_rx_handlers(local, handlers, rx, sta) == - TXRX_CONTINUE) - dev_kfree_skb(rx->skb); -} - -/* - * This is the receive path handler. It is called by a low level driver when an - * 802.11 MPDU is received from the hardware. - */ -void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_rx_status *status) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct ieee80211_sub_if_data *sdata; - struct sta_info *sta; - struct ieee80211_hdr *hdr; - struct ieee80211_txrx_data rx; - u16 type; - int multicast; - int radiotap_len = 0; - - if (status->flag & RX_FLAG_RADIOTAP) { - radiotap_len = ieee80211_get_radiotap_len(skb); - skb_pull(skb, radiotap_len); - } - - hdr = (struct ieee80211_hdr *) skb->data; - memset(&rx, 0, sizeof(rx)); - rx.skb = skb; - rx.local = local; - - rx.u.rx.status = status; - rx.fc = skb->len >= 2 ? le16_to_cpu(hdr->frame_control) : 0; - type = rx.fc & IEEE80211_FCTL_FTYPE; - if (type == IEEE80211_FTYPE_DATA || type == IEEE80211_FTYPE_MGMT) - local->dot11ReceivedFragmentCount++; - multicast = is_multicast_ether_addr(hdr->addr1); - - if (skb->len >= 16) - sta = rx.sta = sta_info_get(local, hdr->addr2); - else - sta = rx.sta = NULL; - - if (sta) { - rx.dev = sta->dev; - rx.sdata = IEEE80211_DEV_TO_SUB_IF(rx.dev); - } - - if ((status->flag & RX_FLAG_MMIC_ERROR)) { - ieee80211_rx_michael_mic_report(local->mdev, hdr, sta, &rx); - goto end; - } - - if (unlikely(local->sta_scanning)) - rx.u.rx.in_scan = 1; - - if (__ieee80211_invoke_rx_handlers(local, local->rx_pre_handlers, &rx, - sta) != TXRX_CONTINUE) - goto end; - skb = rx.skb; - - skb_push(skb, radiotap_len); - if (sta && !sta->assoc_ap && !(sta->flags & WLAN_STA_WDS) && - !local->iff_promiscs && !multicast) { - rx.u.rx.ra_match = 1; - ieee80211_invoke_rx_handlers(local, local->rx_handlers, &rx, - sta); - } else { - struct ieee80211_sub_if_data *prev = NULL; - struct sk_buff *skb_new; - u8 *bssid = ieee80211_get_bssid(hdr, skb->len - radiotap_len); - - read_lock(&local->sub_if_lock); - list_for_each_entry(sdata, &local->sub_if_list, list) { - rx.u.rx.ra_match = 1; - switch (sdata->type) { - case IEEE80211_IF_TYPE_STA: - if (!bssid) - continue; - if (!ieee80211_bssid_match(bssid, - sdata->u.sta.bssid)) { - if (!rx.u.rx.in_scan) - continue; - rx.u.rx.ra_match = 0; - } else if (!multicast && - compare_ether_addr(sdata->dev->dev_addr, - hdr->addr1) != 0) { - if (!sdata->promisc) - continue; - rx.u.rx.ra_match = 0; - } - break; - case IEEE80211_IF_TYPE_IBSS: - if (!bssid) - continue; - if (!ieee80211_bssid_match(bssid, - sdata->u.sta.bssid)) { - if (!rx.u.rx.in_scan) - continue; - rx.u.rx.ra_match = 0; - } else if (!multicast && - compare_ether_addr(sdata->dev->dev_addr, - hdr->addr1) != 0) { - if (!sdata->promisc) - continue; - rx.u.rx.ra_match = 0; - } else if (!sta) - sta = rx.sta = - ieee80211_ibss_add_sta(sdata->dev, - skb, bssid, - hdr->addr2); - break; - case IEEE80211_IF_TYPE_AP: - if (!bssid) { - if (compare_ether_addr(sdata->dev->dev_addr, - hdr->addr1) != 0) - continue; - } else if (!ieee80211_bssid_match(bssid, - sdata->dev->dev_addr)) { - if (!rx.u.rx.in_scan) - continue; - rx.u.rx.ra_match = 0; - } - if (sdata->dev == local->mdev && - !rx.u.rx.in_scan) - /* do not receive anything via - * master device when not scanning */ - continue; - break; - case IEEE80211_IF_TYPE_WDS: - if (bssid || - (rx.fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) - continue; - if (compare_ether_addr(sdata->u.wds.remote_addr, - hdr->addr2) != 0) - continue; - break; - } - - if (prev) { - skb_new = skb_copy(skb, GFP_ATOMIC); - if (!skb_new) { - if (net_ratelimit()) - printk(KERN_DEBUG "%s: failed to copy " - "multicast frame for %s", - local->mdev->name, prev->dev->name); - continue; - } - rx.skb = skb_new; - rx.dev = prev->dev; - rx.sdata = prev; - ieee80211_invoke_rx_handlers(local, - local->rx_handlers, - &rx, sta); - } - prev = sdata; - } - if (prev) { - rx.skb = skb; - rx.dev = prev->dev; - rx.sdata = prev; - ieee80211_invoke_rx_handlers(local, local->rx_handlers, - &rx, sta); - } else - dev_kfree_skb(skb); - read_unlock(&local->sub_if_lock); - } - - end: - if (sta) - sta_info_put(sta); -} -EXPORT_SYMBOL(__ieee80211_rx); - -static ieee80211_txrx_result -ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx) -{ - struct ieee80211_local *local = tx->local; - struct ieee80211_hw_mode *mode = tx->u.tx.mode; - struct sk_buff *skb = tx->skb; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - u32 load = 0, hdrtime; - - /* TODO: this could be part of tx_status handling, so that the number - * of retries would be known; TX rate should in that case be stored - * somewhere with the packet */ - - /* Estimate total channel use caused by this frame */ - - /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values, - * 1 usec = 1/8 * (1080 / 10) = 13.5 */ - - if (mode->mode == MODE_IEEE80211A || - mode->mode == MODE_ATHEROS_TURBO || - mode->mode == MODE_ATHEROS_TURBOG || - (mode->mode == MODE_IEEE80211G && - tx->u.tx.rate->flags & IEEE80211_RATE_ERP)) - hdrtime = CHAN_UTIL_HDR_SHORT; - else - hdrtime = CHAN_UTIL_HDR_LONG; - - load = hdrtime; - if (!is_multicast_ether_addr(hdr->addr1)) - load += hdrtime; - - if (tx->u.tx.control->flags & IEEE80211_TXCTL_USE_RTS_CTS) - load += 2 * hdrtime; - else if (tx->u.tx.control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) - load += hdrtime; - - load += skb->len * tx->u.tx.rate->rate_inv; - - if (tx->u.tx.extra_frag) { - int i; - for (i = 0; i < tx->u.tx.num_extra_frag; i++) { - load += 2 * hdrtime; - load += tx->u.tx.extra_frag[i]->len * - tx->u.tx.rate->rate; - } - } - - /* Divide channel_use by 8 to avoid wrapping around the counter */ - load >>= CHAN_UTIL_SHIFT; - local->channel_use_raw += load; - if (tx->sta) - tx->sta->channel_use_raw += load; - tx->sdata->channel_use_raw += load; - - return TXRX_CONTINUE; -} - - -static ieee80211_txrx_result -ieee80211_rx_h_load_stats(struct ieee80211_txrx_data *rx) -{ - struct ieee80211_local *local = rx->local; - struct sk_buff *skb = rx->skb; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - u32 load = 0, hdrtime; - struct ieee80211_rate *rate; - struct ieee80211_hw_mode *mode = local->hw.conf.mode; - int i; - - /* Estimate total channel use caused by this frame */ - - if (unlikely(mode->num_rates < 0)) - return TXRX_CONTINUE; - - rate = &mode->rates[0]; - for (i = 0; i < mode->num_rates; i++) { - if (mode->rates[i].val == rx->u.rx.status->rate) { - rate = &mode->rates[i]; - break; - } - } - - /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values, - * 1 usec = 1/8 * (1080 / 10) = 13.5 */ - - if (mode->mode == MODE_IEEE80211A || - mode->mode == MODE_ATHEROS_TURBO || - mode->mode == MODE_ATHEROS_TURBOG || - (mode->mode == MODE_IEEE80211G && - rate->flags & IEEE80211_RATE_ERP)) - hdrtime = CHAN_UTIL_HDR_SHORT; - else - hdrtime = CHAN_UTIL_HDR_LONG; - - load = hdrtime; - if (!is_multicast_ether_addr(hdr->addr1)) - load += hdrtime; - - load += skb->len * rate->rate_inv; - - /* Divide channel_use by 8 to avoid wrapping around the counter */ - load >>= CHAN_UTIL_SHIFT; - local->channel_use_raw += load; - if (rx->sta) - rx->sta->channel_use_raw += load; - rx->u.rx.load = load; - - return TXRX_CONTINUE; -} - -static ieee80211_txrx_result -ieee80211_rx_h_if_stats(struct ieee80211_txrx_data *rx) -{ - rx->sdata->channel_use_raw += rx->u.rx.load; - return TXRX_CONTINUE; -} - -static void ieee80211_stat_refresh(unsigned long data) -{ - struct ieee80211_local *local = (struct ieee80211_local *) data; - struct sta_info *sta; - struct ieee80211_sub_if_data *sdata; - - if (!local->stat_time) - return; - - /* go through all stations */ - spin_lock_bh(&local->sta_lock); - list_for_each_entry(sta, &local->sta_list, list) { - sta->channel_use = (sta->channel_use_raw / local->stat_time) / - CHAN_UTIL_PER_10MS; - sta->channel_use_raw = 0; - } - spin_unlock_bh(&local->sta_lock); - - /* go through all subinterfaces */ - read_lock(&local->sub_if_lock); - list_for_each_entry(sdata, &local->sub_if_list, list) { - sdata->channel_use = (sdata->channel_use_raw / - local->stat_time) / CHAN_UTIL_PER_10MS; - sdata->channel_use_raw = 0; - } - read_unlock(&local->sub_if_lock); - - /* hardware interface */ - local->channel_use = (local->channel_use_raw / - local->stat_time) / CHAN_UTIL_PER_10MS; - local->channel_use_raw = 0; - - local->stat_timer.expires = jiffies + HZ * local->stat_time / 100; - add_timer(&local->stat_timer); + sdata->flags &= ~(IEEE80211_SDATA_USE_PROTECTION | + IEEE80211_SDATA_SHORT_PREAMBLE); + ieee80211_erp_info_change_notify(dev, + IEEE80211_ERP_CHANGE_PROTECTION | + IEEE80211_ERP_CHANGE_PREAMBLE); } - -/* This is a version of the rx handler that can be called from hard irq - * context. Post the skb on the queue and schedule the tasklet */ -void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_rx_status *status) -{ - struct ieee80211_local *local = hw_to_local(hw); - - BUILD_BUG_ON(sizeof(struct ieee80211_rx_status) > sizeof(skb->cb)); - - skb->dev = local->mdev; - /* copy status into skb->cb for use by tasklet */ - memcpy(skb->cb, status, sizeof(*status)); - skb->pkt_type = IEEE80211_RX_MSG; - skb_queue_tail(&local->skb_queue, skb); - tasklet_schedule(&local->tasklet); -} -EXPORT_SYMBOL(ieee80211_rx_irqsafe); - void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_status *status) @@ -4398,14 +624,13 @@ static void ieee80211_tasklet_handler(unsigned long data) break; default: /* should never get here! */ printk(KERN_ERR "%s: Unknown message type (%d)\n", - local->mdev->name, skb->pkt_type); + wiphy_name(local->hw.wiphy), skb->pkt_type); dev_kfree_skb(skb); break; } } } - /* Remove added headers (e.g., QoS control), encryption header/MIC, etc. to * make a prepared TX frame (one that has been given to hw) to look like brand * new IEEE 802.11 frame that is ready to go through TX processing again. @@ -4420,10 +645,13 @@ static void ieee80211_remove_tx_extra(struct ieee80211_local *local, pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; pkt_data->ifindex = control->ifindex; - pkt_data->mgmt_iface = (control->type == IEEE80211_IF_TYPE_MGMT); - pkt_data->req_tx_status = !!(control->flags & IEEE80211_TXCTL_REQ_TX_STATUS); - pkt_data->do_not_encrypt = !!(control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT); - pkt_data->requeue = !!(control->flags & IEEE80211_TXCTL_REQUEUE); + pkt_data->flags = 0; + if (control->flags & IEEE80211_TXCTL_REQ_TX_STATUS) + pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS; + if (control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT) + pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT; + if (control->flags & IEEE80211_TXCTL_REQUEUE) + pkt_data->flags |= IEEE80211_TXPD_REQUEUE; pkt_data->queue = control->queue; hdrlen = ieee80211_get_hdrlen_from_skb(skb); @@ -4431,7 +659,7 @@ static void ieee80211_remove_tx_extra(struct ieee80211_local *local, if (!key) goto no_key; - switch (key->alg) { + switch (key->conf.alg) { case ALG_WEP: iv_len = WEP_IV_LEN; mic_len = WEP_ICV_LEN; @@ -4448,7 +676,8 @@ static void ieee80211_remove_tx_extra(struct ieee80211_local *local, goto no_key; } - if (skb->len >= mic_len && key->force_sw_encrypt) + if (skb->len >= mic_len && + !(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) skb_trim(skb, skb->len - mic_len); if (skb->len >= iv_len && skb->len > hdrlen) { memmove(skb->data + iv_len, skb->data, hdrlen); @@ -4468,7 +697,6 @@ no_key: } } - void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_status *status) { @@ -4476,7 +704,6 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_local *local = hw_to_local(hw); u16 frag, type; - u32 msg_type; struct ieee80211_tx_status_rtap_hdr *rthdr; struct ieee80211_sub_if_data *sdata; int monitors; @@ -4484,7 +711,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, if (!status) { printk(KERN_ERR "%s: ieee80211_tx_status called with NULL status\n", - local->mdev->name); + wiphy_name(local->hw.wiphy)); dev_kfree_skb(skb); return; } @@ -4541,7 +768,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, printk(KERN_DEBUG "%s: dropped TX " "filtered frame queue_len=%d " "PS=%d @%lu\n", - local->mdev->name, + wiphy_name(local->hw.wiphy), skb_queue_len( &sta->tx_filtered), !!(sta->flags & WLAN_STA_PS), @@ -4591,29 +818,9 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, local->dot11FailedCount++; } - msg_type = (status->flags & IEEE80211_TX_STATUS_ACK) ? - ieee80211_msg_tx_callback_ack : ieee80211_msg_tx_callback_fail; - /* this was a transmitted frame, but now we want to reuse it */ skb_orphan(skb); - if ((status->control.flags & IEEE80211_TXCTL_REQ_TX_STATUS) && - local->apdev) { - if (local->monitors) { - skb2 = skb_clone(skb, GFP_ATOMIC); - } else { - skb2 = skb; - skb = NULL; - } - - if (skb2) - /* Send frame to hostapd */ - ieee80211_rx_mgmt(local, skb2, NULL, msg_type); - - if (!skb) - return; - } - if (!local->monitors) { dev_kfree_skb(skb); return; @@ -4648,9 +855,9 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, rthdr->data_retries = status->retry_count; - read_lock(&local->sub_if_lock); + rcu_read_lock(); monitors = local->monitors; - list_for_each_entry(sdata, &local->sub_if_list, list) { + list_for_each_entry_rcu(sdata, &local->interfaces, list) { /* * Using the monitors counter is possibly racy, but * if the value is wrong we simply either clone the skb @@ -4666,7 +873,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, continue; monitors--; if (monitors) - skb2 = skb_clone(skb, GFP_KERNEL); + skb2 = skb_clone(skb, GFP_ATOMIC); else skb2 = NULL; skb->dev = sdata->dev; @@ -4681,170 +888,12 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, } } out: - read_unlock(&local->sub_if_lock); + rcu_read_unlock(); if (skb) dev_kfree_skb(skb); } EXPORT_SYMBOL(ieee80211_tx_status); -/* TODO: implement register/unregister functions for adding TX/RX handlers - * into ordered list */ - -/* rx_pre handlers don't have dev and sdata fields available in - * ieee80211_txrx_data */ -static ieee80211_rx_handler ieee80211_rx_pre_handlers[] = -{ - ieee80211_rx_h_parse_qos, - ieee80211_rx_h_load_stats, - NULL -}; - -static ieee80211_rx_handler ieee80211_rx_handlers[] = -{ - ieee80211_rx_h_if_stats, - ieee80211_rx_h_monitor, - ieee80211_rx_h_passive_scan, - ieee80211_rx_h_check, - ieee80211_rx_h_sta_process, - ieee80211_rx_h_ccmp_decrypt, - ieee80211_rx_h_tkip_decrypt, - ieee80211_rx_h_wep_weak_iv_detection, - ieee80211_rx_h_wep_decrypt, - ieee80211_rx_h_defragment, - ieee80211_rx_h_ps_poll, - ieee80211_rx_h_michael_mic_verify, - /* this must be after decryption - so header is counted in MPDU mic - * must be before pae and data, so QOS_DATA format frames - * are not passed to user space by these functions - */ - ieee80211_rx_h_remove_qos_control, - ieee80211_rx_h_802_1x_pae, - ieee80211_rx_h_drop_unencrypted, - ieee80211_rx_h_data, - ieee80211_rx_h_mgmt, - NULL -}; - -static ieee80211_tx_handler ieee80211_tx_handlers[] = -{ - ieee80211_tx_h_check_assoc, - ieee80211_tx_h_sequence, - ieee80211_tx_h_ps_buf, - ieee80211_tx_h_select_key, - ieee80211_tx_h_michael_mic_add, - ieee80211_tx_h_fragment, - ieee80211_tx_h_tkip_encrypt, - ieee80211_tx_h_ccmp_encrypt, - ieee80211_tx_h_wep_encrypt, - ieee80211_tx_h_rate_ctrl, - ieee80211_tx_h_misc, - ieee80211_tx_h_load_stats, - NULL -}; - - -int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct sta_info *sta; - - if (compare_ether_addr(remote_addr, sdata->u.wds.remote_addr) == 0) - return 0; - - /* Create STA entry for the new peer */ - sta = sta_info_add(local, dev, remote_addr, GFP_KERNEL); - if (!sta) - return -ENOMEM; - sta_info_put(sta); - - /* Remove STA entry for the old peer */ - sta = sta_info_get(local, sdata->u.wds.remote_addr); - if (sta) { - sta_info_put(sta); - sta_info_free(sta, 0); - } else { - printk(KERN_DEBUG "%s: could not find STA entry for WDS link " - "peer " MAC_FMT "\n", - dev->name, MAC_ARG(sdata->u.wds.remote_addr)); - } - - /* Update WDS link data */ - memcpy(&sdata->u.wds.remote_addr, remote_addr, ETH_ALEN); - - return 0; -} - -/* Must not be called for mdev and apdev */ -void ieee80211_if_setup(struct net_device *dev) -{ - ether_setup(dev); - dev->hard_start_xmit = ieee80211_subif_start_xmit; - dev->wireless_handlers = &ieee80211_iw_handler_def; - dev->set_multicast_list = ieee80211_set_multicast_list; - dev->change_mtu = ieee80211_change_mtu; - dev->get_stats = ieee80211_get_stats; - dev->open = ieee80211_open; - dev->stop = ieee80211_stop; - dev->uninit = ieee80211_if_reinit; - dev->destructor = ieee80211_if_free; -} - -void ieee80211_if_mgmt_setup(struct net_device *dev) -{ - ether_setup(dev); - dev->hard_start_xmit = ieee80211_mgmt_start_xmit; - dev->change_mtu = ieee80211_change_mtu_apdev; - dev->get_stats = ieee80211_get_stats; - dev->open = ieee80211_mgmt_open; - dev->stop = ieee80211_mgmt_stop; - dev->type = ARPHRD_IEEE80211_PRISM; - dev->hard_header_parse = header_parse_80211; - dev->uninit = ieee80211_if_reinit; - dev->destructor = ieee80211_if_free; -} - -int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, - const char *name) -{ - struct rate_control_ref *ref, *old; - - ASSERT_RTNL(); - if (local->open_count || netif_running(local->mdev) || - (local->apdev && netif_running(local->apdev))) - return -EBUSY; - - ref = rate_control_alloc(name, local); - if (!ref) { - printk(KERN_WARNING "%s: Failed to select rate control " - "algorithm\n", local->mdev->name); - return -ENOENT; - } - - old = local->rate_ctrl; - local->rate_ctrl = ref; - if (old) { - rate_control_put(old); - sta_info_flush(local, NULL); - } - - printk(KERN_DEBUG "%s: Selected rate control " - "algorithm '%s'\n", local->mdev->name, - ref->ops->name); - - - return 0; -} - -static void rate_control_deinitialize(struct ieee80211_local *local) -{ - struct rate_control_ref *ref; - - ref = local->rate_ctrl; - local->rate_ctrl = NULL; - rate_control_put(ref); -} - struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, const struct ieee80211_ops *ops) { @@ -4888,8 +937,12 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); BUG_ON(!ops->tx); + BUG_ON(!ops->start); + BUG_ON(!ops->stop); BUG_ON(!ops->config); BUG_ON(!ops->add_interface); + BUG_ON(!ops->remove_interface); + BUG_ON(!ops->configure_filter); local->ops = ops; /* for now, mdev needs sub_if_data :/ */ @@ -4919,17 +972,13 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, local->long_retry_limit = 4; local->hw.conf.radio_enabled = 1; - local->enabled_modes = (unsigned int) -1; + local->enabled_modes = ~0; INIT_LIST_HEAD(&local->modes_list); - rwlock_init(&local->sub_if_lock); - INIT_LIST_HEAD(&local->sub_if_list); + INIT_LIST_HEAD(&local->interfaces); INIT_DELAYED_WORK(&local->scan_work, ieee80211_sta_scan_work); - init_timer(&local->stat_timer); - local->stat_timer.function = ieee80211_stat_refresh; - local->stat_timer.data = (unsigned long) local; ieee80211_rx_bss_list_init(mdev); sta_info_init(local); @@ -4938,7 +987,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, mdev->open = ieee80211_master_open; mdev->stop = ieee80211_master_stop; mdev->type = ARPHRD_IEEE80211; - mdev->hard_header_parse = header_parse_80211; + mdev->header_ops = &ieee80211_header_ops; + mdev->set_multicast_list = ieee80211_master_set_multicast_list; sdata->type = IEEE80211_IF_TYPE_AP; sdata->dev = mdev; @@ -4946,7 +996,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, sdata->u.ap.force_unicast_rateidx = -1; sdata->u.ap.max_ratectrl_rateidx = -1; ieee80211_if_sdata_init(sdata); - list_add_tail(&sdata->list, &local->sub_if_list); + /* no RCU needed since we're still during init phase */ + list_add_tail(&sdata->list, &local->interfaces); tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, (unsigned long)local); @@ -5019,11 +1070,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) goto fail_dev; ieee80211_debugfs_add_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev)); + ieee80211_if_set_type(local->mdev, IEEE80211_IF_TYPE_AP); result = ieee80211_init_rate_ctrl_alg(local, NULL); if (result < 0) { printk(KERN_DEBUG "%s: Failed to initialize rate control " - "algorithm\n", local->mdev->name); + "algorithm\n", wiphy_name(local->hw.wiphy)); goto fail_rate; } @@ -5031,7 +1083,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (result < 0) { printk(KERN_DEBUG "%s: Failed to initialize wep\n", - local->mdev->name); + wiphy_name(local->hw.wiphy)); goto fail_wep; } @@ -5042,7 +1094,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) IEEE80211_IF_TYPE_STA); if (result) printk(KERN_WARNING "%s: Failed to add default virtual iface\n", - local->mdev->name); + wiphy_name(local->hw.wiphy)); local->reg_state = IEEE80211_DEV_REGISTERED; rtnl_unlock(); @@ -5105,7 +1157,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata, *tmp; - struct list_head tmp_list; int i; tasklet_kill(&local->tx_pending_tasklet); @@ -5116,20 +1167,30 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) BUG_ON(local->reg_state != IEEE80211_DEV_REGISTERED); local->reg_state = IEEE80211_DEV_UNREGISTERED; - if (local->apdev) - ieee80211_if_del_mgmt(local); - write_lock_bh(&local->sub_if_lock); - list_replace_init(&local->sub_if_list, &tmp_list); - write_unlock_bh(&local->sub_if_lock); + /* + * At this point, interface list manipulations are fine + * because the driver cannot be handing us frames any + * more and the tasklet is killed. + */ - list_for_each_entry_safe(sdata, tmp, &tmp_list, list) + /* + * First, we remove all non-master interfaces. Do this because they + * may have bss pointer dependency on the master, and when we free + * the master these would be freed as well, breaking our list + * iteration completely. + */ + list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) { + if (sdata->dev == local->mdev) + continue; + list_del(&sdata->list); __ieee80211_if_del(local, sdata); + } - rtnl_unlock(); + /* then, finally, remove the master interface */ + __ieee80211_if_del(local, IEEE80211_DEV_TO_SUB_IF(local->mdev)); - if (local->stat_time) - del_timer_sync(&local->stat_timer); + rtnl_unlock(); ieee80211_rx_bss_list_deinit(local->mdev); ieee80211_clear_tx_pending(local); @@ -5145,7 +1206,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) if (skb_queue_len(&local->skb_queue) || skb_queue_len(&local->skb_queue_unreliable)) printk(KERN_WARNING "%s: skb_queue not empty\n", - local->mdev->name); + wiphy_name(local->hw.wiphy)); skb_queue_purge(&local->skb_queue); skb_queue_purge(&local->skb_queue_unreliable); @@ -5165,72 +1226,6 @@ void ieee80211_free_hw(struct ieee80211_hw *hw) } EXPORT_SYMBOL(ieee80211_free_hw); -void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) -{ - struct ieee80211_local *local = hw_to_local(hw); - - if (test_and_clear_bit(IEEE80211_LINK_STATE_XOFF, - &local->state[queue])) { - if (test_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[queue])) - tasklet_schedule(&local->tx_pending_tasklet); - else - if (!ieee80211_qdisc_installed(local->mdev)) { - if (queue == 0) - netif_wake_queue(local->mdev); - } else - __netif_schedule(local->mdev); - } -} -EXPORT_SYMBOL(ieee80211_wake_queue); - -void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) -{ - struct ieee80211_local *local = hw_to_local(hw); - - if (!ieee80211_qdisc_installed(local->mdev) && queue == 0) - netif_stop_queue(local->mdev); - set_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]); -} -EXPORT_SYMBOL(ieee80211_stop_queue); - -void ieee80211_start_queues(struct ieee80211_hw *hw) -{ - struct ieee80211_local *local = hw_to_local(hw); - int i; - - for (i = 0; i < local->hw.queues; i++) - clear_bit(IEEE80211_LINK_STATE_XOFF, &local->state[i]); - if (!ieee80211_qdisc_installed(local->mdev)) - netif_start_queue(local->mdev); -} -EXPORT_SYMBOL(ieee80211_start_queues); - -void ieee80211_stop_queues(struct ieee80211_hw *hw) -{ - int i; - - for (i = 0; i < hw->queues; i++) - ieee80211_stop_queue(hw, i); -} -EXPORT_SYMBOL(ieee80211_stop_queues); - -void ieee80211_wake_queues(struct ieee80211_hw *hw) -{ - int i; - - for (i = 0; i < hw->queues; i++) - ieee80211_wake_queue(hw, i); -} -EXPORT_SYMBOL(ieee80211_wake_queues); - -struct net_device_stats *ieee80211_dev_stats(struct net_device *dev) -{ - struct ieee80211_sub_if_data *sdata; - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - return &sdata->stats; -} - static int __init ieee80211_init(void) { struct sk_buff *skb; @@ -5251,7 +1246,6 @@ static int __init ieee80211_init(void) return 0; } - static void __exit ieee80211_exit(void) { ieee80211_wme_unregister(); diff --git a/net/mac80211/ieee80211_cfg.c b/net/mac80211/ieee80211_cfg.c deleted file mode 100644 index 509096e..0000000 --- a/net/mac80211/ieee80211_cfg.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * mac80211 configuration hooks for cfg80211 - * - * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> - * - * This file is GPLv2 as found in COPYING. - */ - -#include <linux/nl80211.h> -#include <linux/rtnetlink.h> -#include <net/cfg80211.h> -#include "ieee80211_i.h" -#include "ieee80211_cfg.h" - -static int ieee80211_add_iface(struct wiphy *wiphy, char *name, - unsigned int type) -{ - struct ieee80211_local *local = wiphy_priv(wiphy); - int itype; - - if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED)) - return -ENODEV; - - switch (type) { - case NL80211_IFTYPE_UNSPECIFIED: - itype = IEEE80211_IF_TYPE_STA; - break; - case NL80211_IFTYPE_ADHOC: - itype = IEEE80211_IF_TYPE_IBSS; - break; - case NL80211_IFTYPE_STATION: - itype = IEEE80211_IF_TYPE_STA; - break; - case NL80211_IFTYPE_MONITOR: - itype = IEEE80211_IF_TYPE_MNTR; - break; - default: - return -EINVAL; - } - - return ieee80211_if_add(local->mdev, name, NULL, itype); -} - -static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex) -{ - struct ieee80211_local *local = wiphy_priv(wiphy); - struct net_device *dev; - char *name; - - if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED)) - return -ENODEV; - - dev = dev_get_by_index(ifindex); - if (!dev) - return 0; - - name = dev->name; - dev_put(dev); - - return ieee80211_if_remove(local->mdev, name, -1); -} - -struct cfg80211_ops mac80211_config_ops = { - .add_virtual_intf = ieee80211_add_iface, - .del_virtual_intf = ieee80211_del_iface, -}; diff --git a/net/mac80211/ieee80211_common.h b/net/mac80211/ieee80211_common.h index 77c6afb..c15295d 100644 --- a/net/mac80211/ieee80211_common.h +++ b/net/mac80211/ieee80211_common.h @@ -48,13 +48,13 @@ enum ieee80211_msg_type { ieee80211_msg_tx_callback_ack = 1, ieee80211_msg_tx_callback_fail = 2, /* hole at 3, was ieee80211_msg_passive_scan but unused */ - ieee80211_msg_wep_frame_unknown_key = 4, + /* hole at 4, was ieee80211_msg_wep_frame_unknown_key but now unused */ ieee80211_msg_michael_mic_failure = 5, /* hole at 6, was monitor but never sent to userspace */ ieee80211_msg_sta_not_assoc = 7, /* 8 was ieee80211_msg_set_aid_for_sta */ - ieee80211_msg_key_threshold_notification = 9, - ieee80211_msg_radar = 11, + /* 9 was ieee80211_msg_key_threshold_notification */ + /* 11 was ieee80211_msg_radar */ }; struct ieee80211_msg_key_notification { @@ -73,8 +73,6 @@ enum ieee80211_phytype { ieee80211_phytype_ofdm_dot11_g = 6, ieee80211_phytype_pbcc_dot11_g = 7, ieee80211_phytype_ofdm_dot11_a = 8, - ieee80211_phytype_dsss_dot11_turbog = 255, - ieee80211_phytype_dsss_dot11_turbo = 256, }; enum ieee80211_ssi_type { diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 6f7bae7..d34a9de 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -21,6 +21,7 @@ #include <linux/workqueue.h> #include <linux/types.h> #include <linux/spinlock.h> +#include <linux/etherdevice.h> #include <net/wireless.h> #include "ieee80211_key.h" #include "sta_info.h" @@ -112,6 +113,16 @@ typedef enum { TXRX_CONTINUE, TXRX_DROP, TXRX_QUEUED } ieee80211_txrx_result; +/* flags used in struct ieee80211_txrx_data.flags */ +/* whether the MSDU was fragmented */ +#define IEEE80211_TXRXD_FRAGMENTED BIT(0) +#define IEEE80211_TXRXD_TXUNICAST BIT(1) +#define IEEE80211_TXRXD_TXPS_BUFFERED BIT(2) +#define IEEE80211_TXRXD_TXPROBE_LAST_FRAG BIT(3) +#define IEEE80211_TXRXD_RXIN_SCAN BIT(4) +/* frame is destined to interface currently processed (incl. multicast frames) */ +#define IEEE80211_TXRXD_RXRA_MATCH BIT(5) +#define IEEE80211_TXRXD_TX_INJECTED BIT(6) struct ieee80211_txrx_data { struct sk_buff *skb; struct net_device *dev; @@ -120,14 +131,10 @@ struct ieee80211_txrx_data { struct sta_info *sta; u16 fc, ethertype; struct ieee80211_key *key; - unsigned int fragmented:1; /* whether the MSDU was fragmented */ + unsigned int flags; union { struct { struct ieee80211_tx_control *control; - unsigned int unicast:1; - unsigned int ps_buffered:1; - unsigned int short_preamble:1; - unsigned int probe_last_frag:1; struct ieee80211_hw_mode *mode; struct ieee80211_rate *rate; /* use this rate (if set) for last fragment; rate can @@ -135,7 +142,6 @@ struct ieee80211_txrx_data { * when using CTS protection with IEEE 802.11g. */ struct ieee80211_rate *last_frag_rate; int last_frag_hwrate; - int mgmt_interface; /* Extra fragments (in addition to the first fragment * in skb) */ @@ -147,23 +153,22 @@ struct ieee80211_txrx_data { int sent_ps_buffered; int queue; int load; - unsigned int in_scan:1; - /* frame is destined to interface currently processed - * (including multicast frames) */ - unsigned int ra_match:1; + u32 tkip_iv32; + u16 tkip_iv16; } rx; } u; }; +/* flags used in struct ieee80211_tx_packet_data.flags */ +#define IEEE80211_TXPD_REQ_TX_STATUS BIT(0) +#define IEEE80211_TXPD_DO_NOT_ENCRYPT BIT(1) +#define IEEE80211_TXPD_REQUEUE BIT(2) /* Stored in sk_buff->cb */ struct ieee80211_tx_packet_data { int ifindex; unsigned long jiffies; - unsigned int req_tx_status:1; - unsigned int do_not_encrypt:1; - unsigned int requeue:1; - unsigned int mgmt_iface:1; - unsigned int queue:4; + unsigned int flags; + u8 queue; }; struct ieee80211_tx_stored_packet { @@ -174,7 +179,7 @@ struct ieee80211_tx_stored_packet { int last_frag_rateidx; int last_frag_hwrate; struct ieee80211_rate *last_frag_rate; - unsigned int last_frag_rate_ctrl_probe:1; + unsigned int last_frag_rate_ctrl_probe; }; typedef ieee80211_txrx_result (*ieee80211_tx_handler) @@ -187,10 +192,10 @@ struct ieee80211_if_ap { u8 *beacon_head, *beacon_tail; int beacon_head_len, beacon_tail_len; + struct list_head vlans; + u8 ssid[IEEE80211_MAX_SSID_LEN]; size_t ssid_len; - u8 *generic_elem; - size_t generic_elem_len; /* yes, this looks ugly, but guarantees that we can later use * bitmap_empty :) @@ -210,9 +215,23 @@ struct ieee80211_if_wds { }; struct ieee80211_if_vlan { - u8 id; + struct ieee80211_sub_if_data *ap; + struct list_head list; }; +/* flags used in struct ieee80211_if_sta.flags */ +#define IEEE80211_STA_SSID_SET BIT(0) +#define IEEE80211_STA_BSSID_SET BIT(1) +#define IEEE80211_STA_PREV_BSSID_SET BIT(2) +#define IEEE80211_STA_AUTHENTICATED BIT(3) +#define IEEE80211_STA_ASSOCIATED BIT(4) +#define IEEE80211_STA_PROBEREQ_POLL BIT(5) +#define IEEE80211_STA_CREATE_IBSS BIT(6) +#define IEEE80211_STA_MIXED_CELL BIT(7) +#define IEEE80211_STA_WMM_ENABLED BIT(8) +#define IEEE80211_STA_AUTO_SSID_SEL BIT(10) +#define IEEE80211_STA_AUTO_BSSID_SEL BIT(11) +#define IEEE80211_STA_AUTO_CHANNEL_SEL BIT(12) struct ieee80211_if_sta { enum { IEEE80211_DISABLED, IEEE80211_AUTHENTICATE, @@ -235,25 +254,14 @@ struct ieee80211_if_sta { int auth_tries, assoc_tries; - unsigned int ssid_set:1; - unsigned int bssid_set:1; - unsigned int prev_bssid_set:1; - unsigned int authenticated:1; - unsigned int associated:1; - unsigned int probereq_poll:1; - unsigned int create_ibss:1; - unsigned int mixed_cell:1; - unsigned int wmm_enabled:1; - unsigned int auto_ssid_sel:1; - unsigned int auto_bssid_sel:1; - unsigned int auto_channel_sel:1; + unsigned int flags; #define IEEE80211_STA_REQ_SCAN 0 #define IEEE80211_STA_REQ_AUTH 1 #define IEEE80211_STA_REQ_RUN 2 unsigned long request; struct sk_buff_head skb_queue; - int key_mgmt; + int key_management_enabled; unsigned long last_probe; #define IEEE80211_AUTH_ALG_OPEN BIT(0) @@ -271,21 +279,29 @@ struct ieee80211_if_sta { }; +/* flags used in struct ieee80211_sub_if_data.flags */ +#define IEEE80211_SDATA_ALLMULTI BIT(0) +#define IEEE80211_SDATA_PROMISC BIT(1) +#define IEEE80211_SDATA_USE_PROTECTION BIT(2) /* CTS protect ERP frames */ +/* use short preamble with IEEE 802.11b: this flag is set when the AP or beacon + * generator reports that there are no present stations that cannot support short + * preambles */ +#define IEEE80211_SDATA_SHORT_PREAMBLE BIT(3) +#define IEEE80211_SDATA_USERSPACE_MLME BIT(4) struct ieee80211_sub_if_data { struct list_head list; - unsigned int type; + enum ieee80211_if_types type; struct wireless_dev wdev; + /* keys */ + struct list_head key_list; + struct net_device *dev; struct ieee80211_local *local; - int mc_count; - unsigned int allmulti:1; - unsigned int promisc:1; - unsigned int use_protection:1; /* CTS protect ERP frames */ + unsigned int flags; - struct net_device_stats stats; int drop_unencrypted; int eapol; /* 0 = process EAPOL frames as normal data frames, * 1 = send EAPOL frames through wlan#ap to hostapd @@ -364,7 +380,6 @@ struct ieee80211_sub_if_data { struct dentry *drop_unencrypted; struct dentry *eapol; struct dentry *ieee8021_x; - struct dentry *vlan_id; } vlan; struct { struct dentry *mode; @@ -393,9 +408,9 @@ struct ieee80211_local { struct list_head modes_list; struct net_device *mdev; /* wmaster# - "master" 802.11 device */ - struct net_device *apdev; /* wlan#ap - management frames (hostapd) */ int open_count; int monitors; + unsigned int filter_flags; /* FIF_* */ struct iw_statistics wstats; u8 wstats_flags; int tx_headroom; /* required headroom for hardware/radiotap */ @@ -416,10 +431,9 @@ struct ieee80211_local { struct sk_buff_head skb_queue_unreliable; /* Station data structures */ - spinlock_t sta_lock; /* mutex for STA data structures */ + rwlock_t sta_lock; /* protects STA data structures */ int num_sta; /* number of stations in sta_list */ struct list_head sta_list; - struct list_head deleted_sta_list; struct sta_info *sta_hash[STA_HASH_SIZE]; struct timer_list sta_cleanup; @@ -427,17 +441,11 @@ struct ieee80211_local { struct ieee80211_tx_stored_packet pending_packet[NUM_TX_DATA_QUEUES]; struct tasklet_struct tx_pending_tasklet; - int mc_count; /* total count of multicast entries in all interfaces */ - int iff_allmultis, iff_promiscs; - /* number of interfaces with corresponding IFF_ flags */ + /* number of interfaces with corresponding IFF_ flags */ + atomic_t iff_allmultis, iff_promiscs; struct rate_control_ref *rate_ctrl; - int next_mode; /* MODE_IEEE80211* - * The mode preference for next channel change. This is - * used to select .11g vs. .11b channels (or 4.9 GHz vs. - * .11a) when the channel number is not unique. */ - /* Supported and basic rate filters for different modes. These are * pointers to -1 terminated lists and rates in 100 kbps units. */ int *supp_rates[NUM_IEEE80211_MODES]; @@ -447,14 +455,10 @@ struct ieee80211_local { int fragmentation_threshold; int short_retry_limit; /* dot11ShortRetryLimit */ int long_retry_limit; /* dot11LongRetryLimit */ - int short_preamble; /* use short preamble with IEEE 802.11b */ struct crypto_blkcipher *wep_tx_tfm; struct crypto_blkcipher *wep_rx_tfm; u32 wep_iv; - int key_tx_rx_threshold; /* number of times any key can be used in TX - * or RX before generating a rekey - * notification; 0 = notification disabled. */ int bridge_packets; /* bridge packets between associated stations and * deliver multicast frames both back to wireless @@ -464,9 +468,8 @@ struct ieee80211_local { ieee80211_rx_handler *rx_handlers; ieee80211_tx_handler *tx_handlers; - rwlock_t sub_if_lock; /* Protects sub_if_list. Cannot be taken under - * sta_bss_lock or sta_lock. */ - struct list_head sub_if_list; + struct list_head interfaces; + int sta_scanning; int scan_channel_idx; enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state; @@ -500,25 +503,17 @@ struct ieee80211_local { #ifdef CONFIG_MAC80211_LEDS int tx_led_counter, rx_led_counter; - struct led_trigger *tx_led, *rx_led; - char tx_led_name[32], rx_led_name[32]; + struct led_trigger *tx_led, *rx_led, *assoc_led; + char tx_led_name[32], rx_led_name[32], assoc_led_name[32]; #endif u32 channel_use; u32 channel_use_raw; - u32 stat_time; - struct timer_list stat_timer; #ifdef CONFIG_MAC80211_DEBUGFS struct work_struct sta_debugfs_add; #endif - enum { - STA_ANTENNA_SEL_AUTO = 0, - STA_ANTENNA_SEL_SW_CTRL = 1, - STA_ANTENNA_SEL_SW_CTRL_DEBUG = 2 - } sta_antenna_sel; - #ifdef CONFIG_MAC80211_DEBUG_COUNTERS /* TX/RX handler statistics */ unsigned int tx_handlers_drop; @@ -548,16 +543,9 @@ struct ieee80211_local { #endif /* CONFIG_MAC80211_DEBUG_COUNTERS */ - int default_wep_only; /* only default WEP keys are used with this - * interface; this is used to decide when hwaccel - * can be used with default keys */ int total_ps_buffered; /* total number of all buffered unicast and * multicast packets for power saving stations */ - int allow_broadcast_always; /* whether to allow TX of broadcast frames - * even when there are no associated STAs - */ - int wifi_wme_noack_test; unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */ @@ -566,17 +554,13 @@ struct ieee80211_local { unsigned int hw_modes; /* bitfield of supported hardware modes; * (1 << MODE_*) */ - int user_space_mlme; - #ifdef CONFIG_MAC80211_DEBUGFS struct local_debugfsdentries { struct dentry *channel; struct dentry *frequency; - struct dentry *radar_detect; struct dentry *antenna_sel_tx; struct dentry *antenna_sel_rx; struct dentry *bridge_packets; - struct dentry *key_tx_rx_threshold; struct dentry *rts_threshold; struct dentry *fragmentation_threshold; struct dentry *short_retry_limit; @@ -584,7 +568,6 @@ struct ieee80211_local { struct dentry *total_ps_buffered; struct dentry *mode; struct dentry *wep_iv; - struct dentry *tx_power_reduction; struct dentry *modes; struct dentry *statistics; struct local_debugfsdentries_statsdentries { @@ -656,38 +639,38 @@ struct sta_attribute { ssize_t (*store)(struct sta_info *, const char *buf, size_t count); }; -static inline void __bss_tim_set(struct ieee80211_if_ap *bss, int aid) +static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) { /* - * This format has ben mandated by the IEEE specifications, + * This format has been mandated by the IEEE specifications, * so this line may not be changed to use the __set_bit() format. */ - bss->tim[(aid)/8] |= 1<<((aid) % 8); + bss->tim[aid / 8] |= (1 << (aid % 8)); } static inline void bss_tim_set(struct ieee80211_local *local, - struct ieee80211_if_ap *bss, int aid) + struct ieee80211_if_ap *bss, u16 aid) { - spin_lock_bh(&local->sta_lock); + read_lock_bh(&local->sta_lock); __bss_tim_set(bss, aid); - spin_unlock_bh(&local->sta_lock); + read_unlock_bh(&local->sta_lock); } -static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, int aid) +static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, u16 aid) { /* - * This format has ben mandated by the IEEE specifications, + * This format has been mandated by the IEEE specifications, * so this line may not be changed to use the __clear_bit() format. */ - bss->tim[(aid)/8] &= !(1<<((aid) % 8)); + bss->tim[aid / 8] &= ~(1 << (aid % 8)); } static inline void bss_tim_clear(struct ieee80211_local *local, - struct ieee80211_if_ap *bss, int aid) + struct ieee80211_if_ap *bss, u16 aid) { - spin_lock_bh(&local->sta_lock); + read_lock_bh(&local->sta_lock); __bss_tim_clear(bss, aid); - spin_unlock_bh(&local->sta_lock); + read_unlock_bh(&local->sta_lock); } /** @@ -707,35 +690,28 @@ static inline int ieee80211_is_erp_rate(int phymode, int rate) return 0; } +static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) +{ + return compare_ether_addr(raddr, addr) == 0 || + is_broadcast_ether_addr(raddr); +} + + /* ieee80211.c */ int ieee80211_hw_config(struct ieee80211_local *local); int ieee80211_if_config(struct net_device *dev); int ieee80211_if_config_beacon(struct net_device *dev); -struct ieee80211_key_conf * -ieee80211_key_data2conf(struct ieee80211_local *local, - const struct ieee80211_key *data); -struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, - int idx, size_t key_len, gfp_t flags); -void ieee80211_key_free(struct ieee80211_key *key); -void ieee80211_rx_mgmt(struct ieee80211_local *local, struct sk_buff *skb, - struct ieee80211_rx_status *status, u32 msg_type); void ieee80211_prepare_rates(struct ieee80211_local *local, struct ieee80211_hw_mode *mode); void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx); int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr); -int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev); -int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev); void ieee80211_if_setup(struct net_device *dev); -void ieee80211_if_mgmt_setup(struct net_device *dev); -int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, - const char *name); -struct net_device_stats *ieee80211_dev_stats(struct net_device *dev); +struct ieee80211_rate *ieee80211_get_rate(struct ieee80211_local *local, + int phymode, int hwrate); /* ieee80211_ioctl.c */ extern const struct iw_handler_def ieee80211_iw_handler_def; -void ieee80211_update_default_wep_only(struct ieee80211_local *local); - /* Least common multiple of the used rates (in 100 kbps). This is used to * calculate rate_inv values for each rate so that only integers are needed. */ @@ -783,6 +759,8 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, u8 *addr); int ieee80211_sta_deauthenticate(struct net_device *dev, u16 reason); int ieee80211_sta_disassociate(struct net_device *dev, u16 reason); +void ieee80211_erp_info_change_notify(struct net_device *dev, u8 changes); +void ieee80211_reset_erp_info(struct net_device *dev); /* ieee80211_iface.c */ int ieee80211_if_add(struct net_device *dev, const char *name, @@ -794,14 +772,32 @@ void __ieee80211_if_del(struct ieee80211_local *local, int ieee80211_if_remove(struct net_device *dev, const char *name, int id); void ieee80211_if_free(struct net_device *dev); void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata); -int ieee80211_if_add_mgmt(struct ieee80211_local *local); -void ieee80211_if_del_mgmt(struct ieee80211_local *local); /* regdomain.c */ void ieee80211_regdomain_init(void); void ieee80211_set_default_regdomain(struct ieee80211_hw_mode *mode); -/* for wiphy privid */ -extern void *mac80211_wiphy_privid; +/* rx handling */ +extern ieee80211_rx_handler ieee80211_rx_pre_handlers[]; +extern ieee80211_rx_handler ieee80211_rx_handlers[]; + +/* tx handling */ +extern ieee80211_tx_handler ieee80211_tx_handlers[]; +void ieee80211_clear_tx_pending(struct ieee80211_local *local); +void ieee80211_tx_pending(unsigned long data); +int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev); +int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev); +int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev); + +/* utility functions/constants */ +extern void *mac80211_wiphy_privid; /* for wiphy privid */ +extern const unsigned char rfc1042_header[6]; +extern const unsigned char bridge_tunnel_header[6]; +u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len); +int ieee80211_is_eapol(const struct sk_buff *skb); +int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, + int rate, int erp, int short_preamble); +void mac80211_ev_michael_mic_failure(struct net_device *dev, int keyidx, + struct ieee80211_hdr *hdr); #endif /* IEEE80211_I_H */ diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c index 8532a5c..43e505d 100644 --- a/net/mac80211/ieee80211_iface.c +++ b/net/mac80211/ieee80211_iface.c @@ -25,6 +25,8 @@ void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata) sdata->eapol = 1; for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) skb_queue_head_init(&sdata->fragments[i].skb_list); + + INIT_LIST_HEAD(&sdata->key_list); } static void ieee80211_if_sdata_deinit(struct ieee80211_sub_if_data *sdata) @@ -77,18 +79,15 @@ int ieee80211_if_add(struct net_device *dev, const char *name, ieee80211_debugfs_add_netdev(sdata); ieee80211_if_set_type(ndev, type); - write_lock_bh(&local->sub_if_lock); + /* we're under RTNL so all this is fine */ if (unlikely(local->reg_state == IEEE80211_DEV_UNREGISTERED)) { - write_unlock_bh(&local->sub_if_lock); __ieee80211_if_del(local, sdata); return -ENODEV; } - list_add(&sdata->list, &local->sub_if_list); + list_add_tail_rcu(&sdata->list, &local->interfaces); + if (new_dev) *new_dev = ndev; - write_unlock_bh(&local->sub_if_lock); - - ieee80211_update_default_wep_only(local); return 0; @@ -97,74 +96,35 @@ fail: return ret; } -int ieee80211_if_add_mgmt(struct ieee80211_local *local) -{ - struct net_device *ndev; - struct ieee80211_sub_if_data *nsdata; - int ret; - - ASSERT_RTNL(); - - ndev = alloc_netdev(sizeof(struct ieee80211_sub_if_data), "wmgmt%d", - ieee80211_if_mgmt_setup); - if (!ndev) - return -ENOMEM; - ret = dev_alloc_name(ndev, ndev->name); - if (ret < 0) - goto fail; - - memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); - SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); - - nsdata = IEEE80211_DEV_TO_SUB_IF(ndev); - ndev->ieee80211_ptr = &nsdata->wdev; - nsdata->wdev.wiphy = local->hw.wiphy; - nsdata->type = IEEE80211_IF_TYPE_MGMT; - nsdata->dev = ndev; - nsdata->local = local; - ieee80211_if_sdata_init(nsdata); - - ret = register_netdevice(ndev); - if (ret) - goto fail; - - ieee80211_debugfs_add_netdev(nsdata); - - if (local->open_count > 0) - dev_open(ndev); - local->apdev = ndev; - return 0; - -fail: - free_netdev(ndev); - return ret; -} - -void ieee80211_if_del_mgmt(struct ieee80211_local *local) -{ - struct net_device *apdev; - - ASSERT_RTNL(); - apdev = local->apdev; - ieee80211_debugfs_remove_netdev(IEEE80211_DEV_TO_SUB_IF(apdev)); - local->apdev = NULL; - unregister_netdevice(apdev); -} - void ieee80211_if_set_type(struct net_device *dev, int type) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); int oldtype = sdata->type; - dev->hard_start_xmit = ieee80211_subif_start_xmit; - + /* + * We need to call this function on the master interface + * which already has a hard_start_xmit routine assigned + * which must not be changed. + */ + if (dev != sdata->local->mdev) + dev->hard_start_xmit = ieee80211_subif_start_xmit; + + /* + * Called even when register_netdevice fails, it would + * oops if assigned before initialising the rest. + */ + dev->uninit = ieee80211_if_reinit; + + /* most have no BSS pointer */ + sdata->bss = NULL; sdata->type = type; + switch (type) { case IEEE80211_IF_TYPE_WDS: - sdata->bss = NULL; + /* nothing special */ break; case IEEE80211_IF_TYPE_VLAN: + sdata->u.vlan.ap = NULL; break; case IEEE80211_IF_TYPE_AP: sdata->u.ap.dtim_period = 2; @@ -172,6 +132,7 @@ void ieee80211_if_set_type(struct net_device *dev, int type) sdata->u.ap.max_ratectrl_rateidx = -1; skb_queue_head_init(&sdata->u.ap.ps_bc_buf); sdata->bss = &sdata->u.ap; + INIT_LIST_HEAD(&sdata->u.ap.vlans); break; case IEEE80211_IF_TYPE_STA: case IEEE80211_IF_TYPE_IBSS: { @@ -187,10 +148,10 @@ void ieee80211_if_set_type(struct net_device *dev, int type) ifsta->capab = WLAN_CAPABILITY_ESS; ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN | IEEE80211_AUTH_ALG_SHARED_KEY; - ifsta->create_ibss = 1; - ifsta->wmm_enabled = 1; - ifsta->auto_channel_sel = 1; - ifsta->auto_bssid_sel = 1; + ifsta->flags |= IEEE80211_STA_CREATE_IBSS | + IEEE80211_STA_WMM_ENABLED | + IEEE80211_STA_AUTO_BSSID_SEL | + IEEE80211_STA_AUTO_CHANNEL_SEL; msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev); sdata->bss = &msdata->u.ap; @@ -205,7 +166,6 @@ void ieee80211_if_set_type(struct net_device *dev, int type) dev->name, __FUNCTION__, type); } ieee80211_debugfs_change_if_type(sdata, oldtype); - ieee80211_update_default_wep_only(local); } /* Must be called with rtnl lock held. */ @@ -214,57 +174,46 @@ void ieee80211_if_reinit(struct net_device *dev) struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct sta_info *sta; - int i; + struct sk_buff *skb; ASSERT_RTNL(); + + ieee80211_free_keys(sdata); + ieee80211_if_sdata_deinit(sdata); - for (i = 0; i < NUM_DEFAULT_KEYS; i++) { - if (!sdata->keys[i]) - continue; -#if 0 - /* The interface is down at the moment, so there is not - * really much point in disabling the keys at this point. */ - memset(addr, 0xff, ETH_ALEN); - if (local->ops->set_key) - local->ops->set_key(local_to_hw(local), DISABLE_KEY, addr, - local->keys[i], 0); -#endif - ieee80211_key_free(sdata->keys[i]); - sdata->keys[i] = NULL; - } switch (sdata->type) { + case IEEE80211_IF_TYPE_INVALID: + /* cannot happen */ + WARN_ON(1); + break; case IEEE80211_IF_TYPE_AP: { /* Remove all virtual interfaces that use this BSS * as their sdata->bss */ struct ieee80211_sub_if_data *tsdata, *n; - LIST_HEAD(tmp_list); - write_lock_bh(&local->sub_if_lock); - list_for_each_entry_safe(tsdata, n, &local->sub_if_list, list) { + list_for_each_entry_safe(tsdata, n, &local->interfaces, list) { if (tsdata != sdata && tsdata->bss == &sdata->u.ap) { printk(KERN_DEBUG "%s: removing virtual " "interface %s because its BSS interface" " is being removed\n", sdata->dev->name, tsdata->dev->name); - list_move_tail(&tsdata->list, &tmp_list); + list_del_rcu(&tsdata->list); + /* + * We have lots of time and can afford + * to sync for each interface + */ + synchronize_rcu(); + __ieee80211_if_del(local, tsdata); } } - write_unlock_bh(&local->sub_if_lock); - - list_for_each_entry_safe(tsdata, n, &tmp_list, list) - __ieee80211_if_del(local, tsdata); kfree(sdata->u.ap.beacon_head); kfree(sdata->u.ap.beacon_tail); - kfree(sdata->u.ap.generic_elem); - if (dev != local->mdev) { - struct sk_buff *skb; - while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) { - local->total_ps_buffered--; - dev_kfree_skb(skb); - } + while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) { + local->total_ps_buffered--; + dev_kfree_skb(skb); } break; @@ -272,8 +221,8 @@ void ieee80211_if_reinit(struct net_device *dev) case IEEE80211_IF_TYPE_WDS: sta = sta_info_get(local, sdata->u.wds.remote_addr); if (sta) { + sta_info_free(sta); sta_info_put(sta); - sta_info_free(sta, 0); } else { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG printk(KERN_DEBUG "%s: Someone had deleted my STA " @@ -298,6 +247,9 @@ void ieee80211_if_reinit(struct net_device *dev) case IEEE80211_IF_TYPE_MNTR: dev->type = ARPHRD_ETHER; break; + case IEEE80211_IF_TYPE_VLAN: + sdata->u.vlan.ap = NULL; + break; } /* remove all STAs that are bound to this virtual interface */ @@ -327,29 +279,23 @@ int ieee80211_if_remove(struct net_device *dev, const char *name, int id) ASSERT_RTNL(); - write_lock_bh(&local->sub_if_lock); - list_for_each_entry_safe(sdata, n, &local->sub_if_list, list) { + list_for_each_entry_safe(sdata, n, &local->interfaces, list) { if ((sdata->type == id || id == -1) && strcmp(name, sdata->dev->name) == 0 && sdata->dev != local->mdev) { - list_del(&sdata->list); - write_unlock_bh(&local->sub_if_lock); + list_del_rcu(&sdata->list); + synchronize_rcu(); __ieee80211_if_del(local, sdata); - ieee80211_update_default_wep_only(local); return 0; } } - write_unlock_bh(&local->sub_if_lock); return -ENODEV; } void ieee80211_if_free(struct net_device *dev) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - /* local->apdev must be NULL when freeing management interface */ - BUG_ON(dev == local->apdev); ieee80211_if_sdata_deinit(sdata); free_netdev(dev); } diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index e7904db..f0224c2 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -21,77 +21,41 @@ #include <net/mac80211.h> #include "ieee80211_i.h" -#include "hostapd_ioctl.h" #include "ieee80211_rate.h" #include "wpa.h" #include "aes_ccm.h" -#include "debugfs_key.h" - -static void ieee80211_set_hw_encryption(struct net_device *dev, - struct sta_info *sta, u8 addr[ETH_ALEN], - struct ieee80211_key *key) -{ - struct ieee80211_key_conf *keyconf = NULL; - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - /* default to sw encryption; this will be cleared by low-level - * driver if the hw supports requested encryption */ - if (key) - key->force_sw_encrypt = 1; - - if (key && local->ops->set_key && - (keyconf = ieee80211_key_data2conf(local, key))) { - if (local->ops->set_key(local_to_hw(local), SET_KEY, addr, - keyconf, sta ? sta->aid : 0)) { - key->force_sw_encrypt = 1; - key->hw_key_idx = HW_KEY_IDX_INVALID; - } else { - key->force_sw_encrypt = - !!(keyconf->flags & IEEE80211_KEY_FORCE_SW_ENCRYPT); - key->hw_key_idx = - keyconf->hw_key_idx; - - } - } - kfree(keyconf); -} static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, - int idx, int alg, int set_tx_key, - const u8 *_key, size_t key_len) + int idx, int alg, int remove, + int set_tx_key, const u8 *_key, + size_t key_len) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); int ret = 0; struct sta_info *sta; - struct ieee80211_key *key, *old_key; - int try_hwaccel = 1; - struct ieee80211_key_conf *keyconf; + struct ieee80211_key *key; struct ieee80211_sub_if_data *sdata; sdata = IEEE80211_DEV_TO_SUB_IF(dev); + if (idx < 0 || idx >= NUM_DEFAULT_KEYS) { + printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d\n", + dev->name, idx); + return -EINVAL; + } + if (is_broadcast_ether_addr(sta_addr)) { sta = NULL; - if (idx >= NUM_DEFAULT_KEYS) { - printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d\n", - dev->name, idx); - return -EINVAL; - } key = sdata->keys[idx]; - - /* TODO: consider adding hwaccel support for these; at least - * Atheros key cache should be able to handle this since AP is - * only transmitting frames with default keys. */ - /* FIX: hw key cache can be used when only one virtual - * STA is associated with each AP. If more than one STA - * is associated to the same AP, software encryption - * must be used. This should be done automatically - * based on configured station devices. For the time - * being, this can be only set at compile time. */ } else { set_tx_key = 0; - if (idx != 0) { + /* + * According to the standard, the key index of a pairwise + * key must be zero. However, some AP are broken when it + * comes to WEP key indices, so we work around this. + */ + if (idx != 0 && alg != ALG_WEP) { printk(KERN_DEBUG "%s: set_encrypt - non-zero idx for " "individual key\n", dev->name); return -EINVAL; @@ -100,9 +64,10 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, sta = sta_info_get(local, sta_addr); if (!sta) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG + DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "%s: set_encrypt - unknown addr " - MAC_FMT "\n", - dev->name, MAC_ARG(sta_addr)); + "%s\n", + dev->name, print_mac(mac, sta_addr)); #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ return -ENOENT; @@ -111,144 +76,25 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, key = sta->key; } - /* FIX: - * Cannot configure default hwaccel keys with WEP algorithm, if - * any of the virtual interfaces is using static WEP - * configuration because hwaccel would otherwise try to decrypt - * these frames. - * - * For now, just disable WEP hwaccel for broadcast when there is - * possibility of conflict with default keys. This can maybe later be - * optimized by using non-default keys (at least with Atheros ar521x). - */ - if (!sta && alg == ALG_WEP && !local->default_wep_only && - sdata->type != IEEE80211_IF_TYPE_IBSS && - sdata->type != IEEE80211_IF_TYPE_AP) { - try_hwaccel = 0; - } - - if (local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP) { - /* Software encryption cannot be used with devices that hide - * encryption from the host system, so always try to use - * hardware acceleration with such devices. */ - try_hwaccel = 1; - } - - if ((local->hw.flags & IEEE80211_HW_NO_TKIP_WMM_HWACCEL) && - alg == ALG_TKIP) { - if (sta && (sta->flags & WLAN_STA_WME)) { - /* Hardware does not support hwaccel with TKIP when using WMM. - */ - try_hwaccel = 0; - } - else if (sdata->type == IEEE80211_IF_TYPE_STA) { - sta = sta_info_get(local, sdata->u.sta.bssid); - if (sta) { - if (sta->flags & WLAN_STA_WME) { - try_hwaccel = 0; - } - sta_info_put(sta); - sta = NULL; - } - } - } - - if (alg == ALG_NONE) { - keyconf = NULL; - if (try_hwaccel && key && - key->hw_key_idx != HW_KEY_IDX_INVALID && - local->ops->set_key && - (keyconf = ieee80211_key_data2conf(local, key)) != NULL && - local->ops->set_key(local_to_hw(local), DISABLE_KEY, - sta_addr, keyconf, sta ? sta->aid : 0)) { - printk(KERN_DEBUG "%s: set_encrypt - low-level disable" - " failed\n", dev->name); - ret = -EINVAL; - } - kfree(keyconf); - - if (set_tx_key || sdata->default_key == key) { - ieee80211_debugfs_key_remove_default(sdata); - sdata->default_key = NULL; - } - ieee80211_debugfs_key_remove(key); - if (sta) - sta->key = NULL; - else - sdata->keys[idx] = NULL; + if (remove) { ieee80211_key_free(key); key = NULL; } else { - old_key = key; - key = ieee80211_key_alloc(sta ? NULL : sdata, idx, key_len, - GFP_KERNEL); + /* + * Automatically frees any old key if present. + */ + key = ieee80211_key_alloc(sdata, sta, alg, idx, key_len, _key); if (!key) { ret = -ENOMEM; goto err_out; } - - /* default to sw encryption; low-level driver sets these if the - * requested encryption is supported */ - key->hw_key_idx = HW_KEY_IDX_INVALID; - key->force_sw_encrypt = 1; - - key->alg = alg; - key->keyidx = idx; - key->keylen = key_len; - memcpy(key->key, _key, key_len); - if (set_tx_key) - key->default_tx_key = 1; - - if (alg == ALG_CCMP) { - /* Initialize AES key state here as an optimization - * so that it does not need to be initialized for every - * packet. */ - key->u.ccmp.tfm = ieee80211_aes_key_setup_encrypt( - key->key); - if (!key->u.ccmp.tfm) { - ret = -ENOMEM; - goto err_free; - } - } - - if (set_tx_key || sdata->default_key == old_key) { - ieee80211_debugfs_key_remove_default(sdata); - sdata->default_key = NULL; - } - ieee80211_debugfs_key_remove(old_key); - if (sta) - sta->key = key; - else - sdata->keys[idx] = key; - ieee80211_key_free(old_key); - ieee80211_debugfs_key_add(local, key); - if (sta) - ieee80211_debugfs_key_sta_link(key, sta); - - if (try_hwaccel && - (alg == ALG_WEP || alg == ALG_TKIP || alg == ALG_CCMP)) - ieee80211_set_hw_encryption(dev, sta, sta_addr, key); } - if (set_tx_key || (!sta && !sdata->default_key && key)) { - sdata->default_key = key; - if (key) - ieee80211_debugfs_key_add_default(sdata); - - if (local->ops->set_key_idx && - local->ops->set_key_idx(local_to_hw(local), idx)) - printk(KERN_DEBUG "%s: failed to set TX key idx for " - "low-level driver\n", dev->name); - } + if (set_tx_key || (!sta && !sdata->default_key && key)) + ieee80211_set_default_key(sdata, idx); - if (sta) - sta_info_put(sta); - - return 0; - -err_free: - ieee80211_key_free(key); -err_out: + ret = 0; + err_out: if (sta) sta_info_put(sta); return ret; @@ -259,44 +105,25 @@ static int ieee80211_ioctl_siwgenie(struct net_device *dev, struct iw_point *data, char *extra) { struct ieee80211_sub_if_data *sdata; - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - if (local->user_space_mlme) + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) return -EOPNOTSUPP; - sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->type == IEEE80211_IF_TYPE_STA || sdata->type == IEEE80211_IF_TYPE_IBSS) { int ret = ieee80211_sta_set_extra_ie(dev, extra, data->length); if (ret) return ret; - sdata->u.sta.auto_bssid_sel = 0; + sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; ieee80211_sta_req_auth(dev, &sdata->u.sta); return 0; } - if (sdata->type == IEEE80211_IF_TYPE_AP) { - kfree(sdata->u.ap.generic_elem); - sdata->u.ap.generic_elem = kmalloc(data->length, GFP_KERNEL); - if (!sdata->u.ap.generic_elem) - return -ENOMEM; - memcpy(sdata->u.ap.generic_elem, extra, data->length); - sdata->u.ap.generic_elem_len = data->length; - return ieee80211_if_config(dev); - } return -EOPNOTSUPP; } -static int ieee80211_ioctl_set_radio_enabled(struct net_device *dev, - int val) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_conf *conf = &local->hw.conf; - - conf->radio_enabled = val; - return ieee80211_hw_config(wdev_priv(dev->ieee80211_ptr)); -} - static int ieee80211_ioctl_giwname(struct net_device *dev, struct iw_request_info *info, char *name, char *extra) @@ -313,9 +140,6 @@ static int ieee80211_ioctl_giwname(struct net_device *dev, case MODE_IEEE80211G: strcpy(name, "IEEE 802.11g"); break; - case MODE_ATHEROS_TURBO: - strcpy(name, "5GHz Turbo"); - break; default: strcpy(name, "IEEE 802.11"); break; @@ -480,11 +304,6 @@ int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq) struct ieee80211_channel *chan = &mode->channels[c]; if (chan->flag & IEEE80211_CHAN_W_SCAN && ((chan->chan == channel) || (chan->freq == freq))) { - /* Use next_mode as the mode preference to - * resolve non-unique channel numbers. */ - if (set && mode->mode != local->next_mode) - continue; - local->oper_channel = chan; local->oper_hw_mode = mode; set++; @@ -512,13 +331,14 @@ static int ieee80211_ioctl_siwfreq(struct net_device *dev, struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->type == IEEE80211_IF_TYPE_STA) - sdata->u.sta.auto_channel_sel = 0; + sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL; /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */ if (freq->e == 0) { if (freq->m < 0) { if (sdata->type == IEEE80211_IF_TYPE_STA) - sdata->u.sta.auto_channel_sel = 1; + sdata->u.sta.flags |= + IEEE80211_STA_AUTO_CHANNEL_SEL; return 0; } else return ieee80211_set_channel(local, freq->m, -1); @@ -554,7 +374,6 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *ssid) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata; size_t len = data->length; @@ -566,14 +385,17 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev, if (sdata->type == IEEE80211_IF_TYPE_STA || sdata->type == IEEE80211_IF_TYPE_IBSS) { int ret; - if (local->user_space_mlme) { + if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) { if (len > IEEE80211_MAX_SSID_LEN) return -EINVAL; memcpy(sdata->u.sta.ssid, ssid, len); sdata->u.sta.ssid_len = len; return 0; } - sdata->u.sta.auto_ssid_sel = !data->flags; + if (data->flags) + sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_SSID_SEL; + else + sdata->u.sta.flags |= IEEE80211_STA_AUTO_SSID_SEL; ret = ieee80211_sta_set_ssid(dev, ssid, len); if (ret) return ret; @@ -628,25 +450,24 @@ static int ieee80211_ioctl_siwap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *ap_addr, char *extra) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata; sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->type == IEEE80211_IF_TYPE_STA || sdata->type == IEEE80211_IF_TYPE_IBSS) { int ret; - if (local->user_space_mlme) { + if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) { memcpy(sdata->u.sta.bssid, (u8 *) &ap_addr->sa_data, ETH_ALEN); return 0; } - if (is_zero_ether_addr((u8 *) &ap_addr->sa_data)) { - sdata->u.sta.auto_bssid_sel = 1; - sdata->u.sta.auto_channel_sel = 1; - } else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data)) - sdata->u.sta.auto_bssid_sel = 1; + if (is_zero_ether_addr((u8 *) &ap_addr->sa_data)) + sdata->u.sta.flags |= IEEE80211_STA_AUTO_BSSID_SEL | + IEEE80211_STA_AUTO_CHANNEL_SEL; + else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data)) + sdata->u.sta.flags |= IEEE80211_STA_AUTO_BSSID_SEL; else - sdata->u.sta.auto_bssid_sel = 0; + sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; ret = ieee80211_sta_set_bssid(dev, (u8 *) &ap_addr->sa_data); if (ret) return ret; @@ -762,9 +583,6 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev, struct ieee80211_rate *rates = &mode->rates[i]; int this_rate = rates->rate; - if (mode->mode == MODE_ATHEROS_TURBO || - mode->mode == MODE_ATHEROS_TURBOG) - this_rate *= 2; if (target_rate == this_rate) { sdata->bss->max_ratectrl_rateidx = i; if (rate->fixed) @@ -798,6 +616,52 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev, return 0; } +static int ieee80211_ioctl_siwtxpower(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *data, char *extra) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + bool need_reconfig = 0; + + if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) + return -EINVAL; + if (data->txpower.flags & IW_TXPOW_RANGE) + return -EINVAL; + if (!data->txpower.fixed) + return -EINVAL; + + if (local->hw.conf.power_level != data->txpower.value) { + local->hw.conf.power_level = data->txpower.value; + need_reconfig = 1; + } + if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) { + local->hw.conf.radio_enabled = !(data->txpower.disabled); + need_reconfig = 1; + } + if (need_reconfig) { + ieee80211_hw_config(local); + /* The return value of hw_config is not of big interest here, + * as it doesn't say that it failed because of _this_ config + * change or something else. Ignore it. */ + } + + return 0; +} + +static int ieee80211_ioctl_giwtxpower(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *data, char *extra) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + + data->txpower.fixed = 1; + data->txpower.disabled = !(local->hw.conf.radio_enabled); + data->txpower.value = local->hw.conf.power_level; + data->txpower.flags = IW_TXPOW_DBM; + + return 0; +} + static int ieee80211_ioctl_siwrts(struct net_device *dev, struct iw_request_info *info, struct iw_param *rts, char *extra) @@ -930,335 +794,6 @@ static int ieee80211_ioctl_giwretry(struct net_device *dev, return 0; } -static void ieee80211_key_enable_hwaccel(struct ieee80211_local *local, - struct ieee80211_key *key) -{ - struct ieee80211_key_conf *keyconf; - u8 addr[ETH_ALEN]; - - if (!key || key->alg != ALG_WEP || !key->force_sw_encrypt || - (local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP)) - return; - - memset(addr, 0xff, ETH_ALEN); - keyconf = ieee80211_key_data2conf(local, key); - if (keyconf && local->ops->set_key && - local->ops->set_key(local_to_hw(local), - SET_KEY, addr, keyconf, 0) == 0) { - key->force_sw_encrypt = - !!(keyconf->flags & IEEE80211_KEY_FORCE_SW_ENCRYPT); - key->hw_key_idx = keyconf->hw_key_idx; - } - kfree(keyconf); -} - - -static void ieee80211_key_disable_hwaccel(struct ieee80211_local *local, - struct ieee80211_key *key) -{ - struct ieee80211_key_conf *keyconf; - u8 addr[ETH_ALEN]; - - if (!key || key->alg != ALG_WEP || key->force_sw_encrypt || - (local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP)) - return; - - memset(addr, 0xff, ETH_ALEN); - keyconf = ieee80211_key_data2conf(local, key); - if (keyconf && local->ops->set_key) - local->ops->set_key(local_to_hw(local), DISABLE_KEY, - addr, keyconf, 0); - kfree(keyconf); - key->force_sw_encrypt = 1; -} - - -static int ieee80211_ioctl_default_wep_only(struct ieee80211_local *local, - int value) -{ - int i; - struct ieee80211_sub_if_data *sdata; - - local->default_wep_only = value; - read_lock(&local->sub_if_lock); - list_for_each_entry(sdata, &local->sub_if_list, list) - for (i = 0; i < NUM_DEFAULT_KEYS; i++) - if (value) - ieee80211_key_enable_hwaccel(local, - sdata->keys[i]); - else - ieee80211_key_disable_hwaccel(local, - sdata->keys[i]); - read_unlock(&local->sub_if_lock); - - return 0; -} - - -void ieee80211_update_default_wep_only(struct ieee80211_local *local) -{ - int i = 0; - struct ieee80211_sub_if_data *sdata; - - read_lock(&local->sub_if_lock); - list_for_each_entry(sdata, &local->sub_if_list, list) { - - if (sdata->dev == local->mdev) - continue; - - /* If there is an AP interface then depend on userspace to - set default_wep_only correctly. */ - if (sdata->type == IEEE80211_IF_TYPE_AP) { - read_unlock(&local->sub_if_lock); - return; - } - - i++; - } - - read_unlock(&local->sub_if_lock); - - if (i <= 1) - ieee80211_ioctl_default_wep_only(local, 1); - else - ieee80211_ioctl_default_wep_only(local, 0); -} - - -static int ieee80211_ioctl_prism2_param(struct net_device *dev, - struct iw_request_info *info, - void *wrqu, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata; - int *i = (int *) extra; - int param = *i; - int value = *(i + 1); - int ret = 0; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - switch (param) { - case PRISM2_PARAM_IEEE_802_1X: - if (local->ops->set_ieee8021x) - ret = local->ops->set_ieee8021x(local_to_hw(local), - value); - if (ret) - printk(KERN_DEBUG "%s: failed to set IEEE 802.1X (%d) " - "for low-level driver\n", dev->name, value); - else - sdata->ieee802_1x = value; - break; - - case PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES: - if (sdata->type != IEEE80211_IF_TYPE_AP) - ret = -ENOENT; - else - sdata->use_protection = value; - break; - - case PRISM2_PARAM_PREAMBLE: - local->short_preamble = value; - break; - - case PRISM2_PARAM_STAT_TIME: - if (!local->stat_time && value) { - local->stat_timer.expires = jiffies + HZ * value / 100; - add_timer(&local->stat_timer); - } else if (local->stat_time && !value) { - del_timer_sync(&local->stat_timer); - } - local->stat_time = value; - break; - case PRISM2_PARAM_SHORT_SLOT_TIME: - if (value) - local->hw.conf.flags |= IEEE80211_CONF_SHORT_SLOT_TIME; - else - local->hw.conf.flags &= ~IEEE80211_CONF_SHORT_SLOT_TIME; - if (ieee80211_hw_config(local)) - ret = -EINVAL; - break; - - case PRISM2_PARAM_NEXT_MODE: - local->next_mode = value; - break; - - case PRISM2_PARAM_RADIO_ENABLED: - ret = ieee80211_ioctl_set_radio_enabled(dev, value); - break; - - case PRISM2_PARAM_ANTENNA_MODE: - local->hw.conf.antenna_mode = value; - if (ieee80211_hw_config(local)) - ret = -EINVAL; - break; - - case PRISM2_PARAM_STA_ANTENNA_SEL: - local->sta_antenna_sel = value; - break; - - case PRISM2_PARAM_TX_POWER_REDUCTION: - if (value < 0) - ret = -EINVAL; - else - local->hw.conf.tx_power_reduction = value; - break; - - case PRISM2_PARAM_KEY_TX_RX_THRESHOLD: - local->key_tx_rx_threshold = value; - break; - - case PRISM2_PARAM_DEFAULT_WEP_ONLY: - ret = ieee80211_ioctl_default_wep_only(local, value); - break; - - case PRISM2_PARAM_WIFI_WME_NOACK_TEST: - local->wifi_wme_noack_test = value; - break; - - case PRISM2_PARAM_SCAN_FLAGS: - local->scan_flags = value; - break; - - case PRISM2_PARAM_MIXED_CELL: - if (sdata->type != IEEE80211_IF_TYPE_STA && - sdata->type != IEEE80211_IF_TYPE_IBSS) - ret = -EINVAL; - else - sdata->u.sta.mixed_cell = !!value; - break; - - case PRISM2_PARAM_HW_MODES: - local->enabled_modes = value; - break; - - case PRISM2_PARAM_CREATE_IBSS: - if (sdata->type != IEEE80211_IF_TYPE_IBSS) - ret = -EINVAL; - else - sdata->u.sta.create_ibss = !!value; - break; - case PRISM2_PARAM_WMM_ENABLED: - if (sdata->type != IEEE80211_IF_TYPE_STA && - sdata->type != IEEE80211_IF_TYPE_IBSS) - ret = -EINVAL; - else - sdata->u.sta.wmm_enabled = !!value; - break; - case PRISM2_PARAM_RADAR_DETECT: - local->hw.conf.radar_detect = value; - break; - case PRISM2_PARAM_SPECTRUM_MGMT: - local->hw.conf.spect_mgmt = value; - break; - default: - ret = -EOPNOTSUPP; - break; - } - - return ret; -} - - -static int ieee80211_ioctl_get_prism2_param(struct net_device *dev, - struct iw_request_info *info, - void *wrqu, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata; - int *param = (int *) extra; - int ret = 0; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - switch (*param) { - case PRISM2_PARAM_IEEE_802_1X: - *param = sdata->ieee802_1x; - break; - - case PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES: - *param = sdata->use_protection; - break; - - case PRISM2_PARAM_PREAMBLE: - *param = local->short_preamble; - break; - - case PRISM2_PARAM_STAT_TIME: - *param = local->stat_time; - break; - case PRISM2_PARAM_SHORT_SLOT_TIME: - *param = !!(local->hw.conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME); - break; - - case PRISM2_PARAM_NEXT_MODE: - *param = local->next_mode; - break; - - case PRISM2_PARAM_ANTENNA_MODE: - *param = local->hw.conf.antenna_mode; - break; - - case PRISM2_PARAM_STA_ANTENNA_SEL: - *param = local->sta_antenna_sel; - break; - - case PRISM2_PARAM_TX_POWER_REDUCTION: - *param = local->hw.conf.tx_power_reduction; - break; - - case PRISM2_PARAM_KEY_TX_RX_THRESHOLD: - *param = local->key_tx_rx_threshold; - break; - - case PRISM2_PARAM_DEFAULT_WEP_ONLY: - *param = local->default_wep_only; - break; - - case PRISM2_PARAM_WIFI_WME_NOACK_TEST: - *param = local->wifi_wme_noack_test; - break; - - case PRISM2_PARAM_SCAN_FLAGS: - *param = local->scan_flags; - break; - - case PRISM2_PARAM_HW_MODES: - *param = local->enabled_modes; - break; - - case PRISM2_PARAM_CREATE_IBSS: - if (sdata->type != IEEE80211_IF_TYPE_IBSS) - ret = -EINVAL; - else - *param = !!sdata->u.sta.create_ibss; - break; - - case PRISM2_PARAM_MIXED_CELL: - if (sdata->type != IEEE80211_IF_TYPE_STA && - sdata->type != IEEE80211_IF_TYPE_IBSS) - ret = -EINVAL; - else - *param = !!sdata->u.sta.mixed_cell; - break; - case PRISM2_PARAM_WMM_ENABLED: - if (sdata->type != IEEE80211_IF_TYPE_STA && - sdata->type != IEEE80211_IF_TYPE_IBSS) - ret = -EINVAL; - else - *param = !!sdata->u.sta.wmm_enabled; - break; - default: - ret = -EOPNOTSUPP; - break; - } - - return ret; -} - static int ieee80211_ioctl_siwmlme(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra) @@ -1291,6 +826,7 @@ static int ieee80211_ioctl_siwencode(struct net_device *dev, struct ieee80211_sub_if_data *sdata; int idx, i, alg = ALG_WEP; u8 bcaddr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + int remove = 0; sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -1309,21 +845,16 @@ static int ieee80211_ioctl_siwencode(struct net_device *dev, idx--; if (erq->flags & IW_ENCODE_DISABLED) - alg = ALG_NONE; + remove = 1; else if (erq->length == 0) { /* No key data - just set the default TX key index */ - if (sdata->default_key != sdata->keys[idx]) { - ieee80211_debugfs_key_remove_default(sdata); - sdata->default_key = sdata->keys[idx]; - if (sdata->default_key) - ieee80211_debugfs_key_add_default(sdata); - } + ieee80211_set_default_key(sdata, idx); return 0; } return ieee80211_set_encryption( dev, bcaddr, - idx, alg, + idx, alg, remove, !sdata->default_key, keybuf, erq->length); } @@ -1362,9 +893,9 @@ static int ieee80211_ioctl_giwencode(struct net_device *dev, return 0; } - memcpy(key, sdata->keys[idx]->key, - min((int)erq->length, sdata->keys[idx]->keylen)); - erq->length = sdata->keys[idx]->keylen; + memcpy(key, sdata->keys[idx]->conf.key, + min_t(int, erq->length, sdata->keys[idx]->conf.keylen)); + erq->length = sdata->keys[idx]->conf.keylen; erq->flags |= IW_ENCODE_ENABLED; return 0; @@ -1390,22 +921,12 @@ static int ieee80211_ioctl_siwauth(struct net_device *dev, ret = -EINVAL; else { /* - * TODO: sdata->u.sta.key_mgmt does not match with WE18 - * value completely; could consider modifying this to - * be closer to WE18. For now, this value is not really - * used for anything else than Privacy matching, so the - * current code here should be more or less OK. + * Key management was set by wpa_supplicant, + * we only need this to associate to a network + * that has privacy enabled regardless of not + * having a key. */ - if (data->value & IW_AUTH_KEY_MGMT_802_1X) { - sdata->u.sta.key_mgmt = - IEEE80211_KEY_MGMT_WPA_EAP; - } else if (data->value & IW_AUTH_KEY_MGMT_PSK) { - sdata->u.sta.key_mgmt = - IEEE80211_KEY_MGMT_WPA_PSK; - } else { - sdata->u.sta.key_mgmt = - IEEE80211_KEY_MGMT_NONE; - } + sdata->u.sta.key_management_enabled = !!data->value; } break; case IW_AUTH_80211_AUTH_ALG: @@ -1484,11 +1005,11 @@ static int ieee80211_ioctl_siwencodeext(struct net_device *dev, { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; - int alg, idx, i; + int uninitialized_var(alg), idx, i, remove = 0; switch (ext->alg) { case IW_ENCODE_ALG_NONE: - alg = ALG_NONE; + remove = 1; break; case IW_ENCODE_ALG_WEP: alg = ALG_WEP; @@ -1504,7 +1025,7 @@ static int ieee80211_ioctl_siwencodeext(struct net_device *dev, } if (erq->flags & IW_ENCODE_DISABLED) - alg = ALG_NONE; + remove = 1; idx = erq->flags & IW_ENCODE_INDEX; if (idx < 1 || idx > 4) { @@ -1523,20 +1044,13 @@ static int ieee80211_ioctl_siwencodeext(struct net_device *dev, idx--; return ieee80211_set_encryption(dev, ext->addr.sa_data, idx, alg, + remove, ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, ext->key, ext->key_len); } -static const struct iw_priv_args ieee80211_ioctl_priv[] = { - { PRISM2_IOCTL_PRISM2_PARAM, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "param" }, - { PRISM2_IOCTL_GET_PRISM2_PARAM, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_param" }, -}; - /* Structures to export the Wireless Handlers */ static const iw_handler ieee80211_handler[] = @@ -1557,10 +1071,10 @@ static const iw_handler ieee80211_handler[] = (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */ (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */ (iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */ - iw_handler_set_spy, /* SIOCSIWSPY */ - iw_handler_get_spy, /* SIOCGIWSPY */ - iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ - iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ + (iw_handler) NULL, /* SIOCSIWSPY */ + (iw_handler) NULL, /* SIOCGIWSPY */ + (iw_handler) NULL, /* SIOCSIWTHRSPY */ + (iw_handler) NULL, /* SIOCGIWTHRSPY */ (iw_handler) ieee80211_ioctl_siwap, /* SIOCSIWAP */ (iw_handler) ieee80211_ioctl_giwap, /* SIOCGIWAP */ (iw_handler) ieee80211_ioctl_siwmlme, /* SIOCSIWMLME */ @@ -1579,8 +1093,8 @@ static const iw_handler ieee80211_handler[] = (iw_handler) ieee80211_ioctl_giwrts, /* SIOCGIWRTS */ (iw_handler) ieee80211_ioctl_siwfrag, /* SIOCSIWFRAG */ (iw_handler) ieee80211_ioctl_giwfrag, /* SIOCGIWFRAG */ - (iw_handler) NULL, /* SIOCSIWTXPOW */ - (iw_handler) NULL, /* SIOCGIWTXPOW */ + (iw_handler) ieee80211_ioctl_siwtxpower, /* SIOCSIWTXPOW */ + (iw_handler) ieee80211_ioctl_giwtxpower, /* SIOCGIWTXPOW */ (iw_handler) ieee80211_ioctl_siwretry, /* SIOCSIWRETRY */ (iw_handler) ieee80211_ioctl_giwretry, /* SIOCGIWRETRY */ (iw_handler) ieee80211_ioctl_siwencode, /* SIOCSIWENCODE */ @@ -1599,19 +1113,9 @@ static const iw_handler ieee80211_handler[] = (iw_handler) NULL, /* -- hole -- */ }; -static const iw_handler ieee80211_private_handler[] = -{ /* SIOCIWFIRSTPRIV + */ - (iw_handler) ieee80211_ioctl_prism2_param, /* 0 */ - (iw_handler) ieee80211_ioctl_get_prism2_param, /* 1 */ -}; - const struct iw_handler_def ieee80211_iw_handler_def = { .num_standard = ARRAY_SIZE(ieee80211_handler), - .num_private = ARRAY_SIZE(ieee80211_private_handler), - .num_private_args = ARRAY_SIZE(ieee80211_ioctl_priv), .standard = (iw_handler *) ieee80211_handler, - .private = (iw_handler *) ieee80211_private_handler, - .private_args = (struct iw_priv_args *) ieee80211_ioctl_priv, .get_wireless_stats = ieee80211_get_wireless_stats, }; diff --git a/net/mac80211/ieee80211_key.h b/net/mac80211/ieee80211_key.h index c333849..fc770e9 100644 --- a/net/mac80211/ieee80211_key.h +++ b/net/mac80211/ieee80211_key.h @@ -11,7 +11,7 @@ #define IEEE80211_KEY_H #include <linux/types.h> -#include <linux/kref.h> +#include <linux/list.h> #include <linux/crypto.h> #include <net/mac80211.h> @@ -41,11 +41,21 @@ #define NUM_RX_DATA_QUEUES 17 +struct ieee80211_local; +struct ieee80211_sub_if_data; +struct sta_info; + +#define KEY_FLAG_UPLOADED_TO_HARDWARE (1<<0) + struct ieee80211_key { - struct kref kref; + struct ieee80211_local *local; + struct ieee80211_sub_if_data *sdata; + struct sta_info *sta; + + struct list_head list; + + unsigned int flags; - int hw_key_idx; /* filled and used by low-level driver */ - ieee80211_key_alg alg; union { struct { /* last used TSC */ @@ -73,22 +83,16 @@ struct ieee80211_key { u8 rx_crypto_buf[6 * AES_BLOCK_LEN]; } ccmp; } u; - int tx_rx_count; /* number of times this key has been used */ - int keylen; - /* if the low level driver can provide hardware acceleration it should - * clear this flag */ - unsigned int force_sw_encrypt:1; - unsigned int default_tx_key:1; /* This key is the new default TX key - * (used only for broadcast keys). */ - s8 keyidx; /* WEP key index */ + /* number of times this key has been used */ + int tx_rx_count; #ifdef CONFIG_MAC80211_DEBUGFS struct { struct dentry *stalink; struct dentry *dir; struct dentry *keylen; - struct dentry *force_sw_encrypt; + struct dentry *flags; struct dentry *keyidx; struct dentry *hw_key_idx; struct dentry *tx_rx_count; @@ -97,10 +101,27 @@ struct ieee80211_key { struct dentry *rx_spec; struct dentry *replays; struct dentry *key; + struct dentry *ifindex; } debugfs; #endif - u8 key[0]; + /* + * key config, must be last because it contains key + * material as variable length member + */ + struct ieee80211_key_conf conf; }; +struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, + struct sta_info *sta, + enum ieee80211_key_alg alg, + int idx, + size_t key_len, + const u8 *key_data); +void ieee80211_key_free(struct ieee80211_key *key); +void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx); +void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata); +void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); +void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata); + #endif /* IEEE80211_KEY_H */ diff --git a/net/mac80211/ieee80211_led.c b/net/mac80211/ieee80211_led.c index 719d75b..4cf89af 100644 --- a/net/mac80211/ieee80211_led.c +++ b/net/mac80211/ieee80211_led.c @@ -33,33 +33,58 @@ void ieee80211_led_tx(struct ieee80211_local *local, int q) led_trigger_event(local->tx_led, LED_FULL); } +void ieee80211_led_assoc(struct ieee80211_local *local, bool associated) +{ + if (unlikely(!local->assoc_led)) + return; + if (associated) + led_trigger_event(local->assoc_led, LED_FULL); + else + led_trigger_event(local->assoc_led, LED_OFF); +} + void ieee80211_led_init(struct ieee80211_local *local) { local->rx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); - if (!local->rx_led) - return; - snprintf(local->rx_led_name, sizeof(local->rx_led_name), - "%srx", wiphy_name(local->hw.wiphy)); - local->rx_led->name = local->rx_led_name; - if (led_trigger_register(local->rx_led)) { - kfree(local->rx_led); - local->rx_led = NULL; + if (local->rx_led) { + snprintf(local->rx_led_name, sizeof(local->rx_led_name), + "%srx", wiphy_name(local->hw.wiphy)); + local->rx_led->name = local->rx_led_name; + if (led_trigger_register(local->rx_led)) { + kfree(local->rx_led); + local->rx_led = NULL; + } } local->tx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); - if (!local->tx_led) - return; - snprintf(local->tx_led_name, sizeof(local->tx_led_name), - "%stx", wiphy_name(local->hw.wiphy)); - local->tx_led->name = local->tx_led_name; - if (led_trigger_register(local->tx_led)) { - kfree(local->tx_led); - local->tx_led = NULL; + if (local->tx_led) { + snprintf(local->tx_led_name, sizeof(local->tx_led_name), + "%stx", wiphy_name(local->hw.wiphy)); + local->tx_led->name = local->tx_led_name; + if (led_trigger_register(local->tx_led)) { + kfree(local->tx_led); + local->tx_led = NULL; + } + } + + local->assoc_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); + if (local->assoc_led) { + snprintf(local->assoc_led_name, sizeof(local->assoc_led_name), + "%sassoc", wiphy_name(local->hw.wiphy)); + local->assoc_led->name = local->assoc_led_name; + if (led_trigger_register(local->assoc_led)) { + kfree(local->assoc_led); + local->assoc_led = NULL; + } } } void ieee80211_led_exit(struct ieee80211_local *local) { + if (local->assoc_led) { + led_trigger_unregister(local->assoc_led); + kfree(local->assoc_led); + } if (local->tx_led) { led_trigger_unregister(local->tx_led); kfree(local->tx_led); @@ -70,6 +95,16 @@ void ieee80211_led_exit(struct ieee80211_local *local) } } +char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw) +{ + struct ieee80211_local *local = hw_to_local(hw); + + if (local->assoc_led) + return local->assoc_led_name; + return NULL; +} +EXPORT_SYMBOL(__ieee80211_get_assoc_led_name); + char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); diff --git a/net/mac80211/ieee80211_led.h b/net/mac80211/ieee80211_led.h index 5c8ab82..0feb226 100644 --- a/net/mac80211/ieee80211_led.h +++ b/net/mac80211/ieee80211_led.h @@ -14,6 +14,8 @@ #ifdef CONFIG_MAC80211_LEDS extern void ieee80211_led_rx(struct ieee80211_local *local); extern void ieee80211_led_tx(struct ieee80211_local *local, int q); +extern void ieee80211_led_assoc(struct ieee80211_local *local, + bool associated); extern void ieee80211_led_init(struct ieee80211_local *local); extern void ieee80211_led_exit(struct ieee80211_local *local); #else @@ -23,6 +25,10 @@ static inline void ieee80211_led_rx(struct ieee80211_local *local) static inline void ieee80211_led_tx(struct ieee80211_local *local, int q) { } +static inline void ieee80211_led_assoc(struct ieee80211_local *local, + bool associated) +{ +} static inline void ieee80211_led_init(struct ieee80211_local *local) { } diff --git a/net/mac80211/ieee80211_rate.c b/net/mac80211/ieee80211_rate.c index 2118de0..93abb8f 100644 --- a/net/mac80211/ieee80211_rate.c +++ b/net/mac80211/ieee80211_rate.c @@ -9,6 +9,7 @@ */ #include <linux/kernel.h> +#include <linux/rtnetlink.h> #include "ieee80211_rate.h" #include "ieee80211_i.h" @@ -137,3 +138,43 @@ void rate_control_put(struct rate_control_ref *ref) { kref_put(&ref->kref, rate_control_release); } + +int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, + const char *name) +{ + struct rate_control_ref *ref, *old; + + ASSERT_RTNL(); + if (local->open_count || netif_running(local->mdev)) + return -EBUSY; + + ref = rate_control_alloc(name, local); + if (!ref) { + printk(KERN_WARNING "%s: Failed to select rate control " + "algorithm\n", wiphy_name(local->hw.wiphy)); + return -ENOENT; + } + + old = local->rate_ctrl; + local->rate_ctrl = ref; + if (old) { + rate_control_put(old); + sta_info_flush(local, NULL); + } + + printk(KERN_DEBUG "%s: Selected rate control " + "algorithm '%s'\n", wiphy_name(local->hw.wiphy), + ref->ops->name); + + + return 0; +} + +void rate_control_deinitialize(struct ieee80211_local *local) +{ + struct rate_control_ref *ref; + + ref = local->rate_ctrl; + local->rate_ctrl = NULL; + rate_control_put(ref); +} diff --git a/net/mac80211/ieee80211_rate.h b/net/mac80211/ieee80211_rate.h index f021a02..7cd1eba 100644 --- a/net/mac80211/ieee80211_rate.h +++ b/net/mac80211/ieee80211_rate.h @@ -30,8 +30,6 @@ struct rate_control_extra { /* parameters from the caller to rate_control_get_rate(): */ struct ieee80211_hw_mode *mode; - int mgmt_data; /* this is data frame that is used for management - * (e.g., IEEE 802.1X EAPOL) */ u16 ethertype; }; @@ -141,4 +139,10 @@ static inline void rate_control_remove_sta_debugfs(struct sta_info *sta) #endif } + +/* functions for rate control related to a device */ +int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, + const char *name); +void rate_control_deinitialize(struct ieee80211_local *local); + #endif /* IEEE80211_RATE_H */ diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 0d99b68..1641e8f 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -31,7 +31,7 @@ #include <net/mac80211.h> #include "ieee80211_i.h" #include "ieee80211_rate.h" -#include "hostapd_ioctl.h" +#include "ieee80211_led.h" #define IEEE80211_AUTH_TIMEOUT (HZ / 5) #define IEEE80211_AUTH_MAX_TRIES 3 @@ -108,11 +108,10 @@ struct ieee802_11_elems { u8 wmm_param_len; }; -typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes; +enum ParseRes { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 }; - -static ParseRes ieee802_11_parse_elems(u8 *start, size_t len, - struct ieee802_11_elems *elems) +static enum ParseRes ieee802_11_parse_elems(u8 *start, size_t len, + struct ieee802_11_elems *elems) { size_t left = len; u8 *pos = start; @@ -234,7 +233,6 @@ static int ecw2cw(int ecw) return cw - 1; } - static void ieee80211_sta_wmm_params(struct net_device *dev, struct ieee80211_if_sta *ifsta, u8 *wmm_param, size_t wmm_param_len) @@ -318,17 +316,43 @@ static void ieee80211_handle_erp_ie(struct net_device *dev, u8 erp_value) struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_if_sta *ifsta = &sdata->u.sta; int use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0; + int preamble_mode = (erp_value & WLAN_ERP_BARKER_PREAMBLE) != 0; + u8 changes = 0; + DECLARE_MAC_BUF(mac); - if (use_protection != sdata->use_protection) { + if (use_protection != !!(sdata->flags & IEEE80211_SDATA_USE_PROTECTION)) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: CTS protection %s (BSSID=" - MAC_FMT ")\n", + "%s)\n", dev->name, use_protection ? "enabled" : "disabled", - MAC_ARG(ifsta->bssid)); + print_mac(mac, ifsta->bssid)); + } + if (use_protection) + sdata->flags |= IEEE80211_SDATA_USE_PROTECTION; + else + sdata->flags &= ~IEEE80211_SDATA_USE_PROTECTION; + changes |= IEEE80211_ERP_CHANGE_PROTECTION; + } + + if (preamble_mode != !(sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE)) { + if (net_ratelimit()) { + printk(KERN_DEBUG "%s: switched to %s barker preamble" + " (BSSID=%s)\n", + dev->name, + (preamble_mode == WLAN_ERP_PREAMBLE_SHORT) ? + "short" : "long", + print_mac(mac, ifsta->bssid)); } - sdata->use_protection = use_protection; + if (preamble_mode) + sdata->flags &= ~IEEE80211_SDATA_SHORT_PREAMBLE; + else + sdata->flags |= IEEE80211_SDATA_SHORT_PREAMBLE; + changes |= IEEE80211_ERP_CHANGE_PREAMBLE; } + + if (changes) + ieee80211_erp_info_change_notify(dev, changes); } @@ -344,7 +368,7 @@ static void ieee80211_sta_send_associnfo(struct net_device *dev, return; buf = kmalloc(50 + 2 * (ifsta->assocreq_ies_len + - ifsta->assocresp_ies_len), GFP_ATOMIC); + ifsta->assocresp_ies_len), GFP_KERNEL); if (!buf) return; @@ -384,19 +408,21 @@ static void ieee80211_sta_send_associnfo(struct net_device *dev, static void ieee80211_set_associated(struct net_device *dev, - struct ieee80211_if_sta *ifsta, int assoc) + struct ieee80211_if_sta *ifsta, + bool assoc) { + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); union iwreq_data wrqu; - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (ifsta->associated == assoc) + if (!!(ifsta->flags & IEEE80211_STA_ASSOCIATED) == assoc) return; - ifsta->associated = assoc; - if (assoc) { struct ieee80211_sub_if_data *sdata; struct ieee80211_sta_bss *bss; + + ifsta->flags |= IEEE80211_STA_ASSOCIATED; + sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->type != IEEE80211_IF_TYPE_STA) return; @@ -409,18 +435,21 @@ static void ieee80211_set_associated(struct net_device *dev, } netif_carrier_on(dev); - ifsta->prev_bssid_set = 1; + ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET; memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN); memcpy(wrqu.ap_addr.sa_data, sdata->u.sta.bssid, ETH_ALEN); ieee80211_sta_send_associnfo(dev, ifsta); } else { + ifsta->flags &= ~IEEE80211_STA_ASSOCIATED; + netif_carrier_off(dev); - sdata->use_protection = 0; + ieee80211_reset_erp_info(dev); memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); } wrqu.ap_addr.sa_family = ARPHRD_ETHER; wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); ifsta->last_probe = jiffies; + ieee80211_led_assoc(local, assoc); } static void ieee80211_set_disassoc(struct net_device *dev, @@ -447,8 +476,8 @@ static void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb, pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data)); pkt_data->ifindex = sdata->dev->ifindex; - pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT); - pkt_data->do_not_encrypt = !encrypt; + if (!encrypt) + pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT; dev_queue_xmit(skb); } @@ -495,18 +524,20 @@ static void ieee80211_send_auth(struct net_device *dev, static void ieee80211_authenticate(struct net_device *dev, struct ieee80211_if_sta *ifsta) { + DECLARE_MAC_BUF(mac); + ifsta->auth_tries++; if (ifsta->auth_tries > IEEE80211_AUTH_MAX_TRIES) { - printk(KERN_DEBUG "%s: authentication with AP " MAC_FMT + printk(KERN_DEBUG "%s: authentication with AP %s" " timed out\n", - dev->name, MAC_ARG(ifsta->bssid)); + dev->name, print_mac(mac, ifsta->bssid)); ifsta->state = IEEE80211_DISABLED; return; } ifsta->state = IEEE80211_AUTHENTICATE; - printk(KERN_DEBUG "%s: authenticate with AP " MAC_FMT "\n", - dev->name, MAC_ARG(ifsta->bssid)); + printk(KERN_DEBUG "%s: authenticate with AP %s\n", + dev->name, print_mac(mac, ifsta->bssid)); ieee80211_send_auth(dev, ifsta, 1, NULL, 0, 0); @@ -559,7 +590,7 @@ static void ieee80211_send_assoc(struct net_device *dev, memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); - if (ifsta->prev_bssid_set) { + if (ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) { skb_put(skb, 10); mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, IEEE80211_STYPE_REASSOC_REQ); @@ -589,8 +620,6 @@ static void ieee80211_send_assoc(struct net_device *dev, *pos++ = len; for (i = 0; i < len; i++) { int rate = mode->rates[i].rate; - if (mode->mode == MODE_ATHEROS_TURBO) - rate /= 2; *pos++ = (u8) (rate / 5); } @@ -600,8 +629,6 @@ static void ieee80211_send_assoc(struct net_device *dev, *pos++ = mode->num_rates - len; for (i = len; i < mode->num_rates; i++) { int rate = mode->rates[i].rate; - if (mode->mode == MODE_ATHEROS_TURBO) - rate /= 2; *pos++ = (u8) (rate / 5); } } @@ -611,7 +638,7 @@ static void ieee80211_send_assoc(struct net_device *dev, memcpy(pos, ifsta->extra_ie, ifsta->extra_ie_len); } - if (wmm && ifsta->wmm_enabled) { + if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { pos = skb_put(skb, 9); *pos++ = WLAN_EID_VENDOR_SPECIFIC; *pos++ = 7; /* len */ @@ -626,7 +653,7 @@ static void ieee80211_send_assoc(struct net_device *dev, kfree(ifsta->assocreq_ies); ifsta->assocreq_ies_len = (skb->data + skb->len) - ies; - ifsta->assocreq_ies = kmalloc(ifsta->assocreq_ies_len, GFP_ATOMIC); + ifsta->assocreq_ies = kmalloc(ifsta->assocreq_ies_len, GFP_KERNEL); if (ifsta->assocreq_ies) memcpy(ifsta->assocreq_ies, ies, ifsta->assocreq_ies_len); @@ -698,8 +725,8 @@ static int ieee80211_privacy_mismatch(struct net_device *dev, struct ieee80211_sta_bss *bss; int res = 0; - if (!ifsta || ifsta->mixed_cell || - ifsta->key_mgmt != IEEE80211_KEY_MGMT_NONE) + if (!ifsta || (ifsta->flags & IEEE80211_STA_MIXED_CELL) || + ifsta->key_management_enabled) return 0; bss = ieee80211_rx_bss_get(dev, ifsta->bssid); @@ -719,18 +746,20 @@ static int ieee80211_privacy_mismatch(struct net_device *dev, static void ieee80211_associate(struct net_device *dev, struct ieee80211_if_sta *ifsta) { + DECLARE_MAC_BUF(mac); + ifsta->assoc_tries++; if (ifsta->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) { - printk(KERN_DEBUG "%s: association with AP " MAC_FMT + printk(KERN_DEBUG "%s: association with AP %s" " timed out\n", - dev->name, MAC_ARG(ifsta->bssid)); + dev->name, print_mac(mac, ifsta->bssid)); ifsta->state = IEEE80211_DISABLED; return; } ifsta->state = IEEE80211_ASSOCIATE; - printk(KERN_DEBUG "%s: associate with AP " MAC_FMT "\n", - dev->name, MAC_ARG(ifsta->bssid)); + printk(KERN_DEBUG "%s: associate with AP %s\n", + dev->name, print_mac(mac, ifsta->bssid)); if (ieee80211_privacy_mismatch(dev, ifsta)) { printk(KERN_DEBUG "%s: mismatch in privacy configuration and " "mixed-cell disabled - abort association\n", dev->name); @@ -750,6 +779,7 @@ static void ieee80211_associated(struct net_device *dev, struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta; int disassoc; + DECLARE_MAC_BUF(mac); /* TODO: start monitoring current AP signal quality and number of * missed beacons. Scan other channels every now and then and search @@ -760,29 +790,27 @@ static void ieee80211_associated(struct net_device *dev, sta = sta_info_get(local, ifsta->bssid); if (!sta) { - printk(KERN_DEBUG "%s: No STA entry for own AP " MAC_FMT "\n", - dev->name, MAC_ARG(ifsta->bssid)); + printk(KERN_DEBUG "%s: No STA entry for own AP %s\n", + dev->name, print_mac(mac, ifsta->bssid)); disassoc = 1; } else { disassoc = 0; if (time_after(jiffies, sta->last_rx + IEEE80211_MONITORING_INTERVAL)) { - if (ifsta->probereq_poll) { + if (ifsta->flags & IEEE80211_STA_PROBEREQ_POLL) { printk(KERN_DEBUG "%s: No ProbeResp from " - "current AP " MAC_FMT " - assume out of " + "current AP %s - assume out of " "range\n", - dev->name, MAC_ARG(ifsta->bssid)); + dev->name, print_mac(mac, ifsta->bssid)); disassoc = 1; - sta_info_free(sta, 0); - ifsta->probereq_poll = 0; - } else { + sta_info_free(sta); + } else ieee80211_send_probe_req(dev, ifsta->bssid, local->scan_ssid, local->scan_ssid_len); - ifsta->probereq_poll = 1; - } + ifsta->flags ^= IEEE80211_STA_PROBEREQ_POLL; } else { - ifsta->probereq_poll = 0; + ifsta->flags &= ~IEEE80211_STA_PROBEREQ_POLL; if (time_after(jiffies, ifsta->last_probe + IEEE80211_PROBE_INTERVAL)) { ifsta->last_probe = jiffies; @@ -862,10 +890,7 @@ static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst, pos = skb_put(skb, 1); supp_rates[1]++; } - if (mode->mode == MODE_ATHEROS_TURBO) - *pos = rate->rate / 10; - else - *pos = rate->rate / 5; + *pos = rate->rate / 5; } ieee80211_sta_tx(dev, skb, 0); @@ -876,7 +901,7 @@ static int ieee80211_sta_wep_configured(struct net_device *dev) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (!sdata || !sdata->default_key || - sdata->default_key->alg != ALG_WEP) + sdata->default_key->conf.alg != ALG_WEP) return 0; return 1; } @@ -886,7 +911,7 @@ static void ieee80211_auth_completed(struct net_device *dev, struct ieee80211_if_sta *ifsta) { printk(KERN_DEBUG "%s: authenticated\n", dev->name); - ifsta->authenticated = 1; + ifsta->flags |= IEEE80211_STA_AUTHENTICATED; ieee80211_associate(dev, ifsta); } @@ -924,37 +949,38 @@ static void ieee80211_rx_mgmt_auth(struct net_device *dev, { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); u16 auth_alg, auth_transaction, status_code; + DECLARE_MAC_BUF(mac); if (ifsta->state != IEEE80211_AUTHENTICATE && sdata->type != IEEE80211_IF_TYPE_IBSS) { printk(KERN_DEBUG "%s: authentication frame received from " - MAC_FMT ", but not in authenticate state - ignored\n", - dev->name, MAC_ARG(mgmt->sa)); + "%s, but not in authenticate state - ignored\n", + dev->name, print_mac(mac, mgmt->sa)); return; } if (len < 24 + 6) { printk(KERN_DEBUG "%s: too short (%zd) authentication frame " - "received from " MAC_FMT " - ignored\n", - dev->name, len, MAC_ARG(mgmt->sa)); + "received from %s - ignored\n", + dev->name, len, print_mac(mac, mgmt->sa)); return; } if (sdata->type != IEEE80211_IF_TYPE_IBSS && memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) { printk(KERN_DEBUG "%s: authentication frame received from " - "unknown AP (SA=" MAC_FMT " BSSID=" MAC_FMT ") - " - "ignored\n", dev->name, MAC_ARG(mgmt->sa), - MAC_ARG(mgmt->bssid)); + "unknown AP (SA=%s BSSID=%s) - " + "ignored\n", dev->name, print_mac(mac, mgmt->sa), + print_mac(mac, mgmt->bssid)); return; } if (sdata->type != IEEE80211_IF_TYPE_IBSS && memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) { printk(KERN_DEBUG "%s: authentication frame received from " - "unknown BSSID (SA=" MAC_FMT " BSSID=" MAC_FMT ") - " - "ignored\n", dev->name, MAC_ARG(mgmt->sa), - MAC_ARG(mgmt->bssid)); + "unknown BSSID (SA=%s BSSID=%s) - " + "ignored\n", dev->name, print_mac(mac, mgmt->sa), + print_mac(mac, mgmt->bssid)); return; } @@ -962,9 +988,9 @@ static void ieee80211_rx_mgmt_auth(struct net_device *dev, auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); status_code = le16_to_cpu(mgmt->u.auth.status_code); - printk(KERN_DEBUG "%s: RX authentication from " MAC_FMT " (alg=%d " + printk(KERN_DEBUG "%s: RX authentication from %s (alg=%d " "transaction=%d status=%d)\n", - dev->name, MAC_ARG(mgmt->sa), auth_alg, + dev->name, print_mac(mac, mgmt->sa), auth_alg, auth_transaction, status_code); if (sdata->type == IEEE80211_IF_TYPE_IBSS) { @@ -1051,29 +1077,30 @@ static void ieee80211_rx_mgmt_deauth(struct net_device *dev, size_t len) { u16 reason_code; + DECLARE_MAC_BUF(mac); if (len < 24 + 2) { printk(KERN_DEBUG "%s: too short (%zd) deauthentication frame " - "received from " MAC_FMT " - ignored\n", - dev->name, len, MAC_ARG(mgmt->sa)); + "received from %s - ignored\n", + dev->name, len, print_mac(mac, mgmt->sa)); return; } if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) { printk(KERN_DEBUG "%s: deauthentication frame received from " - "unknown AP (SA=" MAC_FMT " BSSID=" MAC_FMT ") - " - "ignored\n", dev->name, MAC_ARG(mgmt->sa), - MAC_ARG(mgmt->bssid)); + "unknown AP (SA=%s BSSID=%s) - " + "ignored\n", dev->name, print_mac(mac, mgmt->sa), + print_mac(mac, mgmt->bssid)); return; } reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); - printk(KERN_DEBUG "%s: RX deauthentication from " MAC_FMT + printk(KERN_DEBUG "%s: RX deauthentication from %s" " (reason=%d)\n", - dev->name, MAC_ARG(mgmt->sa), reason_code); + dev->name, print_mac(mac, mgmt->sa), reason_code); - if (ifsta->authenticated) { + if (ifsta->flags & IEEE80211_STA_AUTHENTICATED) { printk(KERN_DEBUG "%s: deauthenticated\n", dev->name); } @@ -1086,7 +1113,7 @@ static void ieee80211_rx_mgmt_deauth(struct net_device *dev, } ieee80211_set_disassoc(dev, ifsta, 1); - ifsta->authenticated = 0; + ifsta->flags &= ~IEEE80211_STA_AUTHENTICATED; } @@ -1096,29 +1123,30 @@ static void ieee80211_rx_mgmt_disassoc(struct net_device *dev, size_t len) { u16 reason_code; + DECLARE_MAC_BUF(mac); if (len < 24 + 2) { printk(KERN_DEBUG "%s: too short (%zd) disassociation frame " - "received from " MAC_FMT " - ignored\n", - dev->name, len, MAC_ARG(mgmt->sa)); + "received from %s - ignored\n", + dev->name, len, print_mac(mac, mgmt->sa)); return; } if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) { printk(KERN_DEBUG "%s: disassociation frame received from " - "unknown AP (SA=" MAC_FMT " BSSID=" MAC_FMT ") - " - "ignored\n", dev->name, MAC_ARG(mgmt->sa), - MAC_ARG(mgmt->bssid)); + "unknown AP (SA=%s BSSID=%s) - " + "ignored\n", dev->name, print_mac(mac, mgmt->sa), + print_mac(mac, mgmt->bssid)); return; } reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); - printk(KERN_DEBUG "%s: RX disassociation from " MAC_FMT + printk(KERN_DEBUG "%s: RX disassociation from %s" " (reason=%d)\n", - dev->name, MAC_ARG(mgmt->sa), reason_code); + dev->name, print_mac(mac, mgmt->sa), reason_code); - if (ifsta->associated) + if (ifsta->flags & IEEE80211_STA_ASSOCIATED) printk(KERN_DEBUG "%s: disassociated\n", dev->name); if (ifsta->state == IEEE80211_ASSOCIATED) { @@ -1145,29 +1173,30 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev, struct ieee802_11_elems elems; u8 *pos; int i, j; + DECLARE_MAC_BUF(mac); /* AssocResp and ReassocResp have identical structure, so process both * of them in this function. */ if (ifsta->state != IEEE80211_ASSOCIATE) { printk(KERN_DEBUG "%s: association frame received from " - MAC_FMT ", but not in associate state - ignored\n", - dev->name, MAC_ARG(mgmt->sa)); + "%s, but not in associate state - ignored\n", + dev->name, print_mac(mac, mgmt->sa)); return; } if (len < 24 + 6) { printk(KERN_DEBUG "%s: too short (%zd) association frame " - "received from " MAC_FMT " - ignored\n", - dev->name, len, MAC_ARG(mgmt->sa)); + "received from %s - ignored\n", + dev->name, len, print_mac(mac, mgmt->sa)); return; } if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) { printk(KERN_DEBUG "%s: association frame received from " - "unknown AP (SA=" MAC_FMT " BSSID=" MAC_FMT ") - " - "ignored\n", dev->name, MAC_ARG(mgmt->sa), - MAC_ARG(mgmt->bssid)); + "unknown AP (SA=%s BSSID=%s) - " + "ignored\n", dev->name, print_mac(mac, mgmt->sa), + print_mac(mac, mgmt->bssid)); return; } @@ -1179,16 +1208,18 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev, "set\n", dev->name, aid); aid &= ~(BIT(15) | BIT(14)); - printk(KERN_DEBUG "%s: RX %sssocResp from " MAC_FMT " (capab=0x%x " + printk(KERN_DEBUG "%s: RX %sssocResp from %s (capab=0x%x " "status=%d aid=%d)\n", - dev->name, reassoc ? "Rea" : "A", MAC_ARG(mgmt->sa), + dev->name, reassoc ? "Rea" : "A", print_mac(mac, mgmt->sa), capab_info, status_code, aid); if (status_code != WLAN_STATUS_SUCCESS) { printk(KERN_DEBUG "%s: AP denied association (code=%d)\n", dev->name, status_code); - if (status_code == WLAN_STATUS_REASSOC_NO_ASSOC) - ifsta->prev_bssid_set = 0; + /* if this was a reassociation, ensure we try a "full" + * association next time. This works around some broken APs + * which do not correctly reject reassociation requests. */ + ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET; return; } @@ -1224,7 +1255,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev, kfree(ifsta->assocresp_ies); ifsta->assocresp_ies_len = len - (pos - (u8 *) mgmt); - ifsta->assocresp_ies = kmalloc(ifsta->assocresp_ies_len, GFP_ATOMIC); + ifsta->assocresp_ies = kmalloc(ifsta->assocresp_ies_len, GFP_KERNEL); if (ifsta->assocresp_ies) memcpy(ifsta->assocresp_ies, pos, ifsta->assocresp_ies_len); @@ -1234,7 +1265,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev, sta = sta_info_get(local, ifsta->bssid); if (!sta) { struct ieee80211_sta_bss *bss; - sta = sta_info_add(local, dev, ifsta->bssid, GFP_ATOMIC); + sta = sta_info_add(local, dev, ifsta->bssid, GFP_KERNEL); if (!sta) { printk(KERN_DEBUG "%s: failed to add STA entry for the" " AP\n", dev->name); @@ -1250,23 +1281,18 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev, } sta->dev = dev; - sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; - sta->assoc_ap = 1; + sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP; rates = 0; mode = local->oper_hw_mode; for (i = 0; i < elems.supp_rates_len; i++) { int rate = (elems.supp_rates[i] & 0x7f) * 5; - if (mode->mode == MODE_ATHEROS_TURBO) - rate *= 2; for (j = 0; j < mode->num_rates; j++) if (mode->rates[j].rate == rate) rates |= BIT(j); } for (i = 0; i < elems.ext_supp_rates_len; i++) { int rate = (elems.ext_supp_rates[i] & 0x7f) * 5; - if (mode->mode == MODE_ATHEROS_TURBO) - rate *= 2; for (j = 0; j < mode->num_rates; j++) if (mode->rates[j].rate == rate) rates |= BIT(j); @@ -1275,7 +1301,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev, rate_control_rate_init(sta, local); - if (elems.wmm_param && ifsta->wmm_enabled) { + if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { sta->flags |= WLAN_STA_WME; ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param, elems.wmm_param_len); @@ -1418,14 +1444,16 @@ static void ieee80211_rx_bss_info(struct net_device *dev, struct sta_info *sta; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); u64 timestamp; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); if (!beacon && memcmp(mgmt->da, dev->dev_addr, ETH_ALEN)) return; /* ignore ProbeResp to foreign address */ #if 0 - printk(KERN_DEBUG "%s: RX %s from " MAC_FMT " to " MAC_FMT "\n", + printk(KERN_DEBUG "%s: RX %s from %s to %s\n", dev->name, beacon ? "Beacon" : "Probe Response", - MAC_ARG(mgmt->sa), MAC_ARG(mgmt->da)); + print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->da)); #endif baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; @@ -1444,10 +1472,10 @@ static void ieee80211_rx_bss_info(struct net_device *dev, else tsf = -1LLU; if (time_after(jiffies, last_tsf_debug + 5 * HZ)) { - printk(KERN_DEBUG "RX beacon SA=" MAC_FMT " BSSID=" - MAC_FMT " TSF=0x%llx BCN=0x%llx diff=%lld " + printk(KERN_DEBUG "RX beacon SA=%s BSSID=" + "%s TSF=0x%llx BCN=0x%llx diff=%lld " "@%lu\n", - MAC_ARG(mgmt->sa), MAC_ARG(mgmt->bssid), + print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->bssid), (unsigned long long)tsf, (unsigned long long)timestamp, (unsigned long long)(tsf - timestamp), @@ -1486,8 +1514,6 @@ static void ieee80211_rx_bss_info(struct net_device *dev, rate = elems.ext_supp_rates [i - elems.supp_rates_len]; own_rate = 5 * (rate & 0x7f); - if (mode->mode == MODE_ATHEROS_TURBO) - own_rate *= 2; for (j = 0; j < num_rates; j++) if (rates[j].rate == own_rate) supp_rates |= BIT(j); @@ -1503,9 +1529,9 @@ static void ieee80211_rx_bss_info(struct net_device *dev, } if (sta->supp_rates != prev_rates) { printk(KERN_DEBUG "%s: updated supp_rates set for " - MAC_FMT " based on beacon info (0x%x & 0x%x -> " + "%s based on beacon info (0x%x & 0x%x -> " "0x%x)\n", - dev->name, MAC_ARG(sta->addr), prev_rates, + dev->name, print_mac(mac, sta->addr), prev_rates, supp_rates, sta->supp_rates); } sta_info_put(sta); @@ -1672,7 +1698,7 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev, return; ifsta = &sdata->u.sta; - if (!ifsta->associated || + if (!(ifsta->flags & IEEE80211_STA_ASSOCIATED) || memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) return; @@ -1688,7 +1714,7 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev, if (elems.erp_info && elems.erp_info_len >= 1) ieee80211_handle_erp_ie(dev, elems.erp_info[0]); - if (elems.wmm_param && ifsta->wmm_enabled) { + if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param, elems.wmm_param_len); } @@ -1707,6 +1733,11 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev, struct sk_buff *skb; struct ieee80211_mgmt *resp; u8 *pos, *end; + DECLARE_MAC_BUF(mac); +#ifdef CONFIG_MAC80211_IBSS_DEBUG + DECLARE_MAC_BUF(mac2); + DECLARE_MAC_BUF(mac3); +#endif if (sdata->type != IEEE80211_IF_TYPE_IBSS || ifsta->state != IEEE80211_IBSS_JOINED || @@ -1719,10 +1750,10 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev, tx_last_beacon = 1; #ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG "%s: RX ProbeReq SA=" MAC_FMT " DA=" MAC_FMT " BSSID=" - MAC_FMT " (tx_last_beacon=%d)\n", - dev->name, MAC_ARG(mgmt->sa), MAC_ARG(mgmt->da), - MAC_ARG(mgmt->bssid), tx_last_beacon); + printk(KERN_DEBUG "%s: RX ProbeReq SA=%s DA=%s BSSID=" + "%s (tx_last_beacon=%d)\n", + dev->name, print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->da), + print_mac(mac3, mgmt->bssid), tx_last_beacon); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ if (!tx_last_beacon) @@ -1738,8 +1769,8 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev, pos + 2 + pos[1] > end) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq " - "from " MAC_FMT "\n", - dev->name, MAC_ARG(mgmt->sa)); + "from %s\n", + dev->name, print_mac(mac, mgmt->sa)); } return; } @@ -1751,15 +1782,15 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev, } /* Reply with ProbeResp */ - skb = skb_copy(ifsta->probe_resp, GFP_ATOMIC); + skb = skb_copy(ifsta->probe_resp, GFP_KERNEL); if (!skb) return; resp = (struct ieee80211_mgmt *) skb->data; memcpy(resp->da, mgmt->sa, ETH_ALEN); #ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG "%s: Sending ProbeResp to " MAC_FMT "\n", - dev->name, MAC_ARG(resp->da)); + printk(KERN_DEBUG "%s: Sending ProbeResp to %s\n", + dev->name, print_mac(mac, resp->da)); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ ieee80211_sta_tx(dev, skb, 0); } @@ -1890,7 +1921,7 @@ static int ieee80211_sta_active_ibss(struct net_device *dev) int active = 0; struct sta_info *sta; - spin_lock_bh(&local->sta_lock); + read_lock_bh(&local->sta_lock); list_for_each_entry(sta, &local->sta_list, list) { if (sta->dev == dev && time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL, @@ -1899,7 +1930,7 @@ static int ieee80211_sta_active_ibss(struct net_device *dev) break; } } - spin_unlock_bh(&local->sta_lock); + read_unlock_bh(&local->sta_lock); return active; } @@ -1909,16 +1940,25 @@ static void ieee80211_sta_expire(struct net_device *dev) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta, *tmp; + LIST_HEAD(tmp_list); + DECLARE_MAC_BUF(mac); - spin_lock_bh(&local->sta_lock); + write_lock_bh(&local->sta_lock); list_for_each_entry_safe(sta, tmp, &local->sta_list, list) if (time_after(jiffies, sta->last_rx + IEEE80211_IBSS_INACTIVITY_LIMIT)) { - printk(KERN_DEBUG "%s: expiring inactive STA " MAC_FMT - "\n", dev->name, MAC_ARG(sta->addr)); - sta_info_free(sta, 1); + printk(KERN_DEBUG "%s: expiring inactive STA %s\n", + dev->name, print_mac(mac, sta->addr)); + __sta_info_get(sta); + sta_info_remove(sta); + list_add(&sta->list, &tmp_list); } - spin_unlock_bh(&local->sta_lock); + write_unlock_bh(&local->sta_lock); + + list_for_each_entry_safe(sta, tmp, &tmp_list, list) { + sta_info_free(sta); + sta_info_put(sta); + } } @@ -2047,7 +2087,8 @@ static void ieee80211_sta_reset_auth(struct net_device *dev, printk(KERN_DEBUG "%s: Initial auth_alg=%d\n", dev->name, ifsta->auth_alg); ifsta->auth_transaction = -1; - ifsta->associated = ifsta->auth_tries = ifsta->assoc_tries = 0; + ifsta->flags &= ~IEEE80211_STA_ASSOCIATED; + ifsta->auth_tries = ifsta->assoc_tries = 0; netif_carrier_off(dev); } @@ -2061,8 +2102,10 @@ void ieee80211_sta_req_auth(struct net_device *dev, if (sdata->type != IEEE80211_IF_TYPE_STA) return; - if ((ifsta->bssid_set || ifsta->auto_bssid_sel) && - (ifsta->ssid_set || ifsta->auto_ssid_sel)) { + if ((ifsta->flags & (IEEE80211_STA_BSSID_SET | + IEEE80211_STA_AUTO_BSSID_SEL)) && + (ifsta->flags & (IEEE80211_STA_SSID_SET | + IEEE80211_STA_AUTO_SSID_SEL))) { set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request); queue_work(local->hw.workqueue, &ifsta->work); } @@ -2076,7 +2119,7 @@ static int ieee80211_sta_match_ssid(struct ieee80211_if_sta *ifsta, if (!memcmp(ifsta->ssid, ssid, ssid_len)) return 1; - if (ifsta->auto_bssid_sel) + if (ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL) return 0; hidden_ssid = 1; @@ -2105,8 +2148,8 @@ static int ieee80211_sta_config_auth(struct net_device *dev, struct ieee80211_sta_bss *bss, *selected = NULL; int top_rssi = 0, freq; - if (!ifsta->auto_channel_sel && !ifsta->auto_bssid_sel && - !ifsta->auto_ssid_sel) { + if (!(ifsta->flags & (IEEE80211_STA_AUTO_SSID_SEL | + IEEE80211_STA_AUTO_BSSID_SEL | IEEE80211_STA_AUTO_CHANNEL_SEL))) { ifsta->state = IEEE80211_AUTHENTICATE; ieee80211_sta_reset_auth(dev, ifsta); return 0; @@ -2122,14 +2165,15 @@ static int ieee80211_sta_config_auth(struct net_device *dev, !!sdata->default_key) continue; - if (!ifsta->auto_channel_sel && bss->freq != freq) + if (!(ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL) && + bss->freq != freq) continue; - if (!ifsta->auto_bssid_sel && + if (!(ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL) && memcmp(bss->bssid, ifsta->bssid, ETH_ALEN)) continue; - if (!ifsta->auto_ssid_sel && + if (!(ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) && !ieee80211_sta_match_ssid(ifsta, bss->ssid, bss->ssid_len)) continue; @@ -2144,7 +2188,7 @@ static int ieee80211_sta_config_auth(struct net_device *dev, if (selected) { ieee80211_set_channel(local, -1, selected->freq); - if (!ifsta->ssid_set) + if (!(ifsta->flags & IEEE80211_STA_SSID_SET)) ieee80211_sta_set_ssid(dev, selected->ssid, selected->ssid_len); ieee80211_sta_set_bssid(dev, selected->bssid); @@ -2154,7 +2198,7 @@ static int ieee80211_sta_config_auth(struct net_device *dev, return 0; } else { if (ifsta->state != IEEE80211_AUTHENTICATE) { - if (ifsta->auto_ssid_sel) + if (ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) ieee80211_sta_start_scan(dev, NULL, 0); else ieee80211_sta_start_scan(dev, ifsta->ssid, @@ -2271,8 +2315,9 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, "for IBSS beacon\n", dev->name); break; } - control.tx_rate = (local->short_preamble && - (rate->flags & IEEE80211_RATE_PREAMBLE2)) ? + control.tx_rate = + ((sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE) && + (rate->flags & IEEE80211_RATE_PREAMBLE2)) ? rate->val2 : rate->val; control.antenna_sel_tx = local->hw.conf.antenna_sel_tx; control.power_level = local->hw.conf.power_level; @@ -2303,8 +2348,6 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, mode = local->oper_hw_mode; for (i = 0; i < bss->supp_rates_len; i++) { int bitrate = (bss->supp_rates[i] & 0x7f) * 5; - if (mode->mode == MODE_ATHEROS_TURBO) - bitrate *= 2; for (j = 0; j < mode->num_rates; j++) if (mode->rates[j].rate == bitrate) rates |= BIT(j); @@ -2336,6 +2379,7 @@ static int ieee80211_sta_create_ibss(struct net_device *dev, struct ieee80211_hw_mode *mode; u8 bssid[ETH_ALEN], *pos; int i; + DECLARE_MAC_BUF(mac); #if 0 /* Easier testing, use fixed BSSID. */ @@ -2351,8 +2395,8 @@ static int ieee80211_sta_create_ibss(struct net_device *dev, bssid[0] |= 0x02; #endif - printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID " MAC_FMT "\n", - dev->name, MAC_ARG(bssid)); + printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %s\n", + dev->name, print_mac(mac, bssid)); bss = ieee80211_rx_bss_add(dev, bssid); if (!bss) @@ -2377,8 +2421,6 @@ static int ieee80211_sta_create_ibss(struct net_device *dev, pos = bss->supp_rates; for (i = 0; i < mode->num_rates; i++) { int rate = mode->rates[i].rate; - if (mode->mode == MODE_ATHEROS_TURBO) - rate /= 2; *pos++ = (u8) (rate / 5); } @@ -2394,6 +2436,8 @@ static int ieee80211_sta_find_ibss(struct net_device *dev, int found = 0; u8 bssid[ETH_ALEN]; int active_ibss; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); if (ifsta->ssid_len == 0) return -EINVAL; @@ -2410,8 +2454,8 @@ static int ieee80211_sta_find_ibss(struct net_device *dev, || !(bss->capability & WLAN_CAPABILITY_IBSS)) continue; #ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG " bssid=" MAC_FMT " found\n", - MAC_ARG(bss->bssid)); + printk(KERN_DEBUG " bssid=%s found\n", + print_mac(mac, bss->bssid)); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ memcpy(bssid, bss->bssid, ETH_ALEN); found = 1; @@ -2421,14 +2465,14 @@ static int ieee80211_sta_find_ibss(struct net_device *dev, spin_unlock_bh(&local->sta_bss_lock); #ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG " sta_find_ibss: selected " MAC_FMT " current " - MAC_FMT "\n", MAC_ARG(bssid), MAC_ARG(ifsta->bssid)); + printk(KERN_DEBUG " sta_find_ibss: selected %s current " + "%s\n", print_mac(mac, bssid), print_mac(mac2, ifsta->bssid)); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0 && (bss = ieee80211_rx_bss_get(dev, bssid))) { - printk(KERN_DEBUG "%s: Selected IBSS BSSID " MAC_FMT + printk(KERN_DEBUG "%s: Selected IBSS BSSID %s" " based on configured SSID\n", - dev->name, MAC_ARG(bssid)); + dev->name, print_mac(mac, bssid)); return ieee80211_sta_join_ibss(dev, ifsta, bss); } #ifdef CONFIG_MAC80211_IBSS_DEBUG @@ -2451,10 +2495,10 @@ static int ieee80211_sta_find_ibss(struct net_device *dev, if (time_after(jiffies, ifsta->ibss_join_req + IEEE80211_IBSS_JOIN_TIMEOUT)) { - if (ifsta->create_ibss && + if ((ifsta->flags & IEEE80211_STA_CREATE_IBSS) && local->oper_channel->flag & IEEE80211_CHAN_W_IBSS) return ieee80211_sta_create_ibss(dev, ifsta); - if (ifsta->create_ibss) { + if (ifsta->flags & IEEE80211_STA_CREATE_IBSS) { printk(KERN_DEBUG "%s: IBSS not allowed on the" " configured channel %d (%d MHz)\n", dev->name, local->hw.conf.channel, @@ -2515,13 +2559,17 @@ int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len) ifsta = &sdata->u.sta; if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0) - ifsta->prev_bssid_set = 0; + ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET; memcpy(ifsta->ssid, ssid, len); memset(ifsta->ssid + len, 0, IEEE80211_MAX_SSID_LEN - len); ifsta->ssid_len = len; - ifsta->ssid_set = len ? 1 : 0; - if (sdata->type == IEEE80211_IF_TYPE_IBSS && !ifsta->bssid_set) { + if (len) + ifsta->flags |= IEEE80211_STA_SSID_SET; + else + ifsta->flags &= ~IEEE80211_STA_SSID_SET; + if (sdata->type == IEEE80211_IF_TYPE_IBSS && + !(ifsta->flags & IEEE80211_STA_BSSID_SET)) { ifsta->ibss_join_req = jiffies; ifsta->state = IEEE80211_IBSS_SEARCH; return ieee80211_sta_find_ibss(dev, ifsta); @@ -2559,10 +2607,11 @@ int ieee80211_sta_set_bssid(struct net_device *dev, u8 *bssid) } } - if (!is_valid_ether_addr(bssid)) - ifsta->bssid_set = 0; + if (is_valid_ether_addr(bssid)) + ifsta->flags |= IEEE80211_STA_BSSID_SET; else - ifsta->bssid_set = 1; + ifsta->flags &= ~IEEE80211_STA_BSSID_SET; + return 0; } @@ -2613,35 +2662,41 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) printk(KERN_DEBUG "%s: failed to restore operational" "channel after scan\n", dev->name); - if (!(local->hw.flags & IEEE80211_HW_NO_PROBE_FILTERING) && - ieee80211_if_config(dev)) - printk(KERN_DEBUG "%s: failed to restore operational" - "BSSID after scan\n", dev->name); + + netif_tx_lock_bh(local->mdev); + local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC; + local->ops->configure_filter(local_to_hw(local), + FIF_BCN_PRBRESP_PROMISC, + &local->filter_flags, + local->mdev->mc_count, + local->mdev->mc_list); + + netif_tx_unlock_bh(local->mdev); memset(&wrqu, 0, sizeof(wrqu)); wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); - read_lock(&local->sub_if_lock); - list_for_each_entry(sdata, &local->sub_if_list, list) { + rcu_read_lock(); + list_for_each_entry_rcu(sdata, &local->interfaces, list) { /* No need to wake the master device. */ if (sdata->dev == local->mdev) continue; if (sdata->type == IEEE80211_IF_TYPE_STA) { - if (sdata->u.sta.associated) + if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) ieee80211_send_nullfunc(local, sdata, 0); ieee80211_sta_timer((unsigned long)sdata); } netif_wake_queue(sdata->dev); } - read_unlock(&local->sub_if_lock); + rcu_read_unlock(); sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->type == IEEE80211_IF_TYPE_IBSS) { struct ieee80211_if_sta *ifsta = &sdata->u.sta; - if (!ifsta->bssid_set || + if (!(ifsta->flags & IEEE80211_STA_BSSID_SET) || (!ifsta->state == IEEE80211_IBSS_JOINED && !ieee80211_sta_active_ibss(dev))) ieee80211_sta_find_ibss(dev, ifsta); @@ -2773,8 +2828,8 @@ static int ieee80211_sta_start_scan(struct net_device *dev, local->sta_scanning = 1; - read_lock(&local->sub_if_lock); - list_for_each_entry(sdata, &local->sub_if_list, list) { + rcu_read_lock(); + list_for_each_entry_rcu(sdata, &local->interfaces, list) { /* Don't stop the master interface, otherwise we can't transmit * probes! */ @@ -2783,10 +2838,10 @@ static int ieee80211_sta_start_scan(struct net_device *dev, netif_stop_queue(sdata->dev); if (sdata->type == IEEE80211_IF_TYPE_STA && - sdata->u.sta.associated) + (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED)) ieee80211_send_nullfunc(local, sdata, 1); } - read_unlock(&local->sub_if_lock); + rcu_read_unlock(); if (ssid) { local->scan_ssid_len = ssid_len; @@ -2800,10 +2855,14 @@ static int ieee80211_sta_start_scan(struct net_device *dev, local->scan_channel_idx = 0; local->scan_dev = dev; - if (!(local->hw.flags & IEEE80211_HW_NO_PROBE_FILTERING) && - ieee80211_if_config(dev)) - printk(KERN_DEBUG "%s: failed to set BSSID for scan\n", - dev->name); + netif_tx_lock_bh(local->mdev); + local->filter_flags |= FIF_BCN_PRBRESP_PROMISC; + local->ops->configure_filter(local_to_hw(local), + FIF_BCN_PRBRESP_PROMISC, + &local->filter_flags, + local->mdev->mc_count, + local->mdev->mc_list); + netif_tx_unlock_bh(local->mdev); /* TODO: start scan as soon as all nullfunc frames are ACKed */ queue_delayed_work(local->hw.workqueue, &local->scan_work, @@ -3041,19 +3100,20 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + DECLARE_MAC_BUF(mac); /* TODO: Could consider removing the least recently used entry and * allow new one to be added. */ if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: No room for a new IBSS STA " - "entry " MAC_FMT "\n", dev->name, MAC_ARG(addr)); + "entry %s\n", dev->name, print_mac(mac, addr)); } return NULL; } - printk(KERN_DEBUG "%s: Adding new IBSS station " MAC_FMT " (dev=%s)\n", - local->mdev->name, MAC_ARG(addr), dev->name); + printk(KERN_DEBUG "%s: Adding new IBSS station %s (dev=%s)\n", + wiphy_name(local->hw.wiphy), print_mac(mac, addr), dev->name); sta = sta_info_add(local, dev, addr, GFP_ATOMIC); if (!sta) @@ -3096,7 +3156,7 @@ int ieee80211_sta_disassociate(struct net_device *dev, u16 reason) if (sdata->type != IEEE80211_IF_TYPE_STA) return -EINVAL; - if (!ifsta->associated) + if (!(ifsta->flags & IEEE80211_STA_ASSOCIATED)) return -1; ieee80211_send_disassoc(dev, ifsta, reason); diff --git a/net/mac80211/key.c b/net/mac80211/key.c new file mode 100644 index 0000000..0b2328f --- /dev/null +++ b/net/mac80211/key.c @@ -0,0 +1,279 @@ +/* + * Copyright 2002-2005, Instant802 Networks, Inc. + * Copyright 2005-2006, Devicescape Software, Inc. + * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> + * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/if_ether.h> +#include <linux/etherdevice.h> +#include <linux/list.h> +#include <linux/rcupdate.h> +#include <net/mac80211.h> +#include "ieee80211_i.h" +#include "debugfs_key.h" +#include "aes_ccm.h" + + +/* + * Key handling basics + * + * Key handling in mac80211 is done based on per-interface (sub_if_data) + * keys and per-station keys. Since each station belongs to an interface, + * each station key also belongs to that interface. + * + * Hardware acceleration is done on a best-effort basis, for each key + * that is eligible the hardware is asked to enable that key but if + * it cannot do that they key is simply kept for software encryption. + * There is currently no way of knowing this except by looking into + * debugfs. + * + * All operations here are called under RTNL so no extra locking is + * required. + */ + +static const u8 bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; +static const u8 zero_addr[ETH_ALEN]; + +static const u8 *get_mac_for_key(struct ieee80211_key *key) +{ + const u8 *addr = bcast_addr; + + /* + * If we're an AP we won't ever receive frames with a non-WEP + * group key so we tell the driver that by using the zero MAC + * address to indicate a transmit-only key. + */ + if (key->conf.alg != ALG_WEP && + (key->sdata->type == IEEE80211_IF_TYPE_AP || + key->sdata->type == IEEE80211_IF_TYPE_VLAN)) + addr = zero_addr; + + if (key->sta) + addr = key->sta->addr; + + return addr; +} + +static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) +{ + const u8 *addr; + int ret; + DECLARE_MAC_BUF(mac); + + if (!key->local->ops->set_key) + return; + + addr = get_mac_for_key(key); + + ret = key->local->ops->set_key(local_to_hw(key->local), SET_KEY, + key->sdata->dev->dev_addr, addr, + &key->conf); + + if (!ret) + key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; + + if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP) + printk(KERN_ERR "mac80211-%s: failed to set key " + "(%d, %s) to hardware (%d)\n", + wiphy_name(key->local->hw.wiphy), + key->conf.keyidx, print_mac(mac, addr), ret); +} + +static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) +{ + const u8 *addr; + int ret; + DECLARE_MAC_BUF(mac); + + if (!key->local->ops->set_key) + return; + + if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) + return; + + addr = get_mac_for_key(key); + + ret = key->local->ops->set_key(local_to_hw(key->local), DISABLE_KEY, + key->sdata->dev->dev_addr, addr, + &key->conf); + + if (ret) + printk(KERN_ERR "mac80211-%s: failed to remove key " + "(%d, %s) from hardware (%d)\n", + wiphy_name(key->local->hw.wiphy), + key->conf.keyidx, print_mac(mac, addr), ret); + + key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; +} + +struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, + struct sta_info *sta, + enum ieee80211_key_alg alg, + int idx, + size_t key_len, + const u8 *key_data) +{ + struct ieee80211_key *key; + + BUG_ON(idx < 0 || idx >= NUM_DEFAULT_KEYS); + + key = kzalloc(sizeof(struct ieee80211_key) + key_len, GFP_KERNEL); + if (!key) + return NULL; + + /* + * Default to software encryption; we'll later upload the + * key to the hardware if possible. + */ + key->conf.flags = 0; + key->flags = 0; + + key->conf.alg = alg; + key->conf.keyidx = idx; + key->conf.keylen = key_len; + memcpy(key->conf.key, key_data, key_len); + + key->local = sdata->local; + key->sdata = sdata; + key->sta = sta; + + if (alg == ALG_CCMP) { + /* + * Initialize AES key state here as an optimization so that + * it does not need to be initialized for every packet. + */ + key->u.ccmp.tfm = ieee80211_aes_key_setup_encrypt(key_data); + if (!key->u.ccmp.tfm) { + ieee80211_key_free(key); + return NULL; + } + } + + ieee80211_debugfs_key_add(key->local, key); + + /* remove key first */ + if (sta) + ieee80211_key_free(sta->key); + else + ieee80211_key_free(sdata->keys[idx]); + + if (sta) { + ieee80211_debugfs_key_sta_link(key, sta); + + /* + * some hardware cannot handle TKIP with QoS, so + * we indicate whether QoS could be in use. + */ + if (sta->flags & WLAN_STA_WME) + key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA; + } else { + if (sdata->type == IEEE80211_IF_TYPE_STA) { + struct sta_info *ap; + + /* same here, the AP could be using QoS */ + ap = sta_info_get(key->local, key->sdata->u.sta.bssid); + if (ap) { + if (ap->flags & WLAN_STA_WME) + key->conf.flags |= + IEEE80211_KEY_FLAG_WMM_STA; + sta_info_put(ap); + } + } + } + + /* enable hwaccel if appropriate */ + if (netif_running(key->sdata->dev)) + ieee80211_key_enable_hw_accel(key); + + if (sta) + rcu_assign_pointer(sta->key, key); + else + rcu_assign_pointer(sdata->keys[idx], key); + + list_add(&key->list, &sdata->key_list); + + return key; +} + +void ieee80211_key_free(struct ieee80211_key *key) +{ + if (!key) + return; + + if (key->sta) { + rcu_assign_pointer(key->sta->key, NULL); + } else { + if (key->sdata->default_key == key) + ieee80211_set_default_key(key->sdata, -1); + if (key->conf.keyidx >= 0 && + key->conf.keyidx < NUM_DEFAULT_KEYS) + rcu_assign_pointer(key->sdata->keys[key->conf.keyidx], + NULL); + else + WARN_ON(1); + } + + /* wait for all key users to complete */ + synchronize_rcu(); + + /* remove from hwaccel if appropriate */ + ieee80211_key_disable_hw_accel(key); + + if (key->conf.alg == ALG_CCMP) + ieee80211_aes_key_free(key->u.ccmp.tfm); + ieee80211_debugfs_key_remove(key); + + list_del(&key->list); + + kfree(key); +} + +void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx) +{ + struct ieee80211_key *key = NULL; + + if (idx >= 0 && idx < NUM_DEFAULT_KEYS) + key = sdata->keys[idx]; + + if (sdata->default_key != key) { + ieee80211_debugfs_key_remove_default(sdata); + + rcu_assign_pointer(sdata->default_key, key); + + if (sdata->default_key) + ieee80211_debugfs_key_add_default(sdata); + } +} + +void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_key *key, *tmp; + + list_for_each_entry_safe(key, tmp, &sdata->key_list, list) + ieee80211_key_free(key); +} + +void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_key *key; + + WARN_ON(!netif_running(sdata->dev)); + if (!netif_running(sdata->dev)) + return; + + list_for_each_entry(key, &sdata->key_list, list) + ieee80211_key_enable_hw_accel(key); +} + +void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_key *key; + + list_for_each_entry(key, &sdata->key_list, list) + ieee80211_key_disable_hw_accel(key); +} diff --git a/net/mac80211/rc80211_simple.c b/net/mac80211/rc80211_simple.c index 17b9f46..314b8de 100644 --- a/net/mac80211/rc80211_simple.c +++ b/net/mac80211/rc80211_simple.c @@ -147,14 +147,6 @@ static void rate_control_simple_tx_status(void *priv, struct net_device *dev, srctrl = sta->rate_ctrl_priv; srctrl->tx_num_xmit++; if (status->excessive_retries) { - sta->antenna_sel_tx = sta->antenna_sel_tx == 1 ? 2 : 1; - sta->antenna_sel_rx = sta->antenna_sel_rx == 1 ? 2 : 1; - if (local->sta_antenna_sel == STA_ANTENNA_SEL_SW_CTRL_DEBUG) { - printk(KERN_DEBUG "%s: " MAC_FMT " TX antenna --> %d " - "RX antenna --> %d (@%lu)\n", - dev->name, MAC_ARG(hdr->addr1), - sta->antenna_sel_tx, sta->antenna_sel_rx, jiffies); - } srctrl->tx_num_failures++; sta->tx_retry_failed++; sta->tx_num_consecutive_failures++; @@ -209,9 +201,10 @@ static void rate_control_simple_tx_status(void *priv, struct net_device *dev, srctrl->avg_rate_update = jiffies; if (srctrl->tx_avg_rate_num > 0) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: STA " MAC_FMT " Average rate: " + DECLARE_MAC_BUF(mac); + printk(KERN_DEBUG "%s: STA %s Average rate: " "%d (%d/%d)\n", - dev->name, MAC_ARG(sta->addr), + dev->name, print_mac(mac, sta->addr), srctrl->tx_avg_rate_sum / srctrl->tx_avg_rate_num, srctrl->tx_avg_rate_sum, diff --git a/net/mac80211/regdomain.c b/net/mac80211/regdomain.c index b697a2a..f42678f 100644 --- a/net/mac80211/regdomain.c +++ b/net/mac80211/regdomain.c @@ -82,12 +82,6 @@ static void ieee80211_unmask_channel(int mode, struct ieee80211_channel *chan) chan->flag = 0; - if (ieee80211_regdom == 64 && - (mode == MODE_ATHEROS_TURBO || mode == MODE_ATHEROS_TURBOG)) { - /* Do not allow Turbo modes in Japan. */ - return; - } - for (i = 0; channel_range[i].start_freq; i++) { const struct ieee80211_channel_range *r = &channel_range[i]; if (r->start_freq <= chan->freq && r->end_freq >= chan->freq) { diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c new file mode 100644 index 0000000..ece7776 --- /dev/null +++ b/net/mac80211/rx.c @@ -0,0 +1,1588 @@ +/* + * Copyright 2002-2005, Instant802 Networks, Inc. + * Copyright 2005-2006, Devicescape Software, Inc. + * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> + * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/rcupdate.h> +#include <net/mac80211.h> +#include <net/ieee80211_radiotap.h> + +#include "ieee80211_i.h" +#include "ieee80211_led.h" +#include "wep.h" +#include "wpa.h" +#include "tkip.h" +#include "wme.h" + +/* + * monitor mode reception + * + * This function cleans up the SKB, i.e. it removes all the stuff + * only useful for monitoring. + */ +static struct sk_buff *remove_monitor_info(struct ieee80211_local *local, + struct sk_buff *skb, + int rtap_len) +{ + skb_pull(skb, rtap_len); + + if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) { + if (likely(skb->len > FCS_LEN)) + skb_trim(skb, skb->len - FCS_LEN); + else { + /* driver bug */ + WARN_ON(1); + dev_kfree_skb(skb); + skb = NULL; + } + } + + return skb; +} + +static inline int should_drop_frame(struct ieee80211_rx_status *status, + struct sk_buff *skb, + int present_fcs_len, + int radiotap_len) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + + if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC)) + return 1; + if (unlikely(skb->len < 16 + present_fcs_len + radiotap_len)) + return 1; + if ((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_FTYPE)) == + cpu_to_le16(IEEE80211_FTYPE_CTL)) + return 1; + return 0; +} + +/* + * This function copies a received frame to all monitor interfaces and + * returns a cleaned-up SKB that no longer includes the FCS nor the + * radiotap header the driver might have added. + */ +static struct sk_buff * +ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, + struct ieee80211_rx_status *status) +{ + struct ieee80211_sub_if_data *sdata; + struct ieee80211_rate *rate; + int needed_headroom = 0; + struct ieee80211_rtap_hdr { + struct ieee80211_radiotap_header hdr; + u8 flags; + u8 rate; + __le16 chan_freq; + __le16 chan_flags; + u8 antsignal; + u8 padding_for_rxflags; + __le16 rx_flags; + } __attribute__ ((packed)) *rthdr; + struct sk_buff *skb, *skb2; + struct net_device *prev_dev = NULL; + int present_fcs_len = 0; + int rtap_len = 0; + + /* + * First, we may need to make a copy of the skb because + * (1) we need to modify it for radiotap (if not present), and + * (2) the other RX handlers will modify the skb we got. + * + * We don't need to, of course, if we aren't going to return + * the SKB because it has a bad FCS/PLCP checksum. + */ + if (status->flag & RX_FLAG_RADIOTAP) + rtap_len = ieee80211_get_radiotap_len(origskb->data); + else + needed_headroom = sizeof(*rthdr); + + if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) + present_fcs_len = FCS_LEN; + + if (!local->monitors) { + if (should_drop_frame(status, origskb, present_fcs_len, + rtap_len)) { + dev_kfree_skb(origskb); + return NULL; + } + + return remove_monitor_info(local, origskb, rtap_len); + } + + if (should_drop_frame(status, origskb, present_fcs_len, rtap_len)) { + /* only need to expand headroom if necessary */ + skb = origskb; + origskb = NULL; + + /* + * This shouldn't trigger often because most devices have an + * RX header they pull before we get here, and that should + * be big enough for our radiotap information. We should + * probably export the length to drivers so that we can have + * them allocate enough headroom to start with. + */ + if (skb_headroom(skb) < needed_headroom && + pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC)) { + dev_kfree_skb(skb); + return NULL; + } + } else { + /* + * Need to make a copy and possibly remove radiotap header + * and FCS from the original. + */ + skb = skb_copy_expand(origskb, needed_headroom, 0, GFP_ATOMIC); + + origskb = remove_monitor_info(local, origskb, rtap_len); + + if (!skb) + return origskb; + } + + /* if necessary, prepend radiotap information */ + if (!(status->flag & RX_FLAG_RADIOTAP)) { + rthdr = (void *) skb_push(skb, sizeof(*rthdr)); + memset(rthdr, 0, sizeof(*rthdr)); + rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr)); + rthdr->hdr.it_present = + cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | + (1 << IEEE80211_RADIOTAP_RATE) | + (1 << IEEE80211_RADIOTAP_CHANNEL) | + (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) | + (1 << IEEE80211_RADIOTAP_RX_FLAGS)); + rthdr->flags = local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS ? + IEEE80211_RADIOTAP_F_FCS : 0; + + /* FIXME: when radiotap gets a 'bad PLCP' flag use it here */ + rthdr->rx_flags = 0; + if (status->flag & + (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC)) + rthdr->rx_flags |= + cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADFCS); + + rate = ieee80211_get_rate(local, status->phymode, + status->rate); + if (rate) + rthdr->rate = rate->rate / 5; + + rthdr->chan_freq = cpu_to_le16(status->freq); + + if (status->phymode == MODE_IEEE80211A) + rthdr->chan_flags = + cpu_to_le16(IEEE80211_CHAN_OFDM | + IEEE80211_CHAN_5GHZ); + else + rthdr->chan_flags = + cpu_to_le16(IEEE80211_CHAN_DYN | + IEEE80211_CHAN_2GHZ); + + rthdr->antsignal = status->ssi; + } + + skb_set_mac_header(skb, 0); + skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = htons(ETH_P_802_2); + + list_for_each_entry_rcu(sdata, &local->interfaces, list) { + if (!netif_running(sdata->dev)) + continue; + + if (sdata->type != IEEE80211_IF_TYPE_MNTR) + continue; + + if (prev_dev) { + skb2 = skb_clone(skb, GFP_ATOMIC); + if (skb2) { + skb2->dev = prev_dev; + netif_rx(skb2); + } + } + + prev_dev = sdata->dev; + sdata->dev->stats.rx_packets++; + sdata->dev->stats.rx_bytes += skb->len; + } + + if (prev_dev) { + skb->dev = prev_dev; + netif_rx(skb); + } else + dev_kfree_skb(skb); + + return origskb; +} + + +/* pre-rx handlers + * + * these don't have dev/sdata fields in the rx data + * The sta value should also not be used because it may + * be NULL even though a STA (in IBSS mode) will be added. + */ + +static ieee80211_txrx_result +ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx) +{ + u8 *data = rx->skb->data; + int tid; + + /* does the frame have a qos control field? */ + if (WLAN_FC_IS_QOS_DATA(rx->fc)) { + u8 *qc = data + ieee80211_get_hdrlen(rx->fc) - QOS_CONTROL_LEN; + /* frame has qos control */ + tid = qc[0] & QOS_CONTROL_TID_MASK; + } else { + if (unlikely((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)) { + /* Separate TID for management frames */ + tid = NUM_RX_DATA_QUEUES - 1; + } else { + /* no qos control present */ + tid = 0; /* 802.1d - Best Effort */ + } + } + + I802_DEBUG_INC(rx->local->wme_rx_queue[tid]); + /* only a debug counter, sta might not be assigned properly yet */ + if (rx->sta) + I802_DEBUG_INC(rx->sta->wme_rx_queue[tid]); + + rx->u.rx.queue = tid; + /* Set skb->priority to 1d tag if highest order bit of TID is not set. + * For now, set skb->priority to 0 for other cases. */ + rx->skb->priority = (tid > 7) ? 0 : tid; + + return TXRX_CONTINUE; +} + +static ieee80211_txrx_result +ieee80211_rx_h_load_stats(struct ieee80211_txrx_data *rx) +{ + struct ieee80211_local *local = rx->local; + struct sk_buff *skb = rx->skb; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u32 load = 0, hdrtime; + struct ieee80211_rate *rate; + struct ieee80211_hw_mode *mode = local->hw.conf.mode; + int i; + + /* Estimate total channel use caused by this frame */ + + if (unlikely(mode->num_rates < 0)) + return TXRX_CONTINUE; + + rate = &mode->rates[0]; + for (i = 0; i < mode->num_rates; i++) { + if (mode->rates[i].val == rx->u.rx.status->rate) { + rate = &mode->rates[i]; + break; + } + } + + /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values, + * 1 usec = 1/8 * (1080 / 10) = 13.5 */ + + if (mode->mode == MODE_IEEE80211A || + (mode->mode == MODE_IEEE80211G && + rate->flags & IEEE80211_RATE_ERP)) + hdrtime = CHAN_UTIL_HDR_SHORT; + else + hdrtime = CHAN_UTIL_HDR_LONG; + + load = hdrtime; + if (!is_multicast_ether_addr(hdr->addr1)) + load += hdrtime; + + load += skb->len * rate->rate_inv; + + /* Divide channel_use by 8 to avoid wrapping around the counter */ + load >>= CHAN_UTIL_SHIFT; + local->channel_use_raw += load; + rx->u.rx.load = load; + + return TXRX_CONTINUE; +} + +ieee80211_rx_handler ieee80211_rx_pre_handlers[] = +{ + ieee80211_rx_h_parse_qos, + ieee80211_rx_h_load_stats, + NULL +}; + +/* rx handlers */ + +static ieee80211_txrx_result +ieee80211_rx_h_if_stats(struct ieee80211_txrx_data *rx) +{ + if (rx->sta) + rx->sta->channel_use_raw += rx->u.rx.load; + rx->sdata->channel_use_raw += rx->u.rx.load; + return TXRX_CONTINUE; +} + +static ieee80211_txrx_result +ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx) +{ + struct ieee80211_local *local = rx->local; + struct sk_buff *skb = rx->skb; + + if (unlikely(local->sta_scanning != 0)) { + ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status); + return TXRX_QUEUED; + } + + if (unlikely(rx->flags & IEEE80211_TXRXD_RXIN_SCAN)) { + /* scanning finished during invoking of handlers */ + I802_DEBUG_INC(local->rx_handlers_drop_passive_scan); + return TXRX_DROP; + } + + return TXRX_CONTINUE; +} + +static ieee80211_txrx_result +ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) +{ + struct ieee80211_hdr *hdr; + hdr = (struct ieee80211_hdr *) rx->skb->data; + + /* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */ + if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) { + if (unlikely(rx->fc & IEEE80211_FCTL_RETRY && + rx->sta->last_seq_ctrl[rx->u.rx.queue] == + hdr->seq_ctrl)) { + if (rx->flags & IEEE80211_TXRXD_RXRA_MATCH) { + rx->local->dot11FrameDuplicateCount++; + rx->sta->num_duplicates++; + } + return TXRX_DROP; + } else + rx->sta->last_seq_ctrl[rx->u.rx.queue] = hdr->seq_ctrl; + } + + if (unlikely(rx->skb->len < 16)) { + I802_DEBUG_INC(rx->local->rx_handlers_drop_short); + return TXRX_DROP; + } + + if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) + rx->skb->pkt_type = PACKET_OTHERHOST; + else if (compare_ether_addr(rx->dev->dev_addr, hdr->addr1) == 0) + rx->skb->pkt_type = PACKET_HOST; + else if (is_multicast_ether_addr(hdr->addr1)) { + if (is_broadcast_ether_addr(hdr->addr1)) + rx->skb->pkt_type = PACKET_BROADCAST; + else + rx->skb->pkt_type = PACKET_MULTICAST; + } else + rx->skb->pkt_type = PACKET_OTHERHOST; + + /* Drop disallowed frame classes based on STA auth/assoc state; + * IEEE 802.11, Chap 5.5. + * + * 80211.o does filtering only based on association state, i.e., it + * drops Class 3 frames from not associated stations. hostapd sends + * deauth/disassoc frames when needed. In addition, hostapd is + * responsible for filtering on both auth and assoc states. + */ + if (unlikely(((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA || + ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL && + (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)) && + rx->sdata->type != IEEE80211_IF_TYPE_IBSS && + (!rx->sta || !(rx->sta->flags & WLAN_STA_ASSOC)))) { + if ((!(rx->fc & IEEE80211_FCTL_FROMDS) && + !(rx->fc & IEEE80211_FCTL_TODS) && + (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) + || !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) { + /* Drop IBSS frames and frames for other hosts + * silently. */ + return TXRX_DROP; + } + + return TXRX_DROP; + } + + return TXRX_CONTINUE; +} + + +static ieee80211_txrx_result +ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; + int keyidx; + int hdrlen; + ieee80211_txrx_result result = TXRX_DROP; + struct ieee80211_key *stakey = NULL; + + /* + * Key selection 101 + * + * There are three types of keys: + * - GTK (group keys) + * - PTK (pairwise keys) + * - STK (station-to-station pairwise keys) + * + * When selecting a key, we have to distinguish between multicast + * (including broadcast) and unicast frames, the latter can only + * use PTKs and STKs while the former always use GTKs. Unless, of + * course, actual WEP keys ("pre-RSNA") are used, then unicast + * frames can also use key indizes like GTKs. Hence, if we don't + * have a PTK/STK we check the key index for a WEP key. + * + * Note that in a regular BSS, multicast frames are sent by the + * AP only, associated stations unicast the frame to the AP first + * which then multicasts it on their behalf. + * + * There is also a slight problem in IBSS mode: GTKs are negotiated + * with each station, that is something we don't currently handle. + * The spec seems to expect that one negotiates the same key with + * every station but there's no such requirement; VLANs could be + * possible. + */ + + if (!(rx->fc & IEEE80211_FCTL_PROTECTED)) + return TXRX_CONTINUE; + + /* + * No point in finding a key and decrypting if the frame is neither + * addressed to us nor a multicast frame. + */ + if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) + return TXRX_CONTINUE; + + if (rx->sta) + stakey = rcu_dereference(rx->sta->key); + + if (!is_multicast_ether_addr(hdr->addr1) && stakey) { + rx->key = stakey; + } else { + /* + * The device doesn't give us the IV so we won't be + * able to look up the key. That's ok though, we + * don't need to decrypt the frame, we just won't + * be able to keep statistics accurate. + * Except for key threshold notifications, should + * we somehow allow the driver to tell us which key + * the hardware used if this flag is set? + */ + if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && + (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) + return TXRX_CONTINUE; + + hdrlen = ieee80211_get_hdrlen(rx->fc); + + if (rx->skb->len < 8 + hdrlen) + return TXRX_DROP; /* TODO: count this? */ + + /* + * no need to call ieee80211_wep_get_keyidx, + * it verifies a bunch of things we've done already + */ + keyidx = rx->skb->data[hdrlen + 3] >> 6; + + rx->key = rcu_dereference(rx->sdata->keys[keyidx]); + + /* + * RSNA-protected unicast frames should always be sent with + * pairwise or station-to-station keys, but for WEP we allow + * using a key index as well. + */ + if (rx->key && rx->key->conf.alg != ALG_WEP && + !is_multicast_ether_addr(hdr->addr1)) + rx->key = NULL; + } + + if (rx->key) { + rx->key->tx_rx_count++; + /* TODO: add threshold stuff again */ + } else { + if (net_ratelimit()) + printk(KERN_DEBUG "%s: RX protected frame," + " but have no key\n", rx->dev->name); + return TXRX_DROP; + } + + /* Check for weak IVs if possible */ + if (rx->sta && rx->key->conf.alg == ALG_WEP && + ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && + (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED) || + !(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) && + ieee80211_wep_is_weak_iv(rx->skb, rx->key)) + rx->sta->wep_weak_iv_count++; + + switch (rx->key->conf.alg) { + case ALG_WEP: + result = ieee80211_crypto_wep_decrypt(rx); + break; + case ALG_TKIP: + result = ieee80211_crypto_tkip_decrypt(rx); + break; + case ALG_CCMP: + result = ieee80211_crypto_ccmp_decrypt(rx); + break; + } + + /* either the frame has been decrypted or will be dropped */ + rx->u.rx.status->flag |= RX_FLAG_DECRYPTED; + + return result; +} + +static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta) +{ + struct ieee80211_sub_if_data *sdata; + DECLARE_MAC_BUF(mac); + + sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + + if (sdata->bss) + atomic_inc(&sdata->bss->num_sta_ps); + sta->flags |= WLAN_STA_PS; + sta->pspoll = 0; +#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG + printk(KERN_DEBUG "%s: STA %s aid %d enters power save mode\n", + dev->name, print_mac(mac, sta->addr), sta->aid); +#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ +} + +static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct sk_buff *skb; + int sent = 0; + struct ieee80211_sub_if_data *sdata; + struct ieee80211_tx_packet_data *pkt_data; + DECLARE_MAC_BUF(mac); + + sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + if (sdata->bss) + atomic_dec(&sdata->bss->num_sta_ps); + sta->flags &= ~(WLAN_STA_PS | WLAN_STA_TIM); + sta->pspoll = 0; + if (!skb_queue_empty(&sta->ps_tx_buf)) { + if (local->ops->set_tim) + local->ops->set_tim(local_to_hw(local), sta->aid, 0); + if (sdata->bss) + bss_tim_clear(local, sdata->bss, sta->aid); + } +#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG + printk(KERN_DEBUG "%s: STA %s aid %d exits power save mode\n", + dev->name, print_mac(mac, sta->addr), sta->aid); +#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ + /* Send all buffered frames to the station */ + while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { + pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; + sent++; + pkt_data->flags |= IEEE80211_TXPD_REQUEUE; + dev_queue_xmit(skb); + } + while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { + pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; + local->total_ps_buffered--; + sent++; +#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG + printk(KERN_DEBUG "%s: STA %s aid %d send PS frame " + "since STA not sleeping anymore\n", dev->name, + print_mac(mac, sta->addr), sta->aid); +#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ + pkt_data->flags |= IEEE80211_TXPD_REQUEUE; + dev_queue_xmit(skb); + } + + return sent; +} + +static ieee80211_txrx_result +ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx) +{ + struct sta_info *sta = rx->sta; + struct net_device *dev = rx->dev; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; + + if (!sta) + return TXRX_CONTINUE; + + /* Update last_rx only for IBSS packets which are for the current + * BSSID to avoid keeping the current IBSS network alive in cases where + * other STAs are using different BSSID. */ + if (rx->sdata->type == IEEE80211_IF_TYPE_IBSS) { + u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len); + if (compare_ether_addr(bssid, rx->sdata->u.sta.bssid) == 0) + sta->last_rx = jiffies; + } else + if (!is_multicast_ether_addr(hdr->addr1) || + rx->sdata->type == IEEE80211_IF_TYPE_STA) { + /* Update last_rx only for unicast frames in order to prevent + * the Probe Request frames (the only broadcast frames from a + * STA in infrastructure mode) from keeping a connection alive. + */ + sta->last_rx = jiffies; + } + + if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) + return TXRX_CONTINUE; + + sta->rx_fragments++; + sta->rx_bytes += rx->skb->len; + sta->last_rssi = rx->u.rx.status->ssi; + sta->last_signal = rx->u.rx.status->signal; + sta->last_noise = rx->u.rx.status->noise; + + if (!(rx->fc & IEEE80211_FCTL_MOREFRAGS)) { + /* Change STA power saving mode only in the end of a frame + * exchange sequence */ + if ((sta->flags & WLAN_STA_PS) && !(rx->fc & IEEE80211_FCTL_PM)) + rx->u.rx.sent_ps_buffered += ap_sta_ps_end(dev, sta); + else if (!(sta->flags & WLAN_STA_PS) && + (rx->fc & IEEE80211_FCTL_PM)) + ap_sta_ps_start(dev, sta); + } + + /* Drop data::nullfunc frames silently, since they are used only to + * control station power saving mode. */ + if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && + (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_NULLFUNC) { + I802_DEBUG_INC(rx->local->rx_handlers_drop_nullfunc); + /* Update counter and free packet here to avoid counting this + * as a dropped packed. */ + sta->rx_packets++; + dev_kfree_skb(rx->skb); + return TXRX_QUEUED; + } + + return TXRX_CONTINUE; +} /* ieee80211_rx_h_sta_process */ + +static inline struct ieee80211_fragment_entry * +ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata, + unsigned int frag, unsigned int seq, int rx_queue, + struct sk_buff **skb) +{ + struct ieee80211_fragment_entry *entry; + int idx; + + idx = sdata->fragment_next; + entry = &sdata->fragments[sdata->fragment_next++]; + if (sdata->fragment_next >= IEEE80211_FRAGMENT_MAX) + sdata->fragment_next = 0; + + if (!skb_queue_empty(&entry->skb_list)) { +#ifdef CONFIG_MAC80211_DEBUG + struct ieee80211_hdr *hdr = + (struct ieee80211_hdr *) entry->skb_list.next->data; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); + printk(KERN_DEBUG "%s: RX reassembly removed oldest " + "fragment entry (idx=%d age=%lu seq=%d last_frag=%d " + "addr1=%s addr2=%s\n", + sdata->dev->name, idx, + jiffies - entry->first_frag_time, entry->seq, + entry->last_frag, print_mac(mac, hdr->addr1), + print_mac(mac2, hdr->addr2)); +#endif /* CONFIG_MAC80211_DEBUG */ + __skb_queue_purge(&entry->skb_list); + } + + __skb_queue_tail(&entry->skb_list, *skb); /* no need for locking */ + *skb = NULL; + entry->first_frag_time = jiffies; + entry->seq = seq; + entry->rx_queue = rx_queue; + entry->last_frag = frag; + entry->ccmp = 0; + entry->extra_len = 0; + + return entry; +} + +static inline struct ieee80211_fragment_entry * +ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata, + u16 fc, unsigned int frag, unsigned int seq, + int rx_queue, struct ieee80211_hdr *hdr) +{ + struct ieee80211_fragment_entry *entry; + int i, idx; + + idx = sdata->fragment_next; + for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) { + struct ieee80211_hdr *f_hdr; + u16 f_fc; + + idx--; + if (idx < 0) + idx = IEEE80211_FRAGMENT_MAX - 1; + + entry = &sdata->fragments[idx]; + if (skb_queue_empty(&entry->skb_list) || entry->seq != seq || + entry->rx_queue != rx_queue || + entry->last_frag + 1 != frag) + continue; + + f_hdr = (struct ieee80211_hdr *) entry->skb_list.next->data; + f_fc = le16_to_cpu(f_hdr->frame_control); + + if ((fc & IEEE80211_FCTL_FTYPE) != (f_fc & IEEE80211_FCTL_FTYPE) || + compare_ether_addr(hdr->addr1, f_hdr->addr1) != 0 || + compare_ether_addr(hdr->addr2, f_hdr->addr2) != 0) + continue; + + if (entry->first_frag_time + 2 * HZ < jiffies) { + __skb_queue_purge(&entry->skb_list); + continue; + } + return entry; + } + + return NULL; +} + +static ieee80211_txrx_result +ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) +{ + struct ieee80211_hdr *hdr; + u16 sc; + unsigned int frag, seq; + struct ieee80211_fragment_entry *entry; + struct sk_buff *skb; + DECLARE_MAC_BUF(mac); + + hdr = (struct ieee80211_hdr *) rx->skb->data; + sc = le16_to_cpu(hdr->seq_ctrl); + frag = sc & IEEE80211_SCTL_FRAG; + + if (likely((!(rx->fc & IEEE80211_FCTL_MOREFRAGS) && frag == 0) || + (rx->skb)->len < 24 || + is_multicast_ether_addr(hdr->addr1))) { + /* not fragmented */ + goto out; + } + I802_DEBUG_INC(rx->local->rx_handlers_fragments); + + seq = (sc & IEEE80211_SCTL_SEQ) >> 4; + + if (frag == 0) { + /* This is the first fragment of a new frame. */ + entry = ieee80211_reassemble_add(rx->sdata, frag, seq, + rx->u.rx.queue, &(rx->skb)); + if (rx->key && rx->key->conf.alg == ALG_CCMP && + (rx->fc & IEEE80211_FCTL_PROTECTED)) { + /* Store CCMP PN so that we can verify that the next + * fragment has a sequential PN value. */ + entry->ccmp = 1; + memcpy(entry->last_pn, + rx->key->u.ccmp.rx_pn[rx->u.rx.queue], + CCMP_PN_LEN); + } + return TXRX_QUEUED; + } + + /* This is a fragment for a frame that should already be pending in + * fragment cache. Add this fragment to the end of the pending entry. + */ + entry = ieee80211_reassemble_find(rx->sdata, rx->fc, frag, seq, + rx->u.rx.queue, hdr); + if (!entry) { + I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag); + return TXRX_DROP; + } + + /* Verify that MPDUs within one MSDU have sequential PN values. + * (IEEE 802.11i, 8.3.3.4.5) */ + if (entry->ccmp) { + int i; + u8 pn[CCMP_PN_LEN], *rpn; + if (!rx->key || rx->key->conf.alg != ALG_CCMP) + return TXRX_DROP; + memcpy(pn, entry->last_pn, CCMP_PN_LEN); + for (i = CCMP_PN_LEN - 1; i >= 0; i--) { + pn[i]++; + if (pn[i]) + break; + } + rpn = rx->key->u.ccmp.rx_pn[rx->u.rx.queue]; + if (memcmp(pn, rpn, CCMP_PN_LEN) != 0) { + if (net_ratelimit()) + printk(KERN_DEBUG "%s: defrag: CCMP PN not " + "sequential A2=%s" + " PN=%02x%02x%02x%02x%02x%02x " + "(expected %02x%02x%02x%02x%02x%02x)\n", + rx->dev->name, print_mac(mac, hdr->addr2), + rpn[0], rpn[1], rpn[2], rpn[3], rpn[4], + rpn[5], pn[0], pn[1], pn[2], pn[3], + pn[4], pn[5]); + return TXRX_DROP; + } + memcpy(entry->last_pn, pn, CCMP_PN_LEN); + } + + skb_pull(rx->skb, ieee80211_get_hdrlen(rx->fc)); + __skb_queue_tail(&entry->skb_list, rx->skb); + entry->last_frag = frag; + entry->extra_len += rx->skb->len; + if (rx->fc & IEEE80211_FCTL_MOREFRAGS) { + rx->skb = NULL; + return TXRX_QUEUED; + } + + rx->skb = __skb_dequeue(&entry->skb_list); + if (skb_tailroom(rx->skb) < entry->extra_len) { + I802_DEBUG_INC(rx->local->rx_expand_skb_head2); + if (unlikely(pskb_expand_head(rx->skb, 0, entry->extra_len, + GFP_ATOMIC))) { + I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag); + __skb_queue_purge(&entry->skb_list); + return TXRX_DROP; + } + } + while ((skb = __skb_dequeue(&entry->skb_list))) { + memcpy(skb_put(rx->skb, skb->len), skb->data, skb->len); + dev_kfree_skb(skb); + } + + /* Complete frame has been reassembled - process it now */ + rx->flags |= IEEE80211_TXRXD_FRAGMENTED; + + out: + if (rx->sta) + rx->sta->rx_packets++; + if (is_multicast_ether_addr(hdr->addr1)) + rx->local->dot11MulticastReceivedFrameCount++; + else + ieee80211_led_rx(rx->local); + return TXRX_CONTINUE; +} + +static ieee80211_txrx_result +ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) +{ + struct sk_buff *skb; + int no_pending_pkts; + DECLARE_MAC_BUF(mac); + + if (likely(!rx->sta || + (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_CTL || + (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PSPOLL || + !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))) + return TXRX_CONTINUE; + + skb = skb_dequeue(&rx->sta->tx_filtered); + if (!skb) { + skb = skb_dequeue(&rx->sta->ps_tx_buf); + if (skb) + rx->local->total_ps_buffered--; + } + no_pending_pkts = skb_queue_empty(&rx->sta->tx_filtered) && + skb_queue_empty(&rx->sta->ps_tx_buf); + + if (skb) { + struct ieee80211_hdr *hdr = + (struct ieee80211_hdr *) skb->data; + + /* tell TX path to send one frame even though the STA may + * still remain is PS mode after this frame exchange */ + rx->sta->pspoll = 1; + +#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG + printk(KERN_DEBUG "STA %s aid %d: PS Poll (entries after %d)\n", + print_mac(mac, rx->sta->addr), rx->sta->aid, + skb_queue_len(&rx->sta->ps_tx_buf)); +#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ + + /* Use MoreData flag to indicate whether there are more + * buffered frames for this STA */ + if (no_pending_pkts) { + hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREDATA); + rx->sta->flags &= ~WLAN_STA_TIM; + } else + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); + + dev_queue_xmit(skb); + + if (no_pending_pkts) { + if (rx->local->ops->set_tim) + rx->local->ops->set_tim(local_to_hw(rx->local), + rx->sta->aid, 0); + if (rx->sdata->bss) + bss_tim_clear(rx->local, rx->sdata->bss, rx->sta->aid); + } +#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG + } else if (!rx->u.rx.sent_ps_buffered) { + printk(KERN_DEBUG "%s: STA %s sent PS Poll even " + "though there is no buffered frames for it\n", + rx->dev->name, print_mac(mac, rx->sta->addr)); +#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ + + } + + /* Free PS Poll skb here instead of returning TXRX_DROP that would + * count as an dropped frame. */ + dev_kfree_skb(rx->skb); + + return TXRX_QUEUED; +} + +static ieee80211_txrx_result +ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx) +{ + u16 fc = rx->fc; + u8 *data = rx->skb->data; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) data; + + if (!WLAN_FC_IS_QOS_DATA(fc)) + return TXRX_CONTINUE; + + /* remove the qos control field, update frame type and meta-data */ + memmove(data + 2, data, ieee80211_get_hdrlen(fc) - 2); + hdr = (struct ieee80211_hdr *) skb_pull(rx->skb, 2); + /* change frame type to non QOS */ + rx->fc = fc &= ~IEEE80211_STYPE_QOS_DATA; + hdr->frame_control = cpu_to_le16(fc); + + return TXRX_CONTINUE; +} + +static ieee80211_txrx_result +ieee80211_rx_h_802_1x_pae(struct ieee80211_txrx_data *rx) +{ + if (rx->sdata->eapol && ieee80211_is_eapol(rx->skb) && + rx->sdata->type != IEEE80211_IF_TYPE_STA && + (rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) + return TXRX_CONTINUE; + + if (unlikely(rx->sdata->ieee802_1x && + (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && + (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_NULLFUNC && + (!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED)) && + !ieee80211_is_eapol(rx->skb))) { +#ifdef CONFIG_MAC80211_DEBUG + struct ieee80211_hdr *hdr = + (struct ieee80211_hdr *) rx->skb->data; + DECLARE_MAC_BUF(mac); + printk(KERN_DEBUG "%s: dropped frame from %s" + " (unauthorized port)\n", rx->dev->name, + print_mac(mac, hdr->addr2)); +#endif /* CONFIG_MAC80211_DEBUG */ + return TXRX_DROP; + } + + return TXRX_CONTINUE; +} + +static ieee80211_txrx_result +ieee80211_rx_h_drop_unencrypted(struct ieee80211_txrx_data *rx) +{ + /* + * Pass through unencrypted frames if the hardware has + * decrypted them already. + */ + if (rx->u.rx.status->flag & RX_FLAG_DECRYPTED) + return TXRX_CONTINUE; + + /* Drop unencrypted frames if key is set. */ + if (unlikely(!(rx->fc & IEEE80211_FCTL_PROTECTED) && + (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && + (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_NULLFUNC && + rx->sdata->drop_unencrypted && + (rx->sdata->eapol == 0 || !ieee80211_is_eapol(rx->skb)))) { + if (net_ratelimit()) + printk(KERN_DEBUG "%s: RX non-WEP frame, but expected " + "encryption\n", rx->dev->name); + return TXRX_DROP; + } + return TXRX_CONTINUE; +} + +static ieee80211_txrx_result +ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) +{ + struct net_device *dev = rx->dev; + struct ieee80211_local *local = rx->local; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; + u16 fc, hdrlen, ethertype; + u8 *payload; + u8 dst[ETH_ALEN]; + u8 src[ETH_ALEN]; + struct sk_buff *skb = rx->skb, *skb2; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); + DECLARE_MAC_BUF(mac3); + DECLARE_MAC_BUF(mac4); + + fc = rx->fc; + if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)) + return TXRX_CONTINUE; + + if (unlikely(!WLAN_FC_DATA_PRESENT(fc))) + return TXRX_DROP; + + hdrlen = ieee80211_get_hdrlen(fc); + + /* convert IEEE 802.11 header + possible LLC headers into Ethernet + * header + * IEEE 802.11 address fields: + * ToDS FromDS Addr1 Addr2 Addr3 Addr4 + * 0 0 DA SA BSSID n/a + * 0 1 DA BSSID SA n/a + * 1 0 BSSID SA DA n/a + * 1 1 RA TA DA SA + */ + + switch (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { + case IEEE80211_FCTL_TODS: + /* BSSID SA DA */ + memcpy(dst, hdr->addr3, ETH_ALEN); + memcpy(src, hdr->addr2, ETH_ALEN); + + if (unlikely(sdata->type != IEEE80211_IF_TYPE_AP && + sdata->type != IEEE80211_IF_TYPE_VLAN)) { + if (net_ratelimit()) + printk(KERN_DEBUG "%s: dropped ToDS frame " + "(BSSID=%s SA=%s DA=%s)\n", + dev->name, + print_mac(mac, hdr->addr1), + print_mac(mac2, hdr->addr2), + print_mac(mac3, hdr->addr3)); + return TXRX_DROP; + } + break; + case (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): + /* RA TA DA SA */ + memcpy(dst, hdr->addr3, ETH_ALEN); + memcpy(src, hdr->addr4, ETH_ALEN); + + if (unlikely(sdata->type != IEEE80211_IF_TYPE_WDS)) { + if (net_ratelimit()) + printk(KERN_DEBUG "%s: dropped FromDS&ToDS " + "frame (RA=%s TA=%s DA=%s SA=%s)\n", + rx->dev->name, + print_mac(mac, hdr->addr1), + print_mac(mac2, hdr->addr2), + print_mac(mac3, hdr->addr3), + print_mac(mac4, hdr->addr4)); + return TXRX_DROP; + } + break; + case IEEE80211_FCTL_FROMDS: + /* DA BSSID SA */ + memcpy(dst, hdr->addr1, ETH_ALEN); + memcpy(src, hdr->addr3, ETH_ALEN); + + if (sdata->type != IEEE80211_IF_TYPE_STA || + (is_multicast_ether_addr(dst) && + !compare_ether_addr(src, dev->dev_addr))) + return TXRX_DROP; + break; + case 0: + /* DA SA BSSID */ + memcpy(dst, hdr->addr1, ETH_ALEN); + memcpy(src, hdr->addr2, ETH_ALEN); + + if (sdata->type != IEEE80211_IF_TYPE_IBSS) { + if (net_ratelimit()) { + printk(KERN_DEBUG "%s: dropped IBSS frame " + "(DA=%s SA=%s BSSID=%s)\n", + dev->name, + print_mac(mac, hdr->addr1), + print_mac(mac2, hdr->addr2), + print_mac(mac3, hdr->addr3)); + } + return TXRX_DROP; + } + break; + } + + payload = skb->data + hdrlen; + + if (unlikely(skb->len - hdrlen < 8)) { + if (net_ratelimit()) { + printk(KERN_DEBUG "%s: RX too short data frame " + "payload\n", dev->name); + } + return TXRX_DROP; + } + + ethertype = (payload[6] << 8) | payload[7]; + + if (likely((compare_ether_addr(payload, rfc1042_header) == 0 && + ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || + compare_ether_addr(payload, bridge_tunnel_header) == 0)) { + /* remove RFC1042 or Bridge-Tunnel encapsulation and + * replace EtherType */ + skb_pull(skb, hdrlen + 6); + memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); + memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); + } else { + struct ethhdr *ehdr; + __be16 len; + skb_pull(skb, hdrlen); + len = htons(skb->len); + ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr)); + memcpy(ehdr->h_dest, dst, ETH_ALEN); + memcpy(ehdr->h_source, src, ETH_ALEN); + ehdr->h_proto = len; + } + skb->dev = dev; + + skb2 = NULL; + + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; + + if (local->bridge_packets && (sdata->type == IEEE80211_IF_TYPE_AP + || sdata->type == IEEE80211_IF_TYPE_VLAN) && + (rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) { + if (is_multicast_ether_addr(skb->data)) { + /* send multicast frames both to higher layers in + * local net stack and back to the wireless media */ + skb2 = skb_copy(skb, GFP_ATOMIC); + if (!skb2 && net_ratelimit()) + printk(KERN_DEBUG "%s: failed to clone " + "multicast frame\n", dev->name); + } else { + struct sta_info *dsta; + dsta = sta_info_get(local, skb->data); + if (dsta && !dsta->dev) { + if (net_ratelimit()) + printk(KERN_DEBUG "Station with null " + "dev structure!\n"); + } else if (dsta && dsta->dev == dev) { + /* Destination station is associated to this + * AP, so send the frame directly to it and + * do not pass the frame to local net stack. + */ + skb2 = skb; + skb = NULL; + } + if (dsta) + sta_info_put(dsta); + } + } + + if (skb) { + /* deliver to local stack */ + skb->protocol = eth_type_trans(skb, dev); + memset(skb->cb, 0, sizeof(skb->cb)); + netif_rx(skb); + } + + if (skb2) { + /* send to wireless media */ + skb2->protocol = __constant_htons(ETH_P_802_3); + skb_set_network_header(skb2, 0); + skb_set_mac_header(skb2, 0); + dev_queue_xmit(skb2); + } + + return TXRX_QUEUED; +} + +static ieee80211_txrx_result +ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx) +{ + struct ieee80211_sub_if_data *sdata; + + if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) + return TXRX_DROP; + + sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); + if ((sdata->type == IEEE80211_IF_TYPE_STA || + sdata->type == IEEE80211_IF_TYPE_IBSS) && + !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)) + ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status); + else + return TXRX_DROP; + + return TXRX_QUEUED; +} + +static inline ieee80211_txrx_result __ieee80211_invoke_rx_handlers( + struct ieee80211_local *local, + ieee80211_rx_handler *handlers, + struct ieee80211_txrx_data *rx, + struct sta_info *sta) +{ + ieee80211_rx_handler *handler; + ieee80211_txrx_result res = TXRX_DROP; + + for (handler = handlers; *handler != NULL; handler++) { + res = (*handler)(rx); + + switch (res) { + case TXRX_CONTINUE: + continue; + case TXRX_DROP: + I802_DEBUG_INC(local->rx_handlers_drop); + if (sta) + sta->rx_dropped++; + break; + case TXRX_QUEUED: + I802_DEBUG_INC(local->rx_handlers_queued); + break; + } + break; + } + + if (res == TXRX_DROP) + dev_kfree_skb(rx->skb); + return res; +} + +static inline void ieee80211_invoke_rx_handlers(struct ieee80211_local *local, + ieee80211_rx_handler *handlers, + struct ieee80211_txrx_data *rx, + struct sta_info *sta) +{ + if (__ieee80211_invoke_rx_handlers(local, handlers, rx, sta) == + TXRX_CONTINUE) + dev_kfree_skb(rx->skb); +} + +static void ieee80211_rx_michael_mic_report(struct net_device *dev, + struct ieee80211_hdr *hdr, + struct sta_info *sta, + struct ieee80211_txrx_data *rx) +{ + int keyidx, hdrlen; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); + + hdrlen = ieee80211_get_hdrlen_from_skb(rx->skb); + if (rx->skb->len >= hdrlen + 4) + keyidx = rx->skb->data[hdrlen + 3] >> 6; + else + keyidx = -1; + + if (net_ratelimit()) + printk(KERN_DEBUG "%s: TKIP hwaccel reported Michael MIC " + "failure from %s to %s keyidx=%d\n", + dev->name, print_mac(mac, hdr->addr2), + print_mac(mac2, hdr->addr1), keyidx); + + if (!sta) { + /* + * Some hardware seem to generate incorrect Michael MIC + * reports; ignore them to avoid triggering countermeasures. + */ + if (net_ratelimit()) + printk(KERN_DEBUG "%s: ignored spurious Michael MIC " + "error for unknown address %s\n", + dev->name, print_mac(mac, hdr->addr2)); + goto ignore; + } + + if (!(rx->fc & IEEE80211_FCTL_PROTECTED)) { + if (net_ratelimit()) + printk(KERN_DEBUG "%s: ignored spurious Michael MIC " + "error for a frame with no PROTECTED flag (src " + "%s)\n", dev->name, print_mac(mac, hdr->addr2)); + goto ignore; + } + + if (rx->sdata->type == IEEE80211_IF_TYPE_AP && keyidx) { + /* + * APs with pairwise keys should never receive Michael MIC + * errors for non-zero keyidx because these are reserved for + * group keys and only the AP is sending real multicast + * frames in the BSS. + */ + if (net_ratelimit()) + printk(KERN_DEBUG "%s: ignored Michael MIC error for " + "a frame with non-zero keyidx (%d)" + " (src %s)\n", dev->name, keyidx, + print_mac(mac, hdr->addr2)); + goto ignore; + } + + if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA && + ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || + (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH)) { + if (net_ratelimit()) + printk(KERN_DEBUG "%s: ignored spurious Michael MIC " + "error for a frame that cannot be encrypted " + "(fc=0x%04x) (src %s)\n", + dev->name, rx->fc, print_mac(mac, hdr->addr2)); + goto ignore; + } + + mac80211_ev_michael_mic_failure(rx->dev, keyidx, hdr); + ignore: + dev_kfree_skb(rx->skb); + rx->skb = NULL; +} + +ieee80211_rx_handler ieee80211_rx_handlers[] = +{ + ieee80211_rx_h_if_stats, + ieee80211_rx_h_passive_scan, + ieee80211_rx_h_check, + ieee80211_rx_h_decrypt, + ieee80211_rx_h_sta_process, + ieee80211_rx_h_defragment, + ieee80211_rx_h_ps_poll, + ieee80211_rx_h_michael_mic_verify, + /* this must be after decryption - so header is counted in MPDU mic + * must be before pae and data, so QOS_DATA format frames + * are not passed to user space by these functions + */ + ieee80211_rx_h_remove_qos_control, + ieee80211_rx_h_802_1x_pae, + ieee80211_rx_h_drop_unencrypted, + ieee80211_rx_h_data, + ieee80211_rx_h_mgmt, + NULL +}; + +/* main receive path */ + +static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, + u8 *bssid, struct ieee80211_txrx_data *rx, + struct ieee80211_hdr *hdr) +{ + int multicast = is_multicast_ether_addr(hdr->addr1); + + switch (sdata->type) { + case IEEE80211_IF_TYPE_STA: + if (!bssid) + return 0; + if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) { + if (!(rx->flags & IEEE80211_TXRXD_RXIN_SCAN)) + return 0; + rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH; + } else if (!multicast && + compare_ether_addr(sdata->dev->dev_addr, + hdr->addr1) != 0) { + if (!(sdata->dev->flags & IFF_PROMISC)) + return 0; + rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH; + } + break; + case IEEE80211_IF_TYPE_IBSS: + if (!bssid) + return 0; + if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) { + if (!(rx->flags & IEEE80211_TXRXD_RXIN_SCAN)) + return 0; + rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH; + } else if (!multicast && + compare_ether_addr(sdata->dev->dev_addr, + hdr->addr1) != 0) { + if (!(sdata->dev->flags & IFF_PROMISC)) + return 0; + rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH; + } else if (!rx->sta) + rx->sta = ieee80211_ibss_add_sta(sdata->dev, rx->skb, + bssid, hdr->addr2); + break; + case IEEE80211_IF_TYPE_VLAN: + case IEEE80211_IF_TYPE_AP: + if (!bssid) { + if (compare_ether_addr(sdata->dev->dev_addr, + hdr->addr1)) + return 0; + } else if (!ieee80211_bssid_match(bssid, + sdata->dev->dev_addr)) { + if (!(rx->flags & IEEE80211_TXRXD_RXIN_SCAN)) + return 0; + rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH; + } + if (sdata->dev == sdata->local->mdev && + !(rx->flags & IEEE80211_TXRXD_RXIN_SCAN)) + /* do not receive anything via + * master device when not scanning */ + return 0; + break; + case IEEE80211_IF_TYPE_WDS: + if (bssid || + (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) + return 0; + if (compare_ether_addr(sdata->u.wds.remote_addr, hdr->addr2)) + return 0; + break; + case IEEE80211_IF_TYPE_MNTR: + /* take everything */ + break; + case IEEE80211_IF_TYPE_INVALID: + /* should never get here */ + WARN_ON(1); + break; + } + + return 1; +} + +/* + * This is the receive path handler. It is called by a low level driver when an + * 802.11 MPDU is received from the hardware. + */ +void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_rx_status *status) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_sub_if_data *sdata; + struct sta_info *sta; + struct ieee80211_hdr *hdr; + struct ieee80211_txrx_data rx; + u16 type; + int prepres; + struct ieee80211_sub_if_data *prev = NULL; + struct sk_buff *skb_new; + u8 *bssid; + + /* + * key references and virtual interfaces are protected using RCU + * and this requires that we are in a read-side RCU section during + * receive processing + */ + rcu_read_lock(); + + /* + * Frames with failed FCS/PLCP checksum are not returned, + * all other frames are returned without radiotap header + * if it was previously present. + * Also, frames with less than 16 bytes are dropped. + */ + skb = ieee80211_rx_monitor(local, skb, status); + if (!skb) { + rcu_read_unlock(); + return; + } + + hdr = (struct ieee80211_hdr *) skb->data; + memset(&rx, 0, sizeof(rx)); + rx.skb = skb; + rx.local = local; + + rx.u.rx.status = status; + rx.fc = le16_to_cpu(hdr->frame_control); + type = rx.fc & IEEE80211_FCTL_FTYPE; + + if (type == IEEE80211_FTYPE_DATA || type == IEEE80211_FTYPE_MGMT) + local->dot11ReceivedFragmentCount++; + + sta = rx.sta = sta_info_get(local, hdr->addr2); + if (sta) { + rx.dev = rx.sta->dev; + rx.sdata = IEEE80211_DEV_TO_SUB_IF(rx.dev); + } + + if ((status->flag & RX_FLAG_MMIC_ERROR)) { + ieee80211_rx_michael_mic_report(local->mdev, hdr, sta, &rx); + goto end; + } + + if (unlikely(local->sta_scanning)) + rx.flags |= IEEE80211_TXRXD_RXIN_SCAN; + + if (__ieee80211_invoke_rx_handlers(local, local->rx_pre_handlers, &rx, + sta) != TXRX_CONTINUE) + goto end; + skb = rx.skb; + + if (sta && !(sta->flags & (WLAN_STA_WDS | WLAN_STA_ASSOC_AP)) && + !atomic_read(&local->iff_promiscs) && + !is_multicast_ether_addr(hdr->addr1)) { + rx.flags |= IEEE80211_TXRXD_RXRA_MATCH; + ieee80211_invoke_rx_handlers(local, local->rx_handlers, &rx, + rx.sta); + sta_info_put(sta); + rcu_read_unlock(); + return; + } + + bssid = ieee80211_get_bssid(hdr, skb->len); + + list_for_each_entry_rcu(sdata, &local->interfaces, list) { + if (!netif_running(sdata->dev)) + continue; + + if (sdata->type == IEEE80211_IF_TYPE_MNTR) + continue; + + rx.flags |= IEEE80211_TXRXD_RXRA_MATCH; + prepres = prepare_for_handlers(sdata, bssid, &rx, hdr); + /* prepare_for_handlers can change sta */ + sta = rx.sta; + + if (!prepres) + continue; + + /* + * frame is destined for this interface, but if it's not + * also for the previous one we handle that after the + * loop to avoid copying the SKB once too much + */ + + if (!prev) { + prev = sdata; + continue; + } + + /* + * frame was destined for the previous interface + * so invoke RX handlers for it + */ + + skb_new = skb_copy(skb, GFP_ATOMIC); + if (!skb_new) { + if (net_ratelimit()) + printk(KERN_DEBUG "%s: failed to copy " + "multicast frame for %s", + wiphy_name(local->hw.wiphy), + prev->dev->name); + continue; + } + rx.skb = skb_new; + rx.dev = prev->dev; + rx.sdata = prev; + ieee80211_invoke_rx_handlers(local, local->rx_handlers, + &rx, sta); + prev = sdata; + } + if (prev) { + rx.skb = skb; + rx.dev = prev->dev; + rx.sdata = prev; + ieee80211_invoke_rx_handlers(local, local->rx_handlers, + &rx, sta); + } else + dev_kfree_skb(skb); + + end: + rcu_read_unlock(); + + if (sta) + sta_info_put(sta); +} +EXPORT_SYMBOL(__ieee80211_rx); + +/* This is a version of the rx handler that can be called from hard irq + * context. Post the skb on the queue and schedule the tasklet */ +void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_rx_status *status) +{ + struct ieee80211_local *local = hw_to_local(hw); + + BUILD_BUG_ON(sizeof(struct ieee80211_rx_status) > sizeof(skb->cb)); + + skb->dev = local->mdev; + /* copy status into skb->cb for use by tasklet */ + memcpy(skb->cb, status, sizeof(*status)); + skb->pkt_type = IEEE80211_RX_MSG; + skb_queue_tail(&local->skb_queue, skb); + tasklet_schedule(&local->tasklet); +} +EXPORT_SYMBOL(ieee80211_rx_irqsafe); diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index ab7b1f0..e849155 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -19,7 +19,6 @@ #include "ieee80211_i.h" #include "ieee80211_rate.h" #include "sta_info.h" -#include "debugfs_key.h" #include "debugfs_sta.h" /* Caller must hold local->sta_lock */ @@ -32,38 +31,34 @@ static void sta_info_hash_add(struct ieee80211_local *local, /* Caller must hold local->sta_lock */ -static void sta_info_hash_del(struct ieee80211_local *local, - struct sta_info *sta) +static int sta_info_hash_del(struct ieee80211_local *local, + struct sta_info *sta) { struct sta_info *s; s = local->sta_hash[STA_HASH(sta->addr)]; if (!s) - return; - if (memcmp(s->addr, sta->addr, ETH_ALEN) == 0) { + return -ENOENT; + if (s == sta) { local->sta_hash[STA_HASH(sta->addr)] = s->hnext; - return; + return 0; } - while (s->hnext && memcmp(s->hnext->addr, sta->addr, ETH_ALEN) != 0) + while (s->hnext && s->hnext != sta) s = s->hnext; - if (s->hnext) - s->hnext = s->hnext->hnext; - else - printk(KERN_ERR "%s: could not remove STA " MAC_FMT " from " - "hash table\n", local->mdev->name, MAC_ARG(sta->addr)); -} + if (s->hnext) { + s->hnext = sta->hnext; + return 0; + } -static inline void __sta_info_get(struct sta_info *sta) -{ - kref_get(&sta->kref); + return -ENOENT; } struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr) { struct sta_info *sta; - spin_lock_bh(&local->sta_lock); + read_lock_bh(&local->sta_lock); sta = local->sta_hash[STA_HASH(addr)]; while (sta) { if (memcmp(sta->addr, addr, ETH_ALEN) == 0) { @@ -72,7 +67,7 @@ struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr) } sta = sta->hnext; } - spin_unlock_bh(&local->sta_lock); + read_unlock_bh(&local->sta_lock); return sta; } @@ -85,7 +80,7 @@ int sta_info_min_txrate_get(struct ieee80211_local *local) int min_txrate = 9999999; int i; - spin_lock_bh(&local->sta_lock); + read_lock_bh(&local->sta_lock); mode = local->oper_hw_mode; for (i = 0; i < STA_HASH_SIZE; i++) { sta = local->sta_hash[i]; @@ -95,7 +90,7 @@ int sta_info_min_txrate_get(struct ieee80211_local *local) sta = sta->hnext; } } - spin_unlock_bh(&local->sta_lock); + read_unlock_bh(&local->sta_lock); if (min_txrate == 9999999) min_txrate = 0; @@ -122,8 +117,6 @@ static void sta_info_release(struct kref *kref) } rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv); rate_control_put(sta->rate_ctrl); - if (sta->key) - ieee80211_debugfs_key_sta_del(sta->key, sta); kfree(sta); } @@ -139,6 +132,7 @@ struct sta_info * sta_info_add(struct ieee80211_local *local, struct net_device *dev, u8 *addr, gfp_t gfp) { struct sta_info *sta; + DECLARE_MAC_BUF(mac); sta = kzalloc(sizeof(*sta), gfp); if (!sta) @@ -150,7 +144,6 @@ struct sta_info * sta_info_add(struct ieee80211_local *local, sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl, gfp); if (!sta->rate_ctrl_priv) { rate_control_put(sta->rate_ctrl); - kref_put(&sta->kref, sta_info_release); kfree(sta); return NULL; } @@ -162,63 +155,40 @@ struct sta_info * sta_info_add(struct ieee80211_local *local, skb_queue_head_init(&sta->tx_filtered); __sta_info_get(sta); /* sta used by caller, decremented by * sta_info_put() */ - spin_lock_bh(&local->sta_lock); + write_lock_bh(&local->sta_lock); list_add(&sta->list, &local->sta_list); local->num_sta++; sta_info_hash_add(local, sta); - spin_unlock_bh(&local->sta_lock); - if (local->ops->sta_table_notification) - local->ops->sta_table_notification(local_to_hw(local), - local->num_sta); - sta->key_idx_compression = HW_KEY_IDX_INVALID; + if (local->ops->sta_notify) + local->ops->sta_notify(local_to_hw(local), dev->ifindex, + STA_NOTIFY_ADD, addr); + write_unlock_bh(&local->sta_lock); #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: Added STA " MAC_FMT "\n", - local->mdev->name, MAC_ARG(addr)); + printk(KERN_DEBUG "%s: Added STA %s\n", + wiphy_name(local->hw.wiphy), print_mac(mac, addr)); #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ #ifdef CONFIG_MAC80211_DEBUGFS - if (!in_interrupt()) { - sta->debugfs_registered = 1; - ieee80211_sta_debugfs_add(sta); - rate_control_add_sta_debugfs(sta); - } else { - /* debugfs entry adding might sleep, so schedule process - * context task for adding entry for STAs that do not yet - * have one. */ - queue_work(local->hw.workqueue, &local->sta_debugfs_add); - } + /* debugfs entry adding might sleep, so schedule process + * context task for adding entry for STAs that do not yet + * have one. */ + queue_work(local->hw.workqueue, &local->sta_debugfs_add); #endif return sta; } -static void finish_sta_info_free(struct ieee80211_local *local, - struct sta_info *sta) -{ -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: Removed STA " MAC_FMT "\n", - local->mdev->name, MAC_ARG(sta->addr)); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ - - if (sta->key) { - ieee80211_debugfs_key_remove(sta->key); - ieee80211_key_free(sta->key); - sta->key = NULL; - } - - rate_control_remove_sta_debugfs(sta); - ieee80211_sta_debugfs_remove(sta); - - sta_info_put(sta); -} - -static void sta_info_remove(struct sta_info *sta) +/* Caller must hold local->sta_lock */ +void sta_info_remove(struct sta_info *sta) { struct ieee80211_local *local = sta->local; struct ieee80211_sub_if_data *sdata; - sta_info_hash_del(local, sta); + /* don't do anything if we've been removed already */ + if (sta_info_hash_del(local, sta)) + return; + list_del(&sta->list); sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); if (sta->flags & WLAN_STA_PS) { @@ -228,61 +198,45 @@ static void sta_info_remove(struct sta_info *sta) } local->num_sta--; sta_info_remove_aid_ptr(sta); + } -void sta_info_free(struct sta_info *sta, int locked) +void sta_info_free(struct sta_info *sta) { struct sk_buff *skb; struct ieee80211_local *local = sta->local; + DECLARE_MAC_BUF(mac); - if (!locked) { - spin_lock_bh(&local->sta_lock); - sta_info_remove(sta); - spin_unlock_bh(&local->sta_lock); - } else { - sta_info_remove(sta); - } - if (local->ops->sta_table_notification) - local->ops->sta_table_notification(local_to_hw(local), - local->num_sta); + might_sleep(); + + write_lock_bh(&local->sta_lock); + sta_info_remove(sta); + write_unlock_bh(&local->sta_lock); while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { local->total_ps_buffered--; - dev_kfree_skb_any(skb); + dev_kfree_skb(skb); } while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { - dev_kfree_skb_any(skb); + dev_kfree_skb(skb); } - if (sta->key) { - if (local->ops->set_key) { - struct ieee80211_key_conf *key; - key = ieee80211_key_data2conf(local, sta->key); - if (key) { - local->ops->set_key(local_to_hw(local), - DISABLE_KEY, - sta->addr, key, sta->aid); - kfree(key); - } - } - } else if (sta->key_idx_compression != HW_KEY_IDX_INVALID) { - struct ieee80211_key_conf conf; - memset(&conf, 0, sizeof(conf)); - conf.hw_key_idx = sta->key_idx_compression; - conf.alg = ALG_NULL; - conf.flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT; - local->ops->set_key(local_to_hw(local), DISABLE_KEY, - sta->addr, &conf, sta->aid); - sta->key_idx_compression = HW_KEY_IDX_INVALID; - } +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + printk(KERN_DEBUG "%s: Removed STA %s\n", + wiphy_name(local->hw.wiphy), print_mac(mac, sta->addr)); +#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ -#ifdef CONFIG_MAC80211_DEBUGFS - if (in_atomic()) { - list_add(&sta->list, &local->deleted_sta_list); - queue_work(local->hw.workqueue, &local->sta_debugfs_add); - } else -#endif - finish_sta_info_free(local, sta); + ieee80211_key_free(sta->key); + sta->key = NULL; + + if (local->ops->sta_notify) + local->ops->sta_notify(local_to_hw(local), sta->dev->ifindex, + STA_NOTIFY_REMOVE, sta->addr); + + rate_control_remove_sta_debugfs(sta); + ieee80211_sta_debugfs_remove(sta); + + sta_info_put(sta); } @@ -312,6 +266,7 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, { unsigned long flags; struct sk_buff *skb; + DECLARE_MAC_BUF(mac); if (skb_queue_empty(&sta->ps_tx_buf)) return; @@ -330,7 +285,7 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, if (skb) { local->total_ps_buffered--; printk(KERN_DEBUG "Buffered frame expired (STA " - MAC_FMT ")\n", MAC_ARG(sta->addr)); + "%s)\n", print_mac(mac, sta->addr)); dev_kfree_skb(skb); } else break; @@ -343,13 +298,13 @@ static void sta_info_cleanup(unsigned long data) struct ieee80211_local *local = (struct ieee80211_local *) data; struct sta_info *sta; - spin_lock_bh(&local->sta_lock); + read_lock_bh(&local->sta_lock); list_for_each_entry(sta, &local->sta_list, list) { __sta_info_get(sta); sta_info_cleanup_expire_buffered(local, sta); sta_info_put(sta); } - spin_unlock_bh(&local->sta_lock); + read_unlock_bh(&local->sta_lock); local->sta_cleanup.expires = jiffies + STA_INFO_CLEANUP_INTERVAL; add_timer(&local->sta_cleanup); @@ -363,35 +318,20 @@ static void sta_info_debugfs_add_task(struct work_struct *work) struct sta_info *sta, *tmp; while (1) { - spin_lock_bh(&local->sta_lock); - if (!list_empty(&local->deleted_sta_list)) { - sta = list_entry(local->deleted_sta_list.next, - struct sta_info, list); - list_del(local->deleted_sta_list.next); - } else - sta = NULL; - spin_unlock_bh(&local->sta_lock); - if (!sta) - break; - finish_sta_info_free(local, sta); - } - - while (1) { sta = NULL; - spin_lock_bh(&local->sta_lock); + read_lock_bh(&local->sta_lock); list_for_each_entry(tmp, &local->sta_list, list) { - if (!tmp->debugfs_registered) { + if (!tmp->debugfs.dir) { sta = tmp; __sta_info_get(sta); break; } } - spin_unlock_bh(&local->sta_lock); + read_unlock_bh(&local->sta_lock); if (!sta) break; - sta->debugfs_registered = 1; ieee80211_sta_debugfs_add(sta); rate_control_add_sta_debugfs(sta); sta_info_put(sta); @@ -401,9 +341,8 @@ static void sta_info_debugfs_add_task(struct work_struct *work) void sta_info_init(struct ieee80211_local *local) { - spin_lock_init(&local->sta_lock); + rwlock_init(&local->sta_lock); INIT_LIST_HEAD(&local->sta_list); - INIT_LIST_HEAD(&local->deleted_sta_list); init_timer(&local->sta_cleanup); local->sta_cleanup.expires = jiffies + STA_INFO_CLEANUP_INTERVAL; @@ -423,17 +362,8 @@ int sta_info_start(struct ieee80211_local *local) void sta_info_stop(struct ieee80211_local *local) { - struct sta_info *sta, *tmp; - del_timer(&local->sta_cleanup); - - list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { - /* sta_info_free must be called with 0 as the last - * parameter to ensure all debugfs sta entries are - * unregistered. We don't need locking at this - * point. */ - sta_info_free(sta, 0); - } + sta_info_flush(local, NULL); } void sta_info_remove_aid_ptr(struct sta_info *sta) @@ -461,10 +391,19 @@ void sta_info_remove_aid_ptr(struct sta_info *sta) void sta_info_flush(struct ieee80211_local *local, struct net_device *dev) { struct sta_info *sta, *tmp; + LIST_HEAD(tmp_list); - spin_lock_bh(&local->sta_lock); + write_lock_bh(&local->sta_lock); list_for_each_entry_safe(sta, tmp, &local->sta_list, list) - if (!dev || dev == sta->dev) - sta_info_free(sta, 1); - spin_unlock_bh(&local->sta_lock); + if (!dev || dev == sta->dev) { + __sta_info_get(sta); + sta_info_remove(sta); + list_add_tail(&sta->list, &tmp_list); + } + write_unlock_bh(&local->sta_lock); + + list_for_each_entry_safe(sta, tmp, &tmp_list, list) { + sta_info_free(sta); + sta_info_put(sta); + } } diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index b5591d2..8f7ebe4 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -26,6 +26,8 @@ * send and receive non-IEEE 802.1X frames */ #define WLAN_STA_SHORT_PREAMBLE BIT(7) +/* whether this is an AP that we are associated with as a client */ +#define WLAN_STA_ASSOC_AP BIT(8) #define WLAN_STA_WME BIT(9) #define WLAN_STA_WDS BIT(27) @@ -90,27 +92,11 @@ struct sta_info { int channel_use; int channel_use_raw; - u8 antenna_sel_tx; - u8 antenna_sel_rx; - - - int key_idx_compression; /* key table index for compression and TX - * filtering; used only if sta->key is not - * set */ - -#ifdef CONFIG_MAC80211_DEBUGFS - int debugfs_registered; -#endif - int assoc_ap; /* whether this is an AP that we are - * associated with as a client */ - #ifdef CONFIG_MAC80211_DEBUG_COUNTERS unsigned int wme_rx_queue[NUM_RX_DATA_QUEUES]; unsigned int wme_tx_queue[NUM_RX_DATA_QUEUES]; #endif /* CONFIG_MAC80211_DEBUG_COUNTERS */ - int vlan_id; - u16 listen_interval; #ifdef CONFIG_MAC80211_DEBUGFS @@ -149,12 +135,18 @@ struct sta_info { */ #define STA_INFO_CLEANUP_INTERVAL (10 * HZ) +static inline void __sta_info_get(struct sta_info *sta) +{ + kref_get(&sta->kref); +} + struct sta_info * sta_info_get(struct ieee80211_local *local, u8 *addr); int sta_info_min_txrate_get(struct ieee80211_local *local); void sta_info_put(struct sta_info *sta); struct sta_info * sta_info_add(struct ieee80211_local *local, struct net_device *dev, u8 *addr, gfp_t gfp); -void sta_info_free(struct sta_info *sta, int locked); +void sta_info_remove(struct sta_info *sta); +void sta_info_free(struct sta_info *sta); void sta_info_init(struct ieee80211_local *local); int sta_info_start(struct ieee80211_local *local); void sta_info_stop(struct ieee80211_local *local); diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index 4162172..3abe194 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c @@ -182,7 +182,7 @@ u8 * ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key, *pos++ = iv0; *pos++ = iv1; *pos++ = iv2; - *pos++ = (key->keyidx << 6) | (1 << 5) /* Ext IV */; + *pos++ = (key->conf.keyidx << 6) | (1 << 5) /* Ext IV */; *pos++ = key->u.tkip.iv32 & 0xff; *pos++ = (key->u.tkip.iv32 >> 8) & 0xff; *pos++ = (key->u.tkip.iv32 >> 16) & 0xff; @@ -194,7 +194,7 @@ u8 * ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key, void ieee80211_tkip_gen_phase1key(struct ieee80211_key *key, u8 *ta, u16 *phase1key) { - tkip_mixing_phase1(ta, &key->key[ALG_TKIP_TEMP_ENCR_KEY], + tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], key->u.tkip.iv32, phase1key); } @@ -204,12 +204,13 @@ void ieee80211_tkip_gen_rc4key(struct ieee80211_key *key, u8 *ta, /* Calculate per-packet key */ if (key->u.tkip.iv16 == 0 || !key->u.tkip.tx_initialized) { /* IV16 wrapped around - perform TKIP phase 1 */ - tkip_mixing_phase1(ta, &key->key[ALG_TKIP_TEMP_ENCR_KEY], + tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], key->u.tkip.iv32, key->u.tkip.p1k); key->u.tkip.tx_initialized = 1; } - tkip_mixing_phase2(key->u.tkip.p1k, &key->key[ALG_TKIP_TEMP_ENCR_KEY], + tkip_mixing_phase2(key->u.tkip.p1k, + &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], key->u.tkip.iv16, rc4key); } @@ -237,7 +238,8 @@ void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm, int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, struct ieee80211_key *key, u8 *payload, size_t payload_len, u8 *ta, - int only_iv, int queue) + int only_iv, int queue, + u32 *out_iv32, u16 *out_iv16) { u32 iv32; u32 iv16; @@ -266,7 +268,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, if (!(keyid & (1 << 5))) return TKIP_DECRYPT_NO_EXT_IV; - if ((keyid >> 6) != key->keyidx) + if ((keyid >> 6) != key->conf.keyidx) return TKIP_DECRYPT_INVALID_KEYIDX; if (key->u.tkip.rx_initialized[queue] && @@ -274,9 +276,10 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, (iv32 == key->u.tkip.iv32_rx[queue] && iv16 <= key->u.tkip.iv16_rx[queue]))) { #ifdef CONFIG_TKIP_DEBUG + DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "TKIP replay detected for RX frame from " - MAC_FMT " (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n", - MAC_ARG(ta), + "%s (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n", + print_mac(mac, ta), iv32, iv16, key->u.tkip.iv32_rx[queue], key->u.tkip.iv16_rx[queue]); #endif /* CONFIG_TKIP_DEBUG */ @@ -293,16 +296,18 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, key->u.tkip.iv32_rx[queue] != iv32) { key->u.tkip.rx_initialized[queue] = 1; /* IV16 wrapped around - perform TKIP phase 1 */ - tkip_mixing_phase1(ta, &key->key[ALG_TKIP_TEMP_ENCR_KEY], + tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], iv32, key->u.tkip.p1k_rx[queue]); #ifdef CONFIG_TKIP_DEBUG { int i; - printk(KERN_DEBUG "TKIP decrypt: Phase1 TA=" MAC_FMT - " TK=", MAC_ARG(ta)); + DECLARE_MAC_BUF(mac); + printk(KERN_DEBUG "TKIP decrypt: Phase1 TA=%s" + " TK=", print_mac(mac, ta)); for (i = 0; i < 16; i++) printk("%02x ", - key->key[ALG_TKIP_TEMP_ENCR_KEY + i]); + key->conf.key[ + ALG_TKIP_TEMP_ENCR_KEY + i]); printk("\n"); printk(KERN_DEBUG "TKIP decrypt: P1K="); for (i = 0; i < 5; i++) @@ -313,7 +318,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, } tkip_mixing_phase2(key->u.tkip.p1k_rx[queue], - &key->key[ALG_TKIP_TEMP_ENCR_KEY], + &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], iv16, rc4key); #ifdef CONFIG_TKIP_DEBUG { @@ -328,11 +333,14 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, res = ieee80211_wep_decrypt_data(tfm, rc4key, 16, pos, payload_len - 12); done: if (res == TKIP_DECRYPT_OK) { - /* FIX: these should be updated only after Michael MIC has been - * verified */ - /* Record previously received IV */ - key->u.tkip.iv32_rx[queue] = iv32; - key->u.tkip.iv16_rx[queue] = iv16; + /* + * Record previously received IV, will be copied into the + * key information after MIC verification. It is possible + * that we don't catch replays of fragments but that's ok + * because the Michael MIC verication will then fail. + */ + *out_iv32 = iv32; + *out_iv16 = iv16; } return res; diff --git a/net/mac80211/tkip.h b/net/mac80211/tkip.h index a0d181a..73d8ef2 100644 --- a/net/mac80211/tkip.h +++ b/net/mac80211/tkip.h @@ -31,6 +31,7 @@ enum { int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, struct ieee80211_key *key, u8 *payload, size_t payload_len, u8 *ta, - int only_iv, int queue); + int only_iv, int queue, + u32 *out_iv32, u16 *out_iv16); #endif /* TKIP_H */ diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c new file mode 100644 index 0000000..1a53154 --- /dev/null +++ b/net/mac80211/tx.c @@ -0,0 +1,1903 @@ +/* + * Copyright 2002-2005, Instant802 Networks, Inc. + * Copyright 2005-2006, Devicescape Software, Inc. + * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> + * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * + * Transmit and frame generation functions. + */ + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/skbuff.h> +#include <linux/etherdevice.h> +#include <linux/bitmap.h> +#include <linux/rcupdate.h> +#include <net/net_namespace.h> +#include <net/ieee80211_radiotap.h> +#include <net/cfg80211.h> +#include <net/mac80211.h> +#include <asm/unaligned.h> + +#include "ieee80211_i.h" +#include "ieee80211_led.h" +#include "wep.h" +#include "wpa.h" +#include "wme.h" +#include "ieee80211_rate.h" + +#define IEEE80211_TX_OK 0 +#define IEEE80211_TX_AGAIN 1 +#define IEEE80211_TX_FRAG_AGAIN 2 + +/* misc utils */ + +static inline void ieee80211_include_sequence(struct ieee80211_sub_if_data *sdata, + struct ieee80211_hdr *hdr) +{ + /* Set the sequence number for this frame. */ + hdr->seq_ctrl = cpu_to_le16(sdata->sequence); + + /* Increase the sequence number. */ + sdata->sequence = (sdata->sequence + 0x10) & IEEE80211_SCTL_SEQ; +} + +#ifdef CONFIG_MAC80211_LOWTX_FRAME_DUMP +static void ieee80211_dump_frame(const char *ifname, const char *title, + const struct sk_buff *skb) +{ + const struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u16 fc; + int hdrlen; + DECLARE_MAC_BUF(mac); + + printk(KERN_DEBUG "%s: %s (len=%d)", ifname, title, skb->len); + if (skb->len < 4) { + printk("\n"); + return; + } + + fc = le16_to_cpu(hdr->frame_control); + hdrlen = ieee80211_get_hdrlen(fc); + if (hdrlen > skb->len) + hdrlen = skb->len; + if (hdrlen >= 4) + printk(" FC=0x%04x DUR=0x%04x", + fc, le16_to_cpu(hdr->duration_id)); + if (hdrlen >= 10) + printk(" A1=%s", print_mac(mac, hdr->addr1)); + if (hdrlen >= 16) + printk(" A2=%s", print_mac(mac, hdr->addr2)); + if (hdrlen >= 24) + printk(" A3=%s", print_mac(mac, hdr->addr3)); + if (hdrlen >= 30) + printk(" A4=%s", print_mac(mac, hdr->addr4)); + printk("\n"); +} +#else /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */ +static inline void ieee80211_dump_frame(const char *ifname, const char *title, + struct sk_buff *skb) +{ +} +#endif /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */ + +static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr, + int next_frag_len) +{ + int rate, mrate, erp, dur, i; + struct ieee80211_rate *txrate = tx->u.tx.rate; + struct ieee80211_local *local = tx->local; + struct ieee80211_hw_mode *mode = tx->u.tx.mode; + + erp = txrate->flags & IEEE80211_RATE_ERP; + + /* + * data and mgmt (except PS Poll): + * - during CFP: 32768 + * - during contention period: + * if addr1 is group address: 0 + * if more fragments = 0 and addr1 is individual address: time to + * transmit one ACK plus SIFS + * if more fragments = 1 and addr1 is individual address: time to + * transmit next fragment plus 2 x ACK plus 3 x SIFS + * + * IEEE 802.11, 9.6: + * - control response frame (CTS or ACK) shall be transmitted using the + * same rate as the immediately previous frame in the frame exchange + * sequence, if this rate belongs to the PHY mandatory rates, or else + * at the highest possible rate belonging to the PHY rates in the + * BSSBasicRateSet + */ + + if ((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) { + /* TODO: These control frames are not currently sent by + * 80211.o, but should they be implemented, this function + * needs to be updated to support duration field calculation. + * + * RTS: time needed to transmit pending data/mgmt frame plus + * one CTS frame plus one ACK frame plus 3 x SIFS + * CTS: duration of immediately previous RTS minus time + * required to transmit CTS and its SIFS + * ACK: 0 if immediately previous directed data/mgmt had + * more=0, with more=1 duration in ACK frame is duration + * from previous frame minus time needed to transmit ACK + * and its SIFS + * PS Poll: BIT(15) | BIT(14) | aid + */ + return 0; + } + + /* data/mgmt */ + if (0 /* FIX: data/mgmt during CFP */) + return 32768; + + if (group_addr) /* Group address as the destination - no ACK */ + return 0; + + /* Individual destination address: + * IEEE 802.11, Ch. 9.6 (after IEEE 802.11g changes) + * CTS and ACK frames shall be transmitted using the highest rate in + * basic rate set that is less than or equal to the rate of the + * immediately previous frame and that is using the same modulation + * (CCK or OFDM). If no basic rate set matches with these requirements, + * the highest mandatory rate of the PHY that is less than or equal to + * the rate of the previous frame is used. + * Mandatory rates for IEEE 802.11g PHY: 1, 2, 5.5, 11, 6, 12, 24 Mbps + */ + rate = -1; + mrate = 10; /* use 1 Mbps if everything fails */ + for (i = 0; i < mode->num_rates; i++) { + struct ieee80211_rate *r = &mode->rates[i]; + if (r->rate > txrate->rate) + break; + + if (IEEE80211_RATE_MODULATION(txrate->flags) != + IEEE80211_RATE_MODULATION(r->flags)) + continue; + + if (r->flags & IEEE80211_RATE_BASIC) + rate = r->rate; + else if (r->flags & IEEE80211_RATE_MANDATORY) + mrate = r->rate; + } + if (rate == -1) { + /* No matching basic rate found; use highest suitable mandatory + * PHY rate */ + rate = mrate; + } + + /* Time needed to transmit ACK + * (10 bytes + 4-byte FCS = 112 bits) plus SIFS; rounded up + * to closest integer */ + + dur = ieee80211_frame_duration(local, 10, rate, erp, + tx->sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE); + + if (next_frag_len) { + /* Frame is fragmented: duration increases with time needed to + * transmit next fragment plus ACK and 2 x SIFS. */ + dur *= 2; /* ACK + SIFS */ + /* next fragment */ + dur += ieee80211_frame_duration(local, next_frag_len, + txrate->rate, erp, + tx->sdata->flags & + IEEE80211_SDATA_SHORT_PREAMBLE); + } + + return dur; +} + +static inline int __ieee80211_queue_stopped(const struct ieee80211_local *local, + int queue) +{ + return test_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]); +} + +static inline int __ieee80211_queue_pending(const struct ieee80211_local *local, + int queue) +{ + return test_bit(IEEE80211_LINK_STATE_PENDING, &local->state[queue]); +} + +static int inline is_ieee80211_device(struct net_device *dev, + struct net_device *master) +{ + return (wdev_priv(dev->ieee80211_ptr) == + wdev_priv(master->ieee80211_ptr)); +} + +/* tx handlers */ + +static ieee80211_txrx_result +ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) +{ +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + struct sk_buff *skb = tx->skb; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; +#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + u32 sta_flags; + + if (unlikely(tx->flags & IEEE80211_TXRXD_TX_INJECTED)) + return TXRX_CONTINUE; + + if (unlikely(tx->local->sta_scanning != 0) && + ((tx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || + (tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ)) + return TXRX_DROP; + + if (tx->flags & IEEE80211_TXRXD_TXPS_BUFFERED) + return TXRX_CONTINUE; + + sta_flags = tx->sta ? tx->sta->flags : 0; + + if (likely(tx->flags & IEEE80211_TXRXD_TXUNICAST)) { + if (unlikely(!(sta_flags & WLAN_STA_ASSOC) && + tx->sdata->type != IEEE80211_IF_TYPE_IBSS && + (tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) { +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + DECLARE_MAC_BUF(mac); + printk(KERN_DEBUG "%s: dropped data frame to not " + "associated station %s\n", + tx->dev->name, print_mac(mac, hdr->addr1)); +#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc); + return TXRX_DROP; + } + } else { + if (unlikely((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && + tx->local->num_sta == 0 && + tx->sdata->type != IEEE80211_IF_TYPE_IBSS)) { + /* + * No associated STAs - no need to send multicast + * frames. + */ + return TXRX_DROP; + } + return TXRX_CONTINUE; + } + + if (unlikely(/* !injected && */ tx->sdata->ieee802_1x && + !(sta_flags & WLAN_STA_AUTHORIZED))) { +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + DECLARE_MAC_BUF(mac); + printk(KERN_DEBUG "%s: dropped frame to %s" + " (unauthorized port)\n", tx->dev->name, + print_mac(mac, hdr->addr1)); +#endif + I802_DEBUG_INC(tx->local->tx_handlers_drop_unauth_port); + return TXRX_DROP; + } + + return TXRX_CONTINUE; +} + +static ieee80211_txrx_result +ieee80211_tx_h_sequence(struct ieee80211_txrx_data *tx) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; + + if (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)) >= 24) + ieee80211_include_sequence(tx->sdata, hdr); + + return TXRX_CONTINUE; +} + +/* This function is called whenever the AP is about to exceed the maximum limit + * of buffered frames for power saving STAs. This situation should not really + * happen often during normal operation, so dropping the oldest buffered packet + * from each queue should be OK to make some room for new frames. */ +static void purge_old_ps_buffers(struct ieee80211_local *local) +{ + int total = 0, purged = 0; + struct sk_buff *skb; + struct ieee80211_sub_if_data *sdata; + struct sta_info *sta; + + /* + * virtual interfaces are protected by RCU + */ + rcu_read_lock(); + + list_for_each_entry_rcu(sdata, &local->interfaces, list) { + struct ieee80211_if_ap *ap; + if (sdata->dev == local->mdev || + sdata->type != IEEE80211_IF_TYPE_AP) + continue; + ap = &sdata->u.ap; + skb = skb_dequeue(&ap->ps_bc_buf); + if (skb) { + purged++; + dev_kfree_skb(skb); + } + total += skb_queue_len(&ap->ps_bc_buf); + } + rcu_read_unlock(); + + read_lock_bh(&local->sta_lock); + list_for_each_entry(sta, &local->sta_list, list) { + skb = skb_dequeue(&sta->ps_tx_buf); + if (skb) { + purged++; + dev_kfree_skb(skb); + } + total += skb_queue_len(&sta->ps_tx_buf); + } + read_unlock_bh(&local->sta_lock); + + local->total_ps_buffered = total; + printk(KERN_DEBUG "%s: PS buffers full - purged %d frames\n", + wiphy_name(local->hw.wiphy), purged); +} + +static inline ieee80211_txrx_result +ieee80211_tx_h_multicast_ps_buf(struct ieee80211_txrx_data *tx) +{ + /* broadcast/multicast frame */ + /* If any of the associated stations is in power save mode, + * the frame is buffered to be sent after DTIM beacon frame */ + if ((tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING) && + tx->sdata->type != IEEE80211_IF_TYPE_WDS && + tx->sdata->bss && atomic_read(&tx->sdata->bss->num_sta_ps) && + !(tx->fc & IEEE80211_FCTL_ORDER)) { + if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) + purge_old_ps_buffers(tx->local); + if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >= + AP_MAX_BC_BUFFER) { + if (net_ratelimit()) { + printk(KERN_DEBUG "%s: BC TX buffer full - " + "dropping the oldest frame\n", + tx->dev->name); + } + dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf)); + } else + tx->local->total_ps_buffered++; + skb_queue_tail(&tx->sdata->bss->ps_bc_buf, tx->skb); + return TXRX_QUEUED; + } + + return TXRX_CONTINUE; +} + +static inline ieee80211_txrx_result +ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) +{ + struct sta_info *sta = tx->sta; + DECLARE_MAC_BUF(mac); + + if (unlikely(!sta || + ((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT && + (tx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP))) + return TXRX_CONTINUE; + + if (unlikely((sta->flags & WLAN_STA_PS) && !sta->pspoll)) { + struct ieee80211_tx_packet_data *pkt_data; +#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG + printk(KERN_DEBUG "STA %s aid %d: PS buffer (entries " + "before %d)\n", + print_mac(mac, sta->addr), sta->aid, + skb_queue_len(&sta->ps_tx_buf)); +#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ + sta->flags |= WLAN_STA_TIM; + if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) + purge_old_ps_buffers(tx->local); + if (skb_queue_len(&sta->ps_tx_buf) >= STA_MAX_TX_BUFFER) { + struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf); + if (net_ratelimit()) { + printk(KERN_DEBUG "%s: STA %s TX " + "buffer full - dropping oldest frame\n", + tx->dev->name, print_mac(mac, sta->addr)); + } + dev_kfree_skb(old); + } else + tx->local->total_ps_buffered++; + /* Queue frame to be sent after STA sends an PS Poll frame */ + if (skb_queue_empty(&sta->ps_tx_buf)) { + if (tx->local->ops->set_tim) + tx->local->ops->set_tim(local_to_hw(tx->local), + sta->aid, 1); + if (tx->sdata->bss) + bss_tim_set(tx->local, tx->sdata->bss, sta->aid); + } + pkt_data = (struct ieee80211_tx_packet_data *)tx->skb->cb; + pkt_data->jiffies = jiffies; + skb_queue_tail(&sta->ps_tx_buf, tx->skb); + return TXRX_QUEUED; + } +#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG + else if (unlikely(sta->flags & WLAN_STA_PS)) { + printk(KERN_DEBUG "%s: STA %s in PS mode, but pspoll " + "set -> send frame\n", tx->dev->name, + print_mac(mac, sta->addr)); + } +#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ + sta->pspoll = 0; + + return TXRX_CONTINUE; +} + + +static ieee80211_txrx_result +ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx) +{ + if (unlikely(tx->flags & IEEE80211_TXRXD_TXPS_BUFFERED)) + return TXRX_CONTINUE; + + if (tx->flags & IEEE80211_TXRXD_TXUNICAST) + return ieee80211_tx_h_unicast_ps_buf(tx); + else + return ieee80211_tx_h_multicast_ps_buf(tx); +} + + + + +static ieee80211_txrx_result +ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx) +{ + struct ieee80211_key *key; + + if (unlikely(tx->u.tx.control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) + tx->key = NULL; + else if (tx->sta && (key = rcu_dereference(tx->sta->key))) + tx->key = key; + else if ((key = rcu_dereference(tx->sdata->default_key))) + tx->key = key; + else if (tx->sdata->drop_unencrypted && + !(tx->sdata->eapol && ieee80211_is_eapol(tx->skb))) { + I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); + return TXRX_DROP; + } else { + tx->key = NULL; + tx->u.tx.control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; + } + + if (tx->key) { + tx->key->tx_rx_count++; + /* TODO: add threshold stuff again */ + } + + return TXRX_CONTINUE; +} + +static ieee80211_txrx_result +ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; + size_t hdrlen, per_fragm, num_fragm, payload_len, left; + struct sk_buff **frags, *first, *frag; + int i; + u16 seq; + u8 *pos; + int frag_threshold = tx->local->fragmentation_threshold; + + if (!(tx->flags & IEEE80211_TXRXD_FRAGMENTED)) + return TXRX_CONTINUE; + + first = tx->skb; + + hdrlen = ieee80211_get_hdrlen(tx->fc); + payload_len = first->len - hdrlen; + per_fragm = frag_threshold - hdrlen - FCS_LEN; + num_fragm = DIV_ROUND_UP(payload_len, per_fragm); + + frags = kzalloc(num_fragm * sizeof(struct sk_buff *), GFP_ATOMIC); + if (!frags) + goto fail; + + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREFRAGS); + seq = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ; + pos = first->data + hdrlen + per_fragm; + left = payload_len - per_fragm; + for (i = 0; i < num_fragm - 1; i++) { + struct ieee80211_hdr *fhdr; + size_t copylen; + + if (left <= 0) + goto fail; + + /* reserve enough extra head and tail room for possible + * encryption */ + frag = frags[i] = + dev_alloc_skb(tx->local->tx_headroom + + frag_threshold + + IEEE80211_ENCRYPT_HEADROOM + + IEEE80211_ENCRYPT_TAILROOM); + if (!frag) + goto fail; + /* Make sure that all fragments use the same priority so + * that they end up using the same TX queue */ + frag->priority = first->priority; + skb_reserve(frag, tx->local->tx_headroom + + IEEE80211_ENCRYPT_HEADROOM); + fhdr = (struct ieee80211_hdr *) skb_put(frag, hdrlen); + memcpy(fhdr, first->data, hdrlen); + if (i == num_fragm - 2) + fhdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREFRAGS); + fhdr->seq_ctrl = cpu_to_le16(seq | ((i + 1) & IEEE80211_SCTL_FRAG)); + copylen = left > per_fragm ? per_fragm : left; + memcpy(skb_put(frag, copylen), pos, copylen); + + pos += copylen; + left -= copylen; + } + skb_trim(first, hdrlen + per_fragm); + + tx->u.tx.num_extra_frag = num_fragm - 1; + tx->u.tx.extra_frag = frags; + + return TXRX_CONTINUE; + + fail: + printk(KERN_DEBUG "%s: failed to fragment frame\n", tx->dev->name); + if (frags) { + for (i = 0; i < num_fragm - 1; i++) + if (frags[i]) + dev_kfree_skb(frags[i]); + kfree(frags); + } + I802_DEBUG_INC(tx->local->tx_handlers_drop_fragment); + return TXRX_DROP; +} + +static ieee80211_txrx_result +ieee80211_tx_h_encrypt(struct ieee80211_txrx_data *tx) +{ + if (!tx->key) + return TXRX_CONTINUE; + + switch (tx->key->conf.alg) { + case ALG_WEP: + return ieee80211_crypto_wep_encrypt(tx); + case ALG_TKIP: + return ieee80211_crypto_tkip_encrypt(tx); + case ALG_CCMP: + return ieee80211_crypto_ccmp_encrypt(tx); + } + + /* not reached */ + WARN_ON(1); + return TXRX_DROP; +} + +static ieee80211_txrx_result +ieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx) +{ + struct rate_control_extra extra; + + if (likely(!tx->u.tx.rate)) { + memset(&extra, 0, sizeof(extra)); + extra.mode = tx->u.tx.mode; + extra.ethertype = tx->ethertype; + + tx->u.tx.rate = rate_control_get_rate(tx->local, tx->dev, + tx->skb, &extra); + if (unlikely(extra.probe != NULL)) { + tx->u.tx.control->flags |= + IEEE80211_TXCTL_RATE_CTRL_PROBE; + tx->flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG; + tx->u.tx.control->alt_retry_rate = tx->u.tx.rate->val; + tx->u.tx.rate = extra.probe; + } else + tx->u.tx.control->alt_retry_rate = -1; + + if (!tx->u.tx.rate) + return TXRX_DROP; + } else + tx->u.tx.control->alt_retry_rate = -1; + + if (tx->u.tx.mode->mode == MODE_IEEE80211G && + (tx->sdata->flags & IEEE80211_SDATA_USE_PROTECTION) && + (tx->flags & IEEE80211_TXRXD_FRAGMENTED) && extra.nonerp) { + tx->u.tx.last_frag_rate = tx->u.tx.rate; + if (extra.probe) + tx->flags &= ~IEEE80211_TXRXD_TXPROBE_LAST_FRAG; + else + tx->flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG; + tx->u.tx.rate = extra.nonerp; + tx->u.tx.control->rate = extra.nonerp; + tx->u.tx.control->flags &= ~IEEE80211_TXCTL_RATE_CTRL_PROBE; + } else { + tx->u.tx.last_frag_rate = tx->u.tx.rate; + tx->u.tx.control->rate = tx->u.tx.rate; + } + tx->u.tx.control->tx_rate = tx->u.tx.rate->val; + + return TXRX_CONTINUE; +} + +static ieee80211_txrx_result +ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; + u16 fc = le16_to_cpu(hdr->frame_control); + u16 dur; + struct ieee80211_tx_control *control = tx->u.tx.control; + struct ieee80211_hw_mode *mode = tx->u.tx.mode; + + if (!control->retry_limit) { + if (!is_multicast_ether_addr(hdr->addr1)) { + if (tx->skb->len + FCS_LEN > tx->local->rts_threshold + && tx->local->rts_threshold < + IEEE80211_MAX_RTS_THRESHOLD) { + control->flags |= + IEEE80211_TXCTL_USE_RTS_CTS; + control->flags |= + IEEE80211_TXCTL_LONG_RETRY_LIMIT; + control->retry_limit = + tx->local->long_retry_limit; + } else { + control->retry_limit = + tx->local->short_retry_limit; + } + } else { + control->retry_limit = 1; + } + } + + if (tx->flags & IEEE80211_TXRXD_FRAGMENTED) { + /* Do not use multiple retry rates when sending fragmented + * frames. + * TODO: The last fragment could still use multiple retry + * rates. */ + control->alt_retry_rate = -1; + } + + /* Use CTS protection for unicast frames sent using extended rates if + * there are associated non-ERP stations and RTS/CTS is not configured + * for the frame. */ + if (mode->mode == MODE_IEEE80211G && + (tx->u.tx.rate->flags & IEEE80211_RATE_ERP) && + (tx->flags & IEEE80211_TXRXD_TXUNICAST) && + (tx->sdata->flags & IEEE80211_SDATA_USE_PROTECTION) && + !(control->flags & IEEE80211_TXCTL_USE_RTS_CTS)) + control->flags |= IEEE80211_TXCTL_USE_CTS_PROTECT; + + /* Transmit data frames using short preambles if the driver supports + * short preambles at the selected rate and short preambles are + * available on the network at the current point in time. */ + if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && + (tx->u.tx.rate->flags & IEEE80211_RATE_PREAMBLE2) && + (tx->sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE) && + (!tx->sta || (tx->sta->flags & WLAN_STA_SHORT_PREAMBLE))) { + tx->u.tx.control->tx_rate = tx->u.tx.rate->val2; + } + + /* Setup duration field for the first fragment of the frame. Duration + * for remaining fragments will be updated when they are being sent + * to low-level driver in ieee80211_tx(). */ + dur = ieee80211_duration(tx, is_multicast_ether_addr(hdr->addr1), + (tx->flags & IEEE80211_TXRXD_FRAGMENTED) ? + tx->u.tx.extra_frag[0]->len : 0); + hdr->duration_id = cpu_to_le16(dur); + + if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) || + (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) { + struct ieee80211_rate *rate; + + /* Do not use multiple retry rates when using RTS/CTS */ + control->alt_retry_rate = -1; + + /* Use min(data rate, max base rate) as CTS/RTS rate */ + rate = tx->u.tx.rate; + while (rate > mode->rates && + !(rate->flags & IEEE80211_RATE_BASIC)) + rate--; + + control->rts_cts_rate = rate->val; + control->rts_rate = rate; + } + + if (tx->sta) { + tx->sta->tx_packets++; + tx->sta->tx_fragments++; + tx->sta->tx_bytes += tx->skb->len; + if (tx->u.tx.extra_frag) { + int i; + tx->sta->tx_fragments += tx->u.tx.num_extra_frag; + for (i = 0; i < tx->u.tx.num_extra_frag; i++) { + tx->sta->tx_bytes += + tx->u.tx.extra_frag[i]->len; + } + } + } + + /* + * Tell hardware to not encrypt when we had sw crypto. + * Because we use the same flag to internally indicate that + * no (software) encryption should be done, we have to set it + * after all crypto handlers. + */ + if (tx->key && !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) + tx->u.tx.control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; + + return TXRX_CONTINUE; +} + +static ieee80211_txrx_result +ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx) +{ + struct ieee80211_local *local = tx->local; + struct ieee80211_hw_mode *mode = tx->u.tx.mode; + struct sk_buff *skb = tx->skb; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u32 load = 0, hdrtime; + + /* TODO: this could be part of tx_status handling, so that the number + * of retries would be known; TX rate should in that case be stored + * somewhere with the packet */ + + /* Estimate total channel use caused by this frame */ + + /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values, + * 1 usec = 1/8 * (1080 / 10) = 13.5 */ + + if (mode->mode == MODE_IEEE80211A || + (mode->mode == MODE_IEEE80211G && + tx->u.tx.rate->flags & IEEE80211_RATE_ERP)) + hdrtime = CHAN_UTIL_HDR_SHORT; + else + hdrtime = CHAN_UTIL_HDR_LONG; + + load = hdrtime; + if (!is_multicast_ether_addr(hdr->addr1)) + load += hdrtime; + + if (tx->u.tx.control->flags & IEEE80211_TXCTL_USE_RTS_CTS) + load += 2 * hdrtime; + else if (tx->u.tx.control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) + load += hdrtime; + + load += skb->len * tx->u.tx.rate->rate_inv; + + if (tx->u.tx.extra_frag) { + int i; + for (i = 0; i < tx->u.tx.num_extra_frag; i++) { + load += 2 * hdrtime; + load += tx->u.tx.extra_frag[i]->len * + tx->u.tx.rate->rate; + } + } + + /* Divide channel_use by 8 to avoid wrapping around the counter */ + load >>= CHAN_UTIL_SHIFT; + local->channel_use_raw += load; + if (tx->sta) + tx->sta->channel_use_raw += load; + tx->sdata->channel_use_raw += load; + + return TXRX_CONTINUE; +} + +/* TODO: implement register/unregister functions for adding TX/RX handlers + * into ordered list */ + +ieee80211_tx_handler ieee80211_tx_handlers[] = +{ + ieee80211_tx_h_check_assoc, + ieee80211_tx_h_sequence, + ieee80211_tx_h_ps_buf, + ieee80211_tx_h_select_key, + ieee80211_tx_h_michael_mic_add, + ieee80211_tx_h_fragment, + ieee80211_tx_h_encrypt, + ieee80211_tx_h_rate_ctrl, + ieee80211_tx_h_misc, + ieee80211_tx_h_load_stats, + NULL +}; + +/* actual transmit path */ + +/* + * deal with packet injection down monitor interface + * with Radiotap Header -- only called for monitor mode interface + */ +static ieee80211_txrx_result +__ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, + struct sk_buff *skb) +{ + /* + * this is the moment to interpret and discard the radiotap header that + * must be at the start of the packet injected in Monitor mode + * + * Need to take some care with endian-ness since radiotap + * args are little-endian + */ + + struct ieee80211_radiotap_iterator iterator; + struct ieee80211_radiotap_header *rthdr = + (struct ieee80211_radiotap_header *) skb->data; + struct ieee80211_hw_mode *mode = tx->local->hw.conf.mode; + int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len); + struct ieee80211_tx_control *control = tx->u.tx.control; + + control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; + tx->flags |= IEEE80211_TXRXD_TX_INJECTED; + tx->flags &= ~IEEE80211_TXRXD_FRAGMENTED; + + /* + * for every radiotap entry that is present + * (ieee80211_radiotap_iterator_next returns -ENOENT when no more + * entries present, or -EINVAL on error) + */ + + while (!ret) { + int i, target_rate; + + ret = ieee80211_radiotap_iterator_next(&iterator); + + if (ret) + continue; + + /* see if this argument is something we can use */ + switch (iterator.this_arg_index) { + /* + * You must take care when dereferencing iterator.this_arg + * for multibyte types... the pointer is not aligned. Use + * get_unaligned((type *)iterator.this_arg) to dereference + * iterator.this_arg for type "type" safely on all arches. + */ + case IEEE80211_RADIOTAP_RATE: + /* + * radiotap rate u8 is in 500kbps units eg, 0x02=1Mbps + * ieee80211 rate int is in 100kbps units eg, 0x0a=1Mbps + */ + target_rate = (*iterator.this_arg) * 5; + for (i = 0; i < mode->num_rates; i++) { + struct ieee80211_rate *r = &mode->rates[i]; + + if (r->rate == target_rate) { + tx->u.tx.rate = r; + break; + } + } + break; + + case IEEE80211_RADIOTAP_ANTENNA: + /* + * radiotap uses 0 for 1st ant, mac80211 is 1 for + * 1st ant + */ + control->antenna_sel_tx = (*iterator.this_arg) + 1; + break; + + case IEEE80211_RADIOTAP_DBM_TX_POWER: + control->power_level = *iterator.this_arg; + break; + + case IEEE80211_RADIOTAP_FLAGS: + if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FCS) { + /* + * this indicates that the skb we have been + * handed has the 32-bit FCS CRC at the end... + * we should react to that by snipping it off + * because it will be recomputed and added + * on transmission + */ + if (skb->len < (iterator.max_length + FCS_LEN)) + return TXRX_DROP; + + skb_trim(skb, skb->len - FCS_LEN); + } + if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP) + control->flags &= + ~IEEE80211_TXCTL_DO_NOT_ENCRYPT; + if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG) + tx->flags |= IEEE80211_TXRXD_FRAGMENTED; + break; + + /* + * Please update the file + * Documentation/networking/mac80211-injection.txt + * when parsing new fields here. + */ + + default: + break; + } + } + + if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */ + return TXRX_DROP; + + /* + * remove the radiotap header + * iterator->max_length was sanity-checked against + * skb->len by iterator init + */ + skb_pull(skb, iterator.max_length); + + return TXRX_CONTINUE; +} + +/* + * initialises @tx + */ +static ieee80211_txrx_result +__ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, + struct sk_buff *skb, + struct net_device *dev, + struct ieee80211_tx_control *control) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_hdr *hdr; + struct ieee80211_sub_if_data *sdata; + ieee80211_txrx_result res = TXRX_CONTINUE; + + int hdrlen; + + memset(tx, 0, sizeof(*tx)); + tx->skb = skb; + tx->dev = dev; /* use original interface */ + tx->local = local; + tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev); + tx->u.tx.control = control; + /* + * Set this flag (used below to indicate "automatic fragmentation"), + * it will be cleared/left by radiotap as desired. + */ + tx->flags |= IEEE80211_TXRXD_FRAGMENTED; + + /* process and remove the injection radiotap header */ + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + if (unlikely(sdata->type == IEEE80211_IF_TYPE_MNTR)) { + if (__ieee80211_parse_tx_radiotap(tx, skb) == TXRX_DROP) + return TXRX_DROP; + + /* + * __ieee80211_parse_tx_radiotap has now removed + * the radiotap header that was present and pre-filled + * 'tx' with tx control information. + */ + } + + hdr = (struct ieee80211_hdr *) skb->data; + + tx->sta = sta_info_get(local, hdr->addr1); + tx->fc = le16_to_cpu(hdr->frame_control); + + if (is_multicast_ether_addr(hdr->addr1)) { + tx->flags &= ~IEEE80211_TXRXD_TXUNICAST; + control->flags |= IEEE80211_TXCTL_NO_ACK; + } else { + tx->flags |= IEEE80211_TXRXD_TXUNICAST; + control->flags &= ~IEEE80211_TXCTL_NO_ACK; + } + + if (tx->flags & IEEE80211_TXRXD_FRAGMENTED) { + if ((tx->flags & IEEE80211_TXRXD_TXUNICAST) && + skb->len + FCS_LEN > local->fragmentation_threshold && + !local->ops->set_frag_threshold) + tx->flags |= IEEE80211_TXRXD_FRAGMENTED; + else + tx->flags &= ~IEEE80211_TXRXD_FRAGMENTED; + } + + if (!tx->sta) + control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK; + else if (tx->sta->clear_dst_mask) { + control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK; + tx->sta->clear_dst_mask = 0; + } + + hdrlen = ieee80211_get_hdrlen(tx->fc); + if (skb->len > hdrlen + sizeof(rfc1042_header) + 2) { + u8 *pos = &skb->data[hdrlen + sizeof(rfc1042_header)]; + tx->ethertype = (pos[0] << 8) | pos[1]; + } + control->flags |= IEEE80211_TXCTL_FIRST_FRAGMENT; + + return res; +} + +/* Device in tx->dev has a reference added; use dev_put(tx->dev) when + * finished with it. + * + * NB: @tx is uninitialised when passed in here + */ +static int ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, + struct sk_buff *skb, + struct net_device *mdev, + struct ieee80211_tx_control *control) +{ + struct ieee80211_tx_packet_data *pkt_data; + struct net_device *dev; + + pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; + dev = dev_get_by_index(&init_net, pkt_data->ifindex); + if (unlikely(dev && !is_ieee80211_device(dev, mdev))) { + dev_put(dev); + dev = NULL; + } + if (unlikely(!dev)) + return -ENODEV; + /* initialises tx with control */ + __ieee80211_tx_prepare(tx, skb, dev, control); + return 0; +} + +static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, + struct ieee80211_txrx_data *tx) +{ + struct ieee80211_tx_control *control = tx->u.tx.control; + int ret, i; + + if (!ieee80211_qdisc_installed(local->mdev) && + __ieee80211_queue_stopped(local, 0)) { + netif_stop_queue(local->mdev); + return IEEE80211_TX_AGAIN; + } + if (skb) { + ieee80211_dump_frame(wiphy_name(local->hw.wiphy), + "TX to low-level driver", skb); + ret = local->ops->tx(local_to_hw(local), skb, control); + if (ret) + return IEEE80211_TX_AGAIN; + local->mdev->trans_start = jiffies; + ieee80211_led_tx(local, 1); + } + if (tx->u.tx.extra_frag) { + control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS | + IEEE80211_TXCTL_USE_CTS_PROTECT | + IEEE80211_TXCTL_CLEAR_DST_MASK | + IEEE80211_TXCTL_FIRST_FRAGMENT); + for (i = 0; i < tx->u.tx.num_extra_frag; i++) { + if (!tx->u.tx.extra_frag[i]) + continue; + if (__ieee80211_queue_stopped(local, control->queue)) + return IEEE80211_TX_FRAG_AGAIN; + if (i == tx->u.tx.num_extra_frag) { + control->tx_rate = tx->u.tx.last_frag_hwrate; + control->rate = tx->u.tx.last_frag_rate; + if (tx->flags & IEEE80211_TXRXD_TXPROBE_LAST_FRAG) + control->flags |= + IEEE80211_TXCTL_RATE_CTRL_PROBE; + else + control->flags &= + ~IEEE80211_TXCTL_RATE_CTRL_PROBE; + } + + ieee80211_dump_frame(wiphy_name(local->hw.wiphy), + "TX to low-level driver", + tx->u.tx.extra_frag[i]); + ret = local->ops->tx(local_to_hw(local), + tx->u.tx.extra_frag[i], + control); + if (ret) + return IEEE80211_TX_FRAG_AGAIN; + local->mdev->trans_start = jiffies; + ieee80211_led_tx(local, 1); + tx->u.tx.extra_frag[i] = NULL; + } + kfree(tx->u.tx.extra_frag); + tx->u.tx.extra_frag = NULL; + } + return IEEE80211_TX_OK; +} + +static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, + struct ieee80211_tx_control *control) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct sta_info *sta; + ieee80211_tx_handler *handler; + struct ieee80211_txrx_data tx; + ieee80211_txrx_result res = TXRX_DROP, res_prepare; + int ret, i; + + WARN_ON(__ieee80211_queue_pending(local, control->queue)); + + if (unlikely(skb->len < 10)) { + dev_kfree_skb(skb); + return 0; + } + + /* initialises tx */ + res_prepare = __ieee80211_tx_prepare(&tx, skb, dev, control); + + if (res_prepare == TXRX_DROP) { + dev_kfree_skb(skb); + return 0; + } + + /* + * key references are protected using RCU and this requires that + * we are in a read-site RCU section during receive processing + */ + rcu_read_lock(); + + sta = tx.sta; + tx.u.tx.mode = local->hw.conf.mode; + + for (handler = local->tx_handlers; *handler != NULL; + handler++) { + res = (*handler)(&tx); + if (res != TXRX_CONTINUE) + break; + } + + skb = tx.skb; /* handlers are allowed to change skb */ + + if (sta) + sta_info_put(sta); + + if (unlikely(res == TXRX_DROP)) { + I802_DEBUG_INC(local->tx_handlers_drop); + goto drop; + } + + if (unlikely(res == TXRX_QUEUED)) { + I802_DEBUG_INC(local->tx_handlers_queued); + rcu_read_unlock(); + return 0; + } + + if (tx.u.tx.extra_frag) { + for (i = 0; i < tx.u.tx.num_extra_frag; i++) { + int next_len, dur; + struct ieee80211_hdr *hdr = + (struct ieee80211_hdr *) + tx.u.tx.extra_frag[i]->data; + + if (i + 1 < tx.u.tx.num_extra_frag) { + next_len = tx.u.tx.extra_frag[i + 1]->len; + } else { + next_len = 0; + tx.u.tx.rate = tx.u.tx.last_frag_rate; + tx.u.tx.last_frag_hwrate = tx.u.tx.rate->val; + } + dur = ieee80211_duration(&tx, 0, next_len); + hdr->duration_id = cpu_to_le16(dur); + } + } + +retry: + ret = __ieee80211_tx(local, skb, &tx); + if (ret) { + struct ieee80211_tx_stored_packet *store = + &local->pending_packet[control->queue]; + + if (ret == IEEE80211_TX_FRAG_AGAIN) + skb = NULL; + set_bit(IEEE80211_LINK_STATE_PENDING, + &local->state[control->queue]); + smp_mb(); + /* When the driver gets out of buffers during sending of + * fragments and calls ieee80211_stop_queue, there is + * a small window between IEEE80211_LINK_STATE_XOFF and + * IEEE80211_LINK_STATE_PENDING flags are set. If a buffer + * gets available in that window (i.e. driver calls + * ieee80211_wake_queue), we would end up with ieee80211_tx + * called with IEEE80211_LINK_STATE_PENDING. Prevent this by + * continuing transmitting here when that situation is + * possible to have happened. */ + if (!__ieee80211_queue_stopped(local, control->queue)) { + clear_bit(IEEE80211_LINK_STATE_PENDING, + &local->state[control->queue]); + goto retry; + } + memcpy(&store->control, control, + sizeof(struct ieee80211_tx_control)); + store->skb = skb; + store->extra_frag = tx.u.tx.extra_frag; + store->num_extra_frag = tx.u.tx.num_extra_frag; + store->last_frag_hwrate = tx.u.tx.last_frag_hwrate; + store->last_frag_rate = tx.u.tx.last_frag_rate; + store->last_frag_rate_ctrl_probe = + !!(tx.flags & IEEE80211_TXRXD_TXPROBE_LAST_FRAG); + } + rcu_read_unlock(); + return 0; + + drop: + if (skb) + dev_kfree_skb(skb); + for (i = 0; i < tx.u.tx.num_extra_frag; i++) + if (tx.u.tx.extra_frag[i]) + dev_kfree_skb(tx.u.tx.extra_frag[i]); + kfree(tx.u.tx.extra_frag); + rcu_read_unlock(); + return 0; +} + +/* device xmit handlers */ + +int ieee80211_master_start_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct ieee80211_tx_control control; + struct ieee80211_tx_packet_data *pkt_data; + struct net_device *odev = NULL; + struct ieee80211_sub_if_data *osdata; + int headroom; + int ret; + + /* + * copy control out of the skb so other people can use skb->cb + */ + pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; + memset(&control, 0, sizeof(struct ieee80211_tx_control)); + + if (pkt_data->ifindex) + odev = dev_get_by_index(&init_net, pkt_data->ifindex); + if (unlikely(odev && !is_ieee80211_device(odev, dev))) { + dev_put(odev); + odev = NULL; + } + if (unlikely(!odev)) { +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + printk(KERN_DEBUG "%s: Discarded packet with nonexistent " + "originating device\n", dev->name); +#endif + dev_kfree_skb(skb); + return 0; + } + osdata = IEEE80211_DEV_TO_SUB_IF(odev); + + headroom = osdata->local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM; + if (skb_headroom(skb) < headroom) { + if (pskb_expand_head(skb, headroom, 0, GFP_ATOMIC)) { + dev_kfree_skb(skb); + dev_put(odev); + return 0; + } + } + + control.ifindex = odev->ifindex; + control.type = osdata->type; + if (pkt_data->flags & IEEE80211_TXPD_REQ_TX_STATUS) + control.flags |= IEEE80211_TXCTL_REQ_TX_STATUS; + if (pkt_data->flags & IEEE80211_TXPD_DO_NOT_ENCRYPT) + control.flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; + if (pkt_data->flags & IEEE80211_TXPD_REQUEUE) + control.flags |= IEEE80211_TXCTL_REQUEUE; + control.queue = pkt_data->queue; + + ret = ieee80211_tx(odev, skb, &control); + dev_put(odev); + + return ret; +} + +int ieee80211_monitor_start_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_tx_packet_data *pkt_data; + struct ieee80211_radiotap_header *prthdr = + (struct ieee80211_radiotap_header *)skb->data; + u16 len_rthdr; + + /* check for not even having the fixed radiotap header part */ + if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header))) + goto fail; /* too short to be possibly valid */ + + /* is it a header version we can trust to find length from? */ + if (unlikely(prthdr->it_version)) + goto fail; /* only version 0 is supported */ + + /* then there must be a radiotap header with a length we can use */ + len_rthdr = ieee80211_get_radiotap_len(skb->data); + + /* does the skb contain enough to deliver on the alleged length? */ + if (unlikely(skb->len < len_rthdr)) + goto fail; /* skb too short for claimed rt header extent */ + + skb->dev = local->mdev; + + pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; + memset(pkt_data, 0, sizeof(*pkt_data)); + /* needed because we set skb device to master */ + pkt_data->ifindex = dev->ifindex; + + pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT; + + /* + * fix up the pointers accounting for the radiotap + * header still being in there. We are being given + * a precooked IEEE80211 header so no need for + * normal processing + */ + skb_set_mac_header(skb, len_rthdr); + /* + * these are just fixed to the end of the rt area since we + * don't have any better information and at this point, nobody cares + */ + skb_set_network_header(skb, len_rthdr); + skb_set_transport_header(skb, len_rthdr); + + /* pass the radiotap header up to the next stage intact */ + dev_queue_xmit(skb); + return NETDEV_TX_OK; + +fail: + dev_kfree_skb(skb); + return NETDEV_TX_OK; /* meaning, we dealt with the skb */ +} + +/** + * ieee80211_subif_start_xmit - netif start_xmit function for Ethernet-type + * subinterfaces (wlan#, WDS, and VLAN interfaces) + * @skb: packet to be sent + * @dev: incoming interface + * + * Returns: 0 on success (and frees skb in this case) or 1 on failure (skb will + * not be freed, and caller is responsible for either retrying later or freeing + * skb). + * + * This function takes in an Ethernet header and encapsulates it with suitable + * IEEE 802.11 header based on which interface the packet is coming in. The + * encapsulated packet will then be passed to master interface, wlan#.11, for + * transmission (through low-level driver). + */ +int ieee80211_subif_start_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_tx_packet_data *pkt_data; + struct ieee80211_sub_if_data *sdata; + int ret = 1, head_need; + u16 ethertype, hdrlen, fc; + struct ieee80211_hdr hdr; + const u8 *encaps_data; + int encaps_len, skip_header_bytes; + int nh_pos, h_pos; + struct sta_info *sta; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + if (unlikely(skb->len < ETH_HLEN)) { + printk(KERN_DEBUG "%s: short skb (len=%d)\n", + dev->name, skb->len); + ret = 0; + goto fail; + } + + nh_pos = skb_network_header(skb) - skb->data; + h_pos = skb_transport_header(skb) - skb->data; + + /* convert Ethernet header to proper 802.11 header (based on + * operation mode) */ + ethertype = (skb->data[12] << 8) | skb->data[13]; + /* TODO: handling for 802.1x authorized/unauthorized port */ + fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA; + + switch (sdata->type) { + case IEEE80211_IF_TYPE_AP: + case IEEE80211_IF_TYPE_VLAN: + fc |= IEEE80211_FCTL_FROMDS; + /* DA BSSID SA */ + memcpy(hdr.addr1, skb->data, ETH_ALEN); + memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); + memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN); + hdrlen = 24; + break; + case IEEE80211_IF_TYPE_WDS: + fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS; + /* RA TA DA SA */ + memcpy(hdr.addr1, sdata->u.wds.remote_addr, ETH_ALEN); + memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); + memcpy(hdr.addr3, skb->data, ETH_ALEN); + memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); + hdrlen = 30; + break; + case IEEE80211_IF_TYPE_STA: + fc |= IEEE80211_FCTL_TODS; + /* BSSID SA DA */ + memcpy(hdr.addr1, sdata->u.sta.bssid, ETH_ALEN); + memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); + memcpy(hdr.addr3, skb->data, ETH_ALEN); + hdrlen = 24; + break; + case IEEE80211_IF_TYPE_IBSS: + /* DA SA BSSID */ + memcpy(hdr.addr1, skb->data, ETH_ALEN); + memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); + memcpy(hdr.addr3, sdata->u.sta.bssid, ETH_ALEN); + hdrlen = 24; + break; + default: + ret = 0; + goto fail; + } + + /* receiver is QoS enabled, use a QoS type frame */ + sta = sta_info_get(local, hdr.addr1); + if (sta) { + if (sta->flags & WLAN_STA_WME) { + fc |= IEEE80211_STYPE_QOS_DATA; + hdrlen += 2; + } + sta_info_put(sta); + } + + hdr.frame_control = cpu_to_le16(fc); + hdr.duration_id = 0; + hdr.seq_ctrl = 0; + + skip_header_bytes = ETH_HLEN; + if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) { + encaps_data = bridge_tunnel_header; + encaps_len = sizeof(bridge_tunnel_header); + skip_header_bytes -= 2; + } else if (ethertype >= 0x600) { + encaps_data = rfc1042_header; + encaps_len = sizeof(rfc1042_header); + skip_header_bytes -= 2; + } else { + encaps_data = NULL; + encaps_len = 0; + } + + skb_pull(skb, skip_header_bytes); + nh_pos -= skip_header_bytes; + h_pos -= skip_header_bytes; + + /* TODO: implement support for fragments so that there is no need to + * reallocate and copy payload; it might be enough to support one + * extra fragment that would be copied in the beginning of the frame + * data.. anyway, it would be nice to include this into skb structure + * somehow + * + * There are few options for this: + * use skb->cb as an extra space for 802.11 header + * allocate new buffer if not enough headroom + * make sure that there is enough headroom in every skb by increasing + * build in headroom in __dev_alloc_skb() (linux/skbuff.h) and + * alloc_skb() (net/core/skbuff.c) + */ + head_need = hdrlen + encaps_len + local->tx_headroom; + head_need -= skb_headroom(skb); + + /* We are going to modify skb data, so make a copy of it if happens to + * be cloned. This could happen, e.g., with Linux bridge code passing + * us broadcast frames. */ + + if (head_need > 0 || skb_cloned(skb)) { +#if 0 + printk(KERN_DEBUG "%s: need to reallocate buffer for %d bytes " + "of headroom\n", dev->name, head_need); +#endif + + if (skb_cloned(skb)) + I802_DEBUG_INC(local->tx_expand_skb_head_cloned); + else + I802_DEBUG_INC(local->tx_expand_skb_head); + /* Since we have to reallocate the buffer, make sure that there + * is enough room for possible WEP IV/ICV and TKIP (8 bytes + * before payload and 12 after). */ + if (pskb_expand_head(skb, (head_need > 0 ? head_need + 8 : 8), + 12, GFP_ATOMIC)) { + printk(KERN_DEBUG "%s: failed to reallocate TX buffer" + "\n", dev->name); + goto fail; + } + } + + if (encaps_data) { + memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len); + nh_pos += encaps_len; + h_pos += encaps_len; + } + + if (fc & IEEE80211_STYPE_QOS_DATA) { + __le16 *qos_control; + + qos_control = (__le16*) skb_push(skb, 2); + memcpy(skb_push(skb, hdrlen - 2), &hdr, hdrlen - 2); + /* + * Maybe we could actually set some fields here, for now just + * initialise to zero to indicate no special operation. + */ + *qos_control = 0; + } else + memcpy(skb_push(skb, hdrlen), &hdr, hdrlen); + + nh_pos += hdrlen; + h_pos += hdrlen; + + pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; + memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data)); + pkt_data->ifindex = dev->ifindex; + + skb->dev = local->mdev; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; + + /* Update skb pointers to various headers since this modified frame + * is going to go through Linux networking code that may potentially + * need things like pointer to IP header. */ + skb_set_mac_header(skb, 0); + skb_set_network_header(skb, nh_pos); + skb_set_transport_header(skb, h_pos); + + dev->trans_start = jiffies; + dev_queue_xmit(skb); + + return 0; + + fail: + if (!ret) + dev_kfree_skb(skb); + + return ret; +} + +/* + * This is the transmit routine for the 802.11 type interfaces + * called by upper layers of the linux networking + * stack when it has a frame to transmit + */ +int ieee80211_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct ieee80211_sub_if_data *sdata; + struct ieee80211_tx_packet_data *pkt_data; + struct ieee80211_hdr *hdr; + u16 fc; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + if (skb->len < 10) { + dev_kfree_skb(skb); + return 0; + } + + if (skb_headroom(skb) < sdata->local->tx_headroom) { + if (pskb_expand_head(skb, sdata->local->tx_headroom, + 0, GFP_ATOMIC)) { + dev_kfree_skb(skb); + return 0; + } + } + + hdr = (struct ieee80211_hdr *) skb->data; + fc = le16_to_cpu(hdr->frame_control); + + pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; + memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data)); + pkt_data->ifindex = sdata->dev->ifindex; + + skb->priority = 20; /* use hardcoded priority for mgmt TX queue */ + skb->dev = sdata->local->mdev; + + /* + * We're using the protocol field of the the frame control header + * to request TX callback for hostapd. BIT(1) is checked. + */ + if ((fc & BIT(1)) == BIT(1)) { + pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS; + fc &= ~BIT(1); + hdr->frame_control = cpu_to_le16(fc); + } + + if (!(fc & IEEE80211_FCTL_PROTECTED)) + pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT; + + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; + + dev_queue_xmit(skb); + + return 0; +} + +/* helper functions for pending packets for when queues are stopped */ + +void ieee80211_clear_tx_pending(struct ieee80211_local *local) +{ + int i, j; + struct ieee80211_tx_stored_packet *store; + + for (i = 0; i < local->hw.queues; i++) { + if (!__ieee80211_queue_pending(local, i)) + continue; + store = &local->pending_packet[i]; + kfree_skb(store->skb); + for (j = 0; j < store->num_extra_frag; j++) + kfree_skb(store->extra_frag[j]); + kfree(store->extra_frag); + clear_bit(IEEE80211_LINK_STATE_PENDING, &local->state[i]); + } +} + +void ieee80211_tx_pending(unsigned long data) +{ + struct ieee80211_local *local = (struct ieee80211_local *)data; + struct net_device *dev = local->mdev; + struct ieee80211_tx_stored_packet *store; + struct ieee80211_txrx_data tx; + int i, ret, reschedule = 0; + + netif_tx_lock_bh(dev); + for (i = 0; i < local->hw.queues; i++) { + if (__ieee80211_queue_stopped(local, i)) + continue; + if (!__ieee80211_queue_pending(local, i)) { + reschedule = 1; + continue; + } + store = &local->pending_packet[i]; + tx.u.tx.control = &store->control; + tx.u.tx.extra_frag = store->extra_frag; + tx.u.tx.num_extra_frag = store->num_extra_frag; + tx.u.tx.last_frag_hwrate = store->last_frag_hwrate; + tx.u.tx.last_frag_rate = store->last_frag_rate; + tx.flags = 0; + if (store->last_frag_rate_ctrl_probe) + tx.flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG; + ret = __ieee80211_tx(local, store->skb, &tx); + if (ret) { + if (ret == IEEE80211_TX_FRAG_AGAIN) + store->skb = NULL; + } else { + clear_bit(IEEE80211_LINK_STATE_PENDING, + &local->state[i]); + reschedule = 1; + } + } + netif_tx_unlock_bh(dev); + if (reschedule) { + if (!ieee80211_qdisc_installed(dev)) { + if (!__ieee80211_queue_stopped(local, 0)) + netif_wake_queue(dev); + } else + netif_schedule(dev); + } +} + +/* functions for drivers to get certain frames */ + +static void ieee80211_beacon_add_tim(struct ieee80211_local *local, + struct ieee80211_if_ap *bss, + struct sk_buff *skb) +{ + u8 *pos, *tim; + int aid0 = 0; + int i, have_bits = 0, n1, n2; + + /* Generate bitmap for TIM only if there are any STAs in power save + * mode. */ + read_lock_bh(&local->sta_lock); + if (atomic_read(&bss->num_sta_ps) > 0) + /* in the hope that this is faster than + * checking byte-for-byte */ + have_bits = !bitmap_empty((unsigned long*)bss->tim, + IEEE80211_MAX_AID+1); + + if (bss->dtim_count == 0) + bss->dtim_count = bss->dtim_period - 1; + else + bss->dtim_count--; + + tim = pos = (u8 *) skb_put(skb, 6); + *pos++ = WLAN_EID_TIM; + *pos++ = 4; + *pos++ = bss->dtim_count; + *pos++ = bss->dtim_period; + + if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf)) + aid0 = 1; + + if (have_bits) { + /* Find largest even number N1 so that bits numbered 1 through + * (N1 x 8) - 1 in the bitmap are 0 and number N2 so that bits + * (N2 + 1) x 8 through 2007 are 0. */ + n1 = 0; + for (i = 0; i < IEEE80211_MAX_TIM_LEN; i++) { + if (bss->tim[i]) { + n1 = i & 0xfe; + break; + } + } + n2 = n1; + for (i = IEEE80211_MAX_TIM_LEN - 1; i >= n1; i--) { + if (bss->tim[i]) { + n2 = i; + break; + } + } + + /* Bitmap control */ + *pos++ = n1 | aid0; + /* Part Virt Bitmap */ + memcpy(pos, bss->tim + n1, n2 - n1 + 1); + + tim[1] = n2 - n1 + 4; + skb_put(skb, n2 - n1); + } else { + *pos++ = aid0; /* Bitmap control */ + *pos++ = 0; /* Part Virt Bitmap */ + } + read_unlock_bh(&local->sta_lock); +} + +struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id, + struct ieee80211_tx_control *control) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct sk_buff *skb; + struct net_device *bdev; + struct ieee80211_sub_if_data *sdata = NULL; + struct ieee80211_if_ap *ap = NULL; + struct ieee80211_rate *rate; + struct rate_control_extra extra; + u8 *b_head, *b_tail; + int bh_len, bt_len; + + bdev = dev_get_by_index(&init_net, if_id); + if (bdev) { + sdata = IEEE80211_DEV_TO_SUB_IF(bdev); + ap = &sdata->u.ap; + dev_put(bdev); + } + + if (!ap || sdata->type != IEEE80211_IF_TYPE_AP || + !ap->beacon_head) { +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + if (net_ratelimit()) + printk(KERN_DEBUG "no beacon data avail for idx=%d " + "(%s)\n", if_id, bdev ? bdev->name : "N/A"); +#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + return NULL; + } + + /* Assume we are generating the normal beacon locally */ + b_head = ap->beacon_head; + b_tail = ap->beacon_tail; + bh_len = ap->beacon_head_len; + bt_len = ap->beacon_tail_len; + + skb = dev_alloc_skb(local->tx_headroom + + bh_len + bt_len + 256 /* maximum TIM len */); + if (!skb) + return NULL; + + skb_reserve(skb, local->tx_headroom); + memcpy(skb_put(skb, bh_len), b_head, bh_len); + + ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data); + + ieee80211_beacon_add_tim(local, ap, skb); + + if (b_tail) { + memcpy(skb_put(skb, bt_len), b_tail, bt_len); + } + + if (control) { + memset(&extra, 0, sizeof(extra)); + extra.mode = local->oper_hw_mode; + + rate = rate_control_get_rate(local, local->mdev, skb, &extra); + if (!rate) { + if (net_ratelimit()) { + printk(KERN_DEBUG "%s: ieee80211_beacon_get: no rate " + "found\n", wiphy_name(local->hw.wiphy)); + } + dev_kfree_skb(skb); + return NULL; + } + + control->tx_rate = + ((sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE) && + (rate->flags & IEEE80211_RATE_PREAMBLE2)) ? + rate->val2 : rate->val; + control->antenna_sel_tx = local->hw.conf.antenna_sel_tx; + control->power_level = local->hw.conf.power_level; + control->flags |= IEEE80211_TXCTL_NO_ACK; + control->retry_limit = 1; + control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK; + } + + ap->num_beacons++; + return skb; +} +EXPORT_SYMBOL(ieee80211_beacon_get); + +void ieee80211_rts_get(struct ieee80211_hw *hw, int if_id, + const void *frame, size_t frame_len, + const struct ieee80211_tx_control *frame_txctl, + struct ieee80211_rts *rts) +{ + const struct ieee80211_hdr *hdr = frame; + u16 fctl; + + fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS; + rts->frame_control = cpu_to_le16(fctl); + rts->duration = ieee80211_rts_duration(hw, if_id, frame_len, frame_txctl); + memcpy(rts->ra, hdr->addr1, sizeof(rts->ra)); + memcpy(rts->ta, hdr->addr2, sizeof(rts->ta)); +} +EXPORT_SYMBOL(ieee80211_rts_get); + +void ieee80211_ctstoself_get(struct ieee80211_hw *hw, int if_id, + const void *frame, size_t frame_len, + const struct ieee80211_tx_control *frame_txctl, + struct ieee80211_cts *cts) +{ + const struct ieee80211_hdr *hdr = frame; + u16 fctl; + + fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS; + cts->frame_control = cpu_to_le16(fctl); + cts->duration = ieee80211_ctstoself_duration(hw, if_id, frame_len, frame_txctl); + memcpy(cts->ra, hdr->addr1, sizeof(cts->ra)); +} +EXPORT_SYMBOL(ieee80211_ctstoself_get); + +struct sk_buff * +ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id, + struct ieee80211_tx_control *control) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct sk_buff *skb; + struct sta_info *sta; + ieee80211_tx_handler *handler; + struct ieee80211_txrx_data tx; + ieee80211_txrx_result res = TXRX_DROP; + struct net_device *bdev; + struct ieee80211_sub_if_data *sdata; + struct ieee80211_if_ap *bss = NULL; + + bdev = dev_get_by_index(&init_net, if_id); + if (bdev) { + sdata = IEEE80211_DEV_TO_SUB_IF(bdev); + bss = &sdata->u.ap; + dev_put(bdev); + } + if (!bss || sdata->type != IEEE80211_IF_TYPE_AP || !bss->beacon_head) + return NULL; + + if (bss->dtim_count != 0) + return NULL; /* send buffered bc/mc only after DTIM beacon */ + memset(control, 0, sizeof(*control)); + while (1) { + skb = skb_dequeue(&bss->ps_bc_buf); + if (!skb) + return NULL; + local->total_ps_buffered--; + + if (!skb_queue_empty(&bss->ps_bc_buf) && skb->len >= 2) { + struct ieee80211_hdr *hdr = + (struct ieee80211_hdr *) skb->data; + /* more buffered multicast/broadcast frames ==> set + * MoreData flag in IEEE 802.11 header to inform PS + * STAs */ + hdr->frame_control |= + cpu_to_le16(IEEE80211_FCTL_MOREDATA); + } + + if (!ieee80211_tx_prepare(&tx, skb, local->mdev, control)) + break; + dev_kfree_skb_any(skb); + } + sta = tx.sta; + tx.flags |= IEEE80211_TXRXD_TXPS_BUFFERED; + tx.u.tx.mode = local->hw.conf.mode; + + for (handler = local->tx_handlers; *handler != NULL; handler++) { + res = (*handler)(&tx); + if (res == TXRX_DROP || res == TXRX_QUEUED) + break; + } + dev_put(tx.dev); + skb = tx.skb; /* handlers are allowed to change skb */ + + if (res == TXRX_DROP) { + I802_DEBUG_INC(local->tx_handlers_drop); + dev_kfree_skb(skb); + skb = NULL; + } else if (res == TXRX_QUEUED) { + I802_DEBUG_INC(local->tx_handlers_queued); + skb = NULL; + } + + if (sta) + sta_info_put(sta); + + return skb; +} +EXPORT_SYMBOL(ieee80211_get_buffered_bc); diff --git a/net/mac80211/util.c b/net/mac80211/util.c new file mode 100644 index 0000000..5a0564e --- /dev/null +++ b/net/mac80211/util.c @@ -0,0 +1,486 @@ +/* + * Copyright 2002-2005, Instant802 Networks, Inc. + * Copyright 2005-2006, Devicescape Software, Inc. + * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> + * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * utilities for mac80211 + */ + +#include <net/mac80211.h> +#include <linux/netdevice.h> +#include <linux/types.h> +#include <linux/slab.h> +#include <linux/skbuff.h> +#include <linux/etherdevice.h> +#include <linux/if_arp.h> +#include <linux/wireless.h> +#include <linux/bitmap.h> +#include <net/net_namespace.h> +#include <net/cfg80211.h> + +#include "ieee80211_i.h" +#include "ieee80211_rate.h" +#include "wme.h" + +/* privid for wiphys to determine whether they belong to us or not */ +void *mac80211_wiphy_privid = &mac80211_wiphy_privid; + +/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ +/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ +const unsigned char rfc1042_header[] = + { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; + +/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ +const unsigned char bridge_tunnel_header[] = + { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; + +/* No encapsulation header if EtherType < 0x600 (=length) */ +static const unsigned char eapol_header[] = + { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8e }; + + +static int rate_list_match(const int *rate_list, int rate) +{ + int i; + + if (!rate_list) + return 0; + + for (i = 0; rate_list[i] >= 0; i++) + if (rate_list[i] == rate) + return 1; + + return 0; +} + +void ieee80211_prepare_rates(struct ieee80211_local *local, + struct ieee80211_hw_mode *mode) +{ + int i; + + for (i = 0; i < mode->num_rates; i++) { + struct ieee80211_rate *rate = &mode->rates[i]; + + rate->flags &= ~(IEEE80211_RATE_SUPPORTED | + IEEE80211_RATE_BASIC); + + if (local->supp_rates[mode->mode]) { + if (!rate_list_match(local->supp_rates[mode->mode], + rate->rate)) + continue; + } + + rate->flags |= IEEE80211_RATE_SUPPORTED; + + /* Use configured basic rate set if it is available. If not, + * use defaults that are sane for most cases. */ + if (local->basic_rates[mode->mode]) { + if (rate_list_match(local->basic_rates[mode->mode], + rate->rate)) + rate->flags |= IEEE80211_RATE_BASIC; + } else switch (mode->mode) { + case MODE_IEEE80211A: + if (rate->rate == 60 || rate->rate == 120 || + rate->rate == 240) + rate->flags |= IEEE80211_RATE_BASIC; + break; + case MODE_IEEE80211B: + if (rate->rate == 10 || rate->rate == 20) + rate->flags |= IEEE80211_RATE_BASIC; + break; + case MODE_IEEE80211G: + if (rate->rate == 10 || rate->rate == 20 || + rate->rate == 55 || rate->rate == 110) + rate->flags |= IEEE80211_RATE_BASIC; + break; + case NUM_IEEE80211_MODES: + /* not useful */ + break; + } + + /* Set ERP and MANDATORY flags based on phymode */ + switch (mode->mode) { + case MODE_IEEE80211A: + if (rate->rate == 60 || rate->rate == 120 || + rate->rate == 240) + rate->flags |= IEEE80211_RATE_MANDATORY; + break; + case MODE_IEEE80211B: + if (rate->rate == 10) + rate->flags |= IEEE80211_RATE_MANDATORY; + break; + case MODE_IEEE80211G: + if (rate->rate == 10 || rate->rate == 20 || + rate->rate == 55 || rate->rate == 110 || + rate->rate == 60 || rate->rate == 120 || + rate->rate == 240) + rate->flags |= IEEE80211_RATE_MANDATORY; + break; + case NUM_IEEE80211_MODES: + /* not useful */ + break; + } + if (ieee80211_is_erp_rate(mode->mode, rate->rate)) + rate->flags |= IEEE80211_RATE_ERP; + } +} + +u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len) +{ + u16 fc; + + if (len < 24) + return NULL; + + fc = le16_to_cpu(hdr->frame_control); + + switch (fc & IEEE80211_FCTL_FTYPE) { + case IEEE80211_FTYPE_DATA: + switch (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { + case IEEE80211_FCTL_TODS: + return hdr->addr1; + case (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): + return NULL; + case IEEE80211_FCTL_FROMDS: + return hdr->addr2; + case 0: + return hdr->addr3; + } + break; + case IEEE80211_FTYPE_MGMT: + return hdr->addr3; + case IEEE80211_FTYPE_CTL: + if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL) + return hdr->addr1; + else + return NULL; + } + + return NULL; +} + +int ieee80211_get_hdrlen(u16 fc) +{ + int hdrlen = 24; + + switch (fc & IEEE80211_FCTL_FTYPE) { + case IEEE80211_FTYPE_DATA: + if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS)) + hdrlen = 30; /* Addr4 */ + /* + * The QoS Control field is two bytes and its presence is + * indicated by the IEEE80211_STYPE_QOS_DATA bit. Add 2 to + * hdrlen if that bit is set. + * This works by masking out the bit and shifting it to + * bit position 1 so the result has the value 0 or 2. + */ + hdrlen += (fc & IEEE80211_STYPE_QOS_DATA) + >> (ilog2(IEEE80211_STYPE_QOS_DATA)-1); + break; + case IEEE80211_FTYPE_CTL: + /* + * ACK and CTS are 10 bytes, all others 16. To see how + * to get this condition consider + * subtype mask: 0b0000000011110000 (0x00F0) + * ACK subtype: 0b0000000011010000 (0x00D0) + * CTS subtype: 0b0000000011000000 (0x00C0) + * bits that matter: ^^^ (0x00E0) + * value of those: 0b0000000011000000 (0x00C0) + */ + if ((fc & 0xE0) == 0xC0) + hdrlen = 10; + else + hdrlen = 16; + break; + } + + return hdrlen; +} +EXPORT_SYMBOL(ieee80211_get_hdrlen); + +int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb) +{ + const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *) skb->data; + int hdrlen; + + if (unlikely(skb->len < 10)) + return 0; + hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)); + if (unlikely(hdrlen > skb->len)) + return 0; + return hdrlen; +} +EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); + +int ieee80211_is_eapol(const struct sk_buff *skb) +{ + const struct ieee80211_hdr *hdr; + u16 fc; + int hdrlen; + + if (unlikely(skb->len < 10)) + return 0; + + hdr = (const struct ieee80211_hdr *) skb->data; + fc = le16_to_cpu(hdr->frame_control); + + if (unlikely(!WLAN_FC_DATA_PRESENT(fc))) + return 0; + + hdrlen = ieee80211_get_hdrlen(fc); + + if (unlikely(skb->len >= hdrlen + sizeof(eapol_header) && + memcmp(skb->data + hdrlen, eapol_header, + sizeof(eapol_header)) == 0)) + return 1; + + return 0; +} + +void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; + + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); + if (tx->u.tx.extra_frag) { + struct ieee80211_hdr *fhdr; + int i; + for (i = 0; i < tx->u.tx.num_extra_frag; i++) { + fhdr = (struct ieee80211_hdr *) + tx->u.tx.extra_frag[i]->data; + fhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); + } + } +} + +int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, + int rate, int erp, int short_preamble) +{ + int dur; + + /* calculate duration (in microseconds, rounded up to next higher + * integer if it includes a fractional microsecond) to send frame of + * len bytes (does not include FCS) at the given rate. Duration will + * also include SIFS. + * + * rate is in 100 kbps, so divident is multiplied by 10 in the + * DIV_ROUND_UP() operations. + */ + + if (local->hw.conf.phymode == MODE_IEEE80211A || erp) { + /* + * OFDM: + * + * N_DBPS = DATARATE x 4 + * N_SYM = Ceiling((16+8xLENGTH+6) / N_DBPS) + * (16 = SIGNAL time, 6 = tail bits) + * TXTIME = T_PREAMBLE + T_SIGNAL + T_SYM x N_SYM + Signal Ext + * + * T_SYM = 4 usec + * 802.11a - 17.5.2: aSIFSTime = 16 usec + * 802.11g - 19.8.4: aSIFSTime = 10 usec + + * signal ext = 6 usec + */ + dur = 16; /* SIFS + signal ext */ + dur += 16; /* 17.3.2.3: T_PREAMBLE = 16 usec */ + dur += 4; /* 17.3.2.3: T_SIGNAL = 4 usec */ + dur += 4 * DIV_ROUND_UP((16 + 8 * (len + 4) + 6) * 10, + 4 * rate); /* T_SYM x N_SYM */ + } else { + /* + * 802.11b or 802.11g with 802.11b compatibility: + * 18.3.4: TXTIME = PreambleLength + PLCPHeaderTime + + * Ceiling(((LENGTH+PBCC)x8)/DATARATE). PBCC=0. + * + * 802.11 (DS): 15.3.3, 802.11b: 18.3.4 + * aSIFSTime = 10 usec + * aPreambleLength = 144 usec or 72 usec with short preamble + * aPLCPHeaderLength = 48 usec or 24 usec with short preamble + */ + dur = 10; /* aSIFSTime = 10 usec */ + dur += short_preamble ? (72 + 24) : (144 + 48); + + dur += DIV_ROUND_UP(8 * (len + 4) * 10, rate); + } + + return dur; +} + +/* Exported duration function for driver use */ +__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, int if_id, + size_t frame_len, int rate) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct net_device *bdev = dev_get_by_index(&init_net, if_id); + struct ieee80211_sub_if_data *sdata; + u16 dur; + int erp; + + if (unlikely(!bdev)) + return 0; + + sdata = IEEE80211_DEV_TO_SUB_IF(bdev); + erp = ieee80211_is_erp_rate(hw->conf.phymode, rate); + dur = ieee80211_frame_duration(local, frame_len, rate, + erp, sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE); + + dev_put(bdev); + return cpu_to_le16(dur); +} +EXPORT_SYMBOL(ieee80211_generic_frame_duration); + +__le16 ieee80211_rts_duration(struct ieee80211_hw *hw, int if_id, + size_t frame_len, + const struct ieee80211_tx_control *frame_txctl) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_rate *rate; + struct net_device *bdev = dev_get_by_index(&init_net, if_id); + struct ieee80211_sub_if_data *sdata; + int short_preamble; + int erp; + u16 dur; + + if (unlikely(!bdev)) + return 0; + + sdata = IEEE80211_DEV_TO_SUB_IF(bdev); + short_preamble = sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE; + + rate = frame_txctl->rts_rate; + erp = !!(rate->flags & IEEE80211_RATE_ERP); + + /* CTS duration */ + dur = ieee80211_frame_duration(local, 10, rate->rate, + erp, short_preamble); + /* Data frame duration */ + dur += ieee80211_frame_duration(local, frame_len, rate->rate, + erp, short_preamble); + /* ACK duration */ + dur += ieee80211_frame_duration(local, 10, rate->rate, + erp, short_preamble); + + dev_put(bdev); + return cpu_to_le16(dur); +} +EXPORT_SYMBOL(ieee80211_rts_duration); + +__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, int if_id, + size_t frame_len, + const struct ieee80211_tx_control *frame_txctl) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_rate *rate; + struct net_device *bdev = dev_get_by_index(&init_net, if_id); + struct ieee80211_sub_if_data *sdata; + int short_preamble; + int erp; + u16 dur; + + if (unlikely(!bdev)) + return 0; + + sdata = IEEE80211_DEV_TO_SUB_IF(bdev); + short_preamble = sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE; + + rate = frame_txctl->rts_rate; + erp = !!(rate->flags & IEEE80211_RATE_ERP); + + /* Data frame duration */ + dur = ieee80211_frame_duration(local, frame_len, rate->rate, + erp, short_preamble); + if (!(frame_txctl->flags & IEEE80211_TXCTL_NO_ACK)) { + /* ACK duration */ + dur += ieee80211_frame_duration(local, 10, rate->rate, + erp, short_preamble); + } + + dev_put(bdev); + return cpu_to_le16(dur); +} +EXPORT_SYMBOL(ieee80211_ctstoself_duration); + +struct ieee80211_rate * +ieee80211_get_rate(struct ieee80211_local *local, int phymode, int hw_rate) +{ + struct ieee80211_hw_mode *mode; + int r; + + list_for_each_entry(mode, &local->modes_list, list) { + if (mode->mode != phymode) + continue; + for (r = 0; r < mode->num_rates; r++) { + struct ieee80211_rate *rate = &mode->rates[r]; + if (rate->val == hw_rate || + (rate->flags & IEEE80211_RATE_PREAMBLE2 && + rate->val2 == hw_rate)) + return rate; + } + } + + return NULL; +} + +void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) +{ + struct ieee80211_local *local = hw_to_local(hw); + + if (test_and_clear_bit(IEEE80211_LINK_STATE_XOFF, + &local->state[queue])) { + if (test_bit(IEEE80211_LINK_STATE_PENDING, + &local->state[queue])) + tasklet_schedule(&local->tx_pending_tasklet); + else + if (!ieee80211_qdisc_installed(local->mdev)) { + if (queue == 0) + netif_wake_queue(local->mdev); + } else + __netif_schedule(local->mdev); + } +} +EXPORT_SYMBOL(ieee80211_wake_queue); + +void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) +{ + struct ieee80211_local *local = hw_to_local(hw); + + if (!ieee80211_qdisc_installed(local->mdev) && queue == 0) + netif_stop_queue(local->mdev); + set_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]); +} +EXPORT_SYMBOL(ieee80211_stop_queue); + +void ieee80211_start_queues(struct ieee80211_hw *hw) +{ + struct ieee80211_local *local = hw_to_local(hw); + int i; + + for (i = 0; i < local->hw.queues; i++) + clear_bit(IEEE80211_LINK_STATE_XOFF, &local->state[i]); + if (!ieee80211_qdisc_installed(local->mdev)) + netif_start_queue(local->mdev); +} +EXPORT_SYMBOL(ieee80211_start_queues); + +void ieee80211_stop_queues(struct ieee80211_hw *hw) +{ + int i; + + for (i = 0; i < hw->queues; i++) + ieee80211_stop_queue(hw, i); +} +EXPORT_SYMBOL(ieee80211_stop_queues); + +void ieee80211_wake_queues(struct ieee80211_hw *hw) +{ + int i; + + for (i = 0; i < hw->queues; i++) + ieee80211_wake_queue(hw, i); +} +EXPORT_SYMBOL(ieee80211_wake_queues); diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index 1ad3d75..6675261 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -63,11 +63,11 @@ static inline int ieee80211_wep_weak_iv(u32 iv, int keylen) } -void ieee80211_wep_get_iv(struct ieee80211_local *local, - struct ieee80211_key *key, u8 *iv) +static void ieee80211_wep_get_iv(struct ieee80211_local *local, + struct ieee80211_key *key, u8 *iv) { local->wep_iv++; - if (ieee80211_wep_weak_iv(local->wep_iv, key->keylen)) + if (ieee80211_wep_weak_iv(local->wep_iv, key->conf.keylen)) local->wep_iv += 0x0100; if (!iv) @@ -76,13 +76,13 @@ void ieee80211_wep_get_iv(struct ieee80211_local *local, *iv++ = (local->wep_iv >> 16) & 0xff; *iv++ = (local->wep_iv >> 8) & 0xff; *iv++ = local->wep_iv & 0xff; - *iv++ = key->keyidx << 6; + *iv++ = key->conf.keyidx << 6; } -u8 * ieee80211_wep_add_iv(struct ieee80211_local *local, - struct sk_buff *skb, - struct ieee80211_key *key) +static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local, + struct sk_buff *skb, + struct ieee80211_key *key) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; u16 fc; @@ -109,9 +109,9 @@ u8 * ieee80211_wep_add_iv(struct ieee80211_local *local, } -void ieee80211_wep_remove_iv(struct ieee80211_local *local, - struct sk_buff *skb, - struct ieee80211_key *key) +static void ieee80211_wep_remove_iv(struct ieee80211_local *local, + struct sk_buff *skb, + struct ieee80211_key *key) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; u16 fc; @@ -159,10 +159,10 @@ int ieee80211_wep_encrypt(struct ieee80211_local *local, struct sk_buff *skb, u8 *rc4key, *iv; size_t len; - if (!key || key->alg != ALG_WEP) + if (!key || key->conf.alg != ALG_WEP) return -1; - klen = 3 + key->keylen; + klen = 3 + key->conf.keylen; rc4key = kmalloc(klen, GFP_ATOMIC); if (!rc4key) return -1; @@ -179,7 +179,7 @@ int ieee80211_wep_encrypt(struct ieee80211_local *local, struct sk_buff *skb, memcpy(rc4key, iv, 3); /* Copy rest of the WEP key (the secret part) */ - memcpy(rc4key + 3, key->key, key->keylen); + memcpy(rc4key + 3, key->conf.key, key->conf.keylen); /* Add room for ICV */ skb_put(skb, WEP_ICV_LEN); @@ -251,10 +251,10 @@ int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb, keyidx = skb->data[hdrlen + 3] >> 6; - if (!key || keyidx != key->keyidx || key->alg != ALG_WEP) + if (!key || keyidx != key->conf.keyidx || key->conf.alg != ALG_WEP) return -1; - klen = 3 + key->keylen; + klen = 3 + key->conf.keylen; rc4key = kmalloc(klen, GFP_ATOMIC); if (!rc4key) @@ -264,7 +264,7 @@ int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb, memcpy(rc4key, skb->data + hdrlen, 3); /* Copy rest of the WEP key (the secret part) */ - memcpy(rc4key + 3, key->key, key->keylen); + memcpy(rc4key + 3, key->conf.key, key->conf.keylen); if (ieee80211_wep_decrypt_data(local->wep_rx_tfm, rc4key, klen, skb->data + hdrlen + WEP_IV_LEN, @@ -286,43 +286,99 @@ int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb, } -int ieee80211_wep_get_keyidx(struct sk_buff *skb) +u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; u16 fc; int hdrlen; + u8 *ivpos; + u32 iv; fc = le16_to_cpu(hdr->frame_control); if (!(fc & IEEE80211_FCTL_PROTECTED)) - return -1; + return NULL; hdrlen = ieee80211_get_hdrlen(fc); + ivpos = skb->data + hdrlen; + iv = (ivpos[0] << 16) | (ivpos[1] << 8) | ivpos[2]; - if (skb->len < 8 + hdrlen) - return -1; + if (ieee80211_wep_weak_iv(iv, key->conf.keylen)) + return ivpos; - return skb->data[hdrlen + 3] >> 6; + return NULL; } +ieee80211_txrx_result +ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx) +{ + if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA && + ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || + (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH)) + return TXRX_CONTINUE; + + if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) { + if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) { + if (net_ratelimit()) + printk(KERN_DEBUG "%s: RX WEP frame, decrypt " + "failed\n", rx->dev->name); + return TXRX_DROP; + } + } else if (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) { + ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key); + /* remove ICV */ + skb_trim(rx->skb, rx->skb->len - 4); + } -u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key) + return TXRX_CONTINUE; +} + +static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { + if (ieee80211_wep_encrypt(tx->local, skb, tx->key)) + return -1; + } else { + tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx; + if (tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) { + if (!ieee80211_wep_add_iv(tx->local, skb, tx->key)) + return -1; + } + } + return 0; +} + +ieee80211_txrx_result +ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; u16 fc; - int hdrlen; - u8 *ivpos; - u32 iv; fc = le16_to_cpu(hdr->frame_control); - if (!(fc & IEEE80211_FCTL_PROTECTED)) - return NULL; - hdrlen = ieee80211_get_hdrlen(fc); - ivpos = skb->data + hdrlen; - iv = (ivpos[0] << 16) | (ivpos[1] << 8) | ivpos[2]; + if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA && + ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || + (fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH))) + return TXRX_CONTINUE; - if (ieee80211_wep_weak_iv(iv, key->keylen)) - return ivpos; + tx->u.tx.control->iv_len = WEP_IV_LEN; + tx->u.tx.control->icv_len = WEP_ICV_LEN; + ieee80211_tx_set_iswep(tx); - return NULL; + if (wep_encrypt_skb(tx, tx->skb) < 0) { + I802_DEBUG_INC(tx->local->tx_handlers_drop_wep); + return TXRX_DROP; + } + + if (tx->u.tx.extra_frag) { + int i; + for (i = 0; i < tx->u.tx.num_extra_frag; i++) { + if (wep_encrypt_skb(tx, tx->u.tx.extra_frag[i]) < 0) { + I802_DEBUG_INC(tx->local-> + tx_handlers_drop_wep); + return TXRX_DROP; + } + } + } + + return TXRX_CONTINUE; } diff --git a/net/mac80211/wep.h b/net/mac80211/wep.h index bfe29e8..785fbb4 100644 --- a/net/mac80211/wep.h +++ b/net/mac80211/wep.h @@ -18,14 +18,6 @@ int ieee80211_wep_init(struct ieee80211_local *local); void ieee80211_wep_free(struct ieee80211_local *local); -void ieee80211_wep_get_iv(struct ieee80211_local *local, - struct ieee80211_key *key, u8 *iv); -u8 * ieee80211_wep_add_iv(struct ieee80211_local *local, - struct sk_buff *skb, - struct ieee80211_key *key); -void ieee80211_wep_remove_iv(struct ieee80211_local *local, - struct sk_buff *skb, - struct ieee80211_key *key); void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, size_t klen, u8 *data, size_t data_len); int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, @@ -34,7 +26,11 @@ int ieee80211_wep_encrypt(struct ieee80211_local *local, struct sk_buff *skb, struct ieee80211_key *key); int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb, struct ieee80211_key *key); -int ieee80211_wep_get_keyidx(struct sk_buff *skb); u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key); +ieee80211_txrx_result +ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx); +ieee80211_txrx_result +ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx); + #endif /* WEP_H */ diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 7ab82b3..5b8a157 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -18,70 +18,6 @@ #include "ieee80211_i.h" #include "wme.h" -static inline int WLAN_FC_IS_QOS_DATA(u16 fc) -{ - return (fc & 0x8C) == 0x88; -} - - -ieee80211_txrx_result -ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx) -{ - u8 *data = rx->skb->data; - int tid; - - /* does the frame have a qos control field? */ - if (WLAN_FC_IS_QOS_DATA(rx->fc)) { - u8 *qc = data + ieee80211_get_hdrlen(rx->fc) - QOS_CONTROL_LEN; - /* frame has qos control */ - tid = qc[0] & QOS_CONTROL_TID_MASK; - } else { - if (unlikely((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)) { - /* Separate TID for management frames */ - tid = NUM_RX_DATA_QUEUES - 1; - } else { - /* no qos control present */ - tid = 0; /* 802.1d - Best Effort */ - } - } -#ifdef CONFIG_MAC80211_DEBUG_COUNTERS - I802_DEBUG_INC(rx->local->wme_rx_queue[tid]); - if (rx->sta) { - I802_DEBUG_INC(rx->sta->wme_rx_queue[tid]); - } -#endif /* CONFIG_MAC80211_DEBUG_COUNTERS */ - - rx->u.rx.queue = tid; - /* Set skb->priority to 1d tag if highest order bit of TID is not set. - * For now, set skb->priority to 0 for other cases. */ - rx->skb->priority = (tid > 7) ? 0 : tid; - - return TXRX_CONTINUE; -} - - -ieee80211_txrx_result -ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx) -{ - u16 fc = rx->fc; - u8 *data = rx->skb->data; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) data; - - if (!WLAN_FC_IS_QOS_DATA(fc)) - return TXRX_CONTINUE; - - /* remove the qos control field, update frame type and meta-data */ - memmove(data + 2, data, ieee80211_get_hdrlen(fc) - 2); - hdr = (struct ieee80211_hdr *) skb_pull(rx->skb, 2); - /* change frame type to non QOS */ - rx->fc = fc &= ~IEEE80211_STYPE_QOS_DATA; - hdr->frame_control = cpu_to_le16(fc); - - return TXRX_CONTINUE; -} - - -#ifdef CONFIG_NET_SCHED /* maximum number of hardware queues we support. */ #define TC_80211_MAX_QUEUES 8 @@ -158,8 +94,6 @@ static inline int wme_downgrade_ac(struct sk_buff *skb) static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd) { struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr); - struct ieee80211_tx_packet_data *pkt_data = - (struct ieee80211_tx_packet_data *) skb->cb; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; unsigned short fc = le16_to_cpu(hdr->frame_control); int qos; @@ -172,12 +106,8 @@ static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd) return IEEE80211_TX_QUEUE_DATA0; } - if (unlikely(pkt_data->mgmt_iface)) { - /* Data frames from hostapd (mainly, EAPOL) use AC_VO - * and they will include QoS control fields if - * the target STA is using WME. */ - skb->priority = 7; - return ieee802_1d_to_ac[skb->priority]; + if (0 /* injected */) { + /* use AC from radiotap */ } /* is this a QoS frame? */ @@ -189,14 +119,13 @@ static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd) } /* use the data classifier to determine what 802.1d tag the - * data frame has */ + * data frame has */ skb->priority = classify_1d(skb, qd); - /* incase we are a client verify acm is not set for this ac */ + /* in case we are a client verify acm is not set for this ac */ while (unlikely(local->wmm_acm & BIT(skb->priority))) { if (wme_downgrade_ac(skb)) { - /* No AC with lower priority has acm=0, - * drop packet. */ + /* No AC with lower priority has acm=0, drop packet. */ return -1; } } @@ -217,7 +146,7 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) struct Qdisc *qdisc; int err, queue; - if (pkt_data->requeue) { + if (pkt_data->flags & IEEE80211_TXPD_REQUEUE) { skb_queue_tail(&q->requeued[pkt_data->queue], skb); qd->q.qlen++; return 0; @@ -675,4 +604,3 @@ void ieee80211_wme_unregister(void) { unregister_qdisc(&wme_qdisc_ops); } -#endif /* CONFIG_NET_SCHED */ diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h index f0bff10..76c713a 100644 --- a/net/mac80211/wme.h +++ b/net/mac80211/wme.h @@ -24,11 +24,10 @@ #define QOS_CONTROL_TAG1D_MASK 0x07 -ieee80211_txrx_result -ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx); - -ieee80211_txrx_result -ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx); +static inline int WLAN_FC_IS_QOS_DATA(u16 fc) +{ + return (fc & 0x8C) == 0x88; +} #ifdef CONFIG_NET_SCHED void ieee80211_install_qdisc(struct net_device *dev); diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 783af32..6695efb 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -11,10 +11,8 @@ #include <linux/slab.h> #include <linux/skbuff.h> #include <linux/compiler.h> -#include <net/iw_handler.h> - #include <net/mac80211.h> -#include "ieee80211_common.h" + #include "ieee80211_i.h" #include "michael.h" #include "tkip.h" @@ -84,16 +82,16 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx) fc = tx->fc; - if (!tx->key || tx->key->alg != ALG_TKIP || skb->len < 24 || + if (!tx->key || tx->key->conf.alg != ALG_TKIP || skb->len < 24 || !WLAN_FC_DATA_PRESENT(fc)) return TXRX_CONTINUE; if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len)) return TXRX_DROP; - if (!tx->key->force_sw_encrypt && - !tx->fragmented && - !(tx->local->hw.flags & IEEE80211_HW_TKIP_INCLUDE_MMIC) && + if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && + !(tx->flags & IEEE80211_TXRXD_FRAGMENTED) && + !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) && !wpa_test) { /* hwaccel - with no need for preallocated room for Michael MIC */ @@ -116,8 +114,8 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx) #else authenticator = 1; #endif - key = &tx->key->key[authenticator ? ALG_TKIP_TEMP_AUTH_TX_MIC_KEY : - ALG_TKIP_TEMP_AUTH_RX_MIC_KEY]; + key = &tx->key->conf.key[authenticator ? ALG_TKIP_TEMP_AUTH_TX_MIC_KEY : + ALG_TKIP_TEMP_AUTH_RX_MIC_KEY]; mic = skb_put(skb, MICHAEL_MIC_LEN); michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic); @@ -134,31 +132,20 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) u8 mic[MICHAEL_MIC_LEN]; struct sk_buff *skb = rx->skb; int authenticator = 1, wpa_test = 0; + DECLARE_MAC_BUF(mac); fc = rx->fc; - /* If device handles decryption totally, skip this check */ - if ((rx->local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP) || - (rx->local->hw.flags & IEEE80211_HW_DEVICE_STRIPS_MIC)) + /* + * No way to verify the MIC if the hardware stripped it + */ + if (rx->u.rx.status->flag & RX_FLAG_MMIC_STRIPPED) return TXRX_CONTINUE; - if (!rx->key || rx->key->alg != ALG_TKIP || + if (!rx->key || rx->key->conf.alg != ALG_TKIP || !(rx->fc & IEEE80211_FCTL_PROTECTED) || !WLAN_FC_DATA_PRESENT(fc)) return TXRX_CONTINUE; - if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && - !rx->key->force_sw_encrypt) { - if (rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) { - if (skb->len < MICHAEL_MIC_LEN) - return TXRX_DROP; - } - /* Need to verify Michael MIC sometimes in software even when - * hwaccel is used. Atheros ar5212: fragmented frames and QoS - * frames. */ - if (!rx->fragmented && !wpa_test) - goto remove_mic; - } - if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len) || data_len < MICHAEL_MIC_LEN) return TXRX_DROP; @@ -170,49 +157,28 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) #else authenticator = 1; #endif - key = &rx->key->key[authenticator ? ALG_TKIP_TEMP_AUTH_RX_MIC_KEY : - ALG_TKIP_TEMP_AUTH_TX_MIC_KEY]; + key = &rx->key->conf.key[authenticator ? ALG_TKIP_TEMP_AUTH_RX_MIC_KEY : + ALG_TKIP_TEMP_AUTH_TX_MIC_KEY]; michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic); if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) { - if (!rx->u.rx.ra_match) + if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) return TXRX_DROP; printk(KERN_DEBUG "%s: invalid Michael MIC in data frame from " - MAC_FMT "\n", rx->dev->name, MAC_ARG(sa)); - - do { - struct ieee80211_hdr *hdr; - union iwreq_data wrqu; - char *buf = kmalloc(128, GFP_ATOMIC); - if (!buf) - break; - - /* TODO: needed parameters: count, key type, TSC */ - hdr = (struct ieee80211_hdr *) skb->data; - sprintf(buf, "MLME-MICHAELMICFAILURE.indication(" - "keyid=%d %scast addr=" MAC_FMT ")", - rx->key->keyidx, - hdr->addr1[0] & 0x01 ? "broad" : "uni", - MAC_ARG(hdr->addr2)); - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = strlen(buf); - wireless_send_event(rx->dev, IWEVCUSTOM, &wrqu, buf); - kfree(buf); - } while (0); - - if (!rx->local->apdev) - return TXRX_DROP; - - ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status, - ieee80211_msg_michael_mic_failure); + "%s\n", rx->dev->name, print_mac(mac, sa)); - return TXRX_QUEUED; + mac80211_ev_michael_mic_failure(rx->dev, rx->key->conf.keyidx, + (void *) skb->data); + return TXRX_DROP; } - remove_mic: /* remove Michael MIC from payload */ skb_trim(skb, skb->len - MICHAEL_MIC_LEN); + /* update IV in key information to be able to detect replays */ + rx->key->u.tkip.iv32_rx[rx->u.rx.queue] = rx->u.rx.tkip_iv32; + rx->key->u.tkip.iv16_rx[rx->u.rx.queue] = rx->u.rx.tkip_iv16; + return TXRX_CONTINUE; } @@ -230,7 +196,11 @@ static int tkip_encrypt_skb(struct ieee80211_txrx_data *tx, hdrlen = ieee80211_get_hdrlen(fc); len = skb->len - hdrlen; - tailneed = !tx->key->force_sw_encrypt ? 0 : TKIP_ICV_LEN; + if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) + tailneed = 0; + else + tailneed = TKIP_ICV_LEN; + if ((skb_headroom(skb) < TKIP_IV_LEN || skb_tailroom(skb) < tailneed)) { I802_DEBUG_INC(tx->local->tx_expand_skb_head); @@ -248,8 +218,7 @@ static int tkip_encrypt_skb(struct ieee80211_txrx_data *tx, if (key->u.tkip.iv16 == 0) key->u.tkip.iv32++; - if (!tx->key->force_sw_encrypt) { - u32 flags = tx->local->hw.flags; + if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { hdr = (struct ieee80211_hdr *)skb->data; /* hwaccel - with preallocated room for IV */ @@ -259,23 +228,7 @@ static int tkip_encrypt_skb(struct ieee80211_txrx_data *tx, 0x7f), (u8) key->u.tkip.iv16); - if (flags & IEEE80211_HW_TKIP_REQ_PHASE2_KEY) - ieee80211_tkip_gen_rc4key(key, hdr->addr2, - tx->u.tx.control->tkip_key); - else if (flags & IEEE80211_HW_TKIP_REQ_PHASE1_KEY) { - if (key->u.tkip.iv16 == 0 || - !key->u.tkip.tx_initialized) { - ieee80211_tkip_gen_phase1key(key, hdr->addr2, - (u16 *)tx->u.tx.control->tkip_key); - key->u.tkip.tx_initialized = 1; - tx->u.tx.control->flags |= - IEEE80211_TXCTL_TKIP_NEW_PHASE1_KEY; - } else - tx->u.tx.control->flags &= - ~IEEE80211_TXCTL_TKIP_NEW_PHASE1_KEY; - } - - tx->u.tx.control->key_idx = tx->key->hw_key_idx; + tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx; return 0; } @@ -290,28 +243,27 @@ static int tkip_encrypt_skb(struct ieee80211_txrx_data *tx, ieee80211_txrx_result -ieee80211_tx_h_tkip_encrypt(struct ieee80211_txrx_data *tx) +ieee80211_crypto_tkip_encrypt(struct ieee80211_txrx_data *tx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; u16 fc; - struct ieee80211_key *key = tx->key; struct sk_buff *skb = tx->skb; int wpa_test = 0, test = 0; fc = le16_to_cpu(hdr->frame_control); - if (!key || key->alg != ALG_TKIP || !WLAN_FC_DATA_PRESENT(fc)) + if (!WLAN_FC_DATA_PRESENT(fc)) return TXRX_CONTINUE; tx->u.tx.control->icv_len = TKIP_ICV_LEN; tx->u.tx.control->iv_len = TKIP_IV_LEN; ieee80211_tx_set_iswep(tx); - if (!tx->key->force_sw_encrypt && - !(tx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) && + if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && + !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) && !wpa_test) { /* hwaccel - with no need for preallocated room for IV/ICV */ - tx->u.tx.control->key_idx = tx->key->hw_key_idx; + tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx; return TXRX_CONTINUE; } @@ -332,30 +284,31 @@ ieee80211_tx_h_tkip_encrypt(struct ieee80211_txrx_data *tx) ieee80211_txrx_result -ieee80211_rx_h_tkip_decrypt(struct ieee80211_txrx_data *rx) +ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; u16 fc; int hdrlen, res, hwaccel = 0, wpa_test = 0; struct ieee80211_key *key = rx->key; struct sk_buff *skb = rx->skb; + DECLARE_MAC_BUF(mac); fc = le16_to_cpu(hdr->frame_control); hdrlen = ieee80211_get_hdrlen(fc); - if (!rx->key || rx->key->alg != ALG_TKIP || - !(rx->fc & IEEE80211_FCTL_PROTECTED) || - (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) + if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) return TXRX_CONTINUE; if (!rx->sta || skb->len - hdrlen < 12) return TXRX_DROP; - if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && - !rx->key->force_sw_encrypt) { - if (!(rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV)) { - /* Hardware takes care of all processing, including - * replay protection, so no need to continue here. */ + if (rx->u.rx.status->flag & RX_FLAG_DECRYPTED) { + if (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED) { + /* + * Hardware took care of all processing, including + * replay protection, and stripped the ICV/IV so + * we cannot do any checks here. + */ return TXRX_CONTINUE; } @@ -366,11 +319,13 @@ ieee80211_rx_h_tkip_decrypt(struct ieee80211_txrx_data *rx) res = ieee80211_tkip_decrypt_data(rx->local->wep_rx_tfm, key, skb->data + hdrlen, skb->len - hdrlen, rx->sta->addr, - hwaccel, rx->u.rx.queue); + hwaccel, rx->u.rx.queue, + &rx->u.rx.tkip_iv32, + &rx->u.rx.tkip_iv16); if (res != TKIP_DECRYPT_OK || wpa_test) { printk(KERN_DEBUG "%s: TKIP decrypt failed for RX frame from " - MAC_FMT " (res=%d)\n", - rx->dev->name, MAC_ARG(rx->sta->addr), res); + "%s (res=%d)\n", + rx->dev->name, print_mac(mac, rx->sta->addr), res); return TXRX_DROP; } @@ -496,7 +451,10 @@ static int ccmp_encrypt_skb(struct ieee80211_txrx_data *tx, hdrlen = ieee80211_get_hdrlen(fc); len = skb->len - hdrlen; - tailneed = !key->force_sw_encrypt ? 0 : CCMP_MIC_LEN; + if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) + tailneed = 0; + else + tailneed = CCMP_MIC_LEN; if ((skb_headroom(skb) < CCMP_HDR_LEN || skb_tailroom(skb) < tailneed)) { @@ -520,11 +478,11 @@ static int ccmp_encrypt_skb(struct ieee80211_txrx_data *tx, break; } - ccmp_pn2hdr(pos, pn, key->keyidx); + ccmp_pn2hdr(pos, pn, key->conf.keyidx); - if (!key->force_sw_encrypt) { + if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { /* hwaccel - with preallocated room for CCMP header */ - tx->u.tx.control->key_idx = key->hw_key_idx; + tx->u.tx.control->key_idx = key->conf.hw_key_idx; return 0; } @@ -538,28 +496,27 @@ static int ccmp_encrypt_skb(struct ieee80211_txrx_data *tx, ieee80211_txrx_result -ieee80211_tx_h_ccmp_encrypt(struct ieee80211_txrx_data *tx) +ieee80211_crypto_ccmp_encrypt(struct ieee80211_txrx_data *tx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; - struct ieee80211_key *key = tx->key; u16 fc; struct sk_buff *skb = tx->skb; int test = 0; fc = le16_to_cpu(hdr->frame_control); - if (!key || key->alg != ALG_CCMP || !WLAN_FC_DATA_PRESENT(fc)) + if (!WLAN_FC_DATA_PRESENT(fc)) return TXRX_CONTINUE; tx->u.tx.control->icv_len = CCMP_MIC_LEN; tx->u.tx.control->iv_len = CCMP_HDR_LEN; ieee80211_tx_set_iswep(tx); - if (!tx->key->force_sw_encrypt && - !(tx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV)) { + if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && + !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { /* hwaccel - with no need for preallocated room for CCMP " * header or MIC fields */ - tx->u.tx.control->key_idx = tx->key->hw_key_idx; + tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx; return TXRX_CONTINUE; } @@ -568,7 +525,6 @@ ieee80211_tx_h_ccmp_encrypt(struct ieee80211_txrx_data *tx) if (tx->u.tx.extra_frag) { int i; - for (i = 0; i < tx->u.tx.num_extra_frag; i++) { if (ccmp_encrypt_skb(tx, tx->u.tx.extra_frag[i], test) < 0) @@ -581,7 +537,7 @@ ieee80211_tx_h_ccmp_encrypt(struct ieee80211_txrx_data *tx) ieee80211_txrx_result -ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx) +ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; u16 fc; @@ -590,13 +546,12 @@ ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx) struct sk_buff *skb = rx->skb; u8 pn[CCMP_PN_LEN]; int data_len; + DECLARE_MAC_BUF(mac); fc = le16_to_cpu(hdr->frame_control); hdrlen = ieee80211_get_hdrlen(fc); - if (!key || key->alg != ALG_CCMP || - !(rx->fc & IEEE80211_FCTL_PROTECTED) || - (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) + if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) return TXRX_CONTINUE; data_len = skb->len - hdrlen - CCMP_HDR_LEN - CCMP_MIC_LEN; @@ -604,8 +559,7 @@ ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx) return TXRX_DROP; if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && - !key->force_sw_encrypt && - !(rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV)) + (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) return TXRX_CONTINUE; (void) ccmp_hdr2pn(pn, skb->data + hdrlen); @@ -613,10 +567,11 @@ ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx) if (memcmp(pn, key->u.ccmp.rx_pn[rx->u.rx.queue], CCMP_PN_LEN) <= 0) { #ifdef CONFIG_MAC80211_DEBUG u8 *ppn = key->u.ccmp.rx_pn[rx->u.rx.queue]; + printk(KERN_DEBUG "%s: CCMP replay detected for RX frame from " - MAC_FMT " (RX PN %02x%02x%02x%02x%02x%02x <= prev. PN " + "%s (RX PN %02x%02x%02x%02x%02x%02x <= prev. PN " "%02x%02x%02x%02x%02x%02x)\n", rx->dev->name, - MAC_ARG(rx->sta->addr), + print_mac(mac, rx->sta->addr), pn[0], pn[1], pn[2], pn[3], pn[4], pn[5], ppn[0], ppn[1], ppn[2], ppn[3], ppn[4], ppn[5]); #endif /* CONFIG_MAC80211_DEBUG */ @@ -624,10 +579,8 @@ ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx) return TXRX_DROP; } - if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && - !key->force_sw_encrypt) { - /* hwaccel has already decrypted frame and verified MIC */ - } else { + if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) { + /* hardware didn't decrypt/verify MIC */ u8 *scratch, *b_0, *aad; scratch = key->u.ccmp.rx_crypto_buf; @@ -642,8 +595,8 @@ ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx) skb->data + skb->len - CCMP_MIC_LEN, skb->data + hdrlen + CCMP_HDR_LEN)) { printk(KERN_DEBUG "%s: CCMP decrypt failed for RX " - "frame from " MAC_FMT "\n", rx->dev->name, - MAC_ARG(rx->sta->addr)); + "frame from %s\n", rx->dev->name, + print_mac(mac, rx->sta->addr)); return TXRX_DROP; } } @@ -657,4 +610,3 @@ ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx) return TXRX_CONTINUE; } - diff --git a/net/mac80211/wpa.h b/net/mac80211/wpa.h index da3b959..49d80cf 100644 --- a/net/mac80211/wpa.h +++ b/net/mac80211/wpa.h @@ -19,13 +19,13 @@ ieee80211_txrx_result ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx); ieee80211_txrx_result -ieee80211_tx_h_tkip_encrypt(struct ieee80211_txrx_data *tx); +ieee80211_crypto_tkip_encrypt(struct ieee80211_txrx_data *tx); ieee80211_txrx_result -ieee80211_rx_h_tkip_decrypt(struct ieee80211_txrx_data *rx); +ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx); ieee80211_txrx_result -ieee80211_tx_h_ccmp_encrypt(struct ieee80211_txrx_data *tx); +ieee80211_crypto_ccmp_encrypt(struct ieee80211_txrx_data *tx); ieee80211_txrx_result -ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx); +ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx); #endif /* WPA_H */ |