aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/feature-removal-schedule.txt10
-rw-r--r--Documentation/networking/ip-sysctl.txt256
-rw-r--r--drivers/net/arm/ixp4xx_eth.c3
-rw-r--r--drivers/net/bonding/bond_alb.c6
-rw-r--r--drivers/net/bonding/bond_main.c39
-rw-r--r--drivers/net/macvlan.c14
-rw-r--r--drivers/net/tun.c322
-rw-r--r--drivers/net/wan/Kconfig3
-rw-r--r--drivers/net/wireless/ath5k/base.c13
-rw-r--r--drivers/net/wireless/b43/main.c48
-rw-r--r--drivers/net/wireless/b43/xmit.c3
-rw-r--r--drivers/net/wireless/b43legacy/main.c45
-rw-r--r--drivers/net/wireless/b43legacy/xmit.c3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-led.c146
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-led.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c50
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.h20
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965-hw.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965-rs.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c42
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000-hw.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c48
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h30
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h27
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-led.c207
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-led.h5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rx.c37
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c103
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c8
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c145
-rw-r--r--drivers/net/wireless/iwlwifi/iwl4965-base.c108
-rw-r--r--drivers/net/wireless/libertas/scan.c4
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c100
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c101
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c161
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h37
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00config.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c9
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00firmware.c8
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00lib.h8
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c40
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.c67
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c112
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c124
-rw-r--r--drivers/net/wireless/rtl8187_dev.c23
-rw-r--r--drivers/net/wireless/rtl8187_rtl8225.c21
-rw-r--r--drivers/net/wireless/rtl8187_rtl8225.h15
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c23
-rw-r--r--include/linux/dccp.h6
-rw-r--r--include/linux/if_tun.h24
-rw-r--r--include/linux/pkt_cls.h1
-rw-r--r--include/linux/ssb/ssb.h1
-rw-r--r--include/linux/xfrm.h1
-rw-r--r--include/net/mac80211.h73
-rw-r--r--include/net/netfilter/nf_conntrack.h20
-rw-r--r--net/8021q/vlan_dev.c28
-rw-r--r--net/bridge/br_if.c9
-rw-r--r--net/core/net-sysfs.c4
-rw-r--r--net/dccp/ccids/ccid3.c14
-rw-r--r--net/dccp/ccids/lib/loss_interval.c10
-rw-r--r--net/dccp/ccids/lib/packet_history.c103
-rw-r--r--net/dccp/ccids/lib/packet_history.h30
-rw-r--r--net/dccp/dccp.h15
-rw-r--r--net/dccp/options.c14
-rw-r--r--net/ipv4/fib_trie.c17
-rw-r--r--net/ipv4/ipmr.c60
-rw-r--r--net/ipv4/netfilter/nf_nat_snmp_basic.c2
-rw-r--r--net/ipv4/tcp_probe.c2
-rw-r--r--net/ipv6/exthdrs.c2
-rw-r--r--net/ipv6/ip6mr.c17
-rw-r--r--net/mac80211/cfg.c36
-rw-r--r--net/mac80211/debugfs.c15
-rw-r--r--net/mac80211/debugfs_netdev.c48
-rw-r--r--net/mac80211/debugfs_netdev.h5
-rw-r--r--net/mac80211/ieee80211_i.h67
-rw-r--r--net/mac80211/iface.c392
-rw-r--r--net/mac80211/main.c171
-rw-r--r--net/mac80211/mlme.c172
-rw-r--r--net/mac80211/rc80211_pid.h5
-rw-r--r--net/mac80211/rc80211_pid_algo.c39
-rw-r--r--net/mac80211/rx.c38
-rw-r--r--net/mac80211/sta_info.c29
-rw-r--r--net/mac80211/sta_info.h1
-rw-r--r--net/mac80211/tx.c126
-rw-r--r--net/mac80211/util.c4
-rw-r--r--net/mac80211/wext.c65
-rw-r--r--net/netfilter/nf_conntrack_core.c13
-rw-r--r--net/netfilter/nf_conntrack_proto_tcp.c10
-rw-r--r--net/netlabel/netlabel_cipso_v4.c9
-rw-r--r--net/netlabel/netlabel_mgmt.c12
-rw-r--r--net/netlabel/netlabel_unlabeled.c6
-rw-r--r--net/packet/af_packet.c14
-rw-r--r--net/sched/cls_flow.c52
-rw-r--r--net/wanrouter/Kconfig2
-rw-r--r--net/wireless/Kconfig11
-rw-r--r--net/xfrm/xfrm_user.c3
99 files changed, 2244 insertions, 2165 deletions
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 8319c462c9f..db300e09c9a 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -333,3 +333,13 @@ Why: This option was introduced just to allow older lm-sensors userspace
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 a40feaee62e..d84932650fd 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -148,9 +148,9 @@ tcp_available_congestion_control - STRING
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 @@ tcp_frto - INTEGER
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 @@ tcp_mem - vector of 3 INTEGERs: min, pressure, max
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 @@ tcp_rmem - vector of 3 INTEGERs: min, default, max
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 @@ tcp_rmem - vector of 3 INTEGERs: min, default, max
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 @@ tcp_slow_start_after_idle - BOOLEAN
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_synack_retries - INTEGER
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 @@ tcp_syncookies - BOOLEAN
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 @@ tcp_window_scaling - BOOLEAN
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 @@ bridge-nf-filter-pppoe-tagged - BOOLEAN
Default: 1
-UNDOCUMENTED:
+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
-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
+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:
+/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 c617b64c288..9b777d9433c 100644
--- a/drivers/net/arm/ixp4xx_eth.c
+++ b/drivers/net/arm/ixp4xx_eth.c
@@ -522,7 +522,6 @@ static int eth_poll(struct napi_struct *napi, int budget)
#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 @@ static int eth_poll(struct napi_struct *napi, int budget)
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 5a673725471..b211486a0ca 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -419,8 +419,10 @@ static void rlb_teach_disabled_mac_on_primary(struct bonding *bond, u8 addr[])
}
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 dc733d75a5e..8ae7ff31321 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -772,39 +772,49 @@ static struct dev_mc_list *bond_mc_list_find_dmi(struct dev_mc_list *dmi, struct
/*
* 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 @@ static void bond_mc_swap(struct bonding *bond, struct slave *new_active, struct
}
if (new_active) {
+ /* FIXME: Signal errors upstream. */
if (bond->dev->flags & IFF_PROMISC) {
dev_set_promiscuity(new_active->dev, 1);
}
@@ -1544,12 +1555,16 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
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 @@ static void bond_set_multicast_list(struct net_device *bond_dev)
* 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 @@ static void bond_set_multicast_list(struct net_device *bond_dev)
/* 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 c02ceaa4a21..980001c2cf9 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -189,12 +189,20 @@ static int macvlan_open(struct net_device *dev)
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 aa4ee4439f0..901551c8ca0 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 @@ static int debug;
#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 tun_struct {
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 @@ static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
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 @@ static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
}
}
- /* Queue packet */
+ /* Enqueue packet */
skb_queue_tail(&tun->readq, skb);
dev->trans_start = jiffies;
@@ -174,41 +282,14 @@ drop:
return 0;
}
-/** Add the specified Ethernet address to this multicast filter. */
-static void
-add_multi(u32* filter, const u8* addr)
-{
- 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)
+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));
-}
-
-/** 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 @@ static void tun_net_init(struct net_device *dev)
case TUN_TAP_DEV:
/* Ethernet TAP Device */
- dev->set_multicast_list = tun_net_mclist;
-
ether_setup(dev);
- dev->change_mtu = tun_net_change_mtu;
+ dev->change_mtu = tun_net_change_mtu;
+ dev->set_multicast_list = tun_net_mclist;
- /* 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 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv,
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 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv,
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 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv,
}
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 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
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 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
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 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file,
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 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file,
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 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file,
}
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 d5140aed7b7..846be60e782 100644
--- a/drivers/net/wan/Kconfig
+++ b/drivers/net/wan/Kconfig
@@ -390,8 +390,7 @@ config WAN_ROUTER_DRIVERS
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 a43e9b25169..217d506527a 100644
--- a/drivers/net/wireless/ath5k/base.c
+++ b/drivers/net/wireless/ath5k/base.c
@@ -207,7 +207,6 @@ static struct ieee80211_ops ath5k_hw_ops = {
.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 @@ ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
* 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 9d2eb273b72..381dbd33dfc 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -1675,14 +1675,24 @@ static void b43_beacon_update_trigger_work(struct work_struct *work)
/* 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 @@ static int b43_op_config_interface(struct ieee80211_hw *hw,
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 @@ out_unlock:
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 @@ static const struct ieee80211_ops b43_hw_ops = {
.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 bf6f6c1ed4c..8d54502222a 100644
--- a/drivers/net/wireless/b43/xmit.c
+++ b/drivers/net/wireless/b43/xmit.c
@@ -317,7 +317,8 @@ int b43_generate_txhdr(struct b43_wldev *dev,
/* 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 069157eea05..a1b8bf3ee73 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -1138,14 +1138,22 @@ static void b43legacy_write_probe_resp_template(struct b43legacy_wldev *dev,
/* 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 @@ static int b43legacy_op_config_interface(struct ieee80211_hw *hw,
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 @@ static int b43legacy_op_beacon_set_tim(struct ieee80211_hw *hw,
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 @@ static const struct ieee80211_ops b43legacy_hw_ops = {
.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 a3540787eb5..e969ed8d412 100644
--- a/drivers/net/wireless/b43legacy/xmit.c
+++ b/drivers/net/wireless/b43legacy/xmit.c
@@ -295,8 +295,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
/* 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 8b1528e52d4..6be1fe13fa5 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 @@ static const struct {
{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 @@ static int iwl3945_led_cmd_callback(struct iwl3945_priv *priv,
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,49 +89,45 @@ static int iwl_send_led_cmd(struct iwl3945_priv *priv,
.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_on(struct iwl3945_priv *priv, int led_id)
+static int iwl3945_led_pattern(struct iwl3945_priv *priv, int led_id,
+ unsigned int idx)
{
struct iwl3945_led_cmd led_cmd = {
.id = led_id,
- .on = IWL_LED_SOLID,
- .off = 0,
.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_pattern(struct iwl3945_priv *priv, int led_id,
- enum led_brightness brightness)
+static int iwl3945_led_on(struct iwl3945_priv *priv, int led_id)
{
struct iwl3945_led_cmd led_cmd = {
.id = led_id,
- .on = brightness,
- .off = brightness,
+ .on = IWL_LED_SOLID,
+ .off = 0,
.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 @@ static int iwl3945_led_off(struct iwl3945_priv *priv, int led_id)
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 @@ static void iwl3945_led_brightness_set(struct led_classdev *led_cdev,
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 int iwl3945_led_register_led(struct iwl3945_priv *priv,
static inline u8 get_blink_rate(struct iwl3945_priv *priv)
{
int index;
- u8 blink_rate;
-
- 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;
- else
- blink_rate = blink_tbl[index].on_time;
+ u64 current_tpt = priv->rxtxpackets;
+ s64 tpt = current_tpt - priv->led_tpt;
- return blink_rate;
+ if (tpt < 0)
+ tpt = -tpt;
+ priv->led_tpt = current_tpt;
+
+ if (!priv->allow_blinking)
+ index = IWL_MAX_BLINK_TBL;
+ else
+ 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 @@ static inline int is_rf_kill(struct iwl3945_priv *priv)
*/
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 @@ void iwl3945_led_background(struct iwl3945_priv *priv)
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 @@ void iwl3945_led_background(struct iwl3945_priv *priv)
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 @@ int iwl3945_led_register(struct iwl3945_priv *priv)
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 @@ int iwl3945_led_register(struct iwl3945_priv *priv)
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 @@ int iwl3945_led_register(struct iwl3945_priv *priv)
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 @@ int iwl3945_led_register(struct iwl3945_priv *priv)
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 b1d2f6b8b25..47b7e0bac80 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-led.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.h
@@ -54,7 +54,7 @@ struct iwl3945_led {
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 94e177a9f51..c2a76785b66 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -514,6 +514,23 @@ static inline void iwl3945_dbg_report_frame(struct iwl3945_priv *priv,
}
#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 @@ static void iwl3945_add_radiotap(struct iwl3945_priv *priv,
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 @@ static void iwl3945_handle_data_packet(struct iwl3945_priv *priv, int is_data,
/* 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 @@ static void iwl3945_handle_data_packet(struct iwl3945_priv *priv, int is_data,
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 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv,
}
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,27 +857,12 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv,
}
}
- iwl3945_handle_data_packet(priv, 0, 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);
+ case IEEE80211_FTYPE_DATA:
+ /* fall through */
+ default:
+ iwl3945_pass_packet_to_mac80211(priv, rxb, &rx_status);
break;
}
- }
}
int iwl3945_hw_txq_attach_buf_to_tfd(struct iwl3945_priv *priv, void *ptr,
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
index 9c0a09eaca6..fa81ba1af3d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -510,8 +510,6 @@ struct iwl3945_ucode {
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 @@ extern int iwl3945_send_add_station(struct iwl3945_priv *priv,
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 @@ struct iwl3945_priv {
u8 last_blink_rate;
u8 allow_blinking;
unsigned int rxtxpackets;
+ u64 led_tpt;
#endif
@@ -859,14 +849,6 @@ struct iwl3945_priv {
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 10f630e1afa..fce950f4163 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
@@ -819,6 +819,7 @@ enum {
#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 c7ebb3bf06f..3ccb84aa5db 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
@@ -2265,9 +2265,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta,
/* 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 04365b39279..9afecb81371 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 @@ static void iwl4965_gain_computation(struct iwl_priv *priv,
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 @@ static int iwl4965_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
{
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 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id,
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 @@ static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
.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 @@ struct iwl_cfg iwl4965_agn_cfg = {
.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 4efe0c06b5b..17d4f31c593 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 717db0d5ffb..878d6193b23 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -370,6 +370,16 @@ static void iwl5000_chain_noise_reset(struct iwl_priv *priv)
}
}
+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 @@ static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
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 @@ static int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
{
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 @@ static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = {
.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_ops iwl5000_ops = {
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 @@ struct iwl_cfg iwl5300_agn_cfg = {
.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 fe05d60ebe6..e9bb1de0ce3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -556,6 +556,8 @@ enum {
#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 @@ struct iwl4965_csa_notification {
* 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 @@ struct iwl4965_ac_qos {
* 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 @@ struct iwl4965_rx_mpdu_res_start {
/* 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 @@ struct iwl_ct_kill_config {
*
*****************************************************************************/
+#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 @@ struct iwl_scan_channel {
/*
* 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 @@ struct iwl_ssid_ie {
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 @@ struct iwl5000_calibration_chain_noise_gain_cmd {
* 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 eee220cf52a..a44188bf445 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -825,7 +825,7 @@ int iwl_setup_mac(struct iwl_priv *priv)
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 dafd62c7dfd..db66114f1e5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -70,7 +70,7 @@ struct iwl_host_cmd;
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 @@ struct iwl_hcmd_utils_ops {
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 @@ struct iwl_mod_params {
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 c8d3d97cf48..4d789e353e3 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 iwl4965_agn_cfg;
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 {
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 iwl_cmd {
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 @@ struct iwl_ht_info {
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 @@ union iwl4965_qos_capabity {
};
/* 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 @@ struct iwl_ucode {
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 @@ struct iwl_priv {
#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 @@ struct iwl_priv {
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 iwl_priv {
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 aa6ad18494c..899d7a2567a 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 @@ static const struct {
{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 @@ static int iwl_send_led_cmd(struct iwl_priv *priv,
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 @@ static int iwl4965_led_on_reg(struct iwl_priv *priv, int led_id)
}
#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 @@ static int iwl4965_led_off_reg(struct iwl_priv *priv, int led_id)
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 @@ static int iwl4965_led_associated(struct iwl_priv *priv, int led_id)
/*
* 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 @@ static void iwl4965_led_brightness_set(struct led_classdev *led_cdev,
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 @@ static void iwl4965_led_brightness_set(struct led_classdev *led_cdev,
/*
* 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 @@ static int iwl_leds_register_led(struct iwl_priv *priv,
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 @@ static int iwl_leds_register_led(struct iwl_priv *priv,
/*
* 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 @@ static inline int is_rf_kill(struct iwl_priv *priv)
*/
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 @@ void iwl_leds_background(struct iwl_priv *priv)
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 @@ void iwl_leds_background(struct iwl_priv *priv)
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 @@ int iwl_leds_register(struct iwl_priv *priv)
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 @@ int iwl_leds_register(struct iwl_priv *priv)
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 @@ int iwl_leds_register(struct iwl_priv *priv)
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 @@ exit_fail:
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 5bb04128cd6..1980ae5a7e8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.h
+++ b/drivers/net/wireless/iwlwifi/iwl-led.h
@@ -49,14 +49,13 @@ enum led_type {
};
-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 3e8500ecf59..e2d9afba38a 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 @@ static void iwl_add_radiotap(struct iwl_priv *priv,
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 @@ static void iwl_add_radiotap(struct iwl_priv *priv,
/* 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 5b420b43af5..efc750d2fc5 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 @@ static void iwl_rx_scan_start_notif(struct iwl_priv *priv,
"(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 @@ void iwl_setup_rx_scan_handlers(struct iwl_priv *priv)
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 @@ static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
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 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
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 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
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 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
/* 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 @@ static u32 iwl_scan_tx_ant(struct iwl_priv *priv, enum ieee80211_band band)
break;
}
}
-
+ IWL_DEBUG_SCAN("select TX ANT = %c\n", 'A' + ind);
return scan_tx_ant[ind];
}
@@ -693,7 +706,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
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 @@ static void iwl_bg_request_scan(struct work_struct *data)
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 @@ static void iwl_bg_request_scan(struct work_struct *data)
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 0be2a71990b..9b50b1052b0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -601,13 +601,7 @@ static void iwl_tx_cmd_build_basic(struct iwl_priv *priv,
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 1a7d18fea89..4a22d3fba75 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -2035,36 +2035,6 @@ static int iwl3945_send_power_mode(struct iwl3945_priv *priv, u32 mode)
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 @@ static int iwl3945_scan_cancel_timeout(struct iwl3945_priv *priv, unsigned long
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 @@ void iwl3945_set_decrypted_flag(struct iwl3945_priv *priv, struct sk_buff *skb,
}
}
-#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 @@ static void iwl3945_bg_post_associate(struct work_struct *data)
break;
}
- iwl3945_sequence_reset(priv);
-
iwl3945_activate_qos(priv, 0);
/* we have just associated, don't start scan too early */
@@ -6907,6 +6795,9 @@ static void iwl3945_config_ap(struct iwl3945_priv *priv)
* 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 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
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 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw,
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 @@ static struct ieee80211_ops iwl3945_hw_ops = {
.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 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
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 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
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 int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
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 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
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 7f65d9123b2..71f5da3fe5c 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -250,6 +250,9 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
/* 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 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
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 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
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 @@ static void iwl4965_ht_conf(struct iwl_priv *priv,
/*
* QoS support
*/
-static int iwl4965_send_qos_params_command(struct iwl_priv *priv,
- struct iwl4965_qosparam_cmd *qos)
-{
-
- 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)
+static void iwl_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 @@ static void iwl4965_activate_qos(struct iwl_priv *priv, u8 force)
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 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
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 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
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 @@ static void iwl4965_mac_stop(struct ieee80211_hw *hw)
*/
mutex_lock(&priv->mutex);
iwl_scan_cancel_timeout(priv, 100);
- cancel_delayed_work(&priv->post_associate);
mutex_unlock(&priv->mutex);
}
@@ -2855,6 +2836,7 @@ out:
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 @@ static void iwl4965_config_ap(struct iwl_priv *priv)
/* 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 @@ static void iwl4965_config_ap(struct iwl_priv *priv)
* 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 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
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 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
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 @@ static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw,
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 @@ static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
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 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw)
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 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
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 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
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 @@ static struct ieee80211_ops iwl4965_hw_ops = {
.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 @@ static struct pci_device_id iwl_hw_card_ids[] = {
{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 343ed38f772..4b274562f96 100644
--- a/drivers/net/wireless/libertas/scan.c
+++ b/drivers/net/wireless/libertas/scan.c
@@ -567,11 +567,11 @@ static int lbs_process_bss(struct bss_descriptor *bss,
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 5d30c57e396..913dc9fe08f 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -126,7 +126,7 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
(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 ee953ca0c6a..4c0538d6099 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -733,6 +733,17 @@ static int rt2400pci_init_registers(struct rt2x00_dev *rt2x00dev)
(rt2x00dev->rx->data_size / 128));
rt2x00pci_register_write(rt2x00dev, CSR9, reg);
+ rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+ rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 0);
+ rt2x00_set_field32(&reg, CSR14_TSF_SYNC, 0);
+ rt2x00_set_field32(&reg, CSR14_TBCN, 0);
+ rt2x00_set_field32(&reg, CSR14_TCFP, 0);
+ rt2x00_set_field32(&reg, CSR14_TATIMW, 0);
+ rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
+ rt2x00_set_field32(&reg, CSR14_CFP_COUNT_PRELOAD, 0);
+ rt2x00_set_field32(&reg, CSR14_TBCM_PRELOAD, 0);
+ rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+
rt2x00pci_register_write(rt2x00dev, CNT3, 0x3f080000);
rt2x00pci_register_read(rt2x00dev, ARCSR0, &reg);
@@ -1058,6 +1069,40 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
/*
* 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, &reg);
+ rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 0);
+ rt2x00_set_field32(&reg, CSR14_TBCN, 0);
+ rt2x00_set_field32(&reg, 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 @@ static u64 rt2400pci_get_tsf(struct ieee80211_hw *hw)
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, &reg);
- rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 0);
- rt2x00_set_field32(&reg, CSR14_TBCN, 0);
- rt2x00_set_field32(&reg, 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 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = {
.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 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
.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 0423c251c78..aa6dfb811c7 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -831,6 +831,17 @@ static int rt2500pci_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, CSR11_CW_SELECT, 0);
rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+ rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+ rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 0);
+ rt2x00_set_field32(&reg, CSR14_TSF_SYNC, 0);
+ rt2x00_set_field32(&reg, CSR14_TBCN, 0);
+ rt2x00_set_field32(&reg, CSR14_TCFP, 0);
+ rt2x00_set_field32(&reg, CSR14_TATIMW, 0);
+ rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
+ rt2x00_set_field32(&reg, CSR14_CFP_COUNT_PRELOAD, 0);
+ rt2x00_set_field32(&reg, CSR14_TBCM_PRELOAD, 0);
+ rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+
rt2x00pci_register_write(rt2x00dev, CNT3, 0);
rt2x00pci_register_read(rt2x00dev, TXCSR8, &reg);
@@ -1216,6 +1227,40 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
/*
* 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, &reg);
+ rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 0);
+ rt2x00_set_field32(&reg, CSR14_TBCN, 0);
+ rt2x00_set_field32(&reg, 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 @@ static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw)
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, &reg);
- rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 0);
- rt2x00_set_field32(&reg, CSR14_TBCN, 0);
- rt2x00_set_field32(&reg, 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 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = {
.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 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
.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 0dd1cb537b9..3558cb21074 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -812,6 +812,13 @@ static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field16(&reg, TXRX_CSR8_BBP_ID1_VALID, 0);
rt2500usb_register_write(rt2x00dev, TXRX_CSR8, reg);
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR19, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR19_TSF_COUNT, 0);
+ rt2x00_set_field16(&reg, TXRX_CSR19_TSF_SYNC, 0);
+ rt2x00_set_field16(&reg, TXRX_CSR19_TBCN, 0);
+ rt2x00_set_field16(&reg, 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 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
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, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR19_TSF_COUNT, 0);
+ rt2x00_set_field16(&reg, TXRX_CSR19_TBCN, 0);
+ rt2x00_set_field16(&reg, 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 @@ static int rt2500usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
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 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev)
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, &reg);
- rt2x00_set_field16(&reg, TXRX_CSR19_TSF_COUNT, 0);
- rt2x00_set_field16(&reg, TXRX_CSR19_TBCN, 0);
- rt2x00_set_field16(&reg, 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 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = {
.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 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
.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 c07d9ef383f..9fab0df18c3 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -364,6 +364,8 @@ struct rt2x00_intf {
#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_conf {
*/
struct rt2x00lib_erp {
int short_preamble;
+ int cts_protection;
int ack_timeout;
int ack_consume_time;
@@ -520,6 +523,7 @@ struct rt2x00lib_ops {
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 @@ static inline u16 get_duration_res(const unsigned int size, const u8 rate)
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 48608e8cc8b..f20ca712504 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -84,6 +84,8 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
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 b48c04e80a3..8c93eb8353b 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -409,7 +409,6 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
{
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 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
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 b971bc6e7ee..bab05a56e7a 100644
--- a/drivers/net/wireless/rt2x00/rt2x00firmware.c
+++ b/drivers/net/wireless/rt2x00/rt2x00firmware.c
@@ -100,6 +100,14 @@ int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev)
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 eae5ce1d4de..f2c9b0e79b5 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -139,6 +139,14 @@ void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
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 3a1fb6d47e5..77af1df5d89 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -96,6 +96,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
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 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
}
}
+ /*
+ * 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 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw,
{
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 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw,
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 @@ int rt2x00mac_config_interface(struct ieee80211_hw *hw,
* 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 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
* 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 3ddce538ef4..7f442030f5a 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -108,12 +108,15 @@ void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
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 @@ void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
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 @@ void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
!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 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
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 bbf1048f640..70ef7bf434a 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -1198,6 +1198,15 @@ static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_54MBS, 42);
rt2x00pci_register_write(rt2x00dev, TXRX_CSR8, reg);
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_INTERVAL, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
+ rt2x00_set_field32(&reg, 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 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
/*
* 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, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
+ rt2x00_set_field32(&reg, 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 @@ static u64 rt61pci_get_tsf(struct ieee80211_hw *hw)
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, &reg);
- rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
- rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
- rt2x00_set_field32(&reg, 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 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = {
.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 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
.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 3ef318e098e..34c6ff27afc 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -1016,6 +1016,15 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_54MBS, 42);
rt73usb_register_write(rt2x00dev, TXRX_CSR8, reg);
+ rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_INTERVAL, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
+ rt2x00_set_field32(&reg, 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, &reg);
@@ -1334,6 +1343,49 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
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, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
+ rt2x00_set_field32(&reg, 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 @@ static int rt73usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
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 @@ static u64 rt73usb_get_tsf(struct ieee80211_hw *hw)
#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, &reg);
- rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
- rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
- rt2x00_set_field32(&reg, 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 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = {
.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 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
.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 33527e58256..d3067b1216c 100644
--- a/drivers/net/wireless/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl8187_dev.c
@@ -430,8 +430,10 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev)
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 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev)
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 @@ static int rtl8187b_init_hw(struct ieee80211_hw *dev)
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 @@ static struct usb_driver rtl8187_driver = {
.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 1e059de9711..1bae8990341 100644
--- a/drivers/net/wireless/rtl8187_rtl8225.c
+++ b/drivers/net/wireless/rtl8187_rtl8225.c
@@ -307,7 +307,8 @@ static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
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 @@ static void rtl8225z2_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
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 @@ static void rtl8225_rf_stop(struct ieee80211_hw *dev)
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 d39ed0295b6..20c5b6ead0f 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 665f76af2fe..fcc532bb6a7 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -707,6 +707,7 @@ static void zd_op_remove_interface(struct ieee80211_hw *hw,
{
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 @@ static int zd_op_config_interface(struct ieee80211_hw *hw,
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 void zd_op_bss_info_changed(struct ieee80211_hw *hw,
}
}
-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 @@ static const struct ieee80211_ops zd_ops = {
.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 aa0737019e3..6080449fbec 100644
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -364,8 +364,6 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
/* 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 @@ extern int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
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 @@ struct dccp_sock {
__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 563fae542da..4c6307ad9fd 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 99efbed81fa..7cf7824df77 100644
--- a/include/linux/pkt_cls.h
+++ b/include/linux/pkt_cls.h
@@ -374,6 +374,7 @@ enum
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 0fe5a0ded3e..4bf8cade9db 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 2ca6bae8872..fb0c215a305 100644
--- a/include/linux/xfrm.h
+++ b/include/linux/xfrm.h
@@ -339,6 +339,7 @@ struct xfrm_usersa_info {
#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 656442c6b1c..24a69f6075c 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -115,17 +115,17 @@ enum ieee80211_max_queues {
* 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 @@ struct ieee80211_bss_conf {
* 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 @@ enum mac80211_tx_control_flags {
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 @@ struct ieee80211_rx_status {
* @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 @@ struct ieee80211_if_init_conf {
};
/**
+ * 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 @@ enum ieee80211_tkip_key_type {
* 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 @@ enum ieee80211_ampdu_mlme_action {
* 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_ops {
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 d5d76ec7abb..8f5b75734dd 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -223,23 +223,23 @@ static inline void nf_ct_refresh(struct nf_conn *ct,
__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 8efa399823e..9efd3c67c1d 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -518,19 +518,35 @@ static int vlan_dev_open(struct net_device *dev)
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 497df086141..a072ea5ca6f 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -373,6 +373,10 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
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 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
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 @@ err2:
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 3f794131921..c1f4e0d428c 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -318,7 +318,7 @@ static struct attribute_group netstat_group = {
.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 @@ int netdev_register_kobject(struct net_device *net)
#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 a1929f33d70..f6756e0c9e6 100644
--- a/net/dccp/ccids/ccid3.c
+++ b/net/dccp/ccids/ccid3.c
@@ -794,7 +794,7 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
{
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 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
}
/*
- * 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 849e181e698..bcd6ac415bb 100644
--- a/net/dccp/ccids/lib/loss_interval.c
+++ b/net/dccp/ccids/lib/loss_interval.c
@@ -90,14 +90,14 @@ u8 tfrc_lh_update_i_mean(struct tfrc_loss_hist *lh, struct sk_buff *skb)
{
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 @@ u8 tfrc_lh_update_i_mean(struct tfrc_loss_hist *lh, struct sk_buff *skb)
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 @@ int tfrc_lh_interval_add(struct tfrc_loss_hist *lh, struct tfrc_rx_hist *rh,
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 20af1a69342..6cc108afdc3 100644
--- a/net/dccp/ccids/lib/packet_history.c
+++ b/net/dccp/ccids/lib/packet_history.c
@@ -153,7 +153,7 @@ void tfrc_rx_packet_history_exit(void)
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 @@ static inline void tfrc_rx_hist_entry_from_skb(struct tfrc_rx_hist_entry *entry,
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 @@ static void tfrc_rx_hist_swap(struct tfrc_rx_hist *h, const u8 a, const u8 b)
*
* 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 @@ static void __one_after_loss(struct tfrc_rx_hist *h, struct sk_buff *skb, u32 n2
/* 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 @@ static int __two_after_loss(struct tfrc_rx_hist *h, struct sk_buff *skb, u32 n3)
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 @@ static int __two_after_loss(struct tfrc_rx_hist *h, struct sk_buff *skb, u32 n3)
}
/* 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 @@ static int __two_after_loss(struct tfrc_rx_hist *h, struct sk_buff *skb, u32 n3)
}
/*
- * 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 @@ static int __two_after_loss(struct tfrc_rx_hist *h, struct sk_buff *skb, u32 n3)
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 @@ static void __three_after_loss(struct tfrc_rx_hist *h)
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 @@ static void __three_after_loss(struct tfrc_rx_hist *h)
* 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 c7eeda49cb2..461cc91cce8 100644
--- a/net/dccp/ccids/lib/packet_history.h
+++ b/net/dccp/ccids/lib/packet_history.h
@@ -64,7 +64,7 @@ struct tfrc_rx_hist_entry {
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 @@ static inline struct tfrc_rx_hist_entry *
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)
-{
- 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)
+static inline bool tfrc_rx_hist_loss_pending(const struct tfrc_rx_hist *h)
{
- 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 1b2cea244e1..32617e0576c 100644
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -153,6 +153,21 @@ static inline u64 max48(const u64 seq1, const u64 seq2)
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 43bc24e761d..dc7c158a2f4 100644
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -124,12 +124,12 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
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 @@ static void dccp_encode_value_var(const u32 value, unsigned char *to,
*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 @@ EXPORT_SYMBOL_GPL(dccp_insert_option);
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 d16ae4623be..f155a66d6eb 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -1357,17 +1357,17 @@ static int check_leaf(struct trie *t, struct leaf *l,
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 @@ static int fn_trie_lookup(struct fib_table *tb, const struct flowi *flp,
/* 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 @@ static int fn_trie_lookup(struct fib_table *tb, const struct flowi *flp,
}
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 438fab9c62a..c9ab47b966b 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -118,6 +118,31 @@ static struct timer_list ipmr_expire_timer;
/* 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 @@ struct net_device *ipmr_new_tunnel(struct vifctl *v)
if (dev_open(dev))
goto failure;
+ dev_hold(dev);
}
}
return dev;
@@ -225,6 +251,8 @@ static struct net_device *ipmr_reg_vif(void)
if (dev_open(dev))
goto failure;
+ dev_hold(dev);
+
return dev;
failure:
@@ -239,9 +267,10 @@ failure:
/*
* 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 @@ static int vif_delete(int vifi)
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 @@ static int vif_add(struct vifctl *vifc, int mrtsock)
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 @@ static int vif_add(struct vifctl *vifc, int mrtsock)
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 @@ static int vif_add(struct vifctl *vifc, int mrtsock)
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 @@ static int vif_add(struct vifctl *vifc, int mrtsock)
/* 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 @@ static void mroute_clean_tables(struct sock *sk)
*/
for (i=0; i<maxvif; i++) {
if (!(vif_table[i].flags&VIFF_STATIC))
- vif_delete(i);
+ vif_delete(i, 0);
}
/*
@@ -909,7 +953,7 @@ int ip_mroute_setsockopt(struct sock *sk,int optname,char __user *optval,int opt
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 @@ static int ipmr_device_event(struct notifier_block *this, unsigned long event, v
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 7750c97fde7..ffeaffc3fff 100644
--- a/net/ipv4/netfilter/nf_nat_snmp_basic.c
+++ b/net/ipv4/netfilter/nf_nat_snmp_basic.c
@@ -439,8 +439,8 @@ static unsigned char asn1_oid_decode(struct asn1_ctx *ctx,
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 5ff0ce6e9d3..7ddc30f0744 100644
--- a/net/ipv4/tcp_probe.c
+++ b/net/ipv4/tcp_probe.c
@@ -224,7 +224,7 @@ static __init int tcpprobe_init(void)
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 602ea826f0a..9f1084b4c0e 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -443,7 +443,7 @@ looped_back:
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 cfac26d674e..0b41aa2675f 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -443,6 +443,7 @@ static struct net_device *ip6mr_reg_vif(void)
if (dev_open(dev))
goto failure;
+ dev_hold(dev);
return dev;
failure:
@@ -595,6 +596,7 @@ static int mif6_add(struct mif6ctl *vifc, int mrtsock)
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 @@ static int mif6_add(struct mif6ctl *vifc, int mrtsock)
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 @@ static int mif6_add(struct mif6ctl *vifc, int mrtsock)
/* 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 81087281b03..8e7ba0e62cf 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -50,14 +50,11 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
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_add_iface(struct wiphy *wiphy, char *name,
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 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
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 @@ static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev)
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 d20d90eead1..ee509f1109e 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -70,16 +70,6 @@ DEBUGFS_READONLY_FILE(rate_ctrl_alg, 100, "%s",
/* 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 @@ static ssize_t format_devstat_counter(struct ieee80211_local *local,
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 b2089b2da48..475f89a8aee 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -156,6 +156,8 @@ static const struct file_operations name##_ops = { \
/* 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(flags);
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 @@ IEEE80211_IF_WFILE(min_discovery_timeout,
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_sta_files(struct ieee80211_sub_if_data *sdata)
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 add_files(struct ieee80211_sub_if_data *sdata)
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_sta_files(struct ieee80211_sub_if_data *sdata)
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 @@ static void del_mesh_config(struct ieee80211_sub_if_data *sdata)
}
#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 @@ void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata)
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 @@ static int netdev_notify(struct notifier_block *nb,
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 a690071fde8..7af731f0b73 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_add_netdev(
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 02a8753a4ec..cbea0154ee3 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -237,8 +237,6 @@ struct ieee80211_if_ap {
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_wds {
};
struct ieee80211_if_vlan {
- struct ieee80211_sub_if_data *ap;
struct list_head list;
};
@@ -422,8 +419,6 @@ struct ieee80211_sub_if_data {
*/
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_sub_if_data {
struct ieee80211_key *keys[NUM_DEFAULT_KEYS];
struct ieee80211_key *default_key;
+ /* BSS configuration for this interface. */
+ struct ieee80211_bss_conf bss_conf;
+
/*
- * 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.
+ * 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_bss_conf bss_conf;
- struct ieee80211_if_ap *bss; /* BSS that this device belongs to */
+ 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 @@ struct ieee80211_sub_if_data *vif_to_sdata(struct ieee80211_vif *p)
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 @@ struct ieee80211_local {
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 @@ static inline int ieee80211_is_multiqueue(struct ieee80211_local *local)
#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 @@ static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
/* 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 @@ int ieee80211_sta_scan_results(struct net_device *dev,
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 @@ static inline void ieee80211_start_mesh(struct net_device *dev)
{}
#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 eeb16926aa7..610ed1d9893 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,145 +18,91 @@
#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);
-
- INIT_LIST_HEAD(&sdata->key_list);
-}
+ ieee80211_debugfs_remove_netdev(sdata);
-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);
-}
-
-/* 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,
- 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;
-
- ASSERT_RTNL();
- ndev = alloc_netdev(sizeof(*sdata) + local->hw.vif_data_size,
- name, ieee80211_if_setup);
- if (!ndev)
- return -ENOMEM;
+ sdata->fragment_next = 0;
- ndev->needed_headroom = local->tx_headroom +
- 4*6 /* four MAC addresses */
- + 2 + 2 + 2 + 2 /* ctl, dur, seq, qos */
- + 6 /* mesh */
- + 8 /* rfc1042/bridge tunnel */
- - ETH_HLEN /* ethernet hard_header_len */
- + IEEE80211_ENCRYPT_HEADROOM;
- ndev->needed_tailroom = IEEE80211_ENCRYPT_TAILROOM;
-
- ret = dev_alloc_name(ndev, ndev->name);
- if (ret < 0)
- 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);
- ndev->ieee80211_ptr = &sdata->wdev;
- sdata->wdev.wiphy = local->hw.wiphy;
- sdata->vif.type = IEEE80211_IF_TYPE_AP;
- sdata->dev = ndev;
- sdata->local = local;
- ieee80211_if_sdata_init(sdata);
-
- ret = register_netdevice(ndev);
- if (ret)
- goto fail;
-
- ieee80211_debugfs_add_netdev(sdata);
- ieee80211_if_set_type(ndev, type);
+ 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);
- if (ieee80211_vif_is_mesh(&sdata->vif) &&
- params && params->mesh_id_len)
- ieee80211_if_sta_set_mesh_id(&sdata->u.sta,
- params->mesh_id_len,
- params->mesh_id);
+ while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
+ local->total_ps_buffered--;
+ dev_kfree_skb(skb);
+ }
- /* we're under RTNL so all this is fine */
- if (unlikely(local->reg_state == IEEE80211_DEV_UNREGISTERED)) {
- __ieee80211_if_del(local, sdata);
- return -ENODEV;
+ 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;
}
- list_add_tail_rcu(&sdata->list, &local->interfaces);
- if (new_dev)
- *new_dev = ndev;
-
- return 0;
-
-fail:
- free_netdev(ndev);
- return ret;
+ flushed = sta_info_flush(local, sdata);
+ WARN_ON(flushed);
}
-void ieee80211_if_set_type(struct net_device *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_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;
+ struct ieee80211_if_sta *ifsta;
- /*
- * Called even when register_netdevice fails, it would
- * oops if assigned before initialising the rest.
- */
- dev->uninit = ieee80211_if_reinit;
+ /* clear type-dependent union */
+ memset(&sdata->u, 0, sizeof(sdata->u));
- /* most have no BSS pointer */
- sdata->bss = NULL;
+ /* and set some type-dependent values */
sdata->vif.type = type;
- sdata->basic_rates = 0;
+ /* only monitor differs */
+ sdata->dev->type = ARPHRD_ETHER;
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;
-
+ case IEEE80211_IF_TYPE_IBSS:
ifsta = &sdata->u.sta;
INIT_WORK(&ifsta->work, ieee80211_sta_work);
setup_timer(&ifsta->timer, ieee80211_sta_timer,
@@ -171,153 +118,152 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
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->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_change_if_type(sdata, oldtype);
+
+ ieee80211_debugfs_add_netdev(sdata);
}
-/* Must be called with rtnl lock held. */
-void ieee80211_if_reinit(struct net_device *dev)
+int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
+ enum ieee80211_if_types type)
{
- 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();
+
+ 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_sub_if_data *sdata = NULL;
+ int ret, i;
ASSERT_RTNL();
- ieee80211_free_keys(sdata);
+ ndev = alloc_netdev(sizeof(*sdata) + local->hw.vif_data_size,
+ name, ieee80211_if_setup);
+ if (!ndev)
+ return -ENOMEM;
- ieee80211_if_sdata_deinit(sdata);
+ ndev->needed_headroom = local->tx_headroom +
+ 4*6 /* four MAC addresses */
+ + 2 + 2 + 2 + 2 /* ctl, dur, seq, qos */
+ + 6 /* mesh */
+ + 8 /* rfc1042/bridge tunnel */
+ - ETH_HLEN /* ethernet hard_header_len */
+ + IEEE80211_ENCRYPT_HEADROOM;
+ ndev->needed_tailroom = IEEE80211_ENCRYPT_TAILROOM;
- /* Need to handle mesh specially to allow eliding the function call */
- if (ieee80211_vif_is_mesh(&sdata->vif))
- mesh_rmc_free(dev);
+ ret = dev_alloc_name(ndev, ndev->name);
+ if (ret < 0)
+ goto fail;
- 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);
- }
- }
+ memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
+ SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));
- beacon = sdata->u.ap.beacon;
- rcu_assign_pointer(sdata->u.ap.beacon, NULL);
- synchronize_rcu();
- kfree(beacon);
+ /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */
+ sdata = netdev_priv(ndev);
+ ndev->ieee80211_ptr = &sdata->wdev;
- while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
- local->total_ps_buffered--;
- dev_kfree_skb(skb);
- }
+ /* initialise type-independent data */
+ sdata->wdev.wiphy = local->hw.wiphy;
+ sdata->local = local;
+ sdata->dev = ndev;
- 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;
- }
+ for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
+ skb_queue_head_init(&sdata->fragments[i].skb_list);
- break;
- case IEEE80211_IF_TYPE_MNTR:
- dev->type = ARPHRD_ETHER;
- break;
- case IEEE80211_IF_TYPE_VLAN:
- sdata->u.vlan.ap = NULL;
- break;
- }
+ INIT_LIST_HEAD(&sdata->key_list);
- flushed = sta_info_flush(local, sdata);
- WARN_ON(flushed);
+ sdata->force_unicast_rateidx = -1;
+ sdata->max_ratectrl_rateidx = -1;
- memset(&sdata->u, 0, sizeof(sdata->u));
- ieee80211_if_sdata_init(sdata);
-}
+ /* setup type-dependent data */
+ ieee80211_setup_sdata(sdata, type);
-/* 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;
+ ret = register_netdevice(ndev);
+ if (ret)
+ goto fail;
- ieee80211_debugfs_remove_netdev(sdata);
- unregister_netdevice(dev);
- /* Except master interface, the net_device will be freed by
- * net_device->destructor (i. e. ieee80211_if_free). */
+ ndev->uninit = ieee80211_teardown_sdata;
+
+ if (ieee80211_vif_is_mesh(&sdata->vif) &&
+ params && params->mesh_id_len)
+ ieee80211_if_sta_set_mesh_id(&sdata->u.sta,
+ params->mesh_id_len,
+ params->mesh_id);
+
+ list_add_tail_rcu(&sdata->list, &local->interfaces);
+
+ if (new_dev)
+ *new_dev = ndev;
+
+ return 0;
+
+ fail:
+ free_netdev(ndev);
+ return ret;
}
-/* Must be called with rtnl lock held. */
-int ieee80211_if_remove(struct net_device *dev, const char *name, int id)
+void ieee80211_if_remove(struct net_device *dev)
{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_sub_if_data *sdata, *n;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
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;
- }
- }
- return -ENODEV;
+ list_del_rcu(&sdata->list);
+ synchronize_rcu();
+ unregister_netdevice(dev);
}
-void ieee80211_if_free(struct net_device *dev)
+/*
+ * 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_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_sub_if_data *sdata, *tmp;
- ieee80211_if_sdata_deinit(sdata);
- free_netdev(dev);
+ ASSERT_RTNL();
+
+ list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) {
+ list_del(&sdata->list);
+ unregister_netdevice(sdata->dev);
+ }
}
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 1c4d3ba6b87..36859e79492 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -105,7 +105,7 @@ static int ieee80211_master_open(struct net_device *dev)
/* 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 @@ static int ieee80211_master_stop(struct net_device *dev)
/* 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 @@ static int ieee80211_open(struct net_device *dev)
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 @@ static int ieee80211_open(struct net_device *dev)
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 @@ static int ieee80211_open(struct net_device *dev)
*/
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 @@ static int ieee80211_open(struct net_device *dev)
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 @@ static int ieee80211_open(struct net_device *dev)
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 @@ static int ieee80211_open(struct net_device *dev)
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 @@ static int ieee80211_open(struct net_device *dev)
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 @@ static int ieee80211_stop(struct net_device *dev)
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 @@ static int ieee80211_stop(struct net_device *dev)
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 @@ static const struct header_ops ieee80211_header_ops = {
.cache_update = eth_header_cache_update,
};
-/* Must not be called for mdev */
void ieee80211_if_setup(struct net_device *dev)
{
ether_setup(dev);
@@ -998,62 +981,52 @@ void ieee80211_if_setup(struct net_device *dev)
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;
}
- 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);
-}
+ if (WARN_ON(!conf.bssid && (changed & IEEE80211_IFCC_BSSID)))
+ return -EINVAL;
-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 (WARN_ON(!conf.ssid && (changed & IEEE80211_IFCC_SSID)))
+ return -EINVAL;
- 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);
+ return local->ops->config_interface(local_to_hw(local),
+ &sdata->vif, &conf);
}
int ieee80211_hw_config(struct ieee80211_local *local)
@@ -1659,7 +1632,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
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 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
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 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
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 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
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 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
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 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
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 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
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 @@ fail_sta_info:
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 @@ EXPORT_SYMBOL(ieee80211_register_hw);
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 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
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 dbc8cf454bc..8f51375317d 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -78,7 +78,7 @@ static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,
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 @@ static void ieee80211_sta_wmm_params(struct net_device *dev,
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 @@ static void ieee80211_set_associated(struct net_device *dev,
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 @@ static void ieee80211_send_assoc(struct net_device *dev,
(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 @@ static int ieee80211_privacy_mismatch(struct net_device *dev,
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 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
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 @@ static void __ieee80211_rx_bss_hash_add(struct net_device *dev,
/* 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_free(struct ieee80211_sta_bss *bss)
}
-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 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
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 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
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 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
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,61 +2490,22 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
memcpy(pos, &bss->supp_rates[8], rates);
}
- control = IEEE80211_SKB_CB(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);
- }
+ ifsta->probe_resp = skb;
- 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);
+ ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON);
+ }
- if (skb) {
- printk(KERN_DEBUG "%s: Failed to configure IBSS beacon "
- "template\n", dev->name);
- dev_kfree_skb(skb);
+ 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 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
*/
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 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
}
}
- ieee80211_rx_bss_put(dev, bss);
+ ieee80211_rx_bss_put(local, bss);
}
@@ -3338,7 +3289,7 @@ static void ieee80211_mesh_housekeeping(struct net_device *dev,
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 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
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 @@ static int ieee80211_sta_create_ibss(struct net_device *dev,
}
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 @@ static int ieee80211_sta_find_ibss(struct net_device *dev,
" 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 @@ int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len)
{
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 @@ int ieee80211_sta_set_bssid(struct net_device *dev, u8 *bssid)
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 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw)
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 @@ static int ieee80211_sta_start_scan(struct net_device *dev,
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 @@ struct sta_info *ieee80211_ibss_add_sta(struct net_device *dev,
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 @@ void ieee80211_notify_mac(struct ieee80211_hw *hw,
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 2078803d358..0a9135b974b 100644
--- a/net/mac80211/rc80211_pid.h
+++ b/net/mac80211/rc80211_pid.h
@@ -141,7 +141,6 @@ struct rc_pid_events_file_info {
* 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 rc_pid_debugfs_entries {
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 @@ struct rc_pid_info {
/* 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 62388f8e902..a914ba73ccf 100644
--- a/net/mac80211/rc80211_pid_algo.c
+++ b/net/mac80211/rc80211_pid_algo.c
@@ -259,8 +259,8 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev,
/* 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 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev,
/* 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 @@ static void *rate_control_pid_alloc(struct ieee80211_local *local)
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 @@ static void *rate_control_pid_alloc(struct ieee80211_local *local)
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 @@ static void *rate_control_pid_alloc(struct ieee80211_local *local)
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 @@ static void rate_control_pid_free(void *priv)
#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 fab443d717e..6d9ae67c27c 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -334,13 +334,18 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
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 @@ static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta)
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 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
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 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
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 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
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 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
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 47d2c1bbfca..f2ba653b9d6 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -320,7 +320,9 @@ int sta_info_insert(struct sta_info *sta)
/* 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 inline void __bss_tim_clear(struct ieee80211_if_ap *bss, u16 aid)
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 @@ void sta_info_set_tim_bit(struct sta_info *sta)
{
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 @@ void sta_info_set_tim_bit(struct sta_info *sta)
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 @@ void sta_info_clear_tim_bit(struct sta_info *sta)
{
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 @@ void __sta_info_unlink(struct sta_info **sta)
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 @@ void __sta_info_unlink(struct sta_info **sta)
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 94311dcfe04..109db787ccb 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -285,6 +285,7 @@ struct sta_info {
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 9bd9faac3c3..0fbadd8b983 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 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
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 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
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 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
* 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 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
}
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 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
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 sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
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 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
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 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
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 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
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 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
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 ce62b163b82..89ce4e07bd8 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -428,8 +428,6 @@ void ieee80211_iterate_active_interfaces(
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 @@ void ieee80211_iterate_active_interfaces_atomic(
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 736c32e340f..34fa8ed1e78 100644
--- a/net/mac80211/wext.c
+++ b/net/mac80211/wext.c
@@ -296,15 +296,7 @@ static int ieee80211_ioctl_siwmode(struct net_device *dev,
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 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev,
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 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev,
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 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev,
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 @@ static int ieee80211_ioctl_giwencode(struct net_device *dev,
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 @@ static const iw_handler ieee80211_handler[] =
(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 212a0888408..28d03e64200 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -848,10 +848,10 @@ acct:
}
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 @@ void __nf_ct_kill_acct(struct nf_conn *ct,
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 740acd6bc7d..420a10d8eb1 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -844,8 +844,14 @@ static int tcp_packet(struct nf_conn *ct,
/* 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 fdc14a0d21a..0aec318bf0e 100644
--- a/net/netlabel/netlabel_cipso_v4.c
+++ b/net/netlabel/netlabel_cipso_v4.c
@@ -584,19 +584,14 @@ list_start:
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 22c19126780..44be5d5261f 100644
--- a/net/netlabel/netlabel_mgmt.c
+++ b/net/netlabel/netlabel_mgmt.c
@@ -386,11 +386,7 @@ static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
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 @@ static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info)
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 52b2611a6eb..56f80872924 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.c
@@ -1107,11 +1107,7 @@ static int netlbl_unlabel_list(struct sk_buff *skb, struct genl_info *info)
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 beca6402f1c..9f226916668 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1173,7 +1173,8 @@ static int packet_getname(struct socket *sock, struct sockaddr *uaddr,
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 @@ static void packet_dev_mc(struct net_device *dev, struct packet_mclist *i, int w
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 @@ static int packet_mc_add(struct sock *sk, struct packet_mreq_max *mreq)
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 971b867e048..8f63a1a9401 100644
--- a/net/sched/cls_flow.c
+++ b/net/sched/cls_flow.c
@@ -36,6 +36,8 @@ struct flow_filter {
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 @@ struct flow_filter {
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 @@ static int flow_classify(struct sk_buff *skb, struct tcf_proto *tp,
}
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 @@ static int flow_classify(struct sk_buff *skb, struct tcf_proto *tp,
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 @@ static const struct nla_policy flow_policy[TCA_FLOW_MAX + 1] = {
[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 @@ static int flow_change(struct tcf_proto *tp, unsigned long base,
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 @@ static int flow_change(struct tcf_proto *tp, unsigned long base,
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 @@ static int flow_change(struct tcf_proto *tp, unsigned long base,
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 @@ static int flow_change(struct tcf_proto *tp, unsigned long base,
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 @@ static int flow_change(struct tcf_proto *tp, unsigned long base,
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 @@ err1:
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 @@ static int flow_init(struct tcf_proto *tp)
{
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 @@ static int flow_dump(struct tcf_proto *tp, unsigned long fh,
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 1debe1cb054..61ceae0b956 100644
--- a/net/wanrouter/Kconfig
+++ b/net/wanrouter/Kconfig
@@ -20,8 +20,6 @@ config WAN_ROUTER
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 79270903bda..ab015c62d56 100644
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -29,3 +29,14 @@ config WIRELESS_EXT
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 b976d9ed10e..04c41504f84 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -277,9 +277,8 @@ static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info *
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;
-
}
/*