Merge branch 'davem-next' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 8319c46..db300e0 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -333,3 +333,13 @@
to keep working over the upgrade to 2.6.26. At the scheduled time of
removal fixed lm-sensors (2.x or 3.x) should be readily available.
Who: Rene Herman <rene.herman@gmail.com>
+
+---------------------------
+
+What: Code that is now under CONFIG_WIRELESS_EXT_SYSFS
+ (in net/core/net-sysfs.c)
+When: After the only user (hal) has seen a release with the patches
+ for enough time, probably some time in 2010.
+Why: Over 1K .text/.data size reduction, data is available in other
+ ways (ioctls)
+Who: Johannes Berg <johannes@sipsolutions.net>
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index a40feae..d849326 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -148,9 +148,9 @@
but not loaded.
tcp_base_mss - INTEGER
- The initial value of search_low to be used by Packetization Layer
- Path MTU Discovery (MTU probing). If MTU probing is enabled,
- this is the inital MSS used by the connection.
+ The initial value of search_low to be used by the packetization layer
+ Path MTU discovery (MTU probing). If MTU probing is enabled,
+ this is the initial MSS used by the connection.
tcp_congestion_control - STRING
Set the congestion control algorithm to be used for new
@@ -185,10 +185,9 @@
timeouts. It is particularly beneficial in wireless environments
where packet loss is typically due to random radio interference
rather than intermediate router congestion. F-RTO is sender-side
- only modification. Therefore it does not require any support from
- the peer, but in a typical case, however, where wireless link is
- the local access link and most of the data flows downlink, the
- faraway servers should have F-RTO enabled to take advantage of it.
+ only modification. Therefore it does not require any support from
+ the peer.
+
If set to 1, basic version is enabled. 2 enables SACK enhanced
F-RTO if flow uses SACK. The basic version can be used also when
SACK is in use though scenario(s) with it exists where F-RTO
@@ -276,7 +275,7 @@
memory.
tcp_moderate_rcvbuf - BOOLEAN
- If set, TCP performs receive buffer autotuning, attempting to
+ If set, TCP performs receive buffer auto-tuning, attempting to
automatically size the buffer (no greater than tcp_rmem[2]) to
match the size required by the path for full throughput. Enabled by
default.
@@ -336,7 +335,7 @@
pressure.
Default: 8K
- default: default size of receive buffer used by TCP sockets.
+ default: initial size of receive buffer used by TCP sockets.
This value overrides net.core.rmem_default used by other protocols.
Default: 87380 bytes. This value results in window of 65535 with
default setting of tcp_adv_win_scale and tcp_app_win:0 and a bit
@@ -344,8 +343,10 @@
max: maximal size of receive buffer allowed for automatically
selected receiver buffers for TCP socket. This value does not override
- net.core.rmem_max, "static" selection via SO_RCVBUF does not use this.
- Default: 87380*2 bytes.
+ net.core.rmem_max. Calling setsockopt() with SO_RCVBUF disables
+ automatic tuning of that socket's receive buffer size, in which
+ case this value is ignored.
+ Default: between 87380B and 4MB, depending on RAM size.
tcp_sack - BOOLEAN
Enable select acknowledgments (SACKS).
@@ -358,7 +359,7 @@
Default: 1
tcp_stdurg - BOOLEAN
- Use the Host requirements interpretation of the TCP urg pointer field.
+ Use the Host requirements interpretation of the TCP urgent pointer field.
Most hosts use the older BSD interpretation, so if you turn this on
Linux might not communicate correctly with them.
Default: FALSE
@@ -371,12 +372,12 @@
tcp_syncookies - BOOLEAN
Only valid when the kernel was compiled with CONFIG_SYNCOOKIES
Send out syncookies when the syn backlog queue of a socket
- overflows. This is to prevent against the common 'syn flood attack'
+ overflows. This is to prevent against the common 'SYN flood attack'
Default: FALSE
Note, that syncookies is fallback facility.
It MUST NOT be used to help highly loaded servers to stand
- against legal connection rate. If you see synflood warnings
+ against legal connection rate. If you see SYN flood warnings
in your logs, but investigation shows that they occur
because of overload with legal connections, you should tune
another parameters until this warning disappear.
@@ -386,7 +387,7 @@
to use TCP extensions, can result in serious degradation
of some services (f.e. SMTP relaying), visible not by you,
but your clients and relays, contacting you. While you see
- synflood warnings in logs not being really flooded, your server
+ SYN flood warnings in logs not being really flooded, your server
is seriously misconfigured.
tcp_syn_retries - INTEGER
@@ -419,19 +420,21 @@
Enable window scaling as defined in RFC1323.
tcp_wmem - vector of 3 INTEGERs: min, default, max
- min: Amount of memory reserved for send buffers for TCP socket.
+ min: Amount of memory reserved for send buffers for TCP sockets.
Each TCP socket has rights to use it due to fact of its birth.
Default: 4K
- default: Amount of memory allowed for send buffers for TCP socket
- by default. This value overrides net.core.wmem_default used
- by other protocols, it is usually lower than net.core.wmem_default.
+ default: initial size of send buffer used by TCP sockets. This
+ value overrides net.core.wmem_default used by other protocols.
+ It is usually lower than net.core.wmem_default.
Default: 16K
- max: Maximal amount of memory allowed for automatically selected
- send buffers for TCP socket. This value does not override
- net.core.wmem_max, "static" selection via SO_SNDBUF does not use this.
- Default: 128K
+ max: Maximal amount of memory allowed for automatically tuned
+ send buffers for TCP sockets. This value does not override
+ net.core.wmem_max. Calling setsockopt() with SO_SNDBUF disables
+ automatic tuning of that socket's send buffer size, in which case
+ this value is ignored.
+ Default: between 64K and 4MB, depending on RAM size.
tcp_workaround_signed_windows - BOOLEAN
If set, assume no receipt of a window scaling option means the
@@ -1073,24 +1076,193 @@
Default: 1
+proc/sys/net/sctp/* Variables:
+
+addip_enable - BOOLEAN
+ Enable or disable extension of Dynamic Address Reconfiguration
+ (ADD-IP) functionality specified in RFC5061. This extension provides
+ the ability to dynamically add and remove new addresses for the SCTP
+ associations.
+
+ 1: Enable extension.
+
+ 0: Disable extension.
+
+ Default: 0
+
+addip_noauth_enable - BOOLEAN
+ Dynamic Address Reconfiguration (ADD-IP) requires the use of
+ authentication to protect the operations of adding or removing new
+ addresses. This requirement is mandated so that unauthorized hosts
+ would not be able to hijack associations. However, older
+ implementations may not have implemented this requirement while
+ allowing the ADD-IP extension. For reasons of interoperability,
+ we provide this variable to control the enforcement of the
+ authentication requirement.
+
+ 1: Allow ADD-IP extension to be used without authentication. This
+ should only be set in a closed environment for interoperability
+ with older implementations.
+
+ 0: Enforce the authentication requirement
+
+ Default: 0
+
+auth_enable - BOOLEAN
+ Enable or disable Authenticated Chunks extension. This extension
+ provides the ability to send and receive authenticated chunks and is
+ required for secure operation of Dynamic Address Reconfiguration
+ (ADD-IP) extension.
+
+ 1: Enable this extension.
+ 0: Disable this extension.
+
+ Default: 0
+
+prsctp_enable - BOOLEAN
+ Enable or disable the Partial Reliability extension (RFC3758) which
+ is used to notify peers that a given DATA should no longer be expected.
+
+ 1: Enable extension
+ 0: Disable
+
+ Default: 1
+
+max_burst - INTEGER
+ The limit of the number of new packets that can be initially sent. It
+ controls how bursty the generated traffic can be.
+
+ Default: 4
+
+association_max_retrans - INTEGER
+ Set the maximum number for retransmissions that an association can
+ attempt deciding that the remote end is unreachable. If this value
+ is exceeded, the association is terminated.
+
+ Default: 10
+
+max_init_retransmits - INTEGER
+ The maximum number of retransmissions of INIT and COOKIE-ECHO chunks
+ that an association will attempt before declaring the destination
+ unreachable and terminating.
+
+ Default: 8
+
+path_max_retrans - INTEGER
+ The maximum number of retransmissions that will be attempted on a given
+ path. Once this threshold is exceeded, the path is considered
+ unreachable, and new traffic will use a different path when the
+ association is multihomed.
+
+ Default: 5
+
+rto_initial - INTEGER
+ The initial round trip timeout value in milliseconds that will be used
+ in calculating round trip times. This is the initial time interval
+ for retransmissions.
+
+ Default: 3000
+
+rto_max - INTEGER
+ The maximum value (in milliseconds) of the round trip timeout. This
+ is the largest time interval that can elapse between retransmissions.
+
+ Default: 60000
+
+rto_min - INTEGER
+ The minimum value (in milliseconds) of the round trip timeout. This
+ is the smallest time interval the can elapse between retransmissions.
+
+ Default: 1000
+
+hb_interval - INTEGER
+ The interval (in milliseconds) between HEARTBEAT chunks. These chunks
+ are sent at the specified interval on idle paths to probe the state of
+ a given path between 2 associations.
+
+ Default: 30000
+
+sack_timeout - INTEGER
+ The amount of time (in milliseconds) that the implementation will wait
+ to send a SACK.
+
+ Default: 200
+
+valid_cookie_life - INTEGER
+ The default lifetime of the SCTP cookie (in milliseconds). The cookie
+ is used during association establishment.
+
+ Default: 60000
+
+cookie_preserve_enable - BOOLEAN
+ Enable or disable the ability to extend the lifetime of the SCTP cookie
+ that is used during the establishment phase of SCTP association
+
+ 1: Enable cookie lifetime extension.
+ 0: Disable
+
+ Default: 1
+
+rcvbuf_policy - INTEGER
+ Determines if the receive buffer is attributed to the socket or to
+ association. SCTP supports the capability to create multiple
+ associations on a single socket. When using this capability, it is
+ possible that a single stalled association that's buffering a lot
+ of data may block other associations from delivering their data by
+ consuming all of the receive buffer space. To work around this,
+ the rcvbuf_policy could be set to attribute the receiver buffer space
+ to each association instead of the socket. This prevents the described
+ blocking.
+
+ 1: rcvbuf space is per association
+ 0: recbuf space is per socket
+
+ Default: 0
+
+sndbuf_policy - INTEGER
+ Similar to rcvbuf_policy above, this applies to send buffer space.
+
+ 1: Send buffer is tracked per association
+ 0: Send buffer is tracked per socket.
+
+ Default: 0
+
+sctp_mem - vector of 3 INTEGERs: min, pressure, max
+ Number of pages allowed for queueing by all SCTP sockets.
+
+ min: Below this number of pages SCTP is not bothered about its
+ memory appetite. When amount of memory allocated by SCTP exceeds
+ this number, SCTP starts to moderate memory usage.
+
+ pressure: This value was introduced to follow format of tcp_mem.
+
+ max: Number of pages allowed for queueing by all SCTP sockets.
+
+ Default is calculated at boot time from amount of available memory.
+
+sctp_rmem - vector of 3 INTEGERs: min, default, max
+ See tcp_rmem for a description.
+
+sctp_wmem - vector of 3 INTEGERs: min, default, max
+ See tcp_wmem for a description.
+
UNDOCUMENTED:
-dev_weight FIXME
-discovery_slots FIXME
-discovery_timeout FIXME
-fast_poll_increase FIXME
-ip6_queue_maxlen FIXME
-lap_keepalive_time FIXME
-lo_cong FIXME
-max_baud_rate FIXME
-max_dgram_qlen FIXME
-max_noreply_time FIXME
-max_tx_data_size FIXME
-max_tx_window FIXME
-min_tx_turn_time FIXME
-mod_cong FIXME
-no_cong FIXME
-no_cong_thresh FIXME
-slot_timeout FIXME
-warn_noreply_time FIXME
+/proc/sys/net/core/*
+ dev_weight FIXME
+/proc/sys/net/unix/*
+ max_dgram_qlen FIXME
+
+/proc/sys/net/irda/*
+ fast_poll_increase FIXME
+ warn_noreply_time FIXME
+ discovery_slots FIXME
+ slot_timeout FIXME
+ max_baud_rate FIXME
+ discovery_timeout FIXME
+ lap_keepalive_time FIXME
+ max_noreply_time FIXME
+ max_tx_data_size FIXME
+ max_tx_window FIXME
+ min_tx_turn_time FIXME
diff --git a/drivers/net/arm/ixp4xx_eth.c b/drivers/net/arm/ixp4xx_eth.c
index c617b64..9b777d9 100644
--- a/drivers/net/arm/ixp4xx_eth.c
+++ b/drivers/net/arm/ixp4xx_eth.c
@@ -522,7 +522,6 @@
#endif
if ((n = queue_get_desc(rxq, port, 0)) < 0) {
- received = 0; /* No packet received */
#if DEBUG_RX
printk(KERN_DEBUG "%s: eth_poll netif_rx_complete\n",
dev->name);
@@ -543,7 +542,7 @@
printk(KERN_DEBUG "%s: eth_poll all done\n",
dev->name);
#endif
- return 0; /* all work done */
+ return received; /* all work done */
}
desc = rx_desc_ptr(port, n);
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 5a67372..b211486 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -419,8 +419,10 @@
}
if (!bond->alb_info.primary_is_promisc) {
- bond->alb_info.primary_is_promisc = 1;
- dev_set_promiscuity(bond->curr_active_slave->dev, 1);
+ if (!dev_set_promiscuity(bond->curr_active_slave->dev, 1))
+ bond->alb_info.primary_is_promisc = 1;
+ else
+ bond->alb_info.primary_is_promisc = 0;
}
bond->alb_info.rlb_promisc_timeout_counter = 0;
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index dc733d7..8ae7ff3 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -772,39 +772,49 @@
/*
* Push the promiscuity flag down to appropriate slaves
*/
-static void bond_set_promiscuity(struct bonding *bond, int inc)
+static int bond_set_promiscuity(struct bonding *bond, int inc)
{
+ int err = 0;
if (USES_PRIMARY(bond->params.mode)) {
/* write lock already acquired */
if (bond->curr_active_slave) {
- dev_set_promiscuity(bond->curr_active_slave->dev, inc);
+ err = dev_set_promiscuity(bond->curr_active_slave->dev,
+ inc);
}
} else {
struct slave *slave;
int i;
bond_for_each_slave(bond, slave, i) {
- dev_set_promiscuity(slave->dev, inc);
+ err = dev_set_promiscuity(slave->dev, inc);
+ if (err)
+ return err;
}
}
+ return err;
}
/*
* Push the allmulti flag down to all slaves
*/
-static void bond_set_allmulti(struct bonding *bond, int inc)
+static int bond_set_allmulti(struct bonding *bond, int inc)
{
+ int err = 0;
if (USES_PRIMARY(bond->params.mode)) {
/* write lock already acquired */
if (bond->curr_active_slave) {
- dev_set_allmulti(bond->curr_active_slave->dev, inc);
+ err = dev_set_allmulti(bond->curr_active_slave->dev,
+ inc);
}
} else {
struct slave *slave;
int i;
bond_for_each_slave(bond, slave, i) {
- dev_set_allmulti(slave->dev, inc);
+ err = dev_set_allmulti(slave->dev, inc);
+ if (err)
+ return err;
}
}
+ return err;
}
/*
@@ -965,6 +975,7 @@
}
if (new_active) {
+ /* FIXME: Signal errors upstream. */
if (bond->dev->flags & IFF_PROMISC) {
dev_set_promiscuity(new_active->dev, 1);
}
@@ -1544,12 +1555,16 @@
if (!USES_PRIMARY(bond->params.mode)) {
/* set promiscuity level to new slave */
if (bond_dev->flags & IFF_PROMISC) {
- dev_set_promiscuity(slave_dev, 1);
+ res = dev_set_promiscuity(slave_dev, 1);
+ if (res)
+ goto err_close;
}
/* set allmulti level to new slave */
if (bond_dev->flags & IFF_ALLMULTI) {
- dev_set_allmulti(slave_dev, 1);
+ res = dev_set_allmulti(slave_dev, 1);
+ if (res)
+ goto err_close;
}
netif_tx_lock_bh(bond_dev);
@@ -4065,6 +4080,10 @@
* Do promisc before checking multicast_mode
*/
if ((bond_dev->flags & IFF_PROMISC) && !(bond->flags & IFF_PROMISC)) {
+ /*
+ * FIXME: Need to handle the error when one of the multi-slaves
+ * encounters error.
+ */
bond_set_promiscuity(bond, 1);
}
@@ -4074,6 +4093,10 @@
/* set allmulti flag to slaves */
if ((bond_dev->flags & IFF_ALLMULTI) && !(bond->flags & IFF_ALLMULTI)) {
+ /*
+ * FIXME: Need to handle the error when one of the multi-slaves
+ * encounters error.
+ */
bond_set_allmulti(bond, 1);
}
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index c02ceaa..980001c 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -189,12 +189,20 @@
err = dev_unicast_add(lowerdev, dev->dev_addr, ETH_ALEN);
if (err < 0)
- return err;
- if (dev->flags & IFF_ALLMULTI)
- dev_set_allmulti(lowerdev, 1);
+ goto out;
+ if (dev->flags & IFF_ALLMULTI) {
+ err = dev_set_allmulti(lowerdev, 1);
+ if (err < 0)
+ goto del_unicast;
+ }
hlist_add_head_rcu(&vlan->hlist, &port->vlan_hash[dev->dev_addr[5]]);
return 0;
+
+del_unicast:
+ dev_unicast_delete(lowerdev, dev->dev_addr, ETH_ALEN);
+out:
+ return err;
}
static int macvlan_stop(struct net_device *dev)
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index aa4ee44..901551c 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -18,15 +18,11 @@
/*
* Changes:
*
- * Brian Braunstein <linuxkernel@bristyle.com> 2007/03/23
- * Fixed hw address handling. Now net_device.dev_addr is kept consistent
- * with tun.dev_addr when the address is set by this module.
- *
* Mike Kershaw <dragorn@kismetwireless.net> 2005/08/14
* Add TUNSETLINK ioctl to set the link encapsulation
*
* Mark Smith <markzzzsmith@yahoo.com.au>
- * Use random_ether_addr() for tap MAC address.
+ * Use random_ether_addr() for tap MAC address.
*
* Harald Roelle <harald.roelle@ifi.lmu.de> 2004/04/20
* Fixes in packet dropping, queue length setting and queue wakeup.
@@ -83,9 +79,16 @@
#define DBG1( a... )
#endif
+#define FLT_EXACT_COUNT 8
+struct tap_filter {
+ unsigned int count; /* Number of addrs. Zero means disabled */
+ u32 mask[2]; /* Mask of the hashed addrs */
+ unsigned char addr[FLT_EXACT_COUNT][ETH_ALEN];
+};
+
struct tun_struct {
struct list_head list;
- unsigned long flags;
+ unsigned int flags;
int attached;
uid_t owner;
gid_t group;
@@ -94,19 +97,119 @@
struct sk_buff_head readq;
struct net_device *dev;
+ struct fasync_struct *fasync;
- struct fasync_struct *fasync;
-
- unsigned long if_flags;
- u8 dev_addr[ETH_ALEN];
- u32 chr_filter[2];
- u32 net_filter[2];
+ struct tap_filter txflt;
#ifdef TUN_DEBUG
int debug;
#endif
};
+/* TAP filterting */
+static void addr_hash_set(u32 *mask, const u8 *addr)
+{
+ int n = ether_crc(ETH_ALEN, addr) >> 26;
+ mask[n >> 5] |= (1 << (n & 31));
+}
+
+static unsigned int addr_hash_test(const u32 *mask, const u8 *addr)
+{
+ int n = ether_crc(ETH_ALEN, addr) >> 26;
+ return mask[n >> 5] & (1 << (n & 31));
+}
+
+static int update_filter(struct tap_filter *filter, void __user *arg)
+{
+ struct { u8 u[ETH_ALEN]; } *addr;
+ struct tun_filter uf;
+ int err, alen, n, nexact;
+
+ if (copy_from_user(&uf, arg, sizeof(uf)))
+ return -EFAULT;
+
+ if (!uf.count) {
+ /* Disabled */
+ filter->count = 0;
+ return 0;
+ }
+
+ alen = ETH_ALEN * uf.count;
+ addr = kmalloc(alen, GFP_KERNEL);
+ if (!addr)
+ return -ENOMEM;
+
+ if (copy_from_user(addr, arg + sizeof(uf), alen)) {
+ err = -EFAULT;
+ goto done;
+ }
+
+ /* The filter is updated without holding any locks. Which is
+ * perfectly safe. We disable it first and in the worst
+ * case we'll accept a few undesired packets. */
+ filter->count = 0;
+ wmb();
+
+ /* Use first set of addresses as an exact filter */
+ for (n = 0; n < uf.count && n < FLT_EXACT_COUNT; n++)
+ memcpy(filter->addr[n], addr[n].u, ETH_ALEN);
+
+ nexact = n;
+
+ /* The rest is hashed */
+ memset(filter->mask, 0, sizeof(filter->mask));
+ for (; n < uf.count; n++)
+ addr_hash_set(filter->mask, addr[n].u);
+
+ /* For ALLMULTI just set the mask to all ones.
+ * This overrides the mask populated above. */
+ if ((uf.flags & TUN_FLT_ALLMULTI))
+ memset(filter->mask, ~0, sizeof(filter->mask));
+
+ /* Now enable the filter */
+ wmb();
+ filter->count = nexact;
+
+ /* Return the number of exact filters */
+ err = nexact;
+
+done:
+ kfree(addr);
+ return err;
+}
+
+/* Returns: 0 - drop, !=0 - accept */
+static int run_filter(struct tap_filter *filter, const struct sk_buff *skb)
+{
+ /* Cannot use eth_hdr(skb) here because skb_mac_hdr() is incorrect
+ * at this point. */
+ struct ethhdr *eh = (struct ethhdr *) skb->data;
+ int i;
+
+ /* Exact match */
+ for (i = 0; i < filter->count; i++)
+ if (!compare_ether_addr(eh->h_dest, filter->addr[i]))
+ return 1;
+
+ /* Inexact match (multicast only) */
+ if (is_multicast_ether_addr(eh->h_dest))
+ return addr_hash_test(filter->mask, eh->h_dest);
+
+ return 0;
+}
+
+/*
+ * Checks whether the packet is accepted or not.
+ * Returns: 0 - drop, !=0 - accept
+ */
+static int check_filter(struct tap_filter *filter, const struct sk_buff *skb)
+{
+ if (!filter->count)
+ return 1;
+
+ return run_filter(filter, skb);
+}
+
/* Network device part of the driver */
static unsigned int tun_net_id;
@@ -141,7 +244,12 @@
if (!tun->attached)
goto drop;
- /* Packet dropping */
+ /* Drop if the filter does not like it.
+ * This is a noop if the filter is disabled.
+ * Filter can be enabled only for the TAP devices. */
+ if (!check_filter(&tun->txflt, skb))
+ goto drop;
+
if (skb_queue_len(&tun->readq) >= dev->tx_queue_len) {
if (!(tun->flags & TUN_ONE_QUEUE)) {
/* Normal queueing mode. */
@@ -158,7 +266,7 @@
}
}
- /* Queue packet */
+ /* Enqueue packet */
skb_queue_tail(&tun->readq, skb);
dev->trans_start = jiffies;
@@ -174,41 +282,14 @@
return 0;
}
-/** Add the specified Ethernet address to this multicast filter. */
-static void
-add_multi(u32* filter, const u8* addr)
+static void tun_net_mclist(struct net_device *dev)
{
- int bit_nr = ether_crc(ETH_ALEN, addr) >> 26;
- filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
-}
-
-/** Remove the specified Ethernet addres from this multicast filter. */
-static void
-del_multi(u32* filter, const u8* addr)
-{
- int bit_nr = ether_crc(ETH_ALEN, addr) >> 26;
- filter[bit_nr >> 5] &= ~(1 << (bit_nr & 31));
-}
-
-/** Update the list of multicast groups to which the network device belongs.
- * This list is used to filter packets being sent from the character device to
- * the network device. */
-static void
-tun_net_mclist(struct net_device *dev)
-{
- struct tun_struct *tun = netdev_priv(dev);
- const struct dev_mc_list *mclist;
- int i;
- DECLARE_MAC_BUF(mac);
- DBG(KERN_DEBUG "%s: tun_net_mclist: mc_count %d\n",
- dev->name, dev->mc_count);
- memset(tun->chr_filter, 0, sizeof tun->chr_filter);
- for (i = 0, mclist = dev->mc_list; i < dev->mc_count && mclist != NULL;
- i++, mclist = mclist->next) {
- add_multi(tun->net_filter, mclist->dmi_addr);
- DBG(KERN_DEBUG "%s: tun_net_mclist: %s\n",
- dev->name, print_mac(mac, mclist->dmi_addr));
- }
+ /*
+ * This callback is supposed to deal with mc filter in
+ * _rx_ path and has nothing to do with the _tx_ path.
+ * In rx path we always accept everything userspace gives us.
+ */
+ return;
}
#define MIN_MTU 68
@@ -244,13 +325,11 @@
case TUN_TAP_DEV:
/* Ethernet TAP Device */
+ ether_setup(dev);
+ dev->change_mtu = tun_net_change_mtu;
dev->set_multicast_list = tun_net_mclist;
- ether_setup(dev);
- dev->change_mtu = tun_net_change_mtu;
-
- /* random address already created for us by tun_set_iff, use it */
- memcpy(dev->dev_addr, tun->dev_addr, min(sizeof(tun->dev_addr), sizeof(dev->dev_addr)) );
+ random_ether_addr(dev->dev_addr);
dev->tx_queue_len = TUN_READQ_SIZE; /* We prefer our own queue length */
break;
@@ -486,7 +565,6 @@
DECLARE_WAITQUEUE(wait, current);
struct sk_buff *skb;
ssize_t len, ret = 0;
- DECLARE_MAC_BUF(mac);
if (!tun)
return -EBADFD;
@@ -499,10 +577,6 @@
add_wait_queue(&tun->read_wait, &wait);
while (len) {
- const u8 ones[ ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
- u8 addr[ ETH_ALEN];
- int bit_nr;
-
current->state = TASK_INTERRUPTIBLE;
/* Read frames from the queue */
@@ -522,36 +596,9 @@
}
netif_wake_queue(tun->dev);
- /** Decide whether to accept this packet. This code is designed to
- * behave identically to an Ethernet interface. Accept the packet if
- * - we are promiscuous.
- * - the packet is addressed to us.
- * - the packet is broadcast.
- * - the packet is multicast and
- * - we are multicast promiscous.
- * - we belong to the multicast group.
- */
- skb_copy_from_linear_data(skb, addr, min_t(size_t, sizeof addr,
- skb->len));
- bit_nr = ether_crc(sizeof addr, addr) >> 26;
- if ((tun->if_flags & IFF_PROMISC) ||
- memcmp(addr, tun->dev_addr, sizeof addr) == 0 ||
- memcmp(addr, ones, sizeof addr) == 0 ||
- (((addr[0] == 1 && addr[1] == 0 && addr[2] == 0x5e) ||
- (addr[0] == 0x33 && addr[1] == 0x33)) &&
- ((tun->if_flags & IFF_ALLMULTI) ||
- (tun->chr_filter[bit_nr >> 5] & (1 << (bit_nr & 31)))))) {
- DBG(KERN_DEBUG "%s: tun_chr_readv: accepted: %s\n",
- tun->dev->name, print_mac(mac, addr));
- ret = tun_put_user(tun, skb, (struct iovec *) iv, len);
- kfree_skb(skb);
- break;
- } else {
- DBG(KERN_DEBUG "%s: tun_chr_readv: rejected: %s\n",
- tun->dev->name, print_mac(mac, addr));
- kfree_skb(skb);
- continue;
- }
+ ret = tun_put_user(tun, skb, (struct iovec *) iv, len);
+ kfree_skb(skb);
+ break;
}
current->state = TASK_RUNNING;
@@ -647,12 +694,7 @@
tun = netdev_priv(dev);
tun->dev = dev;
tun->flags = flags;
- /* Be promiscuous by default to maintain previous behaviour. */
- tun->if_flags = IFF_PROMISC;
- /* Generate random Ethernet address. */
- *(__be16 *)tun->dev_addr = htons(0x00FF);
- get_random_bytes(tun->dev_addr + sizeof(u16), 4);
- memset(tun->chr_filter, 0, sizeof tun->chr_filter);
+ tun->txflt.count = 0;
tun_net_init(dev);
@@ -690,6 +732,12 @@
tun->attached = 1;
get_net(dev_net(tun->dev));
+ /* Make sure persistent devices do not get stuck in
+ * xoff state.
+ */
+ if (netif_running(tun->dev))
+ netif_wake_queue(tun->dev);
+
strcpy(ifr->ifr_name, tun->dev->name);
return 0;
@@ -745,6 +793,7 @@
struct tun_struct *tun = file->private_data;
void __user* argp = (void __user*)arg;
struct ifreq ifr;
+ int ret;
DECLARE_MAC_BUF(mac);
if (cmd == TUNSETIFF || _IOC_TYPE(cmd) == 0x89)
@@ -820,9 +869,6 @@
break;
case TUNSETLINK:
- {
- int ret;
-
/* Only allow setting the type when the interface is down */
rtnl_lock();
if (tun->dev->flags & IFF_UP) {
@@ -836,94 +882,44 @@
}
rtnl_unlock();
return ret;
- }
#ifdef TUN_DEBUG
case TUNSETDEBUG:
tun->debug = arg;
break;
#endif
-
case TUNSETOFFLOAD:
- {
- int ret;
rtnl_lock();
ret = set_offload(tun->dev, arg);
rtnl_unlock();
return ret;
- }
- case SIOCGIFFLAGS:
- ifr.ifr_flags = tun->if_flags;
- if (copy_to_user( argp, &ifr, sizeof ifr))
- return -EFAULT;
- return 0;
-
- case SIOCSIFFLAGS:
- /** Set the character device's interface flags. Currently only
- * IFF_PROMISC and IFF_ALLMULTI are used. */
- tun->if_flags = ifr.ifr_flags;
- DBG(KERN_INFO "%s: interface flags 0x%lx\n",
- tun->dev->name, tun->if_flags);
- return 0;
+ case TUNSETTXFILTER:
+ /* Can be set only for TAPs */
+ if ((tun->flags & TUN_TYPE_MASK) != TUN_TAP_DEV)
+ return -EINVAL;
+ rtnl_lock();
+ ret = update_filter(&tun->txflt, (void *) __user arg);
+ rtnl_unlock();
+ return ret;
case SIOCGIFHWADDR:
- /* Note: the actual net device's address may be different */
- memcpy(ifr.ifr_hwaddr.sa_data, tun->dev_addr,
- min(sizeof ifr.ifr_hwaddr.sa_data, sizeof tun->dev_addr));
- if (copy_to_user( argp, &ifr, sizeof ifr))
+ /* Get hw addres */
+ memcpy(ifr.ifr_hwaddr.sa_data, tun->dev->dev_addr, ETH_ALEN);
+ ifr.ifr_hwaddr.sa_family = tun->dev->type;
+ if (copy_to_user(argp, &ifr, sizeof ifr))
return -EFAULT;
return 0;
case SIOCSIFHWADDR:
- {
- /* try to set the actual net device's hw address */
- int ret;
+ /* Set hw address */
+ DBG(KERN_DEBUG "%s: set hw address: %s\n",
+ tun->dev->name, print_mac(mac, ifr.ifr_hwaddr.sa_data));
rtnl_lock();
ret = dev_set_mac_address(tun->dev, &ifr.ifr_hwaddr);
rtnl_unlock();
-
- if (ret == 0) {
- /** Set the character device's hardware address. This is used when
- * filtering packets being sent from the network device to the character
- * device. */
- memcpy(tun->dev_addr, ifr.ifr_hwaddr.sa_data,
- min(sizeof ifr.ifr_hwaddr.sa_data, sizeof tun->dev_addr));
- DBG(KERN_DEBUG "%s: set hardware address: %x:%x:%x:%x:%x:%x\n",
- tun->dev->name,
- tun->dev_addr[0], tun->dev_addr[1], tun->dev_addr[2],
- tun->dev_addr[3], tun->dev_addr[4], tun->dev_addr[5]);
- }
-
- return ret;
- }
-
- case SIOCADDMULTI:
- /** Add the specified group to the character device's multicast filter
- * list. */
- rtnl_lock();
- netif_tx_lock_bh(tun->dev);
- add_multi(tun->chr_filter, ifr.ifr_hwaddr.sa_data);
- netif_tx_unlock_bh(tun->dev);
- rtnl_unlock();
-
- DBG(KERN_DEBUG "%s: add multi: %s\n",
- tun->dev->name, print_mac(mac, ifr.ifr_hwaddr.sa_data));
- return 0;
-
- case SIOCDELMULTI:
- /** Remove the specified group from the character device's multicast
- * filter list. */
- rtnl_lock();
- netif_tx_lock_bh(tun->dev);
- del_multi(tun->chr_filter, ifr.ifr_hwaddr.sa_data);
- netif_tx_unlock_bh(tun->dev);
- rtnl_unlock();
-
- DBG(KERN_DEBUG "%s: del multi: %s\n",
- tun->dev->name, print_mac(mac, ifr.ifr_hwaddr.sa_data));
- return 0;
+ return ret;
default:
return -EINVAL;
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig
index d5140ae..846be60 100644
--- a/drivers/net/wan/Kconfig
+++ b/drivers/net/wan/Kconfig
@@ -390,8 +390,7 @@
Select driver your card and remember to say Y to "Wan Router."
You will need the wan-tools package which is available from
- <ftp://ftp.sangoma.com/>. For more information read:
- <file:Documentation/networking/wan-router.txt>.
+ <ftp://ftp.sangoma.com/>.
Note that the answer to this question won't directly affect the
kernel except for how subordinate drivers may be built:
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c
index a43e9b2..217d506 100644
--- a/drivers/net/wireless/ath5k/base.c
+++ b/drivers/net/wireless/ath5k/base.c
@@ -207,7 +207,6 @@
.get_tx_stats = ath5k_get_tx_stats,
.get_tsf = ath5k_get_tsf,
.reset_tsf = ath5k_reset_tsf,
- .beacon_update = ath5k_beacon_update,
};
/*
@@ -2785,6 +2784,18 @@
* a clean way of letting us retrieve this yet. */
ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
}
+
+ if (conf->changed & IEEE80211_IFCC_BEACON &&
+ vif->type == IEEE80211_IF_TYPE_IBSS) {
+ struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
+ if (!beacon) {
+ ret = -ENOMEM;
+ goto unlock;
+ }
+ /* call old handler for now */
+ ath5k_beacon_update(hw, beacon);
+ }
+
mutex_unlock(&sc->lock);
return ath5k_reset(hw);
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 9d2eb27..381dbd3 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -1675,14 +1675,24 @@
/* Asynchronously update the packet templates in template RAM.
* Locking: Requires wl->irq_lock to be locked. */
-static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon)
+static void b43_update_templates(struct b43_wl *wl)
{
+ struct sk_buff *beacon;
+
/* This is the top half of the ansynchronous beacon update.
* The bottom half is the beacon IRQ.
* Beacon update must be asynchronous to avoid sending an
* invalid beacon. This can happen for example, if the firmware
* transmits a beacon while we are updating it. */
+ /* We could modify the existing beacon and set the aid bit in
+ * the TIM field, but that would probably require resizing and
+ * moving of data within the beacon template.
+ * Simply request a new beacon and let mac80211 do the hard work. */
+ beacon = ieee80211_beacon_get(wl->hw, wl->vif);
+ if (unlikely(!beacon))
+ return;
+
if (wl->current_beacon)
dev_kfree_skb_any(wl->current_beacon);
wl->current_beacon = beacon;
@@ -3645,10 +3655,14 @@
if (b43_status(dev) >= B43_STAT_INITIALIZED) {
if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP) ||
b43_is_mode(wl, IEEE80211_IF_TYPE_MESH_POINT)) {
- B43_WARN_ON(conf->type != wl->if_type);
- b43_set_ssid(dev, conf->ssid, conf->ssid_len);
- if (conf->beacon)
- b43_update_templates(wl, conf->beacon);
+ B43_WARN_ON(vif->type != wl->if_type);
+ if (conf->changed & IEEE80211_IFCC_SSID)
+ b43_set_ssid(dev, conf->ssid, conf->ssid_len);
+ if (conf->changed & IEEE80211_IFCC_BEACON)
+ b43_update_templates(wl);
+ } else if (b43_is_mode(wl, IEEE80211_IF_TYPE_IBSS)) {
+ if (conf->changed & IEEE80211_IFCC_BEACON)
+ b43_update_templates(wl);
}
b43_write_mac_bssid_templates(dev);
}
@@ -4336,31 +4350,10 @@
static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, int aid, int set)
{
struct b43_wl *wl = hw_to_b43_wl(hw);
- struct sk_buff *beacon;
- unsigned long flags;
-
- /* We could modify the existing beacon and set the aid bit in
- * the TIM field, but that would probably require resizing and
- * moving of data within the beacon template.
- * Simply request a new beacon and let mac80211 do the hard work. */
- beacon = ieee80211_beacon_get(hw, wl->vif);
- if (unlikely(!beacon))
- return -ENOMEM;
- spin_lock_irqsave(&wl->irq_lock, flags);
- b43_update_templates(wl, beacon);
- spin_unlock_irqrestore(&wl->irq_lock, flags);
-
- return 0;
-}
-
-static int b43_op_ibss_beacon_update(struct ieee80211_hw *hw,
- struct sk_buff *beacon)
-{
- struct b43_wl *wl = hw_to_b43_wl(hw);
unsigned long flags;
spin_lock_irqsave(&wl->irq_lock, flags);
- b43_update_templates(wl, beacon);
+ b43_update_templates(wl);
spin_unlock_irqrestore(&wl->irq_lock, flags);
return 0;
@@ -4391,7 +4384,6 @@
.stop = b43_op_stop,
.set_retry_limit = b43_op_set_retry_limit,
.set_tim = b43_op_beacon_set_tim,
- .beacon_update = b43_op_ibss_beacon_update,
.sta_notify = b43_op_sta_notify,
};
diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c
index bf6f6c1..8d54502 100644
--- a/drivers/net/wireless/b43/xmit.c
+++ b/drivers/net/wireless/b43/xmit.c
@@ -317,7 +317,8 @@
/* MAC control */
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
mac_ctl |= B43_TXH_MAC_ACK;
- if (!ieee80211_is_pspoll(fctl))
+ /* use hardware sequence counter as the non-TID counter */
+ if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
mac_ctl |= B43_TXH_MAC_HWSEQ;
if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
mac_ctl |= B43_TXH_MAC_STMSDU;
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index 069157e..a1b8bf3 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -1138,14 +1138,22 @@
/* Asynchronously update the packet templates in template RAM.
* Locking: Requires wl->irq_lock to be locked. */
-static void b43legacy_update_templates(struct b43legacy_wl *wl,
- struct sk_buff *beacon)
+static void b43legacy_update_templates(struct b43legacy_wl *wl)
{
+ struct sk_buff *beacon;
/* This is the top half of the ansynchronous beacon update. The bottom
* half is the beacon IRQ. Beacon update must be asynchronous to avoid
* sending an invalid beacon. This can happen for example, if the
* firmware transmits a beacon while we are updating it. */
+ /* We could modify the existing beacon and set the aid bit in the TIM
+ * field, but that would probably require resizing and moving of data
+ * within the beacon template. Simply request a new beacon and let
+ * mac80211 do the hard work. */
+ beacon = ieee80211_beacon_get(wl->hw, wl->vif);
+ if (unlikely(!beacon))
+ return;
+
if (wl->current_beacon)
dev_kfree_skb_any(wl->current_beacon);
wl->current_beacon = beacon;
@@ -2727,10 +2735,13 @@
memset(wl->bssid, 0, ETH_ALEN);
if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) {
if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) {
- B43legacy_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP);
+ B43legacy_WARN_ON(vif->type != IEEE80211_IF_TYPE_AP);
b43legacy_set_ssid(dev, conf->ssid, conf->ssid_len);
- if (conf->beacon)
- b43legacy_update_templates(wl, conf->beacon);
+ if (conf->changed & IEEE80211_IFCC_BEACON)
+ b43legacy_update_templates(wl);
+ } else if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_IBSS)) {
+ if (conf->changed & IEEE80211_IFCC_BEACON)
+ b43legacy_update_templates(wl);
}
b43legacy_write_mac_bssid_templates(dev);
}
@@ -3396,31 +3407,10 @@
int aid, int set)
{
struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
- struct sk_buff *beacon;
- unsigned long flags;
-
- /* We could modify the existing beacon and set the aid bit in the TIM
- * field, but that would probably require resizing and moving of data
- * within the beacon template. Simply request a new beacon and let
- * mac80211 do the hard work. */
- beacon = ieee80211_beacon_get(hw, wl->vif);
- if (unlikely(!beacon))
- return -ENOMEM;
- spin_lock_irqsave(&wl->irq_lock, flags);
- b43legacy_update_templates(wl, beacon);
- spin_unlock_irqrestore(&wl->irq_lock, flags);
-
- return 0;
-}
-
-static int b43legacy_op_ibss_beacon_update(struct ieee80211_hw *hw,
- struct sk_buff *beacon)
-{
- struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
unsigned long flags;
spin_lock_irqsave(&wl->irq_lock, flags);
- b43legacy_update_templates(wl, beacon);
+ b43legacy_update_templates(wl);
spin_unlock_irqrestore(&wl->irq_lock, flags);
return 0;
@@ -3440,7 +3430,6 @@
.stop = b43legacy_op_stop,
.set_retry_limit = b43legacy_op_set_retry_limit,
.set_tim = b43legacy_op_beacon_set_tim,
- .beacon_update = b43legacy_op_ibss_beacon_update,
};
/* Hard-reset the chip. Do not call this directly.
diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c
index a354078..e969ed8 100644
--- a/drivers/net/wireless/b43legacy/xmit.c
+++ b/drivers/net/wireless/b43legacy/xmit.c
@@ -295,8 +295,7 @@
/* MAC control */
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
mac_ctl |= B43legacy_TX4_MAC_ACK;
- if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
- ((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)))
+ if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
mac_ctl |= B43legacy_TX4_MAC_HWSEQ;
if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
mac_ctl |= B43legacy_TX4_MAC_STMSDU;
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c
index 8b1528e..6be1fe1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c
@@ -42,14 +42,11 @@
#include "iwl-3945.h"
#include "iwl-helpers.h"
-#define IWL_1MB_RATE (128 * 1024)
-#define IWL_LED_THRESHOLD (16)
-#define IWL_MAX_BLINK_TBL (10)
static const struct {
u16 brightness;
u8 on_time;
- u8 of_time;
+ u8 off_time;
} blink_tbl[] =
{
{300, 25, 25},
@@ -61,9 +58,16 @@
{15, 95, 95 },
{10, 110, 110},
{5, 130, 130},
- {0, 167, 167}
+ {0, 167, 167},
+ /*SOLID_ON*/
+ {-1, IWL_LED_SOLID, 0}
};
+#define IWL_1MB_RATE (128 * 1024)
+#define IWL_LED_THRESHOLD (16)
+#define IWL_MAX_BLINK_TBL (ARRAY_SIZE(blink_tbl) - 1) /*Exclude Solid on*/
+#define IWL_SOLID_BLINK_IDX (ARRAY_SIZE(blink_tbl) - 1)
+
static int iwl3945_led_cmd_callback(struct iwl3945_priv *priv,
struct iwl3945_cmd *cmd,
struct sk_buff *skb)
@@ -71,6 +75,10 @@
return 1;
}
+static inline int iwl3945_brightness_to_idx(enum led_brightness brightness)
+{
+ return fls(0x000000FF & (u32)brightness);
+}
/* Send led command */
static int iwl_send_led_cmd(struct iwl3945_priv *priv,
@@ -81,13 +89,33 @@
.len = sizeof(struct iwl3945_led_cmd),
.data = led_cmd,
.meta.flags = CMD_ASYNC,
- .meta.u.callback = iwl3945_led_cmd_callback
+ .meta.u.callback = iwl3945_led_cmd_callback,
};
return iwl3945_send_cmd(priv, &cmd);
}
+
+/* Set led on command */
+static int iwl3945_led_pattern(struct iwl3945_priv *priv, int led_id,
+ unsigned int idx)
+{
+ struct iwl3945_led_cmd led_cmd = {
+ .id = led_id,
+ .interval = IWL_DEF_LED_INTRVL
+ };
+
+ BUG_ON(idx > IWL_MAX_BLINK_TBL);
+
+ led_cmd.on = blink_tbl[idx].on_time;
+ led_cmd.off = blink_tbl[idx].off_time;
+
+ return iwl_send_led_cmd(priv, &led_cmd);
+}
+
+
+#if 1
/* Set led on command */
static int iwl3945_led_on(struct iwl3945_priv *priv, int led_id)
{
@@ -100,30 +128,6 @@
return iwl_send_led_cmd(priv, &led_cmd);
}
-/* Set led on command */
-static int iwl3945_led_pattern(struct iwl3945_priv *priv, int led_id,
- enum led_brightness brightness)
-{
- struct iwl3945_led_cmd led_cmd = {
- .id = led_id,
- .on = brightness,
- .off = brightness,
- .interval = IWL_DEF_LED_INTRVL
- };
- if (brightness == LED_FULL) {
- led_cmd.on = IWL_LED_SOLID;
- led_cmd.off = 0;
- }
- return iwl_send_led_cmd(priv, &led_cmd);
-}
-
-/* Set led register off */
-static int iwl3945_led_on_reg(struct iwl3945_priv *priv, int led_id)
-{
- IWL_DEBUG_LED("led on %d\n", led_id);
- return iwl3945_led_on(priv, led_id);
-}
-
/* Set led off command */
static int iwl3945_led_off(struct iwl3945_priv *priv, int led_id)
{
@@ -136,27 +140,7 @@
IWL_DEBUG_LED("led off %d\n", led_id);
return iwl_send_led_cmd(priv, &led_cmd);
}
-
-/* Set led register off */
-static int iwl3945_led_off_reg(struct iwl3945_priv *priv, int led_id)
-{
- iwl3945_led_off(priv, led_id);
- return 0;
-}
-
-/* Set led blink command */
-static int iwl3945_led_not_solid(struct iwl3945_priv *priv, int led_id,
- u8 brightness)
-{
- struct iwl3945_led_cmd led_cmd = {
- .id = led_id,
- .on = brightness,
- .off = brightness,
- .interval = IWL_DEF_LED_INTRVL
- };
-
- return iwl_send_led_cmd(priv, &led_cmd);
-}
+#endif
/*
@@ -206,8 +190,10 @@
led->led_off(priv, IWL_LED_LINK);
break;
default:
- if (led->led_pattern)
- led->led_pattern(priv, IWL_LED_LINK, brightness);
+ if (led->led_pattern) {
+ int idx = iwl3945_brightness_to_idx(brightness);
+ led->led_pattern(priv, IWL_LED_LINK, idx);
+ }
break;
}
}
@@ -252,24 +238,20 @@
static inline u8 get_blink_rate(struct iwl3945_priv *priv)
{
int index;
- u8 blink_rate;
+ u64 current_tpt = priv->rxtxpackets;
+ s64 tpt = current_tpt - priv->led_tpt;
- if (priv->rxtxpackets < IWL_LED_THRESHOLD)
- index = 10;
- else {
- for (index = 0; index < IWL_MAX_BLINK_TBL; index++) {
- if (priv->rxtxpackets > (blink_tbl[index].brightness *
- IWL_1MB_RATE))
- break;
- }
- }
- /* if 0 frame is transfered */
- if ((index == IWL_MAX_BLINK_TBL) || !priv->allow_blinking)
- blink_rate = IWL_LED_SOLID;
+ if (tpt < 0)
+ tpt = -tpt;
+ priv->led_tpt = current_tpt;
+
+ if (!priv->allow_blinking)
+ index = IWL_MAX_BLINK_TBL;
else
- blink_rate = blink_tbl[index].on_time;
-
- return blink_rate;
+ for (index = 0; index < IWL_MAX_BLINK_TBL; index++)
+ if (tpt > (blink_tbl[index].brightness * IWL_1MB_RATE))
+ break;
+ return index;
}
static inline int is_rf_kill(struct iwl3945_priv *priv)
@@ -285,7 +267,7 @@
*/
void iwl3945_led_background(struct iwl3945_priv *priv)
{
- u8 blink_rate;
+ u8 blink_idx;
if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
priv->last_blink_time = 0;
@@ -298,9 +280,10 @@
if (!priv->allow_blinking) {
priv->last_blink_time = 0;
- if (priv->last_blink_rate != IWL_LED_SOLID) {
- priv->last_blink_rate = IWL_LED_SOLID;
- iwl3945_led_on(priv, IWL_LED_LINK);
+ if (priv->last_blink_rate != IWL_SOLID_BLINK_IDX) {
+ priv->last_blink_rate = IWL_SOLID_BLINK_IDX;
+ iwl3945_led_pattern(priv, IWL_LED_LINK,
+ IWL_SOLID_BLINK_IDX);
}
return;
}
@@ -309,21 +292,14 @@
msecs_to_jiffies(1000)))
return;
- blink_rate = get_blink_rate(priv);
+ blink_idx = get_blink_rate(priv);
/* call only if blink rate change */
- if (blink_rate != priv->last_blink_rate) {
- if (blink_rate != IWL_LED_SOLID) {
- priv->last_blink_time = jiffies +
- msecs_to_jiffies(1000);
- iwl3945_led_not_solid(priv, IWL_LED_LINK, blink_rate);
- } else {
- priv->last_blink_time = 0;
- iwl3945_led_on(priv, IWL_LED_LINK);
- }
- }
+ if (blink_idx != priv->last_blink_rate)
+ iwl3945_led_pattern(priv, IWL_LED_LINK, blink_idx);
- priv->last_blink_rate = blink_rate;
+ priv->last_blink_time = jiffies;
+ priv->last_blink_rate = blink_idx;
priv->rxtxpackets = 0;
}
@@ -337,6 +313,7 @@
priv->last_blink_rate = 0;
priv->rxtxpackets = 0;
+ priv->led_tpt = 0;
priv->last_blink_time = 0;
priv->allow_blinking = 0;
@@ -344,8 +321,8 @@
snprintf(name, sizeof(name), "iwl-%s:radio",
wiphy_name(priv->hw->wiphy));
- priv->led[IWL_LED_TRG_RADIO].led_on = iwl3945_led_on_reg;
- priv->led[IWL_LED_TRG_RADIO].led_off = iwl3945_led_off_reg;
+ priv->led[IWL_LED_TRG_RADIO].led_on = iwl3945_led_on;
+ priv->led[IWL_LED_TRG_RADIO].led_off = iwl3945_led_off;
priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL;
ret = iwl3945_led_register_led(priv,
@@ -364,8 +341,8 @@
IWL_LED_TRG_ASSOC, 0,
name, trigger);
/* for assoc always turn led on */
- priv->led[IWL_LED_TRG_ASSOC].led_on = iwl3945_led_on_reg;
- priv->led[IWL_LED_TRG_ASSOC].led_off = iwl3945_led_on_reg;
+ priv->led[IWL_LED_TRG_ASSOC].led_on = iwl3945_led_on;
+ priv->led[IWL_LED_TRG_ASSOC].led_off = iwl3945_led_on;
priv->led[IWL_LED_TRG_ASSOC].led_pattern = NULL;
if (ret)
@@ -391,6 +368,7 @@
trigger = ieee80211_get_tx_led_name(priv->hw);
snprintf(name, sizeof(name), "iwl-%s:TX",
wiphy_name(priv->hw->wiphy));
+
ret = iwl3945_led_register_led(priv,
&priv->led[IWL_LED_TRG_TX],
IWL_LED_TRG_TX, 0,
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.h b/drivers/net/wireless/iwlwifi/iwl-3945-led.h
index b1d2f6b..47b7e0b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-led.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.h
@@ -54,7 +54,7 @@
int (*led_on) (struct iwl3945_priv *priv, int led_id);
int (*led_off) (struct iwl3945_priv *priv, int led_id);
int (*led_pattern) (struct iwl3945_priv *priv, int led_id,
- enum led_brightness brightness);
+ unsigned int idx);
enum led_type type;
unsigned int registered;
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 94e177a..c2a7678 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -514,6 +514,23 @@
}
#endif
+/* This is necessary only for a number of statistics, see the caller. */
+static int iwl3945_is_network_packet(struct iwl3945_priv *priv,
+ struct ieee80211_hdr *header)
+{
+ /* Filter incoming packets to determine if they are targeted toward
+ * this network, discarding packets coming from ourselves */
+ switch (priv->iw_mode) {
+ case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source | BSSID */
+ /* packets to our IBSS update information */
+ return !compare_ether_addr(header->addr3, priv->bssid);
+ case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */
+ /* packets to our IBSS update information */
+ return !compare_ether_addr(header->addr2, priv->bssid);
+ default:
+ return 1;
+ }
+}
static void iwl3945_add_radiotap(struct iwl3945_priv *priv,
struct sk_buff *skb,
@@ -608,12 +625,12 @@
stats->flag |= RX_FLAG_RADIOTAP;
}
-static void iwl3945_handle_data_packet(struct iwl3945_priv *priv, int is_data,
+static void iwl3945_pass_packet_to_mac80211(struct iwl3945_priv *priv,
struct iwl3945_rx_mem_buffer *rxb,
struct ieee80211_rx_status *stats)
{
- struct ieee80211_hdr *hdr;
struct iwl3945_rx_packet *pkt = (struct iwl3945_rx_packet *)rxb->skb->data;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IWL_RX_DATA(pkt);
struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
short len = le16_to_cpu(rx_hdr->len);
@@ -635,8 +652,6 @@
/* Set the size of the skb to the size of the frame */
skb_put(rxb->skb, le16_to_cpu(rx_hdr->len));
- hdr = (void *)rxb->skb->data;
-
if (iwl3945_param_hwcrypto)
iwl3945_set_decrypted_flag(priv, rxb->skb,
le32_to_cpu(rx_end->status), stats);
@@ -645,7 +660,7 @@
iwl3945_add_radiotap(priv, rxb->skb, rx_hdr, stats);
#ifdef CONFIG_IWL3945_LEDS
- if (is_data)
+ if (ieee80211_is_data(hdr->frame_control))
priv->rxtxpackets += len;
#endif
ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
@@ -694,7 +709,7 @@
}
if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
- iwl3945_handle_data_packet(priv, 1, rxb, &rx_status);
+ iwl3945_pass_packet_to_mac80211(priv, rxb, &rx_status);
return;
}
@@ -842,26 +857,11 @@
}
}
- iwl3945_handle_data_packet(priv, 0, rxb, &rx_status);
+ case IEEE80211_FTYPE_DATA:
+ /* fall through */
+ default:
+ iwl3945_pass_packet_to_mac80211(priv, rxb, &rx_status);
break;
-
- case IEEE80211_FTYPE_CTL:
- break;
-
- case IEEE80211_FTYPE_DATA: {
- DECLARE_MAC_BUF(mac1);
- DECLARE_MAC_BUF(mac2);
- DECLARE_MAC_BUF(mac3);
-
- if (unlikely(iwl3945_is_duplicate_packet(priv, header)))
- IWL_DEBUG_DROP("Dropping (dup): %s, %s, %s\n",
- print_mac(mac1, header->addr1),
- print_mac(mac2, header->addr2),
- print_mac(mac3, header->addr3));
- else
- iwl3945_handle_data_packet(priv, 1, rxb, &rx_status);
- break;
- }
}
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
index 9c0a09e..fa81ba1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -510,8 +510,6 @@
u8 data[0]; /* data in same order as "size" elements */
};
-#define IWL_IBSS_MAC_HASH_SIZE 32
-
struct iwl3945_ibss_seq {
u8 mac[ETH_ALEN];
u16 seq_num;
@@ -569,17 +567,8 @@
struct iwl3945_addsta_cmd *sta, u8 flags);
extern u8 iwl3945_add_station(struct iwl3945_priv *priv, const u8 *bssid,
int is_ap, u8 flags);
-extern int iwl3945_is_network_packet(struct iwl3945_priv *priv,
- struct ieee80211_hdr *header);
extern int iwl3945_power_init_handle(struct iwl3945_priv *priv);
extern int iwl3945_eeprom_init(struct iwl3945_priv *priv);
-extern void iwl3945_handle_data_packet_monitor(struct iwl3945_priv *priv,
- struct iwl3945_rx_mem_buffer *rxb,
- void *data, short len,
- struct ieee80211_rx_status *stats,
- u16 phy_flags);
-extern int iwl3945_is_duplicate_packet(struct iwl3945_priv *priv,
- struct ieee80211_hdr *header);
extern int iwl3945_rx_queue_alloc(struct iwl3945_priv *priv);
extern void iwl3945_rx_queue_reset(struct iwl3945_priv *priv,
struct iwl3945_rx_queue *rxq);
@@ -805,6 +794,7 @@
u8 last_blink_rate;
u8 allow_blinking;
unsigned int rxtxpackets;
+ u64 led_tpt;
#endif
@@ -859,14 +849,6 @@
u32 last_beacon_time;
u64 last_tsf;
- /* Duplicate packet detection */
- u16 last_seq_num;
- u16 last_frag_num;
- unsigned long last_packet_time;
-
- /* Hash table for finding stations in IBSS network */
- struct list_head ibss_mac_hash[IWL_IBSS_MAC_HASH_SIZE];
-
/* eeprom */
struct iwl3945_eeprom eeprom;
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
index 10f630e..fce950f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
@@ -819,6 +819,7 @@
#define IWL49_NUM_FIFOS 7
#define IWL49_CMD_FIFO_NUM 4
#define IWL49_NUM_QUEUES 16
+#define IWL49_NUM_AMPDU_QUEUES 8
/**
* struct iwl_tfd_frame_data
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
index c7ebb3b..3ccb84a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
@@ -2265,9 +2265,7 @@
/* as default allow aggregation for all tids */
lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID;
-#ifdef CONFIG_MAC80211_DEBUGFS
lq_sta->drv = priv;
-#endif
rs_initialize_lq(priv, conf, sta);
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 04365b3..9afecb8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -49,9 +49,17 @@
static int iwl4965_send_tx_power(struct iwl_priv *priv);
static int iwl4965_hw_get_temperature(const struct iwl_priv *priv);
+/* Change firmware file name, using "-" and incrementing number,
+ * *only* when uCode interface or architecture changes so that it
+ * is not compatible with earlier drivers.
+ * This number will also appear in << 8 position of 1st dword of uCode file */
+#define IWL4965_UCODE_API "-2"
+
+
/* module parameters */
static struct iwl_mod_params iwl4965_mod_params = {
.num_of_queues = IWL49_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL49_NUM_AMPDU_QUEUES,
.enable_qos = 1,
.amsdu_size_8K = 1,
.restart_fw = 1,
@@ -642,6 +650,18 @@
data->beacon_count = 0;
}
+static void iwl4965_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
+ __le32 *tx_flags)
+{
+ if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
+ *tx_flags |= TX_CMD_FLG_RTS_MSK;
+ *tx_flags &= ~TX_CMD_FLG_CTS_MSK;
+ } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
+ *tx_flags &= ~TX_CMD_FLG_RTS_MSK;
+ *tx_flags |= TX_CMD_FLG_CTS_MSK;
+ }
+}
+
static void iwl4965_bg_txpower_work(struct work_struct *work)
{
struct iwl_priv *priv = container_of(work, struct iwl_priv,
@@ -1931,9 +1951,11 @@
{
int ret = 0;
- if (IWL49_FIRST_AMPDU_QUEUE > txq_id) {
- IWL_WARNING("queue number too small: %d, must be > %d\n",
- txq_id, IWL49_FIRST_AMPDU_QUEUE);
+ if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) ||
+ (IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES <= txq_id)) {
+ IWL_WARNING("queue number out of range: %d, must be %d to %d\n",
+ txq_id, IWL49_FIRST_AMPDU_QUEUE,
+ IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES - 1);
return -EINVAL;
}
@@ -2000,9 +2022,13 @@
int ret;
u16 ra_tid;
- if (IWL49_FIRST_AMPDU_QUEUE > txq_id)
- IWL_WARNING("queue number too small: %d, must be > %d\n",
- txq_id, IWL49_FIRST_AMPDU_QUEUE);
+ if ((IWL49_FIRST_AMPDU_QUEUE > txq_id) ||
+ (IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES <= txq_id)) {
+ IWL_WARNING("queue number out of range: %d, must be %d to %d\n",
+ txq_id, IWL49_FIRST_AMPDU_QUEUE,
+ IWL49_FIRST_AMPDU_QUEUE + IWL49_NUM_AMPDU_QUEUES - 1);
+ return -EINVAL;
+ }
ra_tid = BUILD_RAxTID(sta_id, tid);
@@ -2372,6 +2398,7 @@
.build_addsta_hcmd = iwl4965_build_addsta_hcmd,
.chain_noise_reset = iwl4965_chain_noise_reset,
.gain_computation = iwl4965_gain_computation,
+ .rts_tx_cmd_flag = iwl4965_rts_tx_cmd_flag,
};
static struct iwl_lib_ops iwl4965_lib = {
@@ -2434,6 +2461,9 @@
.mod_params = &iwl4965_mod_params,
};
+/* Module firmware */
+MODULE_FIRMWARE("iwlwifi-4965" IWL4965_UCODE_API ".ucode");
+
module_param_named(antenna, iwl4965_mod_params.antenna, int, 0444);
MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
module_param_named(disable, iwl4965_mod_params.disable, int, 0444);
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
index 4efe0c0..17d4f31 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
@@ -81,6 +81,7 @@
#define IWL50_QUEUE_SIZE 256
#define IWL50_CMD_FIFO_NUM 7
#define IWL50_NUM_QUEUES 20
+#define IWL50_NUM_AMPDU_QUEUES 10
#define IWL50_FIRST_AMPDU_QUEUE 10
#define IWL_sta_id_POS 12
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index 717db0d..878d619 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -370,6 +370,16 @@
}
}
+static void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
+ __le32 *tx_flags)
+{
+ if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
+ (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT))
+ *tx_flags |= TX_CMD_FLG_RTS_CTS_MSK;
+ else
+ *tx_flags &= ~TX_CMD_FLG_RTS_CTS_MSK;
+}
+
static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
.min_nrg_cck = 95,
.max_nrg_cck = 0,
@@ -1006,9 +1016,13 @@
int ret;
u16 ra_tid;
- if (IWL50_FIRST_AMPDU_QUEUE > txq_id)
- IWL_WARNING("queue number too small: %d, must be > %d\n",
- txq_id, IWL50_FIRST_AMPDU_QUEUE);
+ if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) ||
+ (IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES <= txq_id)) {
+ IWL_WARNING("queue number out of range: %d, must be %d to %d\n",
+ txq_id, IWL50_FIRST_AMPDU_QUEUE,
+ IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES - 1);
+ return -EINVAL;
+ }
ra_tid = BUILD_RAxTID(sta_id, tid);
@@ -1067,9 +1081,11 @@
{
int ret;
- if (IWL50_FIRST_AMPDU_QUEUE > txq_id) {
- IWL_WARNING("queue number too small: %d, must be > %d\n",
- txq_id, IWL50_FIRST_AMPDU_QUEUE);
+ if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) ||
+ (IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES <= txq_id)) {
+ IWL_WARNING("queue number out of range: %d, must be %d to %d\n",
+ txq_id, IWL50_FIRST_AMPDU_QUEUE,
+ IWL50_FIRST_AMPDU_QUEUE + IWL50_NUM_AMPDU_QUEUES - 1);
return -EINVAL;
}
@@ -1437,6 +1453,7 @@
.build_addsta_hcmd = iwl5000_build_addsta_hcmd,
.gain_computation = iwl5000_gain_computation,
.chain_noise_reset = iwl5000_chain_noise_reset,
+ .rts_tx_cmd_flag = iwl5000_rts_tx_cmd_flag,
};
static struct iwl_lib_ops iwl5000_lib = {
@@ -1490,6 +1507,7 @@
static struct iwl_mod_params iwl50_mod_params = {
.num_of_queues = IWL50_NUM_QUEUES,
+ .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
.enable_qos = 1,
.amsdu_size_8K = 1,
.restart_fw = 1,
@@ -1506,6 +1524,24 @@
.mod_params = &iwl50_mod_params,
};
+struct iwl_cfg iwl5100_bg_cfg = {
+ .name = "5100BG",
+ .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode",
+ .sku = IWL_SKU_G,
+ .ops = &iwl5000_ops,
+ .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+ .mod_params = &iwl50_mod_params,
+};
+
+struct iwl_cfg iwl5100_abg_cfg = {
+ .name = "5100ABG",
+ .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode",
+ .sku = IWL_SKU_A|IWL_SKU_G,
+ .ops = &iwl5000_ops,
+ .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+ .mod_params = &iwl50_mod_params,
+};
+
struct iwl_cfg iwl5100_agn_cfg = {
.name = "5100AGN",
.fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode",
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index fe05d60..e9bb1de 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -556,6 +556,8 @@
#define RXON_FLG_CHANNEL_MODE_MSK __constant_cpu_to_le32(0x3 << 25)
#define RXON_FLG_CHANNEL_MODE_PURE_40_MSK __constant_cpu_to_le32(0x1 << 25)
#define RXON_FLG_CHANNEL_MODE_MIXED_MSK __constant_cpu_to_le32(0x2 << 25)
+/* CTS to self (if spec allows) flag */
+#define RXON_FLG_SELF_CTS_EN __constant_cpu_to_le32(0x1<<30)
/* rx_config filter flags */
/* accept all data frames */
@@ -723,7 +725,7 @@
* transmission retry. Device uses cw_max as a bit mask, ANDed with new CW
* value, to cap the CW value.
*/
-struct iwl4965_ac_qos {
+struct iwl_ac_qos {
__le16 cw_min;
__le16 cw_max;
u8 aifsn;
@@ -745,9 +747,9 @@
* This command sets up timings for each of the 4 prioritized EDCA Tx FIFOs
* 0: Background, 1: Best Effort, 2: Video, 3: Voice.
*/
-struct iwl4965_qosparam_cmd {
+struct iwl_qosparam_cmd {
__le32 qos_flags;
- struct iwl4965_ac_qos ac[AC_NUM];
+ struct iwl_ac_qos ac[AC_NUM];
} __attribute__ ((packed));
/******************************************************************************
@@ -1139,6 +1141,11 @@
/* REPLY_TX Tx flags field */
+/* 1: Use RTS/CTS protocol or CTS-to-self if spec alows it
+ * before this frame. if CTS-to-self required check
+ * RXON_FLG_SELF_CTS_EN status. */
+#define TX_CMD_FLG_RTS_CTS_MSK __constant_cpu_to_le32(1 << 0)
+
/* 1: Use Request-To-Send protocol before this frame.
* Mutually exclusive vs. TX_CMD_FLG_CTS_MSK. */
#define TX_CMD_FLG_RTS_MSK __constant_cpu_to_le32(1 << 1)
@@ -2092,6 +2099,9 @@
*
*****************************************************************************/
+#define SCAN_CHANNEL_TYPE_PASSIVE __constant_cpu_to_le32(0)
+#define SCAN_CHANNEL_TYPE_ACTIVE __constant_cpu_to_le32(1)
+
/**
* struct iwl_scan_channel - entry in REPLY_SCAN_CMD channel table
*
@@ -2115,12 +2125,12 @@
/*
* type is defined as:
* 0:0 1 = active, 0 = passive
- * 1:4 SSID direct bit map; if a bit is set, then corresponding
+ * 1:20 SSID direct bit map; if a bit is set, then corresponding
* SSID IE is transmitted in probe request.
- * 5:7 reserved
+ * 21:31 reserved
*/
- u8 type;
- u8 channel; /* band is selected by iwl4965_scan_cmd "flags" field */
+ __le32 type;
+ __le16 channel; /* band is selected by iwl_scan_cmd "flags" field */
u8 tx_gain; /* gain for analog radio */
u8 dsp_atten; /* gain for DSP */
__le16 active_dwell; /* in 1024-uSec TU (time units), typ 5-50 */
@@ -2140,9 +2150,9 @@
u8 ssid[32];
} __attribute__ ((packed));
-#define PROBE_OPTION_MAX 0x4
+#define PROBE_OPTION_MAX 0x14
#define TX_CMD_LIFE_TIME_INFINITE __constant_cpu_to_le32(0xFFFFFFFF)
-#define IWL_GOOD_CRC_TH __constant_cpu_to_le16(1)
+#define IWL_GOOD_CRC_TH __constant_cpu_to_le16(1)
#define IWL_MAX_SCAN_SIZE 1024
/*
@@ -2919,7 +2929,7 @@
* For each of 3 possible LEDs (Activity/Link/Tech, selected by "id" field),
* this command turns it on or off, or sets up a periodic blinking cycle.
*/
-struct iwl4965_led_cmd {
+struct iwl_led_cmd {
__le32 interval; /* "interval" in uSec */
u8 id; /* 1: Activity, 2: Link, 3: Tech */
u8 off; /* # intervals off while blinking;
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index eee220c..a44188b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -825,7 +825,7 @@
hw->queues = 4;
/* queues to support 11n aggregation */
if (priv->cfg->sku & IWL_SKU_N)
- hw->ampdu_queues = 12;
+ hw->ampdu_queues = priv->cfg->mod_params->num_of_ampdu_queues;
hw->conf.beacon_int = 100;
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index dafd62c..db66114 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -70,7 +70,7 @@
struct iwl_cmd;
-#define IWLWIFI_VERSION "1.2.26k"
+#define IWLWIFI_VERSION "1.3.27k"
#define DRV_COPYRIGHT "Copyright(c) 2003-2008 Intel Corporation"
#define IWL_PCI_DEVICE(dev, subdev, cfg) \
@@ -93,6 +93,8 @@
u16 min_average_noise_antennat_i,
u32 min_average_noise);
void (*chain_noise_reset)(struct iwl_priv *priv);
+ void (*rts_tx_cmd_flag)(struct ieee80211_tx_info *info,
+ __le32 *tx_flags);
};
struct iwl_lib_ops {
@@ -157,6 +159,7 @@
int debug; /* def: 0 = minimal debug log messages */
int disable_hw_scan; /* def: 0 = use h/w scan */
int num_of_queues; /* def: HW dependent */
+ int num_of_ampdu_queues;/* def: HW dependent */
int enable_qos; /* def: 1 = use quality of service */
int disable_11n; /* def: 0 = disable 11n capabilities */
int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index c8d3d97..4d789e3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -51,12 +51,8 @@
extern struct iwl_cfg iwl5300_agn_cfg;
extern struct iwl_cfg iwl5100_agn_cfg;
extern struct iwl_cfg iwl5350_agn_cfg;
-
-/* Change firmware file name, using "-" and incrementing number,
- * *only* when uCode interface or architecture changes so that it
- * is not compatible with earlier drivers.
- * This number will also appear in << 8 position of 1st dword of uCode file */
-#define IWL4965_UCODE_API "-1"
+extern struct iwl_cfg iwl5100_bg_cfg;
+extern struct iwl_cfg iwl5100_abg_cfg;
/* CT-KILL constants */
#define CT_KILL_THRESHOLD 110 /* in Celsius */
@@ -280,7 +276,7 @@
struct iwl_cmd_header hdr; /* uCode API */
union {
struct iwl_addsta_cmd addsta;
- struct iwl4965_led_cmd led;
+ struct iwl_led_cmd led;
u32 flags;
u8 val8;
u16 val16;
@@ -288,7 +284,7 @@
struct iwl4965_bt_cmd bt;
struct iwl4965_rxon_time_cmd rxon_time;
struct iwl4965_powertable_cmd powertable;
- struct iwl4965_qosparam_cmd qosparam;
+ struct iwl_qosparam_cmd qosparam;
struct iwl_tx_cmd tx;
struct iwl4965_tx_beacon_cmd tx_beacon;
struct iwl4965_rxon_assoc_cmd rxon_assoc;
@@ -433,7 +429,7 @@
u8 non_GF_STA_present;
};
-union iwl4965_qos_capabity {
+union iwl_qos_capabity {
struct {
u8 edca_count:4; /* bit 0-3 */
u8 q_ack:1; /* bit 4 */
@@ -454,11 +450,11 @@
};
/* QoS structures */
-struct iwl4965_qos_info {
+struct iwl_qos_info {
int qos_enable;
int qos_active;
- union iwl4965_qos_capabity qos_cap;
- struct iwl4965_qosparam_cmd def_qos_parm;
+ union iwl_qos_capabity qos_cap;
+ struct iwl_qosparam_cmd def_qos_parm;
};
#define STA_PS_STATUS_WAKE 0
@@ -490,8 +486,6 @@
u8 data[0]; /* data in same order as "size" elements */
};
-#define IWL_IBSS_MAC_HASH_SIZE 32
-
struct iwl4965_ibss_seq {
u8 mac[ETH_ALEN];
u16 seq_num;
@@ -933,7 +927,7 @@
#endif
#ifdef CONFIG_IWLWIFI_LEDS
- struct iwl4965_led led[IWL_LED_TRG_MAX];
+ struct iwl_led led[IWL_LED_TRG_MAX];
unsigned long last_blink_time;
u8 last_blink_rate;
u8 allow_blinking;
@@ -1042,7 +1036,7 @@
u16 assoc_capability;
u8 ps_mode;
- struct iwl4965_qos_info qos_data;
+ struct iwl_qos_info qos_data;
struct workqueue_struct *workqueue;
@@ -1065,7 +1059,6 @@
struct delayed_work init_alive_start;
struct delayed_work alive_start;
struct delayed_work scan_check;
- struct delayed_work post_associate;
/* TX Power */
s8 tx_power_user_lmt;
s8 tx_power_channel_lmt;
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c
index aa6ad18..899d7a2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-led.c
@@ -44,14 +44,21 @@
#include "iwl-io.h"
#include "iwl-helpers.h"
-#define IWL_1MB_RATE (128 * 1024)
-#define IWL_LED_THRESHOLD (16)
-#define IWL_MAX_BLINK_TBL (10)
+#ifdef CONFIG_IWLWIFI_DEBUG
+static const char *led_type_str[] = {
+ __stringify(IWL_LED_TRG_TX),
+ __stringify(IWL_LED_TRG_RX),
+ __stringify(IWL_LED_TRG_ASSOC),
+ __stringify(IWL_LED_TRG_RADIO),
+ NULL
+};
+#endif /* CONFIG_IWLWIFI_DEBUG */
+
static const struct {
u16 tpt;
u8 on_time;
- u8 of_time;
+ u8 off_time;
} blink_tbl[] =
{
{300, 25, 25},
@@ -63,26 +70,31 @@
{15, 95, 95 },
{10, 110, 110},
{5, 130, 130},
- {0, 167, 167}
+ {0, 167, 167},
+/* SOLID_ON */
+ {-1, IWL_LED_SOLID, 0}
};
-static int iwl_led_cmd_callback(struct iwl_priv *priv,
- struct iwl_cmd *cmd, struct sk_buff *skb)
+#define IWL_1MB_RATE (128 * 1024)
+#define IWL_LED_THRESHOLD (16)
+#define IWL_MAX_BLINK_TBL (ARRAY_SIZE(blink_tbl) - 1) /* exclude SOLID_ON */
+#define IWL_SOLID_BLINK_IDX (ARRAY_SIZE(blink_tbl) - 1)
+
+/* [0-256] -> [0..8] FIXME: we need [0..10] */
+static inline int iwl_brightness_to_idx(enum led_brightness brightness)
{
- return 1;
+ return fls(0x000000FF & (u32)brightness);
}
-
/* Send led command */
-static int iwl_send_led_cmd(struct iwl_priv *priv,
- struct iwl4965_led_cmd *led_cmd)
+static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
{
struct iwl_host_cmd cmd = {
.id = REPLY_LEDS_CMD,
- .len = sizeof(struct iwl4965_led_cmd),
+ .len = sizeof(struct iwl_led_cmd),
.data = led_cmd,
.meta.flags = CMD_ASYNC,
- .meta.u.callback = iwl_led_cmd_callback
+ .meta.u.callback = NULL,
};
u32 reg;
@@ -93,33 +105,20 @@
return iwl_send_cmd(priv, &cmd);
}
-
-/* Set led on command */
-static int iwl4965_led_on(struct iwl_priv *priv, int led_id)
-{
- struct iwl4965_led_cmd led_cmd = {
- .id = led_id,
- .on = IWL_LED_SOLID,
- .off = 0,
- .interval = IWL_DEF_LED_INTRVL
- };
- return iwl_send_led_cmd(priv, &led_cmd);
-}
-
-/* Set led on command */
+/* Set led pattern command */
static int iwl4965_led_pattern(struct iwl_priv *priv, int led_id,
- enum led_brightness brightness)
+ unsigned int idx)
{
- struct iwl4965_led_cmd led_cmd = {
+ struct iwl_led_cmd led_cmd = {
.id = led_id,
- .on = brightness,
- .off = brightness,
.interval = IWL_DEF_LED_INTRVL
};
- if (brightness == LED_FULL) {
- led_cmd.on = IWL_LED_SOLID;
- led_cmd.off = 0;
- }
+
+ BUG_ON(idx > IWL_MAX_BLINK_TBL);
+
+ led_cmd.on = blink_tbl[idx].on_time;
+ led_cmd.off = blink_tbl[idx].off_time;
+
return iwl_send_led_cmd(priv, &led_cmd);
}
@@ -132,10 +131,22 @@
}
#if 0
+/* Set led on command */
+static int iwl4965_led_on(struct iwl_priv *priv, int led_id)
+{
+ struct iwl_led_cmd led_cmd = {
+ .id = led_id,
+ .on = IWL_LED_SOLID,
+ .off = 0,
+ .interval = IWL_DEF_LED_INTRVL
+ };
+ return iwl_send_led_cmd(priv, &led_cmd);
+}
+
/* Set led off command */
int iwl4965_led_off(struct iwl_priv *priv, int led_id)
{
- struct iwl4965_led_cmd led_cmd = {
+ struct iwl_led_cmd led_cmd = {
.id = led_id,
.on = 0,
.off = 0,
@@ -155,25 +166,10 @@
return 0;
}
-/* Set led blink command */
-static int iwl4965_led_not_solid(struct iwl_priv *priv, int led_id,
- u8 brightness)
-{
- struct iwl4965_led_cmd led_cmd = {
- .id = led_id,
- .on = brightness,
- .off = brightness,
- .interval = IWL_DEF_LED_INTRVL
- };
-
- return iwl_send_led_cmd(priv, &led_cmd);
-}
-
-
/*
* brightness call back function for Tx/Rx LED
*/
-static int iwl4965_led_associated(struct iwl_priv *priv, int led_id)
+static int iwl_led_associated(struct iwl_priv *priv, int led_id)
{
if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
!test_bit(STATUS_READY, &priv->status))
@@ -189,16 +185,18 @@
/*
* brightness call back for association and radio
*/
-static void iwl4965_led_brightness_set(struct led_classdev *led_cdev,
+static void iwl_led_brightness_set(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
- struct iwl4965_led *led = container_of(led_cdev,
- struct iwl4965_led, led_dev);
+ struct iwl_led *led = container_of(led_cdev, struct iwl_led, led_dev);
struct iwl_priv *priv = led->priv;
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
+
+ IWL_DEBUG_LED("Led type = %s brightness = %d\n",
+ led_type_str[led->type], brightness);
switch (brightness) {
case LED_FULL:
if (led->type == IWL_LED_TRG_ASSOC)
@@ -215,8 +213,10 @@
led->led_off(priv, IWL_LED_LINK);
break;
default:
- if (led->led_pattern)
- led->led_pattern(priv, IWL_LED_LINK, brightness);
+ if (led->led_pattern) {
+ int idx = iwl_brightness_to_idx(brightness);
+ led->led_pattern(priv, IWL_LED_LINK, idx);
+ }
break;
}
}
@@ -226,8 +226,7 @@
/*
* Register led class with the system
*/
-static int iwl_leds_register_led(struct iwl_priv *priv,
- struct iwl4965_led *led,
+static int iwl_leds_register_led(struct iwl_priv *priv, struct iwl_led *led,
enum led_type type, u8 set_led,
const char *name, char *trigger)
{
@@ -235,7 +234,7 @@
int ret;
led->led_dev.name = name;
- led->led_dev.brightness_set = iwl4965_led_brightness_set;
+ led->led_dev.brightness_set = iwl_led_brightness_set;
led->led_dev.default_trigger = trigger;
led->priv = priv;
@@ -259,32 +258,28 @@
/*
* calculate blink rate according to last 2 sec Tx/Rx activities
*/
-static inline u8 get_blink_rate(struct iwl_priv *priv)
+static int iwl_get_blink_rate(struct iwl_priv *priv)
{
int i;
- u8 blink_rate;
- u64 current_tpt = priv->tx_stats[2].bytes + priv->rx_stats[2].bytes;
+ u64 current_tpt = priv->tx_stats[2].bytes;
+ /* FIXME: + priv->rx_stats[2].bytes; */
s64 tpt = current_tpt - priv->led_tpt;
if (tpt < 0) /* wrapparound */
tpt = -tpt;
+ IWL_DEBUG_LED("tpt %lld current_tpt %lld\n", tpt, current_tpt);
priv->led_tpt = current_tpt;
- if (tpt < IWL_LED_THRESHOLD) {
+ if (!priv->allow_blinking)
i = IWL_MAX_BLINK_TBL;
- } else {
+ else
for (i = 0; i < IWL_MAX_BLINK_TBL; i++)
if (tpt > (blink_tbl[i].tpt * IWL_1MB_RATE))
break;
- }
- /* if 0 frame is transfered */
- if ((i == IWL_MAX_BLINK_TBL) || !priv->allow_blinking)
- blink_rate = IWL_LED_SOLID;
- else
- blink_rate = blink_tbl[i].on_time;
- return blink_rate;
+ IWL_DEBUG_LED("LED BLINK IDX=%d", i);
+ return i;
}
static inline int is_rf_kill(struct iwl_priv *priv)
@@ -300,7 +295,7 @@
*/
void iwl_leds_background(struct iwl_priv *priv)
{
- u8 blink_rate;
+ u8 blink_idx;
if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
priv->last_blink_time = 0;
@@ -313,9 +308,10 @@
if (!priv->allow_blinking) {
priv->last_blink_time = 0;
- if (priv->last_blink_rate != IWL_LED_SOLID) {
- priv->last_blink_rate = IWL_LED_SOLID;
- iwl4965_led_on(priv, IWL_LED_LINK);
+ if (priv->last_blink_rate != IWL_SOLID_BLINK_IDX) {
+ priv->last_blink_rate = IWL_SOLID_BLINK_IDX;
+ iwl4965_led_pattern(priv, IWL_LED_LINK,
+ IWL_SOLID_BLINK_IDX);
}
return;
}
@@ -324,21 +320,14 @@
msecs_to_jiffies(1000)))
return;
- blink_rate = get_blink_rate(priv);
+ blink_idx = iwl_get_blink_rate(priv);
/* call only if blink rate change */
- if (blink_rate != priv->last_blink_rate) {
- if (blink_rate != IWL_LED_SOLID) {
- priv->last_blink_time = jiffies +
- msecs_to_jiffies(1000);
- iwl4965_led_not_solid(priv, IWL_LED_LINK, blink_rate);
- } else {
- priv->last_blink_time = 0;
- iwl4965_led_on(priv, IWL_LED_LINK);
- }
- }
+ if (blink_idx != priv->last_blink_rate)
+ iwl4965_led_pattern(priv, IWL_LED_LINK, blink_idx);
- priv->last_blink_rate = blink_rate;
+ priv->last_blink_time = jiffies;
+ priv->last_blink_rate = blink_idx;
}
EXPORT_SYMBOL(iwl_leds_background);
@@ -362,10 +351,8 @@
priv->led[IWL_LED_TRG_RADIO].led_off = iwl4965_led_off_reg;
priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL;
- ret = iwl_leds_register_led(priv,
- &priv->led[IWL_LED_TRG_RADIO],
- IWL_LED_TRG_RADIO, 1,
- name, trigger);
+ ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_RADIO],
+ IWL_LED_TRG_RADIO, 1, name, trigger);
if (ret)
goto exit_fail;
@@ -373,10 +360,9 @@
snprintf(name, sizeof(name), "iwl-%s:assoc",
wiphy_name(priv->hw->wiphy));
- ret = iwl_leds_register_led(priv,
- &priv->led[IWL_LED_TRG_ASSOC],
- IWL_LED_TRG_ASSOC, 0,
- name, trigger);
+ ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_ASSOC],
+ IWL_LED_TRG_ASSOC, 0, name, trigger);
+
/* for assoc always turn led on */
priv->led[IWL_LED_TRG_ASSOC].led_on = iwl4965_led_on_reg;
priv->led[IWL_LED_TRG_ASSOC].led_off = iwl4965_led_on_reg;
@@ -386,31 +372,26 @@
goto exit_fail;
trigger = ieee80211_get_rx_led_name(priv->hw);
- snprintf(name, sizeof(name), "iwl-%s:RX",
- wiphy_name(priv->hw->wiphy));
+ snprintf(name, sizeof(name), "iwl-%s:RX", wiphy_name(priv->hw->wiphy));
- ret = iwl_leds_register_led(priv,
- &priv->led[IWL_LED_TRG_RX],
- IWL_LED_TRG_RX, 0,
- name, trigger);
+ ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_RX],
+ IWL_LED_TRG_RX, 0, name, trigger);
- priv->led[IWL_LED_TRG_RX].led_on = iwl4965_led_associated;
- priv->led[IWL_LED_TRG_RX].led_off = iwl4965_led_associated;
+ priv->led[IWL_LED_TRG_RX].led_on = iwl_led_associated;
+ priv->led[IWL_LED_TRG_RX].led_off = iwl_led_associated;
priv->led[IWL_LED_TRG_RX].led_pattern = iwl4965_led_pattern;
if (ret)
goto exit_fail;
trigger = ieee80211_get_tx_led_name(priv->hw);
- snprintf(name, sizeof(name), "iwl-%s:TX",
- wiphy_name(priv->hw->wiphy));
- ret = iwl_leds_register_led(priv,
- &priv->led[IWL_LED_TRG_TX],
- IWL_LED_TRG_TX, 0,
- name, trigger);
- priv->led[IWL_LED_TRG_TX].led_on = iwl4965_led_associated;
- priv->led[IWL_LED_TRG_TX].led_off = iwl4965_led_associated;
+ snprintf(name, sizeof(name), "iwl-%s:TX", wiphy_name(priv->hw->wiphy));
+ ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_TX],
+ IWL_LED_TRG_TX, 0, name, trigger);
+
+ priv->led[IWL_LED_TRG_TX].led_on = iwl_led_associated;
+ priv->led[IWL_LED_TRG_TX].led_off = iwl_led_associated;
priv->led[IWL_LED_TRG_TX].led_pattern = iwl4965_led_pattern;
if (ret)
@@ -425,7 +406,7 @@
EXPORT_SYMBOL(iwl_leds_register);
/* unregister led class */
-static void iwl_leds_unregister_led(struct iwl4965_led *led, u8 set_led)
+static void iwl_leds_unregister_led(struct iwl_led *led, u8 set_led)
{
if (!led->registered)
return;
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h
index 5bb0412..1980ae5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.h
+++ b/drivers/net/wireless/iwlwifi/iwl-led.h
@@ -49,14 +49,13 @@
};
-struct iwl4965_led {
+struct iwl_led {
struct iwl_priv *priv;
struct led_classdev led_dev;
int (*led_on) (struct iwl_priv *priv, int led_id);
int (*led_off) (struct iwl_priv *priv, int led_id);
- int (*led_pattern) (struct iwl_priv *priv, int led_id,
- enum led_brightness brightness);
+ int (*led_pattern) (struct iwl_priv *priv, int led_id, unsigned int idx);
enum led_type type;
unsigned int registered;
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index 3e8500e..e2d9afb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -29,6 +29,7 @@
#include <linux/etherdevice.h>
#include <net/mac80211.h>
+#include <asm/unaligned.h>
#include "iwl-eeprom.h"
#include "iwl-dev.h"
#include "iwl-core.h"
@@ -829,23 +830,22 @@
iwl4965_rt->rt_hdr.it_pad = 0;
/* total header + data */
- put_unaligned(cpu_to_le16(sizeof(*iwl4965_rt)),
- &iwl4965_rt->rt_hdr.it_len);
+ put_unaligned_le16(sizeof(*iwl4965_rt), &iwl4965_rt->rt_hdr.it_len);
/* Indicate all the fields we add to the radiotap header */
- put_unaligned(cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) |
- (1 << IEEE80211_RADIOTAP_FLAGS) |
- (1 << IEEE80211_RADIOTAP_RATE) |
- (1 << IEEE80211_RADIOTAP_CHANNEL) |
- (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
- (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |
- (1 << IEEE80211_RADIOTAP_ANTENNA)),
- &iwl4965_rt->rt_hdr.it_present);
+ put_unaligned_le32((1 << IEEE80211_RADIOTAP_TSFT) |
+ (1 << IEEE80211_RADIOTAP_FLAGS) |
+ (1 << IEEE80211_RADIOTAP_RATE) |
+ (1 << IEEE80211_RADIOTAP_CHANNEL) |
+ (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
+ (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |
+ (1 << IEEE80211_RADIOTAP_ANTENNA),
+ &(iwl4965_rt->rt_hdr.it_present));
/* Zero the flags, we'll add to them as we go */
iwl4965_rt->rt_flags = 0;
- put_unaligned(cpu_to_le64(tsf), &iwl4965_rt->rt_tsf);
+ put_unaligned_le64(tsf, &iwl4965_rt->rt_tsf);
iwl4965_rt->rt_dbmsignal = signal;
iwl4965_rt->rt_dbmnoise = noise;
@@ -853,17 +853,14 @@
/* Convert the channel frequency and set the flags */
put_unaligned(cpu_to_le16(stats->freq), &iwl4965_rt->rt_channelMHz);
if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK))
- put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM |
- IEEE80211_CHAN_5GHZ),
- &iwl4965_rt->rt_chbitmask);
+ put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ,
+ &iwl4965_rt->rt_chbitmask);
else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK)
- put_unaligned(cpu_to_le16(IEEE80211_CHAN_CCK |
- IEEE80211_CHAN_2GHZ),
- &iwl4965_rt->rt_chbitmask);
+ put_unaligned_le16(IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ,
+ &iwl4965_rt->rt_chbitmask);
else /* 802.11g */
- put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM |
- IEEE80211_CHAN_2GHZ),
- &iwl4965_rt->rt_chbitmask);
+ put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ,
+ &iwl4965_rt->rt_chbitmask);
if (rate == -1)
iwl4965_rt->rt_rate = 0;
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index 5b420b4..efc750d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -38,8 +38,11 @@
/* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
* sending probe req. This should be set long enough to hear probe responses
* from more than one AP. */
-#define IWL_ACTIVE_DWELL_TIME_24 (20) /* all times in msec */
-#define IWL_ACTIVE_DWELL_TIME_52 (10)
+#define IWL_ACTIVE_DWELL_TIME_24 (30) /* all times in msec */
+#define IWL_ACTIVE_DWELL_TIME_52 (20)
+
+#define IWL_ACTIVE_DWELL_FACTOR_24GHZ (3)
+#define IWL_ACTIVE_DWELL_FACTOR_52GHZ (2)
/* For faster active scanning, scan will move to the next channel if fewer than
* PLCP_QUIET_THRESH packets are heard on this channel within
@@ -48,7 +51,7 @@
* no other traffic).
* Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */
#define IWL_PLCP_QUIET_THRESH __constant_cpu_to_le16(1) /* packets */
-#define IWL_ACTIVE_QUIET_TIME __constant_cpu_to_le16(5) /* msec */
+#define IWL_ACTIVE_QUIET_TIME __constant_cpu_to_le16(10) /* msec */
/* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel.
* Must be set longer than active dwell time.
@@ -58,10 +61,15 @@
#define IWL_PASSIVE_DWELL_BASE (100)
#define IWL_CHANNEL_TUNE_TIME 5
+#define IWL_SCAN_PROBE_MASK(n) cpu_to_le32((BIT(n) | (BIT(n) - BIT(1))))
+
+
static int scan_tx_ant[3] = {
RATE_MCS_ANT_A_MSK, RATE_MCS_ANT_B_MSK, RATE_MCS_ANT_C_MSK
};
+
+
static int iwl_is_empty_essid(const char *essid, int essid_len)
{
/* Single white space is for Linksys APs */
@@ -226,8 +234,9 @@
"(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n",
notif->channel,
notif->band ? "bg" : "a",
- notif->tsf_high,
- notif->tsf_low, notif->status, notif->beacon_timer);
+ le32_to_cpu(notif->tsf_high),
+ le32_to_cpu(notif->tsf_low),
+ notif->status, notif->beacon_timer);
}
/* Service SCAN_RESULTS_NOTIFICATION (0x83) */
@@ -332,19 +341,21 @@
EXPORT_SYMBOL(iwl_setup_rx_scan_handlers);
static inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv,
- enum ieee80211_band band)
+ enum ieee80211_band band,
+ u8 n_probes)
{
if (band == IEEE80211_BAND_5GHZ)
- return IWL_ACTIVE_DWELL_TIME_52;
+ return IWL_ACTIVE_DWELL_TIME_52 +
+ IWL_ACTIVE_DWELL_FACTOR_52GHZ * (n_probes + 1);
else
- return IWL_ACTIVE_DWELL_TIME_24;
+ return IWL_ACTIVE_DWELL_TIME_24 +
+ IWL_ACTIVE_DWELL_FACTOR_24GHZ * (n_probes + 1);
}
static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
- enum ieee80211_band band)
+ enum ieee80211_band band)
{
- u16 active = iwl_get_active_dwell_time(priv, band);
- u16 passive = (band != IEEE80211_BAND_5GHZ) ?
+ u16 passive = (band == IEEE80211_BAND_2GHZ) ?
IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52;
@@ -358,15 +369,12 @@
passive = (passive * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
}
- if (passive <= active)
- passive = active + 1;
-
return passive;
}
static int iwl_get_channels_for_scan(struct iwl_priv *priv,
enum ieee80211_band band,
- u8 is_active, u8 direct_mask,
+ u8 is_active, u8 n_probes,
struct iwl_scan_channel *scan_ch)
{
const struct ieee80211_channel *channels = NULL;
@@ -375,6 +383,7 @@
u16 passive_dwell = 0;
u16 active_dwell = 0;
int added, i;
+ u16 channel;
sband = iwl_get_hw_mode(priv, band);
if (!sband)
@@ -382,31 +391,35 @@
channels = sband->channels;
- active_dwell = iwl_get_active_dwell_time(priv, band);
+ active_dwell = iwl_get_active_dwell_time(priv, band, n_probes);
passive_dwell = iwl_get_passive_dwell_time(priv, band);
+ if (passive_dwell <= active_dwell)
+ passive_dwell = active_dwell + 1;
+
for (i = 0, added = 0; i < sband->n_channels; i++) {
if (channels[i].flags & IEEE80211_CHAN_DISABLED)
continue;
- scan_ch->channel =
+ channel =
ieee80211_frequency_to_channel(channels[i].center_freq);
+ scan_ch->channel = cpu_to_le16(channel);
- ch_info = iwl_get_channel_info(priv, band, scan_ch->channel);
+ ch_info = iwl_get_channel_info(priv, band, channel);
if (!is_channel_valid(ch_info)) {
IWL_DEBUG_SCAN("Channel %d is INVALID for this band.\n",
- scan_ch->channel);
+ channel);
continue;
}
if (!is_active || is_channel_passive(ch_info) ||
(channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN))
- scan_ch->type = 0;
+ scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
else
- scan_ch->type = 1;
+ scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;
- if (scan_ch->type & 1)
- scan_ch->type |= (direct_mask << 1);
+ if ((scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) && n_probes)
+ scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes);
scan_ch->active_dwell = cpu_to_le16(active_dwell);
scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
@@ -414,20 +427,20 @@
/* Set txpower levels to defaults */
scan_ch->dsp_atten = 110;
+ /* NOTE: if we were doing 6Mb OFDM for scans we'd use
+ * power level:
+ * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3;
+ */
if (band == IEEE80211_BAND_5GHZ)
scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
- else {
+ else
scan_ch->tx_gain = ((1 << 5) | (5 << 3));
- /* NOTE: if we were doing 6Mb OFDM for scans we'd use
- * power level:
- * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3;
- */
- }
- IWL_DEBUG_SCAN("Scanning %d [%s %d]\n",
- scan_ch->channel,
- (scan_ch->type & 1) ? "ACTIVE" : "PASSIVE",
- (scan_ch->type & 1) ?
+ IWL_DEBUG_SCAN("Scanning ch=%d prob=0x%X [%s %d]\n",
+ channel, le32_to_cpu(scan_ch->type),
+ (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ?
+ "ACTIVE" : "PASSIVE",
+ (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ?
active_dwell : passive_dwell);
scan_ch++;
@@ -673,7 +686,7 @@
break;
}
}
-
+ IWL_DEBUG_SCAN("select TX ANT = %c\n", 'A' + ind);
return scan_tx_ant[ind];
}
@@ -693,7 +706,7 @@
u32 tx_ant;
u16 cmd_len;
enum ieee80211_band band;
- u8 direct_mask;
+ u8 n_probes = 2;
u8 rx_chain = 0x7; /* bitmap: ABC chains */
conf = ieee80211_get_hw_conf(priv->hw);
@@ -793,17 +806,16 @@
scan->direct_scan[0].len = priv->direct_ssid_len;
memcpy(scan->direct_scan[0].ssid,
priv->direct_ssid, priv->direct_ssid_len);
- direct_mask = 1;
+ n_probes++;
} else if (!iwl_is_associated(priv) && priv->essid_len) {
IWL_DEBUG_SCAN("Start direct scan for '%s' (not associated)\n",
iwl_escape_essid(priv->essid, priv->essid_len));
scan->direct_scan[0].id = WLAN_EID_SSID;
scan->direct_scan[0].len = priv->essid_len;
memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len);
- direct_mask = 1;
+ n_probes++;
} else {
IWL_DEBUG_SCAN("Start indirect scan.\n");
- direct_mask = 0;
}
scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
@@ -860,16 +872,11 @@
scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK |
RXON_FILTER_BCON_AWARE_MSK);
- if (direct_mask)
- scan->channel_count =
- iwl_get_channels_for_scan(priv, band, 1, /* active */
- direct_mask,
- (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
- else
- scan->channel_count =
- iwl_get_channels_for_scan(priv, band, 0, /* passive */
- direct_mask,
- (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
+ scan->channel_count =
+ iwl_get_channels_for_scan(priv, band, 1, /* active */
+ n_probes,
+ (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
+
if (scan->channel_count == 0) {
IWL_DEBUG_SCAN("channel count %d\n", scan->channel_count);
goto done;
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 0be2a71..9b50b10 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -601,13 +601,7 @@
tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
}
- if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
- tx_flags |= TX_CMD_FLG_RTS_MSK;
- tx_flags &= ~TX_CMD_FLG_CTS_MSK;
- } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
- tx_flags &= ~TX_CMD_FLG_RTS_MSK;
- tx_flags |= TX_CMD_FLG_CTS_MSK;
- }
+ priv->cfg->ops->utils->rts_tx_cmd_flag(info, &tx_flags);
if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK))
tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 1a7d18f..4a22d3f 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -2035,36 +2035,6 @@
return rc;
}
-int iwl3945_is_network_packet(struct iwl3945_priv *priv, struct ieee80211_hdr *header)
-{
- /* Filter incoming packets to determine if they are targeted toward
- * this network, discarding packets coming from ourselves */
- switch (priv->iw_mode) {
- case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source | BSSID */
- /* packets from our adapter are dropped (echo) */
- if (!compare_ether_addr(header->addr2, priv->mac_addr))
- return 0;
- /* {broad,multi}cast packets to our IBSS go through */
- if (is_multicast_ether_addr(header->addr1))
- return !compare_ether_addr(header->addr3, priv->bssid);
- /* packets to our adapter go through */
- return !compare_ether_addr(header->addr1, priv->mac_addr);
- case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */
- /* packets from our adapter are dropped (echo) */
- if (!compare_ether_addr(header->addr3, priv->mac_addr))
- return 0;
- /* {broad,multi}cast packets to our BSS go through */
- if (is_multicast_ether_addr(header->addr1))
- return !compare_ether_addr(header->addr2, priv->bssid);
- /* packets to our adapter go through */
- return !compare_ether_addr(header->addr1, priv->mac_addr);
- default:
- return 1;
- }
-
- return 1;
-}
-
/**
* iwl3945_scan_cancel - Cancel any currently executing HW scan
*
@@ -2117,20 +2087,6 @@
return ret;
}
-static void iwl3945_sequence_reset(struct iwl3945_priv *priv)
-{
- /* Reset ieee stats */
-
- /* We don't reset the net_device_stats (ieee->stats) on
- * re-association */
-
- priv->last_seq_num = -1;
- priv->last_frag_num = -1;
- priv->last_packet_time = 0;
-
- iwl3945_scan_cancel(priv);
-}
-
#define MAX_UCODE_BEACON_INTERVAL 1024
#define INTEL_CONN_LISTEN_INTERVAL __constant_cpu_to_le16(0xA)
@@ -2925,72 +2881,6 @@
}
}
-#define IWL_PACKET_RETRY_TIME HZ
-
-int iwl3945_is_duplicate_packet(struct iwl3945_priv *priv, struct ieee80211_hdr *header)
-{
- u16 sc = le16_to_cpu(header->seq_ctrl);
- u16 seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
- u16 frag = sc & IEEE80211_SCTL_FRAG;
- u16 *last_seq, *last_frag;
- unsigned long *last_time;
-
- switch (priv->iw_mode) {
- case IEEE80211_IF_TYPE_IBSS:{
- struct list_head *p;
- struct iwl3945_ibss_seq *entry = NULL;
- u8 *mac = header->addr2;
- int index = mac[5] & (IWL_IBSS_MAC_HASH_SIZE - 1);
-
- __list_for_each(p, &priv->ibss_mac_hash[index]) {
- entry = list_entry(p, struct iwl3945_ibss_seq, list);
- if (!compare_ether_addr(entry->mac, mac))
- break;
- }
- if (p == &priv->ibss_mac_hash[index]) {
- entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
- if (!entry) {
- IWL_ERROR("Cannot malloc new mac entry\n");
- return 0;
- }
- memcpy(entry->mac, mac, ETH_ALEN);
- entry->seq_num = seq;
- entry->frag_num = frag;
- entry->packet_time = jiffies;
- list_add(&entry->list, &priv->ibss_mac_hash[index]);
- return 0;
- }
- last_seq = &entry->seq_num;
- last_frag = &entry->frag_num;
- last_time = &entry->packet_time;
- break;
- }
- case IEEE80211_IF_TYPE_STA:
- last_seq = &priv->last_seq_num;
- last_frag = &priv->last_frag_num;
- last_time = &priv->last_packet_time;
- break;
- default:
- return 0;
- }
- if ((*last_seq == seq) &&
- time_after(*last_time + IWL_PACKET_RETRY_TIME, jiffies)) {
- if (*last_frag == frag)
- goto drop;
- if (*last_frag + 1 != frag)
- /* out-of-order fragment */
- goto drop;
- } else
- *last_seq = seq;
-
- *last_frag = frag;
- *last_time = jiffies;
- return 0;
-
- drop:
- return 1;
-}
-
#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
#include "iwl-spectrum.h"
@@ -6531,8 +6421,6 @@
break;
}
- iwl3945_sequence_reset(priv);
-
iwl3945_activate_qos(priv, 0);
/* we have just associated, don't start scan too early */
@@ -6907,6 +6795,9 @@
* clear sta table, add BCAST sta... */
}
+/* temporary */
+static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb);
+
static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_if_conf *conf)
@@ -6924,10 +6815,21 @@
return 0;
}
+ /* handle this temporarily here */
+ if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS &&
+ conf->changed & IEEE80211_IFCC_BEACON) {
+ struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
+ if (!beacon)
+ return -ENOMEM;
+ rc = iwl3945_mac_beacon_update(hw, beacon);
+ if (rc)
+ return rc;
+ }
+
/* XXX: this MUST use conf->mac_addr */
if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
- (!conf->beacon || !conf->ssid_len)) {
+ (!conf->ssid_len)) {
IWL_DEBUG_MAC80211
("Leaving in AP mode because HostAPD is not ready.\n");
return 0;
@@ -6959,7 +6861,7 @@
if (priv->ibss_beacon)
dev_kfree_skb(priv->ibss_beacon);
- priv->ibss_beacon = conf->beacon;
+ priv->ibss_beacon = ieee80211_beacon_get(hw, vif);
}
if (iwl3945_is_rfkill(priv))
@@ -7940,7 +7842,6 @@
.conf_tx = iwl3945_mac_conf_tx,
.get_tsf = iwl3945_mac_get_tsf,
.reset_tsf = iwl3945_mac_reset_tsf,
- .beacon_update = iwl3945_mac_beacon_update,
.hw_scan = iwl3945_mac_hw_scan
};
@@ -7950,7 +7851,6 @@
struct iwl3945_priv *priv;
struct ieee80211_hw *hw;
struct iwl_3945_cfg *cfg = (struct iwl_3945_cfg *)(ent->driver_data);
- int i;
unsigned long flags;
DECLARE_MAC_BUF(mac);
@@ -8011,9 +7911,6 @@
spin_lock_init(&priv->sta_lock);
spin_lock_init(&priv->hcmd_lock);
- for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++)
- INIT_LIST_HEAD(&priv->ibss_mac_hash[i]);
-
INIT_LIST_HEAD(&priv->free_frames);
mutex_init(&priv->mutex);
@@ -8186,8 +8083,6 @@
static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
{
struct iwl3945_priv *priv = pci_get_drvdata(pdev);
- struct list_head *p, *q;
- int i;
unsigned long flags;
if (!priv)
@@ -8208,14 +8103,6 @@
iwl_synchronize_irq(priv);
- /* Free MAC hash list for ADHOC */
- for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) {
- list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) {
- list_del(p);
- kfree(list_entry(p, struct iwl3945_ibss_seq, list));
- }
- }
-
sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group);
iwl3945_rfkill_unregister(priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index 7f65d91..71f5da3 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -250,6 +250,9 @@
/* always get timestamp with Rx frame */
priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK;
+ /* allow CTS-to-self if possible. this is relevant only for
+ * 5000, but will not damage 4965 */
+ priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN;
ret = iwl4965_check_rxon_cmd(&priv->staging_rxon);
if (ret) {
@@ -325,16 +328,6 @@
if (!priv->error_recovering)
priv->start_calib = 0;
- iwl_init_sensitivity(priv);
-
- /* If we issue a new RXON command which required a tune then we must
- * send a new TXPOWER command or we won't be able to Tx any frames */
- ret = iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);
- if (ret) {
- IWL_ERROR("Error sending TX power (%d)\n", ret);
- return ret;
- }
-
/* Add the broadcast address so we can send broadcast frames */
if (iwl_rxon_add_station(priv, iwl_bcast_addr, 0) ==
IWL_INVALID_STATION) {
@@ -370,6 +363,16 @@
memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
}
+ iwl_init_sensitivity(priv);
+
+ /* If we issue a new RXON command which required a tune then we must
+ * send a new TXPOWER command or we won't be able to Tx any frames */
+ ret = iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);
+ if (ret) {
+ IWL_ERROR("Error sending TX power (%d)\n", ret);
+ return ret;
+ }
+
return 0;
}
@@ -572,25 +575,14 @@
/*
* QoS support
*/
-static int iwl4965_send_qos_params_command(struct iwl_priv *priv,
- struct iwl4965_qosparam_cmd *qos)
+static void iwl_activate_qos(struct iwl_priv *priv, u8 force)
{
-
- return iwl_send_cmd_pdu(priv, REPLY_QOS_PARAM,
- sizeof(struct iwl4965_qosparam_cmd), qos);
-}
-
-static void iwl4965_activate_qos(struct iwl_priv *priv, u8 force)
-{
- unsigned long flags;
-
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
if (!priv->qos_data.qos_enable)
return;
- spin_lock_irqsave(&priv->lock, flags);
priv->qos_data.def_qos_parm.qos_flags = 0;
if (priv->qos_data.qos_cap.q_AP.queue_request &&
@@ -604,15 +596,14 @@
if (priv->current_ht_config.is_ht)
priv->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
- spin_unlock_irqrestore(&priv->lock, flags);
-
if (force || iwl_is_associated(priv)) {
IWL_DEBUG_QOS("send QoS cmd with Qos active=%d FLAGS=0x%X\n",
priv->qos_data.qos_active,
priv->qos_data.def_qos_parm.qos_flags);
- iwl4965_send_qos_params_command(priv,
- &(priv->qos_data.def_qos_parm));
+ iwl_send_cmd_pdu_async(priv, REPLY_QOS_PARAM,
+ sizeof(struct iwl_qosparam_cmd),
+ &priv->qos_data.def_qos_parm, NULL);
}
}
@@ -2421,6 +2412,7 @@
struct ieee80211_conf *conf = NULL;
int ret = 0;
DECLARE_MAC_BUF(mac);
+ unsigned long flags;
if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
IWL_ERROR("%s Should not be called in AP mode\n", __FUNCTION__);
@@ -2510,25 +2502,15 @@
if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
priv->assoc_station_added = 1;
- iwl4965_activate_qos(priv, 0);
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl_activate_qos(priv, 0);
+ spin_unlock_irqrestore(&priv->lock, flags);
iwl_power_update_mode(priv, 0);
/* we have just associated, don't start scan too early */
priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN;
}
-
-static void iwl4965_bg_post_associate(struct work_struct *data)
-{
- struct iwl_priv *priv = container_of(data, struct iwl_priv,
- post_associate.work);
-
- mutex_lock(&priv->mutex);
- iwl4965_post_associate(priv);
- mutex_unlock(&priv->mutex);
-
-}
-
static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
static void iwl_bg_scan_completed(struct work_struct *work)
@@ -2659,7 +2641,6 @@
*/
mutex_lock(&priv->mutex);
iwl_scan_cancel_timeout(priv, 100);
- cancel_delayed_work(&priv->post_associate);
mutex_unlock(&priv->mutex);
}
@@ -2855,6 +2836,7 @@
static void iwl4965_config_ap(struct iwl_priv *priv)
{
int ret = 0;
+ unsigned long flags;
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
@@ -2902,7 +2884,9 @@
/* restore RXON assoc */
priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
iwl4965_commit_rxon(priv);
- iwl4965_activate_qos(priv, 1);
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl_activate_qos(priv, 1);
+ spin_unlock_irqrestore(&priv->lock, flags);
iwl_rxon_add_station(priv, iwl_bcast_addr, 0);
}
iwl4965_send_beacon_cmd(priv);
@@ -2912,6 +2896,9 @@
* clear sta table, add BCAST sta... */
}
+/* temporary */
+static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb);
+
static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_if_conf *conf)
@@ -2929,8 +2916,18 @@
return 0;
}
+ if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS &&
+ conf->changed & IEEE80211_IFCC_BEACON) {
+ struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
+ if (!beacon)
+ return -ENOMEM;
+ rc = iwl4965_mac_beacon_update(hw, beacon);
+ if (rc)
+ return rc;
+ }
+
if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
- (!conf->beacon || !conf->ssid_len)) {
+ (!conf->ssid_len)) {
IWL_DEBUG_MAC80211
("Leaving in AP mode because HostAPD is not ready.\n");
return 0;
@@ -2962,7 +2959,7 @@
if (priv->ibss_beacon)
dev_kfree_skb(priv->ibss_beacon);
- priv->ibss_beacon = conf->beacon;
+ priv->ibss_beacon = ieee80211_beacon_get(hw, vif);
}
if (iwl_is_rfkill(priv))
@@ -3048,7 +3045,6 @@
if (iwl_is_ready_rf(priv)) {
iwl_scan_cancel_timeout(priv, 100);
- cancel_delayed_work(&priv->post_associate);
priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
iwl4965_commit_rxon(priv);
}
@@ -3338,15 +3334,12 @@
priv->qos_data.def_qos_parm.ac[q].reserved1 = 0;
priv->qos_data.qos_active = 1;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- mutex_lock(&priv->mutex);
if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
- iwl4965_activate_qos(priv, 1);
+ iwl_activate_qos(priv, 1);
else if (priv->assoc_id && iwl_is_associated(priv))
- iwl4965_activate_qos(priv, 0);
+ iwl_activate_qos(priv, 0);
- mutex_unlock(&priv->mutex);
+ spin_unlock_irqrestore(&priv->lock, flags);
IWL_DEBUG_MAC80211("leave\n");
return 0;
@@ -3413,8 +3406,6 @@
iwl_reset_qos(priv);
- cancel_delayed_work(&priv->post_associate);
-
spin_lock_irqsave(&priv->lock, flags);
priv->assoc_id = 0;
priv->assoc_capability = 0;
@@ -4016,7 +4007,6 @@
INIT_WORK(&priv->beacon_update, iwl4965_bg_beacon_update);
INIT_WORK(&priv->set_monitor, iwl4965_bg_set_monitor);
INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work);
- INIT_DELAYED_WORK(&priv->post_associate, iwl4965_bg_post_associate);
INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start);
INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);
@@ -4043,7 +4033,6 @@
cancel_delayed_work_sync(&priv->init_alive_start);
cancel_delayed_work(&priv->scan_check);
cancel_delayed_work(&priv->alive_start);
- cancel_delayed_work(&priv->post_associate);
cancel_work_sync(&priv->beacon_update);
del_timer_sync(&priv->statistics_periodic);
}
@@ -4090,7 +4079,6 @@
.get_tx_stats = iwl4965_mac_get_tx_stats,
.conf_tx = iwl4965_mac_conf_tx,
.reset_tsf = iwl4965_mac_reset_tsf,
- .beacon_update = iwl4965_mac_beacon_update,
.bss_info_changed = iwl4965_bss_info_changed,
.ampdu_action = iwl4965_mac_ampdu_action,
.hw_scan = iwl4965_mac_hw_scan
@@ -4409,8 +4397,16 @@
{IWL_PCI_DEVICE(0x4229, PCI_ANY_ID, iwl4965_agn_cfg)},
{IWL_PCI_DEVICE(0x4230, PCI_ANY_ID, iwl4965_agn_cfg)},
#ifdef CONFIG_IWL5000
- {IWL_PCI_DEVICE(0x4235, PCI_ANY_ID, iwl5300_agn_cfg)},
+ {IWL_PCI_DEVICE(0x4232, 0x1205, iwl5100_bg_cfg)},
+ {IWL_PCI_DEVICE(0x4232, 0x1305, iwl5100_bg_cfg)},
+ {IWL_PCI_DEVICE(0x4232, 0x1206, iwl5100_abg_cfg)},
+ {IWL_PCI_DEVICE(0x4232, 0x1306, iwl5100_abg_cfg)},
+ {IWL_PCI_DEVICE(0x4232, 0x1326, iwl5100_abg_cfg)},
+ {IWL_PCI_DEVICE(0x4237, 0x1216, iwl5100_abg_cfg)},
{IWL_PCI_DEVICE(0x4232, PCI_ANY_ID, iwl5100_agn_cfg)},
+ {IWL_PCI_DEVICE(0x4235, PCI_ANY_ID, iwl5300_agn_cfg)},
+ {IWL_PCI_DEVICE(0x4236, PCI_ANY_ID, iwl5300_agn_cfg)},
+ {IWL_PCI_DEVICE(0x4237, PCI_ANY_ID, iwl5100_agn_cfg)},
{IWL_PCI_DEVICE(0x423A, PCI_ANY_ID, iwl5350_agn_cfg)},
#endif /* CONFIG_IWL5000 */
{0}
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
index 343ed38..4b27456 100644
--- a/drivers/net/wireless/libertas/scan.c
+++ b/drivers/net/wireless/libertas/scan.c
@@ -567,11 +567,11 @@
pos += 8;
/* beacon interval is 2 bytes long */
- bss->beaconperiod = le16_to_cpup((void *) pos);
+ bss->beaconperiod = get_unaligned_le16(pos);
pos += 2;
/* capability information is 2 bytes long */
- bss->capability = le16_to_cpup((void *) pos);
+ bss->capability = get_unaligned_le16(pos);
lbs_deb_scan("process_bss: capabilities 0x%04x\n", bss->capability);
pos += 2;
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 5d30c57..913dc9f 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -126,7 +126,7 @@
(1 << IEEE80211_RADIOTAP_CHANNEL));
hdr->rt_flags = 0;
hdr->rt_rate = txrate->bitrate / 5;
- hdr->rt_channel = data->channel->center_freq;
+ hdr->rt_channel = cpu_to_le16(data->channel->center_freq);
flags = IEEE80211_CHAN_2GHZ;
if (txrate->flags & IEEE80211_RATE_ERP_G)
flags |= IEEE80211_CHAN_OFDM;
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index ee953ca..4c0538d 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -733,6 +733,17 @@
(rt2x00dev->rx->data_size / 128));
rt2x00pci_register_write(rt2x00dev, CSR9, reg);
+ rt2x00pci_register_read(rt2x00dev, CSR14, ®);
+ rt2x00_set_field32(®, CSR14_TSF_COUNT, 0);
+ rt2x00_set_field32(®, CSR14_TSF_SYNC, 0);
+ rt2x00_set_field32(®, CSR14_TBCN, 0);
+ rt2x00_set_field32(®, CSR14_TCFP, 0);
+ rt2x00_set_field32(®, CSR14_TATIMW, 0);
+ rt2x00_set_field32(®, CSR14_BEACON_GEN, 0);
+ rt2x00_set_field32(®, CSR14_CFP_COUNT_PRELOAD, 0);
+ rt2x00_set_field32(®, CSR14_TBCM_PRELOAD, 0);
+ rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+
rt2x00pci_register_write(rt2x00dev, CNT3, 0x3f080000);
rt2x00pci_register_read(rt2x00dev, ARCSR0, ®);
@@ -1058,6 +1069,40 @@
/*
* TX data initialization
*/
+static void rt2400pci_write_beacon(struct queue_entry *entry)
+{
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+ struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+ u32 word;
+ u32 reg;
+
+ /*
+ * Disable beaconing while we are reloading the beacon data,
+ * otherwise we might be sending out invalid data.
+ */
+ rt2x00pci_register_read(rt2x00dev, CSR14, ®);
+ rt2x00_set_field32(®, CSR14_TSF_COUNT, 0);
+ rt2x00_set_field32(®, CSR14_TBCN, 0);
+ rt2x00_set_field32(®, CSR14_BEACON_GEN, 0);
+ rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+
+ /*
+ * Replace rt2x00lib allocated descriptor with the
+ * pointer to the _real_ hardware descriptor.
+ * After that, map the beacon to DMA and update the
+ * descriptor.
+ */
+ memcpy(entry_priv->desc, skbdesc->desc, skbdesc->desc_len);
+ skbdesc->desc = entry_priv->desc;
+
+ rt2x00queue_map_txskb(rt2x00dev, entry->skb);
+
+ rt2x00_desc_read(entry_priv->desc, 1, &word);
+ rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
+ rt2x00_desc_write(entry_priv->desc, 1, word);
+}
+
static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
const enum data_queue_qid queue)
{
@@ -1504,59 +1549,6 @@
return tsf;
}
-static int rt2400pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
-{
- struct rt2x00_dev *rt2x00dev = hw->priv;
- struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
- struct queue_entry_priv_pci *entry_priv;
- struct skb_frame_desc *skbdesc;
- struct txentry_desc txdesc;
- u32 reg;
-
- if (unlikely(!intf->beacon))
- return -ENOBUFS;
- entry_priv = intf->beacon->priv_data;
-
- /*
- * Copy all TX descriptor information into txdesc,
- * after that we are free to use the skb->cb array
- * for our information.
- */
- intf->beacon->skb = skb;
- rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
-
- /*
- * Fill in skb descriptor
- */
- skbdesc = get_skb_frame_desc(skb);
- memset(skbdesc, 0, sizeof(*skbdesc));
- skbdesc->desc = entry_priv->desc;
- skbdesc->desc_len = intf->beacon->queue->desc_size;
- skbdesc->entry = intf->beacon;
-
- /*
- * Disable beaconing while we are reloading the beacon data,
- * otherwise we might be sending out invalid data.
- */
- rt2x00pci_register_read(rt2x00dev, CSR14, ®);
- rt2x00_set_field32(®, CSR14_TSF_COUNT, 0);
- rt2x00_set_field32(®, CSR14_TBCN, 0);
- rt2x00_set_field32(®, CSR14_BEACON_GEN, 0);
- rt2x00pci_register_write(rt2x00dev, CSR14, reg);
-
- /*
- * Enable beacon generation.
- * Write entire beacon with descriptor to register,
- * and kick the beacon generator.
- */
- rt2x00queue_map_txskb(rt2x00dev, intf->beacon->skb);
- rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
- rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);
-
- return 0;
-}
-
static int rt2400pci_tx_last_beacon(struct ieee80211_hw *hw)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
@@ -1581,7 +1573,6 @@
.conf_tx = rt2400pci_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
.get_tsf = rt2400pci_get_tsf,
- .beacon_update = rt2400pci_beacon_update,
.tx_last_beacon = rt2400pci_tx_last_beacon,
};
@@ -1599,6 +1590,7 @@
.link_tuner = rt2400pci_link_tuner,
.write_tx_desc = rt2400pci_write_tx_desc,
.write_tx_data = rt2x00pci_write_tx_data,
+ .write_beacon = rt2400pci_write_beacon,
.kick_tx_queue = rt2400pci_kick_tx_queue,
.fill_rxdone = rt2400pci_fill_rxdone,
.config_filter = rt2400pci_config_filter,
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 0423c25..aa6dfb8 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -831,6 +831,17 @@
rt2x00_set_field32(®, CSR11_CW_SELECT, 0);
rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+ rt2x00pci_register_read(rt2x00dev, CSR14, ®);
+ rt2x00_set_field32(®, CSR14_TSF_COUNT, 0);
+ rt2x00_set_field32(®, CSR14_TSF_SYNC, 0);
+ rt2x00_set_field32(®, CSR14_TBCN, 0);
+ rt2x00_set_field32(®, CSR14_TCFP, 0);
+ rt2x00_set_field32(®, CSR14_TATIMW, 0);
+ rt2x00_set_field32(®, CSR14_BEACON_GEN, 0);
+ rt2x00_set_field32(®, CSR14_CFP_COUNT_PRELOAD, 0);
+ rt2x00_set_field32(®, CSR14_TBCM_PRELOAD, 0);
+ rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+
rt2x00pci_register_write(rt2x00dev, CNT3, 0);
rt2x00pci_register_read(rt2x00dev, TXCSR8, ®);
@@ -1216,6 +1227,40 @@
/*
* TX data initialization
*/
+static void rt2500pci_write_beacon(struct queue_entry *entry)
+{
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+ struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+ u32 word;
+ u32 reg;
+
+ /*
+ * Disable beaconing while we are reloading the beacon data,
+ * otherwise we might be sending out invalid data.
+ */
+ rt2x00pci_register_read(rt2x00dev, CSR14, ®);
+ rt2x00_set_field32(®, CSR14_TSF_COUNT, 0);
+ rt2x00_set_field32(®, CSR14_TBCN, 0);
+ rt2x00_set_field32(®, CSR14_BEACON_GEN, 0);
+ rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+
+ /*
+ * Replace rt2x00lib allocated descriptor with the
+ * pointer to the _real_ hardware descriptor.
+ * After that, map the beacon to DMA and update the
+ * descriptor.
+ */
+ memcpy(entry_priv->desc, skbdesc->desc, skbdesc->desc_len);
+ skbdesc->desc = entry_priv->desc;
+
+ rt2x00queue_map_txskb(rt2x00dev, entry->skb);
+
+ rt2x00_desc_read(entry_priv->desc, 1, &word);
+ rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
+ rt2x00_desc_write(entry_priv->desc, 1, word);
+}
+
static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
const enum data_queue_qid queue)
{
@@ -1797,60 +1842,6 @@
return tsf;
}
-static int rt2500pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
-{
- struct rt2x00_dev *rt2x00dev = hw->priv;
- struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
- struct queue_entry_priv_pci *entry_priv;
- struct skb_frame_desc *skbdesc;
- struct txentry_desc txdesc;
- u32 reg;
-
- if (unlikely(!intf->beacon))
- return -ENOBUFS;
-
- entry_priv = intf->beacon->priv_data;
-
- /*
- * Copy all TX descriptor information into txdesc,
- * after that we are free to use the skb->cb array
- * for our information.
- */
- intf->beacon->skb = skb;
- rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
-
- /*
- * Fill in skb descriptor
- */
- skbdesc = get_skb_frame_desc(skb);
- memset(skbdesc, 0, sizeof(*skbdesc));
- skbdesc->desc = entry_priv->desc;
- skbdesc->desc_len = intf->beacon->queue->desc_size;
- skbdesc->entry = intf->beacon;
-
- /*
- * Disable beaconing while we are reloading the beacon data,
- * otherwise we might be sending out invalid data.
- */
- rt2x00pci_register_read(rt2x00dev, CSR14, ®);
- rt2x00_set_field32(®, CSR14_TSF_COUNT, 0);
- rt2x00_set_field32(®, CSR14_TBCN, 0);
- rt2x00_set_field32(®, CSR14_BEACON_GEN, 0);
- rt2x00pci_register_write(rt2x00dev, CSR14, reg);
-
- /*
- * Enable beacon generation.
- * Write entire beacon with descriptor to register,
- * and kick the beacon generator.
- */
- rt2x00queue_map_txskb(rt2x00dev, intf->beacon->skb);
- rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
- rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);
-
- return 0;
-}
-
static int rt2500pci_tx_last_beacon(struct ieee80211_hw *hw)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
@@ -1875,7 +1866,6 @@
.conf_tx = rt2x00mac_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
.get_tsf = rt2500pci_get_tsf,
- .beacon_update = rt2500pci_beacon_update,
.tx_last_beacon = rt2500pci_tx_last_beacon,
};
@@ -1893,6 +1883,7 @@
.link_tuner = rt2500pci_link_tuner,
.write_tx_desc = rt2500pci_write_tx_desc,
.write_tx_data = rt2x00pci_write_tx_data,
+ .write_beacon = rt2500pci_write_beacon,
.kick_tx_queue = rt2500pci_kick_tx_queue,
.fill_rxdone = rt2500pci_fill_rxdone,
.config_filter = rt2500pci_config_filter,
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 0dd1cb5..3558cb2 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -812,6 +812,13 @@
rt2x00_set_field16(®, TXRX_CSR8_BBP_ID1_VALID, 0);
rt2500usb_register_write(rt2x00dev, TXRX_CSR8, reg);
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®);
+ rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 0);
+ rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, 0);
+ rt2x00_set_field16(®, TXRX_CSR19_TBCN, 0);
+ rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 0);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
+
rt2500usb_register_write(rt2x00dev, TXRX_CSR21, 0xe78f);
rt2500usb_register_write(rt2x00dev, MAC_CSR9, 0xff1d);
@@ -1100,6 +1107,65 @@
rt2x00_desc_write(txd, 0, word);
}
+/*
+ * TX data initialization
+ */
+static void rt2500usb_beacondone(struct urb *urb);
+
+static void rt2500usb_write_beacon(struct queue_entry *entry)
+{
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+ struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
+ struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data;
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+ int pipe = usb_sndbulkpipe(usb_dev, 1);
+ int length;
+ u16 reg;
+
+ /*
+ * Add the descriptor in front of the skb.
+ */
+ skb_push(entry->skb, entry->queue->desc_size);
+ memcpy(entry->skb->data, skbdesc->desc, skbdesc->desc_len);
+ skbdesc->desc = entry->skb->data;
+
+ /*
+ * Disable beaconing while we are reloading the beacon data,
+ * otherwise we might be sending out invalid data.
+ */
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®);
+ rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 0);
+ rt2x00_set_field16(®, TXRX_CSR19_TBCN, 0);
+ rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 0);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
+
+ /*
+ * USB devices cannot blindly pass the skb->len as the
+ * length of the data to usb_fill_bulk_urb. Pass the skb
+ * to the driver to determine what the length should be.
+ */
+ length = rt2x00dev->ops->lib->get_tx_data_len(rt2x00dev, entry->skb);
+
+ usb_fill_bulk_urb(bcn_priv->urb, usb_dev, pipe,
+ entry->skb->data, length, rt2500usb_beacondone,
+ entry);
+
+ /*
+ * Second we need to create the guardian byte.
+ * We only need a single byte, so lets recycle
+ * the 'flags' field we are not using for beacons.
+ */
+ bcn_priv->guardian_data = 0;
+ usb_fill_bulk_urb(bcn_priv->guardian_urb, usb_dev, pipe,
+ &bcn_priv->guardian_data, 1, rt2500usb_beacondone,
+ entry);
+
+ /*
+ * Send out the guardian byte.
+ */
+ usb_submit_urb(bcn_priv->guardian_urb, GFP_ATOMIC);
+}
+
static int rt2500usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb)
{
@@ -1115,9 +1181,6 @@
return length;
}
-/*
- * TX data initialization
- */
static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
const enum data_queue_qid queue)
{
@@ -1672,96 +1735,6 @@
return 0;
}
-/*
- * IEEE80211 stack callback functions.
- */
-static int rt2500usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
-{
- struct rt2x00_dev *rt2x00dev = hw->priv;
- struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
- struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
- struct queue_entry_priv_usb_bcn *bcn_priv;
- struct skb_frame_desc *skbdesc;
- struct txentry_desc txdesc;
- int pipe = usb_sndbulkpipe(usb_dev, 1);
- int length;
- u16 reg;
-
- if (unlikely(!intf->beacon))
- return -ENOBUFS;
-
- bcn_priv = intf->beacon->priv_data;
-
- /*
- * Copy all TX descriptor information into txdesc,
- * after that we are free to use the skb->cb array
- * for our information.
- */
- intf->beacon->skb = skb;
- rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
-
- /*
- * Add the descriptor in front of the skb.
- */
- skb_push(skb, intf->beacon->queue->desc_size);
- memset(skb->data, 0, intf->beacon->queue->desc_size);
-
- /*
- * Fill in skb descriptor
- */
- skbdesc = get_skb_frame_desc(skb);
- memset(skbdesc, 0, sizeof(*skbdesc));
- skbdesc->desc = skb->data;
- skbdesc->desc_len = intf->beacon->queue->desc_size;
- skbdesc->entry = intf->beacon;
-
- /*
- * Disable beaconing while we are reloading the beacon data,
- * otherwise we might be sending out invalid data.
- */
- rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®);
- rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 0);
- rt2x00_set_field16(®, TXRX_CSR19_TBCN, 0);
- rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 0);
- rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
-
- rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
-
- /*
- * USB devices cannot blindly pass the skb->len as the
- * length of the data to usb_fill_bulk_urb. Pass the skb
- * to the driver to determine what the length should be.
- */
- length = rt2500usb_get_tx_data_len(rt2x00dev, skb);
-
- usb_fill_bulk_urb(bcn_priv->urb, usb_dev, pipe,
- skb->data, length, rt2500usb_beacondone,
- intf->beacon);
-
- /*
- * Second we need to create the guardian byte.
- * We only need a single byte, so lets recycle
- * the 'flags' field we are not using for beacons.
- */
- bcn_priv->guardian_data = 0;
- usb_fill_bulk_urb(bcn_priv->guardian_urb, usb_dev, pipe,
- &bcn_priv->guardian_data, 1, rt2500usb_beacondone,
- intf->beacon);
-
- /*
- * Send out the guardian byte.
- */
- usb_submit_urb(bcn_priv->guardian_urb, GFP_ATOMIC);
-
- /*
- * Enable beacon generation.
- */
- rt2500usb_kick_tx_queue(rt2x00dev, QID_BEACON);
-
- return 0;
-}
-
static const struct ieee80211_ops rt2500usb_mac80211_ops = {
.tx = rt2x00mac_tx,
.start = rt2x00mac_start,
@@ -1775,7 +1748,6 @@
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2x00mac_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
- .beacon_update = rt2500usb_beacon_update,
};
static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
@@ -1790,6 +1762,7 @@
.link_tuner = rt2500usb_link_tuner,
.write_tx_desc = rt2500usb_write_tx_desc,
.write_tx_data = rt2x00usb_write_tx_data,
+ .write_beacon = rt2500usb_write_beacon,
.get_tx_data_len = rt2500usb_get_tx_data_len,
.kick_tx_queue = rt2500usb_kick_tx_queue,
.fill_rxdone = rt2500usb_fill_rxdone,
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index c07d9ef..9fab0df 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -364,6 +364,8 @@
#define DELAYED_UPDATE_BEACON 0x00000001
#define DELAYED_CONFIG_ERP 0x00000002
#define DELAYED_LED_ASSOC 0x00000004
+
+ u16 seqno;
};
static inline struct rt2x00_intf* vif_to_intf(struct ieee80211_vif *vif)
@@ -434,6 +436,7 @@
*/
struct rt2x00lib_erp {
int short_preamble;
+ int cts_protection;
int ack_timeout;
int ack_consume_time;
@@ -520,6 +523,7 @@
struct sk_buff *skb,
struct txentry_desc *txdesc);
int (*write_tx_data) (struct queue_entry *entry);
+ void (*write_beacon) (struct queue_entry *entry);
int (*get_tx_data_len) (struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb);
void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev,
@@ -910,39 +914,6 @@
void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
/**
- * rt2x00queue_create_tx_descriptor - Create TX descriptor from mac80211 input
- * @entry: The entry which will be used to transfer the TX frame.
- * @txdesc: rt2x00 TX descriptor which will be initialized by this function.
- *
- * This function will initialize the &struct txentry_desc based on information
- * from mac80211. This descriptor can then be used by rt2x00lib and the drivers
- * to correctly initialize the hardware descriptor.
- * Note that before calling this function the skb->cb array must be untouched
- * by rt2x00lib. Only after this function completes will it be save to
- * overwrite the skb->cb information.
- * The reason for this is that mac80211 writes its own tx information into
- * the skb->cb array, and this function will use that information to initialize
- * the &struct txentry_desc structure.
- */
-void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
- struct txentry_desc *txdesc);
-
-/**
- * rt2x00queue_write_tx_descriptor - Write TX descriptor to hardware
- * @entry: The entry which will be used to transfer the TX frame.
- * @txdesc: TX descriptor which will be used to write hardware descriptor
- *
- * This function will write a TX descriptor initialized by
- * &rt2x00queue_create_tx_descriptor to the hardware. After this call
- * has completed the frame is now owned by the hardware, the hardware
- * queue will have automatically be kicked unless this frame was generated
- * by rt2x00lib, in which case the frame is "special" and must be kicked
- * by the caller.
- */
-void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
- struct txentry_desc *txdesc);
-
-/**
* rt2x00queue_get_queue - Convert queue index to queue pointer
* @rt2x00dev: Pointer to &struct rt2x00_dev.
* @queue: rt2x00 queue index (see &enum data_queue_qid).
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index 48608e8..f20ca71 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -84,6 +84,8 @@
memset(&erp, 0, sizeof(erp));
erp.short_preamble = bss_conf->use_short_preamble;
+ erp.cts_protection = bss_conf->use_cts_prot;
+
erp.ack_timeout = PLCP + get_duration(ACK_SIZE, 10);
erp.ack_consume_time = SIFS + PLCP + get_duration(ACK_SIZE, 10);
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index b48c04e..8c93eb8 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -409,7 +409,6 @@
{
struct rt2x00_dev *rt2x00dev = data;
struct rt2x00_intf *intf = vif_to_intf(vif);
- struct sk_buff *skb;
struct ieee80211_bss_conf conf;
int delayed_flags;
@@ -435,12 +434,8 @@
if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
return;
- if (delayed_flags & DELAYED_UPDATE_BEACON) {
- skb = ieee80211_beacon_get(rt2x00dev->hw, vif);
- if (skb &&
- rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, skb))
- dev_kfree_skb(skb);
- }
+ if (delayed_flags & DELAYED_UPDATE_BEACON)
+ rt2x00queue_update_beacon(rt2x00dev, vif);
if (delayed_flags & DELAYED_CONFIG_ERP)
rt2x00lib_config_erp(rt2x00dev, intf, &conf);
diff --git a/drivers/net/wireless/rt2x00/rt2x00firmware.c b/drivers/net/wireless/rt2x00/rt2x00firmware.c
index b971bc6..bab05a5 100644
--- a/drivers/net/wireless/rt2x00/rt2x00firmware.c
+++ b/drivers/net/wireless/rt2x00/rt2x00firmware.c
@@ -100,6 +100,14 @@
retval = rt2x00dev->ops->lib->load_firmware(rt2x00dev,
rt2x00dev->fw->data,
rt2x00dev->fw->size);
+
+ /*
+ * When the firmware is uploaded to the hardware the LED
+ * association status might have been triggered, for correct
+ * LED handling it should now be reset.
+ */
+ rt2x00leds_led_assoc(rt2x00dev, false);
+
return retval;
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index eae5ce1..f2c9b0e 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -139,6 +139,14 @@
int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb);
/**
+ * rt2x00queue_update_beacon - Send new beacon from mac80211 to hardware
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ * @vif: Interface for which the beacon should be updated.
+ */
+int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
+ struct ieee80211_vif *vif);
+
+/**
* rt2x00queue_index_inc - Index incrementation function
* @queue: Queue (&struct data_queue) to perform the action on.
* @index: Index type (&enum queue_index) to perform the action on.
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index 3a1fb6d..77af1df 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -96,6 +96,7 @@
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
enum data_queue_qid qid = skb_get_queue_mapping(skb);
+ struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
struct data_queue *queue;
u16 frame_control;
@@ -151,6 +152,18 @@
}
}
+ /*
+ * XXX: This is as wrong as the old mac80211 code was,
+ * due to beacons not getting sequence numbers assigned
+ * properly.
+ */
+ if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
+ if (tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
+ intf->seqno += 0x10;
+ ieee80211hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
+ ieee80211hdr->seq_ctrl |= cpu_to_le16(intf->seqno);
+ }
+
if (rt2x00queue_write_tx_frame(queue, skb)) {
ieee80211_stop_queue(rt2x00dev->hw, qid);
return NETDEV_TX_BUSY;
@@ -348,7 +361,8 @@
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct rt2x00_intf *intf = vif_to_intf(vif);
- int status;
+ int update_bssid = 0;
+ int status = 0;
/*
* Mac80211 might be calling this function while we are trying
@@ -360,12 +374,13 @@
spin_lock(&intf->lock);
/*
- * If the interface does not work in master mode,
- * then the bssid value in the interface structure
- * should now be set.
+ * conf->bssid can be NULL if coming from the internal
+ * beacon update routine.
*/
- if (conf->type != IEEE80211_IF_TYPE_AP)
+ if (conf->changed & IEEE80211_IFCC_BSSID && conf->bssid) {
+ update_bssid = 1;
memcpy(&intf->bssid, conf->bssid, ETH_ALEN);
+ }
spin_unlock(&intf->lock);
@@ -375,17 +390,14 @@
* values as arguments we make keep access to rt2x00_intf thread safe
* even without the lock.
*/
- rt2x00lib_config_intf(rt2x00dev, intf, conf->type, NULL, conf->bssid);
+ rt2x00lib_config_intf(rt2x00dev, intf, vif->type, NULL,
+ update_bssid ? conf->bssid : NULL);
/*
- * We only need to initialize the beacon when master mode is enabled.
+ * Update the beacon.
*/
- if (conf->type != IEEE80211_IF_TYPE_AP || !conf->beacon)
- return 0;
-
- status = rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, conf->beacon);
- if (status)
- dev_kfree_skb(conf->beacon);
+ if (conf->changed & IEEE80211_IFCC_BEACON)
+ status = rt2x00queue_update_beacon(rt2x00dev, vif);
return status;
}
@@ -501,7 +513,7 @@
* When the erp information has changed, we should perform
* additional configuration steps. For all other changes we are done.
*/
- if (changes & BSS_CHANGED_ERP_PREAMBLE) {
+ if (changes & (BSS_CHANGED_ERP_PREAMBLE | BSS_CHANGED_ERP_CTS_PROT)) {
if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags))
rt2x00lib_config_erp(rt2x00dev, intf, bss_conf);
else
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 3ddce53..7f44203 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -108,12 +108,15 @@
void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
{
+ if (!skb)
+ return;
+
rt2x00queue_unmap_skb(rt2x00dev, skb);
dev_kfree_skb_any(skb);
}
-void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
- struct txentry_desc *txdesc)
+static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
+ struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
@@ -237,10 +240,9 @@
txdesc->signal |= 0x08;
}
}
-EXPORT_SYMBOL_GPL(rt2x00queue_create_tx_descriptor);
-void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
- struct txentry_desc *txdesc)
+static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
+ struct txentry_desc *txdesc)
{
struct data_queue *queue = entry->queue;
struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
@@ -270,7 +272,6 @@
!test_bit(ENTRY_TXD_BURST, &txdesc->flags))
rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, queue->qid);
}
-EXPORT_SYMBOL_GPL(rt2x00queue_write_tx_descriptor);
int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
{
@@ -320,6 +321,60 @@
return 0;
}
+int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
+ struct ieee80211_vif *vif)
+{
+ struct rt2x00_intf *intf = vif_to_intf(vif);
+ struct skb_frame_desc *skbdesc;
+ struct txentry_desc txdesc;
+ __le32 desc[16];
+
+ if (unlikely(!intf->beacon))
+ return -ENOBUFS;
+
+ intf->beacon->skb = ieee80211_beacon_get(rt2x00dev->hw, vif);
+ if (!intf->beacon->skb)
+ return -ENOMEM;
+
+ /*
+ * Copy all TX descriptor information into txdesc,
+ * after that we are free to use the skb->cb array
+ * for our information.
+ */
+ rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
+
+ /*
+ * For the descriptor we use a local array from where the
+ * driver can move it to the correct location required for
+ * the hardware.
+ */
+ memset(desc, 0, sizeof(desc));
+
+ /*
+ * Fill in skb descriptor
+ */
+ skbdesc = get_skb_frame_desc(intf->beacon->skb);
+ memset(skbdesc, 0, sizeof(*skbdesc));
+ skbdesc->desc = desc;
+ skbdesc->desc_len = intf->beacon->queue->desc_size;
+ skbdesc->entry = intf->beacon;
+
+ /*
+ * Write TX descriptor into reserved room in front of the beacon.
+ */
+ rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
+
+ /*
+ * Send beacon to hardware.
+ * Also enable beacon generation, which might have been disabled
+ * by the driver during the config_beacon() callback function.
+ */
+ rt2x00dev->ops->lib->write_beacon(intf->beacon);
+ rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);
+
+ return 0;
+}
+
struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev,
const enum data_queue_qid queue)
{
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index bbf1048..70ef7bf 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -1198,6 +1198,15 @@
rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_54MBS, 42);
rt2x00pci_register_write(rt2x00dev, TXRX_CSR8, reg);
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®);
+ rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, 0);
+ rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0);
+ rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 0);
+ rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0);
+ rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0);
+ rt2x00_set_field32(®, TXRX_CSR9_TIMESTAMP_COMPENSATE, 0);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+
rt2x00pci_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f);
rt2x00pci_register_write(rt2x00dev, MAC_CSR6, 0x00000fff);
@@ -1591,6 +1600,41 @@
/*
* TX data initialization
*/
+static void rt61pci_write_beacon(struct queue_entry *entry)
+{
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+ unsigned int beacon_base;
+ u32 reg;
+
+ /*
+ * Disable beaconing while we are reloading the beacon data,
+ * otherwise we might be sending out invalid data.
+ */
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®);
+ rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0);
+ rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0);
+ rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+
+ /*
+ * Write entire beacon with descriptor to register.
+ */
+ beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
+ rt2x00pci_register_multiwrite(rt2x00dev,
+ beacon_base,
+ skbdesc->desc, skbdesc->desc_len);
+ rt2x00pci_register_multiwrite(rt2x00dev,
+ beacon_base + skbdesc->desc_len,
+ entry->skb->data, entry->skb->len);
+
+ /*
+ * Clean up beacon skb.
+ */
+ dev_kfree_skb_any(entry->skb);
+ entry->skb = NULL;
+}
+
static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
const enum data_queue_qid queue)
{
@@ -2346,72 +2390,6 @@
return tsf;
}
-static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
-{
- struct rt2x00_dev *rt2x00dev = hw->priv;
- struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
- struct queue_entry_priv_pci *entry_priv;
- struct skb_frame_desc *skbdesc;
- struct txentry_desc txdesc;
- unsigned int beacon_base;
- u32 reg;
-
- if (unlikely(!intf->beacon))
- return -ENOBUFS;
-
- /*
- * Copy all TX descriptor information into txdesc,
- * after that we are free to use the skb->cb array
- * for our information.
- */
- intf->beacon->skb = skb;
- rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
-
- entry_priv = intf->beacon->priv_data;
- memset(entry_priv->desc, 0, intf->beacon->queue->desc_size);
-
- /*
- * Fill in skb descriptor
- */
- skbdesc = get_skb_frame_desc(skb);
- memset(skbdesc, 0, sizeof(*skbdesc));
- skbdesc->desc = entry_priv->desc;
- skbdesc->desc_len = intf->beacon->queue->desc_size;
- skbdesc->entry = intf->beacon;
-
- /*
- * Disable beaconing while we are reloading the beacon data,
- * otherwise we might be sending out invalid data.
- */
- rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®);
- rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0);
- rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0);
- rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0);
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
-
- /*
- * Write entire beacon with descriptor to register,
- * and kick the beacon generator.
- */
- rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
- beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx);
- rt2x00pci_register_multiwrite(rt2x00dev, beacon_base,
- skbdesc->desc, skbdesc->desc_len);
- rt2x00pci_register_multiwrite(rt2x00dev,
- beacon_base + skbdesc->desc_len,
- skb->data, skb->len);
- rt61pci_kick_tx_queue(rt2x00dev, QID_BEACON);
-
- /*
- * Clean up beacon skb.
- */
- dev_kfree_skb_any(skb);
- intf->beacon->skb = NULL;
-
- return 0;
-}
-
static const struct ieee80211_ops rt61pci_mac80211_ops = {
.tx = rt2x00mac_tx,
.start = rt2x00mac_start,
@@ -2427,7 +2405,6 @@
.conf_tx = rt2x00mac_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
.get_tsf = rt61pci_get_tsf,
- .beacon_update = rt61pci_beacon_update,
};
static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
@@ -2447,6 +2424,7 @@
.link_tuner = rt61pci_link_tuner,
.write_tx_desc = rt61pci_write_tx_desc,
.write_tx_data = rt2x00pci_write_tx_data,
+ .write_beacon = rt61pci_write_beacon,
.kick_tx_queue = rt61pci_kick_tx_queue,
.fill_rxdone = rt61pci_fill_rxdone,
.config_filter = rt61pci_config_filter,
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 3ef318e..34c6ff2 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -1016,6 +1016,15 @@
rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_54MBS, 42);
rt73usb_register_write(rt2x00dev, TXRX_CSR8, reg);
+ rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®);
+ rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, 0);
+ rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0);
+ rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 0);
+ rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0);
+ rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0);
+ rt2x00_set_field32(®, TXRX_CSR9_TIMESTAMP_COMPENSATE, 0);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+
rt73usb_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f);
rt73usb_register_read(rt2x00dev, MAC_CSR6, ®);
@@ -1334,6 +1343,49 @@
rt2x00_desc_write(txd, 0, word);
}
+/*
+ * TX data initialization
+ */
+static void rt73usb_write_beacon(struct queue_entry *entry)
+{
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+ unsigned int beacon_base;
+ u32 reg;
+
+ /*
+ * Add the descriptor in front of the skb.
+ */
+ skb_push(entry->skb, entry->queue->desc_size);
+ memcpy(entry->skb->data, skbdesc->desc, skbdesc->desc_len);
+ skbdesc->desc = entry->skb->data;
+
+ /*
+ * Disable beaconing while we are reloading the beacon data,
+ * otherwise we might be sending out invalid data.
+ */
+ rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®);
+ rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0);
+ rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0);
+ rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+
+ /*
+ * Write entire beacon with descriptor to register.
+ */
+ beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
+ rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE,
+ USB_VENDOR_REQUEST_OUT, beacon_base, 0,
+ entry->skb->data, entry->skb->len,
+ REGISTER_TIMEOUT32(entry->skb->len));
+
+ /*
+ * Clean up the beacon skb.
+ */
+ dev_kfree_skb(entry->skb);
+ entry->skb = NULL;
+}
+
static int rt73usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
struct sk_buff *skb)
{
@@ -1349,9 +1401,6 @@
return length;
}
-/*
- * TX data initialization
- */
static void rt73usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
const enum data_queue_qid queue)
{
@@ -1949,73 +1998,6 @@
#define rt73usb_get_tsf NULL
#endif
-static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
-{
- struct rt2x00_dev *rt2x00dev = hw->priv;
- struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
- struct skb_frame_desc *skbdesc;
- struct txentry_desc txdesc;
- unsigned int beacon_base;
- u32 reg;
-
- if (unlikely(!intf->beacon))
- return -ENOBUFS;
-
- /*
- * Copy all TX descriptor information into txdesc,
- * after that we are free to use the skb->cb array
- * for our information.
- */
- intf->beacon->skb = skb;
- rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
-
- /*
- * Add the descriptor in front of the skb.
- */
- skb_push(skb, intf->beacon->queue->desc_size);
- memset(skb->data, 0, intf->beacon->queue->desc_size);
-
- /*
- * Fill in skb descriptor
- */
- skbdesc = get_skb_frame_desc(skb);
- memset(skbdesc, 0, sizeof(*skbdesc));
- skbdesc->desc = skb->data;
- skbdesc->desc_len = intf->beacon->queue->desc_size;
- skbdesc->entry = intf->beacon;
-
- /*
- * Disable beaconing while we are reloading the beacon data,
- * otherwise we might be sending out invalid data.
- */
- rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®);
- rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0);
- rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0);
- rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0);
- rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
-
- /*
- * Write entire beacon with descriptor to register,
- * and kick the beacon generator.
- */
- rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
- beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx);
- rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE,
- USB_VENDOR_REQUEST_OUT, beacon_base, 0,
- skb->data, skb->len,
- REGISTER_TIMEOUT32(skb->len));
- rt73usb_kick_tx_queue(rt2x00dev, QID_BEACON);
-
- /*
- * Clean up the beacon skb.
- */
- dev_kfree_skb(skb);
- intf->beacon->skb = NULL;
-
- return 0;
-}
-
static const struct ieee80211_ops rt73usb_mac80211_ops = {
.tx = rt2x00mac_tx,
.start = rt2x00mac_start,
@@ -2031,7 +2013,6 @@
.conf_tx = rt2x00mac_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
.get_tsf = rt73usb_get_tsf,
- .beacon_update = rt73usb_beacon_update,
};
static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
@@ -2049,6 +2030,7 @@
.link_tuner = rt73usb_link_tuner,
.write_tx_desc = rt73usb_write_tx_desc,
.write_tx_data = rt2x00usb_write_tx_data,
+ .write_beacon = rt73usb_write_beacon,
.get_tx_data_len = rt73usb_get_tx_data_len,
.kick_tx_queue = rt73usb_kick_tx_queue,
.fill_rxdone = rt73usb_fill_rxdone,
diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c
index 33527e5..d3067b1 100644
--- a/drivers/net/wireless/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl8187_dev.c
@@ -430,8 +430,10 @@
reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg |
RTL818X_CONFIG3_ANAPARAM_WRITE);
- rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_ON);
- rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
+ rtl818x_iowrite32(priv, &priv->map->ANAPARAM,
+ RTL8187_RTL8225_ANAPARAM_ON);
+ rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
+ RTL8187_RTL8225_ANAPARAM2_ON);
rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg &
~RTL818X_CONFIG3_ANAPARAM_WRITE);
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD,
@@ -453,8 +455,10 @@
reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
rtl818x_iowrite8(priv, &priv->map->CONFIG3,
reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
- rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_ON);
- rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
+ rtl818x_iowrite32(priv, &priv->map->ANAPARAM,
+ RTL8187_RTL8225_ANAPARAM_ON);
+ rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
+ RTL8187_RTL8225_ANAPARAM2_ON);
rtl818x_iowrite8(priv, &priv->map->CONFIG3,
reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
@@ -566,9 +570,12 @@
reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
reg |= RTL818X_CONFIG3_ANAPARAM_WRITE | RTL818X_CONFIG3_GNT_SELECT;
rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg);
- rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, 0x727f3f52);
- rtl818x_iowrite32(priv, &priv->map->ANAPARAM, 0x45090658);
- rtl818x_iowrite8(priv, &priv->map->ANAPARAM3, 0);
+ rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
+ RTL8187B_RTL8225_ANAPARAM2_ON);
+ rtl818x_iowrite32(priv, &priv->map->ANAPARAM,
+ RTL8187B_RTL8225_ANAPARAM_ON);
+ rtl818x_iowrite8(priv, &priv->map->ANAPARAM3,
+ RTL8187B_RTL8225_ANAPARAM3_ON);
rtl818x_iowrite8(priv, (u8 *)0xFF61, 0x10);
reg = rtl818x_ioread8(priv, (u8 *)0xFF62);
@@ -1180,7 +1187,7 @@
.name = KBUILD_MODNAME,
.id_table = rtl8187_table,
.probe = rtl8187_probe,
- .disconnect = rtl8187_disconnect,
+ .disconnect = __devexit_p(rtl8187_disconnect),
};
static int __init rtl8187_init(void)
diff --git a/drivers/net/wireless/rtl8187_rtl8225.c b/drivers/net/wireless/rtl8187_rtl8225.c
index 1e059de..1bae899 100644
--- a/drivers/net/wireless/rtl8187_rtl8225.c
+++ b/drivers/net/wireless/rtl8187_rtl8225.c
@@ -307,7 +307,8 @@
reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
rtl818x_iowrite8(priv, &priv->map->CONFIG3,
reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
- rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
+ rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
+ RTL8187_RTL8225_ANAPARAM2_ON);
rtl818x_iowrite8(priv, &priv->map->CONFIG3,
reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
@@ -560,7 +561,8 @@
reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
rtl818x_iowrite8(priv, &priv->map->CONFIG3,
reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
- rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
+ rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
+ RTL8187_RTL8225_ANAPARAM2_ON);
rtl818x_iowrite8(priv, &priv->map->CONFIG3,
reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
@@ -913,8 +915,19 @@
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
- rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_OFF);
- rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_OFF);
+ if (!priv->is_rtl8187b) {
+ rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
+ RTL8187_RTL8225_ANAPARAM2_OFF);
+ rtl818x_iowrite32(priv, &priv->map->ANAPARAM,
+ RTL8187_RTL8225_ANAPARAM_OFF);
+ } else {
+ rtl818x_iowrite32(priv, &priv->map->ANAPARAM2,
+ RTL8187B_RTL8225_ANAPARAM2_OFF);
+ rtl818x_iowrite32(priv, &priv->map->ANAPARAM,
+ RTL8187B_RTL8225_ANAPARAM_OFF);
+ rtl818x_iowrite8(priv, &priv->map->ANAPARAM3,
+ RTL8187B_RTL8225_ANAPARAM3_OFF);
+ }
rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
}
diff --git a/drivers/net/wireless/rtl8187_rtl8225.h b/drivers/net/wireless/rtl8187_rtl8225.h
index d39ed02..20c5b6e 100644
--- a/drivers/net/wireless/rtl8187_rtl8225.h
+++ b/drivers/net/wireless/rtl8187_rtl8225.h
@@ -15,10 +15,17 @@
#ifndef RTL8187_RTL8225_H
#define RTL8187_RTL8225_H
-#define RTL8225_ANAPARAM_ON 0xa0000a59
-#define RTL8225_ANAPARAM2_ON 0x860c7312
-#define RTL8225_ANAPARAM_OFF 0xa00beb59
-#define RTL8225_ANAPARAM2_OFF 0x840dec11
+#define RTL8187_RTL8225_ANAPARAM_ON 0xa0000a59
+#define RTL8187_RTL8225_ANAPARAM2_ON 0x860c7312
+#define RTL8187_RTL8225_ANAPARAM_OFF 0xa00beb59
+#define RTL8187_RTL8225_ANAPARAM2_OFF 0x840dec11
+
+#define RTL8187B_RTL8225_ANAPARAM_ON 0x45090658
+#define RTL8187B_RTL8225_ANAPARAM2_ON 0x727f3f52
+#define RTL8187B_RTL8225_ANAPARAM3_ON 0x00
+#define RTL8187B_RTL8225_ANAPARAM_OFF 0x55480658
+#define RTL8187B_RTL8225_ANAPARAM2_OFF 0x72003f50
+#define RTL8187B_RTL8225_ANAPARAM3_OFF 0x00
const struct rtl818x_rf_ops * rtl8187_detect_rf(struct ieee80211_hw *);
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 665f76a..fcc532b 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -707,6 +707,7 @@
{
struct zd_mac *mac = zd_hw_mac(hw);
mac->type = IEEE80211_IF_TYPE_INVALID;
+ zd_set_beacon_interval(&mac->chip, 0);
zd_write_mac_addr(&mac->chip, NULL);
}
@@ -727,15 +728,19 @@
if (mac->type == IEEE80211_IF_TYPE_MESH_POINT ||
mac->type == IEEE80211_IF_TYPE_IBSS) {
associated = true;
- if (conf->beacon) {
- r = zd_mac_config_beacon(hw, conf->beacon);
+ if (conf->changed & IEEE80211_IFCC_BEACON) {
+ struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
+
+ if (!beacon)
+ return -ENOMEM;
+ r = zd_mac_config_beacon(hw, beacon);
if (r < 0)
return r;
r = zd_set_beacon_interval(&mac->chip, BCN_MODE_IBSS |
hw->conf.beacon_int);
if (r < 0)
return r;
- kfree_skb(conf->beacon);
+ kfree_skb(beacon);
}
} else
associated = is_valid_ether_addr(conf->bssid);
@@ -889,17 +894,6 @@
}
}
-static int zd_op_beacon_update(struct ieee80211_hw *hw,
- struct sk_buff *skb)
-{
- struct zd_mac *mac = zd_hw_mac(hw);
- zd_mac_config_beacon(hw, skb);
- kfree_skb(skb);
- zd_set_beacon_interval(&mac->chip, BCN_MODE_IBSS |
- hw->conf.beacon_int);
- return 0;
-}
-
static const struct ieee80211_ops zd_ops = {
.tx = zd_op_tx,
.start = zd_op_start,
@@ -910,7 +904,6 @@
.config_interface = zd_op_config_interface,
.configure_filter = zd_op_configure_filter,
.bss_info_changed = zd_op_bss_info_changed,
- .beacon_update = zd_op_beacon_update,
};
struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf)
diff --git a/include/linux/dccp.h b/include/linux/dccp.h
index aa07370..6080449 100644
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -364,8 +364,6 @@
/* FIXME: for now we're default to 1 but it should really be 0 */
#define DCCPF_INITIAL_SEND_NDP_COUNT 1
-#define DCCP_NDP_LIMIT 0xFFFFFF
-
/**
* struct dccp_minisock - Minimal DCCP connection representation
*
@@ -437,7 +435,7 @@
struct sk_buff *skb);
struct dccp_options_received {
- u32 dccpor_ndp; /* only 24 bits */
+ u64 dccpor_ndp:48;
u32 dccpor_timestamp;
u32 dccpor_timestamp_echo;
u32 dccpor_elapsed_time;
@@ -533,7 +531,7 @@
__u16 dccps_r_ack_ratio;
__u16 dccps_pcslen;
__u16 dccps_pcrlen;
- unsigned long dccps_ndp_count;
+ __u64 dccps_ndp_count:48;
unsigned long dccps_rate_last;
struct dccp_minisock dccps_minisock;
struct dccp_ackvec *dccps_hc_rx_ackvec;
diff --git a/include/linux/if_tun.h b/include/linux/if_tun.h
index 563fae5..4c6307a 100644
--- a/include/linux/if_tun.h
+++ b/include/linux/if_tun.h
@@ -17,6 +17,7 @@
#define __IF_TUN_H
#include <linux/types.h>
+#include <linux/if_ether.h>
/* Read queue size */
#define TUN_READQ_SIZE 500
@@ -42,7 +43,8 @@
#define TUNSETLINK _IOW('T', 205, int)
#define TUNSETGROUP _IOW('T', 206, int)
#define TUNGETFEATURES _IOR('T', 207, unsigned int)
-#define TUNSETOFFLOAD _IOW('T', 208, unsigned int)
+#define TUNSETOFFLOAD _IOW('T', 208, unsigned int)
+#define TUNSETTXFILTER _IOW('T', 209, unsigned int)
/* TUNSETIFF ifr flags */
#define IFF_TUN 0x0001
@@ -57,10 +59,26 @@
#define TUN_F_TSO6 0x04 /* I can handle TSO for IPv6 packets */
#define TUN_F_TSO_ECN 0x08 /* I can handle TSO with ECN bits. */
+/* Protocol info prepended to the packets (when IFF_NO_PI is not set) */
+#define TUN_PKT_STRIP 0x0001
struct tun_pi {
- unsigned short flags;
+ __u16 flags;
__be16 proto;
};
-#define TUN_PKT_STRIP 0x0001
+
+/*
+ * Filter spec (used for SETXXFILTER ioctls)
+ * This stuff is applicable only to the TAP (Ethernet) devices.
+ * If the count is zero the filter is disabled and the driver accepts
+ * all packets (promisc mode).
+ * If the filter is enabled in order to accept broadcast packets
+ * broadcast addr must be explicitly included in the addr list.
+ */
+#define TUN_FLT_ALLMULTI 0x0001 /* Accept all multicast packets */
+struct tun_filter {
+ __u16 flags; /* TUN_FLT_ flags see above */
+ __u16 count; /* Number of addresses */
+ __u8 addr[0][ETH_ALEN];
+};
#endif /* __IF_TUN_H */
diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h
index 99efbed..7cf7824d 100644
--- a/include/linux/pkt_cls.h
+++ b/include/linux/pkt_cls.h
@@ -374,6 +374,7 @@
TCA_FLOW_ACT,
TCA_FLOW_POLICE,
TCA_FLOW_EMATCHES,
+ TCA_FLOW_PERTURB,
__TCA_FLOW_MAX
};
diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h
index 0fe5a0d..4bf8cad 100644
--- a/include/linux/ssb/ssb.h
+++ b/include/linux/ssb/ssb.h
@@ -7,6 +7,7 @@
#include <linux/spinlock.h>
#include <linux/pci.h>
#include <linux/mod_devicetable.h>
+#include <linux/dma-mapping.h>
#include <linux/ssb/ssb_regs.h>
diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h
index 2ca6bae..fb0c215 100644
--- a/include/linux/xfrm.h
+++ b/include/linux/xfrm.h
@@ -339,6 +339,7 @@
#define XFRM_STATE_NOPMTUDISC 4
#define XFRM_STATE_WILDRECV 8
#define XFRM_STATE_ICMP 16
+#define XFRM_STATE_AF_UNSPEC 32
};
struct xfrm_usersa_id {
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 656442c..24a69f6 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -115,17 +115,17 @@
* The information provided in this structure is required for QoS
* transmit queue configuration. Cf. IEEE 802.11 7.3.2.29.
*
- * @aifs: arbitration interface space [0..255, -1: use default]
- * @cw_min: minimum contention window [will be a value of the form
- * 2^n-1 in the range 1..1023; 0: use default]
+ * @aifs: arbitration interface space [0..255]
+ * @cw_min: minimum contention window [a value of the form
+ * 2^n-1 in the range 1..32767]
* @cw_max: maximum contention window [like @cw_min]
* @txop: maximum burst time in units of 32 usecs, 0 meaning disabled
*/
struct ieee80211_tx_queue_params {
- s16 aifs;
+ u16 txop;
u16 cw_min;
u16 cw_max;
- u16 txop;
+ u8 aifs;
};
/**
@@ -239,6 +239,17 @@
* is for the whole aggregation.
* @IEEE80211_TX_STAT_AMPDU_NO_BACK: no block ack was returned,
* so consider using block ack request (BAR).
+ * @IEEE80211_TX_CTL_ASSIGN_SEQ: The driver has to assign a sequence
+ * number to this frame, taking care of not overwriting the fragment
+ * number and increasing the sequence number only when the
+ * IEEE80211_TX_CTL_FIRST_FRAGMENT flags is set. mac80211 will properly
+ * assign sequence numbers to QoS-data frames but cannot do so correctly
+ * for non-QoS-data and management frames because beacons need them from
+ * that counter as well and mac80211 cannot guarantee proper sequencing.
+ * If this flag is set, the driver should instruct the hardware to
+ * assign a sequence number to the frame or assign one itself. Cf. IEEE
+ * 802.11-2007 7.1.3.4.1 paragraph 3. This flag will always be set for
+ * beacons always be clear for frames without a sequence number field.
*/
enum mac80211_tx_control_flags {
IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0),
@@ -265,6 +276,7 @@
IEEE80211_TX_STAT_ACK = BIT(21),
IEEE80211_TX_STAT_AMPDU = BIT(22),
IEEE80211_TX_STAT_AMPDU_NO_BACK = BIT(23),
+ IEEE80211_TX_CTL_ASSIGN_SEQ = BIT(24),
};
@@ -407,11 +419,13 @@
* @IEEE80211_CONF_SHORT_SLOT_TIME: use 802.11g short slot time
* @IEEE80211_CONF_RADIOTAP: add radiotap header at receive time (if supported)
* @IEEE80211_CONF_SUPPORT_HT_MODE: use 802.11n HT capabilities (if supported)
+ * @IEEE80211_CONF_PS: Enable 802.11 power save mode
*/
enum ieee80211_conf_flags {
IEEE80211_CONF_SHORT_SLOT_TIME = (1<<0),
IEEE80211_CONF_RADIOTAP = (1<<1),
IEEE80211_CONF_SUPPORT_HT_MODE = (1<<2),
+ IEEE80211_CONF_PS = (1<<3),
};
/**
@@ -527,33 +541,38 @@
};
/**
+ * enum ieee80211_if_conf_change - interface config change flags
+ *
+ * @IEEE80211_IFCC_BSSID: The BSSID changed.
+ * @IEEE80211_IFCC_SSID: The SSID changed.
+ * @IEEE80211_IFCC_BEACON: The beacon for this interface changed
+ * (currently AP and MESH only), use ieee80211_beacon_get().
+ */
+enum ieee80211_if_conf_change {
+ IEEE80211_IFCC_BSSID = BIT(0),
+ IEEE80211_IFCC_SSID = BIT(1),
+ IEEE80211_IFCC_BEACON = BIT(2),
+};
+
+/**
* struct ieee80211_if_conf - configuration of an interface
*
- * @type: type of the interface. This is always the same as was specified in
- * &struct ieee80211_if_init_conf. The type of an interface never changes
- * during the life of the interface; this field is present only for
- * convenience.
+ * @changed: parameters that have changed, see &enum ieee80211_if_conf_change.
* @bssid: BSSID of the network we are associated to/creating.
* @ssid: used (together with @ssid_len) by drivers for hardware that
* generate beacons independently. The pointer is valid only during the
* config_interface() call, so copy the value somewhere if you need
* it.
* @ssid_len: length of the @ssid field.
- * @beacon: beacon template. Valid only if @host_gen_beacon_template in
- * &struct ieee80211_hw is set. The driver is responsible of freeing
- * the sk_buff.
- * @beacon_control: tx_control for the beacon template, this field is only
- * valid when the @beacon field was set.
*
* This structure is passed to the config_interface() callback of
* &struct ieee80211_hw.
*/
struct ieee80211_if_conf {
- int type;
+ u32 changed;
u8 *bssid;
u8 *ssid;
size_t ssid_len;
- struct sk_buff *beacon;
};
/**
@@ -681,15 +700,6 @@
* any particular flags. There are some exceptions to this rule,
* however, so you are advised to review these flags carefully.
*
- * @IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE:
- * The device only needs to be supplied with a beacon template.
- * If you need the host to generate each beacon then don't use
- * this flag and call ieee80211_beacon_get() when you need the
- * next beacon frame. Note that if you set this flag, you must
- * implement the set_tim() callback for powersave mode to work
- * properly.
- * This flag is only relevant for access-point mode.
- *
* @IEEE80211_HW_RX_INCLUDES_FCS:
* Indicates that received frames passed to the stack include
* the FCS at the end.
@@ -1149,17 +1159,6 @@
* function is optional if the firmware/hardware takes full care of
* TSF synchronization.
*
- * @beacon_update: Setup beacon data for IBSS beacons. Unlike access point,
- * IBSS uses a fixed beacon frame which is configured using this
- * function.
- * If the driver returns success (0) from this callback, it owns
- * the skb. That means the driver is responsible to kfree_skb() it.
- * The control structure is not dynamically allocated. That means the
- * driver does not own the pointer and if it needs it somewhere
- * outside of the context of this function, it must copy it
- * somewhere else.
- * This handler is required only for IBSS mode.
- *
* @tx_last_beacon: Determine whether the last IBSS beacon was sent by us.
* This is needed only for IBSS mode and the result of this function is
* used to determine whether to reply to Probe Requests.
@@ -1217,8 +1216,6 @@
struct ieee80211_tx_queue_stats *stats);
u64 (*get_tsf)(struct ieee80211_hw *hw);
void (*reset_tsf)(struct ieee80211_hw *hw);
- int (*beacon_update)(struct ieee80211_hw *hw,
- struct sk_buff *skb);
int (*tx_last_beacon)(struct ieee80211_hw *hw);
int (*ampdu_action)(struct ieee80211_hw *hw,
enum ieee80211_ampdu_mlme_action action,
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index d5d76ec..8f5b757 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -223,23 +223,23 @@
__nf_ct_refresh_acct(ct, 0, skb, extra_jiffies, 0);
}
-extern void __nf_ct_kill_acct(struct nf_conn *ct,
- enum ip_conntrack_info ctinfo,
- const struct sk_buff *skb,
- int do_acct);
+extern bool __nf_ct_kill_acct(struct nf_conn *ct,
+ enum ip_conntrack_info ctinfo,
+ const struct sk_buff *skb,
+ int do_acct);
/* kill conntrack and do accounting */
-static inline void nf_ct_kill_acct(struct nf_conn *ct,
- enum ip_conntrack_info ctinfo,
- const struct sk_buff *skb)
+static inline bool nf_ct_kill_acct(struct nf_conn *ct,
+ enum ip_conntrack_info ctinfo,
+ const struct sk_buff *skb)
{
- __nf_ct_kill_acct(ct, ctinfo, skb, 1);
+ return __nf_ct_kill_acct(ct, ctinfo, skb, 1);
}
/* kill conntrack without accounting */
-static inline void nf_ct_kill(struct nf_conn *ct)
+static inline bool nf_ct_kill(struct nf_conn *ct)
{
- __nf_ct_kill_acct(ct, 0, NULL, 0);
+ return __nf_ct_kill_acct(ct, 0, NULL, 0);
}
/* These are for NAT. Icky. */
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 8efa399..9efd3c6 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -518,19 +518,35 @@
if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) {
err = dev_unicast_add(real_dev, dev->dev_addr, ETH_ALEN);
if (err < 0)
- return err;
+ goto out;
}
- memcpy(vlan->real_dev_addr, real_dev->dev_addr, ETH_ALEN);
- if (dev->flags & IFF_ALLMULTI)
- dev_set_allmulti(real_dev, 1);
- if (dev->flags & IFF_PROMISC)
- dev_set_promiscuity(real_dev, 1);
+ if (dev->flags & IFF_ALLMULTI) {
+ err = dev_set_allmulti(real_dev, 1);
+ if (err < 0)
+ goto del_unicast;
+ }
+ if (dev->flags & IFF_PROMISC) {
+ err = dev_set_promiscuity(real_dev, 1);
+ if (err < 0)
+ goto clear_allmulti;
+ }
+
+ memcpy(vlan->real_dev_addr, real_dev->dev_addr, ETH_ALEN);
if (vlan->flags & VLAN_FLAG_GVRP)
vlan_gvrp_request_join(dev);
return 0;
+
+clear_allmulti:
+ if (dev->flags & IFF_ALLMULTI)
+ dev_set_allmulti(real_dev, -1);
+del_unicast:
+ if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr))
+ dev_unicast_delete(real_dev, dev->dev_addr, ETH_ALEN);
+out:
+ return err;
}
static int vlan_dev_stop(struct net_device *dev)
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 497df08..a072ea5 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -373,6 +373,10 @@
if (IS_ERR(p))
return PTR_ERR(p);
+ err = dev_set_promiscuity(dev, 1);
+ if (err)
+ goto put_back;
+
err = kobject_init_and_add(&p->kobj, &brport_ktype, &(dev->dev.kobj),
SYSFS_BRIDGE_PORT_ATTR);
if (err)
@@ -388,7 +392,6 @@
rcu_assign_pointer(dev->br_port, p);
dev_disable_lro(dev);
- dev_set_promiscuity(dev, 1);
list_add_rcu(&p->list, &br->port_list);
@@ -412,12 +415,12 @@
br_fdb_delete_by_port(br, p, 1);
err1:
kobject_del(&p->kobj);
- goto put_back;
err0:
kobject_put(&p->kobj);
-
+ dev_set_promiscuity(dev, -1);
put_back:
dev_put(dev);
+ kfree(p);
return err;
}
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index 3f79413..c1f4e0d 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -318,7 +318,7 @@
.attrs = netstat_attrs,
};
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_WIRELESS_EXT_SYSFS
/* helper function that does all the locking etc for wireless stats */
static ssize_t wireless_show(struct device *d, char *buf,
ssize_t (*format)(const struct iw_statistics *,
@@ -459,7 +459,7 @@
#ifdef CONFIG_SYSFS
*groups++ = &netstat_group;
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_WIRELESS_EXT_SYSFS
if (net->wireless_handlers && net->wireless_handlers->get_wireless_stats)
*groups++ = &wireless_group;
#endif
diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c
index a1929f3..f6756e0 100644
--- a/net/dccp/ccids/ccid3.c
+++ b/net/dccp/ccids/ccid3.c
@@ -794,7 +794,7 @@
{
struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
enum ccid3_fback_type do_feedback = CCID3_FBACK_NONE;
- const u32 ndp = dccp_sk(sk)->dccps_options_received.dccpor_ndp;
+ const u64 ndp = dccp_sk(sk)->dccps_options_received.dccpor_ndp;
const bool is_data_packet = dccp_data_packet(skb);
if (unlikely(hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA)) {
@@ -825,18 +825,16 @@
}
/*
- * Handle pending losses and otherwise check for new loss
+ * Perform loss detection and handle pending losses
*/
- if (tfrc_rx_hist_loss_pending(&hcrx->ccid3hcrx_hist) &&
- tfrc_rx_handle_loss(&hcrx->ccid3hcrx_hist,
- &hcrx->ccid3hcrx_li_hist,
- skb, ndp, ccid3_first_li, sk) ) {
+ if (tfrc_rx_handle_loss(&hcrx->ccid3hcrx_hist, &hcrx->ccid3hcrx_li_hist,
+ skb, ndp, ccid3_first_li, sk)) {
do_feedback = CCID3_FBACK_PARAM_CHANGE;
goto done_receiving;
}
- if (tfrc_rx_hist_new_loss_indicated(&hcrx->ccid3hcrx_hist, skb, ndp))
- goto update_records;
+ if (tfrc_rx_hist_loss_pending(&hcrx->ccid3hcrx_hist))
+ return; /* done receiving */
/*
* Handle data packets: RTT sampling and monitoring p
diff --git a/net/dccp/ccids/lib/loss_interval.c b/net/dccp/ccids/lib/loss_interval.c
index 849e181..bcd6ac4 100644
--- a/net/dccp/ccids/lib/loss_interval.c
+++ b/net/dccp/ccids/lib/loss_interval.c
@@ -90,14 +90,14 @@
{
struct tfrc_loss_interval *cur = tfrc_lh_peek(lh);
u32 old_i_mean = lh->i_mean;
- s64 length;
+ s64 len;
if (cur == NULL) /* not initialised */
return 0;
- length = dccp_delta_seqno(cur->li_seqno, DCCP_SKB_CB(skb)->dccpd_seq);
+ len = dccp_delta_seqno(cur->li_seqno, DCCP_SKB_CB(skb)->dccpd_seq) + 1;
- if (length - cur->li_length <= 0) /* duplicate or reordered */
+ if (len - (s64)cur->li_length <= 0) /* duplicate or reordered */
return 0;
if (SUB16(dccp_hdr(skb)->dccph_ccval, cur->li_ccval) > 4)
@@ -114,7 +114,7 @@
if (tfrc_lh_length(lh) == 1) /* due to RFC 3448, 6.3.1 */
return 0;
- cur->li_length = length;
+ cur->li_length = len;
tfrc_lh_calc_i_mean(lh);
return (lh->i_mean < old_i_mean);
@@ -159,7 +159,7 @@
else {
cur->li_length = dccp_delta_seqno(cur->li_seqno, new->li_seqno);
new->li_length = dccp_delta_seqno(new->li_seqno,
- tfrc_rx_hist_last_rcv(rh)->tfrchrx_seqno);
+ tfrc_rx_hist_last_rcv(rh)->tfrchrx_seqno) + 1;
if (lh->counter > (2*LIH_SIZE))
lh->counter -= LIH_SIZE;
diff --git a/net/dccp/ccids/lib/packet_history.c b/net/dccp/ccids/lib/packet_history.c
index 20af1a6..6cc108a 100644
--- a/net/dccp/ccids/lib/packet_history.c
+++ b/net/dccp/ccids/lib/packet_history.c
@@ -153,7 +153,7 @@
static inline void tfrc_rx_hist_entry_from_skb(struct tfrc_rx_hist_entry *entry,
const struct sk_buff *skb,
- const u32 ndp)
+ const u64 ndp)
{
const struct dccp_hdr *dh = dccp_hdr(skb);
@@ -166,7 +166,7 @@
void tfrc_rx_hist_add_packet(struct tfrc_rx_hist *h,
const struct sk_buff *skb,
- const u32 ndp)
+ const u64 ndp)
{
struct tfrc_rx_hist_entry *entry = tfrc_rx_hist_last_rcv(h);
@@ -206,31 +206,39 @@
*
* In the descriptions, `Si' refers to the sequence number of entry number i,
* whose NDP count is `Ni' (lower case is used for variables).
- * Note: All __after_loss functions expect that a test against duplicates has
- * been performed already: the seqno of the skb must not be less than the
- * seqno of loss_prev; and it must not equal that of any valid hist_entry.
+ * Note: All __xxx_loss functions expect that a test against duplicates has been
+ * performed already: the seqno of the skb must not be less than the seqno
+ * of loss_prev; and it must not equal that of any valid history entry.
*/
+static void __do_track_loss(struct tfrc_rx_hist *h, struct sk_buff *skb, u64 n1)
+{
+ u64 s0 = tfrc_rx_hist_loss_prev(h)->tfrchrx_seqno,
+ s1 = DCCP_SKB_CB(skb)->dccpd_seq;
+
+ if (!dccp_loss_free(s0, s1, n1)) { /* gap between S0 and S1 */
+ h->loss_count = 1;
+ tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_entry(h, 1), skb, n1);
+ }
+}
+
static void __one_after_loss(struct tfrc_rx_hist *h, struct sk_buff *skb, u32 n2)
{
u64 s0 = tfrc_rx_hist_loss_prev(h)->tfrchrx_seqno,
s1 = tfrc_rx_hist_entry(h, 1)->tfrchrx_seqno,
s2 = DCCP_SKB_CB(skb)->dccpd_seq;
- int n1 = tfrc_rx_hist_entry(h, 1)->tfrchrx_ndp,
- d12 = dccp_delta_seqno(s1, s2), d2;
- if (d12 > 0) { /* S1 < S2 */
+ if (likely(dccp_delta_seqno(s1, s2) > 0)) { /* S1 < S2 */
h->loss_count = 2;
tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_entry(h, 2), skb, n2);
return;
}
/* S0 < S2 < S1 */
- d2 = dccp_delta_seqno(s0, s2);
- if (d2 == 1 || n2 >= d2) { /* S2 is direct successor of S0 */
- int d21 = -d12;
+ if (dccp_loss_free(s0, s2, n2)) {
+ u64 n1 = tfrc_rx_hist_entry(h, 1)->tfrchrx_ndp;
- if (d21 == 1 || n1 >= d21) {
+ if (dccp_loss_free(s2, s1, n1)) {
/* hole is filled: S0, S2, and S1 are consecutive */
h->loss_count = 0;
h->loss_start = tfrc_rx_hist_index(h, 1);
@@ -238,9 +246,9 @@
/* gap between S2 and S1: just update loss_prev */
tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_loss_prev(h), skb, n2);
- } else { /* hole between S0 and S2 */
+ } else { /* gap between S0 and S2 */
/*
- * Reorder history to insert S2 between S0 and s1
+ * Reorder history to insert S2 between S0 and S1
*/
tfrc_rx_hist_swap(h, 0, 3);
h->loss_start = tfrc_rx_hist_index(h, 3);
@@ -256,22 +264,18 @@
s1 = tfrc_rx_hist_entry(h, 1)->tfrchrx_seqno,
s2 = tfrc_rx_hist_entry(h, 2)->tfrchrx_seqno,
s3 = DCCP_SKB_CB(skb)->dccpd_seq;
- int n1 = tfrc_rx_hist_entry(h, 1)->tfrchrx_ndp,
- d23 = dccp_delta_seqno(s2, s3), d13, d3, d31;
- if (d23 > 0) { /* S2 < S3 */
+ if (likely(dccp_delta_seqno(s2, s3) > 0)) { /* S2 < S3 */
h->loss_count = 3;
tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_entry(h, 3), skb, n3);
return 1;
}
/* S3 < S2 */
- d13 = dccp_delta_seqno(s1, s3);
- if (d13 > 0) {
+ if (dccp_delta_seqno(s1, s3) > 0) { /* S1 < S3 < S2 */
/*
- * The sequence number order is S1, S3, S2
- * Reorder history to insert entry between S1 and S2
+ * Reorder history to insert S3 between S1 and S2
*/
tfrc_rx_hist_swap(h, 2, 3);
tfrc_rx_hist_entry_from_skb(tfrc_rx_hist_entry(h, 2), skb, n3);
@@ -280,17 +284,15 @@
}
/* S0 < S3 < S1 */
- d31 = -d13;
- d3 = dccp_delta_seqno(s0, s3);
- if (d3 == 1 || n3 >= d3) { /* S3 is a successor of S0 */
+ if (dccp_loss_free(s0, s3, n3)) {
+ u64 n1 = tfrc_rx_hist_entry(h, 1)->tfrchrx_ndp;
- if (d31 == 1 || n1 >= d31) {
+ if (dccp_loss_free(s3, s1, n1)) {
/* hole between S0 and S1 filled by S3 */
- int d2 = dccp_delta_seqno(s1, s2),
- n2 = tfrc_rx_hist_entry(h, 2)->tfrchrx_ndp;
+ u64 n2 = tfrc_rx_hist_entry(h, 2)->tfrchrx_ndp;
- if (d2 == 1 || n2 >= d2) {
+ if (dccp_loss_free(s1, s2, n2)) {
/* entire hole filled by S0, S3, S1, S2 */
h->loss_start = tfrc_rx_hist_index(h, 2);
h->loss_count = 0;
@@ -307,8 +309,8 @@
}
/*
- * The remaining case: S3 is not a successor of S0.
- * Sequence order is S0, S3, S1, S2; reorder to insert between S0 and S1
+ * The remaining case: S0 < S3 < S1 < S2; gap between S0 and S3
+ * Reorder history to insert S3 between S0 and S1.
*/
tfrc_rx_hist_swap(h, 0, 3);
h->loss_start = tfrc_rx_hist_index(h, 3);
@@ -318,33 +320,25 @@
return 1;
}
-/* return the signed modulo-2^48 sequence number distance from entry e1 to e2 */
-static s64 tfrc_rx_hist_delta_seqno(struct tfrc_rx_hist *h, u8 e1, u8 e2)
-{
- DCCP_BUG_ON(e1 > h->loss_count || e2 > h->loss_count);
-
- return dccp_delta_seqno(tfrc_rx_hist_entry(h, e1)->tfrchrx_seqno,
- tfrc_rx_hist_entry(h, e2)->tfrchrx_seqno);
-}
-
/* recycle RX history records to continue loss detection if necessary */
static void __three_after_loss(struct tfrc_rx_hist *h)
{
/*
- * The distance between S0 and S1 is always greater than 1 and the NDP
- * count of S1 is smaller than this distance. Otherwise there would
- * have been no loss. Hence it is only necessary to see whether there
- * are further missing data packets between S1/S2 and S2/S3.
+ * At this stage we know already that there is a gap between S0 and S1
+ * (since S0 was the highest sequence number received before detecting
+ * the loss). To recycle the loss record, it is thus only necessary to
+ * check for other possible gaps between S1/S2 and between S2/S3.
*/
- int d2 = tfrc_rx_hist_delta_seqno(h, 1, 2),
- d3 = tfrc_rx_hist_delta_seqno(h, 2, 3),
- n2 = tfrc_rx_hist_entry(h, 2)->tfrchrx_ndp,
+ u64 s1 = tfrc_rx_hist_entry(h, 1)->tfrchrx_seqno,
+ s2 = tfrc_rx_hist_entry(h, 2)->tfrchrx_seqno,
+ s3 = tfrc_rx_hist_entry(h, 3)->tfrchrx_seqno;
+ u64 n2 = tfrc_rx_hist_entry(h, 2)->tfrchrx_ndp,
n3 = tfrc_rx_hist_entry(h, 3)->tfrchrx_ndp;
- if (d2 == 1 || n2 >= d2) { /* S2 is successor to S1 */
+ if (dccp_loss_free(s1, s2, n2)) {
- if (d3 == 1 || n3 >= d3) {
- /* S3 is successor of S2: entire hole is filled */
+ if (dccp_loss_free(s2, s3, n3)) {
+ /* no gap between S2 and S3: entire hole is filled */
h->loss_start = tfrc_rx_hist_index(h, 3);
h->loss_count = 0;
} else {
@@ -353,7 +347,7 @@
h->loss_count = 1;
}
- } else { /* gap between S1 and S2 */
+ } else { /* gap between S1 and S2 */
h->loss_start = tfrc_rx_hist_index(h, 1);
h->loss_count = 2;
}
@@ -370,15 +364,20 @@
* Chooses action according to pending loss, updates LI database when a new
* loss was detected, and does required post-processing. Returns 1 when caller
* should send feedback, 0 otherwise.
+ * Since it also takes care of reordering during loss detection and updates the
+ * records accordingly, the caller should not perform any more RX history
+ * operations when loss_count is greater than 0 after calling this function.
*/
int tfrc_rx_handle_loss(struct tfrc_rx_hist *h,
struct tfrc_loss_hist *lh,
- struct sk_buff *skb, u32 ndp,
+ struct sk_buff *skb, const u64 ndp,
u32 (*calc_first_li)(struct sock *), struct sock *sk)
{
int is_new_loss = 0;
- if (h->loss_count == 1) {
+ if (h->loss_count == 0) {
+ __do_track_loss(h, skb, ndp);
+ } else if (h->loss_count == 1) {
__one_after_loss(h, skb, ndp);
} else if (h->loss_count != 2) {
DCCP_BUG("invalid loss_count %d", h->loss_count);
diff --git a/net/dccp/ccids/lib/packet_history.h b/net/dccp/ccids/lib/packet_history.h
index c7eeda4..461cc91 100644
--- a/net/dccp/ccids/lib/packet_history.h
+++ b/net/dccp/ccids/lib/packet_history.h
@@ -64,7 +64,7 @@
u64 tfrchrx_seqno:48,
tfrchrx_ccval:4,
tfrchrx_type:4;
- u32 tfrchrx_ndp; /* In fact it is from 8 to 24 bits */
+ u64 tfrchrx_ndp:48;
ktime_t tfrchrx_tstamp;
};
@@ -118,41 +118,21 @@
return h->ring[h->loss_start];
}
-/* initialise loss detection and disable RTT sampling */
-static inline void tfrc_rx_hist_loss_indicated(struct tfrc_rx_hist *h)
-{
- h->loss_count = 1;
-}
-
/* indicate whether previously a packet was detected missing */
-static inline int tfrc_rx_hist_loss_pending(const struct tfrc_rx_hist *h)
+static inline bool tfrc_rx_hist_loss_pending(const struct tfrc_rx_hist *h)
{
- return h->loss_count;
-}
-
-/* any data packets missing between last reception and skb ? */
-static inline int tfrc_rx_hist_new_loss_indicated(struct tfrc_rx_hist *h,
- const struct sk_buff *skb,
- u32 ndp)
-{
- int delta = dccp_delta_seqno(tfrc_rx_hist_last_rcv(h)->tfrchrx_seqno,
- DCCP_SKB_CB(skb)->dccpd_seq);
-
- if (delta > 1 && ndp < delta)
- tfrc_rx_hist_loss_indicated(h);
-
- return tfrc_rx_hist_loss_pending(h);
+ return h->loss_count > 0;
}
extern void tfrc_rx_hist_add_packet(struct tfrc_rx_hist *h,
- const struct sk_buff *skb, const u32 ndp);
+ const struct sk_buff *skb, const u64 ndp);
extern int tfrc_rx_hist_duplicate(struct tfrc_rx_hist *h, struct sk_buff *skb);
struct tfrc_loss_hist;
extern int tfrc_rx_handle_loss(struct tfrc_rx_hist *h,
struct tfrc_loss_hist *lh,
- struct sk_buff *skb, u32 ndp,
+ struct sk_buff *skb, const u64 ndp,
u32 (*first_li)(struct sock *sk),
struct sock *sk);
extern u32 tfrc_rx_hist_sample_rtt(struct tfrc_rx_hist *h,
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h
index 1b2cea2..32617e0 100644
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -153,6 +153,21 @@
return after48(seq1, seq2) ? seq1 : seq2;
}
+/**
+ * dccp_loss_free - Evaluates condition for data loss from RFC 4340, 7.7.1
+ * @s1: start sequence number
+ * @s2: end sequence number
+ * @ndp: NDP count on packet with sequence number @s2
+ * Returns true if the sequence range s1...s2 has no data loss.
+ */
+static inline bool dccp_loss_free(const u64 s1, const u64 s2, const u64 ndp)
+{
+ s64 delta = dccp_delta_seqno(s1, s2);
+
+ BUG_TRAP(delta >= 0);
+ return (u64)delta <= ndp + 1;
+}
+
enum {
DCCP_MIB_NUM = 0,
DCCP_MIB_ACTIVEOPENS, /* ActiveOpens */
diff --git a/net/dccp/options.c b/net/dccp/options.c
index 43bc24e..dc7c158 100644
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -124,12 +124,12 @@
mandatory = 1;
break;
case DCCPO_NDP_COUNT:
- if (len > 3)
+ if (len > 6)
goto out_invalid_option;
opt_recv->dccpor_ndp = dccp_decode_value_var(value, len);
- dccp_pr_debug("%s rx opt: NDP count=%d\n", dccp_role(sk),
- opt_recv->dccpor_ndp);
+ dccp_pr_debug("%s opt: NDP count=%llu\n", dccp_role(sk),
+ (unsigned long long)opt_recv->dccpor_ndp);
break;
case DCCPO_CHANGE_L:
/* fall through */
@@ -307,9 +307,11 @@
*to++ = (value & 0xFF);
}
-static inline int dccp_ndp_len(const int ndp)
+static inline u8 dccp_ndp_len(const u64 ndp)
{
- return likely(ndp <= 0xFF) ? 1 : ndp <= 0xFFFF ? 2 : 3;
+ if (likely(ndp <= 0xFF))
+ return 1;
+ return likely(ndp <= USHORT_MAX) ? 2 : (ndp <= UINT_MAX ? 4 : 6);
}
int dccp_insert_option(struct sock *sk, struct sk_buff *skb,
@@ -336,7 +338,7 @@
static int dccp_insert_option_ndp(struct sock *sk, struct sk_buff *skb)
{
struct dccp_sock *dp = dccp_sk(sk);
- int ndp = dp->dccps_ndp_count;
+ u64 ndp = dp->dccps_ndp_count;
if (dccp_non_data_packet(skb))
++dp->dccps_ndp_count;
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index d16ae46..f155a66 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -1357,17 +1357,17 @@
t->stats.semantic_match_miss++;
#endif
if (err <= 0)
- return plen;
+ return err;
}
- return -1;
+ return 1;
}
static int fn_trie_lookup(struct fib_table *tb, const struct flowi *flp,
struct fib_result *res)
{
struct trie *t = (struct trie *) tb->tb_data;
- int plen, ret = 0;
+ int ret;
struct node *n;
struct tnode *pn;
int pos, bits;
@@ -1391,10 +1391,7 @@
/* Just a leaf? */
if (IS_LEAF(n)) {
- plen = check_leaf(t, (struct leaf *)n, key, flp, res);
- if (plen < 0)
- goto failed;
- ret = 0;
+ ret = check_leaf(t, (struct leaf *)n, key, flp, res);
goto found;
}
@@ -1419,11 +1416,9 @@
}
if (IS_LEAF(n)) {
- plen = check_leaf(t, (struct leaf *)n, key, flp, res);
- if (plen < 0)
+ ret = check_leaf(t, (struct leaf *)n, key, flp, res);
+ if (ret > 0)
goto backtrace;
-
- ret = 0;
goto found;
}
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 438fab9..c9ab47b 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -118,6 +118,31 @@
/* Service routines creating virtual interfaces: DVMRP tunnels and PIMREG */
+static void ipmr_del_tunnel(struct net_device *dev, struct vifctl *v)
+{
+ dev_close(dev);
+
+ dev = __dev_get_by_name(&init_net, "tunl0");
+ if (dev) {
+ struct ifreq ifr;
+ mm_segment_t oldfs;
+ struct ip_tunnel_parm p;
+
+ memset(&p, 0, sizeof(p));
+ p.iph.daddr = v->vifc_rmt_addr.s_addr;
+ p.iph.saddr = v->vifc_lcl_addr.s_addr;
+ p.iph.version = 4;
+ p.iph.ihl = 5;
+ p.iph.protocol = IPPROTO_IPIP;
+ sprintf(p.name, "dvmrp%d", v->vifc_vifi);
+ ifr.ifr_ifru.ifru_data = (__force void __user *)&p;
+
+ oldfs = get_fs(); set_fs(KERNEL_DS);
+ dev->do_ioctl(dev, &ifr, SIOCDELTUNNEL);
+ set_fs(oldfs);
+ }
+}
+
static
struct net_device *ipmr_new_tunnel(struct vifctl *v)
{
@@ -159,6 +184,7 @@
if (dev_open(dev))
goto failure;
+ dev_hold(dev);
}
}
return dev;
@@ -225,6 +251,8 @@
if (dev_open(dev))
goto failure;
+ dev_hold(dev);
+
return dev;
failure:
@@ -239,9 +267,10 @@
/*
* Delete a VIF entry
+ * @notify: Set to 1, if the caller is a notifier_call
*/
-static int vif_delete(int vifi)
+static int vif_delete(int vifi, int notify)
{
struct vif_device *v;
struct net_device *dev;
@@ -284,7 +313,7 @@
ip_rt_multicast_event(in_dev);
}
- if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER))
+ if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER) && !notify)
unregister_netdevice(dev);
dev_put(dev);
@@ -389,6 +418,7 @@
struct vif_device *v = &vif_table[vifi];
struct net_device *dev;
struct in_device *in_dev;
+ int err;
/* Is vif busy ? */
if (VIF_EXISTS(vifi))
@@ -406,18 +436,34 @@
dev = ipmr_reg_vif();
if (!dev)
return -ENOBUFS;
+ err = dev_set_allmulti(dev, 1);
+ if (err) {
+ unregister_netdevice(dev);
+ dev_put(dev);
+ return err;
+ }
break;
#endif
case VIFF_TUNNEL:
dev = ipmr_new_tunnel(vifc);
if (!dev)
return -ENOBUFS;
+ err = dev_set_allmulti(dev, 1);
+ if (err) {
+ ipmr_del_tunnel(dev, vifc);
+ dev_put(dev);
+ return err;
+ }
break;
case 0:
dev = ip_dev_find(&init_net, vifc->vifc_lcl_addr.s_addr);
if (!dev)
return -EADDRNOTAVAIL;
- dev_put(dev);
+ err = dev_set_allmulti(dev, 1);
+ if (err) {
+ dev_put(dev);
+ return err;
+ }
break;
default:
return -EINVAL;
@@ -426,7 +472,6 @@
if ((in_dev = __in_dev_get_rtnl(dev)) == NULL)
return -EADDRNOTAVAIL;
IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)++;
- dev_set_allmulti(dev, +1);
ip_rt_multicast_event(in_dev);
/*
@@ -449,7 +494,6 @@
/* And finish update writing critical data */
write_lock_bh(&mrt_lock);
- dev_hold(dev);
v->dev=dev;
#ifdef CONFIG_IP_PIMSM
if (v->flags&VIFF_REGISTER)
@@ -796,7 +840,7 @@
*/
for (i=0; i<maxvif; i++) {
if (!(vif_table[i].flags&VIFF_STATIC))
- vif_delete(i);
+ vif_delete(i, 0);
}
/*
@@ -909,7 +953,7 @@
if (optname==MRT_ADD_VIF) {
ret = vif_add(&vif, sk==mroute_socket);
} else {
- ret = vif_delete(vif.vifc_vifi);
+ ret = vif_delete(vif.vifc_vifi, 0);
}
rtnl_unlock();
return ret;
@@ -1088,7 +1132,7 @@
v=&vif_table[0];
for (ct=0;ct<maxvif;ct++,v++) {
if (v->dev==dev)
- vif_delete(ct);
+ vif_delete(ct, 1);
}
return NOTIFY_DONE;
}
diff --git a/net/ipv4/netfilter/nf_nat_snmp_basic.c b/net/ipv4/netfilter/nf_nat_snmp_basic.c
index 7750c97..ffeaffc 100644
--- a/net/ipv4/netfilter/nf_nat_snmp_basic.c
+++ b/net/ipv4/netfilter/nf_nat_snmp_basic.c
@@ -439,8 +439,8 @@
unsigned int *len)
{
unsigned long subid;
- unsigned int size;
unsigned long *optr;
+ size_t size;
size = eoc - ctx->pointer + 1;
diff --git a/net/ipv4/tcp_probe.c b/net/ipv4/tcp_probe.c
index 5ff0ce6..7ddc30f 100644
--- a/net/ipv4/tcp_probe.c
+++ b/net/ipv4/tcp_probe.c
@@ -224,7 +224,7 @@
if (bufsize < 0)
return -EINVAL;
- tcp_probe.log = kcalloc(sizeof(struct tcp_log), bufsize, GFP_KERNEL);
+ tcp_probe.log = kcalloc(bufsize, sizeof(struct tcp_log), GFP_KERNEL);
if (!tcp_probe.log)
goto err0;
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 602ea82..9f1084b 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -443,7 +443,7 @@
kfree_skb(skb);
return -1;
}
- if (!ipv6_chk_home_addr(&init_net, addr)) {
+ if (!ipv6_chk_home_addr(dev_net(skb->dst->dev), addr)) {
IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
IPSTATS_MIB_INADDRERRORS);
kfree_skb(skb);
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index cfac26d..0b41aa2 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -443,6 +443,7 @@
if (dev_open(dev))
goto failure;
+ dev_hold(dev);
return dev;
failure:
@@ -595,6 +596,7 @@
int vifi = vifc->mif6c_mifi;
struct mif_device *v = &vif6_table[vifi];
struct net_device *dev;
+ int err;
/* Is vif busy ? */
if (MIF_EXISTS(vifi))
@@ -612,20 +614,28 @@
dev = ip6mr_reg_vif();
if (!dev)
return -ENOBUFS;
+ err = dev_set_allmulti(dev, 1);
+ if (err) {
+ unregister_netdevice(dev);
+ dev_put(dev);
+ return err;
+ }
break;
#endif
case 0:
dev = dev_get_by_index(&init_net, vifc->mif6c_pifi);
if (!dev)
return -EADDRNOTAVAIL;
- dev_put(dev);
+ err = dev_set_allmulti(dev, 1);
+ if (err) {
+ dev_put(dev);
+ return err;
+ }
break;
default:
return -EINVAL;
}
- dev_set_allmulti(dev, 1);
-
/*
* Fill in the VIF structures
*/
@@ -644,7 +654,6 @@
/* And finish update writing critical data */
write_lock_bh(&mrt_lock);
- dev_hold(dev);
v->dev = dev;
#ifdef CONFIG_IPV6_PIMSM_V2
if (v->flags & MIFF_REGISTER)
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 8108728..8e7ba0e 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -50,14 +50,11 @@
struct ieee80211_sub_if_data *sdata;
int err;
- 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;
- err = ieee80211_if_add(local->mdev, name, &dev, itype, params);
+ err = ieee80211_if_add(local, name, &dev, itype, params);
if (err || itype != IEEE80211_IF_TYPE_MNTR || !flags)
return err;
@@ -68,54 +65,41 @@
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;
+ return -ENODEV;
- name = dev->name;
+ ieee80211_if_remove(dev);
- return ieee80211_if_remove(local->mdev, name, -1);
+ return 0;
}
static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
enum nl80211_iftype type, u32 *flags,
struct vif_params *params)
{
- 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;
+ int ret;
/* 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->vif.type == IEEE80211_IF_TYPE_VLAN)
- return -EOPNOTSUPP;
-
- ieee80211_if_reinit(dev);
- ieee80211_if_set_type(dev, itype);
+ ret = ieee80211_if_change_type(sdata, itype);
+ if (ret)
+ return ret;
if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len)
ieee80211_if_sta_set_mesh_id(&sdata->u.sta,
@@ -485,7 +469,7 @@
kfree(old);
- return ieee80211_if_config_beacon(sdata->dev);
+ return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
}
static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
@@ -539,7 +523,7 @@
synchronize_rcu();
kfree(old);
- return ieee80211_if_config_beacon(dev);
+ return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
}
/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index d20d90e..ee509f1 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -70,16 +70,6 @@
/* statistics stuff */
-static inline int rtnl_lock_local(struct ieee80211_local *local)
-{
- rtnl_lock();
- if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED)) {
- rtnl_unlock();
- return -ENODEV;
- }
- return 0;
-}
-
#define DEBUGFS_STATS_FILE(name, buflen, fmt, value...) \
DEBUGFS_READONLY_FILE(stats_ ##name, buflen, fmt, ##value)
@@ -96,10 +86,7 @@
if (!local->ops->get_stats)
return -EOPNOTSUPP;
- res = rtnl_lock_local(local);
- if (res)
- return res;
-
+ rtnl_lock();
res = local->ops->get_stats(local_to_hw(local), &stats);
rtnl_unlock();
if (!res)
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index b2089b2..475f89a 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -156,6 +156,8 @@
/* common attributes */
IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
+IEEE80211_IF_FILE(force_unicast_rateidx, force_unicast_rateidx, DEC);
+IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC);
/* STA/IBSS attributes */
IEEE80211_IF_FILE(state, u.sta.state, DEC);
@@ -191,8 +193,6 @@
IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC);
IEEE80211_IF_FILE(num_beacons, u.ap.num_beacons, DEC);
-IEEE80211_IF_FILE(force_unicast_rateidx, u.ap.force_unicast_rateidx, DEC);
-IEEE80211_IF_FILE(max_ratectrl_rateidx, u.ap.max_ratectrl_rateidx, DEC);
static ssize_t ieee80211_if_fmt_num_buffered_multicast(
const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
@@ -248,6 +248,9 @@
static void add_sta_files(struct ieee80211_sub_if_data *sdata)
{
DEBUGFS_ADD(drop_unencrypted, sta);
+ DEBUGFS_ADD(force_unicast_rateidx, ap);
+ DEBUGFS_ADD(max_ratectrl_rateidx, ap);
+
DEBUGFS_ADD(state, sta);
DEBUGFS_ADD(bssid, sta);
DEBUGFS_ADD(prev_bssid, sta);
@@ -268,23 +271,29 @@
static void add_ap_files(struct ieee80211_sub_if_data *sdata)
{
DEBUGFS_ADD(drop_unencrypted, ap);
+ DEBUGFS_ADD(force_unicast_rateidx, ap);
+ DEBUGFS_ADD(max_ratectrl_rateidx, ap);
+
DEBUGFS_ADD(num_sta_ps, ap);
DEBUGFS_ADD(dtim_count, ap);
DEBUGFS_ADD(num_beacons, ap);
- DEBUGFS_ADD(force_unicast_rateidx, ap);
- DEBUGFS_ADD(max_ratectrl_rateidx, ap);
DEBUGFS_ADD(num_buffered_multicast, ap);
}
static void add_wds_files(struct ieee80211_sub_if_data *sdata)
{
DEBUGFS_ADD(drop_unencrypted, wds);
+ DEBUGFS_ADD(force_unicast_rateidx, ap);
+ DEBUGFS_ADD(max_ratectrl_rateidx, ap);
+
DEBUGFS_ADD(peer, wds);
}
static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
{
DEBUGFS_ADD(drop_unencrypted, vlan);
+ DEBUGFS_ADD(force_unicast_rateidx, ap);
+ DEBUGFS_ADD(max_ratectrl_rateidx, ap);
}
static void add_monitor_files(struct ieee80211_sub_if_data *sdata)
@@ -372,6 +381,9 @@
static void del_sta_files(struct ieee80211_sub_if_data *sdata)
{
DEBUGFS_DEL(drop_unencrypted, sta);
+ DEBUGFS_DEL(force_unicast_rateidx, ap);
+ DEBUGFS_DEL(max_ratectrl_rateidx, ap);
+
DEBUGFS_DEL(state, sta);
DEBUGFS_DEL(bssid, sta);
DEBUGFS_DEL(prev_bssid, sta);
@@ -392,23 +404,29 @@
static void del_ap_files(struct ieee80211_sub_if_data *sdata)
{
DEBUGFS_DEL(drop_unencrypted, ap);
+ DEBUGFS_DEL(force_unicast_rateidx, ap);
+ DEBUGFS_DEL(max_ratectrl_rateidx, ap);
+
DEBUGFS_DEL(num_sta_ps, ap);
DEBUGFS_DEL(dtim_count, ap);
DEBUGFS_DEL(num_beacons, ap);
- DEBUGFS_DEL(force_unicast_rateidx, ap);
- DEBUGFS_DEL(max_ratectrl_rateidx, ap);
DEBUGFS_DEL(num_buffered_multicast, ap);
}
static void del_wds_files(struct ieee80211_sub_if_data *sdata)
{
DEBUGFS_DEL(drop_unencrypted, wds);
+ DEBUGFS_DEL(force_unicast_rateidx, ap);
+ DEBUGFS_DEL(max_ratectrl_rateidx, ap);
+
DEBUGFS_DEL(peer, wds);
}
static void del_vlan_files(struct ieee80211_sub_if_data *sdata)
{
DEBUGFS_DEL(drop_unencrypted, vlan);
+ DEBUGFS_DEL(force_unicast_rateidx, ap);
+ DEBUGFS_DEL(max_ratectrl_rateidx, ap);
}
static void del_monitor_files(struct ieee80211_sub_if_data *sdata)
@@ -458,12 +476,12 @@
}
#endif
-static void del_files(struct ieee80211_sub_if_data *sdata, int type)
+static void del_files(struct ieee80211_sub_if_data *sdata)
{
if (!sdata->debugfsdir)
return;
- switch (type) {
+ switch (sdata->vif.type) {
case IEEE80211_IF_TYPE_MESH_POINT:
#ifdef CONFIG_MAC80211_MESH
del_mesh_stats(sdata);
@@ -503,29 +521,23 @@
sprintf(buf, "netdev:%s", sdata->dev->name);
sdata->debugfsdir = debugfs_create_dir(buf,
sdata->local->hw.wiphy->debugfsdir);
+ add_files(sdata);
}
void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata)
{
- del_files(sdata, sdata->vif.type);
+ del_files(sdata);
debugfs_remove(sdata->debugfsdir);
sdata->debugfsdir = NULL;
}
-void ieee80211_debugfs_change_if_type(struct ieee80211_sub_if_data *sdata,
- int oldtype)
-{
- del_files(sdata, oldtype);
- add_files(sdata);
-}
-
static int netdev_notify(struct notifier_block *nb,
unsigned long state,
void *ndev)
{
struct net_device *dev = ndev;
struct dentry *dir;
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_sub_if_data *sdata;
char buf[10+IFNAMSIZ];
if (state != NETDEV_CHANGENAME)
@@ -537,6 +549,8 @@
if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid)
return 0;
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
sprintf(buf, "netdev:%s", dev->name);
dir = sdata->debugfsdir;
if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf))
diff --git a/net/mac80211/debugfs_netdev.h b/net/mac80211/debugfs_netdev.h
index a690071..7af731f 100644
--- a/net/mac80211/debugfs_netdev.h
+++ b/net/mac80211/debugfs_netdev.h
@@ -6,8 +6,6 @@
#ifdef CONFIG_MAC80211_DEBUGFS
void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata);
void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata);
-void ieee80211_debugfs_change_if_type(struct ieee80211_sub_if_data *sdata,
- int oldtype);
void ieee80211_debugfs_netdev_init(void);
void ieee80211_debugfs_netdev_exit(void);
#else
@@ -17,9 +15,6 @@
static inline void ieee80211_debugfs_remove_netdev(
struct ieee80211_sub_if_data *sdata)
{}
-static inline void ieee80211_debugfs_change_if_type(
- struct ieee80211_sub_if_data *sdata, int oldtype)
-{}
static inline void ieee80211_debugfs_netdev_init(void)
{}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 02a8753..cbea015 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -237,8 +237,6 @@
struct sk_buff_head ps_bc_buf;
atomic_t num_sta_ps; /* number of stations in PS mode */
int dtim_count;
- int force_unicast_rateidx; /* forced TX rateidx for unicast frames */
- int max_ratectrl_rateidx; /* max TX rateidx for rate control */
int num_beacons; /* number of TXed beacon frames for this BSS */
};
@@ -248,7 +246,6 @@
};
struct ieee80211_if_vlan {
- struct ieee80211_sub_if_data *ap;
struct list_head list;
};
@@ -422,8 +419,6 @@
*/
u64 basic_rates;
- u16 sequence;
-
/* Fragment table for host-based reassembly */
struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX];
unsigned int fragment_next;
@@ -432,16 +427,18 @@
struct ieee80211_key *keys[NUM_DEFAULT_KEYS];
struct ieee80211_key *default_key;
- /*
- * BSS configuration for this interface.
- *
- * FIXME: I feel bad putting this here when we already have a
- * bss pointer, but the bss pointer is just wrong when
- * you have multiple virtual STA mode interfaces...
- * This needs to be fixed.
- */
+ /* BSS configuration for this interface. */
struct ieee80211_bss_conf bss_conf;
- struct ieee80211_if_ap *bss; /* BSS that this device belongs to */
+
+ /*
+ * AP this belongs to: self in AP mode and
+ * corresponding AP in VLAN mode, NULL for
+ * all others (might be needed later in IBSS)
+ */
+ struct ieee80211_if_ap *bss;
+
+ int force_unicast_rateidx; /* forced TX rateidx for unicast frames */
+ int max_ratectrl_rateidx; /* max TX rateidx for rate control */
union {
struct ieee80211_if_ap ap;
@@ -533,8 +530,6 @@
return container_of(p, struct ieee80211_sub_if_data, vif);
}
-#define IEEE80211_DEV_TO_SUB_IF(dev) netdev_priv(dev)
-
enum {
IEEE80211_RX_MSG = 1,
IEEE80211_TX_STATUS_MSG = 2,
@@ -561,12 +556,6 @@
bool tim_in_locked_section; /* see ieee80211_beacon_get() */
int tx_headroom; /* required headroom for hardware/radiotap */
- enum {
- IEEE80211_DEV_UNINITIALIZED = 0,
- IEEE80211_DEV_REGISTERED,
- IEEE80211_DEV_UNREGISTERED,
- } reg_state;
-
/* Tasklet and skb queue to process calls from IRQ mode. All frames
* added to skb_queue will be processed, but frames in
* skb_queue_unreliable may be dropped if the total length of these
@@ -760,6 +749,16 @@
#endif
}
+static inline struct ieee80211_sub_if_data *
+IEEE80211_DEV_TO_SUB_IF(struct net_device *dev)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+ BUG_ON(!local || local->mdev == dev);
+
+ return netdev_priv(dev);
+}
+
/* this struct represents 802.11n's RA/TID combination */
struct ieee80211_ra_tid {
u8 ra[ETH_ALEN];
@@ -853,10 +852,8 @@
/* 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);
+int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed);
void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx);
-void ieee80211_if_setup(struct net_device *dev);
u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht,
struct ieee80211_ht_info *req_ht_cap,
struct ieee80211_ht_bss_info *req_bss_cap);
@@ -883,8 +880,8 @@
ieee80211_rx_result ieee80211_sta_rx_scan(
struct net_device *dev, struct sk_buff *skb,
struct ieee80211_rx_status *rx_status);
-void ieee80211_rx_bss_list_init(struct net_device *dev);
-void ieee80211_rx_bss_list_deinit(struct net_device *dev);
+void ieee80211_rx_bss_list_init(struct ieee80211_local *local);
+void ieee80211_rx_bss_list_deinit(struct ieee80211_local *local);
int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len);
struct sta_info *ieee80211_ibss_add_sta(struct net_device *dev,
struct sk_buff *skb, u8 *bssid,
@@ -925,17 +922,15 @@
{}
#endif
-/* ieee80211_iface.c */
-int ieee80211_if_add(struct net_device *dev, const char *name,
- struct net_device **new_dev, int type,
+/* interface handling */
+void ieee80211_if_setup(struct net_device *dev);
+int ieee80211_if_add(struct ieee80211_local *local, const char *name,
+ struct net_device **new_dev, enum ieee80211_if_types type,
struct vif_params *params);
-void ieee80211_if_set_type(struct net_device *dev, int type);
-void ieee80211_if_reinit(struct net_device *dev);
-void __ieee80211_if_del(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata);
-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_change_type(struct ieee80211_sub_if_data *sdata,
+ enum ieee80211_if_types type);
+void ieee80211_if_remove(struct net_device *dev);
+void ieee80211_remove_interfaces(struct ieee80211_local *local);
/* tx handling */
void ieee80211_clear_tx_pending(struct ieee80211_local *local);
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index eeb1692..610ed1d 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -2,6 +2,7 @@
* Copyright 2002-2005, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
* Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
+ * Copyright 2008, 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
@@ -17,37 +18,164 @@
#include "debugfs_netdev.h"
#include "mesh.h"
-void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata)
+/*
+ * Called when the netdev is removed or, by the code below, before
+ * the interface type changes.
+ */
+static void ieee80211_teardown_sdata(struct net_device *dev)
{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_local *local = sdata->local;
+ struct beacon_data *beacon;
+ struct sk_buff *skb;
+ int flushed;
int i;
- /* Default values for sub-interface parameters */
- sdata->drop_unencrypted = 0;
- for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
- skb_queue_head_init(&sdata->fragments[i].skb_list);
+ ieee80211_debugfs_remove_netdev(sdata);
- INIT_LIST_HEAD(&sdata->key_list);
-}
-
-static void ieee80211_if_sdata_deinit(struct ieee80211_sub_if_data *sdata)
-{
- int i;
+ /* free extra data */
+ ieee80211_free_keys(sdata);
for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
__skb_queue_purge(&sdata->fragments[i].skb_list);
+ sdata->fragment_next = 0;
+
+ switch (sdata->vif.type) {
+ case IEEE80211_IF_TYPE_AP:
+ beacon = sdata->u.ap.beacon;
+ rcu_assign_pointer(sdata->u.ap.beacon, NULL);
+ synchronize_rcu();
+ kfree(beacon);
+
+ while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
+ local->total_ps_buffered--;
+ dev_kfree_skb(skb);
+ }
+
+ break;
+ case IEEE80211_IF_TYPE_MESH_POINT:
+ /* Allow compiler to elide mesh_rmc_free call. */
+ if (ieee80211_vif_is_mesh(&sdata->vif))
+ mesh_rmc_free(dev);
+ /* fall through */
+ case IEEE80211_IF_TYPE_STA:
+ case IEEE80211_IF_TYPE_IBSS:
+ kfree(sdata->u.sta.extra_ie);
+ kfree(sdata->u.sta.assocreq_ies);
+ kfree(sdata->u.sta.assocresp_ies);
+ kfree_skb(sdata->u.sta.probe_resp);
+ break;
+ case IEEE80211_IF_TYPE_WDS:
+ case IEEE80211_IF_TYPE_VLAN:
+ case IEEE80211_IF_TYPE_MNTR:
+ break;
+ case IEEE80211_IF_TYPE_INVALID:
+ BUG();
+ break;
+ }
+
+ flushed = sta_info_flush(local, sdata);
+ WARN_ON(flushed);
}
-/* Must be called with rtnl lock held. */
-int ieee80211_if_add(struct net_device *dev, const char *name,
- struct net_device **new_dev, int type,
+/*
+ * Helper function to initialise an interface to a specific type.
+ */
+static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
+ enum ieee80211_if_types type)
+{
+ struct ieee80211_if_sta *ifsta;
+
+ /* clear type-dependent union */
+ memset(&sdata->u, 0, sizeof(sdata->u));
+
+ /* and set some type-dependent values */
+ sdata->vif.type = type;
+
+ /* only monitor differs */
+ sdata->dev->type = ARPHRD_ETHER;
+
+ switch (type) {
+ case IEEE80211_IF_TYPE_AP:
+ skb_queue_head_init(&sdata->u.ap.ps_bc_buf);
+ INIT_LIST_HEAD(&sdata->u.ap.vlans);
+ break;
+ case IEEE80211_IF_TYPE_MESH_POINT:
+ case IEEE80211_IF_TYPE_STA:
+ case IEEE80211_IF_TYPE_IBSS:
+ ifsta = &sdata->u.sta;
+ INIT_WORK(&ifsta->work, ieee80211_sta_work);
+ setup_timer(&ifsta->timer, ieee80211_sta_timer,
+ (unsigned long) sdata);
+ skb_queue_head_init(&ifsta->skb_queue);
+
+ ifsta->capab = WLAN_CAPABILITY_ESS;
+ ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN |
+ IEEE80211_AUTH_ALG_SHARED_KEY;
+ ifsta->flags |= IEEE80211_STA_CREATE_IBSS |
+ IEEE80211_STA_AUTO_BSSID_SEL |
+ IEEE80211_STA_AUTO_CHANNEL_SEL;
+ if (ieee80211_num_regular_queues(&sdata->local->hw) >= 4)
+ ifsta->flags |= IEEE80211_STA_WMM_ENABLED;
+
+ if (ieee80211_vif_is_mesh(&sdata->vif))
+ ieee80211_mesh_init_sdata(sdata);
+ break;
+ case IEEE80211_IF_TYPE_MNTR:
+ sdata->dev->type = ARPHRD_IEEE80211_RADIOTAP;
+ sdata->dev->hard_start_xmit = ieee80211_monitor_start_xmit;
+ sdata->u.mntr_flags = MONITOR_FLAG_CONTROL |
+ MONITOR_FLAG_OTHER_BSS;
+ break;
+ case IEEE80211_IF_TYPE_WDS:
+ case IEEE80211_IF_TYPE_VLAN:
+ break;
+ case IEEE80211_IF_TYPE_INVALID:
+ BUG();
+ break;
+ }
+
+ ieee80211_debugfs_add_netdev(sdata);
+}
+
+int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
+ enum ieee80211_if_types type)
+{
+ ASSERT_RTNL();
+
+ if (type == sdata->vif.type)
+ return 0;
+
+ /*
+ * We could, here, on changes between IBSS/STA/MESH modes,
+ * invoke an MLME function instead that disassociates etc.
+ * and goes into the requested mode.
+ */
+
+ if (netif_running(sdata->dev))
+ return -EBUSY;
+
+ /* Purge and reset type-dependent state. */
+ ieee80211_teardown_sdata(sdata->dev);
+ ieee80211_setup_sdata(sdata, type);
+
+ /* reset some values that shouldn't be kept across type changes */
+ sdata->basic_rates = 0;
+ sdata->drop_unencrypted = 0;
+
+ return 0;
+}
+
+int ieee80211_if_add(struct ieee80211_local *local, const char *name,
+ struct net_device **new_dev, enum ieee80211_if_types type,
struct vif_params *params)
{
struct net_device *ndev;
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sub_if_data *sdata = NULL;
- int ret;
+ int ret, i;
ASSERT_RTNL();
+
ndev = alloc_netdev(sizeof(*sdata) + local->hw.vif_data_size,
name, ieee80211_if_setup);
if (!ndev)
@@ -67,26 +195,33 @@
goto fail;
memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
- ndev->base_addr = dev->base_addr;
- ndev->irq = dev->irq;
- ndev->mem_start = dev->mem_start;
- ndev->mem_end = dev->mem_end;
SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));
- sdata = IEEE80211_DEV_TO_SUB_IF(ndev);
+ /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */
+ sdata = netdev_priv(ndev);
ndev->ieee80211_ptr = &sdata->wdev;
+
+ /* initialise type-independent data */
sdata->wdev.wiphy = local->hw.wiphy;
- sdata->vif.type = IEEE80211_IF_TYPE_AP;
- sdata->dev = ndev;
sdata->local = local;
- ieee80211_if_sdata_init(sdata);
+ sdata->dev = ndev;
+
+ for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
+ skb_queue_head_init(&sdata->fragments[i].skb_list);
+
+ INIT_LIST_HEAD(&sdata->key_list);
+
+ sdata->force_unicast_rateidx = -1;
+ sdata->max_ratectrl_rateidx = -1;
+
+ /* setup type-dependent data */
+ ieee80211_setup_sdata(sdata, type);
ret = register_netdevice(ndev);
if (ret)
goto fail;
- ieee80211_debugfs_add_netdev(sdata);
- ieee80211_if_set_type(ndev, type);
+ ndev->uninit = ieee80211_teardown_sdata;
if (ieee80211_vif_is_mesh(&sdata->vif) &&
params && params->mesh_id_len)
@@ -94,11 +229,6 @@
params->mesh_id_len,
params->mesh_id);
- /* we're under RTNL so all this is fine */
- if (unlikely(local->reg_state == IEEE80211_DEV_UNREGISTERED)) {
- __ieee80211_if_del(local, sdata);
- return -ENODEV;
- }
list_add_tail_rcu(&sdata->list, &local->interfaces);
if (new_dev)
@@ -106,218 +236,34 @@
return 0;
-fail:
+ fail:
free_netdev(ndev);
return ret;
}
-void ieee80211_if_set_type(struct net_device *dev, int type)
+void ieee80211_if_remove(struct net_device *dev)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- int oldtype = sdata->vif.type;
-
- /*
- * 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->vif.type = type;
-
- sdata->basic_rates = 0;
-
- switch (type) {
- case IEEE80211_IF_TYPE_WDS:
- /* nothing special */
- break;
- case IEEE80211_IF_TYPE_VLAN:
- sdata->u.vlan.ap = NULL;
- break;
- case IEEE80211_IF_TYPE_AP:
- sdata->u.ap.force_unicast_rateidx = -1;
- 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_MESH_POINT:
- case IEEE80211_IF_TYPE_STA:
- case IEEE80211_IF_TYPE_IBSS: {
- struct ieee80211_sub_if_data *msdata;
- struct ieee80211_if_sta *ifsta;
-
- ifsta = &sdata->u.sta;
- INIT_WORK(&ifsta->work, ieee80211_sta_work);
- setup_timer(&ifsta->timer, ieee80211_sta_timer,
- (unsigned long) sdata);
- skb_queue_head_init(&ifsta->skb_queue);
-
- ifsta->capab = WLAN_CAPABILITY_ESS;
- ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN |
- IEEE80211_AUTH_ALG_SHARED_KEY;
- ifsta->flags |= IEEE80211_STA_CREATE_IBSS |
- IEEE80211_STA_AUTO_BSSID_SEL |
- IEEE80211_STA_AUTO_CHANNEL_SEL;
- if (ieee80211_num_regular_queues(&sdata->local->hw) >= 4)
- ifsta->flags |= IEEE80211_STA_WMM_ENABLED;
-
- msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev);
- sdata->bss = &msdata->u.ap;
-
- if (ieee80211_vif_is_mesh(&sdata->vif))
- ieee80211_mesh_init_sdata(sdata);
- break;
- }
- case IEEE80211_IF_TYPE_MNTR:
- dev->type = ARPHRD_IEEE80211_RADIOTAP;
- dev->hard_start_xmit = ieee80211_monitor_start_xmit;
- sdata->u.mntr_flags = MONITOR_FLAG_CONTROL |
- MONITOR_FLAG_OTHER_BSS;
- break;
- case IEEE80211_IF_TYPE_INVALID:
- BUG();
- break;
- }
- ieee80211_debugfs_change_if_type(sdata, oldtype);
-}
-
-/* Must be called with rtnl lock held. */
-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 sk_buff *skb;
- int flushed;
ASSERT_RTNL();
- ieee80211_free_keys(sdata);
-
- ieee80211_if_sdata_deinit(sdata);
-
- /* Need to handle mesh specially to allow eliding the function call */
- if (ieee80211_vif_is_mesh(&sdata->vif))
- mesh_rmc_free(dev);
-
- switch (sdata->vif.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;
- struct beacon_data *beacon;
-
- 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_del_rcu(&tsdata->list);
- /*
- * We have lots of time and can afford
- * to sync for each interface
- */
- synchronize_rcu();
- __ieee80211_if_del(local, tsdata);
- }
- }
-
- beacon = sdata->u.ap.beacon;
- rcu_assign_pointer(sdata->u.ap.beacon, NULL);
- synchronize_rcu();
- kfree(beacon);
-
- while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
- local->total_ps_buffered--;
- dev_kfree_skb(skb);
- }
-
- break;
- }
- case IEEE80211_IF_TYPE_WDS:
- /* nothing to do */
- break;
- case IEEE80211_IF_TYPE_MESH_POINT:
- case IEEE80211_IF_TYPE_STA:
- case IEEE80211_IF_TYPE_IBSS:
- kfree(sdata->u.sta.extra_ie);
- sdata->u.sta.extra_ie = NULL;
- kfree(sdata->u.sta.assocreq_ies);
- sdata->u.sta.assocreq_ies = NULL;
- kfree(sdata->u.sta.assocresp_ies);
- sdata->u.sta.assocresp_ies = NULL;
- if (sdata->u.sta.probe_resp) {
- dev_kfree_skb(sdata->u.sta.probe_resp);
- sdata->u.sta.probe_resp = NULL;
- }
-
- break;
- case IEEE80211_IF_TYPE_MNTR:
- dev->type = ARPHRD_ETHER;
- break;
- case IEEE80211_IF_TYPE_VLAN:
- sdata->u.vlan.ap = NULL;
- break;
- }
-
- flushed = sta_info_flush(local, sdata);
- WARN_ON(flushed);
-
- memset(&sdata->u, 0, sizeof(sdata->u));
- ieee80211_if_sdata_init(sdata);
-}
-
-/* Must be called with rtnl lock held. */
-void __ieee80211_if_del(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata)
-{
- struct net_device *dev = sdata->dev;
-
- ieee80211_debugfs_remove_netdev(sdata);
+ list_del_rcu(&sdata->list);
+ synchronize_rcu();
unregister_netdevice(dev);
- /* Except master interface, the net_device will be freed by
- * net_device->destructor (i. e. ieee80211_if_free). */
}
-/* Must be called with rtnl lock held. */
-int ieee80211_if_remove(struct net_device *dev, const char *name, int id)
+/*
+ * Remove all interfaces, may only be called at hardware unregistration
+ * time because it doesn't do RCU-safe list removals.
+ */
+void ieee80211_remove_interfaces(struct ieee80211_local *local)
{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_sub_if_data *sdata, *n;
+ struct ieee80211_sub_if_data *sdata, *tmp;
ASSERT_RTNL();
- list_for_each_entry_safe(sdata, n, &local->interfaces, list) {
- if ((sdata->vif.type == id || id == -1) &&
- strcmp(name, sdata->dev->name) == 0 &&
- sdata->dev != local->mdev) {
- list_del_rcu(&sdata->list);
- synchronize_rcu();
- __ieee80211_if_del(local, sdata);
- return 0;
- }
+ list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) {
+ list_del(&sdata->list);
+ unregister_netdevice(sdata->dev);
}
- return -ENODEV;
-}
-
-void ieee80211_if_free(struct net_device *dev)
-{
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
- ieee80211_if_sdata_deinit(sdata);
- free_netdev(dev);
}
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 1c4d3ba..36859e7 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -105,7 +105,7 @@
/* 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)) {
+ if (netif_running(sdata->dev)) {
res = 0;
break;
}
@@ -126,7 +126,7 @@
/* 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))
+ if (netif_running(sdata->dev))
dev_close(sdata->dev);
return 0;
@@ -194,7 +194,7 @@
list_for_each_entry(nsdata, &local->interfaces, list) {
struct net_device *ndev = nsdata->dev;
- if (ndev != dev && ndev != local->mdev && netif_running(ndev)) {
+ if (ndev != dev && netif_running(ndev)) {
/*
* Allow only a single IBSS interface to be up at any
* time. This is restricted because beacon distribution
@@ -210,30 +210,6 @@
return -EBUSY;
/*
- * Disallow multiple IBSS/STA mode interfaces.
- *
- * This is a technical restriction, it is possible although
- * most likely not IEEE 802.11 compliant to have multiple
- * STAs with just a single hardware (the TSF timer will not
- * be adjusted properly.)
- *
- * However, because mac80211 uses the master device's BSS
- * information for each STA/IBSS interface, doing this will
- * currently corrupt that BSS information completely, unless,
- * a not very useful case, both STAs are associated to the
- * same BSS.
- *
- * To remove this restriction, the BSS information needs to
- * be embedded in the STA/IBSS mode sdata instead of using
- * the master device's BSS structure.
- */
- if ((sdata->vif.type == IEEE80211_IF_TYPE_STA ||
- sdata->vif.type == IEEE80211_IF_TYPE_IBSS) &&
- (nsdata->vif.type == IEEE80211_IF_TYPE_STA ||
- nsdata->vif.type == IEEE80211_IF_TYPE_IBSS))
- return -EBUSY;
-
- /*
* The remaining checks are only performed for interfaces
* with the same MAC address.
*/
@@ -252,7 +228,7 @@
*/
if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN &&
nsdata->vif.type == IEEE80211_IF_TYPE_AP)
- sdata->u.vlan.ap = nsdata;
+ sdata->bss = &nsdata->u.ap;
}
}
@@ -262,10 +238,13 @@
return -ENOLINK;
break;
case IEEE80211_IF_TYPE_VLAN:
- if (!sdata->u.vlan.ap)
+ if (!sdata->bss)
return -ENOLINK;
+ list_add(&sdata->u.vlan.list, &sdata->bss->vlans);
break;
case IEEE80211_IF_TYPE_AP:
+ sdata->bss = &sdata->u.ap;
+ break;
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_MNTR:
case IEEE80211_IF_TYPE_IBSS:
@@ -283,14 +262,13 @@
if (local->ops->start)
res = local->ops->start(local_to_hw(local));
if (res)
- return res;
+ goto err_del_bss;
need_hw_reconfig = 1;
ieee80211_led_radio(local, local->hw.conf.radio_enabled);
}
switch (sdata->vif.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:
@@ -329,7 +307,8 @@
if (res)
goto err_stop;
- ieee80211_if_config(dev);
+ if (ieee80211_vif_is_mesh(&sdata->vif))
+ ieee80211_start_mesh(sdata->dev);
changed |= ieee80211_reset_erp_info(dev);
ieee80211_bss_info_change_notify(sdata, changed);
ieee80211_enable_keys(sdata);
@@ -404,6 +383,10 @@
err_stop:
if (!local->open_count && local->ops->stop)
local->ops->stop(local_to_hw(local));
+ err_del_bss:
+ sdata->bss = NULL;
+ if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
+ list_del(&sdata->u.vlan.list);
return res;
}
@@ -486,7 +469,6 @@
switch (sdata->vif.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:
@@ -549,6 +531,8 @@
local->ops->remove_interface(local_to_hw(local), &conf);
}
+ sdata->bss = NULL;
+
if (local->open_count == 0) {
if (netif_running(local->mdev))
dev_close(local->mdev);
@@ -988,7 +972,6 @@
.cache_update = eth_header_cache_update,
};
-/* Must not be called for mdev */
void ieee80211_if_setup(struct net_device *dev)
{
ether_setup(dev);
@@ -998,64 +981,54 @@
dev->change_mtu = ieee80211_change_mtu;
dev->open = ieee80211_open;
dev->stop = ieee80211_stop;
- dev->destructor = ieee80211_if_free;
+ dev->destructor = free_netdev;
}
/* everything else */
-static int __ieee80211_if_config(struct net_device *dev,
- struct sk_buff *beacon)
+int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed)
{
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_local *local = sdata->local;
struct ieee80211_if_conf conf;
- if (!local->ops->config_interface || !netif_running(dev))
+ if (WARN_ON(!netif_running(sdata->dev)))
+ return 0;
+
+ if (!local->ops->config_interface)
return 0;
memset(&conf, 0, sizeof(conf));
- conf.type = sdata->vif.type;
+ conf.changed = changed;
+
if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
conf.bssid = sdata->u.sta.bssid;
conf.ssid = sdata->u.sta.ssid;
conf.ssid_len = sdata->u.sta.ssid_len;
- } else if (ieee80211_vif_is_mesh(&sdata->vif)) {
- conf.beacon = beacon;
- ieee80211_start_mesh(dev);
} else if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
+ conf.bssid = sdata->dev->dev_addr;
conf.ssid = sdata->u.ap.ssid;
conf.ssid_len = sdata->u.ap.ssid_len;
- conf.beacon = beacon;
+ } else if (ieee80211_vif_is_mesh(&sdata->vif)) {
+ u8 zero[ETH_ALEN] = { 0 };
+ conf.bssid = zero;
+ conf.ssid = zero;
+ conf.ssid_len = 0;
+ } else {
+ WARN_ON(1);
+ return -EINVAL;
}
+
+ if (WARN_ON(!conf.bssid && (changed & IEEE80211_IFCC_BSSID)))
+ return -EINVAL;
+
+ if (WARN_ON(!conf.ssid && (changed & IEEE80211_IFCC_SSID)))
+ return -EINVAL;
+
return local->ops->config_interface(local_to_hw(local),
&sdata->vif, &conf);
}
-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);
- if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT &&
- (local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE))
- return ieee80211_if_config_beacon(dev);
- return __ieee80211_if_config(dev, NULL);
-}
-
-int ieee80211_if_config_beacon(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 sk_buff *skb;
-
- if (!(local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE))
- return 0;
- skb = ieee80211_beacon_get(local_to_hw(local), &sdata->vif);
- if (!skb)
- return -ENOMEM;
- return __ieee80211_if_config(dev, skb);
-}
-
int ieee80211_hw_config(struct ieee80211_local *local)
{
struct ieee80211_channel *chan;
@@ -1659,7 +1632,7 @@
int result;
enum ieee80211_band band;
struct net_device *mdev;
- struct ieee80211_sub_if_data *sdata;
+ struct wireless_dev *mwdev;
/*
* generic code guarantees at least one band,
@@ -1699,8 +1672,7 @@
hw->ampdu_queues = 0;
#endif
- /* for now, mdev needs sub_if_data :/ */
- mdev = alloc_netdev_mq(sizeof(struct ieee80211_sub_if_data),
+ mdev = alloc_netdev_mq(sizeof(struct wireless_dev),
"wmaster%d", ether_setup,
ieee80211_num_queues(hw));
if (!mdev)
@@ -1709,13 +1681,13 @@
if (ieee80211_num_queues(hw) > 1)
mdev->features |= NETIF_F_MULTI_QUEUE;
- sdata = IEEE80211_DEV_TO_SUB_IF(mdev);
- mdev->ieee80211_ptr = &sdata->wdev;
- sdata->wdev.wiphy = local->hw.wiphy;
+ mwdev = netdev_priv(mdev);
+ mdev->ieee80211_ptr = mwdev;
+ mwdev->wiphy = local->hw.wiphy;
local->mdev = mdev;
- ieee80211_rx_bss_list_init(mdev);
+ ieee80211_rx_bss_list_init(local);
mdev->hard_start_xmit = ieee80211_master_start_xmit;
mdev->open = ieee80211_master_open;
@@ -1724,16 +1696,6 @@
mdev->header_ops = &ieee80211_header_ops;
mdev->set_multicast_list = ieee80211_master_set_multicast_list;
- sdata->vif.type = IEEE80211_IF_TYPE_AP;
- sdata->dev = mdev;
- sdata->local = local;
- sdata->u.ap.force_unicast_rateidx = -1;
- sdata->u.ap.max_ratectrl_rateidx = -1;
- ieee80211_if_sdata_init(sdata);
-
- /* no RCU needed since we're still during init phase */
- list_add_tail(&sdata->list, &local->interfaces);
-
name = wiphy_dev(local->hw.wiphy)->driver->name;
local->hw.workqueue = create_freezeable_workqueue(name);
if (!local->hw.workqueue) {
@@ -1779,9 +1741,6 @@
if (result < 0)
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,
hw->rate_control_algorithm);
if (result < 0) {
@@ -1801,13 +1760,12 @@
ieee80211_install_qdisc(local->mdev);
/* add one default STA interface */
- result = ieee80211_if_add(local->mdev, "wlan%d", NULL,
+ result = ieee80211_if_add(local, "wlan%d", NULL,
IEEE80211_IF_TYPE_STA, NULL);
if (result)
printk(KERN_WARNING "%s: Failed to add default virtual iface\n",
wiphy_name(local->hw.wiphy));
- local->reg_state = IEEE80211_DEV_REGISTERED;
rtnl_unlock();
ieee80211_led_init(local);
@@ -1817,7 +1775,6 @@
fail_wep:
rate_control_deinitialize(local);
fail_rate:
- ieee80211_debugfs_remove_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev));
unregister_netdevice(local->mdev);
local->mdev = NULL;
fail_dev:
@@ -1827,10 +1784,8 @@
debugfs_hw_del(local);
destroy_workqueue(local->hw.workqueue);
fail_workqueue:
- if (local->mdev != NULL) {
- ieee80211_if_free(local->mdev);
- local->mdev = NULL;
- }
+ if (local->mdev)
+ free_netdev(local->mdev);
fail_mdev_alloc:
wiphy_unregister(local->hw.wiphy);
return result;
@@ -1840,42 +1795,27 @@
void ieee80211_unregister_hw(struct ieee80211_hw *hw)
{
struct ieee80211_local *local = hw_to_local(hw);
- struct ieee80211_sub_if_data *sdata, *tmp;
tasklet_kill(&local->tx_pending_tasklet);
tasklet_kill(&local->tasklet);
rtnl_lock();
- BUG_ON(local->reg_state != IEEE80211_DEV_REGISTERED);
-
- local->reg_state = IEEE80211_DEV_UNREGISTERED;
-
/*
* At this point, interface list manipulations are fine
* because the driver cannot be handing us frames any
* more and the tasklet is killed.
*/
- /*
- * 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);
- }
+ /* First, we remove all virtual interfaces. */
+ ieee80211_remove_interfaces(local);
/* then, finally, remove the master interface */
- __ieee80211_if_del(local, IEEE80211_DEV_TO_SUB_IF(local->mdev));
+ unregister_netdevice(local->mdev);
rtnl_unlock();
- ieee80211_rx_bss_list_deinit(local->mdev);
+ ieee80211_rx_bss_list_deinit(local);
ieee80211_clear_tx_pending(local);
sta_info_stop(local);
rate_control_deinitialize(local);
@@ -1892,8 +1832,7 @@
wiphy_unregister(local->hw.wiphy);
ieee80211_wep_free(local);
ieee80211_led_exit(local);
- ieee80211_if_free(local->mdev);
- local->mdev = NULL;
+ free_netdev(local->mdev);
}
EXPORT_SYMBOL(ieee80211_unregister_hw);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index dbc8cf4..8f51375 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -78,7 +78,7 @@
static struct ieee80211_sta_bss *
ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq,
u8 *ssid, u8 ssid_len);
-static void ieee80211_rx_bss_put(struct net_device *dev,
+static void ieee80211_rx_bss_put(struct ieee80211_local *local,
struct ieee80211_sta_bss *bss);
static int ieee80211_sta_find_ibss(struct net_device *dev,
struct ieee80211_if_sta *ifsta);
@@ -345,7 +345,7 @@
params.aifs = pos[0] & 0x0f;
params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4);
params.cw_min = ecw2cw(pos[1] & 0x0f);
- params.txop = pos[2] | (pos[3] << 8);
+ params.txop = get_unaligned_le16(pos + 2);
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d "
"cWmin=%d cWmax=%d txop=%d\n",
@@ -554,7 +554,7 @@
changed |= ieee80211_handle_bss_capability(sdata, bss);
- ieee80211_rx_bss_put(dev, bss);
+ ieee80211_rx_bss_put(local, bss);
}
if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
@@ -760,7 +760,7 @@
(local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT))
capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
- ieee80211_rx_bss_put(dev, bss);
+ ieee80211_rx_bss_put(local, bss);
} else {
rates = ~0;
rates_len = sband->n_bitrates;
@@ -992,7 +992,7 @@
wep_privacy = !!ieee80211_sta_wep_configured(dev);
privacy_invoked = !!(ifsta->flags & IEEE80211_STA_PRIVACY_INVOKED);
- ieee80211_rx_bss_put(dev, bss);
+ ieee80211_rx_bss_put(local, bss);
if ((bss_privacy == wep_privacy) || (bss_privacy == privacy_invoked))
return 0;
@@ -2094,7 +2094,7 @@
sta->last_signal = bss->signal;
sta->last_qual = bss->qual;
sta->last_noise = bss->noise;
- ieee80211_rx_bss_put(dev, bss);
+ ieee80211_rx_bss_put(local, bss);
}
err = sta_info_insert(sta);
@@ -2212,10 +2212,9 @@
/* Caller must hold local->sta_bss_lock */
-static void __ieee80211_rx_bss_hash_del(struct net_device *dev,
+static void __ieee80211_rx_bss_hash_del(struct ieee80211_local *local,
struct ieee80211_sta_bss *bss)
{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sta_bss *b, *prev = NULL;
b = local->sta_bss_hash[STA_HASH(bss->bssid)];
while (b) {
@@ -2367,39 +2366,35 @@
}
-static void ieee80211_rx_bss_put(struct net_device *dev,
+static void ieee80211_rx_bss_put(struct ieee80211_local *local,
struct ieee80211_sta_bss *bss)
{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
local_bh_disable();
if (!atomic_dec_and_lock(&bss->users, &local->sta_bss_lock)) {
local_bh_enable();
return;
}
- __ieee80211_rx_bss_hash_del(dev, bss);
+ __ieee80211_rx_bss_hash_del(local, bss);
list_del(&bss->list);
spin_unlock_bh(&local->sta_bss_lock);
ieee80211_rx_bss_free(bss);
}
-void ieee80211_rx_bss_list_init(struct net_device *dev)
+void ieee80211_rx_bss_list_init(struct ieee80211_local *local)
{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
spin_lock_init(&local->sta_bss_lock);
INIT_LIST_HEAD(&local->sta_bss_list);
}
-void ieee80211_rx_bss_list_deinit(struct net_device *dev)
+void ieee80211_rx_bss_list_deinit(struct ieee80211_local *local)
{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sta_bss *bss, *tmp;
list_for_each_entry_safe(bss, tmp, &local->sta_bss_list, list)
- ieee80211_rx_bss_put(dev, bss);
+ ieee80211_rx_bss_put(local, bss);
}
@@ -2411,8 +2406,6 @@
int res, rates, i, j;
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
- struct ieee80211_tx_info *control;
- struct rate_selection ratesel;
u8 *pos;
struct ieee80211_sub_if_data *sdata;
struct ieee80211_supported_band *sband;
@@ -2430,7 +2423,7 @@
local->ops->reset_tsf(local_to_hw(local));
}
memcpy(ifsta->bssid, bss->bssid, ETH_ALEN);
- res = ieee80211_if_config(dev);
+ res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID);
if (res)
return res;
@@ -2444,19 +2437,16 @@
if (res)
return res;
- /* Set beacon template */
+ /* Build IBSS probe response */
skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
- do {
- if (!skb)
- break;
-
+ if (skb) {
skb_reserve(skb, local->hw.extra_tx_headroom);
mgmt = (struct ieee80211_mgmt *)
skb_put(skb, 24 + sizeof(mgmt->u.beacon));
memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
- IEEE80211_STYPE_BEACON);
+ IEEE80211_STYPE_PROBE_RESP);
memset(mgmt->da, 0xff, ETH_ALEN);
memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
@@ -2500,62 +2490,23 @@
memcpy(pos, &bss->supp_rates[8], rates);
}
- control = IEEE80211_SKB_CB(skb);
+ ifsta->probe_resp = skb;
- rate_control_get_rate(dev, sband, skb, &ratesel);
- if (ratesel.rate_idx < 0) {
- printk(KERN_DEBUG "%s: Failed to determine TX rate "
- "for IBSS beacon\n", dev->name);
- break;
- }
- control->control.vif = &sdata->vif;
- control->tx_rate_idx = ratesel.rate_idx;
- if (sdata->bss_conf.use_short_preamble &&
- sband->bitrates[ratesel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE)
- control->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE;
- control->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
- control->flags |= IEEE80211_TX_CTL_NO_ACK;
- control->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
- control->control.retry_limit = 1;
-
- ifsta->probe_resp = skb_copy(skb, GFP_ATOMIC);
- if (ifsta->probe_resp) {
- mgmt = (struct ieee80211_mgmt *)
- ifsta->probe_resp->data;
- mgmt->frame_control =
- IEEE80211_FC(IEEE80211_FTYPE_MGMT,
- IEEE80211_STYPE_PROBE_RESP);
- } else {
- printk(KERN_DEBUG "%s: Could not allocate ProbeResp "
- "template for IBSS\n", dev->name);
- }
-
- if (local->ops->beacon_update &&
- local->ops->beacon_update(local_to_hw(local), skb) == 0) {
- printk(KERN_DEBUG "%s: Configured IBSS beacon "
- "template\n", dev->name);
- skb = NULL;
- }
-
- rates = 0;
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
- for (i = 0; i < bss->supp_rates_len; i++) {
- int bitrate = (bss->supp_rates[i] & 0x7f) * 5;
- for (j = 0; j < sband->n_bitrates; j++)
- if (sband->bitrates[j].bitrate == bitrate)
- rates |= BIT(j);
- }
- ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates;
-
- ieee80211_sta_def_wmm_params(dev, bss, 1);
- } while (0);
-
- if (skb) {
- printk(KERN_DEBUG "%s: Failed to configure IBSS beacon "
- "template\n", dev->name);
- dev_kfree_skb(skb);
+ ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
}
+ rates = 0;
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+ for (i = 0; i < bss->supp_rates_len; i++) {
+ int bitrate = (bss->supp_rates[i] & 0x7f) * 5;
+ for (j = 0; j < sband->n_bitrates; j++)
+ if (sband->bitrates[j].bitrate == bitrate)
+ rates |= BIT(j);
+ }
+ ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates;
+
+ ieee80211_sta_def_wmm_params(dev, bss, 1);
+
ifsta->state = IEEE80211_IBSS_JOINED;
mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
@@ -2775,7 +2726,7 @@
*/
if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
bss->probe_resp && beacon) {
- ieee80211_rx_bss_put(dev, bss);
+ ieee80211_rx_bss_put(local, bss);
return;
}
@@ -2918,7 +2869,7 @@
}
}
- ieee80211_rx_bss_put(dev, bss);
+ ieee80211_rx_bss_put(local, bss);
}
@@ -3338,7 +3289,7 @@
free_plinks = mesh_plink_availables(sdata);
if (free_plinks != sdata->u.sta.accepting_plinks)
- ieee80211_if_config_beacon(dev);
+ ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
mod_timer(&ifsta->timer, jiffies +
IEEE80211_MESH_HOUSEKEEPING_INTERVAL);
@@ -3578,7 +3529,7 @@
selected->ssid_len);
ieee80211_sta_set_bssid(dev, selected->bssid);
ieee80211_sta_def_wmm_params(dev, selected, 0);
- ieee80211_rx_bss_put(dev, selected);
+ ieee80211_rx_bss_put(local, selected);
ifsta->state = IEEE80211_AUTHENTICATE;
ieee80211_sta_reset_auth(dev, ifsta);
return 0;
@@ -3655,7 +3606,7 @@
}
ret = ieee80211_sta_join_ibss(dev, ifsta, bss);
- ieee80211_rx_bss_put(dev, bss);
+ ieee80211_rx_bss_put(local, bss);
return ret;
}
@@ -3711,7 +3662,7 @@
" based on configured SSID\n",
dev->name, print_mac(mac, bssid));
ret = ieee80211_sta_join_ibss(dev, ifsta, bss);
- ieee80211_rx_bss_put(dev, bss);
+ ieee80211_rx_bss_put(local, bss);
return ret;
}
#ifdef CONFIG_MAC80211_IBSS_DEBUG
@@ -3762,28 +3713,45 @@
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_if_sta *ifsta;
+ int res;
if (len > IEEE80211_MAX_SSID_LEN)
return -EINVAL;
ifsta = &sdata->u.sta;
- if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0)
+ if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0) {
+ memset(ifsta->ssid, 0, sizeof(ifsta->ssid));
+ memcpy(ifsta->ssid, ssid, len);
+ ifsta->ssid_len = len;
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;
+
+ res = 0;
+ /*
+ * Hack! MLME code needs to be cleaned up to have different
+ * entry points for configuration and internal selection change
+ */
+ if (netif_running(sdata->dev))
+ res = ieee80211_if_config(sdata, IEEE80211_IFCC_SSID);
+ if (res) {
+ printk(KERN_DEBUG "%s: Failed to config new SSID to "
+ "the low-level driver\n", dev->name);
+ return res;
+ }
+ }
if (len)
ifsta->flags |= IEEE80211_STA_SSID_SET;
else
ifsta->flags &= ~IEEE80211_STA_SSID_SET;
+
if (sdata->vif.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);
}
+
return 0;
}
@@ -3809,7 +3777,12 @@
if (memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0) {
memcpy(ifsta->bssid, bssid, ETH_ALEN);
- res = ieee80211_if_config(dev);
+ res = 0;
+ /*
+ * Hack! See also ieee80211_sta_set_ssid.
+ */
+ if (netif_running(sdata->dev))
+ res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID);
if (res) {
printk(KERN_DEBUG "%s: Failed to config new BSSID to "
"the low-level driver\n", dev->name);
@@ -3907,11 +3880,6 @@
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;
-
/* Tell AP we're back */
if (sdata->vif.type == IEEE80211_IF_TYPE_STA &&
sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED)
@@ -4077,12 +4045,6 @@
rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-
- /* Don't stop the master interface, otherwise we can't transmit
- * probes! */
- if (sdata->dev == local->mdev)
- continue;
-
netif_stop_queue(sdata->dev);
if (sdata->vif.type == IEEE80211_IF_TYPE_STA &&
(sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED))
@@ -4398,7 +4360,7 @@
return NULL;
}
- if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid))
+ if (compare_ether_addr(bssid, sdata->u.sta.bssid))
return NULL;
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
@@ -4473,12 +4435,10 @@
case IEEE80211_NOTIFY_RE_ASSOC:
rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+ if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
+ continue;
- if (sdata->vif.type == IEEE80211_IF_TYPE_STA) {
- ieee80211_sta_req_auth(sdata->dev,
- &sdata->u.sta);
- }
-
+ ieee80211_sta_req_auth(sdata->dev, &sdata->u.sta);
}
rcu_read_unlock();
break;
diff --git a/net/mac80211/rc80211_pid.h b/net/mac80211/rc80211_pid.h
index 2078803..0a9135b 100644
--- a/net/mac80211/rc80211_pid.h
+++ b/net/mac80211/rc80211_pid.h
@@ -141,7 +141,6 @@
* rate behaviour values (lower means we should trust more what we learnt
* about behaviour of rates, higher means we should trust more the natural
* ordering of rates)
- * @fast_start: if Y, push high rates right after initialization
*/
struct rc_pid_debugfs_entries {
struct dentry *dir;
@@ -154,7 +153,6 @@
struct dentry *sharpen_factor;
struct dentry *sharpen_duration;
struct dentry *norm_offset;
- struct dentry *fast_start;
};
void rate_control_pid_event_tx_status(struct rc_pid_event_buffer *buf,
@@ -267,9 +265,6 @@
/* Normalization offset. */
unsigned int norm_offset;
- /* Fast starst parameter. */
- unsigned int fast_start;
-
/* Rates information. */
struct rc_pid_rateinfo *rinfo;
diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c
index 62388f8..a914ba7 100644
--- a/net/mac80211/rc80211_pid_algo.c
+++ b/net/mac80211/rc80211_pid_algo.c
@@ -259,8 +259,8 @@
/* Don't update the state if we're not controlling the rate. */
sdata = sta->sdata;
- if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) {
- sta->txrate_idx = sdata->bss->max_ratectrl_rateidx;
+ if (sdata->force_unicast_rateidx > -1) {
+ sta->txrate_idx = sdata->max_ratectrl_rateidx;
goto unlock;
}
@@ -337,8 +337,8 @@
/* If a forced rate is in effect, select it. */
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- if (sdata->bss && sdata->bss->force_unicast_rateidx > -1)
- sta->txrate_idx = sdata->bss->force_unicast_rateidx;
+ if (sdata->force_unicast_rateidx > -1)
+ sta->txrate_idx = sdata->force_unicast_rateidx;
rateidx = sta->txrate_idx;
@@ -398,13 +398,25 @@
return NULL;
}
+ pinfo->target = RC_PID_TARGET_PF;
+ pinfo->sampling_period = RC_PID_INTERVAL;
+ pinfo->coeff_p = RC_PID_COEFF_P;
+ pinfo->coeff_i = RC_PID_COEFF_I;
+ pinfo->coeff_d = RC_PID_COEFF_D;
+ pinfo->smoothing_shift = RC_PID_SMOOTHING_SHIFT;
+ pinfo->sharpen_factor = RC_PID_SHARPENING_FACTOR;
+ pinfo->sharpen_duration = RC_PID_SHARPENING_DURATION;
+ pinfo->norm_offset = RC_PID_NORM_OFFSET;
+ pinfo->rinfo = rinfo;
+ pinfo->oldrate = 0;
+
/* Sort the rates. This is optimized for the most common case (i.e.
* almost-sorted CCK+OFDM rates). Kind of bubble-sort with reversed
* mapping too. */
for (i = 0; i < sband->n_bitrates; i++) {
rinfo[i].index = i;
rinfo[i].rev_index = i;
- if (pinfo->fast_start)
+ if (RC_PID_FAST_START)
rinfo[i].diff = 0;
else
rinfo[i].diff = i * pinfo->norm_offset;
@@ -425,19 +437,6 @@
break;
}
- pinfo->target = RC_PID_TARGET_PF;
- pinfo->sampling_period = RC_PID_INTERVAL;
- pinfo->coeff_p = RC_PID_COEFF_P;
- pinfo->coeff_i = RC_PID_COEFF_I;
- pinfo->coeff_d = RC_PID_COEFF_D;
- pinfo->smoothing_shift = RC_PID_SMOOTHING_SHIFT;
- pinfo->sharpen_factor = RC_PID_SHARPENING_FACTOR;
- pinfo->sharpen_duration = RC_PID_SHARPENING_DURATION;
- pinfo->norm_offset = RC_PID_NORM_OFFSET;
- pinfo->fast_start = RC_PID_FAST_START;
- pinfo->rinfo = rinfo;
- pinfo->oldrate = 0;
-
#ifdef CONFIG_MAC80211_DEBUGFS
de = &pinfo->dentries;
de->dir = debugfs_create_dir("rc80211_pid",
@@ -465,9 +464,6 @@
de->norm_offset = debugfs_create_u32("norm_offset",
S_IRUSR | S_IWUSR, de->dir,
&pinfo->norm_offset);
- de->fast_start = debugfs_create_bool("fast_start",
- S_IRUSR | S_IWUSR, de->dir,
- &pinfo->fast_start);
#endif
return pinfo;
@@ -479,7 +475,6 @@
#ifdef CONFIG_MAC80211_DEBUGFS
struct rc_pid_debugfs_entries *de = &pinfo->dentries;
- debugfs_remove(de->fast_start);
debugfs_remove(de->norm_offset);
debugfs_remove(de->sharpen_duration);
debugfs_remove(de->sharpen_factor);
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index fab443d..6d9ae67c 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -334,13 +334,18 @@
else
rx->flags &= ~IEEE80211_RX_AMSDU;
} else {
- if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) {
- /* Separate TID for management frames */
- tid = NUM_RX_DATA_QUEUES - 1;
- } else {
- /* no qos control present */
- tid = 0; /* 802.1d - Best Effort */
- }
+ /*
+ * IEEE 802.11-2007, 7.1.3.4.1 ("Sequence Number field"):
+ *
+ * Sequence numbers for management frames, QoS data
+ * frames with a broadcast/multicast address in the
+ * Address 1 field, and all non-QoS data frames sent
+ * by QoS STAs are assigned using an additional single
+ * modulo-4096 counter, [...]
+ *
+ * We also use that counter for non-QoS STAs.
+ */
+ tid = NUM_RX_DATA_QUEUES - 1;
}
rx->queue = tid;
@@ -647,8 +652,7 @@
sdata = sta->sdata;
- if (sdata->bss)
- atomic_inc(&sdata->bss->num_sta_ps);
+ atomic_inc(&sdata->bss->num_sta_ps);
set_and_clear_sta_flags(sta, WLAN_STA_PS, WLAN_STA_PSPOLL);
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "%s: STA %s aid %d enters power save mode\n",
@@ -667,8 +671,7 @@
sdata = sta->sdata;
- if (sdata->bss)
- atomic_dec(&sdata->bss->num_sta_ps);
+ atomic_dec(&sdata->bss->num_sta_ps);
clear_sta_flags(sta, WLAN_STA_PS | WLAN_STA_PSPOLL);
@@ -742,7 +745,9 @@
sta->last_qual = rx->status->qual;
sta->last_noise = rx->status->noise;
- if (!ieee80211_has_morefrags(hdr->frame_control)) {
+ if (!ieee80211_has_morefrags(hdr->frame_control) &&
+ (rx->sdata->vif.type == IEEE80211_IF_TYPE_AP ||
+ rx->sdata->vif.type == IEEE80211_IF_TYPE_VLAN)) {
/* Change STA power saving mode only in the end of a frame
* exchange sequence */
if (test_sta_flags(sta, WLAN_STA_PS) &&
@@ -1772,11 +1777,6 @@
return 0;
rx->flags &= ~IEEE80211_RX_RA_MATCH;
}
- if (sdata->dev == sdata->local->mdev &&
- !(rx->flags & IEEE80211_RX_IN_SCAN))
- /* do not receive anything via
- * master device when not scanning */
- return 0;
break;
case IEEE80211_IF_TYPE_WDS:
if (bssid || !ieee80211_is_data(hdr->frame_control))
@@ -2046,8 +2046,8 @@
tid_agg_rx = sta->ampdu_mlme.tid_rx[tid];
- /* null data frames are excluded */
- if (unlikely(ieee80211_is_nullfunc(hdr->frame_control)))
+ /* qos null data frames are excluded */
+ if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC)))
goto end_reorder;
/* new un-ordered ampdu frame - process it */
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 47d2c1b..f2ba653 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -320,7 +320,9 @@
/* notify driver */
if (local->ops->sta_notify) {
if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
- sdata = sdata->u.vlan.ap;
+ sdata = container_of(sdata->bss,
+ struct ieee80211_sub_if_data,
+ u.ap);
local->ops->sta_notify(local_to_hw(local), &sdata->vif,
STA_NOTIFY_ADD, sta->addr);
@@ -375,8 +377,10 @@
static void __sta_info_set_tim_bit(struct ieee80211_if_ap *bss,
struct sta_info *sta)
{
- if (bss)
- __bss_tim_set(bss, sta->aid);
+ BUG_ON(!bss);
+
+ __bss_tim_set(bss, sta->aid);
+
if (sta->local->ops->set_tim) {
sta->local->tim_in_locked_section = true;
sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 1);
@@ -388,6 +392,8 @@
{
unsigned long flags;
+ BUG_ON(!sta->sdata->bss);
+
spin_lock_irqsave(&sta->local->sta_lock, flags);
__sta_info_set_tim_bit(sta->sdata->bss, sta);
spin_unlock_irqrestore(&sta->local->sta_lock, flags);
@@ -396,8 +402,10 @@
static void __sta_info_clear_tim_bit(struct ieee80211_if_ap *bss,
struct sta_info *sta)
{
- if (bss)
- __bss_tim_clear(bss, sta->aid);
+ BUG_ON(!bss);
+
+ __bss_tim_clear(bss, sta->aid);
+
if (sta->local->ops->set_tim) {
sta->local->tim_in_locked_section = true;
sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 0);
@@ -409,6 +417,8 @@
{
unsigned long flags;
+ BUG_ON(!sta->sdata->bss);
+
spin_lock_irqsave(&sta->local->sta_lock, flags);
__sta_info_clear_tim_bit(sta->sdata->bss, sta);
spin_unlock_irqrestore(&sta->local->sta_lock, flags);
@@ -437,8 +447,9 @@
list_del(&(*sta)->list);
if (test_and_clear_sta_flags(*sta, WLAN_STA_PS)) {
- if (sdata->bss)
- atomic_dec(&sdata->bss->num_sta_ps);
+ BUG_ON(!sdata->bss);
+
+ atomic_dec(&sdata->bss->num_sta_ps);
__sta_info_clear_tim_bit(sdata->bss, *sta);
}
@@ -446,7 +457,9 @@
if (local->ops->sta_notify) {
if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
- sdata = sdata->u.vlan.ap;
+ sdata = container_of(sdata->bss,
+ struct ieee80211_sub_if_data,
+ u.ap);
local->ops->sta_notify(local_to_hw(local), &sdata->vif,
STA_NOTIFY_REMOVE, (*sta)->addr);
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 94311dc..109db78 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -285,6 +285,7 @@
unsigned long tx_fragments;
int txrate_idx;
int last_txrate_idx;
+ u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1];
#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
unsigned int wme_tx_queue[NUM_RX_DATA_QUEUES];
#endif
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 9bd9faa..0fbadd8 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -38,16 +38,6 @@
/* 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)
@@ -274,17 +264,6 @@
return TX_CONTINUE;
}
-static ieee80211_tx_result debug_noinline
-ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
-{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
-
- if (ieee80211_hdrlen(hdr->frame_control) >= 24)
- ieee80211_include_sequence(tx->sdata, hdr);
-
- return TX_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
@@ -303,8 +282,7 @@
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
struct ieee80211_if_ap *ap;
- if (sdata->dev == local->mdev ||
- sdata->vif.type != IEEE80211_IF_TYPE_AP)
+ if (sdata->vif.type != IEEE80211_IF_TYPE_AP)
continue;
ap = &sdata->u.ap;
skb = skb_dequeue(&ap->ps_bc_buf);
@@ -346,8 +324,12 @@
* This is done either by the hardware or us.
*/
- /* not AP/IBSS or ordered frame */
- if (!tx->sdata->bss || (tx->fc & IEEE80211_FCTL_ORDER))
+ /* powersaving STAs only in AP/VLAN mode */
+ if (!tx->sdata->bss)
+ return TX_CONTINUE;
+
+ /* no buffering for ordered frames */
+ if (tx->fc & IEEE80211_FCTL_ORDER)
return TX_CONTINUE;
/* no stations in PS mode */
@@ -639,6 +621,49 @@
}
static ieee80211_tx_result debug_noinline
+ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
+ u16 *seq;
+ u8 *qc;
+ int tid;
+
+ /* only for injected frames */
+ if (unlikely(ieee80211_is_ctl(hdr->frame_control)))
+ return TX_CONTINUE;
+
+ if (ieee80211_hdrlen(hdr->frame_control) < 24)
+ return TX_CONTINUE;
+
+ if (!ieee80211_is_data_qos(hdr->frame_control)) {
+ info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
+ return TX_CONTINUE;
+ }
+
+ /*
+ * This should be true for injected/management frames only, for
+ * management frames we have set the IEEE80211_TX_CTL_ASSIGN_SEQ
+ * above since they are not QoS-data frames.
+ */
+ if (!tx->sta)
+ return TX_CONTINUE;
+
+ /* include per-STA, per-TID sequence counter */
+
+ qc = ieee80211_get_qos_ctl(hdr);
+ tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
+ seq = &tx->sta->tid_seq[tid];
+
+ hdr->seq_ctrl = cpu_to_le16(*seq);
+
+ /* Increase the sequence number. */
+ *seq = (*seq + 0x10) & IEEE80211_SCTL_SEQ;
+
+ return TX_CONTINUE;
+}
+
+static ieee80211_tx_result debug_noinline
ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
@@ -1107,12 +1132,12 @@
goto txh_done;
CALL_TXH(ieee80211_tx_h_check_assoc)
- CALL_TXH(ieee80211_tx_h_sequence)
CALL_TXH(ieee80211_tx_h_ps_buf)
CALL_TXH(ieee80211_tx_h_select_key)
CALL_TXH(ieee80211_tx_h_michael_mic_add)
CALL_TXH(ieee80211_tx_h_rate_ctrl)
CALL_TXH(ieee80211_tx_h_misc)
+ CALL_TXH(ieee80211_tx_h_sequence)
CALL_TXH(ieee80211_tx_h_fragment)
/* handlers after fragment must be aware of tx info fragmentation! */
CALL_TXH(ieee80211_tx_h_encrypt)
@@ -1785,17 +1810,17 @@
struct ieee80211_vif *vif)
{
struct ieee80211_local *local = hw_to_local(hw);
- struct sk_buff *skb;
+ struct sk_buff *skb = NULL;
struct ieee80211_tx_info *info;
struct net_device *bdev;
struct ieee80211_sub_if_data *sdata = NULL;
struct ieee80211_if_ap *ap = NULL;
+ struct ieee80211_if_sta *ifsta = NULL;
struct rate_selection rsel;
struct beacon_data *beacon;
struct ieee80211_supported_band *sband;
struct ieee80211_mgmt *mgmt;
int *num_beacons;
- bool err = true;
enum ieee80211_band band = local->hw.conf.channel->band;
u8 *pos;
@@ -1824,9 +1849,6 @@
memcpy(skb_put(skb, beacon->head_len), beacon->head,
beacon->head_len);
- ieee80211_include_sequence(sdata,
- (struct ieee80211_hdr *)skb->data);
-
/*
* Not very nice, but we want to allow the driver to call
* ieee80211_beacon_get() as a response to the set_tim()
@@ -1849,9 +1871,24 @@
beacon->tail, beacon->tail_len);
num_beacons = &ap->num_beacons;
+ } else
+ goto out;
+ } else if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
+ struct ieee80211_hdr *hdr;
+ ifsta = &sdata->u.sta;
- err = false;
- }
+ if (!ifsta->probe_resp)
+ goto out;
+
+ skb = skb_copy(ifsta->probe_resp, GFP_ATOMIC);
+ if (!skb)
+ goto out;
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+ hdr->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+ IEEE80211_STYPE_BEACON);
+
+ num_beacons = &ifsta->num_beacons;
} else if (ieee80211_vif_is_mesh(&sdata->vif)) {
/* headroom, head length, tail length and maximum TIM length */
skb = dev_alloc_skb(local->tx_headroom + 400);
@@ -1878,17 +1915,8 @@
mesh_mgmt_ies_add(skb, sdata->dev);
num_beacons = &sdata->u.sta.num_beacons;
-
- err = false;
- }
-
- if (err) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- if (net_ratelimit())
- printk(KERN_DEBUG "no beacon data avail for %s\n",
- bdev->name);
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
- skb = NULL;
+ } else {
+ WARN_ON(1);
goto out;
}
@@ -1910,14 +1938,18 @@
info->control.vif = vif;
info->tx_rate_idx = rsel.rate_idx;
+
+ info->flags |= IEEE80211_TX_CTL_NO_ACK;
+ info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
+ info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
+ info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
if (sdata->bss_conf.use_short_preamble &&
sband->bitrates[rsel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE)
info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE;
+
info->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
- info->flags |= IEEE80211_TX_CTL_NO_ACK;
- info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
info->control.retry_limit = 1;
- info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
+
(*num_beacons)++;
out:
rcu_read_unlock();
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index ce62b16..89ce4e0 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -428,8 +428,6 @@
case IEEE80211_IF_TYPE_MESH_POINT:
break;
}
- if (sdata->dev == local->mdev)
- continue;
if (netif_running(sdata->dev))
iterator(data, sdata->dev->dev_addr,
&sdata->vif);
@@ -463,8 +461,6 @@
case IEEE80211_IF_TYPE_MESH_POINT:
break;
}
- if (sdata->dev == local->mdev)
- continue;
if (netif_running(sdata->dev))
iterator(data, sdata->dev->dev_addr,
&sdata->vif);
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c
index 736c32e..34fa8ed 100644
--- a/net/mac80211/wext.c
+++ b/net/mac80211/wext.c
@@ -296,15 +296,7 @@
return -EINVAL;
}
- if (type == sdata->vif.type)
- return 0;
- if (netif_running(dev))
- return -EBUSY;
-
- ieee80211_if_reinit(dev);
- ieee80211_if_set_type(dev, type);
-
- return 0;
+ return ieee80211_if_change_type(sdata, type);
}
@@ -452,7 +444,7 @@
memset(sdata->u.ap.ssid + len, 0,
IEEE80211_MAX_SSID_LEN - len);
sdata->u.ap.ssid_len = len;
- return ieee80211_if_config(dev);
+ return ieee80211_if_config(sdata, IEEE80211_IFCC_SSID);
}
return -EOPNOTSUPP;
}
@@ -627,16 +619,14 @@
struct ieee80211_supported_band *sband;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- if (!sdata->bss)
- return -ENODEV;
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
/* target_rate = -1, rate->fixed = 0 means auto only, so use all rates
* target_rate = X, rate->fixed = 1 means only rate X
* target_rate = X, rate->fixed = 0 means all rates <= X */
- sdata->bss->max_ratectrl_rateidx = -1;
- sdata->bss->force_unicast_rateidx = -1;
+ sdata->max_ratectrl_rateidx = -1;
+ sdata->force_unicast_rateidx = -1;
if (rate->value < 0)
return 0;
@@ -645,9 +635,9 @@
int this_rate = brate->bitrate;
if (target_rate == this_rate) {
- sdata->bss->max_ratectrl_rateidx = i;
+ sdata->max_ratectrl_rateidx = i;
if (rate->fixed)
- sdata->bss->force_unicast_rateidx = i;
+ sdata->force_unicast_rateidx = i;
err = 0;
break;
}
@@ -1009,6 +999,45 @@
return 0;
}
+static int ieee80211_ioctl_siwpower(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *wrq,
+ char *extra)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_conf *conf = &local->hw.conf;
+
+ if (wrq->disabled) {
+ conf->flags &= ~IEEE80211_CONF_PS;
+ return ieee80211_hw_config(local);
+ }
+
+ switch (wrq->flags & IW_POWER_MODE) {
+ case IW_POWER_ON: /* If not specified */
+ case IW_POWER_MODE: /* If set all mask */
+ case IW_POWER_ALL_R: /* If explicitely state all */
+ conf->flags |= IEEE80211_CONF_PS;
+ break;
+ default: /* Otherwise we don't support it */
+ return -EINVAL;
+ }
+
+ return ieee80211_hw_config(local);
+}
+
+static int ieee80211_ioctl_giwpower(struct net_device *dev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_conf *conf = &local->hw.conf;
+
+ wrqu->power.disabled = !(conf->flags & IEEE80211_CONF_PS);
+
+ return 0;
+}
+
static int ieee80211_ioctl_siwauth(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *data, char *extra)
@@ -1211,8 +1240,8 @@
(iw_handler) ieee80211_ioctl_giwretry, /* SIOCGIWRETRY */
(iw_handler) ieee80211_ioctl_siwencode, /* SIOCSIWENCODE */
(iw_handler) ieee80211_ioctl_giwencode, /* SIOCGIWENCODE */
- (iw_handler) NULL, /* SIOCSIWPOWER */
- (iw_handler) NULL, /* SIOCGIWPOWER */
+ (iw_handler) ieee80211_ioctl_siwpower, /* SIOCSIWPOWER */
+ (iw_handler) ieee80211_ioctl_giwpower, /* SIOCGIWPOWER */
(iw_handler) NULL, /* -- hole -- */
(iw_handler) NULL, /* -- hole -- */
(iw_handler) ieee80211_ioctl_siwgenie, /* SIOCSIWGENIE */
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 212a088..28d03e6 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -848,10 +848,10 @@
}
EXPORT_SYMBOL_GPL(__nf_ct_refresh_acct);
-void __nf_ct_kill_acct(struct nf_conn *ct,
- enum ip_conntrack_info ctinfo,
- const struct sk_buff *skb,
- int do_acct)
+bool __nf_ct_kill_acct(struct nf_conn *ct,
+ enum ip_conntrack_info ctinfo,
+ const struct sk_buff *skb,
+ int do_acct)
{
#ifdef CONFIG_NF_CT_ACCT
if (do_acct) {
@@ -862,8 +862,11 @@
spin_unlock_bh(&nf_conntrack_lock);
}
#endif
- if (del_timer(&ct->timeout))
+ if (del_timer(&ct->timeout)) {
ct->timeout.function((unsigned long)ct);
+ return true;
+ }
+ return false;
}
EXPORT_SYMBOL_GPL(__nf_ct_kill_acct);
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index 740acd6..420a10d 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -844,8 +844,14 @@
/* Attempt to reopen a closed/aborted connection.
* Delete this connection and look up again. */
write_unlock_bh(&tcp_lock);
- nf_ct_kill(ct);
- return -NF_REPEAT;
+
+ /* Only repeat if we can actually remove the timer.
+ * Destruction may already be in progress in process
+ * context and we must give it a chance to terminate.
+ */
+ if (nf_ct_kill(ct))
+ return -NF_REPEAT;
+ return -NF_DROP;
}
/* Fall through */
case TCP_CONNTRACK_IGNORE:
diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c
index fdc14a0..0aec318 100644
--- a/net/netlabel/netlabel_cipso_v4.c
+++ b/net/netlabel/netlabel_cipso_v4.c
@@ -584,19 +584,14 @@
rcu_read_unlock();
genlmsg_end(ans_skb, data);
-
- ret_val = genlmsg_reply(ans_skb, info);
- if (ret_val != 0)
- goto list_failure;
-
- return 0;
+ return genlmsg_reply(ans_skb, info);
list_retry:
/* XXX - this limit is a guesstimate */
if (nlsze_mult < 4) {
rcu_read_unlock();
kfree_skb(ans_skb);
- nlsze_mult++;
+ nlsze_mult *= 2;
goto list_start;
}
list_failure_lock:
diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c
index 22c1912..44be5d5 100644
--- a/net/netlabel/netlabel_mgmt.c
+++ b/net/netlabel/netlabel_mgmt.c
@@ -386,11 +386,7 @@
rcu_read_unlock();
genlmsg_end(ans_skb, data);
-
- ret_val = genlmsg_reply(ans_skb, info);
- if (ret_val != 0)
- goto listdef_failure;
- return 0;
+ return genlmsg_reply(ans_skb, info);
listdef_failure_lock:
rcu_read_unlock();
@@ -501,11 +497,7 @@
goto version_failure;
genlmsg_end(ans_skb, data);
-
- ret_val = genlmsg_reply(ans_skb, info);
- if (ret_val != 0)
- goto version_failure;
- return 0;
+ return genlmsg_reply(ans_skb, info);
version_failure:
kfree_skb(ans_skb);
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
index 52b2611..56f8087 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.c
@@ -1107,11 +1107,7 @@
goto list_failure;
genlmsg_end(ans_skb, data);
-
- ret_val = genlmsg_reply(ans_skb, info);
- if (ret_val != 0)
- goto list_failure;
- return 0;
+ return genlmsg_reply(ans_skb, info);
list_failure:
kfree_skb(ans_skb);
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index beca640..9f22691 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1173,7 +1173,8 @@
return 0;
}
-static void packet_dev_mc(struct net_device *dev, struct packet_mclist *i, int what)
+static int packet_dev_mc(struct net_device *dev, struct packet_mclist *i,
+ int what)
{
switch (i->type) {
case PACKET_MR_MULTICAST:
@@ -1183,13 +1184,14 @@
dev_mc_delete(dev, i->addr, i->alen, 0);
break;
case PACKET_MR_PROMISC:
- dev_set_promiscuity(dev, what);
+ return dev_set_promiscuity(dev, what);
break;
case PACKET_MR_ALLMULTI:
- dev_set_allmulti(dev, what);
+ return dev_set_allmulti(dev, what);
break;
default:;
}
+ return 0;
}
static void packet_dev_mclist(struct net_device *dev, struct packet_mclist *i, int what)
@@ -1243,7 +1245,11 @@
i->count = 1;
i->next = po->mclist;
po->mclist = i;
- packet_dev_mc(dev, i, +1);
+ err = packet_dev_mc(dev, i, 1);
+ if (err) {
+ po->mclist = i->next;
+ kfree(i);
+ }
done:
rtnl_unlock();
diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c
index 971b867..8f63a1a 100644
--- a/net/sched/cls_flow.c
+++ b/net/sched/cls_flow.c
@@ -36,6 +36,8 @@
struct list_head list;
struct tcf_exts exts;
struct tcf_ematch_tree ematches;
+ struct timer_list perturb_timer;
+ u32 perturb_period;
u32 handle;
u32 nkeys;
@@ -47,11 +49,9 @@
u32 addend;
u32 divisor;
u32 baseclass;
+ u32 hashrnd;
};
-static u32 flow_hashrnd __read_mostly;
-static int flow_hashrnd_initted __read_mostly;
-
static const struct tcf_ext_map flow_ext_map = {
.action = TCA_FLOW_ACT,
.police = TCA_FLOW_POLICE,
@@ -348,7 +348,7 @@
}
if (f->mode == FLOW_MODE_HASH)
- classid = jhash2(keys, f->nkeys, flow_hashrnd);
+ classid = jhash2(keys, f->nkeys, f->hashrnd);
else {
classid = keys[0];
classid = (classid & f->mask) ^ f->xor;
@@ -369,6 +369,15 @@
return -1;
}
+static void flow_perturbation(unsigned long arg)
+{
+ struct flow_filter *f = (struct flow_filter *)arg;
+
+ get_random_bytes(&f->hashrnd, 4);
+ if (f->perturb_period)
+ mod_timer(&f->perturb_timer, jiffies + f->perturb_period);
+}
+
static const struct nla_policy flow_policy[TCA_FLOW_MAX + 1] = {
[TCA_FLOW_KEYS] = { .type = NLA_U32 },
[TCA_FLOW_MODE] = { .type = NLA_U32 },
@@ -381,6 +390,7 @@
[TCA_FLOW_ACT] = { .type = NLA_NESTED },
[TCA_FLOW_POLICE] = { .type = NLA_NESTED },
[TCA_FLOW_EMATCHES] = { .type = NLA_NESTED },
+ [TCA_FLOW_PERTURB] = { .type = NLA_U32 },
};
static int flow_change(struct tcf_proto *tp, unsigned long base,
@@ -394,6 +404,7 @@
struct tcf_exts e;
struct tcf_ematch_tree t;
unsigned int nkeys = 0;
+ unsigned int perturb_period = 0;
u32 baseclass = 0;
u32 keymask = 0;
u32 mode;
@@ -442,6 +453,14 @@
mode = nla_get_u32(tb[TCA_FLOW_MODE]);
if (mode != FLOW_MODE_HASH && nkeys > 1)
goto err2;
+
+ if (mode == FLOW_MODE_HASH)
+ perturb_period = f->perturb_period;
+ if (tb[TCA_FLOW_PERTURB]) {
+ if (mode != FLOW_MODE_HASH)
+ goto err2;
+ perturb_period = nla_get_u32(tb[TCA_FLOW_PERTURB]) * HZ;
+ }
} else {
err = -EINVAL;
if (!handle)
@@ -455,6 +474,12 @@
if (mode != FLOW_MODE_HASH && nkeys > 1)
goto err2;
+ if (tb[TCA_FLOW_PERTURB]) {
+ if (mode != FLOW_MODE_HASH)
+ goto err2;
+ perturb_period = nla_get_u32(tb[TCA_FLOW_PERTURB]) * HZ;
+ }
+
if (TC_H_MAJ(baseclass) == 0)
baseclass = TC_H_MAKE(tp->q->handle, baseclass);
if (TC_H_MIN(baseclass) == 0)
@@ -467,6 +492,11 @@
f->handle = handle;
f->mask = ~0U;
+
+ get_random_bytes(&f->hashrnd, 4);
+ f->perturb_timer.function = flow_perturbation;
+ f->perturb_timer.data = (unsigned long)f;
+ init_timer_deferrable(&f->perturb_timer);
}
tcf_exts_change(tp, &f->exts, &e);
@@ -495,6 +525,11 @@
if (baseclass)
f->baseclass = baseclass;
+ f->perturb_period = perturb_period;
+ del_timer(&f->perturb_timer);
+ if (perturb_period)
+ mod_timer(&f->perturb_timer, jiffies + perturb_period);
+
if (*arg == 0)
list_add_tail(&f->list, &head->filters);
@@ -512,6 +547,7 @@
static void flow_destroy_filter(struct tcf_proto *tp, struct flow_filter *f)
{
+ del_timer_sync(&f->perturb_timer);
tcf_exts_destroy(tp, &f->exts);
tcf_em_tree_destroy(tp, &f->ematches);
kfree(f);
@@ -532,11 +568,6 @@
{
struct flow_head *head;
- if (!flow_hashrnd_initted) {
- get_random_bytes(&flow_hashrnd, 4);
- flow_hashrnd_initted = 1;
- }
-
head = kzalloc(sizeof(*head), GFP_KERNEL);
if (head == NULL)
return -ENOBUFS;
@@ -605,6 +636,9 @@
if (f->baseclass)
NLA_PUT_U32(skb, TCA_FLOW_BASECLASS, f->baseclass);
+ if (f->perturb_period)
+ NLA_PUT_U32(skb, TCA_FLOW_PERTURB, f->perturb_period / HZ);
+
if (tcf_exts_dump(skb, &f->exts, &flow_ext_map) < 0)
goto nla_put_failure;
#ifdef CONFIG_NET_EMATCH
diff --git a/net/wanrouter/Kconfig b/net/wanrouter/Kconfig
index 1debe1c..61ceae0 100644
--- a/net/wanrouter/Kconfig
+++ b/net/wanrouter/Kconfig
@@ -20,8 +20,6 @@
wish to use your Linux box as a WAN router, say Y here and also to
the WAN driver for your card, below. You will then need the
wan-tools package which is available from <ftp://ftp.sangoma.com/>.
- Read <file:Documentation/networking/wan-router.txt> for more
- information.
To compile WAN routing support as a module, choose M here: the
module will be called wanrouter.
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
index 7927090..ab015c6 100644
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -29,3 +29,14 @@
Say N (if you can) unless you know you need wireless
extensions for external modules.
+
+config WIRELESS_EXT_SYSFS
+ bool "Wireless extensions sysfs files"
+ default y
+ depends on WIRELESS_EXT && SYSFS
+ help
+ This option enables the deprecated wireless statistics
+ files in /sys/class/net/*/wireless/. The same information
+ is available via the ioctls as well.
+
+ Say Y if you have programs using it (we don't know of any).
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index b976d9e..04c4150 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -277,9 +277,8 @@
memcpy(&x->props.saddr, &p->saddr, sizeof(x->props.saddr));
x->props.flags = p->flags;
- if (!x->sel.family)
+ if (!x->sel.family && !(p->flags & XFRM_STATE_AF_UNSPEC))
x->sel.family = p->family;
-
}
/*