summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/802/psnap.c1
-rw-r--r--net/8021q/vlan.c29
-rw-r--r--net/8021q/vlan_dev.c2
-rw-r--r--net/9p/trans_virtio.c21
-rw-r--r--net/ax25/ax25_subr.c11
-rw-r--r--net/bluetooth/bnep/bnep.h4
-rw-r--r--net/bluetooth/bnep/core.c4
-rw-r--r--net/bluetooth/bnep/netdev.c4
-rw-r--r--net/bluetooth/bnep/sock.c4
-rw-r--r--net/bluetooth/hci_core.c2
-rw-r--r--net/bluetooth/hci_sysfs.c7
-rw-r--r--net/bluetooth/rfcomm/core.c4
-rw-r--r--net/bluetooth/rfcomm/sock.c2
-rw-r--r--net/bluetooth/rfcomm/tty.c15
-rw-r--r--net/bridge/br.c2
-rw-r--r--net/bridge/br_device.c13
-rw-r--r--net/bridge/br_fdb.c3
-rw-r--r--net/bridge/br_forward.c4
-rw-r--r--net/bridge/br_if.c2
-rw-r--r--net/bridge/br_input.c12
-rw-r--r--net/bridge/br_ioctl.c2
-rw-r--r--net/bridge/br_notify.c2
-rw-r--r--net/bridge/br_private.h3
-rw-r--r--net/bridge/br_private_stp.h2
-rw-r--r--net/bridge/br_stp.c3
-rw-r--r--net/bridge/br_stp_bpdu.c2
-rw-r--r--net/bridge/br_stp_if.c2
-rw-r--r--net/bridge/br_stp_timer.c2
-rw-r--r--net/bridge/netfilter/Kconfig9
-rw-r--r--net/bridge/netfilter/Makefile1
-rw-r--r--net/bridge/netfilter/ebt_ip6.c144
-rw-r--r--net/bridge/netfilter/ebt_log.c64
-rw-r--r--net/core/dev.c16
-rw-r--r--net/core/neighbour.c9
-rw-r--r--net/core/net-sysfs.c9
-rw-r--r--net/core/pktgen.c4
-rw-r--r--net/core/rtnetlink.c23
-rw-r--r--net/core/skbuff.c7
-rw-r--r--net/core/sock.c2
-rw-r--r--net/core/sysctl_net_core.c39
-rw-r--r--net/core/user_dma.c2
-rw-r--r--net/dccp/ackvec.c29
-rw-r--r--net/dccp/ccids/ccid3.c27
-rw-r--r--net/dccp/ccids/lib/tfrc.c8
-rw-r--r--net/dccp/ccids/lib/tfrc.h25
-rw-r--r--net/dccp/ccids/lib/tfrc_equation.c8
-rw-r--r--net/dccp/ipv4.c7
-rw-r--r--net/dccp/ipv6.c1
-rw-r--r--net/dccp/minisocks.c8
-rw-r--r--net/dccp/options.c4
-rw-r--r--net/dccp/output.c2
-rw-r--r--net/dccp/probe.c2
-rw-r--r--net/ieee80211/ieee80211_rx.c2
-rw-r--r--net/ieee80211/ieee80211_tx.c86
-rw-r--r--net/ieee80211/ieee80211_wx.c89
-rw-r--r--net/ipv4/af_inet.c2
-rw-r--r--net/ipv4/arp.c7
-rw-r--r--net/ipv4/devinet.c15
-rw-r--r--net/ipv4/fib_frontend.c3
-rw-r--r--net/ipv4/fib_hash.c2
-rw-r--r--net/ipv4/fib_semantics.c7
-rw-r--r--net/ipv4/fib_trie.c2
-rw-r--r--net/ipv4/icmp.c2
-rw-r--r--net/ipv4/igmp.c2
-rw-r--r--net/ipv4/inet_diag.c2
-rw-r--r--net/ipv4/inetpeer.c2
-rw-r--r--net/ipv4/ip_forward.c2
-rw-r--r--net/ipv4/ip_fragment.c36
-rw-r--r--net/ipv4/ip_gre.c178
-rw-r--r--net/ipv4/ip_input.c2
-rw-r--r--net/ipv4/ip_options.c2
-rw-r--r--net/ipv4/ip_output.c2
-rw-r--r--net/ipv4/ip_sockglue.c2
-rw-r--r--net/ipv4/ipconfig.c2
-rw-r--r--net/ipv4/ipip.c154
-rw-r--r--net/ipv4/ipmr.c31
-rw-r--r--net/ipv4/ipvs/ip_vs_app.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_conn.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_core.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_ctl.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_dh.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_est.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_ftp.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_lblc.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_lblcr.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_lc.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_nq.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_proto.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_proto_ah.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_proto_esp.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_proto_tcp.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_proto_udp.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_rr.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_sched.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_sed.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_sh.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_sync.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_wlc.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_wrr.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_xmit.c2
-rw-r--r--net/ipv4/netfilter/Kconfig12
-rw-r--r--net/ipv4/netfilter/Makefile1
-rw-r--r--net/ipv4/netfilter/ip_queue.c3
-rw-r--r--net/ipv4/netfilter/iptable_security.c180
-rw-r--r--net/ipv4/netfilter/nf_conntrack_proto_icmp.c5
-rw-r--r--net/ipv4/netfilter/nf_nat_snmp_basic.c14
-rw-r--r--net/ipv4/proc.c2
-rw-r--r--net/ipv4/protocol.c2
-rw-r--r--net/ipv4/raw.c11
-rw-r--r--net/ipv4/route.c6
-rw-r--r--net/ipv4/syncookies.c5
-rw-r--r--net/ipv4/sysctl_net_ipv4.c2
-rw-r--r--net/ipv4/tcp.c81
-rw-r--r--net/ipv4/tcp_diag.c2
-rw-r--r--net/ipv4/tcp_input.c77
-rw-r--r--net/ipv4/tcp_ipv4.c168
-rw-r--r--net/ipv4/tcp_minisocks.c2
-rw-r--r--net/ipv4/tcp_output.c17
-rw-r--r--net/ipv4/tcp_timer.c2
-rw-r--r--net/ipv4/tunnel4.c2
-rw-r--r--net/ipv4/udp.c5
-rw-r--r--net/ipv4/udplite.c2
-rw-r--r--net/ipv6/addrconf.c166
-rw-r--r--net/ipv6/addrlabel.c106
-rw-r--r--net/ipv6/af_inet6.c4
-rw-r--r--net/ipv6/datagram.c52
-rw-r--r--net/ipv6/exthdrs.c2
-rw-r--r--net/ipv6/icmp.c2
-rw-r--r--net/ipv6/ip6_fib.c2
-rw-r--r--net/ipv6/ip6_flowlabel.c2
-rw-r--r--net/ipv6/ip6_input.c2
-rw-r--r--net/ipv6/ip6_output.c2
-rw-r--r--net/ipv6/ip6_tunnel.c28
-rw-r--r--net/ipv6/ip6mr.c26
-rw-r--r--net/ipv6/ipv6_sockglue.c35
-rw-r--r--net/ipv6/mcast.c3
-rw-r--r--net/ipv6/ndisc.c8
-rw-r--r--net/ipv6/netfilter/Kconfig12
-rw-r--r--net/ipv6/netfilter/Makefile1
-rw-r--r--net/ipv6/netfilter/ip6_queue.c3
-rw-r--r--net/ipv6/netfilter/ip6table_security.c172
-rw-r--r--net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c5
-rw-r--r--net/ipv6/netfilter/nf_conntrack_reasm.c8
-rw-r--r--net/ipv6/proc.c2
-rw-r--r--net/ipv6/protocol.c2
-rw-r--r--net/ipv6/raw.c13
-rw-r--r--net/ipv6/reassembly.c63
-rw-r--r--net/ipv6/route.c28
-rw-r--r--net/ipv6/sit.c115
-rw-r--r--net/ipv6/syncookies.c1
-rw-r--r--net/ipv6/sysctl_net_ipv6.c29
-rw-r--r--net/ipv6/tcp_ipv6.c139
-rw-r--r--net/ipv6/tunnel6.c2
-rw-r--r--net/ipv6/udp.c10
-rw-r--r--net/ipv6/udplite.c2
-rw-r--r--net/irda/af_irda.c12
-rw-r--r--net/irda/irnet/irnet.h1
-rw-r--r--net/irda/irnet/irnet_ppp.c57
-rw-r--r--net/irda/irnet/irnet_ppp.h7
-rw-r--r--net/iucv/af_iucv.c1
-rw-r--r--net/iucv/iucv.c15
-rw-r--r--net/key/af_key.c627
-rw-r--r--net/llc/llc_sap.c10
-rw-r--r--net/mac80211/Kconfig14
-rw-r--r--net/mac80211/Makefile2
-rw-r--r--net/mac80211/aes_ccm.c2
-rw-r--r--net/mac80211/aes_ccm.h2
-rw-r--r--net/mac80211/cfg.c10
-rw-r--r--net/mac80211/debugfs.c43
-rw-r--r--net/mac80211/debugfs_key.c8
-rw-r--r--net/mac80211/debugfs_netdev.c11
-rw-r--r--net/mac80211/debugfs_sta.c56
-rw-r--r--net/mac80211/ieee80211_i.h92
-rw-r--r--net/mac80211/iface.c6
-rw-r--r--net/mac80211/key.c11
-rw-r--r--net/mac80211/key.h17
-rw-r--r--net/mac80211/main.c332
-rw-r--r--net/mac80211/mesh.c38
-rw-r--r--net/mac80211/mesh.h2
-rw-r--r--net/mac80211/mesh_hwmp.c2
-rw-r--r--net/mac80211/mesh_pathtbl.c53
-rw-r--r--net/mac80211/mesh_plink.c88
-rw-r--r--net/mac80211/michael.c106
-rw-r--r--net/mac80211/michael.h8
-rw-r--r--net/mac80211/mlme.c299
-rw-r--r--net/mac80211/rate.c12
-rw-r--r--net/mac80211/rate.h33
-rw-r--r--net/mac80211/rc80211_pid.h4
-rw-r--r--net/mac80211/rc80211_pid_algo.c22
-rw-r--r--net/mac80211/rc80211_pid_debugfs.c8
-rw-r--r--net/mac80211/rx.c295
-rw-r--r--net/mac80211/sta_info.c22
-rw-r--r--net/mac80211/sta_info.h80
-rw-r--r--net/mac80211/tkip.c229
-rw-r--r--net/mac80211/tkip.h8
-rw-r--r--net/mac80211/tx.c863
-rw-r--r--net/mac80211/util.c100
-rw-r--r--net/mac80211/wep.c19
-rw-r--r--net/mac80211/wep.h2
-rw-r--r--net/mac80211/wext.c55
-rw-r--r--net/mac80211/wme.c147
-rw-r--r--net/mac80211/wme.h2
-rw-r--r--net/mac80211/wpa.c135
-rw-r--r--net/netfilter/nf_conntrack_core.c22
-rw-r--r--net/netfilter/nf_conntrack_expect.c4
-rw-r--r--net/netfilter/nf_conntrack_extend.c10
-rw-r--r--net/netfilter/nf_conntrack_helper.c1
-rw-r--r--net/netfilter/nf_conntrack_netlink.c31
-rw-r--r--net/netfilter/nf_conntrack_proto_dccp.c3
-rw-r--r--net/netfilter/nf_conntrack_proto_sctp.c80
-rw-r--r--net/netfilter/nf_conntrack_proto_tcp.c9
-rw-r--r--net/netfilter/nf_log.c4
-rw-r--r--net/netfilter/nfnetlink_queue.c1
-rw-r--r--net/netfilter/xt_CONNSECMARK.c10
-rw-r--r--net/netfilter/xt_SECMARK.c10
-rw-r--r--net/netfilter/xt_connlimit.c3
-rw-r--r--net/netlabel/netlabel_domainhash.c3
-rw-r--r--net/netlink/af_netlink.c4
-rw-r--r--net/netlink/attr.c12
-rw-r--r--net/netlink/genetlink.c6
-rw-r--r--net/packet/af_packet.c2
-rw-r--r--net/sched/cls_api.c2
-rw-r--r--net/sched/sch_dsmark.c6
-rw-r--r--net/sched/sch_gred.c3
-rw-r--r--net/sched/sch_hfsc.c2
-rw-r--r--net/sched/sch_htb.c2
-rw-r--r--net/sched/sch_red.c3
-rw-r--r--net/sctp/associola.c24
-rw-r--r--net/sctp/ipv6.c11
-rw-r--r--net/sctp/output.c2
-rw-r--r--net/sctp/outqueue.c120
-rw-r--r--net/sctp/proc.c141
-rw-r--r--net/sctp/protocol.c14
-rw-r--r--net/sctp/sm_sideeffect.c17
-rw-r--r--net/sctp/socket.c306
-rw-r--r--net/sctp/transport.c50
-rw-r--r--net/sunrpc/auth_gss/Makefile4
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c16
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_crypto.c64
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_seal.c26
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_unseal.c16
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_wrap.c79
-rw-r--r--net/sunrpc/auth_gss/gss_mech_switch.c14
-rw-r--r--net/sunrpc/auth_gss/svcauth_gss.c15
-rw-r--r--net/sunrpc/svc.c110
-rw-r--r--net/sunrpc/svc_xprt.c23
-rw-r--r--net/sunrpc/svcauth_unix.c4
-rw-r--r--net/sunrpc/xprtrdma/svc_rdma.c40
-rw-r--r--net/sunrpc/xprtrdma/svc_rdma_recvfrom.c186
-rw-r--r--net/sunrpc/xprtrdma/svc_rdma_sendto.c136
-rw-r--r--net/sunrpc/xprtrdma/svc_rdma_transport.c419
-rw-r--r--net/sysctl_net.c31
-rw-r--r--net/tipc/bcast.c4
-rw-r--r--net/tipc/cluster.c2
-rw-r--r--net/tipc/config.c11
-rw-r--r--net/tipc/core.c13
-rw-r--r--net/tipc/core.h126
-rw-r--r--net/tipc/dbg.c231
-rw-r--r--net/tipc/dbg.h12
-rw-r--r--net/tipc/discover.c14
-rw-r--r--net/tipc/discover.h2
-rw-r--r--net/tipc/link.c80
-rw-r--r--net/tipc/msg.c13
-rw-r--r--net/tipc/msg.h42
-rw-r--r--net/tipc/name_distr.c6
-rw-r--r--net/tipc/name_table.c14
-rw-r--r--net/tipc/net.c10
-rw-r--r--net/tipc/net.h2
-rw-r--r--net/tipc/netlink.c16
-rw-r--r--net/tipc/node.c26
-rw-r--r--net/tipc/port.c79
-rw-r--r--net/tipc/ref.c12
-rw-r--r--net/tipc/socket.c5
-rw-r--r--net/tipc/subscr.c249
-rw-r--r--net/tipc/subscr.h34
-rw-r--r--net/unix/af_unix.c2
-rw-r--r--net/wanrouter/wanmain.c6
-rw-r--r--net/wanrouter/wanproc.c2
-rw-r--r--net/wireless/core.c33
-rw-r--r--net/wireless/nl80211.c12
-rw-r--r--net/wireless/radiotap.c16
-rw-r--r--net/xfrm/xfrm_algo.c4
-rw-r--r--net/xfrm/xfrm_user.c11
283 files changed, 5153 insertions, 4949 deletions
diff --git a/net/802/psnap.c b/net/802/psnap.c
index 31128cb92a23..ea4643931446 100644
--- a/net/802/psnap.c
+++ b/net/802/psnap.c
@@ -20,6 +20,7 @@
#include <linux/mm.h>
#include <linux/in.h>
#include <linux/init.h>
+#include <linux/rculist.h>
static LIST_HEAD(snap_list);
static DEFINE_SPINLOCK(snap_lock);
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index 2a739adaa92b..08f14f6c5fd6 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -27,6 +27,7 @@
#include <linux/mm.h>
#include <linux/in.h>
#include <linux/init.h>
+#include <linux/rculist.h>
#include <net/p8022.h>
#include <net/arp.h>
#include <linux/rtnetlink.h>
@@ -382,6 +383,18 @@ static void vlan_sync_address(struct net_device *dev,
memcpy(vlan->real_dev_addr, dev->dev_addr, ETH_ALEN);
}
+static void vlan_transfer_features(struct net_device *dev,
+ struct net_device *vlandev)
+{
+ unsigned long old_features = vlandev->features;
+
+ vlandev->features &= ~dev->vlan_features;
+ vlandev->features |= dev->features & dev->vlan_features;
+
+ if (old_features != vlandev->features)
+ netdev_features_change(vlandev);
+}
+
static void __vlan_device_event(struct net_device *dev, unsigned long event)
{
switch (event) {
@@ -410,10 +423,8 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
int i, flgs;
struct net_device *vlandev;
- if (is_vlan_dev(dev)) {
+ if (is_vlan_dev(dev))
__vlan_device_event(dev, event);
- goto out;
- }
grp = __vlan_find_group(dev);
if (!grp)
@@ -450,6 +461,18 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
}
break;
+ case NETDEV_FEAT_CHANGE:
+ /* Propagate device features to underlying device */
+ for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
+ vlandev = vlan_group_get_device(grp, i);
+ if (!vlandev)
+ continue;
+
+ vlan_transfer_features(dev, vlandev);
+ }
+
+ break;
+
case NETDEV_DOWN:
/* Put all VLANs for this dev in the down state too. */
for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index c961f0826005..5d055c242ed8 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -663,6 +663,8 @@ static int vlan_dev_init(struct net_device *dev)
(1<<__LINK_STATE_DORMANT))) |
(1<<__LINK_STATE_PRESENT);
+ dev->features |= real_dev->features & real_dev->vlan_features;
+
/* ipv6 shared card related stuff */
dev->dev_id = real_dev->dev_id;
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c
index 42adc052b149..a6084becf971 100644
--- a/net/9p/trans_virtio.c
+++ b/net/9p/trans_virtio.c
@@ -34,6 +34,7 @@
#include <linux/ipv6.h>
#include <linux/errno.h>
#include <linux/kernel.h>
+#include <linux/spinlock.h>
#include <linux/un.h>
#include <linux/uaccess.h>
#include <linux/inet.h>
@@ -48,8 +49,8 @@
#define VIRTQUEUE_NUM 128
-/* a single mutex to manage channel initialization and attachment */
-static DEFINE_MUTEX(virtio_9p_lock);
+/* a single lock to manage channel initialization and attachment */
+static DEFINE_SPINLOCK(virtio_9p_lock);
/* global which tracks highest initialized channel */
static int chan_index;
@@ -211,9 +212,9 @@ static void p9_virtio_close(struct p9_trans *trans)
chan->max_tag = 0;
spin_unlock_irqrestore(&chan->lock, flags);
- mutex_lock(&virtio_9p_lock);
+ spin_lock(&virtio_9p_lock);
chan->inuse = false;
- mutex_unlock(&virtio_9p_lock);
+ spin_unlock(&virtio_9p_lock);
kfree(trans);
}
@@ -381,10 +382,10 @@ static int p9_virtio_probe(struct virtio_device *vdev)
struct virtio_chan *chan;
int index;
- mutex_lock(&virtio_9p_lock);
+ spin_lock(&virtio_9p_lock);
index = chan_index++;
chan = &channels[index];
- mutex_unlock(&virtio_9p_lock);
+ spin_unlock(&virtio_9p_lock);
if (chan_index > MAX_9P_CHAN) {
printk(KERN_ERR "9p: virtio: Maximum channels exceeded\n");
@@ -413,9 +414,9 @@ static int p9_virtio_probe(struct virtio_device *vdev)
out_free_vq:
vdev->config->del_vq(chan->vq);
fail:
- mutex_lock(&virtio_9p_lock);
+ spin_lock(&virtio_9p_lock);
chan_index--;
- mutex_unlock(&virtio_9p_lock);
+ spin_unlock(&virtio_9p_lock);
return err;
}
@@ -449,7 +450,7 @@ p9_virtio_create(const char *devname, char *args, int msize,
struct virtio_chan *chan = channels;
int index = 0;
- mutex_lock(&virtio_9p_lock);
+ spin_lock(&virtio_9p_lock);
while (index < MAX_9P_CHAN) {
if (chan->initialized && !chan->inuse) {
chan->inuse = true;
@@ -459,7 +460,7 @@ p9_virtio_create(const char *devname, char *args, int msize,
chan = &channels[index];
}
}
- mutex_unlock(&virtio_9p_lock);
+ spin_unlock(&virtio_9p_lock);
if (index >= MAX_9P_CHAN) {
printk(KERN_ERR "9p: no channels available\n");
diff --git a/net/ax25/ax25_subr.c b/net/ax25/ax25_subr.c
index d8f215733175..034aa10a5198 100644
--- a/net/ax25/ax25_subr.c
+++ b/net/ax25/ax25_subr.c
@@ -64,20 +64,15 @@ void ax25_frames_acked(ax25_cb *ax25, unsigned short nr)
void ax25_requeue_frames(ax25_cb *ax25)
{
- struct sk_buff *skb, *skb_prev = NULL;
+ struct sk_buff *skb;
/*
* Requeue all the un-ack-ed frames on the output queue to be picked
* up by ax25_kick called from the timer. This arrangement handles the
* possibility of an empty output queue.
*/
- while ((skb = skb_dequeue(&ax25->ack_queue)) != NULL) {
- if (skb_prev == NULL)
- skb_queue_head(&ax25->write_queue, skb);
- else
- skb_append(skb_prev, skb, &ax25->write_queue);
- skb_prev = skb;
- }
+ while ((skb = skb_dequeue_tail(&ax25->ack_queue)) != NULL)
+ skb_queue_head(&ax25->write_queue, skb);
}
/*
diff --git a/net/bluetooth/bnep/bnep.h b/net/bluetooth/bnep/bnep.h
index e69244dd8de8..b69bf4e7c48b 100644
--- a/net/bluetooth/bnep/bnep.h
+++ b/net/bluetooth/bnep/bnep.h
@@ -16,10 +16,6 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-/*
- * $Id: bnep.h,v 1.5 2002/08/04 21:23:58 maxk Exp $
- */
-
#ifndef _BNEP_H
#define _BNEP_H
diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
index f85d94643aaf..1d98a1b80da7 100644
--- a/net/bluetooth/bnep/core.c
+++ b/net/bluetooth/bnep/core.c
@@ -25,10 +25,6 @@
SOFTWARE IS DISCLAIMED.
*/
-/*
- * $Id: core.c,v 1.20 2002/08/04 21:23:58 maxk Exp $
- */
-
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/net/bluetooth/bnep/netdev.c b/net/bluetooth/bnep/netdev.c
index 95e3837e4312..d9fa0ab2c87f 100644
--- a/net/bluetooth/bnep/netdev.c
+++ b/net/bluetooth/bnep/netdev.c
@@ -25,10 +25,6 @@
SOFTWARE IS DISCLAIMED.
*/
-/*
- * $Id: netdev.c,v 1.8 2002/08/04 21:23:58 maxk Exp $
- */
-
#include <linux/module.h>
#include <linux/socket.h>
diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c
index 201e5b1ce473..8ffb57f2303a 100644
--- a/net/bluetooth/bnep/sock.c
+++ b/net/bluetooth/bnep/sock.c
@@ -24,10 +24,6 @@
SOFTWARE IS DISCLAIMED.
*/
-/*
- * $Id: sock.c,v 1.4 2002/08/04 21:23:58 maxk Exp $
- */
-
#include <linux/module.h>
#include <linux/types.h>
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index aec6929f5c16..7c07cef47e1f 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -875,7 +875,7 @@ int hci_register_dev(struct hci_dev *hdev)
hdev->reassembly[i] = NULL;
init_waitqueue_head(&hdev->req_wait_q);
- init_MUTEX(&hdev->req_lock);
+ mutex_init(&hdev->req_lock);
inquiry_cache_init(hdev);
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index 84360c117d4e..e13600106c6c 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -387,10 +387,6 @@ int hci_register_sysfs(struct hci_dev *hdev)
if (device_create_file(dev, bt_attrs[i]) < 0)
BT_ERR("Failed to create device attribute");
- if (sysfs_create_link(&bt_class->subsys.kobj,
- &dev->kobj, kobject_name(&dev->kobj)) < 0)
- BT_ERR("Failed to create class symlink");
-
return 0;
}
@@ -398,9 +394,6 @@ void hci_unregister_sysfs(struct hci_dev *hdev)
{
BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
- sysfs_remove_link(&bt_class->subsys.kobj,
- kobject_name(&hdev->dev.kobj));
-
device_del(&hdev->dev);
}
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index eb62558e9b09..b4fb84e398e5 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -23,8 +23,6 @@
/*
* Bluetooth RFCOMM core.
- *
- * $Id: core.c,v 1.42 2002/10/01 23:26:25 maxk Exp $
*/
#include <linux/module.h>
@@ -423,8 +421,8 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
rfcomm_dlc_lock(d);
d->state = BT_CLOSED;
- rfcomm_dlc_unlock(d);
d->state_change(d, err);
+ rfcomm_dlc_unlock(d);
skb_queue_purge(&d->tx_queue);
rfcomm_dlc_unlink(d);
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 5083adcbfae5..c9054487670a 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -23,8 +23,6 @@
/*
* RFCOMM sockets.
- *
- * $Id: sock.c,v 1.24 2002/10/03 01:00:34 maxk Exp $
*/
#include <linux/module.h>
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
index c3f749abb2d0..be84f4fc1477 100644
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -23,8 +23,6 @@
/*
* RFCOMM TTY.
- *
- * $Id: tty.c,v 1.24 2002/10/03 01:54:38 holtmann Exp $
*/
#include <linux/module.h>
@@ -566,11 +564,22 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
if (dlc->state == BT_CLOSED) {
if (!dev->tty) {
if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) {
- if (rfcomm_dev_get(dev->id) == NULL)
+ /* Drop DLC lock here to avoid deadlock
+ * 1. rfcomm_dev_get will take rfcomm_dev_lock
+ * but in rfcomm_dev_add there's lock order:
+ * rfcomm_dev_lock -> dlc lock
+ * 2. rfcomm_dev_put will deadlock if it's
+ * the last reference
+ */
+ rfcomm_dlc_unlock(dlc);
+ if (rfcomm_dev_get(dev->id) == NULL) {
+ rfcomm_dlc_lock(dlc);
return;
+ }
rfcomm_dev_del(dev);
rfcomm_dev_put(dev);
+ rfcomm_dlc_lock(dlc);
}
} else
tty_hangup(dev->tty);
diff --git a/net/bridge/br.c b/net/bridge/br.c
index 8f3c58e5f7a5..cede010f4ddd 100644
--- a/net/bridge/br.c
+++ b/net/bridge/br.c
@@ -5,8 +5,6 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br.c,v 1.47 2001/12/24 00:56:41 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index bf7787395fe0..a6ffc6c2a69f 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -5,8 +5,6 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_device.c,v 1.6 2001/12/24 00:59:55 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -21,12 +19,6 @@
#include <asm/uaccess.h>
#include "br_private.h"
-static struct net_device_stats *br_dev_get_stats(struct net_device *dev)
-{
- struct net_bridge *br = netdev_priv(dev);
- return &br->statistics;
-}
-
/* net device transmit always called with no BH (preempt_disabled) */
int br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
{
@@ -34,8 +26,8 @@ int br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
const unsigned char *dest = skb->data;
struct net_bridge_fdb_entry *dst;
- br->statistics.tx_packets++;
- br->statistics.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
skb_reset_mac_header(skb);
skb_pull(skb, ETH_HLEN);
@@ -161,7 +153,6 @@ void br_dev_setup(struct net_device *dev)
ether_setup(dev);
dev->do_ioctl = br_dev_ioctl;
- dev->get_stats = br_dev_get_stats;
dev->hard_start_xmit = br_dev_xmit;
dev->open = br_dev_open;
dev->set_multicast_list = br_dev_set_multicast_list;
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index 72c5976a5ce3..a48f5efdb6bf 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -5,8 +5,6 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_fdb.c,v 1.6 2002/01/17 00:57:07 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -15,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/rculist.h>
#include <linux/spinlock.h>
#include <linux/times.h>
#include <linux/netdevice.h>
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index bdd7c35c3c7b..512645727f51 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -5,8 +5,6 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_forward.c,v 1.4 2001/08/14 22:05:57 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -115,7 +113,7 @@ static void br_flood(struct net_bridge *br, struct sk_buff *skb,
struct sk_buff *skb2;
if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) {
- br->statistics.tx_dropped++;
+ br->dev->stats.tx_dropped++;
kfree_skb(skb);
return;
}
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index c2397f503b0f..143c954681b8 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -5,8 +5,6 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_if.c,v 1.7 2001/12/24 00:59:55 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 255c00f60ce7..0145e9416714 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -5,8 +5,6 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_input.c,v 1.10 2001/12/24 04:50:20 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -24,13 +22,13 @@ const u8 br_group_address[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb)
{
- struct net_device *indev;
+ struct net_device *indev, *brdev = br->dev;
- br->statistics.rx_packets++;
- br->statistics.rx_bytes += skb->len;
+ brdev->stats.rx_packets++;
+ brdev->stats.rx_bytes += skb->len;
indev = skb->dev;
- skb->dev = br->dev;
+ skb->dev = brdev;
NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL,
netif_receive_skb);
@@ -64,7 +62,7 @@ int br_handle_frame_finish(struct sk_buff *skb)
dst = NULL;
if (is_multicast_ether_addr(dest)) {
- br->statistics.multicast++;
+ br->dev->stats.multicast++;
skb2 = skb;
} else if ((dst = __br_fdb_get(br, dest)) && dst->is_local) {
skb2 = skb;
diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c
index 0655a5f07f58..eeee218eed80 100644
--- a/net/bridge/br_ioctl.c
+++ b/net/bridge/br_ioctl.c
@@ -5,8 +5,6 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_ioctl.c,v 1.4 2000/11/08 05:16:40 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c
index 00644a544e3c..88d8ec7b3142 100644
--- a/net/bridge/br_notify.c
+++ b/net/bridge/br_notify.c
@@ -5,8 +5,6 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_notify.c,v 1.2 2000/02/21 15:51:34 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index c11b554fd109..83ff5861c2d2 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -4,8 +4,6 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_private.h,v 1.7 2001/12/24 00:59:55 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -90,7 +88,6 @@ struct net_bridge
spinlock_t lock;
struct list_head port_list;
struct net_device *dev;
- struct net_device_stats statistics;
spinlock_t hash_lock;
struct hlist_head hash[BR_HASH_SIZE];
struct list_head age_list;
diff --git a/net/bridge/br_private_stp.h b/net/bridge/br_private_stp.h
index e29f01ac1adf..8b650f7fbfa0 100644
--- a/net/bridge/br_private_stp.h
+++ b/net/bridge/br_private_stp.h
@@ -4,8 +4,6 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_private_stp.h,v 1.3 2001/02/05 06:03:47 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c
index e38034aa56f5..921bbe5cb94a 100644
--- a/net/bridge/br_stp.c
+++ b/net/bridge/br_stp.c
@@ -5,14 +5,13 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_stp.c,v 1.4 2000/06/19 10:13:35 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/kernel.h>
+#include <linux/rculist.h>
#include "br_private.h"
#include "br_private_stp.h"
diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c
index ddeb6e5d45d6..9dc2de656965 100644
--- a/net/bridge/br_stp_bpdu.c
+++ b/net/bridge/br_stp_bpdu.c
@@ -5,8 +5,6 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_stp_bpdu.c,v 1.3 2001/11/10 02:35:25 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c
index 1a430eccec9b..1a4e5c37a0cf 100644
--- a/net/bridge/br_stp_if.c
+++ b/net/bridge/br_stp_if.c
@@ -5,8 +5,6 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_stp_if.c,v 1.4 2001/04/14 21:14:39 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
diff --git a/net/bridge/br_stp_timer.c b/net/bridge/br_stp_timer.c
index 77f5255e6915..772a140bfdf0 100644
--- a/net/bridge/br_stp_timer.c
+++ b/net/bridge/br_stp_timer.c
@@ -5,8 +5,6 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_stp_timer.c,v 1.3 2000/05/05 02:17:17 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
diff --git a/net/bridge/netfilter/Kconfig b/net/bridge/netfilter/Kconfig
index 7beeefa0f9c0..fb684c2ff8b6 100644
--- a/net/bridge/netfilter/Kconfig
+++ b/net/bridge/netfilter/Kconfig
@@ -83,6 +83,15 @@ config BRIDGE_EBT_IP
To compile it as a module, choose M here. If unsure, say N.
+config BRIDGE_EBT_IP6
+ tristate "ebt: IP6 filter support"
+ depends on BRIDGE_NF_EBTABLES
+ help
+ This option adds the IP6 match, which allows basic IPV6 header field
+ filtering.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
config BRIDGE_EBT_LIMIT
tristate "ebt: limit match support"
depends on BRIDGE_NF_EBTABLES
diff --git a/net/bridge/netfilter/Makefile b/net/bridge/netfilter/Makefile
index 83715d73a503..dd960645b413 100644
--- a/net/bridge/netfilter/Makefile
+++ b/net/bridge/netfilter/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_BRIDGE_EBT_802_3) += ebt_802_3.o
obj-$(CONFIG_BRIDGE_EBT_AMONG) += ebt_among.o
obj-$(CONFIG_BRIDGE_EBT_ARP) += ebt_arp.o
obj-$(CONFIG_BRIDGE_EBT_IP) += ebt_ip.o
+obj-$(CONFIG_BRIDGE_EBT_IP) += ebt_ip6.o
obj-$(CONFIG_BRIDGE_EBT_LIMIT) += ebt_limit.o
obj-$(CONFIG_BRIDGE_EBT_MARK) += ebt_mark_m.o
obj-$(CONFIG_BRIDGE_EBT_PKTTYPE) += ebt_pkttype.o
diff --git a/net/bridge/netfilter/ebt_ip6.c b/net/bridge/netfilter/ebt_ip6.c
new file mode 100644
index 000000000000..36efb3a75249
--- /dev/null
+++ b/net/bridge/netfilter/ebt_ip6.c
@@ -0,0 +1,144 @@
+/*
+ * ebt_ip6
+ *
+ * Authors:
+ * Manohar Castelino <manohar.r.castelino@intel.com>
+ * Kuo-Lang Tseng <kuo-lang.tseng@intel.com>
+ * Jan Engelhardt <jengelh@computergmbh.de>
+ *
+ * Summary:
+ * This is just a modification of the IPv4 code written by
+ * Bart De Schuymer <bdschuym@pandora.be>
+ * with the changes required to support IPv6
+ *
+ * Jan, 2008
+ */
+
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/netfilter_bridge/ebt_ip6.h>
+#include <linux/ipv6.h>
+#include <net/ipv6.h>
+#include <linux/in.h>
+#include <linux/module.h>
+#include <net/dsfield.h>
+
+struct tcpudphdr {
+ __be16 src;
+ __be16 dst;
+};
+
+static int ebt_filter_ip6(const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out, const void *data,
+ unsigned int datalen)
+{
+ const struct ebt_ip6_info *info = (struct ebt_ip6_info *)data;
+ const struct ipv6hdr *ih6;
+ struct ipv6hdr _ip6h;
+ const struct tcpudphdr *pptr;
+ struct tcpudphdr _ports;
+ struct in6_addr tmp_addr;
+ int i;
+
+ ih6 = skb_header_pointer(skb, 0, sizeof(_ip6h), &_ip6h);
+ if (ih6 == NULL)
+ return EBT_NOMATCH;
+ if (info->bitmask & EBT_IP6_TCLASS &&
+ FWINV(info->tclass != ipv6_get_dsfield(ih6), EBT_IP6_TCLASS))
+ return EBT_NOMATCH;
+ for (i = 0; i < 4; i++)
+ tmp_addr.in6_u.u6_addr32[i] = ih6->saddr.in6_u.u6_addr32[i] &
+ info->smsk.in6_u.u6_addr32[i];
+ if (info->bitmask & EBT_IP6_SOURCE &&
+ FWINV((ipv6_addr_cmp(&tmp_addr, &info->saddr) != 0),
+ EBT_IP6_SOURCE))
+ return EBT_NOMATCH;
+ for (i = 0; i < 4; i++)
+ tmp_addr.in6_u.u6_addr32[i] = ih6->daddr.in6_u.u6_addr32[i] &
+ info->dmsk.in6_u.u6_addr32[i];
+ if (info->bitmask & EBT_IP6_DEST &&
+ FWINV((ipv6_addr_cmp(&tmp_addr, &info->daddr) != 0), EBT_IP6_DEST))
+ return EBT_NOMATCH;
+ if (info->bitmask & EBT_IP6_PROTO) {
+ uint8_t nexthdr = ih6->nexthdr;
+ int offset_ph;
+
+ offset_ph = ipv6_skip_exthdr(skb, sizeof(_ip6h), &nexthdr);
+ if (offset_ph == -1)
+ return EBT_NOMATCH;
+ if (FWINV(info->protocol != nexthdr, EBT_IP6_PROTO))
+ return EBT_NOMATCH;
+ if (!(info->bitmask & EBT_IP6_DPORT) &&
+ !(info->bitmask & EBT_IP6_SPORT))
+ return EBT_MATCH;
+ pptr = skb_header_pointer(skb, offset_ph, sizeof(_ports),
+ &_ports);
+ if (pptr == NULL)
+ return EBT_NOMATCH;
+ if (info->bitmask & EBT_IP6_DPORT) {
+ u32 dst = ntohs(pptr->dst);
+ if (FWINV(dst < info->dport[0] ||
+ dst > info->dport[1], EBT_IP6_DPORT))
+ return EBT_NOMATCH;
+ }
+ if (info->bitmask & EBT_IP6_SPORT) {
+ u32 src = ntohs(pptr->src);
+ if (FWINV(src < info->sport[0] ||
+ src > info->sport[1], EBT_IP6_SPORT))
+ return EBT_NOMATCH;
+ }
+ return EBT_MATCH;
+ }
+ return EBT_MATCH;
+}
+
+static int ebt_ip6_check(const char *tablename, unsigned int hookmask,
+ const struct ebt_entry *e, void *data, unsigned int datalen)
+{
+ struct ebt_ip6_info *info = (struct ebt_ip6_info *)data;
+
+ if (datalen != EBT_ALIGN(sizeof(struct ebt_ip6_info)))
+ return -EINVAL;
+ if (e->ethproto != htons(ETH_P_IPV6) || e->invflags & EBT_IPROTO)
+ return -EINVAL;
+ if (info->bitmask & ~EBT_IP6_MASK || info->invflags & ~EBT_IP6_MASK)
+ return -EINVAL;
+ if (info->bitmask & (EBT_IP6_DPORT | EBT_IP6_SPORT)) {
+ if (info->invflags & EBT_IP6_PROTO)
+ return -EINVAL;
+ if (info->protocol != IPPROTO_TCP &&
+ info->protocol != IPPROTO_UDP &&
+ info->protocol != IPPROTO_UDPLITE &&
+ info->protocol != IPPROTO_SCTP &&
+ info->protocol != IPPROTO_DCCP)
+ return -EINVAL;
+ }
+ if (info->bitmask & EBT_IP6_DPORT && info->dport[0] > info->dport[1])
+ return -EINVAL;
+ if (info->bitmask & EBT_IP6_SPORT && info->sport[0] > info->sport[1])
+ return -EINVAL;
+ return 0;
+}
+
+static struct ebt_match filter_ip6 =
+{
+ .name = EBT_IP6_MATCH,
+ .match = ebt_filter_ip6,
+ .check = ebt_ip6_check,
+ .me = THIS_MODULE,
+};
+
+static int __init ebt_ip6_init(void)
+{
+ return ebt_register_match(&filter_ip6);
+}
+
+static void __exit ebt_ip6_fini(void)
+{
+ ebt_unregister_match(&filter_ip6);
+}
+
+module_init(ebt_ip6_init);
+module_exit(ebt_ip6_fini);
+MODULE_DESCRIPTION("Ebtables: IPv6 protocol packet match");
+MODULE_LICENSE("GPL");
diff --git a/net/bridge/netfilter/ebt_log.c b/net/bridge/netfilter/ebt_log.c
index 0b209e4aad0a..c883ec8a28b4 100644
--- a/net/bridge/netfilter/ebt_log.c
+++ b/net/bridge/netfilter/ebt_log.c
@@ -18,6 +18,9 @@
#include <linux/if_arp.h>
#include <linux/spinlock.h>
#include <net/netfilter/nf_log.h>
+#include <linux/ipv6.h>
+#include <net/ipv6.h>
+#include <linux/in6.h>
static DEFINE_SPINLOCK(ebt_log_lock);
@@ -58,6 +61,27 @@ static void print_MAC(const unsigned char *p)
printk("%02x%c", *p, i == ETH_ALEN - 1 ? ' ':':');
}
+static void
+print_ports(const struct sk_buff *skb, uint8_t protocol, int offset)
+{
+ if (protocol == IPPROTO_TCP ||
+ protocol == IPPROTO_UDP ||
+ protocol == IPPROTO_UDPLITE ||
+ protocol == IPPROTO_SCTP ||
+ protocol == IPPROTO_DCCP) {
+ const struct tcpudphdr *pptr;
+ struct tcpudphdr _ports;
+
+ pptr = skb_header_pointer(skb, offset,
+ sizeof(_ports), &_ports);
+ if (pptr == NULL) {
+ printk(" INCOMPLETE TCP/UDP header");
+ return;
+ }
+ printk(" SPT=%u DPT=%u", ntohs(pptr->src), ntohs(pptr->dst));
+ }
+}
+
#define myNIPQUAD(a) a[0], a[1], a[2], a[3]
static void
ebt_log_packet(unsigned int pf, unsigned int hooknum,
@@ -95,23 +119,31 @@ ebt_log_packet(unsigned int pf, unsigned int hooknum,
printk(" IP SRC=%u.%u.%u.%u IP DST=%u.%u.%u.%u, IP "
"tos=0x%02X, IP proto=%d", NIPQUAD(ih->saddr),
NIPQUAD(ih->daddr), ih->tos, ih->protocol);
- if (ih->protocol == IPPROTO_TCP ||
- ih->protocol == IPPROTO_UDP ||
- ih->protocol == IPPROTO_UDPLITE ||
- ih->protocol == IPPROTO_SCTP ||
- ih->protocol == IPPROTO_DCCP) {
- const struct tcpudphdr *pptr;
- struct tcpudphdr _ports;
-
- pptr = skb_header_pointer(skb, ih->ihl*4,
- sizeof(_ports), &_ports);
- if (pptr == NULL) {
- printk(" INCOMPLETE TCP/UDP header");
- goto out;
- }
- printk(" SPT=%u DPT=%u", ntohs(pptr->src),
- ntohs(pptr->dst));
+ print_ports(skb, ih->protocol, ih->ihl*4);
+ goto out;
+ }
+
+ if ((bitmask & EBT_LOG_IP6) && eth_hdr(skb)->h_proto ==
+ htons(ETH_P_IPV6)) {
+ const struct ipv6hdr *ih;
+ struct ipv6hdr _iph;
+ uint8_t nexthdr;
+ int offset_ph;
+
+ ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
+ if (ih == NULL) {
+ printk(" INCOMPLETE IPv6 header");
+ goto out;
}
+ printk(" IPv6 SRC=%x:%x:%x:%x:%x:%x:%x:%x "
+ "IPv6 DST=%x:%x:%x:%x:%x:%x:%x:%x, IPv6 "
+ "priority=0x%01X, Next Header=%d", NIP6(ih->saddr),
+ NIP6(ih->daddr), ih->priority, ih->nexthdr);
+ nexthdr = ih->nexthdr;
+ offset_ph = ipv6_skip_exthdr(skb, sizeof(_iph), &nexthdr);
+ if (offset_ph == -1)
+ goto out;
+ print_ports(skb, nexthdr, offset_ph);
goto out;
}
diff --git a/net/core/dev.c b/net/core/dev.c
index a1607bc0cd4c..305eaabb26f2 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -903,7 +903,11 @@ int dev_change_name(struct net_device *dev, char *newname)
strlcpy(dev->name, newname, IFNAMSIZ);
rollback:
- device_rename(&dev->dev, dev->name);
+ err = device_rename(&dev->dev, dev->name);
+ if (err) {
+ memcpy(dev->name, oldname, IFNAMSIZ);
+ return err;
+ }
write_lock_bh(&dev_base_lock);
hlist_del(&dev->name_hlist);
@@ -2235,7 +2239,7 @@ out:
*/
if (!cpus_empty(net_dma.channel_mask)) {
int chan_idx;
- for_each_cpu_mask(chan_idx, net_dma.channel_mask) {
+ for_each_cpu_mask_nr(chan_idx, net_dma.channel_mask) {
struct dma_chan *chan = net_dma.channels[chan_idx];
if (chan)
dma_async_memcpy_issue_pending(chan);
@@ -3137,7 +3141,7 @@ int dev_change_flags(struct net_device *dev, unsigned flags)
* Load in the correct multicast list now the flags have changed.
*/
- if (dev->change_rx_flags && (dev->flags ^ flags) & IFF_MULTICAST)
+ if (dev->change_rx_flags && (old_flags ^ flags) & IFF_MULTICAST)
dev->change_rx_flags(dev, IFF_MULTICAST);
dev_set_rx_mode(dev);
@@ -4296,7 +4300,7 @@ static void net_dma_rebalance(struct net_dma *net_dma)
i = 0;
cpu = first_cpu(cpu_online_map);
- for_each_cpu_mask(chan_idx, net_dma->channel_mask) {
+ for_each_cpu_mask_nr(chan_idx, net_dma->channel_mask) {
chan = net_dma->channels[chan_idx];
n = ((num_online_cpus() / cpus_weight(net_dma->channel_mask))
@@ -4559,8 +4563,8 @@ static int __init net_dev_init(void)
dev_boot_phase = 0;
- open_softirq(NET_TX_SOFTIRQ, net_tx_action, NULL);
- open_softirq(NET_RX_SOFTIRQ, net_rx_action, NULL);
+ open_softirq(NET_TX_SOFTIRQ, net_tx_action);
+ open_softirq(NET_RX_SOFTIRQ, net_rx_action);
hotcpu_notifier(dev_cpu_callback, 0);
dst_init();
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 5d9d7130bd6e..65f01f71b3f3 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -1714,7 +1714,8 @@ static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
return nla_nest_end(skb, nest);
nla_put_failure:
- return nla_nest_cancel(skb, nest);
+ nla_nest_cancel(skb, nest);
+ return -EMSGSIZE;
}
static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
@@ -2057,9 +2058,9 @@ static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
goto nla_put_failure;
}
- ci.ndm_used = now - neigh->used;
- ci.ndm_confirmed = now - neigh->confirmed;
- ci.ndm_updated = now - neigh->updated;
+ ci.ndm_used = jiffies_to_clock_t(now - neigh->used);
+ ci.ndm_confirmed = jiffies_to_clock_t(now - neigh->confirmed);
+ ci.ndm_updated = jiffies_to_clock_t(now - neigh->updated);
ci.ndm_refcnt = atomic_read(&neigh->refcnt) - 1;
read_unlock_bh(&neigh->lock);
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index 90e2177af081..dccd737ea2e3 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -242,11 +242,11 @@ static ssize_t netstat_show(const struct device *d,
offset % sizeof(unsigned long) != 0);
read_lock(&dev_base_lock);
- if (dev_isalive(dev) && dev->get_stats &&
- (stats = (*dev->get_stats)(dev)))
+ if (dev_isalive(dev)) {
+ stats = dev->get_stats(dev);
ret = sprintf(buf, fmt_ulong,
*(unsigned long *)(((u8 *) stats) + offset));
-
+ }
read_unlock(&dev_base_lock);
return ret;
}
@@ -457,8 +457,7 @@ int netdev_register_kobject(struct net_device *net)
strlcpy(dev->bus_id, net->name, BUS_ID_SIZE);
#ifdef CONFIG_SYSFS
- if (net->get_stats)
- *groups++ = &netstat_group;
+ *groups++ = &netstat_group;
#ifdef CONFIG_WIRELESS_EXT
if (net->wireless_handlers && net->wireless_handlers->get_wireless_stats)
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index 8dca21110493..fdf537707e51 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -390,6 +390,7 @@ struct pktgen_thread {
int cpu;
wait_queue_head_t queue;
+ struct completion start_done;
};
#define REMOVE 1
@@ -3414,6 +3415,7 @@ static int pktgen_thread_worker(void *arg)
BUG_ON(smp_processor_id() != cpu);
init_waitqueue_head(&t->queue);
+ complete(&t->start_done);
pr_debug("pktgen: starting pktgen/%d: pid=%d\n", cpu, task_pid_nr(current));
@@ -3615,6 +3617,7 @@ static int __init pktgen_create_thread(int cpu)
INIT_LIST_HEAD(&t->if_list);
list_add_tail(&t->th_list, &pktgen_threads);
+ init_completion(&t->start_done);
p = kthread_create(pktgen_thread_worker, t, "kpktgend_%d", cpu);
if (IS_ERR(p)) {
@@ -3639,6 +3642,7 @@ static int __init pktgen_create_thread(int cpu)
}
wake_up_process(p);
+ wait_for_completion(&t->start_done);
return 0;
}
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index cf857c4dc7b1..6c8d7f0ea01a 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -498,7 +498,8 @@ int rtnetlink_put_metrics(struct sk_buff *skb, u32 *metrics)
return nla_nest_end(skb, mx);
nla_put_failure:
- return nla_nest_cancel(skb, mx);
+ nla_nest_cancel(skb, mx);
+ return -EMSGSIZE;
}
int rtnl_put_cacheinfo(struct sk_buff *skb, struct dst_entry *dst, u32 id,
@@ -606,6 +607,8 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
{
struct ifinfomsg *ifm;
struct nlmsghdr *nlh;
+ struct net_device_stats *stats;
+ struct nlattr *attr;
nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags);
if (nlh == NULL)
@@ -652,19 +655,13 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
NLA_PUT(skb, IFLA_BROADCAST, dev->addr_len, dev->broadcast);
}
- if (dev->get_stats) {
- struct net_device_stats *stats = dev->get_stats(dev);
- if (stats) {
- struct nlattr *attr;
-
- attr = nla_reserve(skb, IFLA_STATS,
- sizeof(struct rtnl_link_stats));
- if (attr == NULL)
- goto nla_put_failure;
+ attr = nla_reserve(skb, IFLA_STATS,
+ sizeof(struct rtnl_link_stats));
+ if (attr == NULL)
+ goto nla_put_failure;
- copy_rtnl_link_stats(nla_data(attr), stats);
- }
- }
+ stats = dev->get_stats(dev);
+ copy_rtnl_link_stats(nla_data(attr), stats);
if (dev->rtnl_link_ops) {
if (rtnl_link_fill(skb, dev) < 0)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 5c459f2b7985..3e18f8525e82 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -4,8 +4,6 @@
* Authors: Alan Cox <iiitac@pyr.swan.ac.uk>
* Florian La Roche <rzsfl@rz.uni-sb.de>
*
- * Version: $Id: skbuff.c,v 1.90 2001/11/07 05:56:19 davem Exp $
- *
* Fixes:
* Alan Cox : Fixed the worst of the load
* balancer bugs.
@@ -1445,6 +1443,7 @@ done:
if (spd.nr_pages) {
int ret;
+ struct sock *sk = __skb->sk;
/*
* Drop the socket lock, otherwise we have reverse
@@ -1455,9 +1454,9 @@ done:
* we call into ->sendpage() with the i_mutex lock held
* and networking will grab the socket lock.
*/
- release_sock(__skb->sk);
+ release_sock(sk);
ret = splice_to_pipe(pipe, &spd);
- lock_sock(__skb->sk);
+ lock_sock(sk);
return ret;
}
diff --git a/net/core/sock.c b/net/core/sock.c
index 88094cb09c06..3879bf65897e 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -7,8 +7,6 @@
* handler for protocols to use and generic option handler.
*
*
- * Version: $Id: sock.c,v 1.117 2002/02/01 22:01:03 davem Exp $
- *
* Authors: Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Florian La Roche, <flla@stud.uni-sb.de>
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index 5fc801057244..a570e2af22cb 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -125,14 +125,6 @@ static struct ctl_table net_core_table[] = {
#endif /* CONFIG_XFRM */
#endif /* CONFIG_NET */
{
- .ctl_name = NET_CORE_SOMAXCONN,
- .procname = "somaxconn",
- .data = &init_net.core.sysctl_somaxconn,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec
- },
- {
.ctl_name = NET_CORE_BUDGET,
.procname = "netdev_budget",
.data = &netdev_budget,
@@ -151,6 +143,18 @@ static struct ctl_table net_core_table[] = {
{ .ctl_name = 0 }
};
+static struct ctl_table netns_core_table[] = {
+ {
+ .ctl_name = NET_CORE_SOMAXCONN,
+ .procname = "somaxconn",
+ .data = &init_net.core.sysctl_somaxconn,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec
+ },
+ { .ctl_name = 0 }
+};
+
static __net_initdata struct ctl_path net_core_path[] = {
{ .procname = "net", .ctl_name = CTL_NET, },
{ .procname = "core", .ctl_name = NET_CORE, },
@@ -159,23 +163,17 @@ static __net_initdata struct ctl_path net_core_path[] = {
static __net_init int sysctl_core_net_init(struct net *net)
{
- struct ctl_table *tbl, *tmp;
+ struct ctl_table *tbl;
net->core.sysctl_somaxconn = SOMAXCONN;
- tbl = net_core_table;
+ tbl = netns_core_table;
if (net != &init_net) {
- tbl = kmemdup(tbl, sizeof(net_core_table), GFP_KERNEL);
+ tbl = kmemdup(tbl, sizeof(netns_core_table), GFP_KERNEL);
if (tbl == NULL)
goto err_dup;
- for (tmp = tbl; tmp->procname; tmp++) {
- if (tmp->data >= (void *)&init_net &&
- tmp->data < (void *)(&init_net + 1))
- tmp->data += (char *)net - (char *)&init_net;
- else
- tmp->mode &= ~0222;
- }
+ tbl[0].data = &net->core.sysctl_somaxconn;
}
net->core.sysctl_hdr = register_net_sysctl_table(net,
@@ -186,7 +184,7 @@ static __net_init int sysctl_core_net_init(struct net *net)
return 0;
err_reg:
- if (tbl != net_core_table)
+ if (tbl != netns_core_table)
kfree(tbl);
err_dup:
return -ENOMEM;
@@ -198,7 +196,7 @@ static __net_exit void sysctl_core_net_exit(struct net *net)
tbl = net->core.sysctl_hdr->ctl_table_arg;
unregister_net_sysctl_table(net->core.sysctl_hdr);
- BUG_ON(tbl == net_core_table);
+ BUG_ON(tbl == netns_core_table);
kfree(tbl);
}
@@ -209,6 +207,7 @@ static __net_initdata struct pernet_operations sysctl_core_ops = {
static __init int sysctl_core_init(void)
{
+ register_net_sysctl_rotable(net_core_path, net_core_table);
return register_pernet_subsys(&sysctl_core_ops);
}
diff --git a/net/core/user_dma.c b/net/core/user_dma.c
index 0ad1cd57bc39..c77aff9c6eb3 100644
--- a/net/core/user_dma.c
+++ b/net/core/user_dma.c
@@ -75,7 +75,7 @@ int dma_skb_copy_datagram_iovec(struct dma_chan *chan,
end = start + skb_shinfo(skb)->frags[i].size;
copy = end - offset;
- if ((copy = end - offset) > 0) {
+ if (copy > 0) {
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
struct page *page = frag->page;
diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c
index 6de4bd195d28..1e8be246ad15 100644
--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -290,12 +290,12 @@ int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk,
while (1) {
const u8 len = dccp_ackvec_len(av, index);
- const u8 state = dccp_ackvec_state(av, index);
+ const u8 av_state = dccp_ackvec_state(av, index);
/*
* valid packets not yet in av_buf have a reserved
* entry, with a len equal to 0.
*/
- if (state == DCCP_ACKVEC_STATE_NOT_RECEIVED &&
+ if (av_state == DCCP_ACKVEC_STATE_NOT_RECEIVED &&
len == 0 && delta == 0) { /* Found our
reserved seat! */
dccp_pr_debug("Found %llu reserved seat!\n",
@@ -325,31 +325,6 @@ out_duplicate:
return -EILSEQ;
}
-#ifdef CONFIG_IP_DCCP_DEBUG
-void dccp_ackvector_print(const u64 ackno, const unsigned char *vector, int len)
-{
- dccp_pr_debug_cat("ACK vector len=%d, ackno=%llu |", len,
- (unsigned long long)ackno);
-
- while (len--) {
- const u8 state = (*vector & DCCP_ACKVEC_STATE_MASK) >> 6;
- const u8 rl = *vector & DCCP_ACKVEC_LEN_MASK;
-
- dccp_pr_debug_cat("%d,%d|", state, rl);
- ++vector;
- }
-
- dccp_pr_debug_cat("\n");
-}
-
-void dccp_ackvec_print(const struct dccp_ackvec *av)
-{
- dccp_ackvector_print(av->av_buf_ackno,
- av->av_buf + av->av_buf_head,
- av->av_vec_len);
-}
-#endif
-
static void dccp_ackvec_throw_record(struct dccp_ackvec *av,
struct dccp_ackvec_record *avr)
{
diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c
index cd61dea2eea1..a1929f33d703 100644
--- a/net/dccp/ccids/ccid3.c
+++ b/net/dccp/ccids/ccid3.c
@@ -159,8 +159,8 @@ static void ccid3_hc_tx_update_x(struct sock *sk, ktime_t *stamp)
} else if (ktime_us_delta(now, hctx->ccid3hctx_t_ld)
- (s64)hctx->ccid3hctx_rtt >= 0) {
- hctx->ccid3hctx_x =
- max(min(2 * hctx->ccid3hctx_x, min_rate),
+ hctx->ccid3hctx_x = min(2 * hctx->ccid3hctx_x, min_rate);
+ hctx->ccid3hctx_x = max(hctx->ccid3hctx_x,
scaled_div(((__u64)hctx->ccid3hctx_s) << 6,
hctx->ccid3hctx_rtt));
hctx->ccid3hctx_t_ld = now;
@@ -193,22 +193,17 @@ static inline void ccid3_hc_tx_update_s(struct ccid3_hc_tx_sock *hctx, int len)
/*
* Update Window Counter using the algorithm from [RFC 4342, 8.1].
- * The algorithm is not applicable if RTT < 4 microseconds.
+ * As elsewhere, RTT > 0 is assumed by using dccp_sample_rtt().
*/
static inline void ccid3_hc_tx_update_win_count(struct ccid3_hc_tx_sock *hctx,
ktime_t now)
{
- u32 quarter_rtts;
-
- if (unlikely(hctx->ccid3hctx_rtt < 4)) /* avoid divide-by-zero */
- return;
-
- quarter_rtts = ktime_us_delta(now, hctx->ccid3hctx_t_last_win_count);
- quarter_rtts /= hctx->ccid3hctx_rtt / 4;
+ u32 delta = ktime_us_delta(now, hctx->ccid3hctx_t_last_win_count),
+ quarter_rtts = (4 * delta) / hctx->ccid3hctx_rtt;
if (quarter_rtts > 0) {
hctx->ccid3hctx_t_last_win_count = now;
- hctx->ccid3hctx_last_win_count += min_t(u32, quarter_rtts, 5);
+ hctx->ccid3hctx_last_win_count += min(quarter_rtts, 5U);
hctx->ccid3hctx_last_win_count &= 0xF; /* mod 16 */
}
}
@@ -334,8 +329,14 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
hctx->ccid3hctx_x = rfc3390_initial_rate(sk);
hctx->ccid3hctx_t_ld = now;
} else {
- /* Sender does not have RTT sample: X_pps = 1 pkt/sec */
- hctx->ccid3hctx_x = hctx->ccid3hctx_s;
+ /*
+ * Sender does not have RTT sample:
+ * - set fallback RTT (RFC 4340, 3.4) since a RTT value
+ * is needed in several parts (e.g. window counter);
+ * - set sending rate X_pps = 1pps as per RFC 3448, 4.2.
+ */
+ hctx->ccid3hctx_rtt = DCCP_FALLBACK_RTT;
+ hctx->ccid3hctx_x = hctx->ccid3hctx_s;
hctx->ccid3hctx_x <<= 6;
}
ccid3_update_send_interval(hctx);
diff --git a/net/dccp/ccids/lib/tfrc.c b/net/dccp/ccids/lib/tfrc.c
index d1dfbb8de64c..97ecec0a8e76 100644
--- a/net/dccp/ccids/lib/tfrc.c
+++ b/net/dccp/ccids/lib/tfrc.c
@@ -14,14 +14,6 @@ module_param(tfrc_debug, bool, 0444);
MODULE_PARM_DESC(tfrc_debug, "Enable debug messages");
#endif
-extern int tfrc_tx_packet_history_init(void);
-extern void tfrc_tx_packet_history_exit(void);
-extern int tfrc_rx_packet_history_init(void);
-extern void tfrc_rx_packet_history_exit(void);
-
-extern int tfrc_li_init(void);
-extern void tfrc_li_exit(void);
-
static int __init tfrc_module_init(void)
{
int rc = tfrc_li_init();
diff --git a/net/dccp/ccids/lib/tfrc.h b/net/dccp/ccids/lib/tfrc.h
index 1fb1187bbf1c..ed9857527acf 100644
--- a/net/dccp/ccids/lib/tfrc.h
+++ b/net/dccp/ccids/lib/tfrc.h
@@ -15,7 +15,7 @@
* (at your option) any later version.
*/
#include <linux/types.h>
-#include <asm/div64.h>
+#include <linux/math64.h>
#include "../../dccp.h"
/* internal includes that this module exports: */
#include "loss_interval.h"
@@ -29,21 +29,19 @@ extern int tfrc_debug;
#endif
/* integer-arithmetic divisions of type (a * 1000000)/b */
-static inline u64 scaled_div(u64 a, u32 b)
+static inline u64 scaled_div(u64 a, u64 b)
{
BUG_ON(b==0);
- a *= 1000000;
- do_div(a, b);
- return a;
+ return div64_u64(a * 1000000, b);
}
-static inline u32 scaled_div32(u64 a, u32 b)
+static inline u32 scaled_div32(u64 a, u64 b)
{
u64 result = scaled_div(a, b);
if (result > UINT_MAX) {
- DCCP_CRIT("Overflow: a(%llu)/b(%u) > ~0U",
- (unsigned long long)a, b);
+ DCCP_CRIT("Overflow: %llu/%llu > UINT_MAX",
+ (unsigned long long)a, (unsigned long long)b);
return UINT_MAX;
}
return result;
@@ -58,7 +56,14 @@ static inline u32 tfrc_ewma(const u32 avg, const u32 newval, const u8 weight)
return avg ? (weight * avg + (10 - weight) * newval) / 10 : newval;
}
-extern u32 tfrc_calc_x(u16 s, u32 R, u32 p);
-extern u32 tfrc_calc_x_reverse_lookup(u32 fvalue);
+extern u32 tfrc_calc_x(u16 s, u32 R, u32 p);
+extern u32 tfrc_calc_x_reverse_lookup(u32 fvalue);
+extern int tfrc_tx_packet_history_init(void);
+extern void tfrc_tx_packet_history_exit(void);
+extern int tfrc_rx_packet_history_init(void);
+extern void tfrc_rx_packet_history_exit(void);
+
+extern int tfrc_li_init(void);
+extern void tfrc_li_exit(void);
#endif /* _TFRC_H_ */
diff --git a/net/dccp/ccids/lib/tfrc_equation.c b/net/dccp/ccids/lib/tfrc_equation.c
index e4e64b76c10c..2f20a29cffe4 100644
--- a/net/dccp/ccids/lib/tfrc_equation.c
+++ b/net/dccp/ccids/lib/tfrc_equation.c
@@ -661,7 +661,7 @@ u32 tfrc_calc_x(u16 s, u32 R, u32 p)
EXPORT_SYMBOL_GPL(tfrc_calc_x);
-/*
+/**
* tfrc_calc_x_reverse_lookup - try to find p given f(p)
*
* @fvalue: function value to match, scaled by 1000000
@@ -676,11 +676,11 @@ u32 tfrc_calc_x_reverse_lookup(u32 fvalue)
/* Error cases. */
if (fvalue < tfrc_calc_x_lookup[0][1]) {
- DCCP_WARN("fvalue %d smaller than resolution\n", fvalue);
- return tfrc_calc_x_lookup[0][1];
+ DCCP_WARN("fvalue %u smaller than resolution\n", fvalue);
+ return TFRC_SMALLEST_P;
}
if (fvalue > tfrc_calc_x_lookup[TFRC_CALC_X_ARRSIZE - 1][0]) {
- DCCP_WARN("fvalue %d exceeds bounds!\n", fvalue);
+ DCCP_WARN("fvalue %u exceeds bounds!\n", fvalue);
return 1000000;
}
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index b348dd70c685..37d27bcb361f 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -589,7 +589,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
goto drop;
- req = reqsk_alloc(&dccp_request_sock_ops);
+ req = inet_reqsk_alloc(&dccp_request_sock_ops);
if (req == NULL)
goto drop;
@@ -605,7 +605,6 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
ireq = inet_rsk(req);
ireq->loc_addr = ip_hdr(skb)->daddr;
ireq->rmt_addr = ip_hdr(skb)->saddr;
- ireq->opt = NULL;
/*
* Step 3: Process LISTEN state
@@ -739,8 +738,8 @@ int dccp_invalid_packet(struct sk_buff *skb)
* If P.type is not Data, Ack, or DataAck and P.X == 0 (the packet
* has short sequence numbers), drop packet and return
*/
- if (dh->dccph_type >= DCCP_PKT_DATA &&
- dh->dccph_type <= DCCP_PKT_DATAACK && dh->dccph_x == 0) {
+ if ((dh->dccph_type < DCCP_PKT_DATA ||
+ dh->dccph_type > DCCP_PKT_DATAACK) && dh->dccph_x == 0) {
DCCP_WARN("P.type (%s) not Data || [Data]Ack, while P.X == 0\n",
dccp_packet_name(dh->dccph_type));
return 1;
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 9b1129bb7ece..f7fe2a572d7b 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -421,7 +421,6 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
ireq6 = inet6_rsk(req);
ipv6_addr_copy(&ireq6->rmt_addr, &ipv6_hdr(skb)->saddr);
ipv6_addr_copy(&ireq6->loc_addr, &ipv6_hdr(skb)->daddr);
- ireq6->pktopts = NULL;
if (ipv6_opt_accepted(sk, skb) ||
np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c
index 33ad48321b08..66dca5bba858 100644
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -165,12 +165,12 @@ out_free:
/* See dccp_v4_conn_request */
newdmsk->dccpms_sequence_window = req->rcv_wnd;
- newdp->dccps_gar = newdp->dccps_isr = dreq->dreq_isr;
- dccp_update_gsr(newsk, dreq->dreq_isr);
-
- newdp->dccps_iss = dreq->dreq_iss;
+ newdp->dccps_gar = newdp->dccps_iss = dreq->dreq_iss;
dccp_update_gss(newsk, dreq->dreq_iss);
+ newdp->dccps_isr = dreq->dreq_isr;
+ dccp_update_gsr(newsk, dreq->dreq_isr);
+
/*
* SWL and AWL are initially adjusted so that they are not less than
* the initial Sequence Numbers received and sent, respectively:
diff --git a/net/dccp/options.c b/net/dccp/options.c
index d2a84a2fecee..43bc24e761d0 100644
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -107,9 +107,11 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
*
* CCID-specific options are ignored during connection setup, as
* negotiation may still be in progress (see RFC 4340, 10.3).
+ * The same applies to Ack Vectors, as these depend on the CCID.
*
*/
- if (dreq != NULL && opt >= 128)
+ if (dreq != NULL && (opt >= 128 ||
+ opt == DCCPO_ACK_VECTOR_0 || opt == DCCPO_ACK_VECTOR_1))
goto ignore_option;
switch (opt) {
diff --git a/net/dccp/output.c b/net/dccp/output.c
index 1f8a9b64c083..fe20068c5d8e 100644
--- a/net/dccp/output.c
+++ b/net/dccp/output.c
@@ -508,6 +508,7 @@ void dccp_send_ack(struct sock *sk)
EXPORT_SYMBOL_GPL(dccp_send_ack);
+#if 0
/* FIXME: Is this still necessary (11.3) - currently nowhere used by DCCP. */
void dccp_send_delayed_ack(struct sock *sk)
{
@@ -538,6 +539,7 @@ void dccp_send_delayed_ack(struct sock *sk)
icsk->icsk_ack.timeout = timeout;
sk_reset_timer(sk, &icsk->icsk_delack_timer, timeout);
}
+#endif
void dccp_send_sync(struct sock *sk, const u64 ackno,
const enum dccp_pkt_type pkt_type)
diff --git a/net/dccp/probe.c b/net/dccp/probe.c
index 0bcdc9250279..81368a7f5379 100644
--- a/net/dccp/probe.c
+++ b/net/dccp/probe.c
@@ -42,7 +42,7 @@ static int bufsize = 64 * 1024;
static const char procname[] = "dccpprobe";
-struct {
+static struct {
struct kfifo *fifo;
spinlock_t lock;
wait_queue_head_t wait;
diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c
index 200ee1e63728..69dbc342a464 100644
--- a/net/ieee80211/ieee80211_rx.c
+++ b/net/ieee80211/ieee80211_rx.c
@@ -391,7 +391,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
wstats.updated = 0;
if (rx_stats->mask & IEEE80211_STATMASK_RSSI) {
- wstats.level = rx_stats->rssi;
+ wstats.level = rx_stats->signal;
wstats.updated |= IW_QUAL_LEVEL_UPDATED;
} else
wstats.updated |= IW_QUAL_LEVEL_INVALID;
diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c
index d8b02603cbe5..d996547f7a62 100644
--- a/net/ieee80211/ieee80211_tx.c
+++ b/net/ieee80211/ieee80211_tx.c
@@ -542,90 +542,4 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
return 1;
}
-/* Incoming 802.11 strucure is converted to a TXB
- * a block of 802.11 fragment packets (stored as skbs) */
-int ieee80211_tx_frame(struct ieee80211_device *ieee,
- struct ieee80211_hdr *frame, int hdr_len, int total_len,
- int encrypt_mpdu)
-{
- struct ieee80211_txb *txb = NULL;
- unsigned long flags;
- struct net_device_stats *stats = &ieee->stats;
- struct sk_buff *skb_frag;
- int priority = -1;
- int fraglen = total_len;
- int headroom = ieee->tx_headroom;
- struct ieee80211_crypt_data *crypt = ieee->crypt[ieee->tx_keyidx];
-
- spin_lock_irqsave(&ieee->lock, flags);
-
- if (encrypt_mpdu && (!ieee->sec.encrypt || !crypt))
- encrypt_mpdu = 0;
-
- /* If there is no driver handler to take the TXB, dont' bother
- * creating it... */
- if (!ieee->hard_start_xmit) {
- printk(KERN_WARNING "%s: No xmit handler.\n", ieee->dev->name);
- goto success;
- }
-
- if (unlikely(total_len < 24)) {
- printk(KERN_WARNING "%s: skb too small (%d).\n",
- ieee->dev->name, total_len);
- goto success;
- }
-
- if (encrypt_mpdu) {
- frame->frame_ctl |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
- fraglen += crypt->ops->extra_mpdu_prefix_len +
- crypt->ops->extra_mpdu_postfix_len;
- headroom += crypt->ops->extra_mpdu_prefix_len;
- }
-
- /* When we allocate the TXB we allocate enough space for the reserve
- * and full fragment bytes (bytes_per_frag doesn't include prefix,
- * postfix, header, FCS, etc.) */
- txb = ieee80211_alloc_txb(1, fraglen, headroom, GFP_ATOMIC);
- if (unlikely(!txb)) {
- printk(KERN_WARNING "%s: Could not allocate TXB\n",
- ieee->dev->name);
- goto failed;
- }
- txb->encrypted = 0;
- txb->payload_size = fraglen;
-
- skb_frag = txb->fragments[0];
-
- memcpy(skb_put(skb_frag, total_len), frame, total_len);
-
- if (ieee->config &
- (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
- skb_put(skb_frag, 4);
-
- /* To avoid overcomplicating things, we do the corner-case frame
- * encryption in software. The only real situation where encryption is
- * needed here is during software-based shared key authentication. */
- if (encrypt_mpdu)
- ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len);
-
- success:
- spin_unlock_irqrestore(&ieee->lock, flags);
-
- if (txb) {
- if ((*ieee->hard_start_xmit) (txb, ieee->dev, priority) == 0) {
- stats->tx_packets++;
- stats->tx_bytes += txb->payload_size;
- return 0;
- }
- ieee80211_txb_free(txb);
- }
- return 0;
-
- failed:
- spin_unlock_irqrestore(&ieee->lock, flags);
- stats->tx_errors++;
- return 1;
-}
-
-EXPORT_SYMBOL(ieee80211_tx_frame);
EXPORT_SYMBOL(ieee80211_txb_free);
diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c
index 623489afa62c..822606b615ca 100644
--- a/net/ieee80211/ieee80211_wx.c
+++ b/net/ieee80211/ieee80211_wx.c
@@ -744,98 +744,9 @@ int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee,
return 0;
}
-int ieee80211_wx_set_auth(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct ieee80211_device *ieee = netdev_priv(dev);
- unsigned long flags;
- int err = 0;
-
- spin_lock_irqsave(&ieee->lock, flags);
-
- switch (wrqu->param.flags & IW_AUTH_INDEX) {
- case IW_AUTH_WPA_VERSION:
- case IW_AUTH_CIPHER_PAIRWISE:
- case IW_AUTH_CIPHER_GROUP:
- case IW_AUTH_KEY_MGMT:
- /*
- * Host AP driver does not use these parameters and allows
- * wpa_supplicant to control them internally.
- */
- break;
- case IW_AUTH_TKIP_COUNTERMEASURES:
- break; /* FIXME */
- case IW_AUTH_DROP_UNENCRYPTED:
- ieee->drop_unencrypted = !!wrqu->param.value;
- break;
- case IW_AUTH_80211_AUTH_ALG:
- break; /* FIXME */
- case IW_AUTH_WPA_ENABLED:
- ieee->privacy_invoked = ieee->wpa_enabled = !!wrqu->param.value;
- break;
- case IW_AUTH_RX_UNENCRYPTED_EAPOL:
- ieee->ieee802_1x = !!wrqu->param.value;
- break;
- case IW_AUTH_PRIVACY_INVOKED:
- ieee->privacy_invoked = !!wrqu->param.value;
- break;
- default:
- err = -EOPNOTSUPP;
- break;
- }
- spin_unlock_irqrestore(&ieee->lock, flags);
- return err;
-}
-
-int ieee80211_wx_get_auth(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct ieee80211_device *ieee = netdev_priv(dev);
- unsigned long flags;
- int err = 0;
-
- spin_lock_irqsave(&ieee->lock, flags);
-
- switch (wrqu->param.flags & IW_AUTH_INDEX) {
- case IW_AUTH_WPA_VERSION:
- case IW_AUTH_CIPHER_PAIRWISE:
- case IW_AUTH_CIPHER_GROUP:
- case IW_AUTH_KEY_MGMT:
- case IW_AUTH_TKIP_COUNTERMEASURES: /* FIXME */
- case IW_AUTH_80211_AUTH_ALG: /* FIXME */
- /*
- * Host AP driver does not use these parameters and allows
- * wpa_supplicant to control them internally.
- */
- err = -EOPNOTSUPP;
- break;
- case IW_AUTH_DROP_UNENCRYPTED:
- wrqu->param.value = ieee->drop_unencrypted;
- break;
- case IW_AUTH_WPA_ENABLED:
- wrqu->param.value = ieee->wpa_enabled;
- break;
- case IW_AUTH_RX_UNENCRYPTED_EAPOL:
- wrqu->param.value = ieee->ieee802_1x;
- break;
- default:
- err = -EOPNOTSUPP;
- break;
- }
- spin_unlock_irqrestore(&ieee->lock, flags);
- return err;
-}
-
EXPORT_SYMBOL(ieee80211_wx_set_encodeext);
EXPORT_SYMBOL(ieee80211_wx_get_encodeext);
EXPORT_SYMBOL(ieee80211_wx_get_scan);
EXPORT_SYMBOL(ieee80211_wx_set_encode);
EXPORT_SYMBOL(ieee80211_wx_get_encode);
-
-EXPORT_SYMBOL_GPL(ieee80211_wx_set_auth);
-EXPORT_SYMBOL_GPL(ieee80211_wx_get_auth);
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 24eca23c2db3..42bd24b64b57 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -5,8 +5,6 @@
*
* PF_INET protocol family socket handler.
*
- * Version: $Id: af_inet.c,v 1.137 2002/02/01 22:01:03 davem Exp $
- *
* Authors: Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Florian La Roche, <flla@stud.uni-sb.de>
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index 418862f1bf22..20c515a1be28 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -1,7 +1,5 @@
/* linux/net/ipv4/arp.c
*
- * Version: $Id: arp.c,v 1.99 2001/08/30 22:55:42 davem Exp $
- *
* Copyright (C) 1994 by Florian La Roche
*
* This module implements the Address Resolution Protocol ARP (RFC 826),
@@ -1288,7 +1286,6 @@ static void arp_format_neigh_entry(struct seq_file *seq,
struct neighbour *n)
{
char hbuffer[HBUFFERLEN];
- const char hexbuf[] = "0123456789ABCDEF";
int k, j;
char tbuf[16];
struct net_device *dev = n->dev;
@@ -1302,8 +1299,8 @@ static void arp_format_neigh_entry(struct seq_file *seq,
else {
#endif
for (k = 0, j = 0; k < HBUFFERLEN - 3 && j < dev->addr_len; j++) {
- hbuffer[k++] = hexbuf[(n->ha[j] >> 4) & 15];
- hbuffer[k++] = hexbuf[n->ha[j] & 15];
+ hbuffer[k++] = hex_asc_hi(n->ha[j]);
+ hbuffer[k++] = hex_asc_lo(n->ha[j]);
hbuffer[k++] = ':';
}
hbuffer[--k] = 0;
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 6848e4760f34..f8c0b0aea93a 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -1,8 +1,6 @@
/*
* NET3 IP device support routines.
*
- * Version: $Id: devinet.c,v 1.44 2001/10/31 21:55:54 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -90,7 +88,6 @@ static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = {
[IFA_LOCAL] = { .type = NLA_U32 },
[IFA_ADDRESS] = { .type = NLA_U32 },
[IFA_BROADCAST] = { .type = NLA_U32 },
- [IFA_ANYCAST] = { .type = NLA_U32 },
[IFA_LABEL] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 },
};
@@ -536,9 +533,6 @@ static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh)
if (tb[IFA_BROADCAST])
ifa->ifa_broadcast = nla_get_be32(tb[IFA_BROADCAST]);
- if (tb[IFA_ANYCAST])
- ifa->ifa_anycast = nla_get_be32(tb[IFA_ANYCAST]);
-
if (tb[IFA_LABEL])
nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
else
@@ -745,7 +739,6 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
break;
inet_del_ifa(in_dev, ifap, 0);
ifa->ifa_broadcast = 0;
- ifa->ifa_anycast = 0;
ifa->ifa_scope = 0;
}
@@ -1018,7 +1011,7 @@ static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
memcpy(old, ifa->ifa_label, IFNAMSIZ);
memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
if (named++ == 0)
- continue;
+ goto skip;
dot = strchr(old, ':');
if (dot == NULL) {
sprintf(old, ":%d", named);
@@ -1029,6 +1022,8 @@ static void inetdev_changename(struct net_device *dev, struct in_device *in_dev)
} else {
strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot);
}
+skip:
+ rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
}
}
@@ -1113,7 +1108,6 @@ static inline size_t inet_nlmsg_size(void)
+ nla_total_size(4) /* IFA_ADDRESS */
+ nla_total_size(4) /* IFA_LOCAL */
+ nla_total_size(4) /* IFA_BROADCAST */
- + nla_total_size(4) /* IFA_ANYCAST */
+ nla_total_size(IFNAMSIZ); /* IFA_LABEL */
}
@@ -1143,9 +1137,6 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
if (ifa->ifa_broadcast)
NLA_PUT_BE32(skb, IFA_BROADCAST, ifa->ifa_broadcast);
- if (ifa->ifa_anycast)
- NLA_PUT_BE32(skb, IFA_ANYCAST, ifa->ifa_anycast);
-
if (ifa->ifa_label[0])
NLA_PUT_STRING(skb, IFA_LABEL, ifa->ifa_label);
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 0f1557a4ac7a..5ad01d63f83b 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -5,8 +5,6 @@
*
* IPv4 Forwarding Information Base: FIB frontend.
*
- * Version: $Id: fib_frontend.c,v 1.26 2001/10/31 21:55:54 davem Exp $
- *
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
*
* This program is free software; you can redistribute it and/or
@@ -506,7 +504,6 @@ const struct nla_policy rtm_ipv4_policy[RTA_MAX+1] = {
[RTA_PREFSRC] = { .type = NLA_U32 },
[RTA_METRICS] = { .type = NLA_NESTED },
[RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) },
- [RTA_PROTOINFO] = { .type = NLA_U32 },
[RTA_FLOW] = { .type = NLA_U32 },
};
diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c
index 2e2fc3376ac9..eeec4bf982b8 100644
--- a/net/ipv4/fib_hash.c
+++ b/net/ipv4/fib_hash.c
@@ -5,8 +5,6 @@
*
* IPv4 FIB: lookup engine and maintenance routines.
*
- * Version: $Id: fib_hash.c,v 1.13 2001/10/31 21:55:54 davem Exp $
- *
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
*
* This program is free software; you can redistribute it and/or
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 3b83c34019fc..ded2ae34eab1 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -5,8 +5,6 @@
*
* IPv4 Forwarding Information Base: semantics.
*
- * Version: $Id: fib_semantics.c,v 1.19 2002/01/12 07:54:56 davem Exp $
- *
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
*
* This program is free software; you can redistribute it and/or
@@ -960,7 +958,10 @@ int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
rtm->rtm_dst_len = dst_len;
rtm->rtm_src_len = 0;
rtm->rtm_tos = tos;
- rtm->rtm_table = tb_id;
+ if (tb_id < 256)
+ rtm->rtm_table = tb_id;
+ else
+ rtm->rtm_table = RT_TABLE_COMPAT;
NLA_PUT_U32(skb, RTA_TABLE, tb_id);
rtm->rtm_type = type;
rtm->rtm_flags = fi->fib_flags;
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 4b02d14e7ab9..394db9c941a1 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -22,8 +22,6 @@
* IP-address lookup using LC-tries. Stefan Nilsson and Gunnar Karlsson
* IEEE Journal on Selected Areas in Communications, 17(6):1083-1092, June 1999
*
- * Version: $Id: fib_trie.c,v 1.3 2005/06/08 14:20:01 robert Exp $
- *
*
* Code from fib_hash has been reused which includes the following header:
*
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 87397351ddac..aa7cf46853b7 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -3,8 +3,6 @@
*
* Alan Cox, <alan@redhat.com>
*
- * Version: $Id: icmp.c,v 1.85 2002/02/01 22:01:03 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 2769dc4a4c84..68e84a933e90 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -8,8 +8,6 @@
* the older version didn't come out right using gcc 2.5.8, the newer one
* seems to fall out with gcc 2.6.2.
*
- * Version: $Id: igmp.c,v 1.47 2002/02/01 22:01:03 davem Exp $
- *
* Authors:
* Alan Cox <Alan.Cox@linux.org>
*
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index da97695e7096..c10036e7a463 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -1,8 +1,6 @@
/*
* inet_diag.c Module for monitoring INET transport protocols sockets.
*
- * Version: $Id: inet_diag.c,v 1.3 2002/02/01 22:01:04 davem Exp $
- *
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
*
* This program is free software; you can redistribute it and/or
diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c
index af995198f643..a456ceeac3f2 100644
--- a/net/ipv4/inetpeer.c
+++ b/net/ipv4/inetpeer.c
@@ -3,8 +3,6 @@
*
* This source is covered by the GNU GPL, the same as all kernel sources.
*
- * Version: $Id: inetpeer.c,v 1.7 2001/09/20 21:22:50 davem Exp $
- *
* Authors: Andrey V. Savochkin <saw@msu.ru>
*/
diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c
index 4813c39b438b..37d36a3f33cd 100644
--- a/net/ipv4/ip_forward.c
+++ b/net/ipv4/ip_forward.c
@@ -5,8 +5,6 @@
*
* The IP forwarding functionality.
*
- * Version: $Id: ip_forward.c,v 1.48 2000/12/13 18:31:48 davem Exp $
- *
* Authors: see ip.c
*
* Fixes:
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index cd6ce6ac6358..91e321407313 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -5,8 +5,6 @@
*
* The IP fragmentation functionality.
*
- * Version: $Id: ip_fragment.c,v 1.59 2002/01/12 07:54:56 davem Exp $
- *
* Authors: Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG>
* Alan Cox <Alan.Cox@linux.org>
*
@@ -598,7 +596,7 @@ int ip_defrag(struct sk_buff *skb, u32 user)
#ifdef CONFIG_SYSCTL
static int zero;
-static struct ctl_table ip4_frags_ctl_table[] = {
+static struct ctl_table ip4_frags_ns_ctl_table[] = {
{
.ctl_name = NET_IPV4_IPFRAG_HIGH_THRESH,
.procname = "ipfrag_high_thresh",
@@ -624,6 +622,10 @@ static struct ctl_table ip4_frags_ctl_table[] = {
.proc_handler = &proc_dointvec_jiffies,
.strategy = &sysctl_jiffies
},
+ { }
+};
+
+static struct ctl_table ip4_frags_ctl_table[] = {
{
.ctl_name = NET_IPV4_IPFRAG_SECRET_INTERVAL,
.procname = "ipfrag_secret_interval",
@@ -644,22 +646,20 @@ static struct ctl_table ip4_frags_ctl_table[] = {
{ }
};
-static int ip4_frags_ctl_register(struct net *net)
+static int ip4_frags_ns_ctl_register(struct net *net)
{
struct ctl_table *table;
struct ctl_table_header *hdr;
- table = ip4_frags_ctl_table;
+ table = ip4_frags_ns_ctl_table;
if (net != &init_net) {
- table = kmemdup(table, sizeof(ip4_frags_ctl_table), GFP_KERNEL);
+ table = kmemdup(table, sizeof(ip4_frags_ns_ctl_table), GFP_KERNEL);
if (table == NULL)
goto err_alloc;
table[0].data = &net->ipv4.frags.high_thresh;
table[1].data = &net->ipv4.frags.low_thresh;
table[2].data = &net->ipv4.frags.timeout;
- table[3].mode &= ~0222;
- table[4].mode &= ~0222;
}
hdr = register_net_sysctl_table(net, net_ipv4_ctl_path, table);
@@ -676,7 +676,7 @@ err_alloc:
return -ENOMEM;
}
-static void ip4_frags_ctl_unregister(struct net *net)
+static void ip4_frags_ns_ctl_unregister(struct net *net)
{
struct ctl_table *table;
@@ -684,13 +684,22 @@ static void ip4_frags_ctl_unregister(struct net *net)
unregister_net_sysctl_table(net->ipv4.frags_hdr);
kfree(table);
}
+
+static void ip4_frags_ctl_register(void)
+{
+ register_net_sysctl_rotable(net_ipv4_ctl_path, ip4_frags_ctl_table);
+}
#else
-static inline int ip4_frags_ctl_register(struct net *net)
+static inline int ip4_frags_ns_ctl_register(struct net *net)
{
return 0;
}
-static inline void ip4_frags_ctl_unregister(struct net *net)
+static inline void ip4_frags_ns_ctl_unregister(struct net *net)
+{
+}
+
+static inline void ip4_frags_ctl_register(void)
{
}
#endif
@@ -714,12 +723,12 @@ static int ipv4_frags_init_net(struct net *net)
inet_frags_init_net(&net->ipv4.frags);
- return ip4_frags_ctl_register(net);
+ return ip4_frags_ns_ctl_register(net);
}
static void ipv4_frags_exit_net(struct net *net)
{
- ip4_frags_ctl_unregister(net);
+ ip4_frags_ns_ctl_unregister(net);
inet_frags_exit_net(&net->ipv4.frags, &ip4_frags);
}
@@ -730,6 +739,7 @@ static struct pernet_operations ip4_frags_ops = {
void __init ipfrag_init(void)
{
+ ip4_frags_ctl_register();
register_pernet_subsys(&ip4_frags_ops);
ip4_frags.hashfn = ip4_hashfn;
ip4_frags.constructor = ip4_frag_init;
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 2ada033406de..2a61158ea722 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -313,9 +313,8 @@ static void ipgre_tunnel_uninit(struct net_device *dev)
static void ipgre_err(struct sk_buff *skb, u32 info)
{
-#ifndef I_WISH_WORLD_WERE_PERFECT
-/* It is not :-( All the routers (except for Linux) return only
+/* All the routers (except for Linux) return only
8 bytes of packet payload. It means, that precise relaying of
ICMP in the real Internet is absolutely infeasible.
@@ -398,149 +397,6 @@ static void ipgre_err(struct sk_buff *skb, u32 info)
out:
read_unlock(&ipgre_lock);
return;
-#else
- struct iphdr *iph = (struct iphdr*)dp;
- struct iphdr *eiph;
- __be16 *p = (__be16*)(dp+(iph->ihl<<2));
- const int type = icmp_hdr(skb)->type;
- const int code = icmp_hdr(skb)->code;
- int rel_type = 0;
- int rel_code = 0;
- __be32 rel_info = 0;
- __u32 n = 0;
- __be16 flags;
- int grehlen = (iph->ihl<<2) + 4;
- struct sk_buff *skb2;
- struct flowi fl;
- struct rtable *rt;
-
- if (p[1] != htons(ETH_P_IP))
- return;
-
- flags = p[0];
- if (flags&(GRE_CSUM|GRE_KEY|GRE_SEQ|GRE_ROUTING|GRE_VERSION)) {
- if (flags&(GRE_VERSION|GRE_ROUTING))
- return;
- if (flags&GRE_CSUM)
- grehlen += 4;
- if (flags&GRE_KEY)
- grehlen += 4;
- if (flags&GRE_SEQ)
- grehlen += 4;
- }
- if (len < grehlen + sizeof(struct iphdr))
- return;
- eiph = (struct iphdr*)(dp + grehlen);
-
- switch (type) {
- default:
- return;
- case ICMP_PARAMETERPROB:
- n = ntohl(icmp_hdr(skb)->un.gateway) >> 24;
- if (n < (iph->ihl<<2))
- return;
-
- /* So... This guy found something strange INSIDE encapsulated
- packet. Well, he is fool, but what can we do ?
- */
- rel_type = ICMP_PARAMETERPROB;
- n -= grehlen;
- rel_info = htonl(n << 24);
- break;
-
- case ICMP_DEST_UNREACH:
- switch (code) {
- case ICMP_SR_FAILED:
- case ICMP_PORT_UNREACH:
- /* Impossible event. */
- return;
- case ICMP_FRAG_NEEDED:
- /* And it is the only really necessary thing :-) */
- n = ntohs(icmp_hdr(skb)->un.frag.mtu);
- if (n < grehlen+68)
- return;
- n -= grehlen;
- /* BSD 4.2 MORE DOES NOT EXIST IN NATURE. */
- if (n > ntohs(eiph->tot_len))
- return;
- rel_info = htonl(n);
- break;
- default:
- /* All others are translated to HOST_UNREACH.
- rfc2003 contains "deep thoughts" about NET_UNREACH,
- I believe, it is just ether pollution. --ANK
- */
- rel_type = ICMP_DEST_UNREACH;
- rel_code = ICMP_HOST_UNREACH;
- break;
- }
- break;
- case ICMP_TIME_EXCEEDED:
- if (code != ICMP_EXC_TTL)
- return;
- break;
- }
-
- /* Prepare fake skb to feed it to icmp_send */
- skb2 = skb_clone(skb, GFP_ATOMIC);
- if (skb2 == NULL)
- return;
- dst_release(skb2->dst);
- skb2->dst = NULL;
- skb_pull(skb2, skb->data - (u8*)eiph);
- skb_reset_network_header(skb2);
-
- /* Try to guess incoming interface */
- memset(&fl, 0, sizeof(fl));
- fl.fl4_dst = eiph->saddr;
- fl.fl4_tos = RT_TOS(eiph->tos);
- fl.proto = IPPROTO_GRE;
- if (ip_route_output_key(dev_net(skb->dev), &rt, &fl)) {
- kfree_skb(skb2);
- return;
- }
- skb2->dev = rt->u.dst.dev;
-
- /* route "incoming" packet */
- if (rt->rt_flags&RTCF_LOCAL) {
- ip_rt_put(rt);
- rt = NULL;
- fl.fl4_dst = eiph->daddr;
- fl.fl4_src = eiph->saddr;
- fl.fl4_tos = eiph->tos;
- if (ip_route_output_key(dev_net(skb->dev), &rt, &fl) ||
- rt->u.dst.dev->type != ARPHRD_IPGRE) {
- ip_rt_put(rt);
- kfree_skb(skb2);
- return;
- }
- } else {
- ip_rt_put(rt);
- if (ip_route_input(skb2, eiph->daddr, eiph->saddr, eiph->tos, skb2->dev) ||
- skb2->dst->dev->type != ARPHRD_IPGRE) {
- kfree_skb(skb2);
- return;
- }
- }
-
- /* change mtu on this route */
- if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
- if (n > dst_mtu(skb2->dst)) {
- kfree_skb(skb2);
- return;
- }
- skb2->dst->ops->update_pmtu(skb2->dst, n);
- } else if (type == ICMP_TIME_EXCEEDED) {
- struct ip_tunnel *t = netdev_priv(skb2->dev);
- if (t->parms.iph.ttl) {
- rel_type = ICMP_DEST_UNREACH;
- rel_code = ICMP_HOST_UNREACH;
- }
- }
-
- icmp_send(skb2, rel_type, rel_code, rel_info);
- kfree_skb(skb2);
-#endif
}
static inline void ipgre_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb)
@@ -617,6 +473,8 @@ static int ipgre_rcv(struct sk_buff *skb)
read_lock(&ipgre_lock);
if ((tunnel = ipgre_tunnel_lookup(dev_net(skb->dev),
iph->saddr, iph->daddr, key)) != NULL) {
+ struct net_device_stats *stats = &tunnel->dev->stats;
+
secpath_reset(skb);
skb->protocol = *(__be16*)(h + 2);
@@ -641,28 +499,28 @@ static int ipgre_rcv(struct sk_buff *skb)
/* Looped back packet, drop it! */
if (skb->rtable->fl.iif == 0)
goto drop;
- tunnel->stat.multicast++;
+ stats->multicast++;
skb->pkt_type = PACKET_BROADCAST;
}
#endif
if (((flags&GRE_CSUM) && csum) ||
(!(flags&GRE_CSUM) && tunnel->parms.i_flags&GRE_CSUM)) {
- tunnel->stat.rx_crc_errors++;
- tunnel->stat.rx_errors++;
+ stats->rx_crc_errors++;
+ stats->rx_errors++;
goto drop;
}
if (tunnel->parms.i_flags&GRE_SEQ) {
if (!(flags&GRE_SEQ) ||
(tunnel->i_seqno && (s32)(seqno - tunnel->i_seqno) < 0)) {
- tunnel->stat.rx_fifo_errors++;
- tunnel->stat.rx_errors++;
+ stats->rx_fifo_errors++;
+ stats->rx_errors++;
goto drop;
}
tunnel->i_seqno = seqno + 1;
}
- tunnel->stat.rx_packets++;
- tunnel->stat.rx_bytes += skb->len;
+ stats->rx_packets++;
+ stats->rx_bytes += skb->len;
skb->dev = tunnel->dev;
dst_release(skb->dst);
skb->dst = NULL;
@@ -684,7 +542,7 @@ drop_nolock:
static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ip_tunnel *tunnel = netdev_priv(dev);
- struct net_device_stats *stats = &tunnel->stat;
+ struct net_device_stats *stats = &tunnel->dev->stats;
struct iphdr *old_iph = ip_hdr(skb);
struct iphdr *tiph;
u8 tos;
@@ -698,7 +556,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
int mtu;
if (tunnel->recursion++) {
- tunnel->stat.collisions++;
+ stats->collisions++;
goto tx_error;
}
@@ -714,7 +572,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
/* NBMA tunnel */
if (skb->dst == NULL) {
- tunnel->stat.tx_fifo_errors++;
+ stats->tx_fifo_errors++;
goto tx_error;
}
@@ -765,7 +623,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
.tos = RT_TOS(tos) } },
.proto = IPPROTO_GRE };
if (ip_route_output_key(dev_net(dev), &rt, &fl)) {
- tunnel->stat.tx_carrier_errors++;
+ stats->tx_carrier_errors++;
goto tx_error;
}
}
@@ -773,7 +631,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
if (tdev == dev) {
ip_rt_put(rt);
- tunnel->stat.collisions++;
+ stats->collisions++;
goto tx_error;
}
@@ -1098,11 +956,6 @@ done:
return err;
}
-static struct net_device_stats *ipgre_tunnel_get_stats(struct net_device *dev)
-{
- return &(((struct ip_tunnel*)netdev_priv(dev))->stat);
-}
-
static int ipgre_tunnel_change_mtu(struct net_device *dev, int new_mtu)
{
struct ip_tunnel *tunnel = netdev_priv(dev);
@@ -1228,7 +1081,6 @@ static void ipgre_tunnel_setup(struct net_device *dev)
dev->uninit = ipgre_tunnel_uninit;
dev->destructor = free_netdev;
dev->hard_start_xmit = ipgre_tunnel_xmit;
- dev->get_stats = ipgre_tunnel_get_stats;
dev->do_ioctl = ipgre_tunnel_ioctl;
dev->change_mtu = ipgre_tunnel_change_mtu;
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index ff77a4a7f9ec..7c26428ea67b 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -5,8 +5,6 @@
*
* The Internet Protocol (IP) module.
*
- * Version: $Id: ip_input.c,v 1.55 2002/01/12 07:39:45 davem Exp $
- *
* Authors: Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Donald Becker, <becker@super.org>
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c
index 33126ad2cfdc..be3f18a7a40e 100644
--- a/net/ipv4/ip_options.c
+++ b/net/ipv4/ip_options.c
@@ -5,8 +5,6 @@
*
* The options processing module for ip.c
*
- * Version: $Id: ip_options.c,v 1.21 2001/09/01 00:31:50 davem Exp $
- *
* Authors: A.N.Kuznetsov
*
*/
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index e527628f56cf..f1278eecf56d 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -5,8 +5,6 @@
*
* The Internet Protocol (IP) output module.
*
- * Version: $Id: ip_output.c,v 1.100 2002/02/01 22:01:03 davem Exp $
- *
* Authors: Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Donald Becker, <becker@super.org>
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index e0514e82308e..105d92a039b9 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -5,8 +5,6 @@
*
* The IP to API glue.
*
- * Version: $Id: ip_sockglue.c,v 1.62 2002/02/01 22:01:04 davem Exp $
- *
* Authors: see ip.c
*
* Fixes:
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
index ed45037ce9be..b88aa9afa42e 100644
--- a/net/ipv4/ipconfig.c
+++ b/net/ipv4/ipconfig.c
@@ -1,6 +1,4 @@
/*
- * $Id: ipconfig.c,v 1.46 2002/02/01 22:01:04 davem Exp $
- *
* Automatic Configuration of IP -- use DHCP, BOOTP, RARP, or
* user-supplied information to configure own IP address and routes.
*
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 149111f08e8d..4c6d2caf9203 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -1,8 +1,6 @@
/*
* Linux NET3: IP/IP protocol decoder.
*
- * Version: $Id: ipip.c,v 1.50 2001/10/02 02:22:36 davem Exp $
- *
* Authors:
* Sam Lantinga (slouken@cs.ucdavis.edu) 02/01/95
*
@@ -278,9 +276,8 @@ static void ipip_tunnel_uninit(struct net_device *dev)
static int ipip_err(struct sk_buff *skb, u32 info)
{
-#ifndef I_WISH_WORLD_WERE_PERFECT
-/* It is not :-( All the routers (except for Linux) return only
+/* All the routers (except for Linux) return only
8 bytes of packet payload. It means, that precise relaying of
ICMP in the real Internet is absolutely infeasible.
*/
@@ -337,133 +334,6 @@ static int ipip_err(struct sk_buff *skb, u32 info)
out:
read_unlock(&ipip_lock);
return err;
-#else
- struct iphdr *iph = (struct iphdr*)dp;
- int hlen = iph->ihl<<2;
- struct iphdr *eiph;
- const int type = icmp_hdr(skb)->type;
- const int code = icmp_hdr(skb)->code;
- int rel_type = 0;
- int rel_code = 0;
- __be32 rel_info = 0;
- __u32 n = 0;
- struct sk_buff *skb2;
- struct flowi fl;
- struct rtable *rt;
-
- if (len < hlen + sizeof(struct iphdr))
- return 0;
- eiph = (struct iphdr*)(dp + hlen);
-
- switch (type) {
- default:
- return 0;
- case ICMP_PARAMETERPROB:
- n = ntohl(icmp_hdr(skb)->un.gateway) >> 24;
- if (n < hlen)
- return 0;
-
- /* So... This guy found something strange INSIDE encapsulated
- packet. Well, he is fool, but what can we do ?
- */
- rel_type = ICMP_PARAMETERPROB;
- rel_info = htonl((n - hlen) << 24);
- break;
-
- case ICMP_DEST_UNREACH:
- switch (code) {
- case ICMP_SR_FAILED:
- case ICMP_PORT_UNREACH:
- /* Impossible event. */
- return 0;
- case ICMP_FRAG_NEEDED:
- /* And it is the only really necessary thing :-) */
- n = ntohs(icmp_hdr(skb)->un.frag.mtu);
- if (n < hlen+68)
- return 0;
- n -= hlen;
- /* BSD 4.2 MORE DOES NOT EXIST IN NATURE. */
- if (n > ntohs(eiph->tot_len))
- return 0;
- rel_info = htonl(n);
- break;
- default:
- /* All others are translated to HOST_UNREACH.
- rfc2003 contains "deep thoughts" about NET_UNREACH,
- I believe, it is just ether pollution. --ANK
- */
- rel_type = ICMP_DEST_UNREACH;
- rel_code = ICMP_HOST_UNREACH;
- break;
- }
- break;
- case ICMP_TIME_EXCEEDED:
- if (code != ICMP_EXC_TTL)
- return 0;
- break;
- }
-
- /* Prepare fake skb to feed it to icmp_send */
- skb2 = skb_clone(skb, GFP_ATOMIC);
- if (skb2 == NULL)
- return 0;
- dst_release(skb2->dst);
- skb2->dst = NULL;
- skb_pull(skb2, skb->data - (u8*)eiph);
- skb_reset_network_header(skb2);
-
- /* Try to guess incoming interface */
- memset(&fl, 0, sizeof(fl));
- fl.fl4_daddr = eiph->saddr;
- fl.fl4_tos = RT_TOS(eiph->tos);
- fl.proto = IPPROTO_IPIP;
- if (ip_route_output_key(dev_net(skb->dev), &rt, &key)) {
- kfree_skb(skb2);
- return 0;
- }
- skb2->dev = rt->u.dst.dev;
-
- /* route "incoming" packet */
- if (rt->rt_flags&RTCF_LOCAL) {
- ip_rt_put(rt);
- rt = NULL;
- fl.fl4_daddr = eiph->daddr;
- fl.fl4_src = eiph->saddr;
- fl.fl4_tos = eiph->tos;
- if (ip_route_output_key(dev_net(skb->dev), &rt, &fl) ||
- rt->u.dst.dev->type != ARPHRD_TUNNEL) {
- ip_rt_put(rt);
- kfree_skb(skb2);
- return 0;
- }
- } else {
- ip_rt_put(rt);
- if (ip_route_input(skb2, eiph->daddr, eiph->saddr, eiph->tos, skb2->dev) ||
- skb2->dst->dev->type != ARPHRD_TUNNEL) {
- kfree_skb(skb2);
- return 0;
- }
- }
-
- /* change mtu on this route */
- if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
- if (n > dst_mtu(skb2->dst)) {
- kfree_skb(skb2);
- return 0;
- }
- skb2->dst->ops->update_pmtu(skb2->dst, n);
- } else if (type == ICMP_TIME_EXCEEDED) {
- struct ip_tunnel *t = netdev_priv(skb2->dev);
- if (t->parms.iph.ttl) {
- rel_type = ICMP_DEST_UNREACH;
- rel_code = ICMP_HOST_UNREACH;
- }
- }
-
- icmp_send(skb2, rel_type, rel_code, rel_info);
- kfree_skb(skb2);
- return 0;
-#endif
}
static inline void ipip_ecn_decapsulate(const struct iphdr *outer_iph,
@@ -496,8 +366,8 @@ static int ipip_rcv(struct sk_buff *skb)
skb->protocol = htons(ETH_P_IP);
skb->pkt_type = PACKET_HOST;
- tunnel->stat.rx_packets++;
- tunnel->stat.rx_bytes += skb->len;
+ tunnel->dev->stats.rx_packets++;
+ tunnel->dev->stats.rx_bytes += skb->len;
skb->dev = tunnel->dev;
dst_release(skb->dst);
skb->dst = NULL;
@@ -520,7 +390,7 @@ static int ipip_rcv(struct sk_buff *skb)
static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ip_tunnel *tunnel = netdev_priv(dev);
- struct net_device_stats *stats = &tunnel->stat;
+ struct net_device_stats *stats = &tunnel->dev->stats;
struct iphdr *tiph = &tunnel->parms.iph;
u8 tos = tunnel->parms.iph.tos;
__be16 df = tiph->frag_off;
@@ -533,7 +403,7 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
int mtu;
if (tunnel->recursion++) {
- tunnel->stat.collisions++;
+ stats->collisions++;
goto tx_error;
}
@@ -546,7 +416,7 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
if (!dst) {
/* NBMA tunnel */
if ((rt = skb->rtable) == NULL) {
- tunnel->stat.tx_fifo_errors++;
+ stats->tx_fifo_errors++;
goto tx_error;
}
if ((dst = rt->rt_gateway) == 0)
@@ -561,7 +431,7 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
.tos = RT_TOS(tos) } },
.proto = IPPROTO_IPIP };
if (ip_route_output_key(dev_net(dev), &rt, &fl)) {
- tunnel->stat.tx_carrier_errors++;
+ stats->tx_carrier_errors++;
goto tx_error_icmp;
}
}
@@ -569,7 +439,7 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
if (tdev == dev) {
ip_rt_put(rt);
- tunnel->stat.collisions++;
+ stats->collisions++;
goto tx_error;
}
@@ -579,7 +449,7 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
mtu = skb->dst ? dst_mtu(skb->dst) : dev->mtu;
if (mtu < 68) {
- tunnel->stat.collisions++;
+ stats->collisions++;
ip_rt_put(rt);
goto tx_error;
}
@@ -813,11 +683,6 @@ done:
return err;
}
-static struct net_device_stats *ipip_tunnel_get_stats(struct net_device *dev)
-{
- return &(((struct ip_tunnel*)netdev_priv(dev))->stat);
-}
-
static int ipip_tunnel_change_mtu(struct net_device *dev, int new_mtu)
{
if (new_mtu < 68 || new_mtu > 0xFFF8 - sizeof(struct iphdr))
@@ -830,7 +695,6 @@ static void ipip_tunnel_setup(struct net_device *dev)
{
dev->uninit = ipip_tunnel_uninit;
dev->hard_start_xmit = ipip_tunnel_xmit;
- dev->get_stats = ipip_tunnel_get_stats;
dev->do_ioctl = ipip_tunnel_ioctl;
dev->change_mtu = ipip_tunnel_change_mtu;
dev->destructor = free_netdev;
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 11700a4dcd95..300ab0c2919e 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -9,8 +9,6 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * Version: $Id: ipmr.c,v 1.65 2001/10/31 21:55:54 davem Exp $
- *
* Fixes:
* Michael Chastain : Incorrect size of copying.
* Alan Cox : Added the cache manager code
@@ -181,26 +179,20 @@ static int reg_vif_num = -1;
static int reg_vif_xmit(struct sk_buff *skb, struct net_device *dev)
{
read_lock(&mrt_lock);
- ((struct net_device_stats*)netdev_priv(dev))->tx_bytes += skb->len;
- ((struct net_device_stats*)netdev_priv(dev))->tx_packets++;
+ dev->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
ipmr_cache_report(skb, reg_vif_num, IGMPMSG_WHOLEPKT);
read_unlock(&mrt_lock);
kfree_skb(skb);
return 0;
}
-static struct net_device_stats *reg_vif_get_stats(struct net_device *dev)
-{
- return (struct net_device_stats*)netdev_priv(dev);
-}
-
static void reg_vif_setup(struct net_device *dev)
{
dev->type = ARPHRD_PIMREG;
dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr) - 8;
dev->flags = IFF_NOARP;
dev->hard_start_xmit = reg_vif_xmit;
- dev->get_stats = reg_vif_get_stats;
dev->destructor = free_netdev;
}
@@ -209,8 +201,7 @@ static struct net_device *ipmr_reg_vif(void)
struct net_device *dev;
struct in_device *in_dev;
- dev = alloc_netdev(sizeof(struct net_device_stats), "pimreg",
- reg_vif_setup);
+ dev = alloc_netdev(0, "pimreg", reg_vif_setup);
if (dev == NULL)
return NULL;
@@ -1170,8 +1161,8 @@ static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi)
if (vif->flags & VIFF_REGISTER) {
vif->pkt_out++;
vif->bytes_out+=skb->len;
- ((struct net_device_stats*)netdev_priv(vif->dev))->tx_bytes += skb->len;
- ((struct net_device_stats*)netdev_priv(vif->dev))->tx_packets++;
+ vif->dev->stats.tx_bytes += skb->len;
+ vif->dev->stats.tx_packets++;
ipmr_cache_report(skb, vifi, IGMPMSG_WHOLEPKT);
kfree_skb(skb);
return;
@@ -1230,8 +1221,8 @@ static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi)
if (vif->flags & VIFF_TUNNEL) {
ip_encap(skb, vif->local, vif->remote);
/* FIXME: extra output firewall step used to be here. --RR */
- ((struct ip_tunnel *)netdev_priv(vif->dev))->stat.tx_packets++;
- ((struct ip_tunnel *)netdev_priv(vif->dev))->stat.tx_bytes+=skb->len;
+ vif->dev->stats.tx_packets++;
+ vif->dev->stats.tx_bytes += skb->len;
}
IPCB(skb)->flags |= IPSKB_FORWARDED;
@@ -1487,8 +1478,8 @@ int pim_rcv_v1(struct sk_buff * skb)
skb->pkt_type = PACKET_HOST;
dst_release(skb->dst);
skb->dst = NULL;
- ((struct net_device_stats*)netdev_priv(reg_dev))->rx_bytes += skb->len;
- ((struct net_device_stats*)netdev_priv(reg_dev))->rx_packets++;
+ reg_dev->stats.rx_bytes += skb->len;
+ reg_dev->stats.rx_packets++;
nf_reset(skb);
netif_rx(skb);
dev_put(reg_dev);
@@ -1542,8 +1533,8 @@ static int pim_rcv(struct sk_buff * skb)
skb->ip_summed = 0;
skb->pkt_type = PACKET_HOST;
dst_release(skb->dst);
- ((struct net_device_stats*)netdev_priv(reg_dev))->rx_bytes += skb->len;
- ((struct net_device_stats*)netdev_priv(reg_dev))->rx_packets++;
+ reg_dev->stats.rx_bytes += skb->len;
+ reg_dev->stats.rx_packets++;
skb->dst = NULL;
nf_reset(skb);
netif_rx(skb);
diff --git a/net/ipv4/ipvs/ip_vs_app.c b/net/ipv4/ipvs/ip_vs_app.c
index 535abe0c45e7..1f1897a1a702 100644
--- a/net/ipv4/ipvs/ip_vs_app.c
+++ b/net/ipv4/ipvs/ip_vs_app.c
@@ -1,8 +1,6 @@
/*
* ip_vs_app.c: Application module support for IPVS
*
- * Version: $Id: ip_vs_app.c,v 1.17 2003/03/22 06:31:21 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
*
* This program is free software; you can redistribute it and/or
diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c
index 65f1ba112752..f8bdae47a77f 100644
--- a/net/ipv4/ipvs/ip_vs_conn.c
+++ b/net/ipv4/ipvs/ip_vs_conn.c
@@ -5,8 +5,6 @@
* high-performance and highly available server based on a
* cluster of servers.
*
- * Version: $Id: ip_vs_conn.c,v 1.31 2003/04/18 09:03:16 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
* Peter Kese <peter.kese@ijs.si>
* Julian Anastasov <ja@ssi.bg>
diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
index 963981a9d501..bcf6276ba4b2 100644
--- a/net/ipv4/ipvs/ip_vs_core.c
+++ b/net/ipv4/ipvs/ip_vs_core.c
@@ -5,8 +5,6 @@
* high-performance and highly available server based on a
* cluster of servers.
*
- * Version: $Id: ip_vs_core.c,v 1.34 2003/05/10 03:05:23 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
* Peter Kese <peter.kese@ijs.si>
* Julian Anastasov <ja@ssi.bg>
diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index 94c5767c8e01..9a5ace0b4dd6 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -5,8 +5,6 @@
* high-performance and highly available server based on a
* cluster of servers.
*
- * Version: $Id: ip_vs_ctl.c,v 1.36 2003/06/08 09:31:19 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
* Peter Kese <peter.kese@ijs.si>
* Julian Anastasov <ja@ssi.bg>
diff --git a/net/ipv4/ipvs/ip_vs_dh.c b/net/ipv4/ipvs/ip_vs_dh.c
index dcf5d46aaa5e..8afc1503ed20 100644
--- a/net/ipv4/ipvs/ip_vs_dh.c
+++ b/net/ipv4/ipvs/ip_vs_dh.c
@@ -1,8 +1,6 @@
/*
* IPVS: Destination Hashing scheduling module
*
- * Version: $Id: ip_vs_dh.c,v 1.5 2002/09/15 08:14:08 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@gnuchina.org>
*
* Inspired by the consistent hashing scheduler patch from
diff --git a/net/ipv4/ipvs/ip_vs_est.c b/net/ipv4/ipvs/ip_vs_est.c
index dfa0d713c801..bc04eedd6dbb 100644
--- a/net/ipv4/ipvs/ip_vs_est.c
+++ b/net/ipv4/ipvs/ip_vs_est.c
@@ -1,8 +1,6 @@
/*
* ip_vs_est.c: simple rate estimator for IPVS
*
- * Version: $Id: ip_vs_est.c,v 1.4 2002/11/30 01:50:35 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
*
* This program is free software; you can redistribute it and/or
diff --git a/net/ipv4/ipvs/ip_vs_ftp.c b/net/ipv4/ipvs/ip_vs_ftp.c
index 59aa166b7678..c1c758e4f733 100644
--- a/net/ipv4/ipvs/ip_vs_ftp.c
+++ b/net/ipv4/ipvs/ip_vs_ftp.c
@@ -1,8 +1,6 @@
/*
* ip_vs_ftp.c: IPVS ftp application module
*
- * Version: $Id: ip_vs_ftp.c,v 1.13 2002/09/15 08:14:08 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
*
* Changes:
diff --git a/net/ipv4/ipvs/ip_vs_lblc.c b/net/ipv4/ipvs/ip_vs_lblc.c
index 3888642706ad..0efa3db4b180 100644
--- a/net/ipv4/ipvs/ip_vs_lblc.c
+++ b/net/ipv4/ipvs/ip_vs_lblc.c
@@ -1,8 +1,6 @@
/*
* IPVS: Locality-Based Least-Connection scheduling module
*
- * Version: $Id: ip_vs_lblc.c,v 1.10 2002/09/15 08:14:08 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@gnuchina.org>
*
* This program is free software; you can redistribute it and/or
diff --git a/net/ipv4/ipvs/ip_vs_lblcr.c b/net/ipv4/ipvs/ip_vs_lblcr.c
index daa260eb21cf..8e3bbeb45138 100644
--- a/net/ipv4/ipvs/ip_vs_lblcr.c
+++ b/net/ipv4/ipvs/ip_vs_lblcr.c
@@ -1,8 +1,6 @@
/*
* IPVS: Locality-Based Least-Connection with Replication scheduler
*
- * Version: $Id: ip_vs_lblcr.c,v 1.11 2002/09/15 08:14:08 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@gnuchina.org>
*
* This program is free software; you can redistribute it and/or
diff --git a/net/ipv4/ipvs/ip_vs_lc.c b/net/ipv4/ipvs/ip_vs_lc.c
index d88fef90a641..ac9f08e065d5 100644
--- a/net/ipv4/ipvs/ip_vs_lc.c
+++ b/net/ipv4/ipvs/ip_vs_lc.c
@@ -1,8 +1,6 @@
/*
* IPVS: Least-Connection Scheduling module
*
- * Version: $Id: ip_vs_lc.c,v 1.10 2003/04/18 09:03:16 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
*
* This program is free software; you can redistribute it and/or
diff --git a/net/ipv4/ipvs/ip_vs_nq.c b/net/ipv4/ipvs/ip_vs_nq.c
index bc2a9e5f2a7b..a46bf258d420 100644
--- a/net/ipv4/ipvs/ip_vs_nq.c
+++ b/net/ipv4/ipvs/ip_vs_nq.c
@@ -1,8 +1,6 @@
/*
* IPVS: Never Queue scheduling module
*
- * Version: $Id: ip_vs_nq.c,v 1.2 2003/06/08 09:31:19 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
*
* This program is free software; you can redistribute it and/or
diff --git a/net/ipv4/ipvs/ip_vs_proto.c b/net/ipv4/ipvs/ip_vs_proto.c
index 4b1c16cbb16b..876714f23d65 100644
--- a/net/ipv4/ipvs/ip_vs_proto.c
+++ b/net/ipv4/ipvs/ip_vs_proto.c
@@ -1,8 +1,6 @@
/*
* ip_vs_proto.c: transport protocol load balancing support for IPVS
*
- * Version: $Id: ip_vs_proto.c,v 1.2 2003/04/18 09:03:16 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
* Julian Anastasov <ja@ssi.bg>
*
diff --git a/net/ipv4/ipvs/ip_vs_proto_ah.c b/net/ipv4/ipvs/ip_vs_proto_ah.c
index 4bf835e1d86d..73e0ea87c1f5 100644
--- a/net/ipv4/ipvs/ip_vs_proto_ah.c
+++ b/net/ipv4/ipvs/ip_vs_proto_ah.c
@@ -1,8 +1,6 @@
/*
* ip_vs_proto_ah.c: AH IPSec load balancing support for IPVS
*
- * Version: $Id: ip_vs_proto_ah.c,v 1.1 2003/07/04 15:04:37 wensong Exp $
- *
* Authors: Julian Anastasov <ja@ssi.bg>, February 2002
* Wensong Zhang <wensong@linuxvirtualserver.org>
*
diff --git a/net/ipv4/ipvs/ip_vs_proto_esp.c b/net/ipv4/ipvs/ip_vs_proto_esp.c
index db6a6b7b1a0b..21d70c8ffa54 100644
--- a/net/ipv4/ipvs/ip_vs_proto_esp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_esp.c
@@ -1,8 +1,6 @@
/*
* ip_vs_proto_esp.c: ESP IPSec load balancing support for IPVS
*
- * Version: $Id: ip_vs_proto_esp.c,v 1.1 2003/07/04 15:04:37 wensong Exp $
- *
* Authors: Julian Anastasov <ja@ssi.bg>, February 2002
* Wensong Zhang <wensong@linuxvirtualserver.org>
*
diff --git a/net/ipv4/ipvs/ip_vs_proto_tcp.c b/net/ipv4/ipvs/ip_vs_proto_tcp.c
index b83dc14b0a4d..d0ea467986a0 100644
--- a/net/ipv4/ipvs/ip_vs_proto_tcp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_tcp.c
@@ -1,8 +1,6 @@
/*
* ip_vs_proto_tcp.c: TCP load balancing support for IPVS
*
- * Version: $Id: ip_vs_proto_tcp.c,v 1.3 2002/11/30 01:50:35 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
* Julian Anastasov <ja@ssi.bg>
*
diff --git a/net/ipv4/ipvs/ip_vs_proto_udp.c b/net/ipv4/ipvs/ip_vs_proto_udp.c
index 75771cb3cd6f..c6be5d56823f 100644
--- a/net/ipv4/ipvs/ip_vs_proto_udp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_udp.c
@@ -1,8 +1,6 @@
/*
* ip_vs_proto_udp.c: UDP load balancing support for IPVS
*
- * Version: $Id: ip_vs_proto_udp.c,v 1.3 2002/11/30 01:50:35 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
* Julian Anastasov <ja@ssi.bg>
*
diff --git a/net/ipv4/ipvs/ip_vs_rr.c b/net/ipv4/ipvs/ip_vs_rr.c
index 433f8a947924..c8db12d39e61 100644
--- a/net/ipv4/ipvs/ip_vs_rr.c
+++ b/net/ipv4/ipvs/ip_vs_rr.c
@@ -1,8 +1,6 @@
/*
* IPVS: Round-Robin Scheduling module
*
- * Version: $Id: ip_vs_rr.c,v 1.9 2002/09/15 08:14:08 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
* Peter Kese <peter.kese@ijs.si>
*
diff --git a/net/ipv4/ipvs/ip_vs_sched.c b/net/ipv4/ipvs/ip_vs_sched.c
index 121a32b1b756..b64767309855 100644
--- a/net/ipv4/ipvs/ip_vs_sched.c
+++ b/net/ipv4/ipvs/ip_vs_sched.c
@@ -5,8 +5,6 @@
* high-performance and highly available server based on a
* cluster of servers.
*
- * Version: $Id: ip_vs_sched.c,v 1.13 2003/05/10 03:05:23 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
* Peter Kese <peter.kese@ijs.si>
*
diff --git a/net/ipv4/ipvs/ip_vs_sed.c b/net/ipv4/ipvs/ip_vs_sed.c
index dd7c128f9db3..2a7d31358181 100644
--- a/net/ipv4/ipvs/ip_vs_sed.c
+++ b/net/ipv4/ipvs/ip_vs_sed.c
@@ -1,8 +1,6 @@
/*
* IPVS: Shortest Expected Delay scheduling module
*
- * Version: $Id: ip_vs_sed.c,v 1.1 2003/05/10 03:06:08 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
*
* This program is free software; you can redistribute it and/or
diff --git a/net/ipv4/ipvs/ip_vs_sh.c b/net/ipv4/ipvs/ip_vs_sh.c
index 1b25b00ef1e1..b8fdfac65001 100644
--- a/net/ipv4/ipvs/ip_vs_sh.c
+++ b/net/ipv4/ipvs/ip_vs_sh.c
@@ -1,8 +1,6 @@
/*
* IPVS: Source Hashing scheduling module
*
- * Version: $Id: ip_vs_sh.c,v 1.5 2002/09/15 08:14:08 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@gnuchina.org>
*
* This program is free software; you can redistribute it and/or
diff --git a/net/ipv4/ipvs/ip_vs_sync.c b/net/ipv4/ipvs/ip_vs_sync.c
index eff54efe0351..2d4a86f73325 100644
--- a/net/ipv4/ipvs/ip_vs_sync.c
+++ b/net/ipv4/ipvs/ip_vs_sync.c
@@ -5,8 +5,6 @@
* high-performance and highly available server based on a
* cluster of servers.
*
- * Version: $Id: ip_vs_sync.c,v 1.13 2003/06/08 09:31:19 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
*
* ip_vs_sync: sync connection info from master load balancer to backups
diff --git a/net/ipv4/ipvs/ip_vs_wlc.c b/net/ipv4/ipvs/ip_vs_wlc.c
index 8a9d913261d8..772c3cb4eca1 100644
--- a/net/ipv4/ipvs/ip_vs_wlc.c
+++ b/net/ipv4/ipvs/ip_vs_wlc.c
@@ -1,8 +1,6 @@
/*
* IPVS: Weighted Least-Connection Scheduling module
*
- * Version: $Id: ip_vs_wlc.c,v 1.13 2003/04/18 09:03:16 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
* Peter Kese <peter.kese@ijs.si>
*
diff --git a/net/ipv4/ipvs/ip_vs_wrr.c b/net/ipv4/ipvs/ip_vs_wrr.c
index 85c680add6df..1d6932d7dc97 100644
--- a/net/ipv4/ipvs/ip_vs_wrr.c
+++ b/net/ipv4/ipvs/ip_vs_wrr.c
@@ -1,8 +1,6 @@
/*
* IPVS: Weighted Round-Robin Scheduling module
*
- * Version: $Id: ip_vs_wrr.c,v 1.12 2002/09/15 08:14:08 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
*
* This program is free software; you can redistribute it and/or
diff --git a/net/ipv4/ipvs/ip_vs_xmit.c b/net/ipv4/ipvs/ip_vs_xmit.c
index f63006caea03..9892d4aca42e 100644
--- a/net/ipv4/ipvs/ip_vs_xmit.c
+++ b/net/ipv4/ipvs/ip_vs_xmit.c
@@ -1,8 +1,6 @@
/*
* ip_vs_xmit.c: various packet transmitters for IPVS
*
- * Version: $Id: ip_vs_xmit.c,v 1.2 2002/11/30 01:50:35 wensong Exp $
- *
* Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
* Julian Anastasov <ja@ssi.bg>
*
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 2767841a8cef..6e251402506e 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -365,6 +365,18 @@ config IP_NF_RAW
If you want to compile it as a module, say M here and read
<file:Documentation/kbuild/modules.txt>. If unsure, say `N'.
+# security table for MAC policy
+config IP_NF_SECURITY
+ tristate "Security table"
+ depends on IP_NF_IPTABLES
+ depends on SECURITY
+ default m if NETFILTER_ADVANCED=n
+ help
+ This option adds a `security' table to iptables, for use
+ with Mandatory Access Control (MAC) policy.
+
+ If unsure, say N.
+
# ARP tables
config IP_NF_ARPTABLES
tristate "ARP tables support"
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index d9b92fbf5579..3f31291f37ce 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o
obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o
obj-$(CONFIG_NF_NAT) += iptable_nat.o
obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o
+obj-$(CONFIG_IP_NF_SECURITY) += iptable_security.o
# matches
obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c
index 26a37cedcf2e..aa33a4a7a715 100644
--- a/net/ipv4/netfilter/ip_queue.c
+++ b/net/ipv4/netfilter/ip_queue.c
@@ -156,7 +156,6 @@ ipq_build_packet_message(struct nf_queue_entry *entry, int *errp)
case IPQ_COPY_META:
case IPQ_COPY_NONE:
size = NLMSG_SPACE(sizeof(*pmsg));
- data_len = 0;
break;
case IPQ_COPY_PACKET:
@@ -224,8 +223,6 @@ ipq_build_packet_message(struct nf_queue_entry *entry, int *errp)
return skb;
nlmsg_failure:
- if (skb)
- kfree_skb(skb);
*errp = -EINVAL;
printk(KERN_ERR "ip_queue: error creating packet message\n");
return NULL;
diff --git a/net/ipv4/netfilter/iptable_security.c b/net/ipv4/netfilter/iptable_security.c
new file mode 100644
index 000000000000..2b472ac2263a
--- /dev/null
+++ b/net/ipv4/netfilter/iptable_security.c
@@ -0,0 +1,180 @@
+/*
+ * "security" table
+ *
+ * This is for use by Mandatory Access Control (MAC) security models,
+ * which need to be able to manage security policy in separate context
+ * to DAC.
+ *
+ * Based on iptable_mangle.c
+ *
+ * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
+ * Copyright (C) 2000-2004 Netfilter Core Team <coreteam <at> netfilter.org>
+ * Copyright (C) 2008 Red Hat, Inc., James Morris <jmorris <at> redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <net/ip.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("James Morris <jmorris <at> redhat.com>");
+MODULE_DESCRIPTION("iptables security table, for MAC rules");
+
+#define SECURITY_VALID_HOOKS (1 << NF_INET_LOCAL_IN) | \
+ (1 << NF_INET_FORWARD) | \
+ (1 << NF_INET_LOCAL_OUT)
+
+static struct
+{
+ struct ipt_replace repl;
+ struct ipt_standard entries[3];
+ struct ipt_error term;
+} initial_table __initdata = {
+ .repl = {
+ .name = "security",
+ .valid_hooks = SECURITY_VALID_HOOKS,
+ .num_entries = 4,
+ .size = sizeof(struct ipt_standard) * 3 + sizeof(struct ipt_error),
+ .hook_entry = {
+ [NF_INET_LOCAL_IN] = 0,
+ [NF_INET_FORWARD] = sizeof(struct ipt_standard),
+ [NF_INET_LOCAL_OUT] = sizeof(struct ipt_standard) * 2,
+ },
+ .underflow = {
+ [NF_INET_LOCAL_IN] = 0,
+ [NF_INET_FORWARD] = sizeof(struct ipt_standard),
+ [NF_INET_LOCAL_OUT] = sizeof(struct ipt_standard) * 2,
+ },
+ },
+ .entries = {
+ IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */
+ IPT_STANDARD_INIT(NF_ACCEPT), /* FORWARD */
+ IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */
+ },
+ .term = IPT_ERROR_INIT, /* ERROR */
+};
+
+static struct xt_table security_table = {
+ .name = "security",
+ .valid_hooks = SECURITY_VALID_HOOKS,
+ .lock = __RW_LOCK_UNLOCKED(security_table.lock),
+ .me = THIS_MODULE,
+ .af = AF_INET,
+};
+
+static unsigned int
+ipt_local_in_hook(unsigned int hook,
+ struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ return ipt_do_table(skb, hook, in, out,
+ nf_local_in_net(in, out)->ipv4.iptable_security);
+}
+
+static unsigned int
+ipt_forward_hook(unsigned int hook,
+ struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ return ipt_do_table(skb, hook, in, out,
+ nf_forward_net(in, out)->ipv4.iptable_security);
+}
+
+static unsigned int
+ipt_local_out_hook(unsigned int hook,
+ struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ /* Somebody is playing with raw sockets. */
+ if (skb->len < sizeof(struct iphdr)
+ || ip_hdrlen(skb) < sizeof(struct iphdr)) {
+ if (net_ratelimit())
+ printk(KERN_INFO "iptable_security: ignoring short "
+ "SOCK_RAW packet.\n");
+ return NF_ACCEPT;
+ }
+ return ipt_do_table(skb, hook, in, out,
+ nf_local_out_net(in, out)->ipv4.iptable_security);
+}
+
+static struct nf_hook_ops ipt_ops[] __read_mostly = {
+ {
+ .hook = ipt_local_in_hook,
+ .owner = THIS_MODULE,
+ .pf = PF_INET,
+ .hooknum = NF_INET_LOCAL_IN,
+ .priority = NF_IP_PRI_SECURITY,
+ },
+ {
+ .hook = ipt_forward_hook,
+ .owner = THIS_MODULE,
+ .pf = PF_INET,
+ .hooknum = NF_INET_FORWARD,
+ .priority = NF_IP_PRI_SECURITY,
+ },
+ {
+ .hook = ipt_local_out_hook,
+ .owner = THIS_MODULE,
+ .pf = PF_INET,
+ .hooknum = NF_INET_LOCAL_OUT,
+ .priority = NF_IP_PRI_SECURITY,
+ },
+};
+
+static int __net_init iptable_security_net_init(struct net *net)
+{
+ net->ipv4.iptable_security =
+ ipt_register_table(net, &security_table, &initial_table.repl);
+
+ if (IS_ERR(net->ipv4.iptable_security))
+ return PTR_ERR(net->ipv4.iptable_security);
+
+ return 0;
+}
+
+static void __net_exit iptable_security_net_exit(struct net *net)
+{
+ ipt_unregister_table(net->ipv4.iptable_security);
+}
+
+static struct pernet_operations iptable_security_net_ops = {
+ .init = iptable_security_net_init,
+ .exit = iptable_security_net_exit,
+};
+
+static int __init iptable_security_init(void)
+{
+ int ret;
+
+ ret = register_pernet_subsys(&iptable_security_net_ops);
+ if (ret < 0)
+ return ret;
+
+ ret = nf_register_hooks(ipt_ops, ARRAY_SIZE(ipt_ops));
+ if (ret < 0)
+ goto cleanup_table;
+
+ return ret;
+
+cleanup_table:
+ unregister_pernet_subsys(&iptable_security_net_ops);
+ return ret;
+}
+
+static void __exit iptable_security_fini(void)
+{
+ nf_unregister_hooks(ipt_ops, ARRAY_SIZE(ipt_ops));
+ unregister_pernet_subsys(&iptable_security_net_ops);
+}
+
+module_init(iptable_security_init);
+module_exit(iptable_security_fini);
diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
index 78ab19accace..97791048fa9b 100644
--- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
+++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
@@ -87,9 +87,8 @@ static int icmp_packet(struct nf_conn *ct,
means this will only run once even if count hits zero twice
(theoretically possible with SMP) */
if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) {
- if (atomic_dec_and_test(&ct->proto.icmp.count)
- && del_timer(&ct->timeout))
- ct->timeout.function((unsigned long)ct);
+ if (atomic_dec_and_test(&ct->proto.icmp.count))
+ nf_ct_kill_acct(ct, ctinfo, skb);
} else {
atomic_inc(&ct->proto.icmp.count);
nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb);
diff --git a/net/ipv4/netfilter/nf_nat_snmp_basic.c b/net/ipv4/netfilter/nf_nat_snmp_basic.c
index 5daefad3d193..7750c97fde7b 100644
--- a/net/ipv4/netfilter/nf_nat_snmp_basic.c
+++ b/net/ipv4/netfilter/nf_nat_snmp_basic.c
@@ -232,6 +232,11 @@ static unsigned char asn1_length_decode(struct asn1_ctx *ctx,
}
}
}
+
+ /* don't trust len bigger than ctx buffer */
+ if (*len > ctx->end - ctx->pointer)
+ return 0;
+
return 1;
}
@@ -250,6 +255,10 @@ static unsigned char asn1_header_decode(struct asn1_ctx *ctx,
if (!asn1_length_decode(ctx, &def, &len))
return 0;
+ /* primitive shall be definite, indefinite shall be constructed */
+ if (*con == ASN1_PRI && !def)
+ return 0;
+
if (def)
*eoc = ctx->pointer + len;
else
@@ -434,6 +443,11 @@ static unsigned char asn1_oid_decode(struct asn1_ctx *ctx,
unsigned long *optr;
size = eoc - ctx->pointer + 1;
+
+ /* first subid actually encodes first two subids */
+ if (size < 2 || size > ULONG_MAX/sizeof(unsigned long))
+ return 0;
+
*oid = kmalloc(size * sizeof(unsigned long), GFP_ATOMIC);
if (*oid == NULL) {
if (net_ratelimit())
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c
index 552169b41b16..eb5cee279c5f 100644
--- a/net/ipv4/proc.c
+++ b/net/ipv4/proc.c
@@ -7,8 +7,6 @@
* PROC file system. It is mainly used for debugging and
* statistics.
*
- * Version: $Id: proc.c,v 1.45 2001/05/16 16:45:35 davem Exp $
- *
* Authors: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Gerald J. Heim, <heim@peanuts.informatik.uni-tuebingen.de>
* Fred Baumgarten, <dc6iq@insu1.etec.uni-karlsruhe.de>
diff --git a/net/ipv4/protocol.c b/net/ipv4/protocol.c
index 971ab9356e51..ea50da0649fd 100644
--- a/net/ipv4/protocol.c
+++ b/net/ipv4/protocol.c
@@ -5,8 +5,6 @@
*
* INET protocol dispatch tables.
*
- * Version: $Id: protocol.c,v 1.14 2001/05/18 02:25:49 davem Exp $
- *
* Authors: Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
*
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index fead049daf43..1d0c97c8712d 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -5,8 +5,6 @@
*
* RAW - implementation of IP "raw" sockets.
*
- * Version: $Id: raw.c,v 1.64 2002/02/01 22:01:04 davem Exp $
- *
* Authors: Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
*
@@ -608,6 +606,14 @@ static void raw_close(struct sock *sk, long timeout)
sk_common_release(sk);
}
+static int raw_destroy(struct sock *sk)
+{
+ lock_sock(sk);
+ ip_flush_pending_frames(sk);
+ release_sock(sk);
+ return 0;
+}
+
/* This gets rid of all the nasties in af_inet. -DaveM */
static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
{
@@ -820,6 +826,7 @@ struct proto raw_prot = {
.name = "RAW",
.owner = THIS_MODULE,
.close = raw_close,
+ .destroy = raw_destroy,
.connect = ip4_datagram_connect,
.disconnect = udp_disconnect,
.ioctl = raw_ioctl,
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 92f90ae46f4a..fe3a02237286 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -5,8 +5,6 @@
*
* ROUTE - implementation of the IP router.
*
- * Version: $Id: route.c,v 1.103 2002/01/12 07:44:09 davem Exp $
- *
* Authors: Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Alan Cox, <gw4pts@gw4pts.ampr.org>
@@ -160,7 +158,7 @@ static struct dst_ops ipv4_dst_ops = {
.negative_advice = ipv4_negative_advice,
.link_failure = ipv4_link_failure,
.update_pmtu = ip_rt_update_pmtu,
- .local_out = ip_local_out,
+ .local_out = __ip_local_out,
.entry_size = sizeof(struct rtable),
.entries = ATOMIC_INIT(0),
};
@@ -1792,7 +1790,7 @@ static int __mkroute_input(struct sk_buff *skb,
if (err)
flags |= RTCF_DIRECTSRC;
- if (out_dev == in_dev && err && !(flags & RTCF_MASQ) &&
+ if (out_dev == in_dev && err &&
(IN_DEV_SHARED_MEDIA(out_dev) ||
inet_addr_onlink(out_dev, saddr, FIB_RES_GW(*res))))
flags |= RTCF_DOREDIRECT;
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index 73ba98921d64..fdde2ae07e24 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -8,8 +8,6 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
- *
- * $Id: syncookies.c,v 1.18 2002/02/01 22:01:04 davem Exp $
*/
#include <linux/tcp.h>
@@ -285,7 +283,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
cookie_check_timestamp(&tcp_opt);
ret = NULL;
- req = reqsk_alloc(&tcp_request_sock_ops); /* for safety */
+ req = inet_reqsk_alloc(&tcp_request_sock_ops); /* for safety */
if (!req)
goto out;
@@ -301,7 +299,6 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
ireq->rmt_port = th->source;
ireq->loc_addr = ip_hdr(skb)->daddr;
ireq->rmt_addr = ip_hdr(skb)->saddr;
- ireq->opt = NULL;
ireq->snd_wscale = tcp_opt.snd_wscale;
ireq->rcv_wscale = tcp_opt.rcv_wscale;
ireq->sack_ok = tcp_opt.sack_ok;
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index c437f804ee38..901607003205 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -1,8 +1,6 @@
/*
* sysctl_net_ipv4.c: sysctl interface to net IPV4 subsystem.
*
- * $Id: sysctl_net_ipv4.c,v 1.50 2001/10/20 00:00:11 davem Exp $
- *
* Begun April 1, 1996, Mike Shaver.
* Added /proc/sys/net/ipv4 directory entry (empty =) ). [MS]
*/
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index f88653138621..6d30ca559c64 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -5,8 +5,6 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp.c,v 1.216 2002/02/01 22:01:04 davem Exp $
- *
* Authors: Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Mark Evans, <evansmp@uhura.aston.ac.uk>
@@ -1227,7 +1225,14 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
copied += used;
offset += used;
}
- if (offset != skb->len)
+ /*
+ * If recv_actor drops the lock (e.g. TCP splice
+ * receive) the skb pointer might be invalid when
+ * getting here: tcp_collapse might have deleted it
+ * while aggregating skbs from the socket queue.
+ */
+ skb = tcp_recv_skb(sk, seq-1, &offset);
+ if (!skb || (offset+1 != skb->len))
break;
}
if (tcp_hdr(skb)->fin) {
@@ -2452,6 +2457,76 @@ static unsigned long tcp_md5sig_users;
static struct tcp_md5sig_pool **tcp_md5sig_pool;
static DEFINE_SPINLOCK(tcp_md5sig_pool_lock);
+int tcp_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
+ int bplen,
+ struct tcphdr *th, unsigned int tcplen,
+ struct tcp_md5sig_pool *hp)
+{
+ struct scatterlist sg[4];
+ __u16 data_len;
+ int block = 0;
+ __sum16 cksum;
+ struct hash_desc *desc = &hp->md5_desc;
+ int err;
+ unsigned int nbytes = 0;
+
+ sg_init_table(sg, 4);
+
+ /* 1. The TCP pseudo-header */
+ sg_set_buf(&sg[block++], &hp->md5_blk, bplen);
+ nbytes += bplen;
+
+ /* 2. The TCP header, excluding options, and assuming a
+ * checksum of zero
+ */
+ cksum = th->check;
+ th->check = 0;
+ sg_set_buf(&sg[block++], th, sizeof(*th));
+ nbytes += sizeof(*th);
+
+ /* 3. The TCP segment data (if any) */
+ data_len = tcplen - (th->doff << 2);
+ if (data_len > 0) {
+ u8 *data = (u8 *)th + (th->doff << 2);
+ sg_set_buf(&sg[block++], data, data_len);
+ nbytes += data_len;
+ }
+
+ /* 4. an independently-specified key or password, known to both
+ * TCPs and presumably connection-specific
+ */
+ sg_set_buf(&sg[block++], key->key, key->keylen);
+ nbytes += key->keylen;
+
+ sg_mark_end(&sg[block - 1]);
+
+ /* Now store the hash into the packet */
+ err = crypto_hash_init(desc);
+ if (err) {
+ if (net_ratelimit())
+ printk(KERN_WARNING "%s(): hash_init failed\n", __func__);
+ return -1;
+ }
+ err = crypto_hash_update(desc, sg, nbytes);
+ if (err) {
+ if (net_ratelimit())
+ printk(KERN_WARNING "%s(): hash_update failed\n", __func__);
+ return -1;
+ }
+ err = crypto_hash_final(desc, md5_hash);
+ if (err) {
+ if (net_ratelimit())
+ printk(KERN_WARNING "%s(): hash_final failed\n", __func__);
+ return -1;
+ }
+
+ /* Reset header */
+ th->check = cksum;
+
+ return 0;
+}
+EXPORT_SYMBOL(tcp_calc_md5_hash);
+
static void __tcp_free_md5sig_pool(struct tcp_md5sig_pool **pool)
{
int cpu;
diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c
index 2fbcc7d1b1a0..838d491dfda7 100644
--- a/net/ipv4/tcp_diag.c
+++ b/net/ipv4/tcp_diag.c
@@ -1,8 +1,6 @@
/*
* tcp_diag.c Module for monitoring TCP transport protocols sockets.
*
- * Version: $Id: tcp_diag.c,v 1.3 2002/02/01 22:01:04 davem Exp $
- *
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
*
* This program is free software; you can redistribute it and/or
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index b54d9d37b636..bc7f62e2792b 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5,8 +5,6 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_input.c,v 1.243 2002/02/01 22:01:04 davem Exp $
- *
* Authors: Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Mark Evans, <evansmp@uhura.aston.ac.uk>
@@ -1392,9 +1390,9 @@ static struct sk_buff *tcp_maybe_skipping_dsack(struct sk_buff *skb,
if (before(next_dup->start_seq, skip_to_seq)) {
skb = tcp_sacktag_skip(skb, sk, next_dup->start_seq, fack_count);
- tcp_sacktag_walk(skb, sk, NULL,
- next_dup->start_seq, next_dup->end_seq,
- 1, fack_count, reord, flag);
+ skb = tcp_sacktag_walk(skb, sk, NULL,
+ next_dup->start_seq, next_dup->end_seq,
+ 1, fack_count, reord, flag);
}
return skb;
@@ -2483,6 +2481,20 @@ static inline void tcp_complete_cwr(struct sock *sk)
tcp_ca_event(sk, CA_EVENT_COMPLETE_CWR);
}
+static void tcp_try_keep_open(struct sock *sk)
+{
+ struct tcp_sock *tp = tcp_sk(sk);
+ int state = TCP_CA_Open;
+
+ if (tcp_left_out(tp) || tp->retrans_out || tp->undo_marker)
+ state = TCP_CA_Disorder;
+
+ if (inet_csk(sk)->icsk_ca_state != state) {
+ tcp_set_ca_state(sk, state);
+ tp->high_seq = tp->snd_nxt;
+ }
+}
+
static void tcp_try_to_open(struct sock *sk, int flag)
{
struct tcp_sock *tp = tcp_sk(sk);
@@ -2496,15 +2508,7 @@ static void tcp_try_to_open(struct sock *sk, int flag)
tcp_enter_cwr(sk, 1);
if (inet_csk(sk)->icsk_ca_state != TCP_CA_CWR) {
- int state = TCP_CA_Open;
-
- if (tcp_left_out(tp) || tp->retrans_out || tp->undo_marker)
- state = TCP_CA_Disorder;
-
- if (inet_csk(sk)->icsk_ca_state != state) {
- tcp_set_ca_state(sk, state);
- tp->high_seq = tp->snd_nxt;
- }
+ tcp_try_keep_open(sk);
tcp_moderate_cwnd(tp);
} else {
tcp_cwnd_down(sk, flag);
@@ -3310,8 +3314,11 @@ no_queue:
return 1;
old_ack:
- if (TCP_SKB_CB(skb)->sacked)
+ if (TCP_SKB_CB(skb)->sacked) {
tcp_sacktag_write_queue(sk, skb, prior_snd_una);
+ if (icsk->icsk_ca_state == TCP_CA_Open)
+ tcp_try_keep_open(sk);
+ }
uninteresting_ack:
SOCK_DEBUG(sk, "Ack %u out of %u:%u\n", ack, tp->snd_una, tp->snd_nxt);
@@ -3441,6 +3448,43 @@ static int tcp_fast_parse_options(struct sk_buff *skb, struct tcphdr *th,
return 1;
}
+#ifdef CONFIG_TCP_MD5SIG
+/*
+ * Parse MD5 Signature option
+ */
+u8 *tcp_parse_md5sig_option(struct tcphdr *th)
+{
+ int length = (th->doff << 2) - sizeof (*th);
+ u8 *ptr = (u8*)(th + 1);
+
+ /* If the TCP option is too short, we can short cut */
+ if (length < TCPOLEN_MD5SIG)
+ return NULL;
+
+ while (length > 0) {
+ int opcode = *ptr++;
+ int opsize;
+
+ switch(opcode) {
+ case TCPOPT_EOL:
+ return NULL;
+ case TCPOPT_NOP:
+ length--;
+ continue;
+ default:
+ opsize = *ptr++;
+ if (opsize < 2 || opsize > length)
+ return NULL;
+ if (opcode == TCPOPT_MD5SIG)
+ return ptr;
+ }
+ ptr += opsize - 2;
+ length -= opsize;
+ }
+ return NULL;
+}
+#endif
+
static inline void tcp_store_ts_recent(struct tcp_sock *tp)
{
tp->rx_opt.ts_recent = tp->rx_opt.rcv_tsval;
@@ -5458,6 +5502,9 @@ EXPORT_SYMBOL(sysctl_tcp_ecn);
EXPORT_SYMBOL(sysctl_tcp_reordering);
EXPORT_SYMBOL(sysctl_tcp_adv_win_scale);
EXPORT_SYMBOL(tcp_parse_options);
+#ifdef CONFIG_TCP_MD5SIG
+EXPORT_SYMBOL(tcp_parse_md5sig_option);
+#endif
EXPORT_SYMBOL(tcp_rcv_established);
EXPORT_SYMBOL(tcp_rcv_state_process);
EXPORT_SYMBOL(tcp_initialize_rcv_mss);
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index cd601a866c2f..0f9f3665da7e 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -5,8 +5,6 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_ipv4.c,v 1.240 2002/02/01 22:01:04 davem Exp $
- *
* IPv4 specific functions
*
*
@@ -95,8 +93,13 @@ static struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk,
__be32 addr);
static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
__be32 saddr, __be32 daddr,
- struct tcphdr *th, int protocol,
- unsigned int tcplen);
+ struct tcphdr *th, unsigned int tcplen);
+#else
+static inline
+struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr)
+{
+ return NULL;
+}
#endif
struct inet_hashinfo __cacheline_aligned tcp_hashinfo = {
@@ -586,8 +589,7 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb)
key,
ip_hdr(skb)->daddr,
ip_hdr(skb)->saddr,
- &rep.th, IPPROTO_TCP,
- arg.iov[0].iov_len);
+ &rep.th, arg.iov[0].iov_len);
}
#endif
arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr,
@@ -606,9 +608,9 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb)
outside socket context is ugly, certainly. What can I do?
*/
-static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk,
- struct sk_buff *skb, u32 seq, u32 ack,
- u32 win, u32 ts)
+static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack,
+ u32 win, u32 ts, int oif,
+ struct tcp_md5sig_key *key)
{
struct tcphdr *th = tcp_hdr(skb);
struct {
@@ -620,10 +622,6 @@ static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk,
];
} rep;
struct ip_reply_arg arg;
-#ifdef CONFIG_TCP_MD5SIG
- struct tcp_md5sig_key *key;
- struct tcp_md5sig_key tw_key;
-#endif
memset(&rep.th, 0, sizeof(struct tcphdr));
memset(&arg, 0, sizeof(arg));
@@ -649,23 +647,6 @@ static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk,
rep.th.window = htons(win);
#ifdef CONFIG_TCP_MD5SIG
- /*
- * The SKB holds an imcoming packet, but may not have a valid ->sk
- * pointer. This is especially the case when we're dealing with a
- * TIME_WAIT ack, because the sk structure is long gone, and only
- * the tcp_timewait_sock remains. So the md5 key is stashed in that
- * structure, and we use it in preference. I believe that (twsk ||
- * skb->sk) holds true, but we program defensively.
- */
- if (!twsk && skb->sk) {
- key = tcp_v4_md5_do_lookup(skb->sk, ip_hdr(skb)->daddr);
- } else if (twsk && twsk->tw_md5_keylen) {
- tw_key.key = twsk->tw_md5_key;
- tw_key.keylen = twsk->tw_md5_keylen;
- key = &tw_key;
- } else
- key = NULL;
-
if (key) {
int offset = (ts) ? 3 : 0;
@@ -680,16 +661,15 @@ static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk,
key,
ip_hdr(skb)->daddr,
ip_hdr(skb)->saddr,
- &rep.th, IPPROTO_TCP,
- arg.iov[0].iov_len);
+ &rep.th, arg.iov[0].iov_len);
}
#endif
arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr,
ip_hdr(skb)->saddr, /* XXX */
arg.iov[0].iov_len, IPPROTO_TCP, 0);
arg.csumoffset = offsetof(struct tcphdr, check) / 2;
- if (twsk)
- arg.bound_dev_if = twsk->tw_sk.tw_bound_dev_if;
+ if (oif)
+ arg.bound_dev_if = oif;
ip_send_reply(dev_net(skb->dev)->ipv4.tcp_sock, skb,
&arg, arg.iov[0].iov_len);
@@ -702,9 +682,12 @@ static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb)
struct inet_timewait_sock *tw = inet_twsk(sk);
struct tcp_timewait_sock *tcptw = tcp_twsk(sk);
- tcp_v4_send_ack(tcptw, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
+ tcp_v4_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
- tcptw->tw_ts_recent);
+ tcptw->tw_ts_recent,
+ tw->tw_bound_dev_if,
+ tcp_twsk_md5_key(tcptw)
+ );
inet_twsk_put(tw);
}
@@ -712,9 +695,11 @@ static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb)
static void tcp_v4_reqsk_send_ack(struct sk_buff *skb,
struct request_sock *req)
{
- tcp_v4_send_ack(NULL, skb, tcp_rsk(req)->snt_isn + 1,
+ tcp_v4_send_ack(skb, tcp_rsk(req)->snt_isn + 1,
tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd,
- req->ts_recent);
+ req->ts_recent,
+ 0,
+ tcp_v4_md5_do_lookup(skb->sk, ip_hdr(skb)->daddr));
}
/*
@@ -1006,18 +991,12 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, char __user *optval,
static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
__be32 saddr, __be32 daddr,
- struct tcphdr *th, int protocol,
+ struct tcphdr *th,
unsigned int tcplen)
{
- struct scatterlist sg[4];
- __u16 data_len;
- int block = 0;
- __sum16 old_checksum;
struct tcp_md5sig_pool *hp;
struct tcp4_pseudohdr *bp;
- struct hash_desc *desc;
int err;
- unsigned int nbytes = 0;
/*
* Okay, so RFC2385 is turned on for this connection,
@@ -1029,63 +1008,25 @@ static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
goto clear_hash_noput;
bp = &hp->md5_blk.ip4;
- desc = &hp->md5_desc;
/*
- * 1. the TCP pseudo-header (in the order: source IP address,
+ * The TCP pseudo-header (in the order: source IP address,
* destination IP address, zero-padded protocol number, and
* segment length)
*/
bp->saddr = saddr;
bp->daddr = daddr;
bp->pad = 0;
- bp->protocol = protocol;
+ bp->protocol = IPPROTO_TCP;
bp->len = htons(tcplen);
- sg_init_table(sg, 4);
-
- sg_set_buf(&sg[block++], bp, sizeof(*bp));
- nbytes += sizeof(*bp);
-
- /* 2. the TCP header, excluding options, and assuming a
- * checksum of zero/
- */
- old_checksum = th->check;
- th->check = 0;
- sg_set_buf(&sg[block++], th, sizeof(struct tcphdr));
- nbytes += sizeof(struct tcphdr);
-
- /* 3. the TCP segment data (if any) */
- data_len = tcplen - (th->doff << 2);
- if (data_len > 0) {
- unsigned char *data = (unsigned char *)th + (th->doff << 2);
- sg_set_buf(&sg[block++], data, data_len);
- nbytes += data_len;
- }
-
- /* 4. an independently-specified key or password, known to both
- * TCPs and presumably connection-specific
- */
- sg_set_buf(&sg[block++], key->key, key->keylen);
- nbytes += key->keylen;
-
- sg_mark_end(&sg[block - 1]);
-
- /* Now store the Hash into the packet */
- err = crypto_hash_init(desc);
- if (err)
- goto clear_hash;
- err = crypto_hash_update(desc, sg, nbytes);
- if (err)
- goto clear_hash;
- err = crypto_hash_final(desc, md5_hash);
+ err = tcp_calc_md5_hash(md5_hash, key, sizeof(*bp),
+ th, tcplen, hp);
if (err)
goto clear_hash;
- /* Reset header, and free up the crypto */
+ /* Free up the crypto pool */
tcp_put_md5sig_pool();
- th->check = old_checksum;
-
out:
return 0;
clear_hash:
@@ -1099,7 +1040,7 @@ int tcp_v4_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
struct sock *sk,
struct dst_entry *dst,
struct request_sock *req,
- struct tcphdr *th, int protocol,
+ struct tcphdr *th,
unsigned int tcplen)
{
__be32 saddr, daddr;
@@ -1115,7 +1056,7 @@ int tcp_v4_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
}
return tcp_v4_do_calc_md5_hash(md5_hash, key,
saddr, daddr,
- th, protocol, tcplen);
+ th, tcplen);
}
EXPORT_SYMBOL(tcp_v4_calc_md5_hash);
@@ -1134,52 +1075,12 @@ static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb)
struct tcp_md5sig_key *hash_expected;
const struct iphdr *iph = ip_hdr(skb);
struct tcphdr *th = tcp_hdr(skb);
- int length = (th->doff << 2) - sizeof(struct tcphdr);
int genhash;
- unsigned char *ptr;
unsigned char newhash[16];
hash_expected = tcp_v4_md5_do_lookup(sk, iph->saddr);
+ hash_location = tcp_parse_md5sig_option(th);
- /*
- * If the TCP option length is less than the TCP_MD5SIG
- * option length, then we can shortcut
- */
- if (length < TCPOLEN_MD5SIG) {
- if (hash_expected)
- return 1;
- else
- return 0;
- }
-
- /* Okay, we can't shortcut - we have to grub through the options */
- ptr = (unsigned char *)(th + 1);
- while (length > 0) {
- int opcode = *ptr++;
- int opsize;
-
- switch (opcode) {
- case TCPOPT_EOL:
- goto done_opts;
- case TCPOPT_NOP:
- length--;
- continue;
- default:
- opsize = *ptr++;
- if (opsize < 2)
- goto done_opts;
- if (opsize > length)
- goto done_opts;
-
- if (opcode == TCPOPT_MD5SIG) {
- hash_location = ptr;
- goto done_opts;
- }
- }
- ptr += opsize-2;
- length -= opsize;
- }
-done_opts:
/* We've parsed the options - do we have a hash? */
if (!hash_expected && !hash_location)
return 0;
@@ -1206,8 +1107,7 @@ done_opts:
genhash = tcp_v4_do_calc_md5_hash(newhash,
hash_expected,
iph->saddr, iph->daddr,
- th, sk->sk_protocol,
- skb->len);
+ th, skb->len);
if (genhash || memcmp(hash_location, newhash, 16) != 0) {
if (net_ratelimit()) {
@@ -1285,7 +1185,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
goto drop;
- req = reqsk_alloc(&tcp_request_sock_ops);
+ req = inet_reqsk_alloc(&tcp_request_sock_ops);
if (!req)
goto drop;
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 019c8c16e5cc..1276cab85e3e 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -5,8 +5,6 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_minisocks.c,v 1.15 2002/02/01 22:01:04 davem Exp $
- *
* Authors: Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Mark Evans, <evansmp@uhura.aston.ac.uk>
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index debf23581606..8f83ab432705 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -5,8 +5,6 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_output.c,v 1.146 2002/02/01 22:01:04 davem Exp $
- *
* Authors: Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Mark Evans, <evansmp@uhura.aston.ac.uk>
@@ -607,7 +605,6 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
md5,
sk, NULL, NULL,
tcp_hdr(skb),
- sk->sk_protocol,
skb->len);
}
#endif
@@ -1836,7 +1833,7 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
{
struct tcp_sock *tp = tcp_sk(sk);
struct inet_connection_sock *icsk = inet_csk(sk);
- unsigned int cur_mss = tcp_current_mss(sk, 0);
+ unsigned int cur_mss;
int err;
/* Inconslusive MTU probe */
@@ -1858,6 +1855,11 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
return -ENOMEM;
}
+ if (inet_csk(sk)->icsk_af_ops->rebuild_header(sk))
+ return -EHOSTUNREACH; /* Routing failure or similar. */
+
+ cur_mss = tcp_current_mss(sk, 0);
+
/* If receiver has shrunk his window, and skb is out of
* new window, do not retransmit it. The exception is the
* case, when window is shrunk to zero. In this case
@@ -1884,9 +1886,6 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
(sysctl_tcp_retrans_collapse != 0))
tcp_retrans_try_collapse(sk, skb, cur_mss);
- if (inet_csk(sk)->icsk_af_ops->rebuild_header(sk))
- return -EHOSTUNREACH; /* Routing failure or similar. */
-
/* Some Solaris stacks overoptimize and ignore the FIN on a
* retransmit when old data is attached. So strip it off
* since it is cheap to do so and saves bytes on the network.
@@ -2129,6 +2128,8 @@ void tcp_send_active_reset(struct sock *sk, gfp_t priority)
TCP_SKB_CB(skb)->when = tcp_time_stamp;
if (tcp_transmit_skb(sk, skb, 0, priority))
NET_INC_STATS(LINUX_MIB_TCPABORTFAILED);
+
+ TCP_INC_STATS(TCP_MIB_OUTRSTS);
}
/* WARNING: This routine must only be called when we have already sent
@@ -2262,7 +2263,7 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
tp->af_specific->calc_md5_hash(md5_hash_location,
md5,
NULL, dst, req,
- tcp_hdr(skb), sk->sk_protocol,
+ tcp_hdr(skb),
skb->len);
}
#endif
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index 4de68cf5f2aa..e77e7ae0bf2c 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -5,8 +5,6 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_timer.c,v 1.88 2002/02/01 22:01:04 davem Exp $
- *
* Authors: Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Mark Evans, <evansmp@uhura.aston.ac.uk>
diff --git a/net/ipv4/tunnel4.c b/net/ipv4/tunnel4.c
index d3b709a6f264..cb1f0e83830b 100644
--- a/net/ipv4/tunnel4.c
+++ b/net/ipv4/tunnel4.c
@@ -97,7 +97,7 @@ static int tunnel64_rcv(struct sk_buff *skb)
{
struct xfrm_tunnel *handler;
- if (!pskb_may_pull(skb, sizeof(struct iphdr)))
+ if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
goto drop;
for (handler = tunnel64_handlers; handler; handler = handler->next)
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index db1cb7c96d63..355e6d62d483 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -5,8 +5,6 @@
*
* The User Datagram Protocol (UDP).
*
- * Version: $Id: udp.c,v 1.102 2002/02/01 22:01:04 davem Exp $
- *
* Authors: Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Arnt Gulbrandsen, <agulbra@nvg.unit.no>
@@ -420,7 +418,7 @@ void udp_err(struct sk_buff *skb, u32 info)
/*
* Throw away all pending data and cancel the corking. Socket is locked.
*/
-static void udp_flush_pending_frames(struct sock *sk)
+void udp_flush_pending_frames(struct sock *sk)
{
struct udp_sock *up = udp_sk(sk);
@@ -430,6 +428,7 @@ static void udp_flush_pending_frames(struct sock *sk)
ip_flush_pending_frames(sk);
}
}
+EXPORT_SYMBOL(udp_flush_pending_frames);
/**
* udp4_hwcsum_outgoing - handle outgoing HW checksumming
diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c
index 72ce26b6c4d3..4ad16b6d5138 100644
--- a/net/ipv4/udplite.c
+++ b/net/ipv4/udplite.c
@@ -1,8 +1,6 @@
/*
* UDPLITE An implementation of the UDP-Lite protocol (RFC 3828).
*
- * Version: $Id: udplite.c,v 1.25 2006/10/19 07:22:36 gerrit Exp $
- *
* Authors: Gerrit Renker <gerrit@erg.abdn.ac.uk>
*
* Changes:
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index e591e09e5e4e..9be6be3a7ff3 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -6,8 +6,6 @@
* Pedro Roque <roque@di.fc.ul.pt>
* Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
*
- * $Id: addrconf.c,v 1.69 2001/10/31 21:55:54 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -231,6 +229,12 @@ static inline int addrconf_qdisc_ok(struct net_device *dev)
return (dev->qdisc != &noop_qdisc);
}
+/* Check if a route is valid prefix route */
+static inline int addrconf_is_prefix_route(const struct rt6_info *rt)
+{
+ return ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0);
+}
+
static void addrconf_del_timer(struct inet6_ifaddr *ifp)
{
if (del_timer(&ifp->timer))
@@ -731,8 +735,13 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
onlink = -1;
spin_lock(&ifa->lock);
- lifetime = min_t(unsigned long,
- ifa->valid_lft, 0x7fffffffUL/HZ);
+
+ lifetime = addrconf_timeout_fixup(ifa->valid_lft, HZ);
+ /*
+ * Note: Because this address is
+ * not permanent, lifetime <
+ * LONG_MAX / HZ here.
+ */
if (time_before(expires,
ifa->tstamp + lifetime * HZ))
expires = ifa->tstamp + lifetime * HZ;
@@ -772,7 +781,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
ipv6_addr_prefix(&prefix, &ifp->addr, ifp->prefix_len);
rt = rt6_lookup(net, &prefix, NULL, ifp->idev->dev->ifindex, 1);
- if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) {
+ if (rt && addrconf_is_prefix_route(rt)) {
if (onlink == 0) {
ip6_del_rt(rt);
rt = NULL;
@@ -953,7 +962,8 @@ static inline int ipv6_saddr_preferred(int type)
return 0;
}
-static int ipv6_get_saddr_eval(struct ipv6_saddr_score *score,
+static int ipv6_get_saddr_eval(struct net *net,
+ struct ipv6_saddr_score *score,
struct ipv6_saddr_dst *dst,
int i)
{
@@ -1032,7 +1042,8 @@ static int ipv6_get_saddr_eval(struct ipv6_saddr_score *score,
break;
case IPV6_SADDR_RULE_LABEL:
/* Rule 6: Prefer matching label */
- ret = ipv6_addr_label(&score->ifa->addr, score->addr_type,
+ ret = ipv6_addr_label(net,
+ &score->ifa->addr, score->addr_type,
score->ifa->idev->dev->ifindex) == dst->label;
break;
#ifdef CONFIG_IPV6_PRIVACY
@@ -1086,7 +1097,7 @@ int ipv6_dev_get_saddr(struct net_device *dst_dev,
dst.addr = daddr;
dst.ifindex = dst_dev ? dst_dev->ifindex : 0;
dst.scope = __ipv6_addr_src_scope(dst_type);
- dst.label = ipv6_addr_label(daddr, dst_type, dst.ifindex);
+ dst.label = ipv6_addr_label(net, daddr, dst_type, dst.ifindex);
dst.prefs = prefs;
hiscore->rule = -1;
@@ -1154,8 +1165,8 @@ int ipv6_dev_get_saddr(struct net_device *dst_dev,
for (i = 0; i < IPV6_SADDR_RULE_MAX; i++) {
int minihiscore, miniscore;
- minihiscore = ipv6_get_saddr_eval(hiscore, &dst, i);
- miniscore = ipv6_get_saddr_eval(score, &dst, i);
+ minihiscore = ipv6_get_saddr_eval(net, hiscore, &dst, i);
+ miniscore = ipv6_get_saddr_eval(net, score, &dst, i);
if (minihiscore > miniscore) {
if (i == IPV6_SADDR_RULE_SCOPE &&
@@ -1722,7 +1733,6 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
__u32 valid_lft;
__u32 prefered_lft;
int addr_type;
- unsigned long rt_expires;
struct inet6_dev *in6_dev;
pinfo = (struct prefix_info *) opt;
@@ -1764,41 +1774,49 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
* 2) Configure prefixes with the auto flag set
*/
- /* Avoid arithmetic overflow. Really, we could
- save rt_expires in seconds, likely valid_lft,
- but it would require division in fib gc, that it
- not good.
- */
- if (valid_lft >= 0x7FFFFFFF/HZ)
- rt_expires = 0x7FFFFFFF - (0x7FFFFFFF % HZ);
- else
- rt_expires = valid_lft * HZ;
-
- /*
- * We convert this (in jiffies) to clock_t later.
- * Avoid arithmetic overflow there as well.
- * Overflow can happen only if HZ < USER_HZ.
- */
- if (HZ < USER_HZ && rt_expires > 0x7FFFFFFF / USER_HZ)
- rt_expires = 0x7FFFFFFF / USER_HZ;
-
if (pinfo->onlink) {
struct rt6_info *rt;
+ unsigned long rt_expires;
+
+ /* Avoid arithmetic overflow. Really, we could
+ * save rt_expires in seconds, likely valid_lft,
+ * but it would require division in fib gc, that it
+ * not good.
+ */
+ if (HZ > USER_HZ)
+ rt_expires = addrconf_timeout_fixup(valid_lft, HZ);
+ else
+ rt_expires = addrconf_timeout_fixup(valid_lft, USER_HZ);
+
+ if (addrconf_finite_timeout(rt_expires))
+ rt_expires *= HZ;
+
rt = rt6_lookup(dev_net(dev), &pinfo->prefix, NULL,
dev->ifindex, 1);
- if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) {
- if (rt->rt6i_flags&RTF_EXPIRES) {
- if (valid_lft == 0) {
- ip6_del_rt(rt);
- rt = NULL;
- } else {
- rt->rt6i_expires = jiffies + rt_expires;
- }
+ if (rt && addrconf_is_prefix_route(rt)) {
+ /* Autoconf prefix route */
+ if (valid_lft == 0) {
+ ip6_del_rt(rt);
+ rt = NULL;
+ } else if (addrconf_finite_timeout(rt_expires)) {
+ /* not infinity */
+ rt->rt6i_expires = jiffies + rt_expires;
+ rt->rt6i_flags |= RTF_EXPIRES;
+ } else {
+ rt->rt6i_flags &= ~RTF_EXPIRES;
+ rt->rt6i_expires = 0;
}
} else if (valid_lft) {
+ clock_t expires = 0;
+ int flags = RTF_ADDRCONF | RTF_PREFIX_RT;
+ if (addrconf_finite_timeout(rt_expires)) {
+ /* not infinity */
+ flags |= RTF_EXPIRES;
+ expires = jiffies_to_clock_t(rt_expires);
+ }
addrconf_prefix_route(&pinfo->prefix, pinfo->prefix_len,
- dev, jiffies_to_clock_t(rt_expires), RTF_ADDRCONF|RTF_EXPIRES|RTF_PREFIX_RT);
+ dev, expires, flags);
}
if (rt)
dst_release(&rt->u.dst);
@@ -2014,17 +2032,22 @@ err_exit:
* Manual configuration of address on an interface
*/
static int inet6_addr_add(struct net *net, int ifindex, struct in6_addr *pfx,
- int plen, __u8 ifa_flags, __u32 prefered_lft,
+ unsigned int plen, __u8 ifa_flags, __u32 prefered_lft,
__u32 valid_lft)
{
struct inet6_ifaddr *ifp;
struct inet6_dev *idev;
struct net_device *dev;
int scope;
- u32 flags = RTF_EXPIRES;
+ u32 flags;
+ clock_t expires;
+ unsigned long timeout;
ASSERT_RTNL();
+ if (plen > 128)
+ return -EINVAL;
+
/* check the lifetime */
if (!valid_lft || prefered_lft > valid_lft)
return -EINVAL;
@@ -2038,17 +2061,23 @@ static int inet6_addr_add(struct net *net, int ifindex, struct in6_addr *pfx,
scope = ipv6_addr_scope(pfx);
- if (valid_lft == INFINITY_LIFE_TIME) {
- ifa_flags |= IFA_F_PERMANENT;
+ timeout = addrconf_timeout_fixup(valid_lft, HZ);
+ if (addrconf_finite_timeout(timeout)) {
+ expires = jiffies_to_clock_t(timeout * HZ);
+ valid_lft = timeout;
+ flags = RTF_EXPIRES;
+ } else {
+ expires = 0;
flags = 0;
- } else if (valid_lft >= 0x7FFFFFFF/HZ)
- valid_lft = 0x7FFFFFFF/HZ;
+ ifa_flags |= IFA_F_PERMANENT;
+ }
- if (prefered_lft == 0)
- ifa_flags |= IFA_F_DEPRECATED;
- else if ((prefered_lft >= 0x7FFFFFFF/HZ) &&
- (prefered_lft != INFINITY_LIFE_TIME))
- prefered_lft = 0x7FFFFFFF/HZ;
+ timeout = addrconf_timeout_fixup(prefered_lft, HZ);
+ if (addrconf_finite_timeout(timeout)) {
+ if (timeout == 0)
+ ifa_flags |= IFA_F_DEPRECATED;
+ prefered_lft = timeout;
+ }
ifp = ipv6_add_addr(idev, pfx, plen, scope, ifa_flags);
@@ -2060,7 +2089,7 @@ static int inet6_addr_add(struct net *net, int ifindex, struct in6_addr *pfx,
spin_unlock_bh(&ifp->lock);
addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev,
- jiffies_to_clock_t(valid_lft * HZ), flags);
+ expires, flags);
/*
* Note that section 3.1 of RFC 4429 indicates
* that the Optimistic flag should not be set for
@@ -2076,12 +2105,15 @@ static int inet6_addr_add(struct net *net, int ifindex, struct in6_addr *pfx,
}
static int inet6_addr_del(struct net *net, int ifindex, struct in6_addr *pfx,
- int plen)
+ unsigned int plen)
{
struct inet6_ifaddr *ifp;
struct inet6_dev *idev;
struct net_device *dev;
+ if (plen > 128)
+ return -EINVAL;
+
dev = __dev_get_by_index(net, ifindex);
if (!dev)
return -ENODEV;
@@ -3148,22 +3180,30 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags,
u32 prefered_lft, u32 valid_lft)
{
- u32 flags = RTF_EXPIRES;
+ u32 flags;
+ clock_t expires;
+ unsigned long timeout;
if (!valid_lft || (prefered_lft > valid_lft))
return -EINVAL;
- if (valid_lft == INFINITY_LIFE_TIME) {
- ifa_flags |= IFA_F_PERMANENT;
+ timeout = addrconf_timeout_fixup(valid_lft, HZ);
+ if (addrconf_finite_timeout(timeout)) {
+ expires = jiffies_to_clock_t(timeout * HZ);
+ valid_lft = timeout;
+ flags = RTF_EXPIRES;
+ } else {
+ expires = 0;
flags = 0;
- } else if (valid_lft >= 0x7FFFFFFF/HZ)
- valid_lft = 0x7FFFFFFF/HZ;
+ ifa_flags |= IFA_F_PERMANENT;
+ }
- if (prefered_lft == 0)
- ifa_flags |= IFA_F_DEPRECATED;
- else if ((prefered_lft >= 0x7FFFFFFF/HZ) &&
- (prefered_lft != INFINITY_LIFE_TIME))
- prefered_lft = 0x7FFFFFFF/HZ;
+ timeout = addrconf_timeout_fixup(prefered_lft, HZ);
+ if (addrconf_finite_timeout(timeout)) {
+ if (timeout == 0)
+ ifa_flags |= IFA_F_DEPRECATED;
+ prefered_lft = timeout;
+ }
spin_lock_bh(&ifp->lock);
ifp->flags = (ifp->flags & ~(IFA_F_DEPRECATED | IFA_F_PERMANENT | IFA_F_NODAD | IFA_F_HOMEADDRESS)) | ifa_flags;
@@ -3176,7 +3216,7 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags,
ipv6_ifa_notify(0, ifp);
addrconf_prefix_route(&ifp->addr, ifp->prefix_len, ifp->idev->dev,
- jiffies_to_clock_t(valid_lft * HZ), flags);
+ expires, flags);
addrconf_verify(0);
return 0;
@@ -4242,7 +4282,7 @@ static void addrconf_sysctl_register(struct inet6_dev *idev)
neigh_sysctl_register(idev->dev, idev->nd_parms, NET_IPV6,
NET_IPV6_NEIGH, "ipv6",
&ndisc_ifinfo_sysctl_change,
- NULL);
+ ndisc_ifinfo_sysctl_strategy);
__addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name,
idev->dev->ifindex, idev, &idev->cnf);
}
diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c
index 9bfa8846f262..08909039d87b 100644
--- a/net/ipv6/addrlabel.c
+++ b/net/ipv6/addrlabel.c
@@ -29,6 +29,9 @@
*/
struct ip6addrlbl_entry
{
+#ifdef CONFIG_NET_NS
+ struct net *lbl_net;
+#endif
struct in6_addr prefix;
int prefixlen;
int ifindex;
@@ -46,6 +49,16 @@ static struct ip6addrlbl_table
u32 seq;
} ip6addrlbl_table;
+static inline
+struct net *ip6addrlbl_net(const struct ip6addrlbl_entry *lbl)
+{
+#ifdef CONFIG_NET_NS
+ return lbl->lbl_net;
+#else
+ return &init_net;
+#endif
+}
+
/*
* Default policy table (RFC3484 + extensions)
*
@@ -65,7 +78,7 @@ static struct ip6addrlbl_table
#define IPV6_ADDR_LABEL_DEFAULT 0xffffffffUL
-static const __initdata struct ip6addrlbl_init_table
+static const __net_initdata struct ip6addrlbl_init_table
{
const struct in6_addr *prefix;
int prefixlen;
@@ -108,6 +121,9 @@ static const __initdata struct ip6addrlbl_init_table
/* Object management */
static inline void ip6addrlbl_free(struct ip6addrlbl_entry *p)
{
+#ifdef CONFIG_NET_NS
+ release_net(p->lbl_net);
+#endif
kfree(p);
}
@@ -128,10 +144,13 @@ static inline void ip6addrlbl_put(struct ip6addrlbl_entry *p)
}
/* Find label */
-static int __ip6addrlbl_match(struct ip6addrlbl_entry *p,
+static int __ip6addrlbl_match(struct net *net,
+ struct ip6addrlbl_entry *p,
const struct in6_addr *addr,
int addrtype, int ifindex)
{
+ if (!net_eq(ip6addrlbl_net(p), net))
+ return 0;
if (p->ifindex && p->ifindex != ifindex)
return 0;
if (p->addrtype && p->addrtype != addrtype)
@@ -141,19 +160,21 @@ static int __ip6addrlbl_match(struct ip6addrlbl_entry *p,
return 1;
}
-static struct ip6addrlbl_entry *__ipv6_addr_label(const struct in6_addr *addr,
+static struct ip6addrlbl_entry *__ipv6_addr_label(struct net *net,
+ const struct in6_addr *addr,
int type, int ifindex)
{
struct hlist_node *pos;
struct ip6addrlbl_entry *p;
hlist_for_each_entry_rcu(p, pos, &ip6addrlbl_table.head, list) {
- if (__ip6addrlbl_match(p, addr, type, ifindex))
+ if (__ip6addrlbl_match(net, p, addr, type, ifindex))
return p;
}
return NULL;
}
-u32 ipv6_addr_label(const struct in6_addr *addr, int type, int ifindex)
+u32 ipv6_addr_label(struct net *net,
+ const struct in6_addr *addr, int type, int ifindex)
{
u32 label;
struct ip6addrlbl_entry *p;
@@ -161,7 +182,7 @@ u32 ipv6_addr_label(const struct in6_addr *addr, int type, int ifindex)
type &= IPV6_ADDR_MAPPED | IPV6_ADDR_COMPATv4 | IPV6_ADDR_LOOPBACK;
rcu_read_lock();
- p = __ipv6_addr_label(addr, type, ifindex);
+ p = __ipv6_addr_label(net, addr, type, ifindex);
label = p ? p->label : IPV6_ADDR_LABEL_DEFAULT;
rcu_read_unlock();
@@ -174,7 +195,8 @@ u32 ipv6_addr_label(const struct in6_addr *addr, int type, int ifindex)
}
/* allocate one entry */
-static struct ip6addrlbl_entry *ip6addrlbl_alloc(const struct in6_addr *prefix,
+static struct ip6addrlbl_entry *ip6addrlbl_alloc(struct net *net,
+ const struct in6_addr *prefix,
int prefixlen, int ifindex,
u32 label)
{
@@ -216,6 +238,9 @@ static struct ip6addrlbl_entry *ip6addrlbl_alloc(const struct in6_addr *prefix,
newp->addrtype = addrtype;
newp->label = label;
INIT_HLIST_NODE(&newp->list);
+#ifdef CONFIG_NET_NS
+ newp->lbl_net = hold_net(net);
+#endif
atomic_set(&newp->refcnt, 1);
return newp;
}
@@ -237,6 +262,7 @@ static int __ip6addrlbl_add(struct ip6addrlbl_entry *newp, int replace)
hlist_for_each_entry_safe(p, pos, n,
&ip6addrlbl_table.head, list) {
if (p->prefixlen == newp->prefixlen &&
+ net_eq(ip6addrlbl_net(p), ip6addrlbl_net(newp)) &&
p->ifindex == newp->ifindex &&
ipv6_addr_equal(&p->prefix, &newp->prefix)) {
if (!replace) {
@@ -261,7 +287,8 @@ out:
}
/* add a label */
-static int ip6addrlbl_add(const struct in6_addr *prefix, int prefixlen,
+static int ip6addrlbl_add(struct net *net,
+ const struct in6_addr *prefix, int prefixlen,
int ifindex, u32 label, int replace)
{
struct ip6addrlbl_entry *newp;
@@ -274,7 +301,7 @@ static int ip6addrlbl_add(const struct in6_addr *prefix, int prefixlen,
(unsigned int)label,
replace);
- newp = ip6addrlbl_alloc(prefix, prefixlen, ifindex, label);
+ newp = ip6addrlbl_alloc(net, prefix, prefixlen, ifindex, label);
if (IS_ERR(newp))
return PTR_ERR(newp);
spin_lock(&ip6addrlbl_table.lock);
@@ -286,7 +313,8 @@ static int ip6addrlbl_add(const struct in6_addr *prefix, int prefixlen,
}
/* remove a label */
-static int __ip6addrlbl_del(const struct in6_addr *prefix, int prefixlen,
+static int __ip6addrlbl_del(struct net *net,
+ const struct in6_addr *prefix, int prefixlen,
int ifindex)
{
struct ip6addrlbl_entry *p = NULL;
@@ -300,6 +328,7 @@ static int __ip6addrlbl_del(const struct in6_addr *prefix, int prefixlen,
hlist_for_each_entry_safe(p, pos, n, &ip6addrlbl_table.head, list) {
if (p->prefixlen == prefixlen &&
+ net_eq(ip6addrlbl_net(p), net) &&
p->ifindex == ifindex &&
ipv6_addr_equal(&p->prefix, prefix)) {
hlist_del_rcu(&p->list);
@@ -311,7 +340,8 @@ static int __ip6addrlbl_del(const struct in6_addr *prefix, int prefixlen,
return ret;
}
-static int ip6addrlbl_del(const struct in6_addr *prefix, int prefixlen,
+static int ip6addrlbl_del(struct net *net,
+ const struct in6_addr *prefix, int prefixlen,
int ifindex)
{
struct in6_addr prefix_buf;
@@ -324,13 +354,13 @@ static int ip6addrlbl_del(const struct in6_addr *prefix, int prefixlen,
ipv6_addr_prefix(&prefix_buf, prefix, prefixlen);
spin_lock(&ip6addrlbl_table.lock);
- ret = __ip6addrlbl_del(&prefix_buf, prefixlen, ifindex);
+ ret = __ip6addrlbl_del(net, &prefix_buf, prefixlen, ifindex);
spin_unlock(&ip6addrlbl_table.lock);
return ret;
}
/* add default label */
-static __init int ip6addrlbl_init(void)
+static int __net_init ip6addrlbl_net_init(struct net *net)
{
int err = 0;
int i;
@@ -338,7 +368,8 @@ static __init int ip6addrlbl_init(void)
ADDRLABEL(KERN_DEBUG "%s()\n", __func__);
for (i = 0; i < ARRAY_SIZE(ip6addrlbl_init_table); i++) {
- int ret = ip6addrlbl_add(ip6addrlbl_init_table[i].prefix,
+ int ret = ip6addrlbl_add(net,
+ ip6addrlbl_init_table[i].prefix,
ip6addrlbl_init_table[i].prefixlen,
0,
ip6addrlbl_init_table[i].label, 0);
@@ -349,11 +380,32 @@ static __init int ip6addrlbl_init(void)
return err;
}
+static void __net_exit ip6addrlbl_net_exit(struct net *net)
+{
+ struct ip6addrlbl_entry *p = NULL;
+ struct hlist_node *pos, *n;
+
+ /* Remove all labels belonging to the exiting net */
+ spin_lock(&ip6addrlbl_table.lock);
+ hlist_for_each_entry_safe(p, pos, n, &ip6addrlbl_table.head, list) {
+ if (net_eq(ip6addrlbl_net(p), net)) {
+ hlist_del_rcu(&p->list);
+ ip6addrlbl_put(p);
+ }
+ }
+ spin_unlock(&ip6addrlbl_table.lock);
+}
+
+static struct pernet_operations ipv6_addr_label_ops = {
+ .init = ip6addrlbl_net_init,
+ .exit = ip6addrlbl_net_exit,
+};
+
int __init ipv6_addr_label_init(void)
{
spin_lock_init(&ip6addrlbl_table.lock);
- return ip6addrlbl_init();
+ return register_pernet_subsys(&ipv6_addr_label_ops);
}
static const struct nla_policy ifal_policy[IFAL_MAX+1] = {
@@ -371,9 +423,6 @@ static int ip6addrlbl_newdel(struct sk_buff *skb, struct nlmsghdr *nlh,
u32 label;
int err = 0;
- if (net != &init_net)
- return 0;
-
err = nlmsg_parse(nlh, sizeof(*ifal), tb, IFAL_MAX, ifal_policy);
if (err < 0)
return err;
@@ -385,7 +434,7 @@ static int ip6addrlbl_newdel(struct sk_buff *skb, struct nlmsghdr *nlh,
return -EINVAL;
if (ifal->ifal_index &&
- !__dev_get_by_index(&init_net, ifal->ifal_index))
+ !__dev_get_by_index(net, ifal->ifal_index))
return -EINVAL;
if (!tb[IFAL_ADDRESS])
@@ -403,12 +452,12 @@ static int ip6addrlbl_newdel(struct sk_buff *skb, struct nlmsghdr *nlh,
switch(nlh->nlmsg_type) {
case RTM_NEWADDRLABEL:
- err = ip6addrlbl_add(pfx, ifal->ifal_prefixlen,
+ err = ip6addrlbl_add(net, pfx, ifal->ifal_prefixlen,
ifal->ifal_index, label,
nlh->nlmsg_flags & NLM_F_REPLACE);
break;
case RTM_DELADDRLABEL:
- err = ip6addrlbl_del(pfx, ifal->ifal_prefixlen,
+ err = ip6addrlbl_del(net, pfx, ifal->ifal_prefixlen,
ifal->ifal_index);
break;
default:
@@ -458,12 +507,10 @@ static int ip6addrlbl_dump(struct sk_buff *skb, struct netlink_callback *cb)
int idx = 0, s_idx = cb->args[0];
int err;
- if (net != &init_net)
- return 0;
-
rcu_read_lock();
hlist_for_each_entry_rcu(p, pos, &ip6addrlbl_table.head, list) {
- if (idx >= s_idx) {
+ if (idx >= s_idx &&
+ net_eq(ip6addrlbl_net(p), net)) {
if ((err = ip6addrlbl_fill(skb, p,
ip6addrlbl_table.seq,
NETLINK_CB(cb->skb).pid,
@@ -499,9 +546,6 @@ static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh,
struct ip6addrlbl_entry *p;
struct sk_buff *skb;
- if (net != &init_net)
- return 0;
-
err = nlmsg_parse(nlh, sizeof(*ifal), tb, IFAL_MAX, ifal_policy);
if (err < 0)
return err;
@@ -513,7 +557,7 @@ static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh,
return -EINVAL;
if (ifal->ifal_index &&
- !__dev_get_by_index(&init_net, ifal->ifal_index))
+ !__dev_get_by_index(net, ifal->ifal_index))
return -EINVAL;
if (!tb[IFAL_ADDRESS])
@@ -524,7 +568,7 @@ static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh,
return -EINVAL;
rcu_read_lock();
- p = __ipv6_addr_label(addr, ipv6_addr_type(addr), ifal->ifal_index);
+ p = __ipv6_addr_label(net, addr, ipv6_addr_type(addr), ifal->ifal_index);
if (p && ip6addrlbl_hold(p))
p = NULL;
lseq = ip6addrlbl_table.seq;
@@ -552,7 +596,7 @@ static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh,
goto out;
}
- err = rtnl_unicast(skb, &init_net, NETLINK_CB(in_skb).pid);
+ err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).pid);
out:
return err;
}
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 3c6aafb02183..350457c761e6 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -7,8 +7,6 @@
*
* Adapted from linux/net/ipv4/af_inet.c
*
- * $Id: af_inet6.c,v 1.66 2002/02/01 22:01:04 davem Exp $
- *
* Fixes:
* piggy, Karl Knutson : Socket protocol table
* Hideaki YOSHIFUJI : sin6_scope_id support
@@ -191,7 +189,7 @@ lookup_protocol:
np->mcast_hops = -1;
np->mc_loop = 1;
np->pmtudisc = IPV6_PMTUDISC_WANT;
- np->ipv6only = init_net.ipv6.sysctl.bindv6only;
+ np->ipv6only = net->ipv6.sysctl.bindv6only;
/* Init the ipv4 part of the socket since we can have sockets
* using v6 API for ipv4.
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index 94fa6ae77cfe..f7b535dec860 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -5,8 +5,6 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: datagram.c,v 1.24 2002/02/01 22:01:04 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -496,7 +494,8 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
return 0;
}
-int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
+int datagram_send_ctl(struct net *net,
+ struct msghdr *msg, struct flowi *fl,
struct ipv6_txoptions *opt,
int *hlimit, int *tclass)
{
@@ -509,7 +508,6 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
int addr_type;
- struct net_device *dev = NULL;
if (!CMSG_OK(msg, cmsg)) {
err = -EINVAL;
@@ -522,6 +520,9 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
switch (cmsg->cmsg_type) {
case IPV6_PKTINFO:
case IPV6_2292PKTINFO:
+ {
+ struct net_device *dev = NULL;
+
if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct in6_pktinfo))) {
err = -EINVAL;
goto exit_f;
@@ -535,32 +536,32 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
fl->oif = src_info->ipi6_ifindex;
}
- addr_type = ipv6_addr_type(&src_info->ipi6_addr);
+ addr_type = __ipv6_addr_type(&src_info->ipi6_addr);
- if (addr_type == IPV6_ADDR_ANY)
- break;
+ if (fl->oif) {
+ dev = dev_get_by_index(net, fl->oif);
+ if (!dev)
+ return -ENODEV;
+ } else if (addr_type & IPV6_ADDR_LINKLOCAL)
+ return -EINVAL;
- if (addr_type & IPV6_ADDR_LINKLOCAL) {
- if (!src_info->ipi6_ifindex)
- return -EINVAL;
- else {
- dev = dev_get_by_index(&init_net, src_info->ipi6_ifindex);
- if (!dev)
- return -ENODEV;
- }
- }
- if (!ipv6_chk_addr(&init_net, &src_info->ipi6_addr,
- dev, 0)) {
- if (dev)
- dev_put(dev);
- err = -EINVAL;
- goto exit_f;
+ if (addr_type != IPV6_ADDR_ANY) {
+ int strict = __ipv6_addr_src_scope(addr_type) <= IPV6_ADDR_SCOPE_LINKLOCAL;
+ if (!ipv6_chk_addr(net, &src_info->ipi6_addr,
+ strict ? dev : NULL, 0))
+ err = -EINVAL;
+ else
+ ipv6_addr_copy(&fl->fl6_src, &src_info->ipi6_addr);
}
+
if (dev)
dev_put(dev);
- ipv6_addr_copy(&fl->fl6_src, &src_info->ipi6_addr);
+ if (err)
+ goto exit_f;
+
break;
+ }
case IPV6_FLOWINFO:
if (cmsg->cmsg_len < CMSG_LEN(4)) {
@@ -702,6 +703,11 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
}
*hlimit = *(int *)CMSG_DATA(cmsg);
+ if (*hlimit < -1 || *hlimit > 0xff) {
+ err = -EINVAL;
+ goto exit_f;
+ }
+
break;
case IPV6_TCLASS:
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 3cd1c993d52b..602ea826f0a5 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -7,8 +7,6 @@
* Andi Kleen <ak@muc.de>
* Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
*
- * $Id: exthdrs.c,v 1.13 2001/06/19 15:58:56 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index d42dd16d3487..399d41f65437 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -5,8 +5,6 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: icmp.c,v 1.38 2002/02/08 03:57:19 davem Exp $
- *
* Based on net/ipv4/icmp.c
*
* RFC 1885
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 1ee4fa17c129..4de2b9efcacb 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -5,8 +5,6 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: ip6_fib.c,v 1.25 2001/10/31 21:55:55 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
index eb7a940310f4..37a4e777e347 100644
--- a/net/ipv6/ip6_flowlabel.c
+++ b/net/ipv6/ip6_flowlabel.c
@@ -354,7 +354,7 @@ fl_create(struct net *net, struct in6_flowlabel_req *freq, char __user *optval,
msg.msg_control = (void*)(fl->opt+1);
flowi.oif = 0;
- err = datagram_send_ctl(&msg, &flowi, fl->opt, &junk, &junk);
+ err = datagram_send_ctl(net, &msg, &flowi, fl->opt, &junk, &junk);
if (err)
goto done;
err = -EINVAL;
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index 4e5c8615832c..f77a6011c302 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -6,8 +6,6 @@
* Pedro Roque <roque@di.fc.ul.pt>
* Ian P. Morris <I.P.Morris@soton.ac.uk>
*
- * $Id: ip6_input.c,v 1.19 2000/12/13 18:31:50 davem Exp $
- *
* Based in linux/net/ipv4/ip_input.c
*
* This program is free software; you can redistribute it and/or
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 48cdce9c696c..40a2813a63d1 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -5,8 +5,6 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: ip6_output.c,v 1.34 2002/02/01 22:01:04 davem Exp $
- *
* Based on linux/net/ipv4/ip_output.c
*
* This program is free software; you can redistribute it and/or
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 2bda3ba100b1..17c7b098cdb0 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -6,8 +6,6 @@
* Ville Nuorvala <vnuorval@tcs.hut.fi>
* Yasuyuki Kozakai <kozakai@linux-ipv6.org>
*
- * $Id$
- *
* Based on:
* linux/net/ipv6/sit.c and linux/net/ipv4/ipip.c
*
@@ -711,7 +709,7 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
}
if (!ip6_tnl_rcv_ctl(t)) {
- t->stat.rx_dropped++;
+ t->dev->stats.rx_dropped++;
read_unlock(&ip6_tnl_lock);
goto discard;
}
@@ -728,8 +726,8 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
dscp_ecn_decapsulate(t, ipv6h, skb);
- t->stat.rx_packets++;
- t->stat.rx_bytes += skb->len;
+ t->dev->stats.rx_packets++;
+ t->dev->stats.rx_bytes += skb->len;
netif_rx(skb);
read_unlock(&ip6_tnl_lock);
return 0;
@@ -849,7 +847,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
__u32 *pmtu)
{
struct ip6_tnl *t = netdev_priv(dev);
- struct net_device_stats *stats = &t->stat;
+ struct net_device_stats *stats = &t->dev->stats;
struct ipv6hdr *ipv6h = ipv6_hdr(skb);
struct ipv6_tel_txoption opt;
struct dst_entry *dst;
@@ -1043,11 +1041,11 @@ static int
ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ip6_tnl *t = netdev_priv(dev);
- struct net_device_stats *stats = &t->stat;
+ struct net_device_stats *stats = &t->dev->stats;
int ret;
if (t->recursion++) {
- t->stat.collisions++;
+ stats->collisions++;
goto tx_err;
}
@@ -1289,19 +1287,6 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
}
/**
- * ip6_tnl_get_stats - return the stats for tunnel device
- * @dev: virtual device associated with tunnel
- *
- * Return: stats for device
- **/
-
-static struct net_device_stats *
-ip6_tnl_get_stats(struct net_device *dev)
-{
- return &(((struct ip6_tnl *)netdev_priv(dev))->stat);
-}
-
-/**
* ip6_tnl_change_mtu - change mtu manually for tunnel device
* @dev: virtual device associated with tunnel
* @new_mtu: the new mtu
@@ -1334,7 +1319,6 @@ static void ip6_tnl_dev_setup(struct net_device *dev)
dev->uninit = ip6_tnl_dev_uninit;
dev->destructor = free_netdev;
dev->hard_start_xmit = ip6_tnl_xmit;
- dev->get_stats = ip6_tnl_get_stats;
dev->do_ioctl = ip6_tnl_ioctl;
dev->change_mtu = ip6_tnl_change_mtu;
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 2de3c464fe75..90e763073dc5 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -197,7 +197,7 @@ static int ip6mr_vif_seq_show(struct seq_file *seq, void *v)
const char *name = vif->dev ? vif->dev->name : "none";
seq_printf(seq,
- "%2Zd %-10s %8ld %7ld %8ld %7ld %05X\n",
+ "%2td %-10s %8ld %7ld %8ld %7ld %05X\n",
vif - vif6_table,
name, vif->bytes_in, vif->pkt_in,
vif->bytes_out, vif->pkt_out,
@@ -388,8 +388,8 @@ static int pim6_rcv(struct sk_buff *skb)
skb->ip_summed = 0;
skb->pkt_type = PACKET_HOST;
dst_release(skb->dst);
- ((struct net_device_stats *)netdev_priv(reg_dev))->rx_bytes += skb->len;
- ((struct net_device_stats *)netdev_priv(reg_dev))->rx_packets++;
+ reg_dev->stats.rx_bytes += skb->len;
+ reg_dev->stats.rx_packets++;
skb->dst = NULL;
nf_reset(skb);
netif_rx(skb);
@@ -409,26 +409,20 @@ static struct inet6_protocol pim6_protocol = {
static int reg_vif_xmit(struct sk_buff *skb, struct net_device *dev)
{
read_lock(&mrt_lock);
- ((struct net_device_stats *)netdev_priv(dev))->tx_bytes += skb->len;
- ((struct net_device_stats *)netdev_priv(dev))->tx_packets++;
+ dev->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
ip6mr_cache_report(skb, reg_vif_num, MRT6MSG_WHOLEPKT);
read_unlock(&mrt_lock);
kfree_skb(skb);
return 0;
}
-static struct net_device_stats *reg_vif_get_stats(struct net_device *dev)
-{
- return (struct net_device_stats *)netdev_priv(dev);
-}
-
static void reg_vif_setup(struct net_device *dev)
{
dev->type = ARPHRD_PIMREG;
dev->mtu = 1500 - sizeof(struct ipv6hdr) - 8;
dev->flags = IFF_NOARP;
dev->hard_start_xmit = reg_vif_xmit;
- dev->get_stats = reg_vif_get_stats;
dev->destructor = free_netdev;
}
@@ -436,9 +430,7 @@ static struct net_device *ip6mr_reg_vif(void)
{
struct net_device *dev;
- dev = alloc_netdev(sizeof(struct net_device_stats), "pim6reg",
- reg_vif_setup);
-
+ dev = alloc_netdev(0, "pim6reg", reg_vif_setup);
if (dev == NULL)
return NULL;
@@ -1248,7 +1240,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int
#endif
/*
- * Spurious command, or MRT_VERSION which you cannot
+ * Spurious command, or MRT6_VERSION which you cannot
* set.
*/
default:
@@ -1377,8 +1369,8 @@ static int ip6mr_forward2(struct sk_buff *skb, struct mfc6_cache *c, int vifi)
if (vif->flags & MIFF_REGISTER) {
vif->pkt_out++;
vif->bytes_out += skb->len;
- ((struct net_device_stats *)netdev_priv(vif->dev))->tx_bytes += skb->len;
- ((struct net_device_stats *)netdev_priv(vif->dev))->tx_packets++;
+ vif->dev->stats.tx_bytes += skb->len;
+ vif->dev->stats.tx_packets++;
ip6mr_cache_report(skb, vifi, MRT6MSG_WHOLEPKT);
kfree_skb(skb);
return 0;
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 56d55fecf8ec..a9988841172a 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -7,8 +7,6 @@
*
* Based on linux/net/ipv4/ip_sockglue.c
*
- * $Id: ipv6_sockglue.c,v 1.41 2002/02/01 22:01:04 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -67,7 +65,7 @@ int ip6_ra_control(struct sock *sk, int sel, void (*destructor)(struct sock *))
/* RA packet may be delivered ONLY to IPPROTO_RAW socket */
if (sk->sk_type != SOCK_RAW || inet_sk(sk)->num != IPPROTO_RAW)
- return -EINVAL;
+ return -ENOPROTOOPT;
new_ra = (sel>=0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
@@ -161,9 +159,17 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
struct ipv6_txoptions *opt;
struct sk_buff *pktopt;
- if (sk->sk_protocol != IPPROTO_UDP &&
- sk->sk_protocol != IPPROTO_UDPLITE &&
- sk->sk_protocol != IPPROTO_TCP)
+ if (sk->sk_type == SOCK_RAW)
+ break;
+
+ if (sk->sk_protocol == IPPROTO_UDP ||
+ sk->sk_protocol == IPPROTO_UDPLITE) {
+ struct udp_sock *up = udp_sk(sk);
+ if (up->pending == AF_INET6) {
+ retv = -EBUSY;
+ break;
+ }
+ } else if (sk->sk_protocol != IPPROTO_TCP)
break;
if (sk->sk_state != TCP_ESTABLISHED) {
@@ -416,7 +422,7 @@ sticky_done:
msg.msg_controllen = optlen;
msg.msg_control = (void*)(opt+1);
- retv = datagram_send_ctl(&msg, &fl, opt, &junk, &junk);
+ retv = datagram_send_ctl(net, &msg, &fl, opt, &junk, &junk);
if (retv)
goto done;
update:
@@ -438,7 +444,7 @@ done:
case IPV6_MULTICAST_HOPS:
if (sk->sk_type == SOCK_STREAM)
- goto e_inval;
+ break;
if (optlen < sizeof(int))
goto e_inval;
if (val > 255 || val < -1)
@@ -450,13 +456,15 @@ done:
case IPV6_MULTICAST_LOOP:
if (optlen < sizeof(int))
goto e_inval;
+ if (val != valbool)
+ goto e_inval;
np->mc_loop = valbool;
retv = 0;
break;
case IPV6_MULTICAST_IF:
if (sk->sk_type == SOCK_STREAM)
- goto e_inval;
+ break;
if (optlen < sizeof(int))
goto e_inval;
@@ -832,7 +840,7 @@ static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_txoptions *opt,
len = min_t(unsigned int, len, ipv6_optlen(hdr));
if (copy_to_user(optval, hdr, len))
return -EFAULT;
- return ipv6_optlen(hdr);
+ return len;
}
static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
@@ -852,7 +860,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
if (sk->sk_protocol != IPPROTO_UDP &&
sk->sk_protocol != IPPROTO_UDPLITE &&
sk->sk_protocol != IPPROTO_TCP)
- return -EINVAL;
+ return -ENOPROTOOPT;
if (sk->sk_state != TCP_ESTABLISHED)
return -ENOTCONN;
val = sk->sk_family;
@@ -866,6 +874,8 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
return -EINVAL;
if (copy_from_user(&gsf, optval, GROUP_FILTER_SIZE(0)))
return -EFAULT;
+ if (gsf.gf_group.ss_family != AF_INET6)
+ return -EADDRNOTAVAIL;
lock_sock(sk);
err = ip6_mc_msfget(sk, &gsf,
(struct group_filter __user *)optval, optlen);
@@ -975,6 +985,9 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
len = ipv6_getsockopt_sticky(sk, np->opt,
optname, optval, len);
release_sock(sk);
+ /* check if ipv6_getsockopt_sticky() returns err code */
+ if (len < 0)
+ return len;
return put_user(len, optlen);
}
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index fd632dd7f98d..bd2fe4cfafa7 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -5,8 +5,6 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: mcast.c,v 1.40 2002/02/08 03:57:19 davem Exp $
- *
* Based on linux/ipv4/igmp.c and linux/ipv4/ip_sockglue.c
*
* This program is free software; you can redistribute it and/or
@@ -164,7 +162,6 @@ static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml,
((MLDV2_MASK(value, nbmant) | (1<<(nbmant))) << \
(MLDV2_MASK((value) >> (nbmant), nbexp) + (nbexp))))
-#define MLDV2_QQIC(value) MLDV2_EXP(0x80, 4, 3, value)
#define MLDV2_MRC(value) MLDV2_EXP(0x8000, 12, 3, value)
#define IPV6_MLD_MAX_MSF 64
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index a55fc05b8125..282fdb31f8ed 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -1727,10 +1727,10 @@ int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl, int write, struct file * f
return ret;
}
-static int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl, int __user *name,
- int nlen, void __user *oldval,
- size_t __user *oldlenp,
- void __user *newval, size_t newlen)
+int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl, int __user *name,
+ int nlen, void __user *oldval,
+ size_t __user *oldlenp,
+ void __user *newval, size_t newlen)
{
struct net_device *dev = ctl->extra1;
struct inet6_dev *idev;
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index 6cae5475737e..689dec899c57 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -208,5 +208,17 @@ config IP6_NF_RAW
If you want to compile it as a module, say M here and read
<file:Documentation/kbuild/modules.txt>. If unsure, say `N'.
+# security table for MAC policy
+config IP6_NF_SECURITY
+ tristate "Security table"
+ depends on IP6_NF_IPTABLES
+ depends on SECURITY
+ default m if NETFILTER_ADVANCED=n
+ help
+ This option adds a `security' table to iptables, for use
+ with Mandatory Access Control (MAC) policy.
+
+ If unsure, say N.
+
endmenu
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
index fbf2c14ed887..3f17c948eefb 100644
--- a/net/ipv6/netfilter/Makefile
+++ b/net/ipv6/netfilter/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o
obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o
obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
+obj-$(CONFIG_IP6_NF_SECURITY) += ip6table_security.o
# objects for l3 independent conntrack
nf_conntrack_ipv6-objs := nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o nf_conntrack_reasm.o
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c
index 2eff3ae8977d..1b8815f6153d 100644
--- a/net/ipv6/netfilter/ip6_queue.c
+++ b/net/ipv6/netfilter/ip6_queue.c
@@ -159,7 +159,6 @@ ipq_build_packet_message(struct nf_queue_entry *entry, int *errp)
case IPQ_COPY_META:
case IPQ_COPY_NONE:
size = NLMSG_SPACE(sizeof(*pmsg));
- data_len = 0;
break;
case IPQ_COPY_PACKET:
@@ -226,8 +225,6 @@ ipq_build_packet_message(struct nf_queue_entry *entry, int *errp)
return skb;
nlmsg_failure:
- if (skb)
- kfree_skb(skb);
*errp = -EINVAL;
printk(KERN_ERR "ip6_queue: error creating packet message\n");
return NULL;
diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c
new file mode 100644
index 000000000000..063a3d9c3c67
--- /dev/null
+++ b/net/ipv6/netfilter/ip6table_security.c
@@ -0,0 +1,172 @@
+/*
+ * "security" table for IPv6
+ *
+ * This is for use by Mandatory Access Control (MAC) security models,
+ * which need to be able to manage security policy in separate context
+ * to DAC.
+ *
+ * Based on iptable_mangle.c
+ *
+ * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
+ * Copyright (C) 2000-2004 Netfilter Core Team <coreteam <at> netfilter.org>
+ * Copyright (C) 2008 Red Hat, Inc., James Morris <jmorris <at> redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("James Morris <jmorris <at> redhat.com>");
+MODULE_DESCRIPTION("ip6tables security table, for MAC rules");
+
+#define SECURITY_VALID_HOOKS (1 << NF_INET_LOCAL_IN) | \
+ (1 << NF_INET_FORWARD) | \
+ (1 << NF_INET_LOCAL_OUT)
+
+static struct
+{
+ struct ip6t_replace repl;
+ struct ip6t_standard entries[3];
+ struct ip6t_error term;
+} initial_table __initdata = {
+ .repl = {
+ .name = "security",
+ .valid_hooks = SECURITY_VALID_HOOKS,
+ .num_entries = 4,
+ .size = sizeof(struct ip6t_standard) * 3 + sizeof(struct ip6t_error),
+ .hook_entry = {
+ [NF_INET_LOCAL_IN] = 0,
+ [NF_INET_FORWARD] = sizeof(struct ip6t_standard),
+ [NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2,
+ },
+ .underflow = {
+ [NF_INET_LOCAL_IN] = 0,
+ [NF_INET_FORWARD] = sizeof(struct ip6t_standard),
+ [NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2,
+ },
+ },
+ .entries = {
+ IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */
+ IP6T_STANDARD_INIT(NF_ACCEPT), /* FORWARD */
+ IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */
+ },
+ .term = IP6T_ERROR_INIT, /* ERROR */
+};
+
+static struct xt_table security_table = {
+ .name = "security",
+ .valid_hooks = SECURITY_VALID_HOOKS,
+ .lock = __RW_LOCK_UNLOCKED(security_table.lock),
+ .me = THIS_MODULE,
+ .af = AF_INET6,
+};
+
+static unsigned int
+ip6t_local_in_hook(unsigned int hook,
+ struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ return ip6t_do_table(skb, hook, in, out,
+ init_net.ipv6.ip6table_security);
+}
+
+static unsigned int
+ip6t_forward_hook(unsigned int hook,
+ struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ return ip6t_do_table(skb, hook, in, out,
+ init_net.ipv6.ip6table_security);
+}
+
+static unsigned int
+ip6t_local_out_hook(unsigned int hook,
+ struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ /* TBD: handle short packets via raw socket */
+ return ip6t_do_table(skb, hook, in, out,
+ init_net.ipv6.ip6table_security);
+}
+
+static struct nf_hook_ops ip6t_ops[] __read_mostly = {
+ {
+ .hook = ip6t_local_in_hook,
+ .owner = THIS_MODULE,
+ .pf = PF_INET6,
+ .hooknum = NF_INET_LOCAL_IN,
+ .priority = NF_IP6_PRI_SECURITY,
+ },
+ {
+ .hook = ip6t_forward_hook,
+ .owner = THIS_MODULE,
+ .pf = PF_INET6,
+ .hooknum = NF_INET_FORWARD,
+ .priority = NF_IP6_PRI_SECURITY,
+ },
+ {
+ .hook = ip6t_local_out_hook,
+ .owner = THIS_MODULE,
+ .pf = PF_INET6,
+ .hooknum = NF_INET_LOCAL_OUT,
+ .priority = NF_IP6_PRI_SECURITY,
+ },
+};
+
+static int __net_init ip6table_security_net_init(struct net *net)
+{
+ net->ipv6.ip6table_security =
+ ip6t_register_table(net, &security_table, &initial_table.repl);
+
+ if (IS_ERR(net->ipv6.ip6table_security))
+ return PTR_ERR(net->ipv6.ip6table_security);
+
+ return 0;
+}
+
+static void __net_exit ip6table_security_net_exit(struct net *net)
+{
+ ip6t_unregister_table(net->ipv6.ip6table_security);
+}
+
+static struct pernet_operations ip6table_security_net_ops = {
+ .init = ip6table_security_net_init,
+ .exit = ip6table_security_net_exit,
+};
+
+static int __init ip6table_security_init(void)
+{
+ int ret;
+
+ ret = register_pernet_subsys(&ip6table_security_net_ops);
+ if (ret < 0)
+ return ret;
+
+ ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops));
+ if (ret < 0)
+ goto cleanup_table;
+
+ return ret;
+
+cleanup_table:
+ unregister_pernet_subsys(&ip6table_security_net_ops);
+ return ret;
+}
+
+static void __exit ip6table_security_fini(void)
+{
+ nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops));
+ unregister_pernet_subsys(&ip6table_security_net_ops);
+}
+
+module_init(ip6table_security_init);
+module_exit(ip6table_security_fini);
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
index ee713b03e9ec..14d47d833545 100644
--- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
@@ -89,9 +89,8 @@ static int icmpv6_packet(struct nf_conn *ct,
means this will only run once even if count hits zero twice
(theoretically possible with SMP) */
if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) {
- if (atomic_dec_and_test(&ct->proto.icmp.count)
- && del_timer(&ct->timeout))
- ct->timeout.function((unsigned long)ct);
+ if (atomic_dec_and_test(&ct->proto.icmp.count))
+ nf_ct_kill_acct(ct, ctinfo, skb);
} else {
atomic_inc(&ct->proto.icmp.count);
nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb);
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 2dccad48058c..e65e26e210ee 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -209,7 +209,9 @@ fq_find(__be32 id, struct in6_addr *src, struct in6_addr *dst)
arg.dst = dst;
hash = ip6qhashfn(id, src, dst);
+ local_bh_disable();
q = inet_frag_find(&nf_init_frags, &nf_frags, &arg, hash);
+ local_bh_enable();
if (q == NULL)
goto oom;
@@ -638,10 +640,10 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb)
goto ret_orig;
}
- spin_lock(&fq->q.lock);
+ spin_lock_bh(&fq->q.lock);
if (nf_ct_frag6_queue(fq, clone, fhdr, nhoff) < 0) {
- spin_unlock(&fq->q.lock);
+ spin_unlock_bh(&fq->q.lock);
pr_debug("Can't insert skb to queue\n");
fq_put(fq);
goto ret_orig;
@@ -653,7 +655,7 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb)
if (ret_skb == NULL)
pr_debug("Can't reassemble fragmented packets\n");
}
- spin_unlock(&fq->q.lock);
+ spin_unlock_bh(&fq->q.lock);
fq_put(fq);
return ret_skb;
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c
index df0736a4cafa..cbc7e514d3ec 100644
--- a/net/ipv6/proc.c
+++ b/net/ipv6/proc.c
@@ -7,8 +7,6 @@
* PROC file system. This is very similar to the IPv4 version,
* except it reports the sockets in the INET6 address family.
*
- * Version: $Id: proc.c,v 1.17 2002/02/01 22:01:04 davem Exp $
- *
* Authors: David S. Miller (davem@caip.rutgers.edu)
* YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
*
diff --git a/net/ipv6/protocol.c b/net/ipv6/protocol.c
index f929f47b925e..9ab789159913 100644
--- a/net/ipv6/protocol.c
+++ b/net/ipv6/protocol.c
@@ -5,8 +5,6 @@
*
* PF_INET6 protocol dispatch tables.
*
- * Version: $Id: protocol.c,v 1.10 2001/05/18 02:25:49 davem Exp $
- *
* Authors: Pedro Roque <roque@di.fc.ul.pt>
*
* This program is free software; you can redistribute it and/or
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 232e0dc45bf5..e03c1898ab2e 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -7,8 +7,6 @@
*
* Adapted from linux/net/ipv4/raw.c
*
- * $Id: raw.c,v 1.51 2002/02/01 22:01:04 davem Exp $
- *
* Fixes:
* Hideaki YOSHIFUJI : sin6_scope_id support
* YOSHIFUJI,H.@USAGI : raw checksum (RFC2292(bis) compliance)
@@ -813,7 +811,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
memset(opt, 0, sizeof(struct ipv6_txoptions));
opt->tot_len = sizeof(struct ipv6_txoptions);
- err = datagram_send_ctl(msg, &fl, opt, &hlimit, &tclass);
+ err = datagram_send_ctl(sock_net(sk), msg, &fl, opt, &hlimit, &tclass);
if (err < 0) {
fl6_sock_release(flowlabel);
return err;
@@ -1164,6 +1162,14 @@ static void rawv6_close(struct sock *sk, long timeout)
sk_common_release(sk);
}
+static int raw6_destroy(struct sock *sk)
+{
+ lock_sock(sk);
+ ip6_flush_pending_frames(sk);
+ release_sock(sk);
+ return 0;
+}
+
static int rawv6_init_sk(struct sock *sk)
{
struct raw6_sock *rp = raw6_sk(sk);
@@ -1187,6 +1193,7 @@ struct proto rawv6_prot = {
.name = "RAWv6",
.owner = THIS_MODULE,
.close = rawv6_close,
+ .destroy = raw6_destroy,
.connect = ip6_datagram_connect,
.disconnect = udp_disconnect,
.ioctl = rawv6_ioctl,
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 798cabc7535b..13509f906d89 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -5,8 +5,6 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: reassembly.c,v 1.26 2001/03/07 22:00:57 davem Exp $
- *
* Based on: net/ipv4/ip_fragment.c
*
* This program is free software; you can redistribute it and/or
@@ -632,7 +630,7 @@ static struct inet6_protocol frag_protocol =
};
#ifdef CONFIG_SYSCTL
-static struct ctl_table ip6_frags_ctl_table[] = {
+static struct ctl_table ip6_frags_ns_ctl_table[] = {
{
.ctl_name = NET_IPV6_IP6FRAG_HIGH_THRESH,
.procname = "ip6frag_high_thresh",
@@ -658,6 +656,10 @@ static struct ctl_table ip6_frags_ctl_table[] = {
.proc_handler = &proc_dointvec_jiffies,
.strategy = &sysctl_jiffies,
},
+ { }
+};
+
+static struct ctl_table ip6_frags_ctl_table[] = {
{
.ctl_name = NET_IPV6_IP6FRAG_SECRET_INTERVAL,
.procname = "ip6frag_secret_interval",
@@ -670,21 +672,20 @@ static struct ctl_table ip6_frags_ctl_table[] = {
{ }
};
-static int ip6_frags_sysctl_register(struct net *net)
+static int ip6_frags_ns_sysctl_register(struct net *net)
{
struct ctl_table *table;
struct ctl_table_header *hdr;
- table = ip6_frags_ctl_table;
+ table = ip6_frags_ns_ctl_table;
if (net != &init_net) {
- table = kmemdup(table, sizeof(ip6_frags_ctl_table), GFP_KERNEL);
+ table = kmemdup(table, sizeof(ip6_frags_ns_ctl_table), GFP_KERNEL);
if (table == NULL)
goto err_alloc;
table[0].data = &net->ipv6.frags.high_thresh;
table[1].data = &net->ipv6.frags.low_thresh;
table[2].data = &net->ipv6.frags.timeout;
- table[3].mode &= ~0222;
}
hdr = register_net_sysctl_table(net, net_ipv6_ctl_path, table);
@@ -701,7 +702,7 @@ err_alloc:
return -ENOMEM;
}
-static void ip6_frags_sysctl_unregister(struct net *net)
+static void ip6_frags_ns_sysctl_unregister(struct net *net)
{
struct ctl_table *table;
@@ -709,13 +710,36 @@ static void ip6_frags_sysctl_unregister(struct net *net)
unregister_net_sysctl_table(net->ipv6.sysctl.frags_hdr);
kfree(table);
}
+
+static struct ctl_table_header *ip6_ctl_header;
+
+static int ip6_frags_sysctl_register(void)
+{
+ ip6_ctl_header = register_net_sysctl_rotable(net_ipv6_ctl_path,
+ ip6_frags_ctl_table);
+ return ip6_ctl_header == NULL ? -ENOMEM : 0;
+}
+
+static void ip6_frags_sysctl_unregister(void)
+{
+ unregister_net_sysctl_table(ip6_ctl_header);
+}
#else
-static inline int ip6_frags_sysctl_register(struct net *net)
+static inline int ip6_frags_ns_sysctl_register(struct net *net)
{
return 0;
}
-static inline void ip6_frags_sysctl_unregister(struct net *net)
+static inline void ip6_frags_ns_sysctl_unregister(struct net *net)
+{
+}
+
+static inline int ip6_frags_sysctl_register(void)
+{
+ return 0;
+}
+
+static inline void ip6_frags_sysctl_unregister(void)
{
}
#endif
@@ -728,12 +752,12 @@ static int ipv6_frags_init_net(struct net *net)
inet_frags_init_net(&net->ipv6.frags);
- return ip6_frags_sysctl_register(net);
+ return ip6_frags_ns_sysctl_register(net);
}
static void ipv6_frags_exit_net(struct net *net)
{
- ip6_frags_sysctl_unregister(net);
+ ip6_frags_ns_sysctl_unregister(net);
inet_frags_exit_net(&net->ipv6.frags, &ip6_frags);
}
@@ -750,7 +774,13 @@ int __init ipv6_frag_init(void)
if (ret)
goto out;
- register_pernet_subsys(&ip6_frags_ops);
+ ret = ip6_frags_sysctl_register();
+ if (ret)
+ goto err_sysctl;
+
+ ret = register_pernet_subsys(&ip6_frags_ops);
+ if (ret)
+ goto err_pernet;
ip6_frags.hashfn = ip6_hashfn;
ip6_frags.constructor = ip6_frag_init;
@@ -763,11 +793,18 @@ int __init ipv6_frag_init(void)
inet_frags_init(&ip6_frags);
out:
return ret;
+
+err_pernet:
+ ip6_frags_sysctl_unregister();
+err_sysctl:
+ inet6_del_protocol(&frag_protocol, IPPROTO_FRAGMENT);
+ goto out;
}
void ipv6_frag_exit(void)
{
inet_frags_fini(&ip6_frags);
+ ip6_frags_sysctl_unregister();
unregister_pernet_subsys(&ip6_frags_ops);
inet6_del_protocol(&frag_protocol, IPPROTO_FRAGMENT);
}
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 12bba0880345..efe036aa3dd1 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -5,8 +5,6 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: route.c,v 1.56 2001/10/31 21:55:55 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -109,7 +107,7 @@ static struct dst_ops ip6_dst_ops_template = {
.negative_advice = ip6_negative_advice,
.link_failure = ip6_link_failure,
.update_pmtu = ip6_rt_update_pmtu,
- .local_out = ip6_local_out,
+ .local_out = __ip6_local_out,
.entry_size = sizeof(struct rt6_info),
.entries = ATOMIC_INIT(0),
};
@@ -446,7 +444,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
struct route_info *rinfo = (struct route_info *) opt;
struct in6_addr prefix_buf, *prefix;
unsigned int pref;
- u32 lifetime;
+ unsigned long lifetime;
struct rt6_info *rt;
if (len < sizeof(struct route_info)) {
@@ -472,13 +470,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
if (pref == ICMPV6_ROUTER_PREF_INVALID)
pref = ICMPV6_ROUTER_PREF_MEDIUM;
- lifetime = ntohl(rinfo->lifetime);
- if (lifetime == 0xffffffff) {
- /* infinity */
- } else if (lifetime > 0x7fffffff/HZ) {
- /* Avoid arithmetic overflow */
- lifetime = 0x7fffffff/HZ - 1;
- }
+ lifetime = addrconf_timeout_fixup(ntohl(rinfo->lifetime), HZ);
if (rinfo->length == 3)
prefix = (struct in6_addr *)rinfo->prefix;
@@ -506,7 +498,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
(rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
if (rt) {
- if (lifetime == 0xffffffff) {
+ if (!addrconf_finite_timeout(lifetime)) {
rt->rt6i_flags &= ~RTF_EXPIRES;
} else {
rt->rt6i_expires = jiffies + HZ * lifetime;
@@ -1106,7 +1098,9 @@ int ip6_route_add(struct fib6_config *cfg)
}
rt->u.dst.obsolete = -1;
- rt->rt6i_expires = jiffies + clock_t_to_jiffies(cfg->fc_expires);
+ rt->rt6i_expires = (cfg->fc_flags & RTF_EXPIRES) ?
+ jiffies + clock_t_to_jiffies(cfg->fc_expires) :
+ 0;
if (cfg->fc_protocol == RTPROT_UNSPEC)
cfg->fc_protocol = RTPROT_BOOT;
@@ -2200,7 +2194,13 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt,
NLA_PUT_U32(skb, RTA_PRIORITY, rt->rt6i_metric);
- expires = rt->rt6i_expires ? rt->rt6i_expires - jiffies : 0;
+ if (!(rt->rt6i_flags & RTF_EXPIRES))
+ expires = 0;
+ else if (rt->rt6i_expires - jiffies < INT_MAX)
+ expires = rt->rt6i_expires - jiffies;
+ else
+ expires = INT_MAX;
+
if (rtnl_put_cacheinfo(skb, &rt->u.dst, 0, 0, 0,
expires, rt->u.dst.error) < 0)
goto nla_put_failure;
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 5a6fab95569f..b0c5080420a8 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -6,8 +6,6 @@
* Pedro Roque <roque@di.fc.ul.pt>
* Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
*
- * $Id: sit.c,v 1.53 2001/09/25 05:09:53 davem Exp $
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -403,9 +401,8 @@ static void ipip6_tunnel_uninit(struct net_device *dev)
static int ipip6_err(struct sk_buff *skb, u32 info)
{
-#ifndef I_WISH_WORLD_WERE_PERFECT
-/* It is not :-( All the routers (except for Linux) return only
+/* All the routers (except for Linux) return only
8 bytes of packet payload. It means, that precise relaying of
ICMP in the real Internet is absolutely infeasible.
*/
@@ -462,92 +459,6 @@ static int ipip6_err(struct sk_buff *skb, u32 info)
out:
read_unlock(&ipip6_lock);
return err;
-#else
- struct iphdr *iph = (struct iphdr*)dp;
- int hlen = iph->ihl<<2;
- struct ipv6hdr *iph6;
- const int type = icmp_hdr(skb)->type;
- const int code = icmp_hdr(skb)->code;
- int rel_type = 0;
- int rel_code = 0;
- int rel_info = 0;
- struct sk_buff *skb2;
- struct rt6_info *rt6i;
-
- if (len < hlen + sizeof(struct ipv6hdr))
- return;
- iph6 = (struct ipv6hdr*)(dp + hlen);
-
- switch (type) {
- default:
- return;
- case ICMP_PARAMETERPROB:
- if (icmp_hdr(skb)->un.gateway < hlen)
- return;
-
- /* So... This guy found something strange INSIDE encapsulated
- packet. Well, he is fool, but what can we do ?
- */
- rel_type = ICMPV6_PARAMPROB;
- rel_info = icmp_hdr(skb)->un.gateway - hlen;
- break;
-
- case ICMP_DEST_UNREACH:
- switch (code) {
- case ICMP_SR_FAILED:
- case ICMP_PORT_UNREACH:
- /* Impossible event. */
- return;
- case ICMP_FRAG_NEEDED:
- /* Too complicated case ... */
- return;
- default:
- /* All others are translated to HOST_UNREACH.
- rfc2003 contains "deep thoughts" about NET_UNREACH,
- I believe, it is just ether pollution. --ANK
- */
- rel_type = ICMPV6_DEST_UNREACH;
- rel_code = ICMPV6_ADDR_UNREACH;
- break;
- }
- break;
- case ICMP_TIME_EXCEEDED:
- if (code != ICMP_EXC_TTL)
- return;
- rel_type = ICMPV6_TIME_EXCEED;
- rel_code = ICMPV6_EXC_HOPLIMIT;
- break;
- }
-
- /* Prepare fake skb to feed it to icmpv6_send */
- skb2 = skb_clone(skb, GFP_ATOMIC);
- if (skb2 == NULL)
- return 0;
- dst_release(skb2->dst);
- skb2->dst = NULL;
- skb_pull(skb2, skb->data - (u8*)iph6);
- skb_reset_network_header(skb2);
-
- /* Try to guess incoming interface */
- rt6i = rt6_lookup(dev_net(skb->dev), &iph6->saddr, NULL, NULL, 0);
- if (rt6i && rt6i->rt6i_dev) {
- skb2->dev = rt6i->rt6i_dev;
-
- rt6i = rt6_lookup(dev_net(skb->dev),
- &iph6->daddr, &iph6->saddr, NULL, 0);
-
- if (rt6i && rt6i->rt6i_dev && rt6i->rt6i_dev->type == ARPHRD_SIT) {
- struct ip_tunnel *t = netdev_priv(rt6i->rt6i_dev);
- if (rel_type == ICMPV6_TIME_EXCEED && t->parms.iph.ttl) {
- rel_type = ICMPV6_DEST_UNREACH;
- rel_code = ICMPV6_ADDR_UNREACH;
- }
- icmpv6_send(skb2, rel_type, rel_code, rel_info, skb2->dev);
- }
- }
- kfree_skb(skb2);
- return 0;
-#endif
}
static inline void ipip6_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb)
@@ -578,13 +489,13 @@ static int ipip6_rcv(struct sk_buff *skb)
if ((tunnel->dev->priv_flags & IFF_ISATAP) &&
!isatap_chksrc(skb, iph, tunnel)) {
- tunnel->stat.rx_errors++;
+ tunnel->dev->stats.rx_errors++;
read_unlock(&ipip6_lock);
kfree_skb(skb);
return 0;
}
- tunnel->stat.rx_packets++;
- tunnel->stat.rx_bytes += skb->len;
+ tunnel->dev->stats.rx_packets++;
+ tunnel->dev->stats.rx_bytes += skb->len;
skb->dev = tunnel->dev;
dst_release(skb->dst);
skb->dst = NULL;
@@ -624,7 +535,7 @@ static inline __be32 try_6to4(struct in6_addr *v6dst)
static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ip_tunnel *tunnel = netdev_priv(dev);
- struct net_device_stats *stats = &tunnel->stat;
+ struct net_device_stats *stats = &tunnel->dev->stats;
struct iphdr *tiph = &tunnel->parms.iph;
struct ipv6hdr *iph6 = ipv6_hdr(skb);
u8 tos = tunnel->parms.iph.tos;
@@ -638,7 +549,7 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
int addr_type;
if (tunnel->recursion++) {
- tunnel->stat.collisions++;
+ stats->collisions++;
goto tx_error;
}
@@ -705,20 +616,20 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
.oif = tunnel->parms.link,
.proto = IPPROTO_IPV6 };
if (ip_route_output_key(dev_net(dev), &rt, &fl)) {
- tunnel->stat.tx_carrier_errors++;
+ stats->tx_carrier_errors++;
goto tx_error_icmp;
}
}
if (rt->rt_type != RTN_UNICAST) {
ip_rt_put(rt);
- tunnel->stat.tx_carrier_errors++;
+ stats->tx_carrier_errors++;
goto tx_error_icmp;
}
tdev = rt->u.dst.dev;
if (tdev == dev) {
ip_rt_put(rt);
- tunnel->stat.collisions++;
+ stats->collisions++;
goto tx_error;
}
@@ -728,7 +639,7 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
mtu = skb->dst ? dst_mtu(skb->dst) : dev->mtu;
if (mtu < 68) {
- tunnel->stat.collisions++;
+ stats->collisions++;
ip_rt_put(rt);
goto tx_error;
}
@@ -1003,11 +914,6 @@ done:
return err;
}
-static struct net_device_stats *ipip6_tunnel_get_stats(struct net_device *dev)
-{
- return &(((struct ip_tunnel*)netdev_priv(dev))->stat);
-}
-
static int ipip6_tunnel_change_mtu(struct net_device *dev, int new_mtu)
{
if (new_mtu < IPV6_MIN_MTU || new_mtu > 0xFFF8 - sizeof(struct iphdr))
@@ -1021,7 +927,6 @@ static void ipip6_tunnel_setup(struct net_device *dev)
dev->uninit = ipip6_tunnel_uninit;
dev->destructor = free_netdev;
dev->hard_start_xmit = ipip6_tunnel_xmit;
- dev->get_stats = ipip6_tunnel_get_stats;
dev->do_ioctl = ipip6_tunnel_ioctl;
dev->change_mtu = ipip6_tunnel_change_mtu;
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index 938ce4ecde55..3ecc1157994e 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -198,7 +198,6 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
ireq = inet_rsk(req);
ireq6 = inet6_rsk(req);
treq = tcp_rsk(req);
- ireq6->pktopts = NULL;
if (security_inet_conn_request(sk, skb, req)) {
reqsk_free(req);
diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c
index 3804dcbbfab0..5c99274558bf 100644
--- a/net/ipv6/sysctl_net_ipv6.c
+++ b/net/ipv6/sysctl_net_ipv6.c
@@ -37,6 +37,10 @@ static ctl_table ipv6_table_template[] = {
.mode = 0644,
.proc_handler = &proc_dointvec
},
+ { .ctl_name = 0 }
+};
+
+static ctl_table ipv6_table[] = {
{
.ctl_name = NET_IPV6_MLD_MAX_MSF,
.procname = "mld_max_msf",
@@ -80,12 +84,6 @@ static int ipv6_sysctl_net_init(struct net *net)
ipv6_table[2].data = &net->ipv6.sysctl.bindv6only;
- /* We don't want this value to be per namespace, it should be global
- to all namespaces, so make it read-only when we are not in the
- init network namespace */
- if (net != &init_net)
- ipv6_table[3].mode = 0444;
-
net->ipv6.sysctl.table = register_net_sysctl_table(net, net_ipv6_ctl_path,
ipv6_table);
if (!net->ipv6.sysctl.table)
@@ -126,12 +124,29 @@ static struct pernet_operations ipv6_sysctl_net_ops = {
.exit = ipv6_sysctl_net_exit,
};
+static struct ctl_table_header *ip6_header;
+
int ipv6_sysctl_register(void)
{
- return register_pernet_subsys(&ipv6_sysctl_net_ops);
+ int err = -ENOMEM;;
+
+ ip6_header = register_net_sysctl_rotable(net_ipv6_ctl_path, ipv6_table);
+ if (ip6_header == NULL)
+ goto out;
+
+ err = register_pernet_subsys(&ipv6_sysctl_net_ops);
+ if (err)
+ goto err_pernet;
+out:
+ return err;
+
+err_pernet:
+ unregister_net_sysctl_table(ip6_header);
+ goto out;
}
void ipv6_sysctl_unregister(void)
{
+ unregister_net_sysctl_table(ip6_header);
unregister_pernet_subsys(&ipv6_sysctl_net_ops);
}
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 715965f0fac0..ebed5d3adb82 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -5,8 +5,6 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: tcp_ipv6.c,v 1.144 2002/02/01 22:01:04 davem Exp $
- *
* Based on:
* linux/net/ipv4/tcp.c
* linux/net/ipv4/tcp_input.c
@@ -82,6 +80,12 @@ static struct inet_connection_sock_af_ops ipv6_specific;
#ifdef CONFIG_TCP_MD5SIG
static struct tcp_sock_af_ops tcp_sock_ipv6_specific;
static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific;
+#else
+static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk,
+ struct in6_addr *addr)
+{
+ return NULL;
+}
#endif
static void tcp_v6_hash(struct sock *sk)
@@ -736,78 +740,34 @@ static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval,
static int tcp_v6_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
struct in6_addr *saddr,
struct in6_addr *daddr,
- struct tcphdr *th, int protocol,
- unsigned int tcplen)
+ struct tcphdr *th, unsigned int tcplen)
{
- struct scatterlist sg[4];
- __u16 data_len;
- int block = 0;
- __sum16 cksum;
struct tcp_md5sig_pool *hp;
struct tcp6_pseudohdr *bp;
- struct hash_desc *desc;
int err;
- unsigned int nbytes = 0;
hp = tcp_get_md5sig_pool();
if (!hp) {
printk(KERN_WARNING "%s(): hash pool not found...\n", __func__);
goto clear_hash_noput;
}
+
bp = &hp->md5_blk.ip6;
- desc = &hp->md5_desc;
/* 1. TCP pseudo-header (RFC2460) */
ipv6_addr_copy(&bp->saddr, saddr);
ipv6_addr_copy(&bp->daddr, daddr);
bp->len = htonl(tcplen);
- bp->protocol = htonl(protocol);
-
- sg_init_table(sg, 4);
+ bp->protocol = htonl(IPPROTO_TCP);
- sg_set_buf(&sg[block++], bp, sizeof(*bp));
- nbytes += sizeof(*bp);
+ err = tcp_calc_md5_hash(md5_hash, key, sizeof(*bp),
+ th, tcplen, hp);
- /* 2. TCP header, excluding options */
- cksum = th->check;
- th->check = 0;
- sg_set_buf(&sg[block++], th, sizeof(*th));
- nbytes += sizeof(*th);
-
- /* 3. TCP segment data (if any) */
- data_len = tcplen - (th->doff << 2);
- if (data_len > 0) {
- u8 *data = (u8 *)th + (th->doff << 2);
- sg_set_buf(&sg[block++], data, data_len);
- nbytes += data_len;
- }
-
- /* 4. shared key */
- sg_set_buf(&sg[block++], key->key, key->keylen);
- nbytes += key->keylen;
-
- sg_mark_end(&sg[block - 1]);
-
- /* Now store the hash into the packet */
- err = crypto_hash_init(desc);
- if (err) {
- printk(KERN_WARNING "%s(): hash_init failed\n", __func__);
- goto clear_hash;
- }
- err = crypto_hash_update(desc, sg, nbytes);
- if (err) {
- printk(KERN_WARNING "%s(): hash_update failed\n", __func__);
- goto clear_hash;
- }
- err = crypto_hash_final(desc, md5_hash);
- if (err) {
- printk(KERN_WARNING "%s(): hash_final failed\n", __func__);
+ if (err)
goto clear_hash;
- }
- /* Reset header, and free up the crypto */
+ /* Free up the crypto pool */
tcp_put_md5sig_pool();
- th->check = cksum;
out:
return 0;
clear_hash:
@@ -821,8 +781,7 @@ static int tcp_v6_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
struct sock *sk,
struct dst_entry *dst,
struct request_sock *req,
- struct tcphdr *th, int protocol,
- unsigned int tcplen)
+ struct tcphdr *th, unsigned int tcplen)
{
struct in6_addr *saddr, *daddr;
@@ -835,7 +794,7 @@ static int tcp_v6_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
}
return tcp_v6_do_calc_md5_hash(md5_hash, key,
saddr, daddr,
- th, protocol, tcplen);
+ th, tcplen);
}
static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb)
@@ -844,43 +803,12 @@ static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb)
struct tcp_md5sig_key *hash_expected;
struct ipv6hdr *ip6h = ipv6_hdr(skb);
struct tcphdr *th = tcp_hdr(skb);
- int length = (th->doff << 2) - sizeof (*th);
int genhash;
- u8 *ptr;
u8 newhash[16];
hash_expected = tcp_v6_md5_do_lookup(sk, &ip6h->saddr);
+ hash_location = tcp_parse_md5sig_option(th);
- /* If the TCP option is too short, we can short cut */
- if (length < TCPOLEN_MD5SIG)
- return hash_expected ? 1 : 0;
-
- /* parse options */
- ptr = (u8*)(th + 1);
- while (length > 0) {
- int opcode = *ptr++;
- int opsize;
-
- switch(opcode) {
- case TCPOPT_EOL:
- goto done_opts;
- case TCPOPT_NOP:
- length--;
- continue;
- default:
- opsize = *ptr++;
- if (opsize < 2 || opsize > length)
- goto done_opts;
- if (opcode == TCPOPT_MD5SIG) {
- hash_location = ptr;
- goto done_opts;
- }
- }
- ptr += opsize - 2;
- length -= opsize;
- }
-
-done_opts:
/* do we have a hash as expected? */
if (!hash_expected) {
if (!hash_location)
@@ -910,8 +838,7 @@ done_opts:
genhash = tcp_v6_do_calc_md5_hash(newhash,
hash_expected,
&ip6h->saddr, &ip6h->daddr,
- th, sk->sk_protocol,
- skb->len);
+ th, skb->len);
if (genhash || memcmp(hash_location, newhash, 16) != 0) {
if (net_ratelimit()) {
printk(KERN_INFO "MD5 Hash %s for "
@@ -1051,7 +978,7 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
tcp_v6_do_calc_md5_hash((__u8 *)&opt[1], key,
&ipv6_hdr(skb)->daddr,
&ipv6_hdr(skb)->saddr,
- t1, IPPROTO_TCP, tot_len);
+ t1, tot_len);
}
#endif
@@ -1088,8 +1015,8 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
kfree_skb(buff);
}
-static void tcp_v6_send_ack(struct tcp_timewait_sock *tw,
- struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts)
+static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts,
+ struct tcp_md5sig_key *key)
{
struct tcphdr *th = tcp_hdr(skb), *t1;
struct sk_buff *buff;
@@ -1098,22 +1025,6 @@ static void tcp_v6_send_ack(struct tcp_timewait_sock *tw,
struct sock *ctl_sk = net->ipv6.tcp_sk;
unsigned int tot_len = sizeof(struct tcphdr);
__be32 *topt;
-#ifdef CONFIG_TCP_MD5SIG
- struct tcp_md5sig_key *key;
- struct tcp_md5sig_key tw_key;
-#endif
-
-#ifdef CONFIG_TCP_MD5SIG
- if (!tw && skb->sk) {
- key = tcp_v6_md5_do_lookup(skb->sk, &ipv6_hdr(skb)->daddr);
- } else if (tw && tw->tw_md5_keylen) {
- tw_key.key = tw->tw_md5_key;
- tw_key.keylen = tw->tw_md5_keylen;
- key = &tw_key;
- } else {
- key = NULL;
- }
-#endif
if (ts)
tot_len += TCPOLEN_TSTAMP_ALIGNED;
@@ -1157,7 +1068,7 @@ static void tcp_v6_send_ack(struct tcp_timewait_sock *tw,
tcp_v6_do_calc_md5_hash((__u8 *)topt, key,
&ipv6_hdr(skb)->daddr,
&ipv6_hdr(skb)->saddr,
- t1, IPPROTO_TCP, tot_len);
+ t1, tot_len);
}
#endif
@@ -1193,16 +1104,17 @@ static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)
struct inet_timewait_sock *tw = inet_twsk(sk);
struct tcp_timewait_sock *tcptw = tcp_twsk(sk);
- tcp_v6_send_ack(tcptw, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
+ tcp_v6_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
- tcptw->tw_ts_recent);
+ tcptw->tw_ts_recent, tcp_twsk_md5_key(tcptw));
inet_twsk_put(tw);
}
static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req)
{
- tcp_v6_send_ack(NULL, skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, req->ts_recent);
+ tcp_v6_send_ack(skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, req->ts_recent,
+ tcp_v6_md5_do_lookup(skb->sk, &ipv6_hdr(skb)->daddr));
}
@@ -1299,7 +1211,6 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
treq = inet6_rsk(req);
ipv6_addr_copy(&treq->rmt_addr, &ipv6_hdr(skb)->saddr);
ipv6_addr_copy(&treq->loc_addr, &ipv6_hdr(skb)->daddr);
- treq->pktopts = NULL;
if (!want_cookie)
TCP_ECN_create_request(req, tcp_hdr(skb));
diff --git a/net/ipv6/tunnel6.c b/net/ipv6/tunnel6.c
index 6323921b40be..669f280989c3 100644
--- a/net/ipv6/tunnel6.c
+++ b/net/ipv6/tunnel6.c
@@ -109,7 +109,7 @@ static int tunnel46_rcv(struct sk_buff *skb)
{
struct xfrm6_tunnel *handler;
- if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
+ if (!pskb_may_pull(skb, sizeof(struct iphdr)))
goto drop;
for (handler = tunnel46_handlers; handler; handler = handler->next)
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 1fd784f3e2ec..e0693fffc9bd 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -7,8 +7,6 @@
*
* Based on linux/ipv4/udp.c
*
- * $Id: udp.c,v 1.65 2002/02/01 22:01:04 davem Exp $
- *
* Fixes:
* Hideaki YOSHIFUJI : sin6_scope_id support
* YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which
@@ -534,7 +532,9 @@ static void udp_v6_flush_pending_frames(struct sock *sk)
{
struct udp_sock *up = udp_sk(sk);
- if (up->pending) {
+ if (up->pending == AF_INET)
+ udp_flush_pending_frames(sk);
+ else if (up->pending) {
up->len = 0;
up->pending = 0;
ip6_flush_pending_frames(sk);
@@ -731,7 +731,7 @@ do_udp_sendmsg:
memset(opt, 0, sizeof(struct ipv6_txoptions));
opt->tot_len = sizeof(*opt);
- err = datagram_send_ctl(msg, &fl, opt, &hlimit, &tclass);
+ err = datagram_send_ctl(sock_net(sk), msg, &fl, opt, &hlimit, &tclass);
if (err < 0) {
fl6_sock_release(flowlabel);
return err;
@@ -848,12 +848,14 @@ do_append_data:
} else {
dst_release(dst);
}
+ dst = NULL;
}
if (err > 0)
err = np->recverr ? net_xmit_errno(err) : 0;
release_sock(sk);
out:
+ dst_release(dst);
fl6_sock_release(flowlabel);
if (!err)
return len;
diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c
index 491efd00a866..f6cdcb348e05 100644
--- a/net/ipv6/udplite.c
+++ b/net/ipv6/udplite.c
@@ -2,8 +2,6 @@
* UDPLITEv6 An implementation of the UDP-Lite protocol over IPv6.
* See also net/ipv4/udplite.c
*
- * Version: $Id: udplite.c,v 1.9 2006/10/19 08:28:10 gerrit Exp $
- *
* Authors: Gerrit Renker <gerrit@erg.abdn.ac.uk>
*
* Changes:
diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c
index ae54b20d0470..3eb5bcc75f99 100644
--- a/net/irda/af_irda.c
+++ b/net/irda/af_irda.c
@@ -1093,11 +1093,6 @@ static int irda_create(struct net *net, struct socket *sock, int protocol)
init_waitqueue_head(&self->query_wait);
- /* Initialise networking socket struct */
- sock_init_data(sock, sk); /* Note : set sk->sk_refcnt to 1 */
- sk->sk_family = PF_IRDA;
- sk->sk_protocol = protocol;
-
switch (sock->type) {
case SOCK_STREAM:
sock->ops = &irda_stream_ops;
@@ -1124,13 +1119,20 @@ static int irda_create(struct net *net, struct socket *sock, int protocol)
self->max_sdu_size_rx = TTP_SAR_UNBOUND;
break;
default:
+ sk_free(sk);
return -ESOCKTNOSUPPORT;
}
break;
default:
+ sk_free(sk);
return -ESOCKTNOSUPPORT;
}
+ /* Initialise networking socket struct */
+ sock_init_data(sock, sk); /* Note : set sk->sk_refcnt to 1 */
+ sk->sk_family = PF_IRDA;
+ sk->sk_protocol = protocol;
+
/* Register as a client with IrLMP */
self->ckey = irlmp_register_client(0, NULL, NULL, NULL);
self->mask.word = 0xffff;
diff --git a/net/irda/irnet/irnet.h b/net/irda/irnet/irnet.h
index b001c361ad30..bccf4d0059f0 100644
--- a/net/irda/irnet/irnet.h
+++ b/net/irda/irnet/irnet.h
@@ -241,6 +241,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/smp_lock.h>
#include <linux/skbuff.h>
#include <linux/tty.h>
#include <linux/proc_fs.h>
diff --git a/net/irda/irnet/irnet_ppp.c b/net/irda/irnet/irnet_ppp.c
index e0eab5927c4f..6d8ae03c14f5 100644
--- a/net/irda/irnet/irnet_ppp.c
+++ b/net/irda/irnet/irnet_ppp.c
@@ -479,6 +479,7 @@ dev_irnet_open(struct inode * inode,
ap = kzalloc(sizeof(*ap), GFP_KERNEL);
DABORT(ap == NULL, -ENOMEM, FS_ERROR, "Can't allocate struct irnet...\n");
+ lock_kernel();
/* initialize the irnet structure */
ap->file = file;
@@ -500,6 +501,7 @@ dev_irnet_open(struct inode * inode,
{
DERROR(FS_ERROR, "Can't setup IrDA link...\n");
kfree(ap);
+ unlock_kernel();
return err;
}
@@ -510,6 +512,7 @@ dev_irnet_open(struct inode * inode,
file->private_data = ap;
DEXIT(FS_TRACE, " - ap=0x%p\n", ap);
+ unlock_kernel();
return 0;
}
@@ -628,8 +631,8 @@ dev_irnet_poll(struct file * file,
* This is the way pppd configure us and control us while the PPP
* instance is active.
*/
-static int
-dev_irnet_ioctl(struct inode * inode,
+static long
+dev_irnet_ioctl(
struct file * file,
unsigned int cmd,
unsigned long arg)
@@ -660,6 +663,7 @@ dev_irnet_ioctl(struct inode * inode,
{
DEBUG(FS_INFO, "Entering PPP discipline.\n");
/* PPP channel setup (ap->chan in configued in dev_irnet_open())*/
+ lock_kernel();
err = ppp_register_channel(&ap->chan);
if(err == 0)
{
@@ -672,12 +676,14 @@ dev_irnet_ioctl(struct inode * inode,
}
else
DERROR(FS_ERROR, "Can't setup PPP channel...\n");
+ unlock_kernel();
}
else
{
/* In theory, should be N_TTY */
DEBUG(FS_INFO, "Exiting PPP discipline.\n");
/* Disconnect from the generic PPP layer */
+ lock_kernel();
if(ap->ppp_open)
{
ap->ppp_open = 0;
@@ -686,24 +692,20 @@ dev_irnet_ioctl(struct inode * inode,
else
DERROR(FS_ERROR, "Channel not registered !\n");
err = 0;
+ unlock_kernel();
}
break;
/* Query PPP channel and unit number */
case PPPIOCGCHAN:
- if(!ap->ppp_open)
- break;
- if(put_user(ppp_channel_index(&ap->chan), (int __user *)argp))
- break;
- DEBUG(FS_INFO, "Query channel.\n");
- err = 0;
+ if(ap->ppp_open && !put_user(ppp_channel_index(&ap->chan),
+ (int __user *)argp))
+ err = 0;
break;
case PPPIOCGUNIT:
- if(!ap->ppp_open)
- break;
- if(put_user(ppp_unit_number(&ap->chan), (int __user *)argp))
- break;
- DEBUG(FS_INFO, "Query unit number.\n");
+ lock_kernel();
+ if(ap->ppp_open && !put_user(ppp_unit_number(&ap->chan),
+ (int __user *)argp))
err = 0;
break;
@@ -723,34 +725,39 @@ dev_irnet_ioctl(struct inode * inode,
DEBUG(FS_INFO, "Standard PPP ioctl.\n");
if(!capable(CAP_NET_ADMIN))
err = -EPERM;
- else
+ else {
+ lock_kernel();
err = ppp_irnet_ioctl(&ap->chan, cmd, arg);
+ unlock_kernel();
+ }
break;
/* TTY IOCTLs : Pretend that we are a tty, to keep pppd happy */
/* Get termios */
case TCGETS:
DEBUG(FS_INFO, "Get termios.\n");
+ lock_kernel();
#ifndef TCGETS2
- if(kernel_termios_to_user_termios((struct termios __user *)argp, &ap->termios))
- break;
+ if(!kernel_termios_to_user_termios((struct termios __user *)argp, &ap->termios))
+ err = 0;
#else
if(kernel_termios_to_user_termios_1((struct termios __user *)argp, &ap->termios))
- break;
+ err = 0;
#endif
- err = 0;
+ unlock_kernel();
break;
/* Set termios */
case TCSETSF:
DEBUG(FS_INFO, "Set termios.\n");
+ lock_kernel();
#ifndef TCGETS2
- if(user_termios_to_kernel_termios(&ap->termios, (struct termios __user *)argp))
- break;
+ if(!user_termios_to_kernel_termios(&ap->termios, (struct termios __user *)argp))
+ err = 0;
#else
- if(user_termios_to_kernel_termios_1(&ap->termios, (struct termios __user *)argp))
- break;
+ if(!user_termios_to_kernel_termios_1(&ap->termios, (struct termios __user *)argp))
+ err = 0;
#endif
- err = 0;
+ unlock_kernel();
break;
/* Set DTR/RTS */
@@ -773,7 +780,9 @@ dev_irnet_ioctl(struct inode * inode,
* We should also worry that we don't accept junk here and that
* we get rid of our own buffers */
#ifdef FLUSH_TO_PPP
+ lock_kernel();
ppp_output_wakeup(&ap->chan);
+ unlock_kernel();
#endif /* FLUSH_TO_PPP */
err = 0;
break;
@@ -788,7 +797,7 @@ dev_irnet_ioctl(struct inode * inode,
default:
DERROR(FS_ERROR, "Unsupported ioctl (0x%X)\n", cmd);
- err = -ENOIOCTLCMD;
+ err = -ENOTTY;
}
DEXIT(FS_TRACE, " - err = 0x%X\n", err);
diff --git a/net/irda/irnet/irnet_ppp.h b/net/irda/irnet/irnet_ppp.h
index d2beb7df8f7f..d9f8bd4ebd05 100644
--- a/net/irda/irnet/irnet_ppp.h
+++ b/net/irda/irnet/irnet_ppp.h
@@ -76,9 +76,8 @@ static ssize_t
static unsigned int
dev_irnet_poll(struct file *,
poll_table *);
-static int
- dev_irnet_ioctl(struct inode *,
- struct file *,
+static long
+ dev_irnet_ioctl(struct file *,
unsigned int,
unsigned long);
/* ------------------------ PPP INTERFACE ------------------------ */
@@ -102,7 +101,7 @@ static struct file_operations irnet_device_fops =
.read = dev_irnet_read,
.write = dev_irnet_write,
.poll = dev_irnet_poll,
- .ioctl = dev_irnet_ioctl,
+ .unlocked_ioctl = dev_irnet_ioctl,
.open = dev_irnet_open,
.release = dev_irnet_close
/* Also : llseek, readdir, mmap, flush, fsync, fasync, lock, readv, writev */
diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c
index 7b0038f45b16..58e4aee3e696 100644
--- a/net/iucv/af_iucv.c
+++ b/net/iucv/af_iucv.c
@@ -644,6 +644,7 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
}
txmsg.class = 0;
+ memcpy(&txmsg.class, skb->data, skb->len >= 4 ? 4 : skb->len);
txmsg.tag = iucv->send_tag++;
memcpy(skb->cb, &txmsg.tag, 4);
skb_queue_tail(&iucv->send_skb_q, skb);
diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c
index 918970762131..f3cd78de0c54 100644
--- a/net/iucv/iucv.c
+++ b/net/iucv/iucv.c
@@ -474,14 +474,14 @@ static void iucv_setmask_mp(void)
{
int cpu;
- preempt_disable();
+ get_online_cpus();
for_each_online_cpu(cpu)
/* Enable all cpus with a declared buffer. */
if (cpu_isset(cpu, iucv_buffer_cpumask) &&
!cpu_isset(cpu, iucv_irq_cpumask))
smp_call_function_single(cpu, iucv_allow_cpu,
NULL, 0, 1);
- preempt_enable();
+ put_online_cpus();
}
/**
@@ -497,7 +497,7 @@ static void iucv_setmask_up(void)
/* Disable all cpu but the first in cpu_irq_cpumask. */
cpumask = iucv_irq_cpumask;
cpu_clear(first_cpu(iucv_irq_cpumask), cpumask);
- for_each_cpu_mask(cpu, cpumask)
+ for_each_cpu_mask_nr(cpu, cpumask)
smp_call_function_single(cpu, iucv_block_cpu, NULL, 0, 1);
}
@@ -521,16 +521,17 @@ static int iucv_enable(void)
goto out;
/* Declare per cpu buffers. */
rc = -EIO;
- preempt_disable();
+ get_online_cpus();
for_each_online_cpu(cpu)
smp_call_function_single(cpu, iucv_declare_cpu, NULL, 0, 1);
- preempt_enable();
if (cpus_empty(iucv_buffer_cpumask))
/* No cpu could declare an iucv buffer. */
goto out_path;
+ put_online_cpus();
return 0;
out_path:
+ put_online_cpus();
kfree(iucv_path_table);
out:
return rc;
@@ -545,7 +546,9 @@ out:
*/
static void iucv_disable(void)
{
+ get_online_cpus();
on_each_cpu(iucv_retrieve_cpu, NULL, 0, 1);
+ put_online_cpus();
kfree(iucv_path_table);
}
@@ -598,7 +601,7 @@ static int __cpuinit iucv_cpu_notify(struct notifier_block *self,
return NOTIFY_OK;
}
-static struct notifier_block __cpuinitdata iucv_cpu_notifier = {
+static struct notifier_block __refdata iucv_cpu_notifier = {
.notifier_call = iucv_cpu_notify,
};
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 9e7236ff6bcc..f0fc46c8038d 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -579,25 +579,43 @@ static uint8_t pfkey_proto_from_xfrm(uint8_t proto)
return (proto ? proto : IPSEC_PROTO_ANY);
}
-static int pfkey_sadb_addr2xfrm_addr(struct sadb_address *addr,
- xfrm_address_t *xaddr)
+static inline int pfkey_sockaddr_len(sa_family_t family)
{
- switch (((struct sockaddr*)(addr + 1))->sa_family) {
+ switch (family) {
+ case AF_INET:
+ return sizeof(struct sockaddr_in);
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ case AF_INET6:
+ return sizeof(struct sockaddr_in6);
+#endif
+ }
+ return 0;
+}
+
+static
+int pfkey_sockaddr_extract(const struct sockaddr *sa, xfrm_address_t *xaddr)
+{
+ switch (sa->sa_family) {
case AF_INET:
xaddr->a4 =
- ((struct sockaddr_in *)(addr + 1))->sin_addr.s_addr;
+ ((struct sockaddr_in *)sa)->sin_addr.s_addr;
return AF_INET;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
case AF_INET6:
memcpy(xaddr->a6,
- &((struct sockaddr_in6 *)(addr + 1))->sin6_addr,
+ &((struct sockaddr_in6 *)sa)->sin6_addr,
sizeof(struct in6_addr));
return AF_INET6;
#endif
- default:
- return 0;
}
- /* NOTREACHED */
+ return 0;
+}
+
+static
+int pfkey_sadb_addr2xfrm_addr(struct sadb_address *addr, xfrm_address_t *xaddr)
+{
+ return pfkey_sockaddr_extract((struct sockaddr *)(addr + 1),
+ xaddr);
}
static struct xfrm_state *pfkey_xfrm_state_lookup(struct sadb_msg *hdr, void **ext_hdrs)
@@ -642,20 +660,11 @@ static struct xfrm_state *pfkey_xfrm_state_lookup(struct sadb_msg *hdr, void **
}
#define PFKEY_ALIGN8(a) (1 + (((a) - 1) | (8 - 1)))
+
static int
pfkey_sockaddr_size(sa_family_t family)
{
- switch (family) {
- case AF_INET:
- return PFKEY_ALIGN8(sizeof(struct sockaddr_in));
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- case AF_INET6:
- return PFKEY_ALIGN8(sizeof(struct sockaddr_in6));
-#endif
- default:
- return 0;
- }
- /* NOTREACHED */
+ return PFKEY_ALIGN8(pfkey_sockaddr_len(family));
}
static inline int pfkey_mode_from_xfrm(int mode)
@@ -687,6 +696,36 @@ static inline int pfkey_mode_to_xfrm(int mode)
}
}
+static unsigned int pfkey_sockaddr_fill(xfrm_address_t *xaddr, __be16 port,
+ struct sockaddr *sa,
+ unsigned short family)
+{
+ switch (family) {
+ case AF_INET:
+ {
+ struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+ sin->sin_family = AF_INET;
+ sin->sin_port = port;
+ sin->sin_addr.s_addr = xaddr->a4;
+ memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+ return 32;
+ }
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ case AF_INET6:
+ {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = port;
+ sin6->sin6_flowinfo = 0;
+ ipv6_addr_copy(&sin6->sin6_addr, (struct in6_addr *)xaddr->a6);
+ sin6->sin6_scope_id = 0;
+ return 128;
+ }
+#endif
+ }
+ return 0;
+}
+
static struct sk_buff *__pfkey_xfrm_state2msg(struct xfrm_state *x,
int add_keys, int hsc)
{
@@ -697,13 +736,9 @@ static struct sk_buff *__pfkey_xfrm_state2msg(struct xfrm_state *x,
struct sadb_address *addr;
struct sadb_key *key;
struct sadb_x_sa2 *sa2;
- struct sockaddr_in *sin;
struct sadb_x_sec_ctx *sec_ctx;
struct xfrm_sec_ctx *xfrm_ctx;
int ctx_size = 0;
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- struct sockaddr_in6 *sin6;
-#endif
int size;
int auth_key_size = 0;
int encrypt_key_size = 0;
@@ -732,14 +767,7 @@ static struct sk_buff *__pfkey_xfrm_state2msg(struct xfrm_state *x,
}
/* identity & sensitivity */
-
- if ((x->props.family == AF_INET &&
- x->sel.saddr.a4 != x->props.saddr.a4)
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- || (x->props.family == AF_INET6 &&
- memcmp (x->sel.saddr.a6, x->props.saddr.a6, sizeof (struct in6_addr)))
-#endif
- )
+ if (xfrm_addr_cmp(&x->sel.saddr, &x->props.saddr, x->props.family))
size += sizeof(struct sadb_address) + sockaddr_size;
if (add_keys) {
@@ -861,29 +889,12 @@ static struct sk_buff *__pfkey_xfrm_state2msg(struct xfrm_state *x,
protocol's number." - RFC2367 */
addr->sadb_address_proto = 0;
addr->sadb_address_reserved = 0;
- if (x->props.family == AF_INET) {
- addr->sadb_address_prefixlen = 32;
- sin = (struct sockaddr_in *) (addr + 1);
- sin->sin_family = AF_INET;
- sin->sin_addr.s_addr = x->props.saddr.a4;
- sin->sin_port = 0;
- memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
- }
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- else if (x->props.family == AF_INET6) {
- addr->sadb_address_prefixlen = 128;
-
- sin6 = (struct sockaddr_in6 *) (addr + 1);
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = 0;
- sin6->sin6_flowinfo = 0;
- memcpy(&sin6->sin6_addr, x->props.saddr.a6,
- sizeof(struct in6_addr));
- sin6->sin6_scope_id = 0;
- }
-#endif
- else
+ addr->sadb_address_prefixlen =
+ pfkey_sockaddr_fill(&x->props.saddr, 0,
+ (struct sockaddr *) (addr + 1),
+ x->props.family);
+ if (!addr->sadb_address_prefixlen)
BUG();
/* dst address */
@@ -894,70 +905,32 @@ static struct sk_buff *__pfkey_xfrm_state2msg(struct xfrm_state *x,
sizeof(uint64_t);
addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
addr->sadb_address_proto = 0;
- addr->sadb_address_prefixlen = 32; /* XXX */
addr->sadb_address_reserved = 0;
- if (x->props.family == AF_INET) {
- sin = (struct sockaddr_in *) (addr + 1);
- sin->sin_family = AF_INET;
- sin->sin_addr.s_addr = x->id.daddr.a4;
- sin->sin_port = 0;
- memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
- if (x->sel.saddr.a4 != x->props.saddr.a4) {
- addr = (struct sadb_address*) skb_put(skb,
- sizeof(struct sadb_address)+sockaddr_size);
- addr->sadb_address_len =
- (sizeof(struct sadb_address)+sockaddr_size)/
- sizeof(uint64_t);
- addr->sadb_address_exttype = SADB_EXT_ADDRESS_PROXY;
- addr->sadb_address_proto =
- pfkey_proto_from_xfrm(x->sel.proto);
- addr->sadb_address_prefixlen = x->sel.prefixlen_s;
- addr->sadb_address_reserved = 0;
-
- sin = (struct sockaddr_in *) (addr + 1);
- sin->sin_family = AF_INET;
- sin->sin_addr.s_addr = x->sel.saddr.a4;
- sin->sin_port = x->sel.sport;
- memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
- }
- }
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- else if (x->props.family == AF_INET6) {
- addr->sadb_address_prefixlen = 128;
+ addr->sadb_address_prefixlen =
+ pfkey_sockaddr_fill(&x->id.daddr, 0,
+ (struct sockaddr *) (addr + 1),
+ x->props.family);
+ if (!addr->sadb_address_prefixlen)
+ BUG();
- sin6 = (struct sockaddr_in6 *) (addr + 1);
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = 0;
- sin6->sin6_flowinfo = 0;
- memcpy(&sin6->sin6_addr, x->id.daddr.a6, sizeof(struct in6_addr));
- sin6->sin6_scope_id = 0;
+ if (xfrm_addr_cmp(&x->sel.saddr, &x->props.saddr,
+ x->props.family)) {
+ addr = (struct sadb_address*) skb_put(skb,
+ sizeof(struct sadb_address)+sockaddr_size);
+ addr->sadb_address_len =
+ (sizeof(struct sadb_address)+sockaddr_size)/
+ sizeof(uint64_t);
+ addr->sadb_address_exttype = SADB_EXT_ADDRESS_PROXY;
+ addr->sadb_address_proto =
+ pfkey_proto_from_xfrm(x->sel.proto);
+ addr->sadb_address_prefixlen = x->sel.prefixlen_s;
+ addr->sadb_address_reserved = 0;
- if (memcmp (x->sel.saddr.a6, x->props.saddr.a6,
- sizeof(struct in6_addr))) {
- addr = (struct sadb_address *) skb_put(skb,
- sizeof(struct sadb_address)+sockaddr_size);
- addr->sadb_address_len =
- (sizeof(struct sadb_address)+sockaddr_size)/
- sizeof(uint64_t);
- addr->sadb_address_exttype = SADB_EXT_ADDRESS_PROXY;
- addr->sadb_address_proto =
- pfkey_proto_from_xfrm(x->sel.proto);
- addr->sadb_address_prefixlen = x->sel.prefixlen_s;
- addr->sadb_address_reserved = 0;
-
- sin6 = (struct sockaddr_in6 *) (addr + 1);
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = x->sel.sport;
- sin6->sin6_flowinfo = 0;
- memcpy(&sin6->sin6_addr, x->sel.saddr.a6,
- sizeof(struct in6_addr));
- sin6->sin6_scope_id = 0;
- }
+ pfkey_sockaddr_fill(&x->sel.saddr, x->sel.sport,
+ (struct sockaddr *) (addr + 1),
+ x->props.family);
}
-#endif
- else
- BUG();
/* auth key */
if (add_keys && auth_key_size) {
@@ -1251,7 +1224,7 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr,
x->sel.prefixlen_s = addr->sadb_address_prefixlen;
}
- if (x->props.mode == XFRM_MODE_TRANSPORT)
+ if (!x->sel.family)
x->sel.family = x->props.family;
if (ext_hdrs[SADB_X_EXT_NAT_T_TYPE-1]) {
@@ -1853,10 +1826,6 @@ static int
parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq)
{
struct xfrm_tmpl *t = xp->xfrm_vec + xp->xfrm_nr;
- struct sockaddr_in *sin;
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- struct sockaddr_in6 *sin6;
-#endif
int mode;
if (xp->xfrm_nr >= XFRM_MAX_DEPTH)
@@ -1881,31 +1850,19 @@ parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq)
/* addresses present only in tunnel mode */
if (t->mode == XFRM_MODE_TUNNEL) {
- struct sockaddr *sa;
- sa = (struct sockaddr *)(rq+1);
- switch(sa->sa_family) {
- case AF_INET:
- sin = (struct sockaddr_in*)sa;
- t->saddr.a4 = sin->sin_addr.s_addr;
- sin++;
- if (sin->sin_family != AF_INET)
- return -EINVAL;
- t->id.daddr.a4 = sin->sin_addr.s_addr;
- break;
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- case AF_INET6:
- sin6 = (struct sockaddr_in6*)sa;
- memcpy(t->saddr.a6, &sin6->sin6_addr, sizeof(struct in6_addr));
- sin6++;
- if (sin6->sin6_family != AF_INET6)
- return -EINVAL;
- memcpy(t->id.daddr.a6, &sin6->sin6_addr, sizeof(struct in6_addr));
- break;
-#endif
- default:
+ u8 *sa = (u8 *) (rq + 1);
+ int family, socklen;
+
+ family = pfkey_sockaddr_extract((struct sockaddr *)sa,
+ &t->saddr);
+ if (!family)
return -EINVAL;
- }
- t->encap_family = sa->sa_family;
+
+ socklen = pfkey_sockaddr_len(family);
+ if (pfkey_sockaddr_extract((struct sockaddr *)(sa + socklen),
+ &t->id.daddr) != family)
+ return -EINVAL;
+ t->encap_family = family;
} else
t->encap_family = xp->family;
@@ -1952,9 +1909,7 @@ static int pfkey_xfrm_policy2msg_size(struct xfrm_policy *xp)
for (i=0; i<xp->xfrm_nr; i++) {
t = xp->xfrm_vec + i;
- socklen += (t->encap_family == AF_INET ?
- sizeof(struct sockaddr_in) :
- sizeof(struct sockaddr_in6));
+ socklen += pfkey_sockaddr_len(t->encap_family);
}
return sizeof(struct sadb_msg) +
@@ -1987,18 +1942,12 @@ static int pfkey_xfrm_policy2msg(struct sk_buff *skb, struct xfrm_policy *xp, in
struct sadb_address *addr;
struct sadb_lifetime *lifetime;
struct sadb_x_policy *pol;
- struct sockaddr_in *sin;
struct sadb_x_sec_ctx *sec_ctx;
struct xfrm_sec_ctx *xfrm_ctx;
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- struct sockaddr_in6 *sin6;
-#endif
int i;
int size;
int sockaddr_size = pfkey_sockaddr_size(xp->family);
- int socklen = (xp->family == AF_INET ?
- sizeof(struct sockaddr_in) :
- sizeof(struct sockaddr_in6));
+ int socklen = pfkey_sockaddr_len(xp->family);
size = pfkey_xfrm_policy2msg_size(xp);
@@ -2016,26 +1965,10 @@ static int pfkey_xfrm_policy2msg(struct sk_buff *skb, struct xfrm_policy *xp, in
addr->sadb_address_proto = pfkey_proto_from_xfrm(xp->selector.proto);
addr->sadb_address_prefixlen = xp->selector.prefixlen_s;
addr->sadb_address_reserved = 0;
- /* src address */
- if (xp->family == AF_INET) {
- sin = (struct sockaddr_in *) (addr + 1);
- sin->sin_family = AF_INET;
- sin->sin_addr.s_addr = xp->selector.saddr.a4;
- sin->sin_port = xp->selector.sport;
- memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
- }
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- else if (xp->family == AF_INET6) {
- sin6 = (struct sockaddr_in6 *) (addr + 1);
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = xp->selector.sport;
- sin6->sin6_flowinfo = 0;
- memcpy(&sin6->sin6_addr, xp->selector.saddr.a6,
- sizeof(struct in6_addr));
- sin6->sin6_scope_id = 0;
- }
-#endif
- else
+ if (!pfkey_sockaddr_fill(&xp->selector.saddr,
+ xp->selector.sport,
+ (struct sockaddr *) (addr + 1),
+ xp->family))
BUG();
/* dst address */
@@ -2048,26 +1981,10 @@ static int pfkey_xfrm_policy2msg(struct sk_buff *skb, struct xfrm_policy *xp, in
addr->sadb_address_proto = pfkey_proto_from_xfrm(xp->selector.proto);
addr->sadb_address_prefixlen = xp->selector.prefixlen_d;
addr->sadb_address_reserved = 0;
- if (xp->family == AF_INET) {
- sin = (struct sockaddr_in *) (addr + 1);
- sin->sin_family = AF_INET;
- sin->sin_addr.s_addr = xp->selector.daddr.a4;
- sin->sin_port = xp->selector.dport;
- memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
- }
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- else if (xp->family == AF_INET6) {
- sin6 = (struct sockaddr_in6 *) (addr + 1);
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = xp->selector.dport;
- sin6->sin6_flowinfo = 0;
- memcpy(&sin6->sin6_addr, xp->selector.daddr.a6,
- sizeof(struct in6_addr));
- sin6->sin6_scope_id = 0;
- }
-#endif
- else
- BUG();
+
+ pfkey_sockaddr_fill(&xp->selector.daddr, xp->selector.dport,
+ (struct sockaddr *) (addr + 1),
+ xp->family);
/* hard time */
lifetime = (struct sadb_lifetime *) skb_put(skb,
@@ -2121,12 +2038,13 @@ static int pfkey_xfrm_policy2msg(struct sk_buff *skb, struct xfrm_policy *xp, in
int mode;
req_size = sizeof(struct sadb_x_ipsecrequest);
- if (t->mode == XFRM_MODE_TUNNEL)
- req_size += ((t->encap_family == AF_INET ?
- sizeof(struct sockaddr_in) :
- sizeof(struct sockaddr_in6)) * 2);
- else
+ if (t->mode == XFRM_MODE_TUNNEL) {
+ socklen = pfkey_sockaddr_len(t->encap_family);
+ req_size += socklen * 2;
+ } else {
size -= 2*socklen;
+ socklen = 0;
+ }
rq = (void*)skb_put(skb, req_size);
pol->sadb_x_policy_len += req_size/8;
memset(rq, 0, sizeof(*rq));
@@ -2141,42 +2059,15 @@ static int pfkey_xfrm_policy2msg(struct sk_buff *skb, struct xfrm_policy *xp, in
if (t->optional)
rq->sadb_x_ipsecrequest_level = IPSEC_LEVEL_USE;
rq->sadb_x_ipsecrequest_reqid = t->reqid;
+
if (t->mode == XFRM_MODE_TUNNEL) {
- switch (t->encap_family) {
- case AF_INET:
- sin = (void*)(rq+1);
- sin->sin_family = AF_INET;
- sin->sin_addr.s_addr = t->saddr.a4;
- sin->sin_port = 0;
- memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
- sin++;
- sin->sin_family = AF_INET;
- sin->sin_addr.s_addr = t->id.daddr.a4;
- sin->sin_port = 0;
- memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
- break;
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- case AF_INET6:
- sin6 = (void*)(rq+1);
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = 0;
- sin6->sin6_flowinfo = 0;
- memcpy(&sin6->sin6_addr, t->saddr.a6,
- sizeof(struct in6_addr));
- sin6->sin6_scope_id = 0;
-
- sin6++;
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = 0;
- sin6->sin6_flowinfo = 0;
- memcpy(&sin6->sin6_addr, t->id.daddr.a6,
- sizeof(struct in6_addr));
- sin6->sin6_scope_id = 0;
- break;
-#endif
- default:
- break;
- }
+ u8 *sa = (void *)(rq + 1);
+ pfkey_sockaddr_fill(&t->saddr, 0,
+ (struct sockaddr *)sa,
+ t->encap_family);
+ pfkey_sockaddr_fill(&t->id.daddr, 0,
+ (struct sockaddr *) (sa + socklen),
+ t->encap_family);
}
}
@@ -2459,61 +2350,31 @@ out:
#ifdef CONFIG_NET_KEY_MIGRATE
static int pfkey_sockaddr_pair_size(sa_family_t family)
{
- switch (family) {
- case AF_INET:
- return PFKEY_ALIGN8(sizeof(struct sockaddr_in) * 2);
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- case AF_INET6:
- return PFKEY_ALIGN8(sizeof(struct sockaddr_in6) * 2);
-#endif
- default:
- return 0;
- }
- /* NOTREACHED */
+ return PFKEY_ALIGN8(pfkey_sockaddr_len(family) * 2);
}
static int parse_sockaddr_pair(struct sadb_x_ipsecrequest *rq,
xfrm_address_t *saddr, xfrm_address_t *daddr,
u16 *family)
{
- struct sockaddr *sa = (struct sockaddr *)(rq + 1);
+ u8 *sa = (u8 *) (rq + 1);
+ int af, socklen;
+
if (rq->sadb_x_ipsecrequest_len <
- pfkey_sockaddr_pair_size(sa->sa_family))
+ pfkey_sockaddr_pair_size(((struct sockaddr *)sa)->sa_family))
return -EINVAL;
- switch (sa->sa_family) {
- case AF_INET:
- {
- struct sockaddr_in *sin;
- sin = (struct sockaddr_in *)sa;
- if ((sin+1)->sin_family != AF_INET)
- return -EINVAL;
- memcpy(&saddr->a4, &sin->sin_addr, sizeof(saddr->a4));
- sin++;
- memcpy(&daddr->a4, &sin->sin_addr, sizeof(daddr->a4));
- *family = AF_INET;
- break;
- }
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- case AF_INET6:
- {
- struct sockaddr_in6 *sin6;
- sin6 = (struct sockaddr_in6 *)sa;
- if ((sin6+1)->sin6_family != AF_INET6)
- return -EINVAL;
- memcpy(&saddr->a6, &sin6->sin6_addr,
- sizeof(saddr->a6));
- sin6++;
- memcpy(&daddr->a6, &sin6->sin6_addr,
- sizeof(daddr->a6));
- *family = AF_INET6;
- break;
- }
-#endif
- default:
+ af = pfkey_sockaddr_extract((struct sockaddr *) sa,
+ saddr);
+ if (!af)
+ return -EINVAL;
+
+ socklen = pfkey_sockaddr_len(af);
+ if (pfkey_sockaddr_extract((struct sockaddr *) (sa + socklen),
+ daddr) != af)
return -EINVAL;
- }
+ *family = af;
return 0;
}
@@ -3030,6 +2891,9 @@ static int key_notify_sa_expire(struct xfrm_state *x, struct km_event *c)
static int pfkey_send_notify(struct xfrm_state *x, struct km_event *c)
{
+ if (atomic_read(&pfkey_socks_nr) == 0)
+ return 0;
+
switch (c->event) {
case XFRM_MSG_EXPIRE:
return key_notify_sa_expire(x, c);
@@ -3091,10 +2955,6 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct
struct sadb_msg *hdr;
struct sadb_address *addr;
struct sadb_x_policy *pol;
- struct sockaddr_in *sin;
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- struct sockaddr_in6 *sin6;
-#endif
int sockaddr_size;
int size;
struct sadb_x_sec_ctx *sec_ctx;
@@ -3143,29 +3003,11 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct
addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
addr->sadb_address_proto = 0;
addr->sadb_address_reserved = 0;
- if (x->props.family == AF_INET) {
- addr->sadb_address_prefixlen = 32;
-
- sin = (struct sockaddr_in *) (addr + 1);
- sin->sin_family = AF_INET;
- sin->sin_addr.s_addr = x->props.saddr.a4;
- sin->sin_port = 0;
- memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
- }
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- else if (x->props.family == AF_INET6) {
- addr->sadb_address_prefixlen = 128;
-
- sin6 = (struct sockaddr_in6 *) (addr + 1);
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = 0;
- sin6->sin6_flowinfo = 0;
- memcpy(&sin6->sin6_addr,
- x->props.saddr.a6, sizeof(struct in6_addr));
- sin6->sin6_scope_id = 0;
- }
-#endif
- else
+ addr->sadb_address_prefixlen =
+ pfkey_sockaddr_fill(&x->props.saddr, 0,
+ (struct sockaddr *) (addr + 1),
+ x->props.family);
+ if (!addr->sadb_address_prefixlen)
BUG();
/* dst address */
@@ -3177,29 +3019,11 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct
addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
addr->sadb_address_proto = 0;
addr->sadb_address_reserved = 0;
- if (x->props.family == AF_INET) {
- addr->sadb_address_prefixlen = 32;
-
- sin = (struct sockaddr_in *) (addr + 1);
- sin->sin_family = AF_INET;
- sin->sin_addr.s_addr = x->id.daddr.a4;
- sin->sin_port = 0;
- memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
- }
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- else if (x->props.family == AF_INET6) {
- addr->sadb_address_prefixlen = 128;
-
- sin6 = (struct sockaddr_in6 *) (addr + 1);
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = 0;
- sin6->sin6_flowinfo = 0;
- memcpy(&sin6->sin6_addr,
- x->id.daddr.a6, sizeof(struct in6_addr));
- sin6->sin6_scope_id = 0;
- }
-#endif
- else
+ addr->sadb_address_prefixlen =
+ pfkey_sockaddr_fill(&x->id.daddr, 0,
+ (struct sockaddr *) (addr + 1),
+ x->props.family);
+ if (!addr->sadb_address_prefixlen)
BUG();
pol = (struct sadb_x_policy *) skb_put(skb, sizeof(struct sadb_x_policy));
@@ -3325,10 +3149,6 @@ static int pfkey_send_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr,
struct sadb_sa *sa;
struct sadb_address *addr;
struct sadb_x_nat_t_port *n_port;
- struct sockaddr_in *sin;
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- struct sockaddr_in6 *sin6;
-#endif
int sockaddr_size;
int size;
__u8 satype = (x->id.proto == IPPROTO_ESP ? SADB_SATYPE_ESP : 0);
@@ -3392,29 +3212,11 @@ static int pfkey_send_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr,
addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
addr->sadb_address_proto = 0;
addr->sadb_address_reserved = 0;
- if (x->props.family == AF_INET) {
- addr->sadb_address_prefixlen = 32;
-
- sin = (struct sockaddr_in *) (addr + 1);
- sin->sin_family = AF_INET;
- sin->sin_addr.s_addr = x->props.saddr.a4;
- sin->sin_port = 0;
- memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
- }
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- else if (x->props.family == AF_INET6) {
- addr->sadb_address_prefixlen = 128;
-
- sin6 = (struct sockaddr_in6 *) (addr + 1);
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = 0;
- sin6->sin6_flowinfo = 0;
- memcpy(&sin6->sin6_addr,
- x->props.saddr.a6, sizeof(struct in6_addr));
- sin6->sin6_scope_id = 0;
- }
-#endif
- else
+ addr->sadb_address_prefixlen =
+ pfkey_sockaddr_fill(&x->props.saddr, 0,
+ (struct sockaddr *) (addr + 1),
+ x->props.family);
+ if (!addr->sadb_address_prefixlen)
BUG();
/* NAT_T_SPORT (old port) */
@@ -3433,28 +3235,11 @@ static int pfkey_send_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr,
addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
addr->sadb_address_proto = 0;
addr->sadb_address_reserved = 0;
- if (x->props.family == AF_INET) {
- addr->sadb_address_prefixlen = 32;
-
- sin = (struct sockaddr_in *) (addr + 1);
- sin->sin_family = AF_INET;
- sin->sin_addr.s_addr = ipaddr->a4;
- sin->sin_port = 0;
- memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
- }
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- else if (x->props.family == AF_INET6) {
- addr->sadb_address_prefixlen = 128;
-
- sin6 = (struct sockaddr_in6 *) (addr + 1);
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = 0;
- sin6->sin6_flowinfo = 0;
- memcpy(&sin6->sin6_addr, &ipaddr->a6, sizeof(struct in6_addr));
- sin6->sin6_scope_id = 0;
- }
-#endif
- else
+ addr->sadb_address_prefixlen =
+ pfkey_sockaddr_fill(ipaddr, 0,
+ (struct sockaddr *) (addr + 1),
+ x->props.family);
+ if (!addr->sadb_address_prefixlen)
BUG();
/* NAT_T_DPORT (new port) */
@@ -3472,10 +3257,6 @@ static int set_sadb_address(struct sk_buff *skb, int sasize, int type,
struct xfrm_selector *sel)
{
struct sadb_address *addr;
- struct sockaddr_in *sin;
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- struct sockaddr_in6 *sin6;
-#endif
addr = (struct sadb_address *)skb_put(skb, sizeof(struct sadb_address) + sasize);
addr->sadb_address_len = (sizeof(struct sadb_address) + sasize)/8;
addr->sadb_address_exttype = type;
@@ -3484,50 +3265,16 @@ static int set_sadb_address(struct sk_buff *skb, int sasize, int type,
switch (type) {
case SADB_EXT_ADDRESS_SRC:
- if (sel->family == AF_INET) {
- addr->sadb_address_prefixlen = sel->prefixlen_s;
- sin = (struct sockaddr_in *)(addr + 1);
- sin->sin_family = AF_INET;
- memcpy(&sin->sin_addr.s_addr, &sel->saddr,
- sizeof(sin->sin_addr.s_addr));
- sin->sin_port = 0;
- memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
- }
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- else if (sel->family == AF_INET6) {
- addr->sadb_address_prefixlen = sel->prefixlen_s;
- sin6 = (struct sockaddr_in6 *)(addr + 1);
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = 0;
- sin6->sin6_flowinfo = 0;
- sin6->sin6_scope_id = 0;
- memcpy(&sin6->sin6_addr.s6_addr, &sel->saddr,
- sizeof(sin6->sin6_addr.s6_addr));
- }
-#endif
+ addr->sadb_address_prefixlen = sel->prefixlen_s;
+ pfkey_sockaddr_fill(&sel->saddr, 0,
+ (struct sockaddr *)(addr + 1),
+ sel->family);
break;
case SADB_EXT_ADDRESS_DST:
- if (sel->family == AF_INET) {
- addr->sadb_address_prefixlen = sel->prefixlen_d;
- sin = (struct sockaddr_in *)(addr + 1);
- sin->sin_family = AF_INET;
- memcpy(&sin->sin_addr.s_addr, &sel->daddr,
- sizeof(sin->sin_addr.s_addr));
- sin->sin_port = 0;
- memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
- }
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- else if (sel->family == AF_INET6) {
- addr->sadb_address_prefixlen = sel->prefixlen_d;
- sin6 = (struct sockaddr_in6 *)(addr + 1);
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = 0;
- sin6->sin6_flowinfo = 0;
- sin6->sin6_scope_id = 0;
- memcpy(&sin6->sin6_addr.s6_addr, &sel->daddr,
- sizeof(sin6->sin6_addr.s6_addr));
- }
-#endif
+ addr->sadb_address_prefixlen = sel->prefixlen_d;
+ pfkey_sockaddr_fill(&sel->daddr, 0,
+ (struct sockaddr *)(addr + 1),
+ sel->family);
break;
default:
return -EINVAL;
@@ -3542,10 +3289,8 @@ static int set_ipsecrequest(struct sk_buff *skb,
xfrm_address_t *src, xfrm_address_t *dst)
{
struct sadb_x_ipsecrequest *rq;
- struct sockaddr_in *sin;
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- struct sockaddr_in6 *sin6;
-#endif
+ u8 *sa;
+ int socklen = pfkey_sockaddr_len(family);
int size_req;
size_req = sizeof(struct sadb_x_ipsecrequest) +
@@ -3559,38 +3304,10 @@ static int set_ipsecrequest(struct sk_buff *skb,
rq->sadb_x_ipsecrequest_level = level;
rq->sadb_x_ipsecrequest_reqid = reqid;
- switch (family) {
- case AF_INET:
- sin = (struct sockaddr_in *)(rq + 1);
- sin->sin_family = AF_INET;
- memcpy(&sin->sin_addr.s_addr, src,
- sizeof(sin->sin_addr.s_addr));
- sin++;
- sin->sin_family = AF_INET;
- memcpy(&sin->sin_addr.s_addr, dst,
- sizeof(sin->sin_addr.s_addr));
- break;
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- case AF_INET6:
- sin6 = (struct sockaddr_in6 *)(rq + 1);
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = 0;
- sin6->sin6_flowinfo = 0;
- sin6->sin6_scope_id = 0;
- memcpy(&sin6->sin6_addr.s6_addr, src,
- sizeof(sin6->sin6_addr.s6_addr));
- sin6++;
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = 0;
- sin6->sin6_flowinfo = 0;
- sin6->sin6_scope_id = 0;
- memcpy(&sin6->sin6_addr.s6_addr, dst,
- sizeof(sin6->sin6_addr.s6_addr));
- break;
-#endif
- default:
+ sa = (u8 *) (rq + 1);
+ if (!pfkey_sockaddr_fill(src, 0, (struct sockaddr *)sa, family) ||
+ !pfkey_sockaddr_fill(dst, 0, (struct sockaddr *)(sa + socklen), family))
return -EINVAL;
- }
return 0;
}
diff --git a/net/llc/llc_sap.c b/net/llc/llc_sap.c
index e2ddde755019..008de1fc42ca 100644
--- a/net/llc/llc_sap.c
+++ b/net/llc/llc_sap.c
@@ -286,12 +286,14 @@ void llc_build_and_send_xid_pkt(struct llc_sap *sap, struct sk_buff *skb,
*
* Sends received pdus to the sap state machine.
*/
-static void llc_sap_rcv(struct llc_sap *sap, struct sk_buff *skb)
+static void llc_sap_rcv(struct llc_sap *sap, struct sk_buff *skb,
+ struct sock *sk)
{
struct llc_sap_state_ev *ev = llc_sap_ev(skb);
ev->type = LLC_SAP_EV_TYPE_PDU;
ev->reason = 0;
+ skb->sk = sk;
llc_sap_state_process(sap, skb);
}
@@ -360,8 +362,7 @@ static void llc_sap_mcast(struct llc_sap *sap,
break;
sock_hold(sk);
- skb_set_owner_r(skb1, sk);
- llc_sap_rcv(sap, skb1);
+ llc_sap_rcv(sap, skb1, sk);
sock_put(sk);
}
read_unlock_bh(&sap->sk_list.lock);
@@ -381,8 +382,7 @@ void llc_sap_handler(struct llc_sap *sap, struct sk_buff *skb)
} else {
struct sock *sk = llc_lookup_dgram(sap, &laddr);
if (sk) {
- skb_set_owner_r(skb, sk);
- llc_sap_rcv(sap, skb);
+ llc_sap_rcv(sap, skb, sk);
sock_put(sk);
} else
kfree_skb(skb);
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index a24b459dd45a..590e00b2766c 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -7,11 +7,23 @@ config MAC80211
select CRC32
select WIRELESS_EXT
select CFG80211
- select NET_SCH_FIFO
---help---
This option enables the hardware independent IEEE 802.11
networking stack.
+config MAC80211_QOS
+ def_bool y
+ depends on MAC80211
+ depends on NET_SCHED
+ depends on NETDEVICES_MULTIQUEUE
+
+comment "QoS/HT support disabled"
+ depends on MAC80211 && !MAC80211_QOS
+comment "QoS/HT support needs CONFIG_NET_SCHED"
+ depends on MAC80211 && !NET_SCHED
+comment "QoS/HT support needs CONFIG_NETDEVICES_MULTIQUEUE"
+ depends on MAC80211 && !NETDEVICES_MULTIQUEUE
+
menu "Rate control algorithm selection"
depends on MAC80211 != n
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile
index 4e5847fd316c..1d2a4e010e5c 100644
--- a/net/mac80211/Makefile
+++ b/net/mac80211/Makefile
@@ -29,7 +29,7 @@ mac80211-y := \
event.o
mac80211-$(CONFIG_MAC80211_LEDS) += led.o
-mac80211-$(CONFIG_NET_SCHED) += wme.o
+mac80211-$(CONFIG_MAC80211_QOS) += wme.o
mac80211-$(CONFIG_MAC80211_DEBUGFS) += \
debugfs.o \
debugfs_sta.o \
diff --git a/net/mac80211/aes_ccm.c b/net/mac80211/aes_ccm.c
index 59f1691f62c8..4d4c2dfcf9a0 100644
--- a/net/mac80211/aes_ccm.c
+++ b/net/mac80211/aes_ccm.c
@@ -134,7 +134,7 @@ int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch,
}
-struct crypto_cipher * ieee80211_aes_key_setup_encrypt(const u8 key[])
+struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[])
{
struct crypto_cipher *tfm;
diff --git a/net/mac80211/aes_ccm.h b/net/mac80211/aes_ccm.h
index 885f19030b29..8cd0f14aab4d 100644
--- a/net/mac80211/aes_ccm.h
+++ b/net/mac80211/aes_ccm.h
@@ -14,7 +14,7 @@
#define AES_BLOCK_LEN 16
-struct crypto_cipher * ieee80211_aes_key_setup_encrypt(const u8 key[]);
+struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[]);
void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch,
u8 *b_0, u8 *aad, u8 *data, size_t data_len,
u8 *cdata, u8 *mic);
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 699d97b8de5e..81087281b031 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -256,8 +256,8 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
case ALG_TKIP:
params.cipher = WLAN_CIPHER_SUITE_TKIP;
- iv32 = key->u.tkip.iv32;
- iv16 = key->u.tkip.iv16;
+ iv32 = key->u.tkip.tx.iv32;
+ iv16 = key->u.tkip.tx.iv16;
if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
sdata->local->ops->get_tkip_seq)
@@ -602,6 +602,7 @@ static void sta_apply_parameters(struct ieee80211_local *local,
*/
if (params->station_flags & STATION_FLAG_CHANGED) {
+ spin_lock_bh(&sta->lock);
sta->flags &= ~WLAN_STA_AUTHORIZED;
if (params->station_flags & STATION_FLAG_AUTHORIZED)
sta->flags |= WLAN_STA_AUTHORIZED;
@@ -613,6 +614,7 @@ static void sta_apply_parameters(struct ieee80211_local *local,
sta->flags &= ~WLAN_STA_WME;
if (params->station_flags & STATION_FLAG_WME)
sta->flags |= WLAN_STA_WME;
+ spin_unlock_bh(&sta->lock);
}
/*
@@ -672,7 +674,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
if (params->vlan) {
sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
- if (sdata->vif.type != IEEE80211_IF_TYPE_VLAN ||
+ if (sdata->vif.type != IEEE80211_IF_TYPE_VLAN &&
sdata->vif.type != IEEE80211_IF_TYPE_AP)
return -EINVAL;
} else
@@ -760,7 +762,7 @@ static int ieee80211_change_station(struct wiphy *wiphy,
if (params->vlan && params->vlan != sta->sdata->dev) {
vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
- if (vlansdata->vif.type != IEEE80211_IF_TYPE_VLAN ||
+ if (vlansdata->vif.type != IEEE80211_IF_TYPE_VLAN &&
vlansdata->vif.type != IEEE80211_IF_TYPE_AP) {
rcu_read_unlock();
return -EINVAL;
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 1cccbfd781f6..d20d90eead1f 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -197,45 +197,6 @@ DEBUGFS_STATS_FILE(rx_handlers_fragments, 20, "%u",
DEBUGFS_STATS_FILE(tx_status_drop, 20, "%u",
local->tx_status_drop);
-static ssize_t stats_wme_rx_queue_read(struct file *file,
- char __user *userbuf,
- size_t count, loff_t *ppos)
-{
- struct ieee80211_local *local = file->private_data;
- char buf[NUM_RX_DATA_QUEUES*15], *p = buf;
- int i;
-
- for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
- p += scnprintf(p, sizeof(buf)+buf-p,
- "%u\n", local->wme_rx_queue[i]);
-
- return simple_read_from_buffer(userbuf, count, ppos, buf, p-buf);
-}
-
-static const struct file_operations stats_wme_rx_queue_ops = {
- .read = stats_wme_rx_queue_read,
- .open = mac80211_open_file_generic,
-};
-
-static ssize_t stats_wme_tx_queue_read(struct file *file,
- char __user *userbuf,
- size_t count, loff_t *ppos)
-{
- struct ieee80211_local *local = file->private_data;
- char buf[NUM_TX_DATA_QUEUES*15], *p = buf;
- int i;
-
- for (i = 0; i < NUM_TX_DATA_QUEUES; i++)
- p += scnprintf(p, sizeof(buf)+buf-p,
- "%u\n", local->wme_tx_queue[i]);
-
- return simple_read_from_buffer(userbuf, count, ppos, buf, p-buf);
-}
-
-static const struct file_operations stats_wme_tx_queue_ops = {
- .read = stats_wme_tx_queue_read,
- .open = mac80211_open_file_generic,
-};
#endif
DEBUGFS_DEVSTATS_FILE(dot11ACKFailureCount);
@@ -303,8 +264,6 @@ void debugfs_hw_add(struct ieee80211_local *local)
DEBUGFS_STATS_ADD(rx_expand_skb_head2);
DEBUGFS_STATS_ADD(rx_handlers_fragments);
DEBUGFS_STATS_ADD(tx_status_drop);
- DEBUGFS_STATS_ADD(wme_tx_queue);
- DEBUGFS_STATS_ADD(wme_rx_queue);
#endif
DEBUGFS_STATS_ADD(dot11ACKFailureCount);
DEBUGFS_STATS_ADD(dot11RTSFailureCount);
@@ -356,8 +315,6 @@ void debugfs_hw_del(struct ieee80211_local *local)
DEBUGFS_STATS_DEL(rx_expand_skb_head2);
DEBUGFS_STATS_DEL(rx_handlers_fragments);
DEBUGFS_STATS_DEL(tx_status_drop);
- DEBUGFS_STATS_DEL(wme_tx_queue);
- DEBUGFS_STATS_DEL(wme_rx_queue);
#endif
DEBUGFS_STATS_DEL(dot11ACKFailureCount);
DEBUGFS_STATS_DEL(dot11RTSFailureCount);
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c
index 19efc3a6a932..7439b63df5d0 100644
--- a/net/mac80211/debugfs_key.c
+++ b/net/mac80211/debugfs_key.c
@@ -97,8 +97,8 @@ static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf,
break;
case ALG_TKIP:
len = scnprintf(buf, sizeof(buf), "%08x %04x\n",
- key->u.tkip.iv32,
- key->u.tkip.iv16);
+ key->u.tkip.tx.iv32,
+ key->u.tkip.tx.iv16);
break;
case ALG_CCMP:
tpn = key->u.ccmp.tx_pn;
@@ -128,8 +128,8 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf,
for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
p += scnprintf(p, sizeof(buf)+buf-p,
"%08x %04x\n",
- key->u.tkip.iv32_rx[i],
- key->u.tkip.iv16_rx[i]);
+ key->u.tkip.rx[i].iv32,
+ key->u.tkip.rx[i].iv16);
len = p - buf;
break;
case ALG_CCMP:
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index e3326d046944..b2089b2da48a 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -155,7 +155,6 @@ static const struct file_operations name##_ops = { \
__IEEE80211_IF_WFILE(name)
/* common attributes */
-IEEE80211_IF_FILE(channel_use, channel_use, DEC);
IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
/* STA/IBSS attributes */
@@ -248,7 +247,6 @@ IEEE80211_IF_WFILE(min_discovery_timeout,
static void add_sta_files(struct ieee80211_sub_if_data *sdata)
{
- DEBUGFS_ADD(channel_use, sta);
DEBUGFS_ADD(drop_unencrypted, sta);
DEBUGFS_ADD(state, sta);
DEBUGFS_ADD(bssid, sta);
@@ -269,7 +267,6 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
static void add_ap_files(struct ieee80211_sub_if_data *sdata)
{
- DEBUGFS_ADD(channel_use, ap);
DEBUGFS_ADD(drop_unencrypted, ap);
DEBUGFS_ADD(num_sta_ps, ap);
DEBUGFS_ADD(dtim_count, ap);
@@ -281,14 +278,12 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata)
static void add_wds_files(struct ieee80211_sub_if_data *sdata)
{
- DEBUGFS_ADD(channel_use, wds);
DEBUGFS_ADD(drop_unencrypted, wds);
DEBUGFS_ADD(peer, wds);
}
static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
{
- DEBUGFS_ADD(channel_use, vlan);
DEBUGFS_ADD(drop_unencrypted, vlan);
}
@@ -376,7 +371,6 @@ static void add_files(struct ieee80211_sub_if_data *sdata)
static void del_sta_files(struct ieee80211_sub_if_data *sdata)
{
- DEBUGFS_DEL(channel_use, sta);
DEBUGFS_DEL(drop_unencrypted, sta);
DEBUGFS_DEL(state, sta);
DEBUGFS_DEL(bssid, sta);
@@ -397,7 +391,6 @@ static void del_sta_files(struct ieee80211_sub_if_data *sdata)
static void del_ap_files(struct ieee80211_sub_if_data *sdata)
{
- DEBUGFS_DEL(channel_use, ap);
DEBUGFS_DEL(drop_unencrypted, ap);
DEBUGFS_DEL(num_sta_ps, ap);
DEBUGFS_DEL(dtim_count, ap);
@@ -409,14 +402,12 @@ static void del_ap_files(struct ieee80211_sub_if_data *sdata)
static void del_wds_files(struct ieee80211_sub_if_data *sdata)
{
- DEBUGFS_DEL(channel_use, wds);
DEBUGFS_DEL(drop_unencrypted, wds);
DEBUGFS_DEL(peer, wds);
}
static void del_vlan_files(struct ieee80211_sub_if_data *sdata)
{
- DEBUGFS_DEL(channel_use, vlan);
DEBUGFS_DEL(drop_unencrypted, vlan);
}
@@ -528,7 +519,7 @@ void ieee80211_debugfs_change_if_type(struct ieee80211_sub_if_data *sdata,
add_files(sdata);
}
-static int netdev_notify(struct notifier_block * nb,
+static int netdev_notify(struct notifier_block *nb,
unsigned long state,
void *ndev)
{
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index 6d47a1d31b37..79a062782d52 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -63,10 +63,9 @@ STA_FILE(tx_fragments, tx_fragments, LU);
STA_FILE(tx_filtered, tx_filtered_count, LU);
STA_FILE(tx_retry_failed, tx_retry_failed, LU);
STA_FILE(tx_retry_count, tx_retry_count, LU);
-STA_FILE(last_rssi, last_rssi, D);
STA_FILE(last_signal, last_signal, D);
+STA_FILE(last_qual, last_qual, D);
STA_FILE(last_noise, last_noise, D);
-STA_FILE(channel_use, channel_use, D);
STA_FILE(wep_weak_iv_count, wep_weak_iv_count, LU);
static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
@@ -74,14 +73,15 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
{
char buf[100];
struct sta_info *sta = file->private_data;
+ u32 staflags = get_sta_flags(sta);
int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s",
- sta->flags & WLAN_STA_AUTH ? "AUTH\n" : "",
- sta->flags & WLAN_STA_ASSOC ? "ASSOC\n" : "",
- sta->flags & WLAN_STA_PS ? "PS\n" : "",
- sta->flags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "",
- sta->flags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "",
- sta->flags & WLAN_STA_WME ? "WME\n" : "",
- sta->flags & WLAN_STA_WDS ? "WDS\n" : "");
+ staflags & WLAN_STA_AUTH ? "AUTH\n" : "",
+ staflags & WLAN_STA_ASSOC ? "ASSOC\n" : "",
+ staflags & WLAN_STA_PS ? "PS\n" : "",
+ staflags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "",
+ staflags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "",
+ staflags & WLAN_STA_WME ? "WME\n" : "",
+ staflags & WLAN_STA_WDS ? "WDS\n" : "");
return simple_read_from_buffer(userbuf, count, ppos, buf, res);
}
STA_OPS(flags);
@@ -123,36 +123,6 @@ static ssize_t sta_last_seq_ctrl_read(struct file *file, char __user *userbuf,
}
STA_OPS(last_seq_ctrl);
-#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
-static ssize_t sta_wme_rx_queue_read(struct file *file, char __user *userbuf,
- size_t count, loff_t *ppos)
-{
- char buf[15*NUM_RX_DATA_QUEUES], *p = buf;
- int i;
- struct sta_info *sta = file->private_data;
- for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
- p += scnprintf(p, sizeof(buf)+buf-p, "%u ",
- sta->wme_rx_queue[i]);
- p += scnprintf(p, sizeof(buf)+buf-p, "\n");
- return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
-}
-STA_OPS(wme_rx_queue);
-
-static ssize_t sta_wme_tx_queue_read(struct file *file, char __user *userbuf,
- size_t count, loff_t *ppos)
-{
- char buf[15*NUM_TX_DATA_QUEUES], *p = buf;
- int i;
- struct sta_info *sta = file->private_data;
- for (i = 0; i < NUM_TX_DATA_QUEUES; i++)
- p += scnprintf(p, sizeof(buf)+buf-p, "%u ",
- sta->wme_tx_queue[i]);
- p += scnprintf(p, sizeof(buf)+buf-p, "\n");
- return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
-}
-STA_OPS(wme_tx_queue);
-#endif
-
static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
@@ -293,10 +263,6 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
DEBUGFS_ADD(num_ps_buf_frames);
DEBUGFS_ADD(inactive_ms);
DEBUGFS_ADD(last_seq_ctrl);
-#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
- DEBUGFS_ADD(wme_rx_queue);
- DEBUGFS_ADD(wme_tx_queue);
-#endif
DEBUGFS_ADD(agg_status);
}
@@ -306,10 +272,6 @@ void ieee80211_sta_debugfs_remove(struct sta_info *sta)
DEBUGFS_DEL(num_ps_buf_frames);
DEBUGFS_DEL(inactive_ms);
DEBUGFS_DEL(last_seq_ctrl);
-#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
- DEBUGFS_DEL(wme_rx_queue);
- DEBUGFS_DEL(wme_tx_queue);
-#endif
DEBUGFS_DEL(agg_status);
debugfs_remove(sta->debugfs.dir);
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index c7314bf4bec2..b19bd16703b2 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2,6 +2,7 @@
* Copyright 2002-2005, Instant802 Networks, Inc.
* Copyright 2005, Devicescape Software, Inc.
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
+ * Copyright 2007-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
@@ -82,7 +83,7 @@ struct ieee80211_sta_bss {
u16 capability; /* host byte order */
enum ieee80211_band band;
int freq;
- int rssi, signal, noise;
+ int signal, noise, qual;
u8 *wpa_ie;
size_t wpa_ie_len;
u8 *rsn_ie;
@@ -91,6 +92,8 @@ struct ieee80211_sta_bss {
size_t wmm_ie_len;
u8 *ht_ie;
size_t ht_ie_len;
+ u8 *ht_add_ie;
+ size_t ht_add_ie_len;
#ifdef CONFIG_MAC80211_MESH
u8 *mesh_id;
size_t mesh_id_len;
@@ -147,7 +150,6 @@ typedef unsigned __bitwise__ ieee80211_tx_result;
#define IEEE80211_TX_UNICAST BIT(1)
#define IEEE80211_TX_PS_BUFFERED BIT(2)
#define IEEE80211_TX_PROBE_LAST_FRAG BIT(3)
-#define IEEE80211_TX_INJECTED BIT(4)
struct ieee80211_tx_data {
struct sk_buff *skb;
@@ -157,13 +159,12 @@ struct ieee80211_tx_data {
struct sta_info *sta;
struct ieee80211_key *key;
- struct ieee80211_tx_control *control;
struct ieee80211_channel *channel;
- struct ieee80211_rate *rate;
+ s8 rate_idx;
/* use this rate (if set) for last fragment; rate can
* be set to lower rate for the first fragments, e.g.,
* when using CTS protection with IEEE 802.11g. */
- struct ieee80211_rate *last_frag_rate;
+ s8 last_frag_rate_idx;
/* Extra fragments (in addition to the first fragment
* in skb) */
@@ -202,32 +203,16 @@ struct ieee80211_rx_data {
unsigned int flags;
int sent_ps_buffered;
int queue;
- int load;
u32 tkip_iv32;
u16 tkip_iv16;
};
-/* flags used in struct ieee80211_tx_packet_data.flags */
-#define IEEE80211_TXPD_REQ_TX_STATUS BIT(0)
-#define IEEE80211_TXPD_DO_NOT_ENCRYPT BIT(1)
-#define IEEE80211_TXPD_REQUEUE BIT(2)
-#define IEEE80211_TXPD_EAPOL_FRAME BIT(3)
-#define IEEE80211_TXPD_AMPDU BIT(4)
-/* Stored in sk_buff->cb */
-struct ieee80211_tx_packet_data {
- int ifindex;
- unsigned long jiffies;
- unsigned int flags;
- u8 queue;
-};
-
struct ieee80211_tx_stored_packet {
- struct ieee80211_tx_control control;
struct sk_buff *skb;
struct sk_buff **extra_frag;
- struct ieee80211_rate *last_frag_rate;
+ s8 last_frag_rate_idx;
int num_extra_frag;
- unsigned int last_frag_rate_ctrl_probe;
+ bool last_frag_rate_ctrl_probe;
};
struct beacon_data {
@@ -464,14 +449,11 @@ struct ieee80211_sub_if_data {
struct ieee80211_if_sta sta;
u32 mntr_flags;
} u;
- int channel_use;
- int channel_use_raw;
#ifdef CONFIG_MAC80211_DEBUGFS
struct dentry *debugfsdir;
union {
struct {
- struct dentry *channel_use;
struct dentry *drop_unencrypted;
struct dentry *state;
struct dentry *bssid;
@@ -490,7 +472,6 @@ struct ieee80211_sub_if_data {
struct dentry *num_beacons_sta;
} sta;
struct {
- struct dentry *channel_use;
struct dentry *drop_unencrypted;
struct dentry *num_sta_ps;
struct dentry *dtim_count;
@@ -500,12 +481,10 @@ struct ieee80211_sub_if_data {
struct dentry *num_buffered_multicast;
} ap;
struct {
- struct dentry *channel_use;
struct dentry *drop_unencrypted;
struct dentry *peer;
} wds;
struct {
- struct dentry *channel_use;
struct dentry *drop_unencrypted;
} vlan;
struct {
@@ -610,8 +589,8 @@ struct ieee80211_local {
struct sta_info *sta_hash[STA_HASH_SIZE];
struct timer_list sta_cleanup;
- unsigned long state[NUM_TX_DATA_QUEUES_AMPDU];
- struct ieee80211_tx_stored_packet pending_packet[NUM_TX_DATA_QUEUES_AMPDU];
+ unsigned long queues_pending[BITS_TO_LONGS(IEEE80211_MAX_QUEUES)];
+ struct ieee80211_tx_stored_packet pending_packet[IEEE80211_MAX_QUEUES];
struct tasklet_struct tx_pending_tasklet;
/* number of interfaces with corresponding IFF_ flags */
@@ -677,9 +656,6 @@ struct ieee80211_local {
assoc_led_name[32], radio_led_name[32];
#endif
- u32 channel_use;
- u32 channel_use_raw;
-
#ifdef CONFIG_MAC80211_DEBUGFS
struct work_struct sta_debugfs_add;
#endif
@@ -705,8 +681,6 @@ struct ieee80211_local {
unsigned int rx_expand_skb_head2;
unsigned int rx_handlers_fragments;
unsigned int tx_status_drop;
- unsigned int wme_rx_queue[NUM_RX_DATA_QUEUES];
- unsigned int wme_tx_queue[NUM_RX_DATA_QUEUES];
#define I802_DEBUG_INC(c) (c)++
#else /* CONFIG_MAC80211_DEBUG_COUNTERS */
#define I802_DEBUG_INC(c) do { } while (0)
@@ -764,8 +738,6 @@ struct ieee80211_local {
struct dentry *rx_expand_skb_head2;
struct dentry *rx_handlers_fragments;
struct dentry *tx_status_drop;
- struct dentry *wme_tx_queue;
- struct dentry *wme_rx_queue;
#endif
struct dentry *dot11ACKFailureCount;
struct dentry *dot11RTSFailureCount;
@@ -778,6 +750,15 @@ struct ieee80211_local {
#endif
};
+static inline int ieee80211_is_multiqueue(struct ieee80211_local *local)
+{
+#ifdef CONFIG_MAC80211_QOS
+ return netif_is_multiqueue(local->mdev);
+#else
+ return 0;
+#endif
+}
+
/* this struct represents 802.11n's RA/TID combination */
struct ieee80211_ra_tid {
u8 ra[ETH_ALEN];
@@ -847,11 +828,6 @@ static inline struct ieee80211_hw *local_to_hw(
return &local->hw;
}
-enum ieee80211_link_state_t {
- IEEE80211_LINK_STATE_XOFF = 0,
- IEEE80211_LINK_STATE_PENDING,
-};
-
struct sta_attribute {
struct attribute attr;
ssize_t (*show)(const struct sta_info *, char *buf);
@@ -877,29 +853,8 @@ u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht,
/* ieee80211_ioctl.c */
extern const struct iw_handler_def ieee80211_iw_handler_def;
+int ieee80211_set_freq(struct net_device *dev, int freq);
-
-/* Least common multiple of the used rates (in 100 kbps). This is used to
- * calculate rate_inv values for each rate so that only integers are needed. */
-#define CHAN_UTIL_RATE_LCM 95040
-/* 1 usec is 1/8 * (95040/10) = 1188 */
-#define CHAN_UTIL_PER_USEC 1188
-/* Amount of bits to shift the result right to scale the total utilization
- * to values that will not wrap around 32-bit integers. */
-#define CHAN_UTIL_SHIFT 9
-/* Theoretical maximum of channel utilization counter in 10 ms (stat_time=1):
- * (CHAN_UTIL_PER_USEC * 10000) >> CHAN_UTIL_SHIFT = 23203. So dividing the
- * raw value with about 23 should give utilization in 10th of a percentage
- * (1/1000). However, utilization is only estimated and not all intervals
- * between frames etc. are calculated. 18 seems to give numbers that are closer
- * to the real maximum. */
-#define CHAN_UTIL_PER_10MS 18
-#define CHAN_UTIL_HDR_LONG (202 * CHAN_UTIL_PER_USEC)
-#define CHAN_UTIL_HDR_SHORT (40 * CHAN_UTIL_PER_USEC)
-
-
-/* ieee80211_ioctl.c */
-int ieee80211_set_freq(struct ieee80211_local *local, int freq);
/* ieee80211_sta.c */
void ieee80211_sta_timer(unsigned long data);
void ieee80211_sta_work(struct work_struct *work);
@@ -919,9 +874,9 @@ ieee80211_rx_result ieee80211_sta_rx_scan(
void ieee80211_rx_bss_list_init(struct net_device *dev);
void ieee80211_rx_bss_list_deinit(struct net_device *dev);
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,
- u8 *addr);
+struct sta_info *ieee80211_ibss_add_sta(struct net_device *dev,
+ struct sk_buff *skb, u8 *bssid,
+ u8 *addr);
int ieee80211_sta_deauthenticate(struct net_device *dev, u16 reason);
int ieee80211_sta_disassociate(struct net_device *dev, u16 reason);
void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
@@ -940,7 +895,6 @@ void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid,
void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *da,
u16 tid, u16 initiator, u16 reason);
-void sta_rx_agg_session_timer_expired(unsigned long data);
void sta_addba_resp_timer_expired(unsigned long data);
void ieee80211_sta_tear_down_BA_sessions(struct net_device *dev, u8 *addr);
u64 ieee80211_sta_get_rates(struct ieee80211_local *local,
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 06e88a5a036d..984472702381 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -33,9 +33,8 @@ static void ieee80211_if_sdata_deinit(struct ieee80211_sub_if_data *sdata)
{
int i;
- for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) {
+ for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
__skb_queue_purge(&sdata->fragments[i].skb_list);
- }
}
/* Must be called with rtnl lock held. */
@@ -167,9 +166,10 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN |
IEEE80211_AUTH_ALG_SHARED_KEY;
ifsta->flags |= IEEE80211_STA_CREATE_IBSS |
- IEEE80211_STA_WMM_ENABLED |
IEEE80211_STA_AUTO_BSSID_SEL |
IEEE80211_STA_AUTO_CHANNEL_SEL;
+ if (ieee80211_num_regular_queues(&sdata->local->hw) >= 4)
+ ifsta->flags |= IEEE80211_STA_WMM_ENABLED;
msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev);
sdata->bss = &msdata->u.ap;
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index 150d66dbda9d..d4893bd17754 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -321,8 +321,15 @@ void ieee80211_key_link(struct ieee80211_key *key,
* some hardware cannot handle TKIP with QoS, so
* we indicate whether QoS could be in use.
*/
- if (sta->flags & WLAN_STA_WME)
+ if (test_sta_flags(sta, WLAN_STA_WME))
key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA;
+
+ /*
+ * This key is for a specific sta interface,
+ * inform the driver that it should try to store
+ * this key as pairwise key.
+ */
+ key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE;
} else {
if (sdata->vif.type == IEEE80211_IF_TYPE_STA) {
struct sta_info *ap;
@@ -335,7 +342,7 @@ void ieee80211_key_link(struct ieee80211_key *key,
/* same here, the AP could be using QoS */
ap = sta_info_get(key->local, key->sdata->u.sta.bssid);
if (ap) {
- if (ap->flags & WLAN_STA_WME)
+ if (test_sta_flags(ap, WLAN_STA_WME))
key->conf.flags |=
IEEE80211_KEY_FLAG_WMM_STA;
}
diff --git a/net/mac80211/key.h b/net/mac80211/key.h
index f52c3df1fe9a..a0f774aafa45 100644
--- a/net/mac80211/key.h
+++ b/net/mac80211/key.h
@@ -69,6 +69,13 @@ enum ieee80211_internal_key_flags {
KEY_FLAG_TODO_ADD_DEBUGFS = BIT(5),
};
+struct tkip_ctx {
+ u32 iv32;
+ u16 iv16;
+ u16 p1k[5];
+ int initialized;
+};
+
struct ieee80211_key {
struct ieee80211_local *local;
struct ieee80211_sub_if_data *sdata;
@@ -85,16 +92,10 @@ struct ieee80211_key {
union {
struct {
/* last used TSC */
- u32 iv32;
- u16 iv16;
- u16 p1k[5];
- int tx_initialized;
+ struct tkip_ctx tx;
/* last received RSC */
- u32 iv32_rx[NUM_RX_DATA_QUEUES];
- u16 iv16_rx[NUM_RX_DATA_QUEUES];
- u16 p1k_rx[NUM_RX_DATA_QUEUES][5];
- int rx_initialized[NUM_RX_DATA_QUEUES];
+ struct tkip_ctx rx[NUM_RX_DATA_QUEUES];
} tkip;
struct {
u8 tx_pn[6];
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 915afadb0602..b182f018a187 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -35,8 +35,6 @@
#include "debugfs.h"
#include "debugfs_netdev.h"
-#define SUPP_MCS_SET_LEN 16
-
/*
* For seeing transmitted packets on monitor interfaces
* we have a radiotap header too.
@@ -112,7 +110,13 @@ static int ieee80211_master_open(struct net_device *dev)
break;
}
}
- return res;
+
+ if (res)
+ return res;
+
+ netif_start_queue(local->mdev);
+
+ return 0;
}
static int ieee80211_master_stop(struct net_device *dev)
@@ -346,6 +350,7 @@ static int ieee80211_open(struct net_device *dev)
goto err_del_interface;
}
+ /* no locking required since STA is not live yet */
sta->flags |= WLAN_STA_AUTHORIZED;
res = sta_info_insert(sta);
@@ -385,8 +390,8 @@ static int ieee80211_open(struct net_device *dev)
* yet be effective. Trigger execution of ieee80211_sta_work
* to fix this.
*/
- if(sdata->vif.type == IEEE80211_IF_TYPE_STA ||
- sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
+ if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
+ sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
struct ieee80211_if_sta *ifsta = &sdata->u.sta;
queue_work(local->hw.workqueue, &ifsta->work);
}
@@ -511,6 +516,7 @@ static int ieee80211_stop(struct net_device *dev)
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_IBSS:
sdata->u.sta.state = IEEE80211_DISABLED;
+ memset(sdata->u.sta.bssid, 0, ETH_ALEN);
del_timer_sync(&sdata->u.sta.timer);
/*
* When we get here, the interface is marked down.
@@ -584,16 +590,16 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
sta = sta_info_get(local, ra);
if (!sta) {
printk(KERN_DEBUG "Could not find the station\n");
- rcu_read_unlock();
- return -ENOENT;
+ ret = -ENOENT;
+ goto exit;
}
- spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_lock_bh(&sta->lock);
/* we have tried too many times, receiver does not want A-MPDU */
if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) {
ret = -EBUSY;
- goto start_ba_exit;
+ goto err_unlock_sta;
}
state = &sta->ampdu_mlme.tid_state_tx[tid];
@@ -604,7 +610,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
"idle on tid %u\n", tid);
#endif /* CONFIG_MAC80211_HT_DEBUG */
ret = -EAGAIN;
- goto start_ba_exit;
+ goto err_unlock_sta;
}
/* prepare A-MPDU MLME for Tx aggregation */
@@ -615,7 +621,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
printk(KERN_ERR "allocate tx mlme to tid %d failed\n",
tid);
ret = -ENOMEM;
- goto start_ba_exit;
+ goto err_unlock_sta;
}
/* Tx timer */
sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function =
@@ -638,7 +644,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
printk(KERN_DEBUG "BA request denied - queue unavailable for"
" tid %d\n", tid);
#endif /* CONFIG_MAC80211_HT_DEBUG */
- goto start_ba_err;
+ goto err_unlock_queue;
}
sdata = sta->sdata;
@@ -660,12 +666,13 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
" tid %d\n", tid);
#endif /* CONFIG_MAC80211_HT_DEBUG */
*state = HT_AGG_STATE_IDLE;
- goto start_ba_err;
+ goto err_unlock_queue;
}
/* Will put all the packets in the new SW queue */
ieee80211_requeue(local, ieee802_1d_to_ac[tid]);
spin_unlock_bh(&local->mdev->queue_lock);
+ spin_unlock_bh(&sta->lock);
/* send an addBA request */
sta->ampdu_mlme.dialog_token_allocator++;
@@ -673,25 +680,26 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
sta->ampdu_mlme.dialog_token_allocator;
sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num;
+
ieee80211_send_addba_request(sta->sdata->dev, ra, tid,
sta->ampdu_mlme.tid_tx[tid]->dialog_token,
sta->ampdu_mlme.tid_tx[tid]->ssn,
0x40, 5000);
-
/* activate the timer for the recipient's addBA response */
sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires =
jiffies + ADDBA_RESP_INTERVAL;
add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
- goto start_ba_exit;
+ goto exit;
-start_ba_err:
+err_unlock_queue:
kfree(sta->ampdu_mlme.tid_tx[tid]);
sta->ampdu_mlme.tid_tx[tid] = NULL;
spin_unlock_bh(&local->mdev->queue_lock);
ret = -EBUSY;
-start_ba_exit:
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+err_unlock_sta:
+ spin_unlock_bh(&sta->lock);
+exit:
rcu_read_unlock();
return ret;
}
@@ -719,7 +727,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
/* check if the TID is in aggregation */
state = &sta->ampdu_mlme.tid_state_tx[tid];
- spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_lock_bh(&sta->lock);
if (*state != HT_AGG_STATE_OPERATIONAL) {
ret = -ENOENT;
@@ -749,7 +757,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
}
stop_BA_exit:
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
rcu_read_unlock();
return ret;
}
@@ -778,12 +786,12 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
}
state = &sta->ampdu_mlme.tid_state_tx[tid];
- spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_lock_bh(&sta->lock);
if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
printk(KERN_DEBUG "addBA was not requested yet, state is %d\n",
*state);
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
rcu_read_unlock();
return;
}
@@ -796,7 +804,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
}
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
rcu_read_unlock();
}
EXPORT_SYMBOL(ieee80211_start_tx_ba_cb);
@@ -830,10 +838,11 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
}
state = &sta->ampdu_mlme.tid_state_tx[tid];
- spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+ /* NOTE: no need to use sta->lock in this state check, as
+ * ieee80211_stop_tx_ba_session will let only
+ * one stop call to pass through per sta/tid */
if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) {
printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
rcu_read_unlock();
return;
}
@@ -856,11 +865,12 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
* ieee80211_wake_queue is not used here as this queue is not
* necessarily stopped */
netif_schedule(local->mdev);
+ spin_lock_bh(&sta->lock);
*state = HT_AGG_STATE_IDLE;
sta->ampdu_mlme.addba_req_num[tid] = 0;
kfree(sta->ampdu_mlme.tid_tx[tid]);
sta->ampdu_mlme.tid_tx[tid] = NULL;
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
rcu_read_unlock();
}
@@ -966,8 +976,7 @@ void ieee80211_if_setup(struct net_device *dev)
/* everything else */
static int __ieee80211_if_config(struct net_device *dev,
- struct sk_buff *beacon,
- struct ieee80211_tx_control *control)
+ struct sk_buff *beacon)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
@@ -985,13 +994,11 @@ static int __ieee80211_if_config(struct net_device *dev,
conf.ssid_len = sdata->u.sta.ssid_len;
} else if (ieee80211_vif_is_mesh(&sdata->vif)) {
conf.beacon = beacon;
- conf.beacon_control = control;
ieee80211_start_mesh(dev);
} else if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
conf.ssid = sdata->u.ap.ssid;
conf.ssid_len = sdata->u.ap.ssid_len;
conf.beacon = beacon;
- conf.beacon_control = control;
}
return local->ops->config_interface(local_to_hw(local),
&sdata->vif, &conf);
@@ -1004,23 +1011,21 @@ int ieee80211_if_config(struct net_device *dev)
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, NULL);
+ return __ieee80211_if_config(dev, NULL);
}
int ieee80211_if_config_beacon(struct net_device *dev)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_tx_control control;
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct sk_buff *skb;
if (!(local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE))
return 0;
- skb = ieee80211_beacon_get(local_to_hw(local), &sdata->vif,
- &control);
+ skb = ieee80211_beacon_get(local_to_hw(local), &sdata->vif);
if (!skb)
return -ENOMEM;
- return __ieee80211_if_config(dev, skb, &control);
+ return __ieee80211_if_config(dev, skb);
}
int ieee80211_hw_config(struct ieee80211_local *local)
@@ -1067,56 +1072,84 @@ u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht,
struct ieee80211_supported_band *sband;
struct ieee80211_ht_info ht_conf;
struct ieee80211_ht_bss_info ht_bss_conf;
- int i;
u32 changed = 0;
+ int i;
+ u8 max_tx_streams = IEEE80211_HT_CAP_MAX_STREAMS;
+ u8 tx_mcs_set_cap;
sband = local->hw.wiphy->bands[conf->channel->band];
+ memset(&ht_conf, 0, sizeof(struct ieee80211_ht_info));
+ memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info));
+
/* HT is not supported */
if (!sband->ht_info.ht_supported) {
conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
- return 0;
+ goto out;
}
- memset(&ht_conf, 0, sizeof(struct ieee80211_ht_info));
- memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info));
-
- if (enable_ht) {
- if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE))
+ /* disable HT */
+ if (!enable_ht) {
+ if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)
changed |= BSS_CHANGED_HT;
+ conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
+ conf->ht_conf.ht_supported = 0;
+ goto out;
+ }
- conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE;
- ht_conf.ht_supported = 1;
- ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap;
- ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS);
- ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS;
+ if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE))
+ changed |= BSS_CHANGED_HT;
- for (i = 0; i < SUPP_MCS_SET_LEN; i++)
- ht_conf.supp_mcs_set[i] =
- sband->ht_info.supp_mcs_set[i] &
- req_ht_cap->supp_mcs_set[i];
+ conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE;
+ ht_conf.ht_supported = 1;
- ht_bss_conf.primary_channel = req_bss_cap->primary_channel;
- ht_bss_conf.bss_cap = req_bss_cap->bss_cap;
- ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode;
+ ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap;
+ ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS);
+ ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS;
+ ht_bss_conf.primary_channel = req_bss_cap->primary_channel;
+ ht_bss_conf.bss_cap = req_bss_cap->bss_cap;
+ ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode;
- ht_conf.ampdu_factor = req_ht_cap->ampdu_factor;
- ht_conf.ampdu_density = req_ht_cap->ampdu_density;
+ ht_conf.ampdu_factor = req_ht_cap->ampdu_factor;
+ ht_conf.ampdu_density = req_ht_cap->ampdu_density;
- /* if bss configuration changed store the new one */
- if (memcmp(&conf->ht_conf, &ht_conf, sizeof(ht_conf)) ||
- memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) {
- changed |= BSS_CHANGED_HT;
- memcpy(&conf->ht_conf, &ht_conf, sizeof(ht_conf));
- memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf));
- }
- } else {
- if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)
- changed |= BSS_CHANGED_HT;
- conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
- }
+ /* Bits 96-100 */
+ tx_mcs_set_cap = sband->ht_info.supp_mcs_set[12];
+
+ /* configure suppoerted Tx MCS according to requested MCS
+ * (based in most cases on Rx capabilities of peer) and self
+ * Tx MCS capabilities (as defined by low level driver HW
+ * Tx capabilities) */
+ if (!(tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_DEFINED))
+ goto check_changed;
+ /* Counting from 0 therfore + 1 */
+ if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_RX_DIFF)
+ max_tx_streams = ((tx_mcs_set_cap &
+ IEEE80211_HT_CAP_MCS_TX_STREAMS) >> 2) + 1;
+
+ for (i = 0; i < max_tx_streams; i++)
+ ht_conf.supp_mcs_set[i] =
+ sband->ht_info.supp_mcs_set[i] &
+ req_ht_cap->supp_mcs_set[i];
+
+ if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_UEQM)
+ for (i = IEEE80211_SUPP_MCS_SET_UEQM;
+ i < IEEE80211_SUPP_MCS_SET_LEN; i++)
+ ht_conf.supp_mcs_set[i] =
+ sband->ht_info.supp_mcs_set[i] &
+ req_ht_cap->supp_mcs_set[i];
+
+check_changed:
+ /* if bss configuration changed store the new one */
+ if (memcmp(&conf->ht_conf, &ht_conf, sizeof(ht_conf)) ||
+ memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) {
+ changed |= BSS_CHANGED_HT;
+ memcpy(&conf->ht_conf, &ht_conf, sizeof(ht_conf));
+ memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf));
+ }
+out:
return changed;
}
@@ -1147,38 +1180,20 @@ void ieee80211_reset_erp_info(struct net_device *dev)
}
void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
- struct sk_buff *skb,
- struct ieee80211_tx_status *status)
+ struct sk_buff *skb)
{
struct ieee80211_local *local = hw_to_local(hw);
- struct ieee80211_tx_status *saved;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
int tmp;
skb->dev = local->mdev;
- saved = kmalloc(sizeof(struct ieee80211_tx_status), GFP_ATOMIC);
- if (unlikely(!saved)) {
- if (net_ratelimit())
- printk(KERN_WARNING "%s: Not enough memory, "
- "dropping tx status", skb->dev->name);
- /* should be dev_kfree_skb_irq, but due to this function being
- * named _irqsafe instead of just _irq we can't be sure that
- * people won't call it from non-irq contexts */
- dev_kfree_skb_any(skb);
- return;
- }
- memcpy(saved, status, sizeof(struct ieee80211_tx_status));
- /* copy pointer to saved status into skb->cb for use by tasklet */
- memcpy(skb->cb, &saved, sizeof(saved));
-
skb->pkt_type = IEEE80211_TX_STATUS_MSG;
- skb_queue_tail(status->control.flags & IEEE80211_TXCTL_REQ_TX_STATUS ?
+ skb_queue_tail(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS ?
&local->skb_queue : &local->skb_queue_unreliable, skb);
tmp = skb_queue_len(&local->skb_queue) +
skb_queue_len(&local->skb_queue_unreliable);
while (tmp > IEEE80211_IRQSAFE_QUEUE_LIMIT &&
(skb = skb_dequeue(&local->skb_queue_unreliable))) {
- memcpy(&saved, skb->cb, sizeof(saved));
- kfree(saved);
dev_kfree_skb_irq(skb);
tmp--;
I802_DEBUG_INC(local->tx_status_drop);
@@ -1192,7 +1207,6 @@ static void ieee80211_tasklet_handler(unsigned long data)
struct ieee80211_local *local = (struct ieee80211_local *) data;
struct sk_buff *skb;
struct ieee80211_rx_status rx_status;
- struct ieee80211_tx_status *tx_status;
struct ieee80211_ra_tid *ra_tid;
while ((skb = skb_dequeue(&local->skb_queue)) ||
@@ -1207,12 +1221,8 @@ static void ieee80211_tasklet_handler(unsigned long data)
__ieee80211_rx(local_to_hw(local), skb, &rx_status);
break;
case IEEE80211_TX_STATUS_MSG:
- /* get pointer to saved status out of skb->cb */
- memcpy(&tx_status, skb->cb, sizeof(tx_status));
skb->pkt_type = 0;
- ieee80211_tx_status(local_to_hw(local),
- skb, tx_status);
- kfree(tx_status);
+ ieee80211_tx_status(local_to_hw(local), skb);
break;
case IEEE80211_DELBA_MSG:
ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
@@ -1241,24 +1251,15 @@ static void ieee80211_tasklet_handler(unsigned long data)
* Also, tx_packet_data in cb is restored from tx_control. */
static void ieee80211_remove_tx_extra(struct ieee80211_local *local,
struct ieee80211_key *key,
- struct sk_buff *skb,
- struct ieee80211_tx_control *control)
+ struct sk_buff *skb)
{
int hdrlen, iv_len, mic_len;
- struct ieee80211_tx_packet_data *pkt_data;
-
- pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
- pkt_data->ifindex = vif_to_sdata(control->vif)->dev->ifindex;
- pkt_data->flags = 0;
- if (control->flags & IEEE80211_TXCTL_REQ_TX_STATUS)
- pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS;
- if (control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)
- pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;
- if (control->flags & IEEE80211_TXCTL_REQUEUE)
- pkt_data->flags |= IEEE80211_TXPD_REQUEUE;
- if (control->flags & IEEE80211_TXCTL_EAPOL_FRAME)
- pkt_data->flags |= IEEE80211_TXPD_EAPOL_FRAME;
- pkt_data->queue = control->queue;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+ info->flags &= IEEE80211_TX_CTL_REQ_TX_STATUS |
+ IEEE80211_TX_CTL_DO_NOT_ENCRYPT |
+ IEEE80211_TX_CTL_REQUEUE |
+ IEEE80211_TX_CTL_EAPOL_FRAME;
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
@@ -1305,17 +1306,18 @@ no_key:
static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
struct sta_info *sta,
- struct sk_buff *skb,
- struct ieee80211_tx_status *status)
+ struct sk_buff *skb)
{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
sta->tx_filtered_count++;
/*
* Clear the TX filter mask for this STA when sending the next
* packet. If the STA went to power save mode, this will happen
- * happen when it wakes up for the next time.
+ * when it wakes up for the next time.
*/
- sta->flags |= WLAN_STA_CLEAR_PS_FILT;
+ set_sta_flags(sta, WLAN_STA_CLEAR_PS_FILT);
/*
* This code races in the following way:
@@ -1347,20 +1349,18 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
* can be unknown, for example with different interrupt status
* bits.
*/
- if (sta->flags & WLAN_STA_PS &&
+ if (test_sta_flags(sta, WLAN_STA_PS) &&
skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) {
- ieee80211_remove_tx_extra(local, sta->key, skb,
- &status->control);
+ ieee80211_remove_tx_extra(local, sta->key, skb);
skb_queue_tail(&sta->tx_filtered, skb);
return;
}
- if (!(sta->flags & WLAN_STA_PS) &&
- !(status->control.flags & IEEE80211_TXCTL_REQUEUE)) {
+ if (!test_sta_flags(sta, WLAN_STA_PS) &&
+ !(info->flags & IEEE80211_TX_CTL_REQUEUE)) {
/* Software retry the packet once */
- status->control.flags |= IEEE80211_TXCTL_REQUEUE;
- ieee80211_remove_tx_extra(local, sta->key, skb,
- &status->control);
+ info->flags |= IEEE80211_TX_CTL_REQUEUE;
+ ieee80211_remove_tx_extra(local, sta->key, skb);
dev_queue_xmit(skb);
return;
}
@@ -1370,61 +1370,49 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
"queue_len=%d PS=%d @%lu\n",
wiphy_name(local->hw.wiphy),
skb_queue_len(&sta->tx_filtered),
- !!(sta->flags & WLAN_STA_PS), jiffies);
+ !!test_sta_flags(sta, WLAN_STA_PS), jiffies);
dev_kfree_skb(skb);
}
-void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ieee80211_tx_status *status)
+void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct sk_buff *skb2;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_local *local = hw_to_local(hw);
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
u16 frag, type;
struct ieee80211_tx_status_rtap_hdr *rthdr;
struct ieee80211_sub_if_data *sdata;
struct net_device *prev_dev = NULL;
- if (!status) {
- printk(KERN_ERR
- "%s: ieee80211_tx_status called with NULL status\n",
- wiphy_name(local->hw.wiphy));
- dev_kfree_skb(skb);
- return;
- }
-
rcu_read_lock();
- if (status->excessive_retries) {
+ if (info->status.excessive_retries) {
struct sta_info *sta;
sta = sta_info_get(local, hdr->addr1);
if (sta) {
- if (sta->flags & WLAN_STA_PS) {
+ if (test_sta_flags(sta, WLAN_STA_PS)) {
/*
* The STA is in power save mode, so assume
* that this TX packet failed because of that.
*/
- status->excessive_retries = 0;
- status->flags |= IEEE80211_TX_STATUS_TX_FILTERED;
- ieee80211_handle_filtered_frame(local, sta,
- skb, status);
+ ieee80211_handle_filtered_frame(local, sta, skb);
rcu_read_unlock();
return;
}
}
}
- if (status->flags & IEEE80211_TX_STATUS_TX_FILTERED) {
+ if (info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
struct sta_info *sta;
sta = sta_info_get(local, hdr->addr1);
if (sta) {
- ieee80211_handle_filtered_frame(local, sta, skb,
- status);
+ ieee80211_handle_filtered_frame(local, sta, skb);
rcu_read_unlock();
return;
}
} else
- rate_control_tx_status(local->mdev, skb, status);
+ rate_control_tx_status(local->mdev, skb);
rcu_read_unlock();
@@ -1438,14 +1426,14 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
frag = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG;
type = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_FTYPE;
- if (status->flags & IEEE80211_TX_STATUS_ACK) {
+ if (info->flags & IEEE80211_TX_STAT_ACK) {
if (frag == 0) {
local->dot11TransmittedFrameCount++;
if (is_multicast_ether_addr(hdr->addr1))
local->dot11MulticastTransmittedFrameCount++;
- if (status->retry_count > 0)
+ if (info->status.retry_count > 0)
local->dot11RetryCount++;
- if (status->retry_count > 1)
+ if (info->status.retry_count > 1)
local->dot11MultipleRetryCount++;
}
@@ -1482,7 +1470,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
return;
}
- rthdr = (struct ieee80211_tx_status_rtap_hdr*)
+ rthdr = (struct ieee80211_tx_status_rtap_hdr *)
skb_push(skb, sizeof(*rthdr));
memset(rthdr, 0, sizeof(*rthdr));
@@ -1491,17 +1479,17 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) |
(1 << IEEE80211_RADIOTAP_DATA_RETRIES));
- if (!(status->flags & IEEE80211_TX_STATUS_ACK) &&
+ if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
!is_multicast_ether_addr(hdr->addr1))
rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL);
- if ((status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS) &&
- (status->control.flags & IEEE80211_TXCTL_USE_CTS_PROTECT))
+ if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) &&
+ (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT))
rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS);
- else if (status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS)
+ else if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS);
- rthdr->data_retries = status->retry_count;
+ rthdr->data_retries = info->status.retry_count;
/* XXX: is this sufficient for BPF? */
skb_set_mac_header(skb, 0);
@@ -1651,12 +1639,32 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
if (result < 0)
return result;
+ /*
+ * We use the number of queues for feature tests (QoS, HT) internally
+ * so restrict them appropriately.
+ */
+#ifdef CONFIG_MAC80211_QOS
+ if (hw->queues > IEEE80211_MAX_QUEUES)
+ hw->queues = IEEE80211_MAX_QUEUES;
+ if (hw->ampdu_queues > IEEE80211_MAX_AMPDU_QUEUES)
+ hw->ampdu_queues = IEEE80211_MAX_AMPDU_QUEUES;
+ if (hw->queues < 4)
+ hw->ampdu_queues = 0;
+#else
+ hw->queues = 1;
+ hw->ampdu_queues = 0;
+#endif
+
/* for now, mdev needs sub_if_data :/ */
- mdev = alloc_netdev(sizeof(struct ieee80211_sub_if_data),
- "wmaster%d", ether_setup);
+ mdev = alloc_netdev_mq(sizeof(struct ieee80211_sub_if_data),
+ "wmaster%d", ether_setup,
+ ieee80211_num_queues(hw));
if (!mdev)
goto fail_mdev_alloc;
+ 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;
@@ -1701,13 +1709,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
local->hw.conf.beacon_int = 1000;
- local->wstats_flags |= local->hw.max_rssi ?
- IW_QUAL_LEVEL_UPDATED : IW_QUAL_LEVEL_INVALID;
- local->wstats_flags |= local->hw.max_signal ?
+ local->wstats_flags |= local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC |
+ IEEE80211_HW_SIGNAL_DB |
+ IEEE80211_HW_SIGNAL_DBM) ?
IW_QUAL_QUAL_UPDATED : IW_QUAL_QUAL_INVALID;
- local->wstats_flags |= local->hw.max_noise ?
+ local->wstats_flags |= local->hw.flags & IEEE80211_HW_NOISE_DBM ?
IW_QUAL_NOISE_UPDATED : IW_QUAL_NOISE_INVALID;
- if (local->hw.max_rssi < 0 || local->hw.max_noise < 0)
+ if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
local->wstats_flags |= IW_QUAL_DBM;
result = sta_info_start(local);
@@ -1857,7 +1865,9 @@ static int __init ieee80211_init(void)
struct sk_buff *skb;
int ret;
- BUILD_BUG_ON(sizeof(struct ieee80211_tx_packet_data) > sizeof(skb->cb));
+ BUILD_BUG_ON(sizeof(struct ieee80211_tx_info) > sizeof(skb->cb));
+ BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, driver_data) +
+ IEEE80211_TX_INFO_DRIVER_DATA_SIZE > sizeof(skb->cb));
ret = rc80211_pid_init();
if (ret)
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 697ef67f96b6..b5933b271491 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -315,6 +315,13 @@ struct mesh_table *mesh_table_alloc(int size_order)
return newtbl;
}
+static void __mesh_table_free(struct mesh_table *tbl)
+{
+ kfree(tbl->hash_buckets);
+ kfree(tbl->hashwlock);
+ kfree(tbl);
+}
+
void mesh_table_free(struct mesh_table *tbl, bool free_leafs)
{
struct hlist_head *mesh_hash;
@@ -330,9 +337,7 @@ void mesh_table_free(struct mesh_table *tbl, bool free_leafs)
}
spin_unlock(&tbl->hashwlock[i]);
}
- kfree(tbl->hash_buckets);
- kfree(tbl->hashwlock);
- kfree(tbl);
+ __mesh_table_free(tbl);
}
static void ieee80211_mesh_path_timer(unsigned long data)
@@ -349,21 +354,16 @@ struct mesh_table *mesh_table_grow(struct mesh_table *tbl)
{
struct mesh_table *newtbl;
struct hlist_head *oldhash;
- struct hlist_node *p;
- int err = 0;
+ struct hlist_node *p, *q;
int i;
if (atomic_read(&tbl->entries)
- < tbl->mean_chain_len * (tbl->hash_mask + 1)) {
- err = -EPERM;
+ < tbl->mean_chain_len * (tbl->hash_mask + 1))
goto endgrow;
- }
newtbl = mesh_table_alloc(tbl->size_order + 1);
- if (!newtbl) {
- err = -ENOMEM;
+ if (!newtbl)
goto endgrow;
- }
newtbl->free_node = tbl->free_node;
newtbl->mean_chain_len = tbl->mean_chain_len;
@@ -373,13 +373,19 @@ struct mesh_table *mesh_table_grow(struct mesh_table *tbl)
oldhash = tbl->hash_buckets;
for (i = 0; i <= tbl->hash_mask; i++)
hlist_for_each(p, &oldhash[i])
- tbl->copy_node(p, newtbl);
+ if (tbl->copy_node(p, newtbl) < 0)
+ goto errcopy;
+ return newtbl;
+
+errcopy:
+ for (i = 0; i <= newtbl->hash_mask; i++) {
+ hlist_for_each_safe(p, q, &newtbl->hash_buckets[i])
+ tbl->free_node(p, 0);
+ }
+ __mesh_table_free(tbl);
endgrow:
- if (err)
- return NULL;
- else
- return newtbl;
+ return NULL;
}
/**
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 2e161f6d8288..669eafafe497 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -109,7 +109,7 @@ struct mesh_table {
__u32 hash_rnd; /* Used for hash generation */
atomic_t entries; /* Up to MAX_MESH_NEIGHBOURS */
void (*free_node) (struct hlist_node *p, bool free_leafs);
- void (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl);
+ int (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl);
int size_order;
int mean_chain_len;
};
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index af0cd1e3e213..7fa149e230e6 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -26,7 +26,7 @@ static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae)
{
if (ae)
offset += 6;
- return le32_to_cpu(get_unaligned((__le32 *) (preq_elem + offset)));
+ return get_unaligned_le32(preq_elem + offset);
}
/* HWMP IE processing macros */
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 99c2d360888e..947b13b40726 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -158,19 +158,14 @@ int mesh_path_add(u8 *dst, struct net_device *dev)
if (atomic_add_unless(&sdata->u.sta.mpaths, 1, MESH_MAX_MPATHS) == 0)
return -ENOSPC;
+ err = -ENOMEM;
new_mpath = kzalloc(sizeof(struct mesh_path), GFP_KERNEL);
- if (!new_mpath) {
- atomic_dec(&sdata->u.sta.mpaths);
- err = -ENOMEM;
- goto endadd2;
- }
+ if (!new_mpath)
+ goto err_path_alloc;
+
new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL);
- if (!new_node) {
- kfree(new_mpath);
- atomic_dec(&sdata->u.sta.mpaths);
- err = -ENOMEM;
- goto endadd2;
- }
+ if (!new_node)
+ goto err_node_alloc;
read_lock(&pathtbl_resize_lock);
memcpy(new_mpath->dst, dst, ETH_ALEN);
@@ -189,16 +184,11 @@ int mesh_path_add(u8 *dst, struct net_device *dev)
spin_lock(&mesh_paths->hashwlock[hash_idx]);
+ err = -EEXIST;
hlist_for_each_entry(node, n, bucket, list) {
mpath = node->mpath;
- if (mpath->dev == dev && memcmp(dst, mpath->dst, ETH_ALEN)
- == 0) {
- err = -EEXIST;
- atomic_dec(&sdata->u.sta.mpaths);
- kfree(new_node);
- kfree(new_mpath);
- goto endadd;
- }
+ if (mpath->dev == dev && memcmp(dst, mpath->dst, ETH_ALEN) == 0)
+ goto err_exists;
}
hlist_add_head_rcu(&new_node->list, bucket);
@@ -206,10 +196,9 @@ int mesh_path_add(u8 *dst, struct net_device *dev)
mesh_paths->mean_chain_len * (mesh_paths->hash_mask + 1))
grow = 1;
-endadd:
spin_unlock(&mesh_paths->hashwlock[hash_idx]);
read_unlock(&pathtbl_resize_lock);
- if (!err && grow) {
+ if (grow) {
struct mesh_table *oldtbl, *newtbl;
write_lock(&pathtbl_resize_lock);
@@ -217,7 +206,7 @@ endadd:
newtbl = mesh_table_grow(mesh_paths);
if (!newtbl) {
write_unlock(&pathtbl_resize_lock);
- return -ENOMEM;
+ return 0;
}
rcu_assign_pointer(mesh_paths, newtbl);
write_unlock(&pathtbl_resize_lock);
@@ -225,7 +214,16 @@ endadd:
synchronize_rcu();
mesh_table_free(oldtbl, false);
}
-endadd2:
+ return 0;
+
+err_exists:
+ spin_unlock(&mesh_paths->hashwlock[hash_idx]);
+ read_unlock(&pathtbl_resize_lock);
+ kfree(new_node);
+err_node_alloc:
+ kfree(new_mpath);
+err_path_alloc:
+ atomic_dec(&sdata->u.sta.mpaths);
return err;
}
@@ -460,25 +458,28 @@ static void mesh_path_node_free(struct hlist_node *p, bool free_leafs)
struct mpath_node *node = hlist_entry(p, struct mpath_node, list);
mpath = node->mpath;
hlist_del_rcu(p);
- synchronize_rcu();
if (free_leafs)
kfree(mpath);
kfree(node);
}
-static void mesh_path_node_copy(struct hlist_node *p, struct mesh_table *newtbl)
+static int mesh_path_node_copy(struct hlist_node *p, struct mesh_table *newtbl)
{
struct mesh_path *mpath;
struct mpath_node *node, *new_node;
u32 hash_idx;
+ new_node = kmalloc(sizeof(struct mpath_node), GFP_ATOMIC);
+ if (new_node == NULL)
+ return -ENOMEM;
+
node = hlist_entry(p, struct mpath_node, list);
mpath = node->mpath;
- new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL);
new_node->mpath = mpath;
hash_idx = mesh_table_hash(mpath->dst, mpath->dev, newtbl);
hlist_add_head(&new_node->list,
&newtbl->hash_buckets[hash_idx]);
+ return 0;
}
int mesh_pathtbl_init(void)
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 37f0c2b94ae7..9efeb1f07025 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -79,7 +79,7 @@ void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata)
*
* @sta: mes peer link to restart
*
- * Locking: this function must be called holding sta->plink_lock
+ * Locking: this function must be called holding sta->lock
*/
static inline void mesh_plink_fsm_restart(struct sta_info *sta)
{
@@ -105,7 +105,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
if (!sta)
return NULL;
- sta->flags |= WLAN_STA_AUTHORIZED;
+ sta->flags = WLAN_STA_AUTHORIZED;
sta->supp_rates[local->hw.conf.channel->band] = rates;
return sta;
@@ -118,7 +118,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
*
* All mesh paths with this peer as next hop will be flushed
*
- * Locking: the caller must hold sta->plink_lock
+ * Locking: the caller must hold sta->lock
*/
static void __mesh_plink_deactivate(struct sta_info *sta)
{
@@ -139,9 +139,9 @@ static void __mesh_plink_deactivate(struct sta_info *sta)
*/
void mesh_plink_deactivate(struct sta_info *sta)
{
- spin_lock_bh(&sta->plink_lock);
+ spin_lock_bh(&sta->lock);
__mesh_plink_deactivate(sta);
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
}
static int mesh_plink_frame_tx(struct net_device *dev,
@@ -270,10 +270,10 @@ static void mesh_plink_timer(unsigned long data)
*/
sta = (struct sta_info *) data;
- spin_lock_bh(&sta->plink_lock);
+ spin_lock_bh(&sta->lock);
if (sta->ignore_plink_timer) {
sta->ignore_plink_timer = false;
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
return;
}
mpl_dbg("Mesh plink timer for %s fired on state %d\n",
@@ -298,7 +298,7 @@ static void mesh_plink_timer(unsigned long data)
rand % sta->plink_timeout;
++sta->plink_retries;
mod_plink_timer(sta, sta->plink_timeout);
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
mesh_plink_frame_tx(dev, PLINK_OPEN, sta->addr, llid,
0, 0);
break;
@@ -311,7 +311,7 @@ static void mesh_plink_timer(unsigned long data)
reason = cpu_to_le16(MESH_CONFIRM_TIMEOUT);
sta->plink_state = PLINK_HOLDING;
mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid,
reason);
break;
@@ -319,10 +319,10 @@ static void mesh_plink_timer(unsigned long data)
/* holding timer */
del_timer(&sta->plink_timer);
mesh_plink_fsm_restart(sta);
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
break;
default:
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
break;
}
}
@@ -344,16 +344,16 @@ int mesh_plink_open(struct sta_info *sta)
DECLARE_MAC_BUF(mac);
#endif
- spin_lock_bh(&sta->plink_lock);
+ spin_lock_bh(&sta->lock);
get_random_bytes(&llid, 2);
sta->llid = llid;
if (sta->plink_state != PLINK_LISTEN) {
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
return -EBUSY;
}
sta->plink_state = PLINK_OPN_SNT;
mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
mpl_dbg("Mesh plink: starting establishment with %s\n",
print_mac(mac, sta->addr));
@@ -367,10 +367,10 @@ void mesh_plink_block(struct sta_info *sta)
DECLARE_MAC_BUF(mac);
#endif
- spin_lock_bh(&sta->plink_lock);
+ spin_lock_bh(&sta->lock);
__mesh_plink_deactivate(sta);
sta->plink_state = PLINK_BLOCKED;
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
}
int mesh_plink_close(struct sta_info *sta)
@@ -383,14 +383,14 @@ int mesh_plink_close(struct sta_info *sta)
mpl_dbg("Mesh plink: closing link with %s\n",
print_mac(mac, sta->addr));
- spin_lock_bh(&sta->plink_lock);
+ spin_lock_bh(&sta->lock);
sta->reason = cpu_to_le16(MESH_LINK_CANCELLED);
reason = sta->reason;
if (sta->plink_state == PLINK_LISTEN ||
sta->plink_state == PLINK_BLOCKED) {
mesh_plink_fsm_restart(sta);
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
return 0;
} else if (sta->plink_state == PLINK_ESTAB) {
__mesh_plink_deactivate(sta);
@@ -402,7 +402,7 @@ int mesh_plink_close(struct sta_info *sta)
sta->plink_state = PLINK_HOLDING;
llid = sta->llid;
plid = sta->plid;
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
mesh_plink_frame_tx(sta->sdata->dev, PLINK_CLOSE, sta->addr, llid,
plid, reason);
return 0;
@@ -490,7 +490,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
/* avoid warning */
break;
}
- spin_lock_bh(&sta->plink_lock);
+ spin_lock_bh(&sta->lock);
} else if (!sta) {
/* ftype == PLINK_OPEN */
u64 rates;
@@ -512,9 +512,9 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
return;
}
event = OPN_ACPT;
- spin_lock_bh(&sta->plink_lock);
+ spin_lock_bh(&sta->lock);
} else {
- spin_lock_bh(&sta->plink_lock);
+ spin_lock_bh(&sta->lock);
switch (ftype) {
case PLINK_OPEN:
if (!mesh_plink_free_count(sdata) ||
@@ -551,7 +551,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
break;
default:
mpl_dbg("Mesh plink: unknown frame subtype\n");
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
rcu_read_unlock();
return;
}
@@ -568,7 +568,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
switch (event) {
case CLS_ACPT:
mesh_plink_fsm_restart(sta);
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
break;
case OPN_ACPT:
sta->plink_state = PLINK_OPN_RCVD;
@@ -576,14 +576,14 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
get_random_bytes(&llid, 2);
sta->llid = llid;
mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
mesh_plink_frame_tx(dev, PLINK_OPEN, sta->addr, llid,
0, 0);
mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr,
llid, plid, 0);
break;
default:
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
break;
}
break;
@@ -603,7 +603,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
sta->ignore_plink_timer = true;
llid = sta->llid;
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
plid, reason);
break;
@@ -612,7 +612,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
sta->plink_state = PLINK_OPN_RCVD;
sta->plid = plid;
llid = sta->llid;
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid,
plid, 0);
break;
@@ -622,10 +622,10 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
dot11MeshConfirmTimeout(sdata)))
sta->ignore_plink_timer = true;
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
break;
default:
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
break;
}
break;
@@ -645,13 +645,13 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
sta->ignore_plink_timer = true;
llid = sta->llid;
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
plid, reason);
break;
case OPN_ACPT:
llid = sta->llid;
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid,
plid, 0);
break;
@@ -659,12 +659,12 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
del_timer(&sta->plink_timer);
sta->plink_state = PLINK_ESTAB;
mesh_plink_inc_estab_count(sdata);
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
mpl_dbg("Mesh plink with %s ESTABLISHED\n",
print_mac(mac, sta->addr));
break;
default:
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
break;
}
break;
@@ -684,7 +684,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
sta->ignore_plink_timer = true;
llid = sta->llid;
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
plid, reason);
break;
@@ -692,14 +692,14 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
del_timer(&sta->plink_timer);
sta->plink_state = PLINK_ESTAB;
mesh_plink_inc_estab_count(sdata);
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
mpl_dbg("Mesh plink with %s ESTABLISHED\n",
print_mac(mac, sta->addr));
mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid,
plid, 0);
break;
default:
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
break;
}
break;
@@ -713,18 +713,18 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
sta->plink_state = PLINK_HOLDING;
llid = sta->llid;
mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
plid, reason);
break;
case OPN_ACPT:
llid = sta->llid;
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid,
plid, 0);
break;
default:
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
break;
}
break;
@@ -734,7 +734,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
if (del_timer(&sta->plink_timer))
sta->ignore_plink_timer = 1;
mesh_plink_fsm_restart(sta);
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
break;
case OPN_ACPT:
case CNF_ACPT:
@@ -742,19 +742,19 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
case CNF_RJCT:
llid = sta->llid;
reason = sta->reason;
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
plid, reason);
break;
default:
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
}
break;
default:
/* should not get here, PLINK_BLOCKED is dealt with at the
* beggining of the function
*/
- spin_unlock_bh(&sta->plink_lock);
+ spin_unlock_bh(&sta->lock);
break;
}
diff --git a/net/mac80211/michael.c b/net/mac80211/michael.c
index 0f844f7895f1..1fcdf38cf60c 100644
--- a/net/mac80211/michael.c
+++ b/net/mac80211/michael.c
@@ -6,85 +6,58 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-
#include <linux/types.h>
+#include <linux/bitops.h>
+#include <asm/unaligned.h>
#include "michael.h"
-static inline u32 rotr(u32 val, int bits)
-{
- return (val >> bits) | (val << (32 - bits));
-}
-
-
-static inline u32 rotl(u32 val, int bits)
-{
- return (val << bits) | (val >> (32 - bits));
-}
-
-
-static inline u32 xswap(u32 val)
-{
- return ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8);
-}
-
-
-#define michael_block(l, r) \
-do { \
- r ^= rotl(l, 17); \
- l += r; \
- r ^= xswap(l); \
- l += r; \
- r ^= rotl(l, 3); \
- l += r; \
- r ^= rotr(l, 2); \
- l += r; \
-} while (0)
-
-
-static inline u32 michael_get32(u8 *data)
+static void michael_block(struct michael_mic_ctx *mctx, u32 val)
{
- return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
+ mctx->l ^= val;
+ mctx->r ^= rol32(mctx->l, 17);
+ mctx->l += mctx->r;
+ mctx->r ^= ((mctx->l & 0xff00ff00) >> 8) |
+ ((mctx->l & 0x00ff00ff) << 8);
+ mctx->l += mctx->r;
+ mctx->r ^= rol32(mctx->l, 3);
+ mctx->l += mctx->r;
+ mctx->r ^= ror32(mctx->l, 2);
+ mctx->l += mctx->r;
}
-
-static inline void michael_put32(u32 val, u8 *data)
+static void michael_mic_hdr(struct michael_mic_ctx *mctx,
+ const u8 *key, const u8 *da, const u8 *sa, u8 priority)
{
- data[0] = val & 0xff;
- data[1] = (val >> 8) & 0xff;
- data[2] = (val >> 16) & 0xff;
- data[3] = (val >> 24) & 0xff;
+ mctx->l = get_unaligned_le32(key);
+ mctx->r = get_unaligned_le32(key + 4);
+
+ /*
+ * A pseudo header (DA, SA, Priority, 0, 0, 0) is used in Michael MIC
+ * calculation, but it is _not_ transmitted
+ */
+ michael_block(mctx, get_unaligned_le32(da));
+ michael_block(mctx, get_unaligned_le16(&da[4]) |
+ (get_unaligned_le16(sa) << 16));
+ michael_block(mctx, get_unaligned_le32(&sa[2]));
+ michael_block(mctx, priority);
}
-
-void michael_mic(u8 *key, u8 *da, u8 *sa, u8 priority,
- u8 *data, size_t data_len, u8 *mic)
+void michael_mic(const u8 *key, const u8 *da, const u8 *sa, u8 priority,
+ const u8 *data, size_t data_len, u8 *mic)
{
- u32 l, r, val;
+ u32 val;
size_t block, blocks, left;
+ struct michael_mic_ctx mctx;
- l = michael_get32(key);
- r = michael_get32(key + 4);
-
- /* A pseudo header (DA, SA, Priority, 0, 0, 0) is used in Michael MIC
- * calculation, but it is _not_ transmitted */
- l ^= michael_get32(da);
- michael_block(l, r);
- l ^= da[4] | (da[5] << 8) | (sa[0] << 16) | (sa[1] << 24);
- michael_block(l, r);
- l ^= michael_get32(&sa[2]);
- michael_block(l, r);
- l ^= priority;
- michael_block(l, r);
+ michael_mic_hdr(&mctx, key, da, sa, priority);
/* Real data */
blocks = data_len / 4;
left = data_len % 4;
- for (block = 0; block < blocks; block++) {
- l ^= michael_get32(&data[block * 4]);
- michael_block(l, r);
- }
+ for (block = 0; block < blocks; block++)
+ michael_block(&mctx, get_unaligned_le32(&data[block * 4]));
/* Partial block of 0..3 bytes and padding: 0x5a + 4..7 zeros to make
* total length a multiple of 4. */
@@ -94,11 +67,10 @@ void michael_mic(u8 *key, u8 *da, u8 *sa, u8 priority,
left--;
val |= data[blocks * 4 + left];
}
- l ^= val;
- michael_block(l, r);
- /* last block is zero, so l ^ 0 = l */
- michael_block(l, r);
- michael_put32(l, mic);
- michael_put32(r, mic + 4);
+ michael_block(&mctx, val);
+ michael_block(&mctx, 0);
+
+ put_unaligned_le32(mctx.l, mic);
+ put_unaligned_le32(mctx.r, mic + 4);
}
diff --git a/net/mac80211/michael.h b/net/mac80211/michael.h
index 2e6aebabeea1..69b4501f13ba 100644
--- a/net/mac80211/michael.h
+++ b/net/mac80211/michael.h
@@ -14,7 +14,11 @@
#define MICHAEL_MIC_LEN 8
-void michael_mic(u8 *key, u8 *da, u8 *sa, u8 priority,
- u8 *data, size_t data_len, u8 *mic);
+struct michael_mic_ctx {
+ u32 l, r;
+};
+
+void michael_mic(const u8 *key, const u8 *da, const u8 *sa, u8 priority,
+ const u8 *data, size_t data_len, u8 *mic);
#endif /* MICHAEL_H */
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 4adba09e80ca..7f05820dc629 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -44,7 +44,7 @@
#define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ)
#define IEEE80211_SCAN_INTERVAL (2 * HZ)
#define IEEE80211_SCAN_INTERVAL_SLOW (15 * HZ)
-#define IEEE80211_IBSS_JOIN_TIMEOUT (20 * HZ)
+#define IEEE80211_IBSS_JOIN_TIMEOUT (7 * HZ)
#define IEEE80211_PROBE_DELAY (HZ / 33)
#define IEEE80211_CHANNEL_TIME (HZ / 33)
@@ -87,6 +87,7 @@ static int ieee80211_sta_start_scan(struct net_device *dev,
u8 *ssid, size_t ssid_len);
static int ieee80211_sta_config_auth(struct net_device *dev,
struct ieee80211_if_sta *ifsta);
+static void sta_rx_agg_session_timer_expired(unsigned long data);
void ieee802_11_parse_elems(u8 *start, size_t len,
@@ -256,19 +257,8 @@ static void ieee80211_sta_def_wmm_params(struct net_device *dev,
qparam.cw_max = 1023;
qparam.txop = 0;
- for (i = IEEE80211_TX_QUEUE_DATA0; i < NUM_TX_DATA_QUEUES; i++)
- local->ops->conf_tx(local_to_hw(local),
- i + IEEE80211_TX_QUEUE_DATA0,
- &qparam);
-
- if (ibss) {
- /* IBSS uses different parameters for Beacon sending */
- qparam.cw_min++;
- qparam.cw_min *= 2;
- qparam.cw_min--;
- local->ops->conf_tx(local_to_hw(local),
- IEEE80211_TX_QUEUE_BEACON, &qparam);
- }
+ for (i = 0; i < local_to_hw(local)->queues; i++)
+ local->ops->conf_tx(local_to_hw(local), i, &qparam);
}
}
@@ -282,6 +272,12 @@ static void ieee80211_sta_wmm_params(struct net_device *dev,
int count;
u8 *pos;
+ if (!(ifsta->flags & IEEE80211_STA_WMM_ENABLED))
+ return;
+
+ if (!wmm_param)
+ return;
+
if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1)
return;
count = wmm_param[6] & 0x0f;
@@ -305,29 +301,25 @@ static void ieee80211_sta_wmm_params(struct net_device *dev,
switch (aci) {
case 1:
- queue = IEEE80211_TX_QUEUE_DATA3;
- if (acm) {
+ queue = 3;
+ if (acm)
local->wmm_acm |= BIT(0) | BIT(3);
- }
break;
case 2:
- queue = IEEE80211_TX_QUEUE_DATA1;
- if (acm) {
+ queue = 1;
+ if (acm)
local->wmm_acm |= BIT(4) | BIT(5);
- }
break;
case 3:
- queue = IEEE80211_TX_QUEUE_DATA0;
- if (acm) {
+ queue = 0;
+ if (acm)
local->wmm_acm |= BIT(6) | BIT(7);
- }
break;
case 0:
default:
- queue = IEEE80211_TX_QUEUE_DATA2;
- if (acm) {
+ queue = 2;
+ if (acm)
local->wmm_acm |= BIT(1) | BIT(2);
- }
break;
}
@@ -586,7 +578,7 @@ void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb,
int encrypt)
{
struct ieee80211_sub_if_data *sdata;
- struct ieee80211_tx_packet_data *pkt_data;
+ struct ieee80211_tx_info *info;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
skb->dev = sdata->local->mdev;
@@ -594,11 +586,11 @@ void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb,
skb_set_network_header(skb, 0);
skb_set_transport_header(skb, 0);
- pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
- memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
- pkt_data->ifindex = sdata->dev->ifindex;
+ info = IEEE80211_SKB_CB(skb);
+ memset(info, 0, sizeof(struct ieee80211_tx_info));
+ info->control.ifindex = sdata->dev->ifindex;
if (!encrypt)
- pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;
+ info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
dev_queue_xmit(skb);
}
@@ -727,10 +719,19 @@ static void ieee80211_send_assoc(struct net_device *dev,
if (bss) {
if (bss->capability & WLAN_CAPABILITY_PRIVACY)
capab |= WLAN_CAPABILITY_PRIVACY;
- if (bss->wmm_ie) {
+ if (bss->wmm_ie)
wmm = 1;
- }
+
+ /* get all rates supported by the device and the AP as
+ * some APs don't like getting a superset of their rates
+ * in the association request (e.g. D-Link DAP 1353 in
+ * b-only mode) */
+ rates_len = ieee80211_compatible_rates(bss, sband, &rates);
+
ieee80211_rx_bss_put(dev, bss);
+ } else {
+ rates = ~0;
+ rates_len = sband->n_bitrates;
}
mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
@@ -761,10 +762,7 @@ static void ieee80211_send_assoc(struct net_device *dev,
*pos++ = ifsta->ssid_len;
memcpy(pos, ifsta->ssid, ifsta->ssid_len);
- /* all supported rates should be added here but some APs
- * (e.g. D-Link DAP 1353 in b-only mode) don't like that
- * Therefore only add rates the AP supports */
- rates_len = ieee80211_compatible_rates(bss, sband, &rates);
+ /* add all rates which were marked to be used above */
supp_rates_len = rates_len;
if (supp_rates_len > 8)
supp_rates_len = 8;
@@ -814,9 +812,32 @@ static void ieee80211_send_assoc(struct net_device *dev,
*pos++ = 1; /* WME ver */
*pos++ = 0;
}
+
/* wmm support is a must to HT */
- if (wmm && sband->ht_info.ht_supported) {
- __le16 tmp = cpu_to_le16(sband->ht_info.cap);
+ if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) &&
+ sband->ht_info.ht_supported && bss->ht_add_ie) {
+ struct ieee80211_ht_addt_info *ht_add_info =
+ (struct ieee80211_ht_addt_info *)bss->ht_add_ie;
+ u16 cap = sband->ht_info.cap;
+ __le16 tmp;
+ u32 flags = local->hw.conf.channel->flags;
+
+ switch (ht_add_info->ht_param & IEEE80211_HT_IE_CHA_SEC_OFFSET) {
+ case IEEE80211_HT_IE_CHA_SEC_ABOVE:
+ if (flags & IEEE80211_CHAN_NO_FAT_ABOVE) {
+ cap &= ~IEEE80211_HT_CAP_SUP_WIDTH;
+ cap &= ~IEEE80211_HT_CAP_SGI_40;
+ }
+ break;
+ case IEEE80211_HT_IE_CHA_SEC_BELOW:
+ if (flags & IEEE80211_CHAN_NO_FAT_BELOW) {
+ cap &= ~IEEE80211_HT_CAP_SUP_WIDTH;
+ cap &= ~IEEE80211_HT_CAP_SGI_40;
+ }
+ break;
+ }
+
+ tmp = cpu_to_le16(cap);
pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2);
*pos++ = WLAN_EID_HT_CAPABILITY;
*pos++ = sizeof(struct ieee80211_ht_cap);
@@ -1134,8 +1155,8 @@ static void ieee80211_send_addba_resp(struct net_device *dev, u8 *da, u16 tid,
struct ieee80211_mgmt *mgmt;
u16 capab;
- skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 +
- sizeof(mgmt->u.action.u.addba_resp));
+ skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
+
if (!skb) {
printk(KERN_DEBUG "%s: failed to allocate buffer "
"for addba resp frame\n", dev->name);
@@ -1183,9 +1204,7 @@ void ieee80211_send_addba_request(struct net_device *dev, const u8 *da,
struct ieee80211_mgmt *mgmt;
u16 capab;
- skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 +
- sizeof(mgmt->u.action.u.addba_req));
-
+ skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
if (!skb) {
printk(KERN_ERR "%s: failed to allocate buffer "
@@ -1286,7 +1305,7 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev,
/* examine state machine */
- spin_lock_bh(&sta->ampdu_mlme.ampdu_rx);
+ spin_lock_bh(&sta->lock);
if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_IDLE) {
#ifdef CONFIG_MAC80211_HT_DEBUG
@@ -1318,7 +1337,7 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev,
/* prepare reordering buffer */
tid_agg_rx->reorder_buf =
- kmalloc(buf_size * sizeof(struct sk_buf *), GFP_ATOMIC);
+ kmalloc(buf_size * sizeof(struct sk_buff *), GFP_ATOMIC);
if (!tid_agg_rx->reorder_buf) {
if (net_ratelimit())
printk(KERN_ERR "can not allocate reordering buffer "
@@ -1327,7 +1346,7 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev,
goto end;
}
memset(tid_agg_rx->reorder_buf, 0,
- buf_size * sizeof(struct sk_buf *));
+ buf_size * sizeof(struct sk_buff *));
if (local->ops->ampdu_action)
ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START,
@@ -1353,7 +1372,7 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev,
tid_agg_rx->stored_mpdu_num = 0;
status = WLAN_STATUS_SUCCESS;
end:
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
+ spin_unlock_bh(&sta->lock);
end_no_lock:
ieee80211_send_addba_resp(sta->sdata->dev, sta->addr, tid,
@@ -1385,10 +1404,10 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev,
state = &sta->ampdu_mlme.tid_state_tx[tid];
- spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_lock_bh(&sta->lock);
if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
printk(KERN_DEBUG "state not HT_ADDBA_REQUESTED_MSK:"
"%d\n", *state);
goto addba_resp_exit;
@@ -1396,7 +1415,7 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev,
if (mgmt->u.action.u.addba_resp.dialog_token !=
sta->ampdu_mlme.tid_tx[tid]->dialog_token) {
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid);
#endif /* CONFIG_MAC80211_HT_DEBUG */
@@ -1420,7 +1439,7 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev,
ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
}
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
printk(KERN_DEBUG "recipient accepted agg: tid %d \n", tid);
} else {
printk(KERN_DEBUG "recipient rejected agg: tid %d \n", tid);
@@ -1428,7 +1447,7 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev,
sta->ampdu_mlme.addba_req_num[tid]++;
/* this will allow the state check in stop_BA_session */
*state = HT_AGG_STATE_OPERATIONAL;
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
ieee80211_stop_tx_ba_session(hw, sta->addr, tid,
WLAN_BACK_INITIATOR);
}
@@ -1447,8 +1466,7 @@ void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid,
struct ieee80211_mgmt *mgmt;
u16 params;
- skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 +
- sizeof(mgmt->u.action.u.delba));
+ skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom);
if (!skb) {
printk(KERN_ERR "%s: failed to allocate buffer "
@@ -1499,17 +1517,17 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid,
}
/* check if TID is in operational state */
- spin_lock_bh(&sta->ampdu_mlme.ampdu_rx);
+ spin_lock_bh(&sta->lock);
if (sta->ampdu_mlme.tid_state_rx[tid]
!= HT_AGG_STATE_OPERATIONAL) {
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
+ spin_unlock_bh(&sta->lock);
rcu_read_unlock();
return;
}
sta->ampdu_mlme.tid_state_rx[tid] =
HT_AGG_STATE_REQ_STOP_BA_MSK |
(initiator << HT_AGG_STATE_INITIATOR_SHIFT);
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
+ spin_unlock_bh(&sta->lock);
/* stop HW Rx aggregation. ampdu_action existence
* already verified in session init so we add the BUG_ON */
@@ -1586,10 +1604,10 @@ static void ieee80211_sta_process_delba(struct net_device *dev,
ieee80211_sta_stop_rx_ba_session(dev, sta->addr, tid,
WLAN_BACK_INITIATOR, 0);
else { /* WLAN_BACK_RECIPIENT */
- spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_lock_bh(&sta->lock);
sta->ampdu_mlme.tid_state_tx[tid] =
HT_AGG_STATE_OPERATIONAL;
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
ieee80211_stop_tx_ba_session(&local->hw, sta->addr, tid,
WLAN_BACK_RECIPIENT);
}
@@ -1607,7 +1625,7 @@ void sta_addba_resp_timer_expired(unsigned long data)
* only one argument, and both sta_info and TID are needed, so init
* flow in sta_info_create gives the TID as data, while the timer_to_id
* array gives the sta through container_of */
- u16 tid = *(int *)data;
+ u16 tid = *(u8 *)data;
struct sta_info *temp_sta = container_of((void *)data,
struct sta_info, timer_to_tid[tid]);
@@ -1626,9 +1644,9 @@ void sta_addba_resp_timer_expired(unsigned long data)
state = &sta->ampdu_mlme.tid_state_tx[tid];
/* check if the TID waits for addBA response */
- spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_lock_bh(&sta->lock);
if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
*state = HT_AGG_STATE_IDLE;
printk(KERN_DEBUG "timer expired on tid %d but we are not "
"expecting addBA response there", tid);
@@ -1639,7 +1657,7 @@ void sta_addba_resp_timer_expired(unsigned long data)
/* go through the state check in stop_BA_session */
*state = HT_AGG_STATE_OPERATIONAL;
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
ieee80211_stop_tx_ba_session(hw, temp_sta->addr, tid,
WLAN_BACK_INITIATOR);
@@ -1652,10 +1670,10 @@ timer_expired_exit:
* resetting it after each frame that arrives from the originator.
* if this timer expires ieee80211_sta_stop_rx_ba_session will be executed.
*/
-void sta_rx_agg_session_timer_expired(unsigned long data)
+static void sta_rx_agg_session_timer_expired(unsigned long data)
{
/* not an elegant detour, but there is no choice as the timer passes
- * only one argument, and verious sta_info are needed here, so init
+ * only one argument, and various sta_info are needed here, so init
* flow in sta_info_create gives the TID as data, while the timer_to_id
* array gives the sta through container_of */
u8 *ptid = (u8 *)data;
@@ -1841,9 +1859,8 @@ static void ieee80211_rx_mgmt_deauth(struct net_device *dev,
" (reason=%d)\n",
dev->name, print_mac(mac, mgmt->sa), reason_code);
- if (ifsta->flags & IEEE80211_STA_AUTHENTICATED) {
+ if (ifsta->flags & IEEE80211_STA_AUTHENTICATED)
printk(KERN_DEBUG "%s: deauthenticated\n", dev->name);
- }
if (ifsta->state == IEEE80211_AUTHENTICATE ||
ifsta->state == IEEE80211_ASSOCIATE ||
@@ -2006,8 +2023,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
local->hw.conf.channel->center_freq,
ifsta->ssid, ifsta->ssid_len);
if (bss) {
- sta->last_rssi = bss->rssi;
sta->last_signal = bss->signal;
+ sta->last_qual = bss->qual;
sta->last_noise = bss->noise;
ieee80211_rx_bss_put(dev, bss);
}
@@ -2031,8 +2048,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
* to between the sta_info_alloc() and sta_info_insert() above.
*/
- sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP |
- WLAN_STA_AUTHORIZED;
+ set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP |
+ WLAN_STA_AUTHORIZED);
rates = 0;
basic_rates = 0;
@@ -2076,7 +2093,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
else
sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
- if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param) {
+ if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param &&
+ (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
struct ieee80211_ht_bss_info bss_info;
ieee80211_ht_cap_ie_to_ht_info(
(struct ieee80211_ht_cap *)
@@ -2089,8 +2107,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
rate_control_rate_init(sta, local);
- if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
- sta->flags |= WLAN_STA_WME;
+ if (elems.wmm_param) {
+ set_sta_flags(sta, WLAN_STA_WME);
rcu_read_unlock();
ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
elems.wmm_param_len);
@@ -2274,6 +2292,7 @@ static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss)
kfree(bss->rsn_ie);
kfree(bss->wmm_ie);
kfree(bss->ht_ie);
+ kfree(bss->ht_add_ie);
kfree(bss_mesh_id(bss));
kfree(bss_mesh_cfg(bss));
kfree(bss);
@@ -2324,11 +2343,12 @@ 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_control control;
+ struct ieee80211_tx_info *control;
struct rate_selection ratesel;
u8 *pos;
struct ieee80211_sub_if_data *sdata;
struct ieee80211_supported_band *sband;
+ union iwreq_data wrqu;
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
@@ -2351,13 +2371,10 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
sdata->drop_unencrypted = bss->capability &
WLAN_CAPABILITY_PRIVACY ? 1 : 0;
- res = ieee80211_set_freq(local, bss->freq);
+ res = ieee80211_set_freq(dev, bss->freq);
- if (local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS) {
- printk(KERN_DEBUG "%s: IBSS not allowed on frequency "
- "%d MHz\n", dev->name, local->oper_channel->center_freq);
- return -1;
- }
+ if (res)
+ return res;
/* Set beacon template */
skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
@@ -2414,21 +2431,22 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
memcpy(pos, &bss->supp_rates[8], rates);
}
- memset(&control, 0, sizeof(control));
+ control = IEEE80211_SKB_CB(skb);
+
rate_control_get_rate(dev, sband, skb, &ratesel);
- if (!ratesel.rate) {
+ if (ratesel.rate_idx < 0) {
printk(KERN_DEBUG "%s: Failed to determine TX rate "
"for IBSS beacon\n", dev->name);
break;
}
- control.vif = &sdata->vif;
- control.tx_rate = ratesel.rate;
+ control->control.vif = &sdata->vif;
+ control->tx_rate_idx = ratesel.rate_idx;
if (sdata->bss_conf.use_short_preamble &&
- ratesel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
- control.flags |= IEEE80211_TXCTL_SHORT_PREAMBLE;
- control.antenna_sel_tx = local->hw.conf.antenna_sel_tx;
- control.flags |= IEEE80211_TXCTL_NO_ACK;
- control.retry_limit = 1;
+ 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->control.retry_limit = 1;
ifsta->probe_resp = skb_copy(skb, GFP_ATOMIC);
if (ifsta->probe_resp) {
@@ -2443,8 +2461,7 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
}
if (local->ops->beacon_update &&
- local->ops->beacon_update(local_to_hw(local),
- skb, &control) == 0) {
+ local->ops->beacon_update(local_to_hw(local), skb) == 0) {
printk(KERN_DEBUG "%s: Configured IBSS beacon "
"template\n", dev->name);
skb = NULL;
@@ -2472,7 +2489,9 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
ifsta->state = IEEE80211_IBSS_JOINED;
mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
- ieee80211_rx_bss_put(dev, bss);
+ memset(&wrqu, 0, sizeof(wrqu));
+ memcpy(wrqu.ap_addr.sa_data, bss->bssid, ETH_ALEN);
+ wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
return res;
}
@@ -2650,6 +2669,26 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
bss->ht_ie_len = 0;
}
+ if (elems.ht_info_elem &&
+ (!bss->ht_add_ie ||
+ bss->ht_add_ie_len != elems.ht_info_elem_len ||
+ memcmp(bss->ht_add_ie, elems.ht_info_elem,
+ elems.ht_info_elem_len))) {
+ kfree(bss->ht_add_ie);
+ bss->ht_add_ie =
+ kmalloc(elems.ht_info_elem_len + 2, GFP_ATOMIC);
+ if (bss->ht_add_ie) {
+ memcpy(bss->ht_add_ie, elems.ht_info_elem - 2,
+ elems.ht_info_elem_len + 2);
+ bss->ht_add_ie_len = elems.ht_info_elem_len + 2;
+ } else
+ bss->ht_add_ie_len = 0;
+ } else if (!elems.ht_info_elem && bss->ht_add_ie) {
+ kfree(bss->ht_add_ie);
+ bss->ht_add_ie = NULL;
+ bss->ht_add_ie_len = 0;
+ }
+
bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int);
bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info);
@@ -2675,9 +2714,9 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
bss->timestamp = beacon_timestamp;
bss->last_update = jiffies;
- bss->rssi = rx_status->ssi;
bss->signal = rx_status->signal;
bss->noise = rx_status->noise;
+ bss->qual = rx_status->qual;
if (!beacon && !bss->probe_resp)
bss->probe_resp = true;
@@ -2872,10 +2911,8 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev,
ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
- if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
- ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
- elems.wmm_param_len);
- }
+ ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
+ elems.wmm_param_len);
/* Do not send changes to driver if we are scanning. This removes
* requirement that driver's bss_info_changed function needs to be
@@ -3446,21 +3483,17 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
struct ieee80211_sta_bss *bss, *selected = NULL;
int top_rssi = 0, freq;
- if (!(ifsta->flags & (IEEE80211_STA_AUTO_SSID_SEL |
- IEEE80211_STA_AUTO_BSSID_SEL | IEEE80211_STA_AUTO_CHANNEL_SEL))) {
- ifsta->state = IEEE80211_AUTHENTICATE;
- ieee80211_sta_reset_auth(dev, ifsta);
- return 0;
- }
-
spin_lock_bh(&local->sta_bss_lock);
freq = local->oper_channel->center_freq;
list_for_each_entry(bss, &local->sta_bss_list, list) {
if (!(bss->capability & WLAN_CAPABILITY_ESS))
continue;
- if (!!(bss->capability & WLAN_CAPABILITY_PRIVACY) ^
- !!sdata->default_key)
+ if ((ifsta->flags & (IEEE80211_STA_AUTO_SSID_SEL |
+ IEEE80211_STA_AUTO_BSSID_SEL |
+ IEEE80211_STA_AUTO_CHANNEL_SEL)) &&
+ (!!(bss->capability & WLAN_CAPABILITY_PRIVACY) ^
+ !!sdata->default_key))
continue;
if (!(ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL) &&
@@ -3475,9 +3508,9 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
!ieee80211_sta_match_ssid(ifsta, bss->ssid, bss->ssid_len))
continue;
- if (!selected || top_rssi < bss->rssi) {
+ if (!selected || top_rssi < bss->signal) {
selected = bss;
- top_rssi = bss->rssi;
+ top_rssi = bss->signal;
}
}
if (selected)
@@ -3485,7 +3518,7 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
spin_unlock_bh(&local->sta_bss_lock);
if (selected) {
- ieee80211_set_freq(local, selected->freq);
+ ieee80211_set_freq(dev, selected->freq);
if (!(ifsta->flags & IEEE80211_STA_SSID_SET))
ieee80211_sta_set_ssid(dev, selected->ssid,
selected->ssid_len);
@@ -3520,6 +3553,7 @@ static int ieee80211_sta_create_ibss(struct net_device *dev,
struct ieee80211_supported_band *sband;
u8 bssid[ETH_ALEN], *pos;
int i;
+ int ret;
DECLARE_MAC_BUF(mac);
#if 0
@@ -3553,10 +3587,12 @@ static int ieee80211_sta_create_ibss(struct net_device *dev,
bss->beacon_int = local->hw.conf.beacon_int;
bss->last_update = jiffies;
bss->capability = WLAN_CAPABILITY_IBSS;
- if (sdata->default_key) {
+
+ if (sdata->default_key)
bss->capability |= WLAN_CAPABILITY_PRIVACY;
- } else
+ else
sdata->drop_unencrypted = 0;
+
bss->supp_rates_len = sband->n_bitrates;
pos = bss->supp_rates;
for (i = 0; i < sband->n_bitrates; i++) {
@@ -3564,7 +3600,9 @@ static int ieee80211_sta_create_ibss(struct net_device *dev,
*pos++ = (u8) (rate / 5);
}
- return ieee80211_sta_join_ibss(dev, ifsta, bss);
+ ret = ieee80211_sta_join_ibss(dev, ifsta, bss);
+ ieee80211_rx_bss_put(dev, bss);
+ return ret;
}
@@ -3612,10 +3650,13 @@ static int ieee80211_sta_find_ibss(struct net_device *dev,
(bss = ieee80211_rx_bss_get(dev, bssid,
local->hw.conf.channel->center_freq,
ifsta->ssid, ifsta->ssid_len))) {
+ int ret;
printk(KERN_DEBUG "%s: Selected IBSS BSSID %s"
" based on configured SSID\n",
dev->name, print_mac(mac, bssid));
- return ieee80211_sta_join_ibss(dev, ifsta, bss);
+ ret = ieee80211_sta_join_ibss(dev, ifsta, bss);
+ ieee80211_rx_bss_put(dev, bss);
+ return ret;
}
#ifdef CONFIG_MAC80211_IBSS_DEBUG
printk(KERN_DEBUG " did not try to join ibss\n");
@@ -4092,22 +4133,21 @@ ieee80211_sta_scan_result(struct net_device *dev,
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = SIOCGIWFREQ;
- iwe.u.freq.m = bss->freq;
- iwe.u.freq.e = 6;
+ iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq);
+ iwe.u.freq.e = 0;
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
IW_EV_FREQ_LEN);
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = SIOCGIWFREQ;
- iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq);
- iwe.u.freq.e = 0;
+ iwe.u.freq.m = bss->freq;
+ iwe.u.freq.e = 6;
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
IW_EV_FREQ_LEN);
-
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = IWEVQUAL;
- iwe.u.qual.qual = bss->signal;
- iwe.u.qual.level = bss->rssi;
+ iwe.u.qual.qual = bss->qual;
+ iwe.u.qual.level = bss->signal;
iwe.u.qual.noise = bss->noise;
iwe.u.qual.updated = local->wstats_flags;
current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
@@ -4138,6 +4178,14 @@ ieee80211_sta_scan_result(struct net_device *dev,
bss->rsn_ie);
}
+ if (bss && bss->ht_ie) {
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length = bss->ht_ie_len;
+ current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
+ bss->ht_ie);
+ }
+
if (bss && bss->supp_rates_len > 0) {
/* display all supported rates in readable format */
char *p = current_ev + IW_EV_LCP_LEN;
@@ -4239,6 +4287,7 @@ int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+
kfree(ifsta->extra_ie);
if (len == 0) {
ifsta->extra_ie = NULL;
@@ -4256,9 +4305,9 @@ 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,
- u8 *addr)
+struct sta_info *ieee80211_ibss_add_sta(struct net_device *dev,
+ struct sk_buff *skb, u8 *bssid,
+ u8 *addr)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct sta_info *sta;
@@ -4282,7 +4331,7 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev,
if (!sta)
return NULL;
- sta->flags |= WLAN_STA_AUTHORIZED;
+ set_sta_flags(sta, WLAN_STA_AUTHORIZED);
sta->supp_rates[local->hw.conf.channel->band] =
sdata->u.sta.supp_rates_bits[local->hw.conf.channel->band];
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c
index 841df93807fc..0388c090dfe9 100644
--- a/net/mac80211/rate.c
+++ b/net/mac80211/rate.c
@@ -176,20 +176,24 @@ void rate_control_get_rate(struct net_device *dev,
rcu_read_lock();
sta = sta_info_get(local, hdr->addr1);
- memset(sel, 0, sizeof(struct rate_selection));
+ sel->rate_idx = -1;
+ sel->nonerp_idx = -1;
+ sel->probe_idx = -1;
ref->ops->get_rate(ref->priv, dev, sband, skb, sel);
+ BUG_ON(sel->rate_idx < 0);
+
/* Select a non-ERP backup rate. */
- if (!sel->nonerp) {
+ if (sel->nonerp_idx < 0) {
for (i = 0; i < sband->n_bitrates; i++) {
struct ieee80211_rate *rate = &sband->bitrates[i];
- if (sel->rate->bitrate < rate->bitrate)
+ if (sband->bitrates[sel->rate_idx].bitrate < rate->bitrate)
break;
if (rate_supported(sta, sband->band, i) &&
!(rate->flags & IEEE80211_RATE_ERP_G))
- sel->nonerp = rate;
+ sel->nonerp_idx = i;
}
}
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h
index 5b45f33cb766..0ed9c8a2f56f 100644
--- a/net/mac80211/rate.h
+++ b/net/mac80211/rate.h
@@ -19,22 +19,22 @@
#include "ieee80211_i.h"
#include "sta_info.h"
-/* TODO: kdoc */
+/**
+ * struct rate_selection - rate selection for rate control algos
+ * @rate: selected transmission rate index
+ * @nonerp: Non-ERP rate to use instead if ERP cannot be used
+ * @probe: rate for probing (or -1)
+ *
+ */
struct rate_selection {
- /* Selected transmission rate */
- struct ieee80211_rate *rate;
- /* Non-ERP rate to use if mac80211 decides it cannot use an ERP rate */
- struct ieee80211_rate *nonerp;
- /* probe with this rate, or NULL for no probing */
- struct ieee80211_rate *probe;
+ s8 rate_idx, nonerp_idx, probe_idx;
};
struct rate_control_ops {
struct module *module;
const char *name;
void (*tx_status)(void *priv, struct net_device *dev,
- struct sk_buff *skb,
- struct ieee80211_tx_status *status);
+ struct sk_buff *skb);
void (*get_rate)(void *priv, struct net_device *dev,
struct ieee80211_supported_band *band,
struct sk_buff *skb,
@@ -76,13 +76,12 @@ struct rate_control_ref *rate_control_get(struct rate_control_ref *ref);
void rate_control_put(struct rate_control_ref *ref);
static inline void rate_control_tx_status(struct net_device *dev,
- struct sk_buff *skb,
- struct ieee80211_tx_status *status)
+ struct sk_buff *skb)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct rate_control_ref *ref = local->rate_ctrl;
- ref->ops->tx_status(ref->priv, dev, skb, status);
+ ref->ops->tx_status(ref->priv, dev, skb);
}
@@ -138,7 +137,7 @@ static inline int rate_supported(struct sta_info *sta,
return (sta == NULL || sta->supp_rates[band] & BIT(index));
}
-static inline int
+static inline s8
rate_lowest_index(struct ieee80211_local *local,
struct ieee80211_supported_band *sband,
struct sta_info *sta)
@@ -155,14 +154,6 @@ rate_lowest_index(struct ieee80211_local *local,
return 0;
}
-static inline struct ieee80211_rate *
-rate_lowest(struct ieee80211_local *local,
- struct ieee80211_supported_band *sband,
- struct sta_info *sta)
-{
- return &sband->bitrates[rate_lowest_index(local, sband, sta)];
-}
-
/* functions for rate control related to a device */
int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
diff --git a/net/mac80211/rc80211_pid.h b/net/mac80211/rc80211_pid.h
index 04afc13ed825..2078803d3581 100644
--- a/net/mac80211/rc80211_pid.h
+++ b/net/mac80211/rc80211_pid.h
@@ -61,7 +61,7 @@ enum rc_pid_event_type {
union rc_pid_event_data {
/* RC_PID_EVENT_TX_STATUS */
struct {
- struct ieee80211_tx_status tx_status;
+ struct ieee80211_tx_info tx_status;
};
/* RC_PID_EVENT_TYPE_RATE_CHANGE */
/* RC_PID_EVENT_TYPE_TX_RATE */
@@ -158,7 +158,7 @@ struct rc_pid_debugfs_entries {
};
void rate_control_pid_event_tx_status(struct rc_pid_event_buffer *buf,
- struct ieee80211_tx_status *stat);
+ struct ieee80211_tx_info *stat);
void rate_control_pid_event_rate_change(struct rc_pid_event_buffer *buf,
int index, int rate);
diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c
index a849b745bdb5..e8945413e4a2 100644
--- a/net/mac80211/rc80211_pid_algo.c
+++ b/net/mac80211/rc80211_pid_algo.c
@@ -237,8 +237,7 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo,
}
static void rate_control_pid_tx_status(void *priv, struct net_device *dev,
- struct sk_buff *skb,
- struct ieee80211_tx_status *status)
+ struct sk_buff *skb)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
@@ -248,6 +247,7 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev,
struct rc_pid_sta_info *spinfo;
unsigned long period;
struct ieee80211_supported_band *sband;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
rcu_read_lock();
@@ -266,28 +266,28 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev,
/* Ignore all frames that were sent with a different rate than the rate
* we currently advise mac80211 to use. */
- if (status->control.tx_rate != &sband->bitrates[sta->txrate_idx])
+ if (info->tx_rate_idx != sta->txrate_idx)
goto unlock;
spinfo = sta->rate_ctrl_priv;
spinfo->tx_num_xmit++;
#ifdef CONFIG_MAC80211_DEBUGFS
- rate_control_pid_event_tx_status(&spinfo->events, status);
+ rate_control_pid_event_tx_status(&spinfo->events, info);
#endif
/* We count frames that totally failed to be transmitted as two bad
* frames, those that made it out but had some retries as one good and
* one bad frame. */
- if (status->excessive_retries) {
+ if (info->status.excessive_retries) {
spinfo->tx_num_failed += 2;
spinfo->tx_num_xmit++;
- } else if (status->retry_count) {
+ } else if (info->status.retry_count) {
spinfo->tx_num_failed++;
spinfo->tx_num_xmit++;
}
- if (status->excessive_retries) {
+ if (info->status.excessive_retries) {
sta->tx_retry_failed++;
sta->tx_num_consecutive_failures++;
sta->tx_num_mpdu_fail++;
@@ -295,8 +295,8 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev,
sta->tx_num_consecutive_failures = 0;
sta->tx_num_mpdu_ok++;
}
- sta->tx_retry_count += status->retry_count;
- sta->tx_num_mpdu_fail += status->retry_count;
+ sta->tx_retry_count += info->status.retry_count;
+ sta->tx_num_mpdu_fail += info->status.retry_count;
/* Update PID controller state. */
period = (HZ * pinfo->sampling_period + 500) / 1000;
@@ -330,7 +330,7 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev,
fc = le16_to_cpu(hdr->frame_control);
if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
is_multicast_ether_addr(hdr->addr1) || !sta) {
- sel->rate = rate_lowest(local, sband, sta);
+ sel->rate_idx = rate_lowest_index(local, sband, sta);
rcu_read_unlock();
return;
}
@@ -349,7 +349,7 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev,
rcu_read_unlock();
- sel->rate = &sband->bitrates[rateidx];
+ sel->rate_idx = rateidx;
#ifdef CONFIG_MAC80211_DEBUGFS
rate_control_pid_event_tx_rate(
diff --git a/net/mac80211/rc80211_pid_debugfs.c b/net/mac80211/rc80211_pid_debugfs.c
index ff5c380f3c13..8121d3bc6835 100644
--- a/net/mac80211/rc80211_pid_debugfs.c
+++ b/net/mac80211/rc80211_pid_debugfs.c
@@ -39,11 +39,11 @@ static void rate_control_pid_event(struct rc_pid_event_buffer *buf,
}
void rate_control_pid_event_tx_status(struct rc_pid_event_buffer *buf,
- struct ieee80211_tx_status *stat)
+ struct ieee80211_tx_info *stat)
{
union rc_pid_event_data evd;
- memcpy(&evd.tx_status, stat, sizeof(struct ieee80211_tx_status));
+ memcpy(&evd.tx_status, stat, sizeof(struct ieee80211_tx_info));
rate_control_pid_event(buf, RC_PID_EVENT_TYPE_TX_STATUS, &evd);
}
@@ -167,8 +167,8 @@ static ssize_t rate_control_pid_events_read(struct file *file, char __user *buf,
switch (ev->type) {
case RC_PID_EVENT_TYPE_TX_STATUS:
p += snprintf(pb + p, length - p, "tx_status %u %u",
- ev->data.tx_status.excessive_retries,
- ev->data.tx_status.retry_count);
+ ev->data.tx_status.status.excessive_retries,
+ ev->data.tx_status.status.retry_count);
break;
case RC_PID_EVENT_TYPE_RATE_CHANGE:
p += snprintf(pb + p, length - p, "rate_change %d %d",
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 1958bfb361c6..a3643fd86af9 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -77,6 +77,134 @@ static inline int should_drop_frame(struct ieee80211_rx_status *status,
return 0;
}
+static int
+ieee80211_rx_radiotap_len(struct ieee80211_local *local,
+ struct ieee80211_rx_status *status)
+{
+ int len;
+
+ /* always present fields */
+ len = sizeof(struct ieee80211_radiotap_header) + 9;
+
+ if (status->flag & RX_FLAG_TSFT)
+ len += 8;
+ if (local->hw.flags & IEEE80211_HW_SIGNAL_DB ||
+ local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
+ len += 1;
+ if (local->hw.flags & IEEE80211_HW_NOISE_DBM)
+ len += 1;
+
+ if (len & 1) /* padding for RX_FLAGS if necessary */
+ len++;
+
+ /* make sure radiotap starts at a naturally aligned address */
+ if (len % 8)
+ len = roundup(len, 8);
+
+ return len;
+}
+
+/**
+ * ieee80211_add_rx_radiotap_header - add radiotap header
+ *
+ * add a radiotap header containing all the fields which the hardware provided.
+ */
+static void
+ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
+ struct sk_buff *skb,
+ struct ieee80211_rx_status *status,
+ struct ieee80211_rate *rate,
+ int rtap_len)
+{
+ struct ieee80211_radiotap_header *rthdr;
+ unsigned char *pos;
+
+ rthdr = (struct ieee80211_radiotap_header *)skb_push(skb, rtap_len);
+ memset(rthdr, 0, rtap_len);
+
+ /* radiotap header, set always present flags */
+ rthdr->it_present =
+ cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
+ (1 << IEEE80211_RADIOTAP_RATE) |
+ (1 << IEEE80211_RADIOTAP_CHANNEL) |
+ (1 << IEEE80211_RADIOTAP_ANTENNA) |
+ (1 << IEEE80211_RADIOTAP_RX_FLAGS));
+ rthdr->it_len = cpu_to_le16(rtap_len);
+
+ pos = (unsigned char *)(rthdr+1);
+
+ /* the order of the following fields is important */
+
+ /* IEEE80211_RADIOTAP_TSFT */
+ if (status->flag & RX_FLAG_TSFT) {
+ *(__le64 *)pos = cpu_to_le64(status->mactime);
+ rthdr->it_present |=
+ cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT);
+ pos += 8;
+ }
+
+ /* IEEE80211_RADIOTAP_FLAGS */
+ if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
+ *pos |= IEEE80211_RADIOTAP_F_FCS;
+ pos++;
+
+ /* IEEE80211_RADIOTAP_RATE */
+ *pos = rate->bitrate / 5;
+ pos++;
+
+ /* IEEE80211_RADIOTAP_CHANNEL */
+ *(__le16 *)pos = cpu_to_le16(status->freq);
+ pos += 2;
+ if (status->band == IEEE80211_BAND_5GHZ)
+ *(__le16 *)pos = cpu_to_le16(IEEE80211_CHAN_OFDM |
+ IEEE80211_CHAN_5GHZ);
+ else
+ *(__le16 *)pos = cpu_to_le16(IEEE80211_CHAN_DYN |
+ IEEE80211_CHAN_2GHZ);
+ pos += 2;
+
+ /* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */
+ if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) {
+ *pos = status->signal;
+ rthdr->it_present |=
+ cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL);
+ pos++;
+ }
+
+ /* IEEE80211_RADIOTAP_DBM_ANTNOISE */
+ if (local->hw.flags & IEEE80211_HW_NOISE_DBM) {
+ *pos = status->noise;
+ rthdr->it_present |=
+ cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTNOISE);
+ pos++;
+ }
+
+ /* IEEE80211_RADIOTAP_LOCK_QUALITY is missing */
+
+ /* IEEE80211_RADIOTAP_ANTENNA */
+ *pos = status->antenna;
+ pos++;
+
+ /* IEEE80211_RADIOTAP_DB_ANTSIGNAL */
+ if (local->hw.flags & IEEE80211_HW_SIGNAL_DB) {
+ *pos = status->signal;
+ rthdr->it_present |=
+ cpu_to_le32(1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL);
+ pos++;
+ }
+
+ /* IEEE80211_RADIOTAP_DB_ANTNOISE is not used */
+
+ /* IEEE80211_RADIOTAP_RX_FLAGS */
+ /* ensure 2 byte alignment for the 2 byte field as required */
+ if ((pos - (unsigned char *)rthdr) & 1)
+ pos++;
+ /* FIXME: when radiotap gets a 'bad PLCP' flag use it here */
+ if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))
+ *(__le16 *)pos |= cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADFCS);
+ pos += 2;
+}
+
/*
* This function copies a received frame to all monitor interfaces and
* returns a cleaned-up SKB that no longer includes the FCS nor the
@@ -89,17 +217,6 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
{
struct ieee80211_sub_if_data *sdata;
int needed_headroom = 0;
- struct ieee80211_radiotap_header *rthdr;
- __le64 *rttsft = NULL;
- struct ieee80211_rtap_fixed_data {
- u8 flags;
- u8 rate;
- __le16 chan_freq;
- __le16 chan_flags;
- u8 antsignal;
- u8 padding_for_rxflags;
- __le16 rx_flags;
- } __attribute__ ((packed)) *rtfixed;
struct sk_buff *skb, *skb2;
struct net_device *prev_dev = NULL;
int present_fcs_len = 0;
@@ -116,8 +233,8 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
if (status->flag & RX_FLAG_RADIOTAP)
rtap_len = ieee80211_get_radiotap_len(origskb->data);
else
- /* room for radiotap header, always present fields and TSFT */
- needed_headroom = sizeof(*rthdr) + sizeof(*rtfixed) + 8;
+ /* room for the radiotap header based on driver features */
+ needed_headroom = ieee80211_rx_radiotap_len(local, status);
if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
present_fcs_len = FCS_LEN;
@@ -163,55 +280,9 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
}
/* if necessary, prepend radiotap information */
- if (!(status->flag & RX_FLAG_RADIOTAP)) {
- rtfixed = (void *) skb_push(skb, sizeof(*rtfixed));
- rtap_len = sizeof(*rthdr) + sizeof(*rtfixed);
- if (status->flag & RX_FLAG_TSFT) {
- rttsft = (void *) skb_push(skb, sizeof(*rttsft));
- rtap_len += 8;
- }
- rthdr = (void *) skb_push(skb, sizeof(*rthdr));
- memset(rthdr, 0, sizeof(*rthdr));
- memset(rtfixed, 0, sizeof(*rtfixed));
- rthdr->it_present =
- cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
- (1 << IEEE80211_RADIOTAP_RATE) |
- (1 << IEEE80211_RADIOTAP_CHANNEL) |
- (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) |
- (1 << IEEE80211_RADIOTAP_RX_FLAGS));
- rtfixed->flags = 0;
- if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
- rtfixed->flags |= IEEE80211_RADIOTAP_F_FCS;
-
- if (rttsft) {
- *rttsft = cpu_to_le64(status->mactime);
- rthdr->it_present |=
- cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT);
- }
-
- /* FIXME: when radiotap gets a 'bad PLCP' flag use it here */
- rtfixed->rx_flags = 0;
- if (status->flag &
- (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC))
- rtfixed->rx_flags |=
- cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADFCS);
-
- rtfixed->rate = rate->bitrate / 5;
-
- rtfixed->chan_freq = cpu_to_le16(status->freq);
-
- if (status->band == IEEE80211_BAND_5GHZ)
- rtfixed->chan_flags =
- cpu_to_le16(IEEE80211_CHAN_OFDM |
- IEEE80211_CHAN_5GHZ);
- else
- rtfixed->chan_flags =
- cpu_to_le16(IEEE80211_CHAN_DYN |
- IEEE80211_CHAN_2GHZ);
-
- rtfixed->antsignal = status->ssi;
- rthdr->it_len = cpu_to_le16(rtap_len);
- }
+ if (!(status->flag & RX_FLAG_RADIOTAP))
+ ieee80211_add_rx_radiotap_header(local, skb, status, rate,
+ needed_headroom);
skb_reset_mac_header(skb);
skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -275,11 +346,6 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
}
}
- I802_DEBUG_INC(rx->local->wme_rx_queue[tid]);
- /* only a debug counter, sta might not be assigned properly yet */
- if (rx->sta)
- I802_DEBUG_INC(rx->sta->wme_rx_queue[tid]);
-
rx->queue = tid;
/* Set skb->priority to 1d tag if highest order bit of TID is not set.
* For now, set skb->priority to 0 for other cases. */
@@ -321,51 +387,9 @@ static void ieee80211_verify_ip_alignment(struct ieee80211_rx_data *rx)
}
-static u32 ieee80211_rx_load_stats(struct ieee80211_local *local,
- struct sk_buff *skb,
- struct ieee80211_rx_status *status,
- struct ieee80211_rate *rate)
-{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- u32 load = 0, hdrtime;
-
- /* Estimate total channel use caused by this frame */
-
- /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values,
- * 1 usec = 1/8 * (1080 / 10) = 13.5 */
-
- if (status->band == IEEE80211_BAND_5GHZ ||
- (status->band == IEEE80211_BAND_5GHZ &&
- rate->flags & IEEE80211_RATE_ERP_G))
- hdrtime = CHAN_UTIL_HDR_SHORT;
- else
- hdrtime = CHAN_UTIL_HDR_LONG;
-
- load = hdrtime;
- if (!is_multicast_ether_addr(hdr->addr1))
- load += hdrtime;
-
- /* TODO: optimise again */
- load += skb->len * CHAN_UTIL_RATE_LCM / rate->bitrate;
-
- /* Divide channel_use by 8 to avoid wrapping around the counter */
- load >>= CHAN_UTIL_SHIFT;
-
- return load;
-}
-
/* rx handlers */
static ieee80211_rx_result
-ieee80211_rx_h_if_stats(struct ieee80211_rx_data *rx)
-{
- if (rx->sta)
- rx->sta->channel_use_raw += rx->load;
- rx->sdata->channel_use_raw += rx->load;
- return RX_CONTINUE;
-}
-
-static ieee80211_rx_result
ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx)
{
struct ieee80211_local *local = rx->local;
@@ -484,7 +508,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL &&
(rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)) &&
rx->sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
- (!rx->sta || !(rx->sta->flags & WLAN_STA_ASSOC)))) {
+ (!rx->sta || !test_sta_flags(rx->sta, WLAN_STA_ASSOC)))) {
if ((!(rx->fc & IEEE80211_FCTL_FROMDS) &&
!(rx->fc & IEEE80211_FCTL_TODS) &&
(rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)
@@ -635,8 +659,7 @@ static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta)
if (sdata->bss)
atomic_inc(&sdata->bss->num_sta_ps);
- sta->flags |= WLAN_STA_PS;
- sta->flags &= ~WLAN_STA_PSPOLL;
+ 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",
dev->name, print_mac(mac, sta->addr), sta->aid);
@@ -649,7 +672,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
struct sk_buff *skb;
int sent = 0;
struct ieee80211_sub_if_data *sdata;
- struct ieee80211_tx_packet_data *pkt_data;
+ struct ieee80211_tx_info *info;
DECLARE_MAC_BUF(mac);
sdata = sta->sdata;
@@ -657,7 +680,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
if (sdata->bss)
atomic_dec(&sdata->bss->num_sta_ps);
- sta->flags &= ~(WLAN_STA_PS | WLAN_STA_PSPOLL);
+ clear_sta_flags(sta, WLAN_STA_PS | WLAN_STA_PSPOLL);
if (!skb_queue_empty(&sta->ps_tx_buf))
sta_info_clear_tim_bit(sta);
@@ -669,13 +692,13 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
/* Send all buffered frames to the station */
while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
- pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
+ info = IEEE80211_SKB_CB(skb);
sent++;
- pkt_data->flags |= IEEE80211_TXPD_REQUEUE;
+ info->flags |= IEEE80211_TX_CTL_REQUEUE;
dev_queue_xmit(skb);
}
while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
- pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
+ info = IEEE80211_SKB_CB(skb);
local->total_ps_buffered--;
sent++;
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
@@ -683,7 +706,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
"since STA not sleeping anymore\n", dev->name,
print_mac(mac, sta->addr), sta->aid);
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
- pkt_data->flags |= IEEE80211_TXPD_REQUEUE;
+ info->flags |= IEEE80211_TX_CTL_REQUEUE;
dev_queue_xmit(skb);
}
@@ -725,16 +748,17 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
sta->rx_fragments++;
sta->rx_bytes += rx->skb->len;
- sta->last_rssi = rx->status->ssi;
sta->last_signal = rx->status->signal;
+ sta->last_qual = rx->status->qual;
sta->last_noise = rx->status->noise;
if (!(rx->fc & IEEE80211_FCTL_MOREFRAGS)) {
/* Change STA power saving mode only in the end of a frame
* exchange sequence */
- if ((sta->flags & WLAN_STA_PS) && !(rx->fc & IEEE80211_FCTL_PM))
+ if (test_sta_flags(sta, WLAN_STA_PS) &&
+ !(rx->fc & IEEE80211_FCTL_PM))
rx->sent_ps_buffered += ap_sta_ps_end(dev, sta);
- else if (!(sta->flags & WLAN_STA_PS) &&
+ else if (!test_sta_flags(sta, WLAN_STA_PS) &&
(rx->fc & IEEE80211_FCTL_PM))
ap_sta_ps_start(dev, sta);
}
@@ -988,7 +1012,7 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx)
* Tell TX path to send one frame even though the STA may
* still remain is PS mode after this frame exchange.
*/
- rx->sta->flags |= WLAN_STA_PSPOLL;
+ set_sta_flags(rx->sta, WLAN_STA_PSPOLL);
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "STA %s aid %d: PS Poll (entries after %d)\n",
@@ -1051,7 +1075,8 @@ ieee80211_rx_h_remove_qos_control(struct ieee80211_rx_data *rx)
static int
ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx)
{
- if (unlikely(!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED))) {
+ if (unlikely(!rx->sta ||
+ !test_sta_flags(rx->sta, WLAN_STA_AUTHORIZED))) {
#ifdef CONFIG_MAC80211_DEBUG
if (net_ratelimit())
printk(KERN_DEBUG "%s: dropped frame "
@@ -1091,7 +1116,7 @@ ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
u16 fc, hdrlen, ethertype;
u8 *payload;
u8 dst[ETH_ALEN];
- u8 src[ETH_ALEN];
+ u8 src[ETH_ALEN] __aligned(2);
struct sk_buff *skb = rx->skb;
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
DECLARE_MAC_BUF(mac);
@@ -1234,7 +1259,7 @@ ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
*/
static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx)
{
- static const u8 pae_group_addr[ETH_ALEN]
+ static const u8 pae_group_addr[ETH_ALEN] __aligned(2)
= { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x03 };
struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data;
@@ -1713,7 +1738,6 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx)
typedef ieee80211_rx_result (*ieee80211_rx_handler)(struct ieee80211_rx_data *);
static ieee80211_rx_handler ieee80211_rx_handlers[] =
{
- ieee80211_rx_h_if_stats,
ieee80211_rx_h_passive_scan,
ieee80211_rx_h_check,
ieee80211_rx_h_decrypt,
@@ -1872,7 +1896,6 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
struct sk_buff *skb,
struct ieee80211_rx_status *status,
- u32 load,
struct ieee80211_rate *rate)
{
struct ieee80211_local *local = hw_to_local(hw);
@@ -1891,7 +1914,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
rx.local = local;
rx.status = status;
- rx.load = load;
rx.rate = rate;
rx.fc = le16_to_cpu(hdr->frame_control);
type = rx.fc & IEEE80211_FCTL_FTYPE;
@@ -2000,7 +2022,6 @@ u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
struct ieee80211_rx_status status;
u16 head_seq_num, buf_size;
int index;
- u32 pkt_load;
struct ieee80211_supported_band *sband;
struct ieee80211_rate *rate;
@@ -2035,12 +2056,9 @@ u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
sizeof(status));
sband = local->hw.wiphy->bands[status.band];
rate = &sband->bitrates[status.rate_idx];
- pkt_load = ieee80211_rx_load_stats(local,
- tid_agg_rx->reorder_buf[index],
- &status, rate);
__ieee80211_rx_handle_packet(hw,
tid_agg_rx->reorder_buf[index],
- &status, pkt_load, rate);
+ &status, rate);
tid_agg_rx->stored_mpdu_num--;
tid_agg_rx->reorder_buf[index] = NULL;
}
@@ -2082,11 +2100,8 @@ u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
sizeof(status));
sband = local->hw.wiphy->bands[status.band];
rate = &sband->bitrates[status.rate_idx];
- pkt_load = ieee80211_rx_load_stats(local,
- tid_agg_rx->reorder_buf[index],
- &status, rate);
__ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index],
- &status, pkt_load, rate);
+ &status, rate);
tid_agg_rx->stored_mpdu_num--;
tid_agg_rx->reorder_buf[index] = NULL;
tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
@@ -2165,7 +2180,6 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ieee80211_rx_status *status)
{
struct ieee80211_local *local = hw_to_local(hw);
- u32 pkt_load;
struct ieee80211_rate *rate = NULL;
struct ieee80211_supported_band *sband;
@@ -2205,11 +2219,8 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
return;
}
- pkt_load = ieee80211_rx_load_stats(local, skb, status, rate);
- local->channel_use_raw += pkt_load;
-
if (!ieee80211_rx_reorder_ampdu(local, skb))
- __ieee80211_rx_handle_packet(hw, skb, status, pkt_load, rate);
+ __ieee80211_rx_handle_packet(hw, skb, status, rate);
rcu_read_unlock();
}
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 7d4fe4a52929..c24770cb02c5 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -202,14 +202,12 @@ void sta_info_destroy(struct sta_info *sta)
dev_kfree_skb_any(skb);
for (i = 0; i < STA_TID_NUM; i++) {
- spin_lock_bh(&sta->ampdu_mlme.ampdu_rx);
+ spin_lock_bh(&sta->lock);
if (sta->ampdu_mlme.tid_rx[i])
del_timer_sync(&sta->ampdu_mlme.tid_rx[i]->session_timer);
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
- spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
if (sta->ampdu_mlme.tid_tx[i])
del_timer_sync(&sta->ampdu_mlme.tid_tx[i]->addba_resp_timer);
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
}
__sta_info_free(local, sta);
@@ -236,6 +234,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
if (!sta)
return NULL;
+ spin_lock_init(&sta->lock);
+
memcpy(sta->addr, addr, ETH_ALEN);
sta->local = local;
sta->sdata = sdata;
@@ -249,15 +249,13 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
return NULL;
}
- spin_lock_init(&sta->ampdu_mlme.ampdu_rx);
- spin_lock_init(&sta->ampdu_mlme.ampdu_tx);
for (i = 0; i < STA_TID_NUM; i++) {
/* timer_to_tid must be initialized with identity mapping to
* enable session_timer's data differentiation. refer to
* sta_rx_agg_session_timer_expired for useage */
sta->timer_to_tid[i] = i;
/* tid to tx queue: initialize according to HW (0 is valid) */
- sta->tid_to_tx_q[i] = local->hw.queues;
+ sta->tid_to_tx_q[i] = ieee80211_num_queues(&local->hw);
/* rx */
sta->ampdu_mlme.tid_state_rx[i] = HT_AGG_STATE_IDLE;
sta->ampdu_mlme.tid_rx[i] = NULL;
@@ -276,7 +274,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
#ifdef CONFIG_MAC80211_MESH
sta->plink_state = PLINK_LISTEN;
- spin_lock_init(&sta->plink_lock);
init_timer(&sta->plink_timer);
#endif
@@ -437,8 +434,7 @@ void __sta_info_unlink(struct sta_info **sta)
list_del(&(*sta)->list);
- if ((*sta)->flags & WLAN_STA_PS) {
- (*sta)->flags &= ~WLAN_STA_PS;
+ if (test_and_clear_sta_flags(*sta, WLAN_STA_PS)) {
if (sdata->bss)
atomic_dec(&sdata->bss->num_sta_ps);
__sta_info_clear_tim_bit(sdata->bss, *sta);
@@ -515,20 +511,20 @@ static inline int sta_info_buffer_expired(struct ieee80211_local *local,
struct sta_info *sta,
struct sk_buff *skb)
{
- struct ieee80211_tx_packet_data *pkt_data;
+ struct ieee80211_tx_info *info;
int timeout;
if (!skb)
return 0;
- pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
+ info = IEEE80211_SKB_CB(skb);
/* Timeout: (2 * listen_interval * beacon_int * 1024 / 1000000) sec */
timeout = (sta->listen_interval * local->hw.conf.beacon_int * 32 /
15625) * HZ;
if (timeout < STA_TX_BUFFER_EXPIRE)
timeout = STA_TX_BUFFER_EXPIRE;
- return time_after(jiffies, pkt_data->jiffies + timeout);
+ return time_after(jiffies, info->control.jiffies + timeout);
}
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index f8c95bc9659c..95753f860acf 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -32,7 +32,7 @@
* @WLAN_STA_WDS: Station is one of our WDS peers.
* @WLAN_STA_PSPOLL: Station has just PS-polled us.
* @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the
- * IEEE80211_TXCTL_CLEAR_PS_FILT control flag) when the next
+ * IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next
* frame to this station is transmitted.
*/
enum ieee80211_sta_info_flags {
@@ -129,23 +129,19 @@ enum plink_state {
*
* @tid_state_rx: TID's state in Rx session state machine.
* @tid_rx: aggregation info for Rx per TID
- * @ampdu_rx: for locking sections in aggregation Rx flow
* @tid_state_tx: TID's state in Tx session state machine.
* @tid_tx: aggregation info for Tx per TID
* @addba_req_num: number of times addBA request has been sent.
- * @ampdu_tx: for locking sectionsi in aggregation Tx flow
* @dialog_token_allocator: dialog token enumerator for each new session;
*/
struct sta_ampdu_mlme {
/* rx */
u8 tid_state_rx[STA_TID_NUM];
struct tid_ampdu_rx *tid_rx[STA_TID_NUM];
- spinlock_t ampdu_rx;
/* tx */
u8 tid_state_tx[STA_TID_NUM];
struct tid_ampdu_tx *tid_tx[STA_TID_NUM];
u8 addba_req_num[STA_TID_NUM];
- spinlock_t ampdu_tx;
u8 dialog_token_allocator;
};
@@ -177,6 +173,8 @@ struct sta_ampdu_mlme {
* @rx_bytes: Number of bytes received from this STA
* @supp_rates: Bitmap of supported rates (per band)
* @ht_info: HT capabilities of this STA
+ * @lock: used for locking all fields that require locking, see comments
+ * in the header file.
*/
struct sta_info {
/* General information, mostly static */
@@ -187,6 +185,7 @@ struct sta_info {
struct ieee80211_key *key;
struct rate_control_ref *rate_ctrl;
void *rate_ctrl_priv;
+ spinlock_t lock;
struct ieee80211_ht_info ht_info;
u64 supp_rates[IEEE80211_NUM_BANDS];
u8 addr[ETH_ALEN];
@@ -199,7 +198,7 @@ struct sta_info {
*/
u8 pin_status;
- /* frequently updated information, needs locking? */
+ /* frequently updated information, locked with lock spinlock */
u32 flags;
/*
@@ -217,8 +216,8 @@ struct sta_info {
* from this STA */
unsigned long rx_fragments; /* number of received MPDUs */
unsigned long rx_dropped; /* number of dropped MPDUs from this STA */
- int last_rssi; /* RSSI of last received frame from this STA */
int last_signal; /* signal of last received frame from this STA */
+ int last_qual; /* qual of last received frame from this STA */
int last_noise; /* noise of last received frame from this STA */
/* last received seq/frag number from this STA (per RX queue) */
__le16 last_seq_ctrl[NUM_RX_DATA_QUEUES];
@@ -246,12 +245,8 @@ struct sta_info {
unsigned int wme_tx_queue[NUM_RX_DATA_QUEUES];
#endif
- /* Debug counters, no locking doesn't matter */
- int channel_use;
- int channel_use_raw;
-
/*
- * Aggregation information, comes with own locking.
+ * Aggregation information, locked with lock.
*/
struct sta_ampdu_mlme ampdu_mlme;
u8 timer_to_tid[STA_TID_NUM]; /* identity mapping to ID timers */
@@ -270,9 +265,6 @@ struct sta_info {
enum plink_state plink_state;
u32 plink_timeout;
struct timer_list plink_timer;
- spinlock_t plink_lock; /* For peer_state reads / updates and other
- updates in the structure. Ensures robust
- transitions for the peerlink FSM */
#endif
#ifdef CONFIG_MAC80211_DEBUGFS
@@ -299,6 +291,64 @@ static inline enum plink_state sta_plink_state(struct sta_info *sta)
return PLINK_LISTEN;
}
+static inline void set_sta_flags(struct sta_info *sta, const u32 flags)
+{
+ spin_lock_bh(&sta->lock);
+ sta->flags |= flags;
+ spin_unlock_bh(&sta->lock);
+}
+
+static inline void clear_sta_flags(struct sta_info *sta, const u32 flags)
+{
+ spin_lock_bh(&sta->lock);
+ sta->flags &= ~flags;
+ spin_unlock_bh(&sta->lock);
+}
+
+static inline void set_and_clear_sta_flags(struct sta_info *sta,
+ const u32 set, const u32 clear)
+{
+ spin_lock_bh(&sta->lock);
+ sta->flags |= set;
+ sta->flags &= ~clear;
+ spin_unlock_bh(&sta->lock);
+}
+
+static inline u32 test_sta_flags(struct sta_info *sta, const u32 flags)
+{
+ u32 ret;
+
+ spin_lock_bh(&sta->lock);
+ ret = sta->flags & flags;
+ spin_unlock_bh(&sta->lock);
+
+ return ret;
+}
+
+static inline u32 test_and_clear_sta_flags(struct sta_info *sta,
+ const u32 flags)
+{
+ u32 ret;
+
+ spin_lock_bh(&sta->lock);
+ ret = sta->flags & flags;
+ sta->flags &= ~flags;
+ spin_unlock_bh(&sta->lock);
+
+ return ret;
+}
+
+static inline u32 get_sta_flags(struct sta_info *sta)
+{
+ u32 ret;
+
+ spin_lock_bh(&sta->lock);
+ ret = sta->flags;
+ spin_unlock_bh(&sta->lock);
+
+ return ret;
+}
+
/* Maximum number of concurrently registered stations */
#define MAX_STA_COUNT 2007
diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c
index 09093da24af6..a00cf1ea7719 100644
--- a/net/mac80211/tkip.c
+++ b/net/mac80211/tkip.c
@@ -6,25 +6,23 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-
#include <linux/kernel.h>
+#include <linux/bitops.h>
#include <linux/types.h>
#include <linux/netdevice.h>
+#include <asm/unaligned.h>
#include <net/mac80211.h>
#include "key.h"
#include "tkip.h"
#include "wep.h"
-
-/* TKIP key mixing functions */
-
-
#define PHASE1_LOOP_COUNT 8
-
-/* 2-byte by 2-byte subset of the full AES S-box table; second part of this
- * table is identical to first part but byte-swapped */
+/*
+ * 2-byte by 2-byte subset of the full AES S-box table; second part of this
+ * table is identical to first part but byte-swapped
+ */
static const u16 tkip_sbox[256] =
{
0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
@@ -61,84 +59,48 @@ static const u16 tkip_sbox[256] =
0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A,
};
-
-static inline u16 Mk16(u8 x, u8 y)
-{
- return ((u16) x << 8) | (u16) y;
-}
-
-
-static inline u8 Hi8(u16 v)
-{
- return v >> 8;
-}
-
-
-static inline u8 Lo8(u16 v)
-{
- return v & 0xff;
-}
-
-
-static inline u16 Hi16(u32 v)
+static u16 tkipS(u16 val)
{
- return v >> 16;
+ return tkip_sbox[val & 0xff] ^ swab16(tkip_sbox[val >> 8]);
}
-
-static inline u16 Lo16(u32 v)
-{
- return v & 0xffff;
-}
-
-
-static inline u16 RotR1(u16 v)
-{
- return (v >> 1) | ((v & 0x0001) << 15);
-}
-
-
-static inline u16 tkip_S(u16 val)
-{
- u16 a = tkip_sbox[Hi8(val)];
-
- return tkip_sbox[Lo8(val)] ^ Hi8(a) ^ (Lo8(a) << 8);
-}
-
-
-
-/* P1K := Phase1(TA, TK, TSC)
+/*
+ * P1K := Phase1(TA, TK, TSC)
* TA = transmitter address (48 bits)
* TK = dot11DefaultKeyValue or dot11KeyMappingValue (128 bits)
* TSC = TKIP sequence counter (48 bits, only 32 msb bits used)
* P1K: 80 bits
*/
-static void tkip_mixing_phase1(const u8 *ta, const u8 *tk, u32 tsc_IV32,
- u16 *p1k)
+static void tkip_mixing_phase1(struct ieee80211_key *key, const u8 *ta,
+ struct tkip_ctx *ctx, u32 tsc_IV32)
{
int i, j;
+ const u8 *tk = &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY];
+ u16 *p1k = ctx->p1k;
- p1k[0] = Lo16(tsc_IV32);
- p1k[1] = Hi16(tsc_IV32);
- p1k[2] = Mk16(ta[1], ta[0]);
- p1k[3] = Mk16(ta[3], ta[2]);
- p1k[4] = Mk16(ta[5], ta[4]);
+ p1k[0] = tsc_IV32 & 0xFFFF;
+ p1k[1] = tsc_IV32 >> 16;
+ p1k[2] = get_unaligned_le16(ta + 0);
+ p1k[3] = get_unaligned_le16(ta + 2);
+ p1k[4] = get_unaligned_le16(ta + 4);
for (i = 0; i < PHASE1_LOOP_COUNT; i++) {
j = 2 * (i & 1);
- p1k[0] += tkip_S(p1k[4] ^ Mk16(tk[ 1 + j], tk[ 0 + j]));
- p1k[1] += tkip_S(p1k[0] ^ Mk16(tk[ 5 + j], tk[ 4 + j]));
- p1k[2] += tkip_S(p1k[1] ^ Mk16(tk[ 9 + j], tk[ 8 + j]));
- p1k[3] += tkip_S(p1k[2] ^ Mk16(tk[13 + j], tk[12 + j]));
- p1k[4] += tkip_S(p1k[3] ^ Mk16(tk[ 1 + j], tk[ 0 + j])) + i;
+ p1k[0] += tkipS(p1k[4] ^ get_unaligned_le16(tk + 0 + j));
+ p1k[1] += tkipS(p1k[0] ^ get_unaligned_le16(tk + 4 + j));
+ p1k[2] += tkipS(p1k[1] ^ get_unaligned_le16(tk + 8 + j));
+ p1k[3] += tkipS(p1k[2] ^ get_unaligned_le16(tk + 12 + j));
+ p1k[4] += tkipS(p1k[3] ^ get_unaligned_le16(tk + 0 + j)) + i;
}
+ ctx->initialized = 1;
}
-
-static void tkip_mixing_phase2(const u16 *p1k, const u8 *tk, u16 tsc_IV16,
- u8 *rc4key)
+static void tkip_mixing_phase2(struct ieee80211_key *key, struct tkip_ctx *ctx,
+ u16 tsc_IV16, u8 *rc4key)
{
u16 ppk[6];
+ const u16 *p1k = ctx->p1k;
+ const u8 *tk = &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY];
int i;
ppk[0] = p1k[0];
@@ -148,70 +110,51 @@ static void tkip_mixing_phase2(const u16 *p1k, const u8 *tk, u16 tsc_IV16,
ppk[4] = p1k[4];
ppk[5] = p1k[4] + tsc_IV16;
- ppk[0] += tkip_S(ppk[5] ^ Mk16(tk[ 1], tk[ 0]));
- ppk[1] += tkip_S(ppk[0] ^ Mk16(tk[ 3], tk[ 2]));
- ppk[2] += tkip_S(ppk[1] ^ Mk16(tk[ 5], tk[ 4]));
- ppk[3] += tkip_S(ppk[2] ^ Mk16(tk[ 7], tk[ 6]));
- ppk[4] += tkip_S(ppk[3] ^ Mk16(tk[ 9], tk[ 8]));
- ppk[5] += tkip_S(ppk[4] ^ Mk16(tk[11], tk[10]));
- ppk[0] += RotR1(ppk[5] ^ Mk16(tk[13], tk[12]));
- ppk[1] += RotR1(ppk[0] ^ Mk16(tk[15], tk[14]));
- ppk[2] += RotR1(ppk[1]);
- ppk[3] += RotR1(ppk[2]);
- ppk[4] += RotR1(ppk[3]);
- ppk[5] += RotR1(ppk[4]);
-
- rc4key[0] = Hi8(tsc_IV16);
- rc4key[1] = (Hi8(tsc_IV16) | 0x20) & 0x7f;
- rc4key[2] = Lo8(tsc_IV16);
- rc4key[3] = Lo8((ppk[5] ^ Mk16(tk[1], tk[0])) >> 1);
-
- for (i = 0; i < 6; i++) {
- rc4key[4 + 2 * i] = Lo8(ppk[i]);
- rc4key[5 + 2 * i] = Hi8(ppk[i]);
- }
+ ppk[0] += tkipS(ppk[5] ^ get_unaligned_le16(tk + 0));
+ ppk[1] += tkipS(ppk[0] ^ get_unaligned_le16(tk + 2));
+ ppk[2] += tkipS(ppk[1] ^ get_unaligned_le16(tk + 4));
+ ppk[3] += tkipS(ppk[2] ^ get_unaligned_le16(tk + 6));
+ ppk[4] += tkipS(ppk[3] ^ get_unaligned_le16(tk + 8));
+ ppk[5] += tkipS(ppk[4] ^ get_unaligned_le16(tk + 10));
+ ppk[0] += ror16(ppk[5] ^ get_unaligned_le16(tk + 12), 1);
+ ppk[1] += ror16(ppk[0] ^ get_unaligned_le16(tk + 14), 1);
+ ppk[2] += ror16(ppk[1], 1);
+ ppk[3] += ror16(ppk[2], 1);
+ ppk[4] += ror16(ppk[3], 1);
+ ppk[5] += ror16(ppk[4], 1);
+
+ rc4key[0] = tsc_IV16 >> 8;
+ rc4key[1] = ((tsc_IV16 >> 8) | 0x20) & 0x7f;
+ rc4key[2] = tsc_IV16 & 0xFF;
+ rc4key[3] = ((ppk[5] ^ get_unaligned_le16(tk)) >> 1) & 0xFF;
+
+ rc4key += 4;
+ for (i = 0; i < 6; i++)
+ put_unaligned_le16(ppk[i], rc4key + 2 * i);
}
-
/* Add TKIP IV and Ext. IV at @pos. @iv0, @iv1, and @iv2 are the first octets
* of the IV. Returns pointer to the octet following IVs (i.e., beginning of
* the packet payload). */
-u8 * ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key,
+u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key,
u8 iv0, u8 iv1, u8 iv2)
{
*pos++ = iv0;
*pos++ = iv1;
*pos++ = iv2;
*pos++ = (key->conf.keyidx << 6) | (1 << 5) /* Ext IV */;
- *pos++ = key->u.tkip.iv32 & 0xff;
- *pos++ = (key->u.tkip.iv32 >> 8) & 0xff;
- *pos++ = (key->u.tkip.iv32 >> 16) & 0xff;
- *pos++ = (key->u.tkip.iv32 >> 24) & 0xff;
- return pos;
-}
-
-
-void ieee80211_tkip_gen_phase1key(struct ieee80211_key *key, u8 *ta,
- u16 *phase1key)
-{
- tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY],
- key->u.tkip.iv32, phase1key);
+ put_unaligned_le32(key->u.tkip.tx.iv32, pos);
+ return pos + 4;
}
-void ieee80211_tkip_gen_rc4key(struct ieee80211_key *key, u8 *ta,
+static void ieee80211_tkip_gen_rc4key(struct ieee80211_key *key, u8 *ta,
u8 *rc4key)
{
/* Calculate per-packet key */
- if (key->u.tkip.iv16 == 0 || !key->u.tkip.tx_initialized) {
- /* IV16 wrapped around - perform TKIP phase 1 */
- tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY],
- key->u.tkip.iv32, key->u.tkip.p1k);
- key->u.tkip.tx_initialized = 1;
- }
+ if (key->u.tkip.tx.iv16 == 0 || !key->u.tkip.tx.initialized)
+ tkip_mixing_phase1(key, ta, &key->u.tkip.tx, key->u.tkip.tx.iv32);
- tkip_mixing_phase2(key->u.tkip.p1k,
- &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY],
- key->u.tkip.iv16, rc4key);
+ tkip_mixing_phase2(key, &key->u.tkip.tx, key->u.tkip.tx.iv16, rc4key);
}
void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf,
@@ -228,18 +171,16 @@ void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf,
u16 iv16;
u32 iv32;
- iv16 = data[hdr_len] << 8;
- iv16 += data[hdr_len + 2];
- iv32 = data[hdr_len + 4] | (data[hdr_len + 5] << 8) |
- (data[hdr_len + 6] << 16) | (data[hdr_len + 7] << 24);
+ iv16 = data[hdr_len + 2] | (data[hdr_len] << 8);
+ iv32 = get_unaligned_le32(data + hdr_len + 4);
#ifdef CONFIG_TKIP_DEBUG
printk(KERN_DEBUG "TKIP encrypt: iv16 = 0x%04x, iv32 = 0x%08x\n",
iv16, iv32);
- if (iv32 != key->u.tkip.iv32) {
+ if (iv32 != key->u.tkip.tx.iv32) {
printk(KERN_DEBUG "skb: iv32 = 0x%08x key: iv32 = 0x%08x\n",
- iv32, key->u.tkip.iv32);
+ iv32, key->u.tkip.tx.iv32);
printk(KERN_DEBUG "Wrap around of iv16 in the middle of a "
"fragmented packet\n");
}
@@ -248,20 +189,15 @@ void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf,
/* Update the p1k only when the iv16 in the packet wraps around, this
* might occur after the wrap around of iv16 in the key in case of
* fragmented packets. */
- if (iv16 == 0 || !key->u.tkip.tx_initialized) {
- /* IV16 wrapped around - perform TKIP phase 1 */
- tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY],
- iv32, key->u.tkip.p1k);
- key->u.tkip.tx_initialized = 1;
- }
+ if (iv16 == 0 || !key->u.tkip.tx.initialized)
+ tkip_mixing_phase1(key, ta, &key->u.tkip.tx, iv32);
if (type == IEEE80211_TKIP_P1_KEY) {
- memcpy(outkey, key->u.tkip.p1k, sizeof(u16) * 5);
+ memcpy(outkey, key->u.tkip.tx.p1k, sizeof(u16) * 5);
return;
}
- tkip_mixing_phase2(key->u.tkip.p1k,
- &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], iv16, outkey);
+ tkip_mixing_phase2(key, &key->u.tkip.tx, iv16, outkey);
}
EXPORT_SYMBOL(ieee80211_get_tkip_key);
@@ -281,7 +217,6 @@ void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
ieee80211_wep_encrypt_data(tfm, rc4key, 16, pos, payload_len);
}
-
/* Decrypt packet payload with TKIP using @key. @pos is a pointer to the
* beginning of the buffer containing IEEE 802.11 header payload, i.e.,
* including IV, Ext. IV, real data, Michael MIC, ICV. @payload_len is the
@@ -302,7 +237,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
iv16 = (pos[0] << 8) | pos[2];
keyid = pos[3];
- iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24);
+ iv32 = get_unaligned_le32(pos + 4);
pos += 8;
#ifdef CONFIG_TKIP_DEBUG
{
@@ -322,33 +257,31 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
if ((keyid >> 6) != key->conf.keyidx)
return TKIP_DECRYPT_INVALID_KEYIDX;
- if (key->u.tkip.rx_initialized[queue] &&
- (iv32 < key->u.tkip.iv32_rx[queue] ||
- (iv32 == key->u.tkip.iv32_rx[queue] &&
- iv16 <= key->u.tkip.iv16_rx[queue]))) {
+ if (key->u.tkip.rx[queue].initialized &&
+ (iv32 < key->u.tkip.rx[queue].iv32 ||
+ (iv32 == key->u.tkip.rx[queue].iv32 &&
+ iv16 <= key->u.tkip.rx[queue].iv16))) {
#ifdef CONFIG_TKIP_DEBUG
DECLARE_MAC_BUF(mac);
printk(KERN_DEBUG "TKIP replay detected for RX frame from "
"%s (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n",
print_mac(mac, ta),
- iv32, iv16, key->u.tkip.iv32_rx[queue],
- key->u.tkip.iv16_rx[queue]);
+ iv32, iv16, key->u.tkip.rx[queue].iv32,
+ key->u.tkip.rx[queue].iv16);
#endif /* CONFIG_TKIP_DEBUG */
return TKIP_DECRYPT_REPLAY;
}
if (only_iv) {
res = TKIP_DECRYPT_OK;
- key->u.tkip.rx_initialized[queue] = 1;
+ key->u.tkip.rx[queue].initialized = 1;
goto done;
}
- if (!key->u.tkip.rx_initialized[queue] ||
- key->u.tkip.iv32_rx[queue] != iv32) {
- key->u.tkip.rx_initialized[queue] = 1;
+ if (!key->u.tkip.rx[queue].initialized ||
+ key->u.tkip.rx[queue].iv32 != iv32) {
/* IV16 wrapped around - perform TKIP phase 1 */
- tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY],
- iv32, key->u.tkip.p1k_rx[queue]);
+ tkip_mixing_phase1(key, ta, &key->u.tkip.rx[queue], iv32);
#ifdef CONFIG_TKIP_DEBUG
{
int i;
@@ -362,7 +295,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
printk("\n");
printk(KERN_DEBUG "TKIP decrypt: P1K=");
for (i = 0; i < 5; i++)
- printk("%04x ", key->u.tkip.p1k_rx[queue][i]);
+ printk("%04x ", key->u.tkip.rx[queue].p1k[i]);
printk("\n");
}
#endif /* CONFIG_TKIP_DEBUG */
@@ -377,13 +310,11 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
key->local->ops->update_tkip_key(
local_to_hw(key->local), &key->conf,
- sta_addr, iv32, key->u.tkip.p1k_rx[queue]);
+ sta_addr, iv32, key->u.tkip.rx[queue].p1k);
}
}
- tkip_mixing_phase2(key->u.tkip.p1k_rx[queue],
- &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY],
- iv16, rc4key);
+ tkip_mixing_phase2(key, &key->u.tkip.rx[queue], iv16, rc4key);
#ifdef CONFIG_TKIP_DEBUG
{
int i;
@@ -409,5 +340,3 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
return res;
}
-
-
diff --git a/net/mac80211/tkip.h b/net/mac80211/tkip.h
index b7c2ee763d9d..b890427fc959 100644
--- a/net/mac80211/tkip.h
+++ b/net/mac80211/tkip.h
@@ -13,12 +13,8 @@
#include <linux/crypto.h>
#include "key.h"
-u8 * ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key,
- u8 iv0, u8 iv1, u8 iv2);
-void ieee80211_tkip_gen_phase1key(struct ieee80211_key *key, u8 *ta,
- u16 *phase1key);
-void ieee80211_tkip_gen_rc4key(struct ieee80211_key *key, u8 *ta,
- u8 *rc4key);
+u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key,
+ u8 iv0, u8 iv1, u8 iv2);
void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
struct ieee80211_key *key,
u8 *pos, size_t payload_len, u8 *ta);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 1d7dd54aacef..1ad9e664f287 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -91,11 +91,12 @@ static u16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr,
int next_frag_len)
{
int rate, mrate, erp, dur, i;
- struct ieee80211_rate *txrate = tx->rate;
+ struct ieee80211_rate *txrate;
struct ieee80211_local *local = tx->local;
struct ieee80211_supported_band *sband;
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+ sband = local->hw.wiphy->bands[tx->channel->band];
+ txrate = &sband->bitrates[tx->rate_idx];
erp = 0;
if (tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
@@ -212,18 +213,6 @@ static u16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr,
return dur;
}
-static inline int __ieee80211_queue_stopped(const struct ieee80211_local *local,
- int queue)
-{
- return test_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]);
-}
-
-static inline int __ieee80211_queue_pending(const struct ieee80211_local *local,
- int queue)
-{
- return test_bit(IEEE80211_LINK_STATE_PENDING, &local->state[queue]);
-}
-
static int inline is_ieee80211_device(struct net_device *dev,
struct net_device *master)
{
@@ -237,12 +226,12 @@ static ieee80211_tx_result
ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
{
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- struct sk_buff *skb = tx->skb;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
u32 sta_flags;
- if (unlikely(tx->flags & IEEE80211_TX_INJECTED))
+ if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED))
return TX_CONTINUE;
if (unlikely(tx->local->sta_sw_scanning) &&
@@ -256,7 +245,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
if (tx->flags & IEEE80211_TX_PS_BUFFERED)
return TX_CONTINUE;
- sta_flags = tx->sta ? tx->sta->flags : 0;
+ sta_flags = tx->sta ? get_sta_flags(tx->sta) : 0;
if (likely(tx->flags & IEEE80211_TX_UNICAST)) {
if (unlikely(!(sta_flags & WLAN_STA_ASSOC) &&
@@ -347,6 +336,8 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
static ieee80211_tx_result
ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
+
/*
* broadcast/multicast frame
*
@@ -382,7 +373,7 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
}
/* buffered in hardware */
- tx->control->flags |= IEEE80211_TXCTL_SEND_AFTER_DTIM;
+ info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM;
return TX_CONTINUE;
}
@@ -391,6 +382,8 @@ static ieee80211_tx_result
ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
{
struct sta_info *sta = tx->sta;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
+ u32 staflags;
DECLARE_MAC_BUF(mac);
if (unlikely(!sta ||
@@ -398,9 +391,10 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
(tx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP)))
return TX_CONTINUE;
- if (unlikely((sta->flags & WLAN_STA_PS) &&
- !(sta->flags & WLAN_STA_PSPOLL))) {
- struct ieee80211_tx_packet_data *pkt_data;
+ staflags = get_sta_flags(sta);
+
+ if (unlikely((staflags & WLAN_STA_PS) &&
+ !(staflags & WLAN_STA_PSPOLL))) {
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "STA %s aid %d: PS buffer (entries "
"before %d)\n",
@@ -424,19 +418,18 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
if (skb_queue_empty(&sta->ps_tx_buf))
sta_info_set_tim_bit(sta);
- pkt_data = (struct ieee80211_tx_packet_data *)tx->skb->cb;
- pkt_data->jiffies = jiffies;
+ info->control.jiffies = jiffies;
skb_queue_tail(&sta->ps_tx_buf, tx->skb);
return TX_QUEUED;
}
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
- else if (unlikely(sta->flags & WLAN_STA_PS)) {
+ else if (unlikely(test_sta_flags(sta, WLAN_STA_PS))) {
printk(KERN_DEBUG "%s: STA %s in PS mode, but pspoll "
"set -> send frame\n", tx->dev->name,
print_mac(mac, sta->addr));
}
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
- sta->flags &= ~WLAN_STA_PSPOLL;
+ clear_sta_flags(sta, WLAN_STA_PSPOLL);
return TX_CONTINUE;
}
@@ -457,17 +450,18 @@ static ieee80211_tx_result
ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
{
struct ieee80211_key *key;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
u16 fc = tx->fc;
- if (unlikely(tx->control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT))
+ if (unlikely(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT))
tx->key = NULL;
else if (tx->sta && (key = rcu_dereference(tx->sta->key)))
tx->key = key;
else if ((key = rcu_dereference(tx->sdata->default_key)))
tx->key = key;
else if (tx->sdata->drop_unencrypted &&
- !(tx->control->flags & IEEE80211_TXCTL_EAPOL_FRAME) &&
- !(tx->flags & IEEE80211_TX_INJECTED)) {
+ !(info->flags & IEEE80211_TX_CTL_EAPOL_FRAME) &&
+ !(info->flags & IEEE80211_TX_CTL_INJECTED)) {
I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted);
return TX_DROP;
} else
@@ -496,7 +490,156 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
}
if (!tx->key || !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
- tx->control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
+ info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
+
+ return TX_CONTINUE;
+}
+
+static ieee80211_tx_result
+ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
+{
+ struct rate_selection rsel;
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
+
+ sband = tx->local->hw.wiphy->bands[tx->channel->band];
+
+ if (likely(tx->rate_idx < 0)) {
+ rate_control_get_rate(tx->dev, sband, tx->skb, &rsel);
+ tx->rate_idx = rsel.rate_idx;
+ if (unlikely(rsel.probe_idx >= 0)) {
+ info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
+ tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG;
+ info->control.alt_retry_rate_idx = tx->rate_idx;
+ tx->rate_idx = rsel.probe_idx;
+ } else
+ info->control.alt_retry_rate_idx = -1;
+
+ if (unlikely(tx->rate_idx < 0))
+ return TX_DROP;
+ } else
+ info->control.alt_retry_rate_idx = -1;
+
+ if (tx->sdata->bss_conf.use_cts_prot &&
+ (tx->flags & IEEE80211_TX_FRAGMENTED) && (rsel.nonerp_idx >= 0)) {
+ tx->last_frag_rate_idx = tx->rate_idx;
+ if (rsel.probe_idx >= 0)
+ tx->flags &= ~IEEE80211_TX_PROBE_LAST_FRAG;
+ else
+ tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG;
+ tx->rate_idx = rsel.nonerp_idx;
+ info->tx_rate_idx = rsel.nonerp_idx;
+ info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE;
+ } else {
+ tx->last_frag_rate_idx = tx->rate_idx;
+ info->tx_rate_idx = tx->rate_idx;
+ }
+ info->tx_rate_idx = tx->rate_idx;
+
+ return TX_CONTINUE;
+}
+
+static ieee80211_tx_result
+ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
+ u16 fc = le16_to_cpu(hdr->frame_control);
+ u16 dur;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
+ struct ieee80211_supported_band *sband;
+
+ sband = tx->local->hw.wiphy->bands[tx->channel->band];
+
+ if (tx->sta)
+ info->control.aid = tx->sta->aid;
+
+ if (!info->control.retry_limit) {
+ if (!is_multicast_ether_addr(hdr->addr1)) {
+ int len = min_t(int, tx->skb->len + FCS_LEN,
+ tx->local->fragmentation_threshold);
+ if (len > tx->local->rts_threshold
+ && tx->local->rts_threshold <
+ IEEE80211_MAX_RTS_THRESHOLD) {
+ info->flags |= IEEE80211_TX_CTL_USE_RTS_CTS;
+ info->flags |=
+ IEEE80211_TX_CTL_LONG_RETRY_LIMIT;
+ info->control.retry_limit =
+ tx->local->long_retry_limit;
+ } else {
+ info->control.retry_limit =
+ tx->local->short_retry_limit;
+ }
+ } else {
+ info->control.retry_limit = 1;
+ }
+ }
+
+ if (tx->flags & IEEE80211_TX_FRAGMENTED) {
+ /* Do not use multiple retry rates when sending fragmented
+ * frames.
+ * TODO: The last fragment could still use multiple retry
+ * rates. */
+ info->control.alt_retry_rate_idx = -1;
+ }
+
+ /* Use CTS protection for unicast frames sent using extended rates if
+ * there are associated non-ERP stations and RTS/CTS is not configured
+ * for the frame. */
+ if ((tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) &&
+ (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_ERP_G) &&
+ (tx->flags & IEEE80211_TX_UNICAST) &&
+ tx->sdata->bss_conf.use_cts_prot &&
+ !(info->flags & IEEE80211_TX_CTL_USE_RTS_CTS))
+ info->flags |= IEEE80211_TX_CTL_USE_CTS_PROTECT;
+
+ /* Transmit data frames using short preambles if the driver supports
+ * short preambles at the selected rate and short preambles are
+ * available on the network at the current point in time. */
+ if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
+ (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
+ tx->sdata->bss_conf.use_short_preamble &&
+ (!tx->sta || test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))) {
+ info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE;
+ }
+
+ /* Setup duration field for the first fragment of the frame. Duration
+ * for remaining fragments will be updated when they are being sent
+ * to low-level driver in ieee80211_tx(). */
+ dur = ieee80211_duration(tx, is_multicast_ether_addr(hdr->addr1),
+ (tx->flags & IEEE80211_TX_FRAGMENTED) ?
+ tx->extra_frag[0]->len : 0);
+ hdr->duration_id = cpu_to_le16(dur);
+
+ if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
+ (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) {
+ struct ieee80211_rate *rate;
+ s8 baserate = -1;
+ int idx;
+
+ /* Do not use multiple retry rates when using RTS/CTS */
+ info->control.alt_retry_rate_idx = -1;
+
+ /* Use min(data rate, max base rate) as CTS/RTS rate */
+ rate = &sband->bitrates[tx->rate_idx];
+
+ for (idx = 0; idx < sband->n_bitrates; idx++) {
+ if (sband->bitrates[idx].bitrate > rate->bitrate)
+ continue;
+ if (tx->sdata->basic_rates & BIT(idx) &&
+ (baserate < 0 ||
+ (sband->bitrates[baserate].bitrate
+ < sband->bitrates[idx].bitrate)))
+ baserate = idx;
+ }
+
+ if (baserate >= 0)
+ info->control.rts_cts_rate_idx = baserate;
+ else
+ info->control.rts_cts_rate_idx = 0;
+ }
+
+ if (tx->sta)
+ info->control.aid = tx->sta->aid;
return TX_CONTINUE;
}
@@ -515,6 +658,17 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
if (!(tx->flags & IEEE80211_TX_FRAGMENTED))
return TX_CONTINUE;
+ /*
+ * Warn when submitting a fragmented A-MPDU frame and drop it.
+ * This is an error and needs to be fixed elsewhere, but when
+ * done needs to take care of monitor interfaces (injection)
+ * etc.
+ */
+ if (WARN_ON(tx->flags & IEEE80211_TX_CTL_AMPDU ||
+ skb_get_queue_mapping(tx->skb) >=
+ ieee80211_num_regular_queues(&tx->local->hw)))
+ return TX_DROP;
+
first = tx->skb;
hdrlen = ieee80211_get_hdrlen(tx->fc);
@@ -602,215 +756,22 @@ ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx)
}
static ieee80211_tx_result
-ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
+ieee80211_tx_h_stats(struct ieee80211_tx_data *tx)
{
- struct rate_selection rsel;
- struct ieee80211_supported_band *sband;
-
- sband = tx->local->hw.wiphy->bands[tx->local->hw.conf.channel->band];
-
- if (likely(!tx->rate)) {
- rate_control_get_rate(tx->dev, sband, tx->skb, &rsel);
- tx->rate = rsel.rate;
- if (unlikely(rsel.probe)) {
- tx->control->flags |=
- IEEE80211_TXCTL_RATE_CTRL_PROBE;
- tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG;
- tx->control->alt_retry_rate = tx->rate;
- tx->rate = rsel.probe;
- } else
- tx->control->alt_retry_rate = NULL;
-
- if (!tx->rate)
- return TX_DROP;
- } else
- tx->control->alt_retry_rate = NULL;
-
- if (tx->sdata->bss_conf.use_cts_prot &&
- (tx->flags & IEEE80211_TX_FRAGMENTED) && rsel.nonerp) {
- tx->last_frag_rate = tx->rate;
- if (rsel.probe)
- tx->flags &= ~IEEE80211_TX_PROBE_LAST_FRAG;
- else
- tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG;
- tx->rate = rsel.nonerp;
- tx->control->tx_rate = rsel.nonerp;
- tx->control->flags &= ~IEEE80211_TXCTL_RATE_CTRL_PROBE;
- } else {
- tx->last_frag_rate = tx->rate;
- tx->control->tx_rate = tx->rate;
- }
- tx->control->tx_rate = tx->rate;
-
- return TX_CONTINUE;
-}
-
-static ieee80211_tx_result
-ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
-{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
- u16 fc = le16_to_cpu(hdr->frame_control);
- u16 dur;
- struct ieee80211_tx_control *control = tx->control;
-
- if (!control->retry_limit) {
- if (!is_multicast_ether_addr(hdr->addr1)) {
- if (tx->skb->len + FCS_LEN > tx->local->rts_threshold
- && tx->local->rts_threshold <
- IEEE80211_MAX_RTS_THRESHOLD) {
- control->flags |=
- IEEE80211_TXCTL_USE_RTS_CTS;
- control->flags |=
- IEEE80211_TXCTL_LONG_RETRY_LIMIT;
- control->retry_limit =
- tx->local->long_retry_limit;
- } else {
- control->retry_limit =
- tx->local->short_retry_limit;
- }
- } else {
- control->retry_limit = 1;
- }
- }
-
- if (tx->flags & IEEE80211_TX_FRAGMENTED) {
- /* Do not use multiple retry rates when sending fragmented
- * frames.
- * TODO: The last fragment could still use multiple retry
- * rates. */
- control->alt_retry_rate = NULL;
- }
-
- /* Use CTS protection for unicast frames sent using extended rates if
- * there are associated non-ERP stations and RTS/CTS is not configured
- * for the frame. */
- if ((tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) &&
- (tx->rate->flags & IEEE80211_RATE_ERP_G) &&
- (tx->flags & IEEE80211_TX_UNICAST) &&
- tx->sdata->bss_conf.use_cts_prot &&
- !(control->flags & IEEE80211_TXCTL_USE_RTS_CTS))
- control->flags |= IEEE80211_TXCTL_USE_CTS_PROTECT;
-
- /* Transmit data frames using short preambles if the driver supports
- * short preambles at the selected rate and short preambles are
- * available on the network at the current point in time. */
- if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
- (tx->rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
- tx->sdata->bss_conf.use_short_preamble &&
- (!tx->sta || (tx->sta->flags & WLAN_STA_SHORT_PREAMBLE))) {
- tx->control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE;
- }
-
- /* Setup duration field for the first fragment of the frame. Duration
- * for remaining fragments will be updated when they are being sent
- * to low-level driver in ieee80211_tx(). */
- dur = ieee80211_duration(tx, is_multicast_ether_addr(hdr->addr1),
- (tx->flags & IEEE80211_TX_FRAGMENTED) ?
- tx->extra_frag[0]->len : 0);
- hdr->duration_id = cpu_to_le16(dur);
-
- if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
- (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) {
- struct ieee80211_supported_band *sband;
- struct ieee80211_rate *rate, *baserate;
- int idx;
-
- sband = tx->local->hw.wiphy->bands[
- tx->local->hw.conf.channel->band];
-
- /* Do not use multiple retry rates when using RTS/CTS */
- control->alt_retry_rate = NULL;
-
- /* Use min(data rate, max base rate) as CTS/RTS rate */
- rate = tx->rate;
- baserate = NULL;
-
- for (idx = 0; idx < sband->n_bitrates; idx++) {
- if (sband->bitrates[idx].bitrate > rate->bitrate)
- continue;
- if (tx->sdata->basic_rates & BIT(idx) &&
- (!baserate ||
- (baserate->bitrate < sband->bitrates[idx].bitrate)))
- baserate = &sband->bitrates[idx];
- }
-
- if (baserate)
- control->rts_cts_rate = baserate;
- else
- control->rts_cts_rate = &sband->bitrates[0];
- }
-
- if (tx->sta) {
- control->aid = tx->sta->aid;
- tx->sta->tx_packets++;
- tx->sta->tx_fragments++;
- tx->sta->tx_bytes += tx->skb->len;
- if (tx->extra_frag) {
- int i;
- tx->sta->tx_fragments += tx->num_extra_frag;
- for (i = 0; i < tx->num_extra_frag; i++) {
- tx->sta->tx_bytes +=
- tx->extra_frag[i]->len;
- }
- }
- }
-
- return TX_CONTINUE;
-}
-
-static ieee80211_tx_result
-ieee80211_tx_h_load_stats(struct ieee80211_tx_data *tx)
-{
- struct ieee80211_local *local = tx->local;
- struct sk_buff *skb = tx->skb;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- u32 load = 0, hdrtime;
- struct ieee80211_rate *rate = tx->rate;
-
- /* TODO: this could be part of tx_status handling, so that the number
- * of retries would be known; TX rate should in that case be stored
- * somewhere with the packet */
-
- /* Estimate total channel use caused by this frame */
-
- /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values,
- * 1 usec = 1/8 * (1080 / 10) = 13.5 */
-
- if (tx->channel->band == IEEE80211_BAND_5GHZ ||
- (tx->channel->band == IEEE80211_BAND_2GHZ &&
- rate->flags & IEEE80211_RATE_ERP_G))
- hdrtime = CHAN_UTIL_HDR_SHORT;
- else
- hdrtime = CHAN_UTIL_HDR_LONG;
-
- load = hdrtime;
- if (!is_multicast_ether_addr(hdr->addr1))
- load += hdrtime;
-
- if (tx->control->flags & IEEE80211_TXCTL_USE_RTS_CTS)
- load += 2 * hdrtime;
- else if (tx->control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
- load += hdrtime;
+ int i;
- /* TODO: optimise again */
- load += skb->len * CHAN_UTIL_RATE_LCM / rate->bitrate;
+ if (!tx->sta)
+ return TX_CONTINUE;
+ tx->sta->tx_packets++;
+ tx->sta->tx_fragments++;
+ tx->sta->tx_bytes += tx->skb->len;
if (tx->extra_frag) {
- int i;
- for (i = 0; i < tx->num_extra_frag; i++) {
- load += 2 * hdrtime;
- load += tx->extra_frag[i]->len *
- tx->rate->bitrate;
- }
+ tx->sta->tx_fragments += tx->num_extra_frag;
+ for (i = 0; i < tx->num_extra_frag; i++)
+ tx->sta->tx_bytes += tx->extra_frag[i]->len;
}
- /* Divide channel_use by 8 to avoid wrapping around the counter */
- load >>= CHAN_UTIL_SHIFT;
- local->channel_use_raw += load;
- if (tx->sta)
- tx->sta->channel_use_raw += load;
- tx->sdata->channel_use_raw += load;
-
return TX_CONTINUE;
}
@@ -823,11 +784,12 @@ static ieee80211_tx_handler ieee80211_tx_handlers[] =
ieee80211_tx_h_ps_buf,
ieee80211_tx_h_select_key,
ieee80211_tx_h_michael_mic_add,
- ieee80211_tx_h_fragment,
- ieee80211_tx_h_encrypt,
ieee80211_tx_h_rate_ctrl,
ieee80211_tx_h_misc,
- ieee80211_tx_h_load_stats,
+ ieee80211_tx_h_fragment,
+ /* handlers after fragment must be aware of tx info fragmentation! */
+ ieee80211_tx_h_encrypt,
+ ieee80211_tx_h_stats,
NULL
};
@@ -854,12 +816,12 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
(struct ieee80211_radiotap_header *) skb->data;
struct ieee80211_supported_band *sband;
int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len);
- struct ieee80211_tx_control *control = tx->control;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- sband = tx->local->hw.wiphy->bands[tx->local->hw.conf.channel->band];
+ sband = tx->local->hw.wiphy->bands[tx->channel->band];
- control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
- tx->flags |= IEEE80211_TX_INJECTED;
+ info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
+ info->flags |= IEEE80211_TX_CTL_INJECTED;
tx->flags &= ~IEEE80211_TX_FRAGMENTED;
/*
@@ -896,7 +858,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
r = &sband->bitrates[i];
if (r->bitrate == target_rate) {
- tx->rate = r;
+ tx->rate_idx = i;
break;
}
}
@@ -907,7 +869,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
* radiotap uses 0 for 1st ant, mac80211 is 1 for
* 1st ant
*/
- control->antenna_sel_tx = (*iterator.this_arg) + 1;
+ info->antenna_sel_tx = (*iterator.this_arg) + 1;
break;
#if 0
@@ -931,8 +893,8 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
skb_trim(skb, skb->len - FCS_LEN);
}
if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP)
- control->flags &=
- ~IEEE80211_TXCTL_DO_NOT_ENCRYPT;
+ info->flags &=
+ ~IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG)
tx->flags |= IEEE80211_TX_FRAGMENTED;
break;
@@ -967,12 +929,12 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
static ieee80211_tx_result
__ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
struct sk_buff *skb,
- struct net_device *dev,
- struct ieee80211_tx_control *control)
+ struct net_device *dev)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_hdr *hdr;
struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
int hdrlen;
@@ -981,7 +943,9 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
tx->dev = dev; /* use original interface */
tx->local = local;
tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- tx->control = control;
+ tx->channel = local->hw.conf.channel;
+ tx->rate_idx = -1;
+ tx->last_frag_rate_idx = -1;
/*
* Set this flag (used below to indicate "automatic fragmentation"),
* it will be cleared/left by radiotap as desired.
@@ -1008,10 +972,10 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
if (is_multicast_ether_addr(hdr->addr1)) {
tx->flags &= ~IEEE80211_TX_UNICAST;
- control->flags |= IEEE80211_TXCTL_NO_ACK;
+ info->flags |= IEEE80211_TX_CTL_NO_ACK;
} else {
tx->flags |= IEEE80211_TX_UNICAST;
- control->flags &= ~IEEE80211_TXCTL_NO_ACK;
+ info->flags &= ~IEEE80211_TX_CTL_NO_ACK;
}
if (tx->flags & IEEE80211_TX_FRAGMENTED) {
@@ -1024,18 +988,16 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
}
if (!tx->sta)
- control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT;
- else if (tx->sta->flags & WLAN_STA_CLEAR_PS_FILT) {
- control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT;
- tx->sta->flags &= ~WLAN_STA_CLEAR_PS_FILT;
- }
+ info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
+ else if (test_and_clear_sta_flags(tx->sta, WLAN_STA_CLEAR_PS_FILT))
+ info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
hdrlen = ieee80211_get_hdrlen(tx->fc);
if (skb->len > hdrlen + sizeof(rfc1042_header) + 2) {
u8 *pos = &skb->data[hdrlen + sizeof(rfc1042_header)];
tx->ethertype = (pos[0] << 8) | pos[1];
}
- control->flags |= IEEE80211_TXCTL_FIRST_FRAGMENT;
+ info->flags |= IEEE80211_TX_CTL_FIRST_FRAGMENT;
return TX_CONTINUE;
}
@@ -1045,14 +1007,12 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
*/
static int ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
struct sk_buff *skb,
- struct net_device *mdev,
- struct ieee80211_tx_control *control)
+ struct net_device *mdev)
{
- struct ieee80211_tx_packet_data *pkt_data;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct net_device *dev;
- pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
- dev = dev_get_by_index(&init_net, pkt_data->ifindex);
+ dev = dev_get_by_index(&init_net, info->control.ifindex);
if (unlikely(dev && !is_ieee80211_device(dev, mdev))) {
dev_put(dev);
dev = NULL;
@@ -1060,7 +1020,7 @@ static int ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
if (unlikely(!dev))
return -ENODEV;
/* initialises tx with control */
- __ieee80211_tx_prepare(tx, skb, dev, control);
+ __ieee80211_tx_prepare(tx, skb, dev);
dev_put(dev);
return 0;
}
@@ -1068,50 +1028,49 @@ static int ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb,
struct ieee80211_tx_data *tx)
{
- struct ieee80211_tx_control *control = tx->control;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
int ret, i;
- if (!ieee80211_qdisc_installed(local->mdev) &&
- __ieee80211_queue_stopped(local, 0)) {
- netif_stop_queue(local->mdev);
+ if (netif_subqueue_stopped(local->mdev, skb))
return IEEE80211_TX_AGAIN;
- }
+
if (skb) {
ieee80211_dump_frame(wiphy_name(local->hw.wiphy),
"TX to low-level driver", skb);
- ret = local->ops->tx(local_to_hw(local), skb, control);
+ ret = local->ops->tx(local_to_hw(local), skb);
if (ret)
return IEEE80211_TX_AGAIN;
local->mdev->trans_start = jiffies;
ieee80211_led_tx(local, 1);
}
if (tx->extra_frag) {
- control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS |
- IEEE80211_TXCTL_USE_CTS_PROTECT |
- IEEE80211_TXCTL_CLEAR_PS_FILT |
- IEEE80211_TXCTL_FIRST_FRAGMENT);
for (i = 0; i < tx->num_extra_frag; i++) {
if (!tx->extra_frag[i])
continue;
- if (__ieee80211_queue_stopped(local, control->queue))
+ info = IEEE80211_SKB_CB(tx->extra_frag[i]);
+ info->flags &= ~(IEEE80211_TX_CTL_USE_RTS_CTS |
+ IEEE80211_TX_CTL_USE_CTS_PROTECT |
+ IEEE80211_TX_CTL_CLEAR_PS_FILT |
+ IEEE80211_TX_CTL_FIRST_FRAGMENT);
+ if (netif_subqueue_stopped(local->mdev,
+ tx->extra_frag[i]))
return IEEE80211_TX_FRAG_AGAIN;
if (i == tx->num_extra_frag) {
- control->tx_rate = tx->last_frag_rate;
+ info->tx_rate_idx = tx->last_frag_rate_idx;
if (tx->flags & IEEE80211_TX_PROBE_LAST_FRAG)
- control->flags |=
- IEEE80211_TXCTL_RATE_CTRL_PROBE;
+ info->flags |=
+ IEEE80211_TX_CTL_RATE_CTRL_PROBE;
else
- control->flags &=
- ~IEEE80211_TXCTL_RATE_CTRL_PROBE;
+ info->flags &=
+ ~IEEE80211_TX_CTL_RATE_CTRL_PROBE;
}
ieee80211_dump_frame(wiphy_name(local->hw.wiphy),
"TX to low-level driver",
tx->extra_frag[i]);
ret = local->ops->tx(local_to_hw(local),
- tx->extra_frag[i],
- control);
+ tx->extra_frag[i]);
if (ret)
return IEEE80211_TX_FRAG_AGAIN;
local->mdev->trans_start = jiffies;
@@ -1124,17 +1083,20 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb,
return IEEE80211_TX_OK;
}
-static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
- struct ieee80211_tx_control *control)
+static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct sta_info *sta;
ieee80211_tx_handler *handler;
struct ieee80211_tx_data tx;
ieee80211_tx_result res = TX_DROP, res_prepare;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
int ret, i;
+ u16 queue;
+
+ queue = skb_get_queue_mapping(skb);
- WARN_ON(__ieee80211_queue_pending(local, control->queue));
+ WARN_ON(test_bit(queue, local->queues_pending));
if (unlikely(skb->len < 10)) {
dev_kfree_skb(skb);
@@ -1144,7 +1106,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
rcu_read_lock();
/* initialises tx */
- res_prepare = __ieee80211_tx_prepare(&tx, skb, dev, control);
+ res_prepare = __ieee80211_tx_prepare(&tx, skb, dev);
if (res_prepare == TX_DROP) {
dev_kfree_skb(skb);
@@ -1154,6 +1116,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
sta = tx.sta;
tx.channel = local->hw.conf.channel;
+ info->band = tx.channel->band;
for (handler = ieee80211_tx_handlers; *handler != NULL;
handler++) {
@@ -1162,7 +1125,8 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
break;
}
- skb = tx.skb; /* handlers are allowed to change skb */
+ if (WARN_ON(tx.skb != skb))
+ goto drop;
if (unlikely(res == TX_DROP)) {
I802_DEBUG_INC(local->tx_handlers_drop);
@@ -1186,7 +1150,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
next_len = tx.extra_frag[i + 1]->len;
} else {
next_len = 0;
- tx.rate = tx.last_frag_rate;
+ tx.rate_idx = tx.last_frag_rate_idx;
}
dur = ieee80211_duration(&tx, 0, next_len);
hdr->duration_id = cpu_to_le16(dur);
@@ -1196,34 +1160,41 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
retry:
ret = __ieee80211_tx(local, skb, &tx);
if (ret) {
- struct ieee80211_tx_stored_packet *store =
- &local->pending_packet[control->queue];
+ struct ieee80211_tx_stored_packet *store;
+
+ /*
+ * Since there are no fragmented frames on A-MPDU
+ * queues, there's no reason for a driver to reject
+ * a frame there, warn and drop it.
+ */
+ if (WARN_ON(queue >= ieee80211_num_regular_queues(&local->hw)))
+ goto drop;
+
+ store = &local->pending_packet[queue];
if (ret == IEEE80211_TX_FRAG_AGAIN)
skb = NULL;
- set_bit(IEEE80211_LINK_STATE_PENDING,
- &local->state[control->queue]);
+ set_bit(queue, local->queues_pending);
smp_mb();
- /* When the driver gets out of buffers during sending of
- * fragments and calls ieee80211_stop_queue, there is
- * a small window between IEEE80211_LINK_STATE_XOFF and
- * IEEE80211_LINK_STATE_PENDING flags are set. If a buffer
+ /*
+ * When the driver gets out of buffers during sending of
+ * fragments and calls ieee80211_stop_queue, the netif
+ * subqueue is stopped. There is, however, a small window
+ * in which the PENDING bit is not yet set. If a buffer
* gets available in that window (i.e. driver calls
* ieee80211_wake_queue), we would end up with ieee80211_tx
- * called with IEEE80211_LINK_STATE_PENDING. Prevent this by
+ * called with the PENDING bit still set. Prevent this by
* continuing transmitting here when that situation is
- * possible to have happened. */
- if (!__ieee80211_queue_stopped(local, control->queue)) {
- clear_bit(IEEE80211_LINK_STATE_PENDING,
- &local->state[control->queue]);
+ * possible to have happened.
+ */
+ if (!__netif_subqueue_stopped(local->mdev, queue)) {
+ clear_bit(queue, local->queues_pending);
goto retry;
}
- memcpy(&store->control, control,
- sizeof(struct ieee80211_tx_control));
store->skb = skb;
store->extra_frag = tx.extra_frag;
store->num_extra_frag = tx.num_extra_frag;
- store->last_frag_rate = tx.last_frag_rate;
+ store->last_frag_rate_idx = tx.last_frag_rate_idx;
store->last_frag_rate_ctrl_probe =
!!(tx.flags & IEEE80211_TX_PROBE_LAST_FRAG);
}
@@ -1243,24 +1214,57 @@ retry:
/* device xmit handlers */
+static int ieee80211_skb_resize(struct ieee80211_local *local,
+ struct sk_buff *skb,
+ int head_need, bool may_encrypt)
+{
+ int tail_need = 0;
+
+ /*
+ * This could be optimised, devices that do full hardware
+ * crypto (including TKIP MMIC) need no tailroom... But we
+ * have no drivers for such devices currently.
+ */
+ if (may_encrypt) {
+ tail_need = IEEE80211_ENCRYPT_TAILROOM;
+ tail_need -= skb_tailroom(skb);
+ tail_need = max_t(int, tail_need, 0);
+ }
+
+ if (head_need || tail_need) {
+ /* Sorry. Can't account for this any more */
+ skb_orphan(skb);
+ }
+
+ if (skb_header_cloned(skb))
+ I802_DEBUG_INC(local->tx_expand_skb_head_cloned);
+ else
+ I802_DEBUG_INC(local->tx_expand_skb_head);
+
+ if (pskb_expand_head(skb, head_need, tail_need, GFP_ATOMIC)) {
+ printk(KERN_DEBUG "%s: failed to reallocate TX buffer\n",
+ wiphy_name(local->hw.wiphy));
+ return -ENOMEM;
+ }
+
+ /* update truesize too */
+ skb->truesize += head_need + tail_need;
+
+ return 0;
+}
+
int ieee80211_master_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
- struct ieee80211_tx_control control;
- struct ieee80211_tx_packet_data *pkt_data;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct net_device *odev = NULL;
struct ieee80211_sub_if_data *osdata;
int headroom;
+ bool may_encrypt;
int ret;
- /*
- * copy control out of the skb so other people can use skb->cb
- */
- pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
- memset(&control, 0, sizeof(struct ieee80211_tx_control));
-
- if (pkt_data->ifindex)
- odev = dev_get_by_index(&init_net, pkt_data->ifindex);
+ if (info->control.ifindex)
+ odev = dev_get_by_index(&init_net, info->control.ifindex);
if (unlikely(odev && !is_ieee80211_device(odev, dev))) {
dev_put(odev);
odev = NULL;
@@ -1273,32 +1277,25 @@ int ieee80211_master_start_xmit(struct sk_buff *skb,
dev_kfree_skb(skb);
return 0;
}
+
osdata = IEEE80211_DEV_TO_SUB_IF(odev);
- headroom = osdata->local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM;
- if (skb_headroom(skb) < headroom) {
- if (pskb_expand_head(skb, headroom, 0, GFP_ATOMIC)) {
- dev_kfree_skb(skb);
- dev_put(odev);
- return 0;
- }
+ may_encrypt = !(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT);
+
+ headroom = osdata->local->tx_headroom;
+ if (may_encrypt)
+ headroom += IEEE80211_ENCRYPT_HEADROOM;
+ headroom -= skb_headroom(skb);
+ headroom = max_t(int, 0, headroom);
+
+ if (ieee80211_skb_resize(osdata->local, skb, headroom, may_encrypt)) {
+ dev_kfree_skb(skb);
+ dev_put(odev);
+ return 0;
}
- control.vif = &osdata->vif;
- control.type = osdata->vif.type;
- if (pkt_data->flags & IEEE80211_TXPD_REQ_TX_STATUS)
- control.flags |= IEEE80211_TXCTL_REQ_TX_STATUS;
- if (pkt_data->flags & IEEE80211_TXPD_DO_NOT_ENCRYPT)
- control.flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
- if (pkt_data->flags & IEEE80211_TXPD_REQUEUE)
- control.flags |= IEEE80211_TXCTL_REQUEUE;
- if (pkt_data->flags & IEEE80211_TXPD_EAPOL_FRAME)
- control.flags |= IEEE80211_TXCTL_EAPOL_FRAME;
- if (pkt_data->flags & IEEE80211_TXPD_AMPDU)
- control.flags |= IEEE80211_TXCTL_AMPDU;
- control.queue = pkt_data->queue;
-
- ret = ieee80211_tx(odev, skb, &control);
+ info->control.vif = &osdata->vif;
+ ret = ieee80211_tx(odev, skb);
dev_put(odev);
return ret;
@@ -1308,7 +1305,7 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_tx_packet_data *pkt_data;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_radiotap_header *prthdr =
(struct ieee80211_radiotap_header *)skb->data;
u16 len_rthdr;
@@ -1330,12 +1327,12 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb,
skb->dev = local->mdev;
- pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
- memset(pkt_data, 0, sizeof(*pkt_data));
/* needed because we set skb device to master */
- pkt_data->ifindex = dev->ifindex;
+ info->control.ifindex = dev->ifindex;
- pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;
+ info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
+ /* Interfaces should always request a status report */
+ info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
/*
* fix up the pointers accounting for the radiotap
@@ -1379,7 +1376,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_tx_packet_data *pkt_data;
+ struct ieee80211_tx_info *info;
struct ieee80211_sub_if_data *sdata;
int ret = 1, head_need;
u16 ethertype, hdrlen, meshhdrlen = 0, fc;
@@ -1486,12 +1483,13 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
rcu_read_lock();
sta = sta_info_get(local, hdr.addr1);
if (sta)
- sta_flags = sta->flags;
+ sta_flags = get_sta_flags(sta);
rcu_read_unlock();
}
- /* receiver is QoS enabled, use a QoS type frame */
- if (sta_flags & WLAN_STA_WME) {
+ /* receiver and we are QoS enabled, use a QoS type frame */
+ if (sta_flags & WLAN_STA_WME &&
+ ieee80211_num_regular_queues(&local->hw) >= 4) {
fc |= IEEE80211_STYPE_QOS_DATA;
hdrlen += 2;
}
@@ -1555,32 +1553,26 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
* build in headroom in __dev_alloc_skb() (linux/skbuff.h) and
* alloc_skb() (net/core/skbuff.c)
*/
- head_need = hdrlen + encaps_len + meshhdrlen + local->tx_headroom;
- head_need -= skb_headroom(skb);
+ head_need = hdrlen + encaps_len + meshhdrlen - skb_headroom(skb);
- /* We are going to modify skb data, so make a copy of it if happens to
- * be cloned. This could happen, e.g., with Linux bridge code passing
- * us broadcast frames. */
+ /*
+ * So we need to modify the skb header and hence need a copy of
+ * that. The head_need variable above doesn't, so far, include
+ * the needed header space that we don't need right away. If we
+ * can, then we don't reallocate right now but only after the
+ * frame arrives at the master device (if it does...)
+ *
+ * If we cannot, however, then we will reallocate to include all
+ * the ever needed space. Also, if we need to reallocate it anyway,
+ * make it big enough for everything we may ever need.
+ */
if (head_need > 0 || skb_header_cloned(skb)) {
-#if 0
- printk(KERN_DEBUG "%s: need to reallocate buffer for %d bytes "
- "of headroom\n", dev->name, head_need);
-#endif
-
- if (skb_header_cloned(skb))
- I802_DEBUG_INC(local->tx_expand_skb_head_cloned);
- else
- I802_DEBUG_INC(local->tx_expand_skb_head);
- /* Since we have to reallocate the buffer, make sure that there
- * is enough room for possible WEP IV/ICV and TKIP (8 bytes
- * before payload and 12 after). */
- if (pskb_expand_head(skb, (head_need > 0 ? head_need + 8 : 8),
- 12, GFP_ATOMIC)) {
- printk(KERN_DEBUG "%s: failed to reallocate TX buffer"
- "\n", dev->name);
+ head_need += IEEE80211_ENCRYPT_HEADROOM;
+ head_need += local->tx_headroom;
+ head_need = max_t(int, 0, head_need);
+ if (ieee80211_skb_resize(local, skb, head_need, true))
goto fail;
- }
}
if (encaps_data) {
@@ -1611,11 +1603,14 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
nh_pos += hdrlen;
h_pos += hdrlen;
- pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
- memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
- pkt_data->ifindex = dev->ifindex;
+ info = IEEE80211_SKB_CB(skb);
+ memset(info, 0, sizeof(*info));
+ info->control.ifindex = dev->ifindex;
if (ethertype == ETH_P_PAE)
- pkt_data->flags |= IEEE80211_TXPD_EAPOL_FRAME;
+ info->flags |= IEEE80211_TX_CTL_EAPOL_FRAME;
+
+ /* Interfaces should always request a status report */
+ info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
skb->dev = local->mdev;
dev->stats.tx_packets++;
@@ -1640,46 +1635,55 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
return ret;
}
-/* helper functions for pending packets for when queues are stopped */
+/*
+ * ieee80211_clear_tx_pending may not be called in a context where
+ * it is possible that it packets could come in again.
+ */
void ieee80211_clear_tx_pending(struct ieee80211_local *local)
{
int i, j;
struct ieee80211_tx_stored_packet *store;
- for (i = 0; i < local->hw.queues; i++) {
- if (!__ieee80211_queue_pending(local, i))
+ for (i = 0; i < ieee80211_num_regular_queues(&local->hw); i++) {
+ if (!test_bit(i, local->queues_pending))
continue;
store = &local->pending_packet[i];
kfree_skb(store->skb);
for (j = 0; j < store->num_extra_frag; j++)
kfree_skb(store->extra_frag[j]);
kfree(store->extra_frag);
- clear_bit(IEEE80211_LINK_STATE_PENDING, &local->state[i]);
+ clear_bit(i, local->queues_pending);
}
}
+/*
+ * Transmit all pending packets. Called from tasklet, locks master device
+ * TX lock so that no new packets can come in.
+ */
void ieee80211_tx_pending(unsigned long data)
{
struct ieee80211_local *local = (struct ieee80211_local *)data;
struct net_device *dev = local->mdev;
struct ieee80211_tx_stored_packet *store;
struct ieee80211_tx_data tx;
- int i, ret, reschedule = 0;
+ int i, ret;
netif_tx_lock_bh(dev);
- for (i = 0; i < local->hw.queues; i++) {
- if (__ieee80211_queue_stopped(local, i))
+ for (i = 0; i < ieee80211_num_regular_queues(&local->hw); i++) {
+ /* Check that this queue is ok */
+ if (__netif_subqueue_stopped(local->mdev, i))
continue;
- if (!__ieee80211_queue_pending(local, i)) {
- reschedule = 1;
+
+ if (!test_bit(i, local->queues_pending)) {
+ ieee80211_wake_queue(&local->hw, i);
continue;
}
+
store = &local->pending_packet[i];
- tx.control = &store->control;
tx.extra_frag = store->extra_frag;
tx.num_extra_frag = store->num_extra_frag;
- tx.last_frag_rate = store->last_frag_rate;
+ tx.last_frag_rate_idx = store->last_frag_rate_idx;
tx.flags = 0;
if (store->last_frag_rate_ctrl_probe)
tx.flags |= IEEE80211_TX_PROBE_LAST_FRAG;
@@ -1688,19 +1692,11 @@ void ieee80211_tx_pending(unsigned long data)
if (ret == IEEE80211_TX_FRAG_AGAIN)
store->skb = NULL;
} else {
- clear_bit(IEEE80211_LINK_STATE_PENDING,
- &local->state[i]);
- reschedule = 1;
+ clear_bit(i, local->queues_pending);
+ ieee80211_wake_queue(&local->hw, i);
}
}
netif_tx_unlock_bh(dev);
- if (reschedule) {
- if (!ieee80211_qdisc_installed(dev)) {
- if (!__ieee80211_queue_stopped(local, 0))
- netif_wake_queue(dev);
- } else
- netif_schedule(dev);
- }
}
/* functions for drivers to get certain frames */
@@ -1769,11 +1765,11 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local,
}
struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_tx_control *control)
+ struct ieee80211_vif *vif)
{
struct ieee80211_local *local = hw_to_local(hw);
struct sk_buff *skb;
+ struct ieee80211_tx_info *info;
struct net_device *bdev;
struct ieee80211_sub_if_data *sdata = NULL;
struct ieee80211_if_ap *ap = NULL;
@@ -1783,9 +1779,10 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
struct ieee80211_mgmt *mgmt;
int *num_beacons;
bool err = true;
+ enum ieee80211_band band = local->hw.conf.channel->band;
u8 *pos;
- sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+ sband = local->hw.wiphy->bands[band];
rcu_read_lock();
@@ -1878,30 +1875,32 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
goto out;
}
- if (control) {
- rate_control_get_rate(local->mdev, sband, skb, &rsel);
- if (!rsel.rate) {
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: ieee80211_beacon_get: "
- "no rate found\n",
- wiphy_name(local->hw.wiphy));
- }
- dev_kfree_skb(skb);
- skb = NULL;
- goto out;
- }
+ info = IEEE80211_SKB_CB(skb);
- control->vif = vif;
- control->tx_rate = rsel.rate;
- if (sdata->bss_conf.use_short_preamble &&
- rsel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
- control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE;
- control->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
- control->flags |= IEEE80211_TXCTL_NO_ACK;
- control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
- control->retry_limit = 1;
- control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT;
+ info->band = band;
+ rate_control_get_rate(local->mdev, sband, skb, &rsel);
+
+ if (unlikely(rsel.rate_idx < 0)) {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "%s: ieee80211_beacon_get: "
+ "no rate found\n",
+ wiphy_name(local->hw.wiphy));
+ }
+ dev_kfree_skb(skb);
+ skb = NULL;
+ goto out;
}
+
+ info->control.vif = vif;
+ info->tx_rate_idx = rsel.rate_idx;
+ 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();
@@ -1911,7 +1910,7 @@ EXPORT_SYMBOL(ieee80211_beacon_get);
void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
const void *frame, size_t frame_len,
- const struct ieee80211_tx_control *frame_txctl,
+ const struct ieee80211_tx_info *frame_txctl,
struct ieee80211_rts *rts)
{
const struct ieee80211_hdr *hdr = frame;
@@ -1928,7 +1927,7 @@ EXPORT_SYMBOL(ieee80211_rts_get);
void ieee80211_ctstoself_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
const void *frame, size_t frame_len,
- const struct ieee80211_tx_control *frame_txctl,
+ const struct ieee80211_tx_info *frame_txctl,
struct ieee80211_cts *cts)
{
const struct ieee80211_hdr *hdr = frame;
@@ -1944,11 +1943,10 @@ EXPORT_SYMBOL(ieee80211_ctstoself_get);
struct sk_buff *
ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_tx_control *control)
+ struct ieee80211_vif *vif)
{
struct ieee80211_local *local = hw_to_local(hw);
- struct sk_buff *skb;
+ struct sk_buff *skb = NULL;
struct sta_info *sta;
ieee80211_tx_handler *handler;
struct ieee80211_tx_data tx;
@@ -1957,10 +1955,11 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
struct ieee80211_sub_if_data *sdata;
struct ieee80211_if_ap *bss = NULL;
struct beacon_data *beacon;
+ struct ieee80211_tx_info *info;
sdata = vif_to_sdata(vif);
bdev = sdata->dev;
-
+ bss = &sdata->u.ap;
if (!bss)
return NULL;
@@ -1968,19 +1967,16 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
rcu_read_lock();
beacon = rcu_dereference(bss->beacon);
- if (sdata->vif.type != IEEE80211_IF_TYPE_AP || !beacon ||
- !beacon->head) {
- rcu_read_unlock();
- return NULL;
- }
+ if (sdata->vif.type != IEEE80211_IF_TYPE_AP || !beacon || !beacon->head)
+ goto out;
if (bss->dtim_count != 0)
- return NULL; /* send buffered bc/mc only after DTIM beacon */
- memset(control, 0, sizeof(*control));
+ goto out; /* send buffered bc/mc only after DTIM beacon */
+
while (1) {
skb = skb_dequeue(&bss->ps_bc_buf);
if (!skb)
- return NULL;
+ goto out;
local->total_ps_buffered--;
if (!skb_queue_empty(&bss->ps_bc_buf) && skb->len >= 2) {
@@ -1993,20 +1989,26 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
cpu_to_le16(IEEE80211_FCTL_MOREDATA);
}
- if (!ieee80211_tx_prepare(&tx, skb, local->mdev, control))
+ if (!ieee80211_tx_prepare(&tx, skb, local->mdev))
break;
dev_kfree_skb_any(skb);
}
+
+ info = IEEE80211_SKB_CB(skb);
+
sta = tx.sta;
tx.flags |= IEEE80211_TX_PS_BUFFERED;
tx.channel = local->hw.conf.channel;
+ info->band = tx.channel->band;
for (handler = ieee80211_tx_handlers; *handler != NULL; handler++) {
res = (*handler)(&tx);
if (res == TX_DROP || res == TX_QUEUED)
break;
}
- skb = tx.skb; /* handlers are allowed to change skb */
+
+ if (WARN_ON(tx.skb != skb))
+ res = TX_DROP;
if (res == TX_DROP) {
I802_DEBUG_INC(local->tx_handlers_drop);
@@ -2017,6 +2019,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
skb = NULL;
}
+out:
rcu_read_unlock();
return skb;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 24a465c4df09..6513bc2d2707 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -34,11 +34,11 @@ void *mac80211_wiphy_privid = &mac80211_wiphy_privid;
/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
-const unsigned char rfc1042_header[] =
+const unsigned char rfc1042_header[] __aligned(2) =
{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
-const unsigned char bridge_tunnel_header[] =
+const unsigned char bridge_tunnel_header[] __aligned(2) =
{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
@@ -258,7 +258,7 @@ EXPORT_SYMBOL(ieee80211_generic_frame_duration);
__le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, size_t frame_len,
- const struct ieee80211_tx_control *frame_txctl)
+ const struct ieee80211_tx_info *frame_txctl)
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_rate *rate;
@@ -266,10 +266,13 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
bool short_preamble;
int erp;
u16 dur;
+ struct ieee80211_supported_band *sband;
+
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
short_preamble = sdata->bss_conf.use_short_preamble;
- rate = frame_txctl->rts_cts_rate;
+ rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx];
erp = 0;
if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
@@ -292,7 +295,7 @@ EXPORT_SYMBOL(ieee80211_rts_duration);
__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
size_t frame_len,
- const struct ieee80211_tx_control *frame_txctl)
+ const struct ieee80211_tx_info *frame_txctl)
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_rate *rate;
@@ -300,10 +303,13 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
bool short_preamble;
int erp;
u16 dur;
+ struct ieee80211_supported_band *sband;
+
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
short_preamble = sdata->bss_conf.use_short_preamble;
- rate = frame_txctl->rts_cts_rate;
+ rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx];
erp = 0;
if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
erp = rate->flags & IEEE80211_RATE_ERP_G;
@@ -311,7 +317,7 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
/* Data frame duration */
dur = ieee80211_frame_duration(local, frame_len, rate->bitrate,
erp, short_preamble);
- if (!(frame_txctl->flags & IEEE80211_TXCTL_NO_ACK)) {
+ if (!(frame_txctl->flags & IEEE80211_TX_CTL_NO_ACK)) {
/* ACK duration */
dur += ieee80211_frame_duration(local, 10, rate->bitrate,
erp, short_preamble);
@@ -325,17 +331,15 @@ void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue)
{
struct ieee80211_local *local = hw_to_local(hw);
- if (test_and_clear_bit(IEEE80211_LINK_STATE_XOFF,
- &local->state[queue])) {
- if (test_bit(IEEE80211_LINK_STATE_PENDING,
- &local->state[queue]))
- tasklet_schedule(&local->tx_pending_tasklet);
- else
- if (!ieee80211_qdisc_installed(local->mdev)) {
- if (queue == 0)
- netif_wake_queue(local->mdev);
- } else
- __netif_schedule(local->mdev);
+ if (test_bit(queue, local->queues_pending)) {
+ tasklet_schedule(&local->tx_pending_tasklet);
+ } else {
+ if (ieee80211_is_multiqueue(local)) {
+ netif_wake_subqueue(local->mdev, queue);
+ } else {
+ WARN_ON(queue != 0);
+ netif_wake_queue(local->mdev);
+ }
}
}
EXPORT_SYMBOL(ieee80211_wake_queue);
@@ -344,29 +348,20 @@ void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue)
{
struct ieee80211_local *local = hw_to_local(hw);
- if (!ieee80211_qdisc_installed(local->mdev) && queue == 0)
+ if (ieee80211_is_multiqueue(local)) {
+ netif_stop_subqueue(local->mdev, queue);
+ } else {
+ WARN_ON(queue != 0);
netif_stop_queue(local->mdev);
- set_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]);
+ }
}
EXPORT_SYMBOL(ieee80211_stop_queue);
-void ieee80211_start_queues(struct ieee80211_hw *hw)
-{
- struct ieee80211_local *local = hw_to_local(hw);
- int i;
-
- for (i = 0; i < local->hw.queues; i++)
- clear_bit(IEEE80211_LINK_STATE_XOFF, &local->state[i]);
- if (!ieee80211_qdisc_installed(local->mdev))
- netif_start_queue(local->mdev);
-}
-EXPORT_SYMBOL(ieee80211_start_queues);
-
void ieee80211_stop_queues(struct ieee80211_hw *hw)
{
int i;
- for (i = 0; i < hw->queues; i++)
+ for (i = 0; i < ieee80211_num_queues(hw); i++)
ieee80211_stop_queue(hw, i);
}
EXPORT_SYMBOL(ieee80211_stop_queues);
@@ -375,7 +370,7 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw)
{
int i;
- for (i = 0; i < hw->queues; i++)
+ for (i = 0; i < hw->queues + hw->ampdu_queues; i++)
ieee80211_wake_queue(hw, i);
}
EXPORT_SYMBOL(ieee80211_wake_queues);
@@ -389,6 +384,41 @@ void ieee80211_iterate_active_interfaces(
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_sub_if_data *sdata;
+ rtnl_lock();
+
+ list_for_each_entry(sdata, &local->interfaces, list) {
+ switch (sdata->vif.type) {
+ case IEEE80211_IF_TYPE_INVALID:
+ case IEEE80211_IF_TYPE_MNTR:
+ case IEEE80211_IF_TYPE_VLAN:
+ continue;
+ case IEEE80211_IF_TYPE_AP:
+ case IEEE80211_IF_TYPE_STA:
+ case IEEE80211_IF_TYPE_IBSS:
+ case IEEE80211_IF_TYPE_WDS:
+ 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);
+ }
+
+ rtnl_unlock();
+}
+EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces);
+
+void ieee80211_iterate_active_interfaces_atomic(
+ struct ieee80211_hw *hw,
+ void (*iterator)(void *data, u8 *mac,
+ struct ieee80211_vif *vif),
+ void *data)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct ieee80211_sub_if_data *sdata;
+
rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
@@ -413,4 +443,4 @@ void ieee80211_iterate_active_interfaces(
rcu_read_unlock();
}
-EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces);
+EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic);
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c
index affcecd78c10..e7b6344c900a 100644
--- a/net/mac80211/wep.c
+++ b/net/mac80211/wep.c
@@ -93,13 +93,9 @@ static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local,
fc |= IEEE80211_FCTL_PROTECTED;
hdr->frame_control = cpu_to_le16(fc);
- if ((skb_headroom(skb) < WEP_IV_LEN ||
- skb_tailroom(skb) < WEP_ICV_LEN)) {
- I802_DEBUG_INC(local->tx_expand_skb_head);
- if (unlikely(pskb_expand_head(skb, WEP_IV_LEN, WEP_ICV_LEN,
- GFP_ATOMIC)))
- return NULL;
- }
+ if (WARN_ON(skb_tailroom(skb) < WEP_ICV_LEN ||
+ skb_headroom(skb) < WEP_IV_LEN))
+ return NULL;
hdrlen = ieee80211_get_hdrlen(fc);
newhdr = skb_push(skb, WEP_IV_LEN);
@@ -333,11 +329,16 @@ ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx)
static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+ info->control.iv_len = WEP_IV_LEN;
+ info->control.icv_len = WEP_ICV_LEN;
+
if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) {
if (ieee80211_wep_encrypt(tx->local, skb, tx->key))
return -1;
} else {
- tx->control->key_idx = tx->key->conf.hw_key_idx;
+ info->control.hw_key = &tx->key->conf;
if (tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) {
if (!ieee80211_wep_add_iv(tx->local, skb, tx->key))
return -1;
@@ -349,8 +350,6 @@ static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
ieee80211_tx_result
ieee80211_crypto_wep_encrypt(struct ieee80211_tx_data *tx)
{
- tx->control->iv_len = WEP_IV_LEN;
- tx->control->icv_len = WEP_ICV_LEN;
ieee80211_tx_set_protected(tx);
if (wep_encrypt_skb(tx, tx->skb) < 0) {
diff --git a/net/mac80211/wep.h b/net/mac80211/wep.h
index 363779c50658..e587172115b8 100644
--- a/net/mac80211/wep.h
+++ b/net/mac80211/wep.h
@@ -26,7 +26,7 @@ int ieee80211_wep_encrypt(struct ieee80211_local *local, struct sk_buff *skb,
struct ieee80211_key *key);
int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb,
struct ieee80211_key *key);
-u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key);
+u8 *ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key);
ieee80211_rx_result
ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx);
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c
index 76e1de1dc735..4806d96b9877 100644
--- a/net/mac80211/wext.c
+++ b/net/mac80211/wext.c
@@ -169,14 +169,26 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev,
range->num_encoding_sizes = 2;
range->max_encoding_tokens = NUM_DEFAULT_KEYS;
- range->max_qual.qual = local->hw.max_signal;
- range->max_qual.level = local->hw.max_rssi;
- range->max_qual.noise = local->hw.max_noise;
+ if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC ||
+ local->hw.flags & IEEE80211_HW_SIGNAL_DB)
+ range->max_qual.level = local->hw.max_signal;
+ else if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
+ range->max_qual.level = -110;
+ else
+ range->max_qual.level = 0;
+
+ if (local->hw.flags & IEEE80211_HW_NOISE_DBM)
+ range->max_qual.noise = -110;
+ else
+ range->max_qual.noise = 0;
+
+ range->max_qual.qual = 100;
range->max_qual.updated = local->wstats_flags;
- range->avg_qual.qual = local->hw.max_signal/2;
- range->avg_qual.level = 0;
- range->avg_qual.noise = 0;
+ range->avg_qual.qual = 50;
+ /* not always true but better than nothing */
+ range->avg_qual.level = range->max_qual.level / 2;
+ range->avg_qual.noise = range->max_qual.noise / 2;
range->avg_qual.updated = local->wstats_flags;
range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
@@ -209,7 +221,6 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev,
range->num_frequency = c;
IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
- IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWTHRSPY);
IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
@@ -291,14 +302,22 @@ static int ieee80211_ioctl_giwmode(struct net_device *dev,
return 0;
}
-int ieee80211_set_freq(struct ieee80211_local *local, int freqMHz)
+int ieee80211_set_freq(struct net_device *dev, int freqMHz)
{
int ret = -EINVAL;
struct ieee80211_channel *chan;
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
chan = ieee80211_get_channel(local->hw.wiphy, freqMHz);
if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) {
+ if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS &&
+ chan->flags & IEEE80211_CHAN_NO_IBSS) {
+ printk(KERN_DEBUG "%s: IBSS not allowed on frequency "
+ "%d MHz\n", dev->name, chan->center_freq);
+ return ret;
+ }
local->oper_channel = chan;
if (local->sta_sw_scanning || local->sta_hw_scanning)
@@ -316,7 +335,6 @@ static int ieee80211_ioctl_siwfreq(struct net_device *dev,
struct iw_request_info *info,
struct iw_freq *freq, char *extra)
{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->vif.type == IEEE80211_IF_TYPE_STA)
@@ -330,14 +348,14 @@ static int ieee80211_ioctl_siwfreq(struct net_device *dev,
IEEE80211_STA_AUTO_CHANNEL_SEL;
return 0;
} else
- return ieee80211_set_freq(local,
+ return ieee80211_set_freq(dev,
ieee80211_channel_to_frequency(freq->m));
} else {
int i, div = 1000000;
for (i = 0; i < freq->e; i++)
div /= 10;
if (div > 0)
- return ieee80211_set_freq(local, freq->m / div);
+ return ieee80211_set_freq(dev, freq->m / div);
else
return -EINVAL;
}
@@ -490,9 +508,14 @@ static int ieee80211_ioctl_giwap(struct net_device *dev,
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
- ap_addr->sa_family = ARPHRD_ETHER;
- memcpy(&ap_addr->sa_data, sdata->u.sta.bssid, ETH_ALEN);
- return 0;
+ if (sdata->u.sta.state == IEEE80211_ASSOCIATED) {
+ ap_addr->sa_family = ARPHRD_ETHER;
+ memcpy(&ap_addr->sa_data, sdata->u.sta.bssid, ETH_ALEN);
+ return 0;
+ } else {
+ memset(&ap_addr->sa_data, 0, ETH_ALEN);
+ return 0;
+ }
} else if (sdata->vif.type == IEEE80211_IF_TYPE_WDS) {
ap_addr->sa_family = ARPHRD_ETHER;
memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN);
@@ -996,8 +1019,8 @@ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev
wstats->qual.noise = 0;
wstats->qual.updated = IW_QUAL_ALL_INVALID;
} else {
- wstats->qual.level = sta->last_rssi;
- wstats->qual.qual = sta->last_signal;
+ wstats->qual.level = sta->last_signal;
+ wstats->qual.qual = sta->last_qual;
wstats->qual.noise = sta->last_noise;
wstats->qual.updated = local->wstats_flags;
}
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index dc1598b86004..14a9ff10a1e9 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -19,16 +19,22 @@
#include "wme.h"
/* maximum number of hardware queues we support. */
-#define TC_80211_MAX_QUEUES 16
+#define QD_MAX_QUEUES (IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_QUEUES)
+/* current number of hardware queues we support. */
+#define QD_NUM(hw) ((hw)->queues + (hw)->ampdu_queues)
+/*
+ * Default mapping in classifier to work with default
+ * queue setup.
+ */
const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 };
struct ieee80211_sched_data
{
- unsigned long qdisc_pool[BITS_TO_LONGS(TC_80211_MAX_QUEUES)];
+ unsigned long qdisc_pool[BITS_TO_LONGS(QD_MAX_QUEUES)];
struct tcf_proto *filter_list;
- struct Qdisc *queues[TC_80211_MAX_QUEUES];
- struct sk_buff_head requeued[TC_80211_MAX_QUEUES];
+ struct Qdisc *queues[QD_MAX_QUEUES];
+ struct sk_buff_head requeued[QD_MAX_QUEUES];
};
static const char llc_ip_hdr[8] = {0xAA, 0xAA, 0x3, 0, 0, 0, 0x08, 0};
@@ -95,7 +101,7 @@ static inline int wme_downgrade_ac(struct sk_buff *skb)
/* positive return value indicates which queue to use
* negative return value indicates to drop the frame */
-static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd)
+static int classify80211(struct sk_buff *skb, struct Qdisc *qd)
{
struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
@@ -106,7 +112,7 @@ static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd)
if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)) {
/* management frames go on AC_VO queue, but are sent
* without QoS control fields */
- return IEEE80211_TX_QUEUE_DATA0;
+ return 0;
}
if (0 /* injected */) {
@@ -141,29 +147,29 @@ static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd)
static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd)
{
struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
+ struct ieee80211_hw *hw = &local->hw;
struct ieee80211_sched_data *q = qdisc_priv(qd);
- struct ieee80211_tx_packet_data *pkt_data =
- (struct ieee80211_tx_packet_data *) skb->cb;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
unsigned short fc = le16_to_cpu(hdr->frame_control);
struct Qdisc *qdisc;
- int err, queue;
struct sta_info *sta;
+ int err, queue;
u8 tid;
- if (pkt_data->flags & IEEE80211_TXPD_REQUEUE) {
- queue = pkt_data->queue;
+ if (info->flags & IEEE80211_TX_CTL_REQUEUE) {
+ queue = skb_get_queue_mapping(skb);
rcu_read_lock();
sta = sta_info_get(local, hdr->addr1);
tid = skb->priority & QOS_CONTROL_TAG1D_MASK;
if (sta) {
int ampdu_queue = sta->tid_to_tx_q[tid];
- if ((ampdu_queue < local->hw.queues) &&
+ if ((ampdu_queue < QD_NUM(hw)) &&
test_bit(ampdu_queue, q->qdisc_pool)) {
queue = ampdu_queue;
- pkt_data->flags |= IEEE80211_TXPD_AMPDU;
+ info->flags |= IEEE80211_TX_CTL_AMPDU;
} else {
- pkt_data->flags &= ~IEEE80211_TXPD_AMPDU;
+ info->flags &= ~IEEE80211_TX_CTL_AMPDU;
}
}
rcu_read_unlock();
@@ -174,6 +180,9 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd)
queue = classify80211(skb, qd);
+ if (unlikely(queue >= local->hw.queues))
+ queue = local->hw.queues - 1;
+
/* now we know the 1d priority, fill in the QoS header if there is one
*/
if (WLAN_FC_IS_QOS_DATA(fc)) {
@@ -193,35 +202,24 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd)
sta = sta_info_get(local, hdr->addr1);
if (sta) {
int ampdu_queue = sta->tid_to_tx_q[tid];
- if ((ampdu_queue < local->hw.queues) &&
- test_bit(ampdu_queue, q->qdisc_pool)) {
+ if ((ampdu_queue < QD_NUM(hw)) &&
+ test_bit(ampdu_queue, q->qdisc_pool)) {
queue = ampdu_queue;
- pkt_data->flags |= IEEE80211_TXPD_AMPDU;
+ info->flags |= IEEE80211_TX_CTL_AMPDU;
} else {
- pkt_data->flags &= ~IEEE80211_TXPD_AMPDU;
+ info->flags &= ~IEEE80211_TX_CTL_AMPDU;
}
}
rcu_read_unlock();
}
- if (unlikely(queue >= local->hw.queues)) {
-#if 0
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s - queue=%d (hw does not "
- "support) -> %d\n",
- __func__, queue, local->hw.queues - 1);
- }
-#endif
- queue = local->hw.queues - 1;
- }
-
if (unlikely(queue < 0)) {
kfree_skb(skb);
err = NET_XMIT_DROP;
} else {
tid = skb->priority & QOS_CONTROL_TAG1D_MASK;
- pkt_data->queue = (unsigned int) queue;
+ skb_set_queue_mapping(skb, queue);
qdisc = q->queues[queue];
err = qdisc->enqueue(skb, qdisc);
if (err == NET_XMIT_SUCCESS) {
@@ -242,13 +240,11 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd)
static int wme_qdiscop_requeue(struct sk_buff *skb, struct Qdisc* qd)
{
struct ieee80211_sched_data *q = qdisc_priv(qd);
- struct ieee80211_tx_packet_data *pkt_data =
- (struct ieee80211_tx_packet_data *) skb->cb;
struct Qdisc *qdisc;
int err;
/* we recorded which queue to use earlier! */
- qdisc = q->queues[pkt_data->queue];
+ qdisc = q->queues[skb_get_queue_mapping(skb)];
if ((err = qdisc->ops->requeue(skb, qdisc)) == 0) {
qd->q.qlen++;
@@ -270,13 +266,10 @@ static struct sk_buff *wme_qdiscop_dequeue(struct Qdisc* qd)
int queue;
/* check all the h/w queues in numeric/priority order */
- for (queue = 0; queue < hw->queues; queue++) {
+ for (queue = 0; queue < QD_NUM(hw); queue++) {
/* see if there is room in this hardware queue */
- if ((test_bit(IEEE80211_LINK_STATE_XOFF,
- &local->state[queue])) ||
- (test_bit(IEEE80211_LINK_STATE_PENDING,
- &local->state[queue])) ||
- (!test_bit(queue, q->qdisc_pool)))
+ if (__netif_subqueue_stopped(local->mdev, queue) ||
+ !test_bit(queue, q->qdisc_pool))
continue;
/* there is space - try and get a frame */
@@ -308,7 +301,7 @@ static void wme_qdiscop_reset(struct Qdisc* qd)
/* QUESTION: should we have some hardware flush functionality here? */
- for (queue = 0; queue < hw->queues; queue++) {
+ for (queue = 0; queue < QD_NUM(hw); queue++) {
skb_queue_purge(&q->requeued[queue]);
qdisc_reset(q->queues[queue]);
}
@@ -326,7 +319,7 @@ static void wme_qdiscop_destroy(struct Qdisc* qd)
tcf_destroy_chain(q->filter_list);
q->filter_list = NULL;
- for (queue=0; queue < hw->queues; queue++) {
+ for (queue = 0; queue < QD_NUM(hw); queue++) {
skb_queue_purge(&q->requeued[queue]);
qdisc_destroy(q->queues[queue]);
q->queues[queue] = &noop_qdisc;
@@ -337,17 +330,6 @@ static void wme_qdiscop_destroy(struct Qdisc* qd)
/* called whenever parameters are updated on existing qdisc */
static int wme_qdiscop_tune(struct Qdisc *qd, struct nlattr *opt)
{
-/* struct ieee80211_sched_data *q = qdisc_priv(qd);
-*/
- /* check our options block is the right size */
- /* copy any options to our local structure */
-/* Ignore options block for now - always use static mapping
- struct tc_ieee80211_qopt *qopt = nla_data(opt);
-
- if (opt->nla_len < nla_attr_size(sizeof(*qopt)))
- return -EINVAL;
- memcpy(q->tag2queue, qopt->tag2queue, sizeof(qopt->tag2queue));
-*/
return 0;
}
@@ -358,7 +340,7 @@ static int wme_qdiscop_init(struct Qdisc *qd, struct nlattr *opt)
struct ieee80211_sched_data *q = qdisc_priv(qd);
struct net_device *dev = qd->dev;
struct ieee80211_local *local;
- int queues;
+ struct ieee80211_hw *hw;
int err = 0, i;
/* check that device is a mac80211 device */
@@ -366,29 +348,26 @@ static int wme_qdiscop_init(struct Qdisc *qd, struct nlattr *opt)
dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid)
return -EINVAL;
- /* check this device is an ieee80211 master type device */
- if (dev->type != ARPHRD_IEEE80211)
+ local = wdev_priv(dev->ieee80211_ptr);
+ hw = &local->hw;
+
+ /* only allow on master dev */
+ if (dev != local->mdev)
return -EINVAL;
- /* check that there is no qdisc currently attached to device
- * this ensures that we will be the root qdisc. (I can't find a better
- * way to test this explicitly) */
- if (dev->qdisc_sleeping != &noop_qdisc)
+ /* ensure that we are root qdisc */
+ if (qd->parent != TC_H_ROOT)
return -EINVAL;
if (qd->flags & TCQ_F_INGRESS)
return -EINVAL;
- local = wdev_priv(dev->ieee80211_ptr);
- queues = local->hw.queues;
-
/* if options were passed in, set them */
- if (opt) {
+ if (opt)
err = wme_qdiscop_tune(qd, opt);
- }
/* create child queues */
- for (i = 0; i < queues; i++) {
+ for (i = 0; i < QD_NUM(hw); i++) {
skb_queue_head_init(&q->requeued[i]);
q->queues[i] = qdisc_create_dflt(qd->dev, &pfifo_qdisc_ops,
qd->handle);
@@ -399,8 +378,8 @@ static int wme_qdiscop_init(struct Qdisc *qd, struct nlattr *opt)
}
}
- /* reserve all legacy QoS queues */
- for (i = 0; i < min(IEEE80211_TX_QUEUE_DATA4, queues); i++)
+ /* non-aggregation queues: reserve/mark as used */
+ for (i = 0; i < local->hw.queues; i++)
set_bit(i, q->qdisc_pool);
return err;
@@ -408,16 +387,6 @@ static int wme_qdiscop_init(struct Qdisc *qd, struct nlattr *opt)
static int wme_qdiscop_dump(struct Qdisc *qd, struct sk_buff *skb)
{
-/* struct ieee80211_sched_data *q = qdisc_priv(qd);
- unsigned char *p = skb->tail;
- struct tc_ieee80211_qopt opt;
-
- memcpy(&opt.tag2queue, q->tag2queue, TC_80211_MAX_TAG + 1);
- NLA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
-*/ return skb->len;
-/*
-nla_put_failure:
- skb_trim(skb, p - skb->data);*/
return -1;
}
@@ -430,7 +399,7 @@ static int wme_classop_graft(struct Qdisc *qd, unsigned long arg,
struct ieee80211_hw *hw = &local->hw;
unsigned long queue = arg - 1;
- if (queue >= hw->queues)
+ if (queue >= QD_NUM(hw))
return -EINVAL;
if (!new)
@@ -454,7 +423,7 @@ wme_classop_leaf(struct Qdisc *qd, unsigned long arg)
struct ieee80211_hw *hw = &local->hw;
unsigned long queue = arg - 1;
- if (queue >= hw->queues)
+ if (queue >= QD_NUM(hw))
return NULL;
return q->queues[queue];
@@ -467,7 +436,7 @@ static unsigned long wme_classop_get(struct Qdisc *qd, u32 classid)
struct ieee80211_hw *hw = &local->hw;
unsigned long queue = TC_H_MIN(classid);
- if (queue - 1 >= hw->queues)
+ if (queue - 1 >= QD_NUM(hw))
return 0;
return queue;
@@ -493,7 +462,7 @@ static int wme_classop_change(struct Qdisc *qd, u32 handle, u32 parent,
struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
struct ieee80211_hw *hw = &local->hw;
- if (cl - 1 > hw->queues)
+ if (cl - 1 > QD_NUM(hw))
return -ENOENT;
/* TODO: put code to program hardware queue parameters here,
@@ -510,7 +479,7 @@ static int wme_classop_delete(struct Qdisc *qd, unsigned long cl)
struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
struct ieee80211_hw *hw = &local->hw;
- if (cl - 1 > hw->queues)
+ if (cl - 1 > QD_NUM(hw))
return -ENOENT;
return 0;
}
@@ -523,7 +492,7 @@ static int wme_classop_dump_class(struct Qdisc *qd, unsigned long cl,
struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
struct ieee80211_hw *hw = &local->hw;
- if (cl - 1 > hw->queues)
+ if (cl - 1 > QD_NUM(hw))
return -ENOENT;
tcm->tcm_handle = TC_H_MIN(cl);
tcm->tcm_parent = qd->handle;
@@ -541,7 +510,7 @@ static void wme_classop_walk(struct Qdisc *qd, struct qdisc_walker *arg)
if (arg->stop)
return;
- for (queue = 0; queue < hw->queues; queue++) {
+ for (queue = 0; queue < QD_NUM(hw); queue++) {
if (arg->count < arg->skip) {
arg->count++;
continue;
@@ -658,10 +627,13 @@ int ieee80211_ht_agg_queue_add(struct ieee80211_local *local,
DECLARE_MAC_BUF(mac);
/* prepare the filter and save it for the SW queue
- * matching the recieved HW queue */
+ * matching the received HW queue */
+
+ if (!local->hw.ampdu_queues)
+ return -EPERM;
/* try to get a Qdisc from the pool */
- for (i = IEEE80211_TX_QUEUE_BEACON; i < local->hw.queues; i++)
+ for (i = local->hw.queues; i < QD_NUM(&local->hw); i++)
if (!test_and_set_bit(i, q->qdisc_pool)) {
ieee80211_stop_queue(local_to_hw(local), i);
sta->tid_to_tx_q[tid] = i;
@@ -690,13 +662,14 @@ void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local,
struct sta_info *sta, u16 tid,
u8 requeue)
{
+ struct ieee80211_hw *hw = &local->hw;
struct ieee80211_sched_data *q =
qdisc_priv(local->mdev->qdisc_sleeping);
int agg_queue = sta->tid_to_tx_q[tid];
/* return the qdisc to the pool */
clear_bit(agg_queue, q->qdisc_pool);
- sta->tid_to_tx_q[tid] = local->hw.queues;
+ sta->tid_to_tx_q[tid] = QD_NUM(hw);
if (requeue)
ieee80211_requeue(local, agg_queue);
diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h
index fcc6b05508cc..bbdb53344817 100644
--- a/net/mac80211/wme.h
+++ b/net/mac80211/wme.h
@@ -31,7 +31,7 @@ static inline int WLAN_FC_IS_QOS_DATA(u16 fc)
return (fc & 0x8C) == 0x88;
}
-#ifdef CONFIG_NET_SCHED
+#ifdef CONFIG_MAC80211_QOS
void ieee80211_install_qdisc(struct net_device *dev);
int ieee80211_qdisc_installed(struct net_device *dev);
int ieee80211_ht_agg_queue_add(struct ieee80211_local *local,
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index 45709ada8fee..9f6fd20374e1 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -79,6 +79,7 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
struct sk_buff *skb = tx->skb;
int authenticator;
int wpa_test = 0;
+ int tail;
fc = tx->fc;
@@ -98,16 +99,13 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
return TX_CONTINUE;
}
- if (skb_tailroom(skb) < MICHAEL_MIC_LEN) {
- I802_DEBUG_INC(tx->local->tx_expand_skb_head);
- if (unlikely(pskb_expand_head(skb, TKIP_IV_LEN,
- MICHAEL_MIC_LEN + TKIP_ICV_LEN,
- GFP_ATOMIC))) {
- printk(KERN_DEBUG "%s: failed to allocate more memory "
- "for Michael MIC\n", tx->dev->name);
- return TX_DROP;
- }
- }
+ tail = MICHAEL_MIC_LEN;
+ if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
+ tail += TKIP_ICV_LEN;
+
+ if (WARN_ON(skb_tailroom(skb) < tail ||
+ skb_headroom(skb) < TKIP_IV_LEN))
+ return TX_DROP;
#if 0
authenticator = fc & IEEE80211_FCTL_FROMDS; /* FIX */
@@ -176,59 +174,65 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
skb_trim(skb, skb->len - MICHAEL_MIC_LEN);
/* update IV in key information to be able to detect replays */
- rx->key->u.tkip.iv32_rx[rx->queue] = rx->tkip_iv32;
- rx->key->u.tkip.iv16_rx[rx->queue] = rx->tkip_iv16;
+ rx->key->u.tkip.rx[rx->queue].iv32 = rx->tkip_iv32;
+ rx->key->u.tkip.rx[rx->queue].iv16 = rx->tkip_iv16;
return RX_CONTINUE;
}
-static int tkip_encrypt_skb(struct ieee80211_tx_data *tx,
- struct sk_buff *skb, int test)
+static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_key *key = tx->key;
- int hdrlen, len, tailneed;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ int hdrlen, len, tail;
u16 fc;
u8 *pos;
+ info->control.icv_len = TKIP_ICV_LEN;
+ info->control.iv_len = TKIP_IV_LEN;
+
+ if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
+ !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
+ /* hwaccel - with no need for preallocated room for IV/ICV */
+ info->control.hw_key = &tx->key->conf;
+ return 0;
+ }
+
fc = le16_to_cpu(hdr->frame_control);
hdrlen = ieee80211_get_hdrlen(fc);
len = skb->len - hdrlen;
if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)
- tailneed = 0;
+ tail = 0;
else
- tailneed = TKIP_ICV_LEN;
-
- if ((skb_headroom(skb) < TKIP_IV_LEN ||
- skb_tailroom(skb) < tailneed)) {
- I802_DEBUG_INC(tx->local->tx_expand_skb_head);
- if (unlikely(pskb_expand_head(skb, TKIP_IV_LEN, tailneed,
- GFP_ATOMIC)))
- return -1;
- }
+ tail = TKIP_ICV_LEN;
+
+ if (WARN_ON(skb_tailroom(skb) < tail ||
+ skb_headroom(skb) < TKIP_IV_LEN))
+ return -1;
pos = skb_push(skb, TKIP_IV_LEN);
memmove(pos, pos + TKIP_IV_LEN, hdrlen);
pos += hdrlen;
/* Increase IV for the frame */
- key->u.tkip.iv16++;
- if (key->u.tkip.iv16 == 0)
- key->u.tkip.iv32++;
+ key->u.tkip.tx.iv16++;
+ if (key->u.tkip.tx.iv16 == 0)
+ key->u.tkip.tx.iv32++;
if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
hdr = (struct ieee80211_hdr *)skb->data;
/* hwaccel - with preallocated room for IV */
ieee80211_tkip_add_iv(pos, key,
- (u8) (key->u.tkip.iv16 >> 8),
- (u8) (((key->u.tkip.iv16 >> 8) | 0x20) &
+ (u8) (key->u.tkip.tx.iv16 >> 8),
+ (u8) (((key->u.tkip.tx.iv16 >> 8) | 0x20) &
0x7f),
- (u8) key->u.tkip.iv16);
+ (u8) key->u.tkip.tx.iv16);
- tx->control->key_idx = tx->key->conf.hw_key_idx;
+ info->control.hw_key = &tx->key->conf;
return 0;
}
@@ -246,28 +250,16 @@ ieee80211_tx_result
ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx)
{
struct sk_buff *skb = tx->skb;
- int wpa_test = 0, test = 0;
- tx->control->icv_len = TKIP_ICV_LEN;
- tx->control->iv_len = TKIP_IV_LEN;
ieee80211_tx_set_protected(tx);
- if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
- !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) &&
- !wpa_test) {
- /* hwaccel - with no need for preallocated room for IV/ICV */
- tx->control->key_idx = tx->key->conf.hw_key_idx;
- return TX_CONTINUE;
- }
-
- if (tkip_encrypt_skb(tx, skb, test) < 0)
+ if (tkip_encrypt_skb(tx, skb) < 0)
return TX_DROP;
if (tx->extra_frag) {
int i;
for (i = 0; i < tx->num_extra_frag; i++) {
- if (tkip_encrypt_skb(tx, tx->extra_frag[i], test)
- < 0)
+ if (tkip_encrypt_skb(tx, tx->extra_frag[i]) < 0)
return TX_DROP;
}
}
@@ -429,16 +421,27 @@ static inline int ccmp_hdr2pn(u8 *pn, u8 *hdr)
}
-static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx,
- struct sk_buff *skb, int test)
+static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_key *key = tx->key;
- int hdrlen, len, tailneed;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ int hdrlen, len, tail;
u16 fc;
u8 *pos, *pn, *b_0, *aad, *scratch;
int i;
+ info->control.icv_len = CCMP_MIC_LEN;
+ info->control.iv_len = CCMP_HDR_LEN;
+
+ if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
+ !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
+ /* hwaccel - with no need for preallocated room for CCMP "
+ * header or MIC fields */
+ info->control.hw_key = &tx->key->conf;
+ return 0;
+ }
+
scratch = key->u.ccmp.tx_crypto_buf;
b_0 = scratch + 3 * AES_BLOCK_LEN;
aad = scratch + 4 * AES_BLOCK_LEN;
@@ -448,17 +451,13 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx,
len = skb->len - hdrlen;
if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)
- tailneed = 0;
+ tail = 0;
else
- tailneed = CCMP_MIC_LEN;
-
- if ((skb_headroom(skb) < CCMP_HDR_LEN ||
- skb_tailroom(skb) < tailneed)) {
- I802_DEBUG_INC(tx->local->tx_expand_skb_head);
- if (unlikely(pskb_expand_head(skb, CCMP_HDR_LEN, tailneed,
- GFP_ATOMIC)))
- return -1;
- }
+ tail = CCMP_MIC_LEN;
+
+ if (WARN_ON(skb_tailroom(skb) < tail ||
+ skb_headroom(skb) < CCMP_HDR_LEN))
+ return -1;
pos = skb_push(skb, CCMP_HDR_LEN);
memmove(pos, pos + CCMP_HDR_LEN, hdrlen);
@@ -478,7 +477,7 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx,
if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
/* hwaccel - with preallocated room for CCMP header */
- tx->control->key_idx = key->conf.hw_key_idx;
+ info->control.hw_key = &tx->key->conf;
return 0;
}
@@ -495,28 +494,16 @@ ieee80211_tx_result
ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx)
{
struct sk_buff *skb = tx->skb;
- int test = 0;
- tx->control->icv_len = CCMP_MIC_LEN;
- tx->control->iv_len = CCMP_HDR_LEN;
ieee80211_tx_set_protected(tx);
- if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
- !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
- /* hwaccel - with no need for preallocated room for CCMP "
- * header or MIC fields */
- tx->control->key_idx = tx->key->conf.hw_key_idx;
- return TX_CONTINUE;
- }
-
- if (ccmp_encrypt_skb(tx, skb, test) < 0)
+ if (ccmp_encrypt_skb(tx, skb) < 0)
return TX_DROP;
if (tx->extra_frag) {
int i;
for (i = 0; i < tx->num_extra_frag; i++) {
- if (ccmp_encrypt_skb(tx, tx->extra_frag[i], test)
- < 0)
+ if (ccmp_encrypt_skb(tx, tx->extra_frag[i]) < 0)
return TX_DROP;
}
}
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index c4b1799da5d7..f27c99246a4c 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -196,8 +196,6 @@ destroy_conntrack(struct nf_conntrack *nfct)
if (l4proto && l4proto->destroy)
l4proto->destroy(ct);
- nf_ct_ext_destroy(ct);
-
rcu_read_unlock();
spin_lock_bh(&nf_conntrack_lock);
@@ -520,6 +518,7 @@ static void nf_conntrack_free_rcu(struct rcu_head *head)
void nf_conntrack_free(struct nf_conn *ct)
{
+ nf_ct_ext_destroy(ct);
call_rcu(&ct->rcu, nf_conntrack_free_rcu);
}
EXPORT_SYMBOL_GPL(nf_conntrack_free);
@@ -848,6 +847,25 @@ 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)
+{
+#ifdef CONFIG_NF_CT_ACCT
+ if (do_acct) {
+ spin_lock_bh(&nf_conntrack_lock);
+ ct->counters[CTINFO2DIR(ctinfo)].packets++;
+ ct->counters[CTINFO2DIR(ctinfo)].bytes +=
+ skb->len - skb_network_offset(skb);
+ spin_unlock_bh(&nf_conntrack_lock);
+ }
+#endif
+ if (del_timer(&ct->timeout))
+ ct->timeout.function((unsigned long)ct);
+}
+EXPORT_SYMBOL_GPL(__nf_ct_kill_acct);
+
#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
#include <linux/netfilter/nfnetlink.h>
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
index e31beeb33b2b..e8f0dead267f 100644
--- a/net/netfilter/nf_conntrack_expect.c
+++ b/net/netfilter/nf_conntrack_expect.c
@@ -587,10 +587,10 @@ int __init nf_conntrack_expect_init(void)
return 0;
err3:
+ kmem_cache_destroy(nf_ct_expect_cachep);
+err2:
nf_ct_free_hashtable(nf_ct_expect_hash, nf_ct_expect_vmalloc,
nf_ct_expect_hsize);
-err2:
- kmem_cache_destroy(nf_ct_expect_cachep);
err1:
return err;
}
diff --git a/net/netfilter/nf_conntrack_extend.c b/net/netfilter/nf_conntrack_extend.c
index bcc19fa4ed1e..ba1c4915e9eb 100644
--- a/net/netfilter/nf_conntrack_extend.c
+++ b/net/netfilter/nf_conntrack_extend.c
@@ -88,13 +88,11 @@ void *__nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp)
newlen = newoff + t->len;
rcu_read_unlock();
- if (newlen >= ksize(ct->ext)) {
- new = kmalloc(newlen, gfp);
- if (!new)
- return NULL;
-
- memcpy(new, ct->ext, ct->ext->len);
+ new = krealloc(ct->ext, newlen, gfp);
+ if (!new)
+ return NULL;
+ if (new != ct->ext) {
for (i = 0; i < NF_CT_EXT_NUM; i++) {
if (!nf_ct_ext_exist(ct, i))
continue;
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
index 7d1b11703741..8e0b4c8f62a8 100644
--- a/net/netfilter/nf_conntrack_helper.c
+++ b/net/netfilter/nf_conntrack_helper.c
@@ -20,6 +20,7 @@
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
+#include <linux/rculist.h>
#include <net/netfilter/nf_conntrack.h>
#include <net/netfilter/nf_conntrack_l3proto.h>
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 0edefcfc5949..6926061542b4 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -4,7 +4,7 @@
* (C) 2001 by Jay Schulist <jschlst@samba.org>
* (C) 2002-2006 by Harald Welte <laforge@gnumonks.org>
* (C) 2003 by Patrick Mchardy <kaber@trash.net>
- * (C) 2005-2007 by Pablo Neira Ayuso <pablo@netfilter.org>
+ * (C) 2005-2008 by Pablo Neira Ayuso <pablo@netfilter.org>
*
* Initial connection tracking via netlink development funded and
* generally made possible by Network Robots, Inc. (www.networkrobots.com)
@@ -18,6 +18,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/rculist.h>
#include <linux/types.h>
#include <linux/timer.h>
#include <linux/skbuff.h>
@@ -475,14 +476,14 @@ static int ctnetlink_conntrack_event(struct notifier_block *this,
if (ctnetlink_dump_id(skb, ct) < 0)
goto nla_put_failure;
+ if (ctnetlink_dump_status(skb, ct) < 0)
+ goto nla_put_failure;
+
if (events & IPCT_DESTROY) {
if (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 ||
ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0)
goto nla_put_failure;
} else {
- if (ctnetlink_dump_status(skb, ct) < 0)
- goto nla_put_failure;
-
if (ctnetlink_dump_timeout(skb, ct) < 0)
goto nla_put_failure;
@@ -812,9 +813,8 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
return -ENOENT;
}
}
- if (del_timer(&ct->timeout))
- ct->timeout.function((unsigned long)ct);
+ nf_ct_kill(ct);
nf_ct_put(ct);
return 0;
@@ -891,20 +891,19 @@ ctnetlink_change_status(struct nf_conn *ct, struct nlattr *cda[])
if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING))
/* unchangeable */
- return -EINVAL;
+ return -EBUSY;
if (d & IPS_SEEN_REPLY && !(status & IPS_SEEN_REPLY))
/* SEEN_REPLY bit can only be set */
- return -EINVAL;
-
+ return -EBUSY;
if (d & IPS_ASSURED && !(status & IPS_ASSURED))
/* ASSURED bit can only be set */
- return -EINVAL;
+ return -EBUSY;
if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) {
#ifndef CONFIG_NF_NAT_NEEDED
- return -EINVAL;
+ return -EOPNOTSUPP;
#else
struct nf_nat_range range;
@@ -945,7 +944,7 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nlattr *cda[])
/* don't change helper of sibling connections */
if (ct->master)
- return -EINVAL;
+ return -EBUSY;
err = ctnetlink_parse_help(cda[CTA_HELP], &helpname);
if (err < 0)
@@ -963,7 +962,7 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nlattr *cda[])
helper = __nf_conntrack_helper_find_byname(helpname);
if (helper == NULL)
- return -EINVAL;
+ return -EOPNOTSUPP;
if (help) {
if (help->helper == helper)
@@ -1258,12 +1257,12 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
if (!(nlh->nlmsg_flags & NLM_F_EXCL)) {
/* we only allow nat config for new conntracks */
if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) {
- err = -EINVAL;
+ err = -EOPNOTSUPP;
goto out_unlock;
}
/* can't link an existing conntrack to a master */
if (cda[CTA_TUPLE_MASTER]) {
- err = -EINVAL;
+ err = -EOPNOTSUPP;
goto out_unlock;
}
err = ctnetlink_change_conntrack(nf_ct_tuplehash_to_ctrack(h),
@@ -1608,7 +1607,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
h = __nf_conntrack_helper_find_byname(name);
if (!h) {
spin_unlock_bh(&nf_conntrack_lock);
- return -EINVAL;
+ return -EOPNOTSUPP;
}
for (i = 0; i < nf_ct_expect_hsize; i++) {
hlist_for_each_entry_safe(exp, n, next,
diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c
index afb4a1861d2c..e7866dd3cde6 100644
--- a/net/netfilter/nf_conntrack_proto_dccp.c
+++ b/net/netfilter/nf_conntrack_proto_dccp.c
@@ -475,8 +475,7 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb,
if (type == DCCP_PKT_RESET &&
!test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
/* Tear down connection immediately if only reply is a RESET */
- if (del_timer(&ct->timeout))
- ct->timeout.function((unsigned long)ct);
+ nf_ct_kill_acct(ct, ctinfo, skb);
return NF_ACCEPT;
}
diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c
index cbf2e27a22b2..41183a4d2d62 100644
--- a/net/netfilter/nf_conntrack_proto_sctp.c
+++ b/net/netfilter/nf_conntrack_proto_sctp.c
@@ -463,6 +463,82 @@ static bool sctp_new(struct nf_conn *ct, const struct sk_buff *skb,
return true;
}
+#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
+
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nfnetlink_conntrack.h>
+
+static int sctp_to_nlattr(struct sk_buff *skb, struct nlattr *nla,
+ const struct nf_conn *ct)
+{
+ struct nlattr *nest_parms;
+
+ read_lock_bh(&sctp_lock);
+ nest_parms = nla_nest_start(skb, CTA_PROTOINFO_SCTP | NLA_F_NESTED);
+ if (!nest_parms)
+ goto nla_put_failure;
+
+ NLA_PUT_U8(skb, CTA_PROTOINFO_SCTP_STATE, ct->proto.sctp.state);
+
+ NLA_PUT_BE32(skb,
+ CTA_PROTOINFO_SCTP_VTAG_ORIGINAL,
+ htonl(ct->proto.sctp.vtag[IP_CT_DIR_ORIGINAL]));
+
+ NLA_PUT_BE32(skb,
+ CTA_PROTOINFO_SCTP_VTAG_REPLY,
+ htonl(ct->proto.sctp.vtag[IP_CT_DIR_REPLY]));
+
+ read_unlock_bh(&sctp_lock);
+
+ nla_nest_end(skb, nest_parms);
+
+ return 0;
+
+nla_put_failure:
+ read_unlock_bh(&sctp_lock);
+ return -1;
+}
+
+static const struct nla_policy sctp_nla_policy[CTA_PROTOINFO_SCTP_MAX+1] = {
+ [CTA_PROTOINFO_SCTP_STATE] = { .type = NLA_U8 },
+ [CTA_PROTOINFO_SCTP_VTAG_ORIGINAL] = { .type = NLA_U32 },
+ [CTA_PROTOINFO_SCTP_VTAG_REPLY] = { .type = NLA_U32 },
+};
+
+static int nlattr_to_sctp(struct nlattr *cda[], struct nf_conn *ct)
+{
+ struct nlattr *attr = cda[CTA_PROTOINFO_SCTP];
+ struct nlattr *tb[CTA_PROTOINFO_SCTP_MAX+1];
+ int err;
+
+ /* updates may not contain the internal protocol info, skip parsing */
+ if (!attr)
+ return 0;
+
+ err = nla_parse_nested(tb,
+ CTA_PROTOINFO_SCTP_MAX,
+ attr,
+ sctp_nla_policy);
+ if (err < 0)
+ return err;
+
+ if (!tb[CTA_PROTOINFO_SCTP_STATE] ||
+ !tb[CTA_PROTOINFO_SCTP_VTAG_ORIGINAL] ||
+ !tb[CTA_PROTOINFO_SCTP_VTAG_REPLY])
+ return -EINVAL;
+
+ write_lock_bh(&sctp_lock);
+ ct->proto.sctp.state = nla_get_u8(tb[CTA_PROTOINFO_SCTP_STATE]);
+ ct->proto.sctp.vtag[IP_CT_DIR_ORIGINAL] =
+ ntohl(nla_get_be32(tb[CTA_PROTOINFO_SCTP_VTAG_ORIGINAL]));
+ ct->proto.sctp.vtag[IP_CT_DIR_REPLY] =
+ ntohl(nla_get_be32(tb[CTA_PROTOINFO_SCTP_VTAG_REPLY]));
+ write_unlock_bh(&sctp_lock);
+
+ return 0;
+}
+#endif
+
#ifdef CONFIG_SYSCTL
static unsigned int sctp_sysctl_table_users;
static struct ctl_table_header *sctp_sysctl_header;
@@ -591,6 +667,8 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 __read_mostly = {
.new = sctp_new,
.me = THIS_MODULE,
#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
+ .to_nlattr = sctp_to_nlattr,
+ .from_nlattr = nlattr_to_sctp,
.tuple_to_nlattr = nf_ct_port_tuple_to_nlattr,
.nlattr_to_tuple = nf_ct_port_nlattr_to_tuple,
.nla_policy = nf_ct_port_nla_policy,
@@ -617,6 +695,8 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 __read_mostly = {
.new = sctp_new,
.me = THIS_MODULE,
#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
+ .to_nlattr = sctp_to_nlattr,
+ .from_nlattr = nlattr_to_sctp,
.tuple_to_nlattr = nf_ct_port_tuple_to_nlattr,
.nlattr_to_tuple = nf_ct_port_nlattr_to_tuple,
.nla_policy = nf_ct_port_nla_policy,
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index ba94004fe323..8db13fba10bc 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -843,8 +843,7 @@ 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);
- if (del_timer(&ct->timeout))
- ct->timeout.function((unsigned long)ct);
+ nf_ct_kill(ct);
return -NF_REPEAT;
}
/* Fall through */
@@ -877,8 +876,7 @@ static int tcp_packet(struct nf_conn *ct,
if (LOG_INVALID(IPPROTO_TCP))
nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
"nf_ct_tcp: killing out of sync session ");
- if (del_timer(&ct->timeout))
- ct->timeout.function((unsigned long)ct);
+ nf_ct_kill(ct);
return -NF_DROP;
}
ct->proto.tcp.last_index = index;
@@ -961,8 +959,7 @@ static int tcp_packet(struct nf_conn *ct,
problem case, so we can delete the conntrack
immediately. --RR */
if (th->rst) {
- if (del_timer(&ct->timeout))
- ct->timeout.function((unsigned long)ct);
+ nf_ct_kill_acct(ct, ctinfo, skb);
return NF_ACCEPT;
}
} else if (!test_bit(IPS_ASSURED_BIT, &ct->status)
diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c
index bc11d7092032..9fda6ee95a31 100644
--- a/net/netfilter/nf_log.c
+++ b/net/netfilter/nf_log.c
@@ -92,10 +92,6 @@ void nf_log_packet(int pf,
vsnprintf(prefix, sizeof(prefix), fmt, args);
va_end(args);
logger->logfn(pf, hooknum, skb, in, out, loginfo, prefix);
- } else if (net_ratelimit()) {
- printk(KERN_WARNING "nf_log_packet: can\'t log since "
- "no backend logging module loaded in! Please either "
- "load one, or disable logging explicitly\n");
}
rcu_read_unlock();
}
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index 3447025ce068..04e9c965f8ca 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -243,7 +243,6 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
switch ((enum nfqnl_config_mode)queue->copy_mode) {
case NFQNL_COPY_META:
case NFQNL_COPY_NONE:
- data_len = 0;
break;
case NFQNL_COPY_PACKET:
diff --git a/net/netfilter/xt_CONNSECMARK.c b/net/netfilter/xt_CONNSECMARK.c
index 211189eb2b67..76ca1f2421eb 100644
--- a/net/netfilter/xt_CONNSECMARK.c
+++ b/net/netfilter/xt_CONNSECMARK.c
@@ -8,7 +8,7 @@
* Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
* by Henrik Nordstrom <hno@marasystems.com>
*
- * (C) 2006 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ * (C) 2006,2008 Red Hat, Inc., James Morris <jmorris@redhat.com>
*
* 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
@@ -94,6 +94,12 @@ connsecmark_tg_check(const char *tablename, const void *entry,
{
const struct xt_connsecmark_target_info *info = targinfo;
+ if (strcmp(tablename, "mangle") && strcmp(tablename, "security")) {
+ printk(KERN_INFO PFX "target only valid in the \'mangle\' "
+ "or \'security\' tables, not \'%s\'.\n", tablename);
+ return false;
+ }
+
switch (info->mode) {
case CONNSECMARK_SAVE:
case CONNSECMARK_RESTORE:
@@ -126,7 +132,6 @@ static struct xt_target connsecmark_tg_reg[] __read_mostly = {
.destroy = connsecmark_tg_destroy,
.target = connsecmark_tg,
.targetsize = sizeof(struct xt_connsecmark_target_info),
- .table = "mangle",
.me = THIS_MODULE,
},
{
@@ -136,7 +141,6 @@ static struct xt_target connsecmark_tg_reg[] __read_mostly = {
.destroy = connsecmark_tg_destroy,
.target = connsecmark_tg,
.targetsize = sizeof(struct xt_connsecmark_target_info),
- .table = "mangle",
.me = THIS_MODULE,
},
};
diff --git a/net/netfilter/xt_SECMARK.c b/net/netfilter/xt_SECMARK.c
index c0284856ccd4..94f87ee7552b 100644
--- a/net/netfilter/xt_SECMARK.c
+++ b/net/netfilter/xt_SECMARK.c
@@ -5,7 +5,7 @@
* Based on the nfmark match by:
* (C) 1999-2001 Marc Boucher <marc@mbsi.ca>
*
- * (C) 2006 Red Hat, Inc., James Morris <jmorris@redhat.com>
+ * (C) 2006,2008 Red Hat, Inc., James Morris <jmorris@redhat.com>
*
* 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
@@ -89,6 +89,12 @@ secmark_tg_check(const char *tablename, const void *entry,
{
struct xt_secmark_target_info *info = targinfo;
+ if (strcmp(tablename, "mangle") && strcmp(tablename, "security")) {
+ printk(KERN_INFO PFX "target only valid in the \'mangle\' "
+ "or \'security\' tables, not \'%s\'.\n", tablename);
+ return false;
+ }
+
if (mode && mode != info->mode) {
printk(KERN_INFO PFX "mode already set to %hu cannot mix with "
"rules for mode %hu\n", mode, info->mode);
@@ -127,7 +133,6 @@ static struct xt_target secmark_tg_reg[] __read_mostly = {
.destroy = secmark_tg_destroy,
.target = secmark_tg,
.targetsize = sizeof(struct xt_secmark_target_info),
- .table = "mangle",
.me = THIS_MODULE,
},
{
@@ -137,7 +142,6 @@ static struct xt_target secmark_tg_reg[] __read_mostly = {
.destroy = secmark_tg_destroy,
.target = secmark_tg,
.targetsize = sizeof(struct xt_secmark_target_info),
- .table = "mangle",
.me = THIS_MODULE,
},
};
diff --git a/net/netfilter/xt_connlimit.c b/net/netfilter/xt_connlimit.c
index 2e89a00df92c..70907f6baac3 100644
--- a/net/netfilter/xt_connlimit.c
+++ b/net/netfilter/xt_connlimit.c
@@ -73,7 +73,8 @@ connlimit_iphash6(const union nf_inet_addr *addr,
static inline bool already_closed(const struct nf_conn *conn)
{
if (nf_ct_protonum(conn) == IPPROTO_TCP)
- return conn->proto.tcp.state == TCP_CONNTRACK_TIME_WAIT;
+ return conn->proto.tcp.state == TCP_CONNTRACK_TIME_WAIT ||
+ conn->proto.tcp.state == TCP_CONNTRACK_CLOSE;
else
return 0;
}
diff --git a/net/netlabel/netlabel_domainhash.c b/net/netlabel/netlabel_domainhash.c
index 02c2f7c0b255..643c032a3a57 100644
--- a/net/netlabel/netlabel_domainhash.c
+++ b/net/netlabel/netlabel_domainhash.c
@@ -30,8 +30,7 @@
*/
#include <linux/types.h>
-#include <linux/rcupdate.h>
-#include <linux/list.h>
+#include <linux/rculist.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/string.h>
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 9b97f8006c9c..6507c02dbe0d 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -759,7 +759,7 @@ struct sock *netlink_getsockbyfilp(struct file *filp)
* 0: continue
* 1: repeat lookup - reference dropped while waiting for socket memory.
*/
-int netlink_attachskb(struct sock *sk, struct sk_buff *skb, int nonblock,
+int netlink_attachskb(struct sock *sk, struct sk_buff *skb,
long *timeo, struct sock *ssk)
{
struct netlink_sock *nlk;
@@ -892,7 +892,7 @@ retry:
return err;
}
- err = netlink_attachskb(sk, skb, nonblock, &timeo, ssk);
+ err = netlink_attachskb(sk, skb, &timeo, ssk);
if (err == 1)
goto retry;
if (err)
diff --git a/net/netlink/attr.c b/net/netlink/attr.c
index feb326f4a752..47bbf45ae5d7 100644
--- a/net/netlink/attr.c
+++ b/net/netlink/attr.c
@@ -400,13 +400,13 @@ void __nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data)
* @attrlen: length of attribute payload
* @data: head of attribute payload
*
- * Returns -1 if the tailroom of the skb is insufficient to store
+ * Returns -EMSGSIZE if the tailroom of the skb is insufficient to store
* the attribute header and payload.
*/
int nla_put(struct sk_buff *skb, int attrtype, int attrlen, const void *data)
{
if (unlikely(skb_tailroom(skb) < nla_total_size(attrlen)))
- return -1;
+ return -EMSGSIZE;
__nla_put(skb, attrtype, attrlen, data);
return 0;
@@ -418,13 +418,13 @@ int nla_put(struct sk_buff *skb, int attrtype, int attrlen, const void *data)
* @attrlen: length of attribute payload
* @data: head of attribute payload
*
- * Returns -1 if the tailroom of the skb is insufficient to store
+ * Returns -EMSGSIZE if the tailroom of the skb is insufficient to store
* the attribute payload.
*/
int nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data)
{
if (unlikely(skb_tailroom(skb) < NLA_ALIGN(attrlen)))
- return -1;
+ return -EMSGSIZE;
__nla_put_nohdr(skb, attrlen, data);
return 0;
@@ -436,13 +436,13 @@ int nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data)
* @attrlen: length of attribute payload
* @data: head of attribute payload
*
- * Returns -1 if the tailroom of the skb is insufficient to store
+ * Returns -EMSGSIZE if the tailroom of the skb is insufficient to store
* the attribute payload.
*/
int nla_append(struct sk_buff *skb, int attrlen, const void *data)
{
if (unlikely(skb_tailroom(skb) < NLA_ALIGN(attrlen)))
- return -1;
+ return -EMSGSIZE;
memcpy(skb_put(skb, attrlen), data, attrlen);
return 0;
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index d16929c9b4bc..f5aa23c3e886 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -554,7 +554,8 @@ static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq,
return genlmsg_end(skb, hdr);
nla_put_failure:
- return genlmsg_cancel(skb, hdr);
+ genlmsg_cancel(skb, hdr);
+ return -EMSGSIZE;
}
static int ctrl_fill_mcgrp_info(struct genl_multicast_group *grp, u32 pid,
@@ -590,7 +591,8 @@ static int ctrl_fill_mcgrp_info(struct genl_multicast_group *grp, u32 pid,
return genlmsg_end(skb, hdr);
nla_put_failure:
- return genlmsg_cancel(skb, hdr);
+ genlmsg_cancel(skb, hdr);
+ return -EMSGSIZE;
}
static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb)
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 2cee87da4441..beca6402f1cf 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -5,8 +5,6 @@
*
* PACKET - implements raw packet sockets.
*
- * Version: $Id: af_packet.c,v 1.61 2002/02/08 03:57:19 davem Exp $
- *
* Authors: Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Alan Cox, <gw4pts@gw4pts.ampr.org>
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 1086df7478bc..9360fc81e8c7 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -220,7 +220,7 @@ replay:
tp = kzalloc(sizeof(*tp), GFP_KERNEL);
if (tp == NULL)
goto errout;
- err = -EINVAL;
+ err = -ENOENT;
tp_ops = tcf_proto_lookup_ops(tca[TCA_KIND]);
if (tp_ops == NULL) {
#ifdef CONFIG_KMOD
diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c
index 0df911fd67b1..64465bacbe79 100644
--- a/net/sched/sch_dsmark.c
+++ b/net/sched/sch_dsmark.c
@@ -444,7 +444,8 @@ static int dsmark_dump_class(struct Qdisc *sch, unsigned long cl,
return nla_nest_end(skb, opts);
nla_put_failure:
- return nla_nest_cancel(skb, opts);
+ nla_nest_cancel(skb, opts);
+ return -EMSGSIZE;
}
static int dsmark_dump(struct Qdisc *sch, struct sk_buff *skb)
@@ -466,7 +467,8 @@ static int dsmark_dump(struct Qdisc *sch, struct sk_buff *skb)
return nla_nest_end(skb, opts);
nla_put_failure:
- return nla_nest_cancel(skb, opts);
+ nla_nest_cancel(skb, opts);
+ return -EMSGSIZE;
}
static const struct Qdisc_class_ops dsmark_class_ops = {
diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c
index 3a9d226ff1e4..c89fba56db56 100644
--- a/net/sched/sch_gred.c
+++ b/net/sched/sch_gred.c
@@ -582,7 +582,8 @@ append_opt:
return nla_nest_end(skb, opts);
nla_put_failure:
- return nla_nest_cancel(skb, opts);
+ nla_nest_cancel(skb, opts);
+ return -EMSGSIZE;
}
static void gred_destroy(struct Qdisc *sch)
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
index 87293d0db1d7..fdfaa3fcc16d 100644
--- a/net/sched/sch_hfsc.c
+++ b/net/sched/sch_hfsc.c
@@ -1360,7 +1360,7 @@ hfsc_dump_class(struct Qdisc *sch, unsigned long arg, struct sk_buff *skb,
nla_put_failure:
nla_nest_cancel(skb, nest);
- return -1;
+ return -EMSGSIZE;
}
static int
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 5bc1ed490180..213071859030 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -24,8 +24,6 @@
* Jiri Fojtasek
* fixed requeue routine
* and many others. thanks.
- *
- * $Id: sch_htb.c,v 1.25 2003/12/07 11:08:25 devik Exp devik $
*/
#include <linux/module.h>
#include <linux/types.h>
diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c
index 3dcd493f4f4a..5c569853b9c0 100644
--- a/net/sched/sch_red.c
+++ b/net/sched/sch_red.c
@@ -281,7 +281,8 @@ static int red_dump(struct Qdisc *sch, struct sk_buff *skb)
return nla_nest_end(skb, opts);
nla_put_failure:
- return nla_nest_cancel(skb, opts);
+ nla_nest_cancel(skb, opts);
+ return -EMSGSIZE;
}
static int red_dump_stats(struct Qdisc *sch, struct gnet_dump *d)
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index b4cd2b71953f..d5cc731b6798 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -136,6 +136,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
/* Set association default SACK delay */
asoc->sackdelay = msecs_to_jiffies(sp->sackdelay);
+ asoc->sackfreq = sp->sackfreq;
/* Set the association default flags controlling
* Heartbeat, SACK delay, and Path MTU Discovery.
@@ -261,6 +262,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
* already received one packet.]
*/
asoc->peer.sack_needed = 1;
+ asoc->peer.sack_cnt = 0;
/* Assume that the peer will tell us if he recognizes ASCONF
* as part of INIT exchange.
@@ -615,6 +617,7 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
* association configured value.
*/
peer->sackdelay = asoc->sackdelay;
+ peer->sackfreq = asoc->sackfreq;
/* Enable/disable heartbeat, SACK delay, and path MTU discovery
* based on association setting.
@@ -1203,6 +1206,9 @@ void sctp_assoc_update_retran_path(struct sctp_association *asoc)
struct list_head *head = &asoc->peer.transport_addr_list;
struct list_head *pos;
+ if (asoc->peer.transport_count == 1)
+ return;
+
/* Find the next transport in a round-robin fashion. */
t = asoc->peer.retran_path;
pos = &t->transports;
@@ -1217,6 +1223,15 @@ void sctp_assoc_update_retran_path(struct sctp_association *asoc)
t = list_entry(pos, struct sctp_transport, transports);
+ /* We have exhausted the list, but didn't find any
+ * other active transports. If so, use the next
+ * transport.
+ */
+ if (t == asoc->peer.retran_path) {
+ t = next;
+ break;
+ }
+
/* Try to find an active transport. */
if ((t->state == SCTP_ACTIVE) ||
@@ -1229,15 +1244,6 @@ void sctp_assoc_update_retran_path(struct sctp_association *asoc)
if (!next)
next = t;
}
-
- /* We have exhausted the list, but didn't find any
- * other active transports. If so, use the next
- * transport.
- */
- if (t == asoc->peer.retran_path) {
- t = next;
- break;
- }
}
asoc->peer.retran_path = t;
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index e45e44c60635..a2f4d4d51593 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -299,7 +299,8 @@ static inline int sctp_v6_addr_match_len(union sctp_addr *s1,
/* Fills in the source address(saddr) based on the destination address(daddr)
* and asoc's bind address list.
*/
-static void sctp_v6_get_saddr(struct sctp_association *asoc,
+static void sctp_v6_get_saddr(struct sctp_sock *sk,
+ struct sctp_association *asoc,
struct dst_entry *dst,
union sctp_addr *daddr,
union sctp_addr *saddr)
@@ -318,7 +319,7 @@ static void sctp_v6_get_saddr(struct sctp_association *asoc,
if (!asoc) {
ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL,
&daddr->v6.sin6_addr,
- inet6_sk(asoc->base.sk)->srcprefs,
+ inet6_sk(&sk->inet.sk)->srcprefs,
&saddr->v6.sin6_addr);
SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: " NIP6_FMT "\n",
NIP6(saddr->v6.sin6_addr));
@@ -726,6 +727,11 @@ static void sctp_v6_seq_dump_addr(struct seq_file *seq, union sctp_addr *addr)
seq_printf(seq, NIP6_FMT " ", NIP6(addr->v6.sin6_addr));
}
+static void sctp_v6_ecn_capable(struct sock *sk)
+{
+ inet6_sk(sk)->tclass |= INET_ECN_ECT_0;
+}
+
/* Initialize a PF_INET6 socket msg_name. */
static void sctp_inet6_msgname(char *msgname, int *addr_len)
{
@@ -996,6 +1002,7 @@ static struct sctp_af sctp_af_inet6 = {
.skb_iif = sctp_v6_skb_iif,
.is_ce = sctp_v6_is_ce,
.seq_dump_addr = sctp_v6_seq_dump_addr,
+ .ecn_capable = sctp_v6_ecn_capable,
.net_header_len = sizeof(struct ipv6hdr),
.sockaddr_len = sizeof(struct sockaddr_in6),
#ifdef CONFIG_COMPAT
diff --git a/net/sctp/output.c b/net/sctp/output.c
index cf4f9fb6819d..6d45bae93b46 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -548,7 +548,7 @@ int sctp_packet_transmit(struct sctp_packet *packet)
* Note: The works for IPv6 layer checks this bit too later
* in transmission. See IP6_ECN_flow_xmit().
*/
- INET_ECN_xmit(nskb->sk);
+ (*tp->af_specific->ecn_capable)(nskb->sk);
/* Set up the IP options. */
/* BUG: not implemented
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index 59edfd25a19c..ace6770e9048 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -208,6 +208,7 @@ void sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q)
INIT_LIST_HEAD(&q->sacked);
INIT_LIST_HEAD(&q->abandoned);
+ q->fast_rtx = 0;
q->outstanding_bytes = 0;
q->empty = 1;
q->cork = 0;
@@ -500,6 +501,7 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
case SCTP_RTXR_FAST_RTX:
SCTP_INC_STATS(SCTP_MIB_FAST_RETRANSMITS);
sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_FAST_RTX);
+ q->fast_rtx = 1;
break;
case SCTP_RTXR_PMTUD:
SCTP_INC_STATS(SCTP_MIB_PMTUD_RETRANSMITS);
@@ -518,9 +520,15 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
* the sender SHOULD try to advance the "Advanced.Peer.Ack.Point" by
* following the procedures outlined in C1 - C5.
*/
- sctp_generate_fwdtsn(q, q->asoc->ctsn_ack_point);
+ if (reason == SCTP_RTXR_T3_RTX)
+ sctp_generate_fwdtsn(q, q->asoc->ctsn_ack_point);
- error = sctp_outq_flush(q, /* rtx_timeout */ 1);
+ /* Flush the queues only on timeout, since fast_rtx is only
+ * triggered during sack processing and the queue
+ * will be flushed at the end.
+ */
+ if (reason != SCTP_RTXR_FAST_RTX)
+ error = sctp_outq_flush(q, /* rtx_timeout */ 1);
if (error)
q->asoc->base.sk->sk_err = -error;
@@ -538,17 +546,23 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
int rtx_timeout, int *start_timer)
{
struct list_head *lqueue;
- struct list_head *lchunk;
struct sctp_transport *transport = pkt->transport;
sctp_xmit_t status;
struct sctp_chunk *chunk, *chunk1;
struct sctp_association *asoc;
+ int fast_rtx;
int error = 0;
+ int timer = 0;
+ int done = 0;
asoc = q->asoc;
lqueue = &q->retransmit;
+ fast_rtx = q->fast_rtx;
- /* RFC 2960 6.3.3 Handle T3-rtx Expiration
+ /* This loop handles time-out retransmissions, fast retransmissions,
+ * and retransmissions due to opening of whindow.
+ *
+ * RFC 2960 6.3.3 Handle T3-rtx Expiration
*
* E3) Determine how many of the earliest (i.e., lowest TSN)
* outstanding DATA chunks for the address for which the
@@ -563,12 +577,12 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
* [Just to be painfully clear, if we are retransmitting
* because a timeout just happened, we should send only ONE
* packet of retransmitted data.]
+ *
+ * For fast retransmissions we also send only ONE packet. However,
+ * if we are just flushing the queue due to open window, we'll
+ * try to send as much as possible.
*/
- lchunk = sctp_list_dequeue(lqueue);
-
- while (lchunk) {
- chunk = list_entry(lchunk, struct sctp_chunk,
- transmitted_list);
+ list_for_each_entry_safe(chunk, chunk1, lqueue, transmitted_list) {
/* Make sure that Gap Acked TSNs are not retransmitted. A
* simple approach is just to move such TSNs out of the
@@ -576,58 +590,60 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
* next chunk.
*/
if (chunk->tsn_gap_acked) {
- list_add_tail(lchunk, &transport->transmitted);
- lchunk = sctp_list_dequeue(lqueue);
+ list_del(&chunk->transmitted_list);
+ list_add_tail(&chunk->transmitted_list,
+ &transport->transmitted);
continue;
}
+ /* If we are doing fast retransmit, ignore non-fast_rtransmit
+ * chunks
+ */
+ if (fast_rtx && !chunk->fast_retransmit)
+ continue;
+
/* Attempt to append this chunk to the packet. */
status = sctp_packet_append_chunk(pkt, chunk);
switch (status) {
case SCTP_XMIT_PMTU_FULL:
/* Send this packet. */
- if ((error = sctp_packet_transmit(pkt)) == 0)
- *start_timer = 1;
+ error = sctp_packet_transmit(pkt);
/* If we are retransmitting, we should only
* send a single packet.
*/
- if (rtx_timeout) {
- list_add(lchunk, lqueue);
- lchunk = NULL;
- }
+ if (rtx_timeout || fast_rtx)
+ done = 1;
- /* Bundle lchunk in the next round. */
+ /* Bundle next chunk in the next round. */
break;
case SCTP_XMIT_RWND_FULL:
/* Send this packet. */
- if ((error = sctp_packet_transmit(pkt)) == 0)
- *start_timer = 1;
+ error = sctp_packet_transmit(pkt);
/* Stop sending DATA as there is no more room
* at the receiver.
*/
- list_add(lchunk, lqueue);
- lchunk = NULL;
+ done = 1;
break;
case SCTP_XMIT_NAGLE_DELAY:
/* Send this packet. */
- if ((error = sctp_packet_transmit(pkt)) == 0)
- *start_timer = 1;
+ error = sctp_packet_transmit(pkt);
/* Stop sending DATA because of nagle delay. */
- list_add(lchunk, lqueue);
- lchunk = NULL;
+ done = 1;
break;
default:
/* The append was successful, so add this chunk to
* the transmitted list.
*/
- list_add_tail(lchunk, &transport->transmitted);
+ list_del(&chunk->transmitted_list);
+ list_add_tail(&chunk->transmitted_list,
+ &transport->transmitted);
/* Mark the chunk as ineligible for fast retransmit
* after it is retransmitted.
@@ -635,27 +651,44 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
if (chunk->fast_retransmit > 0)
chunk->fast_retransmit = -1;
- *start_timer = 1;
- q->empty = 0;
+ /* Force start T3-rtx timer when fast retransmitting
+ * the earliest outstanding TSN
+ */
+ if (!timer && fast_rtx &&
+ ntohl(chunk->subh.data_hdr->tsn) ==
+ asoc->ctsn_ack_point + 1)
+ timer = 2;
- /* Retrieve a new chunk to bundle. */
- lchunk = sctp_list_dequeue(lqueue);
+ q->empty = 0;
break;
}
- /* If we are here due to a retransmit timeout or a fast
- * retransmit and if there are any chunks left in the retransmit
- * queue that could not fit in the PMTU sized packet, they need
- * to be marked as ineligible for a subsequent fast retransmit.
- */
- if (rtx_timeout && !lchunk) {
- list_for_each_entry(chunk1, lqueue, transmitted_list) {
- if (chunk1->fast_retransmit > 0)
- chunk1->fast_retransmit = -1;
- }
+ /* Set the timer if there were no errors */
+ if (!error && !timer)
+ timer = 1;
+
+ if (done)
+ break;
+ }
+
+ /* If we are here due to a retransmit timeout or a fast
+ * retransmit and if there are any chunks left in the retransmit
+ * queue that could not fit in the PMTU sized packet, they need
+ * to be marked as ineligible for a subsequent fast retransmit.
+ */
+ if (rtx_timeout || fast_rtx) {
+ list_for_each_entry(chunk1, lqueue, transmitted_list) {
+ if (chunk1->fast_retransmit > 0)
+ chunk1->fast_retransmit = -1;
}
}
+ *start_timer = timer;
+
+ /* Clear fast retransmit hint */
+ if (fast_rtx)
+ q->fast_rtx = 0;
+
return error;
}
@@ -862,7 +895,8 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
rtx_timeout, &start_timer);
if (start_timer)
- sctp_transport_reset_timers(transport);
+ sctp_transport_reset_timers(transport,
+ start_timer-1);
/* This can happen on COOKIE-ECHO resend. Only
* one chunk can get bundled with a COOKIE-ECHO.
@@ -977,7 +1011,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
list_add_tail(&chunk->transmitted_list,
&transport->transmitted);
- sctp_transport_reset_timers(transport);
+ sctp_transport_reset_timers(transport, start_timer-1);
q->empty = 0;
diff --git a/net/sctp/proc.c b/net/sctp/proc.c
index 0aba759cb9b7..5dd89831eceb 100644
--- a/net/sctp/proc.c
+++ b/net/sctp/proc.c
@@ -383,3 +383,144 @@ void sctp_assocs_proc_exit(void)
{
remove_proc_entry("assocs", proc_net_sctp);
}
+
+static void *sctp_remaddr_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ if (*pos >= sctp_assoc_hashsize)
+ return NULL;
+
+ if (*pos < 0)
+ *pos = 0;
+
+ if (*pos == 0)
+ seq_printf(seq, "ADDR ASSOC_ID HB_ACT RTO MAX_PATH_RTX "
+ "REM_ADDR_RTX START\n");
+
+ return (void *)pos;
+}
+
+static void *sctp_remaddr_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ if (++*pos >= sctp_assoc_hashsize)
+ return NULL;
+
+ return pos;
+}
+
+static void sctp_remaddr_seq_stop(struct seq_file *seq, void *v)
+{
+ return;
+}
+
+static int sctp_remaddr_seq_show(struct seq_file *seq, void *v)
+{
+ struct sctp_hashbucket *head;
+ struct sctp_ep_common *epb;
+ struct sctp_association *assoc;
+ struct hlist_node *node;
+ struct sctp_transport *tsp;
+ int hash = *(loff_t *)v;
+
+ if (hash >= sctp_assoc_hashsize)
+ return -ENOMEM;
+
+ head = &sctp_assoc_hashtable[hash];
+ sctp_local_bh_disable();
+ read_lock(&head->lock);
+ sctp_for_each_hentry(epb, node, &head->chain) {
+ assoc = sctp_assoc(epb);
+ list_for_each_entry(tsp, &assoc->peer.transport_addr_list,
+ transports) {
+ /*
+ * The remote address (ADDR)
+ */
+ tsp->af_specific->seq_dump_addr(seq, &tsp->ipaddr);
+ seq_printf(seq, " ");
+
+ /*
+ * The association ID (ASSOC_ID)
+ */
+ seq_printf(seq, "%d ", tsp->asoc->assoc_id);
+
+ /*
+ * If the Heartbeat is active (HB_ACT)
+ * Note: 1 = Active, 0 = Inactive
+ */
+ seq_printf(seq, "%d ", timer_pending(&tsp->hb_timer));
+
+ /*
+ * Retransmit time out (RTO)
+ */
+ seq_printf(seq, "%lu ", tsp->rto);
+
+ /*
+ * Maximum path retransmit count (PATH_MAX_RTX)
+ */
+ seq_printf(seq, "%d ", tsp->pathmaxrxt);
+
+ /*
+ * remote address retransmit count (REM_ADDR_RTX)
+ * Note: We don't have a way to tally this at the moment
+ * so lets just leave it as zero for the moment
+ */
+ seq_printf(seq, "0 ");
+
+ /*
+ * remote address start time (START). This is also not
+ * currently implemented, but we can record it with a
+ * jiffies marker in a subsequent patch
+ */
+ seq_printf(seq, "0");
+
+ seq_printf(seq, "\n");
+ }
+ }
+
+ read_unlock(&head->lock);
+ sctp_local_bh_enable();
+
+ return 0;
+
+}
+
+static const struct seq_operations sctp_remaddr_ops = {
+ .start = sctp_remaddr_seq_start,
+ .next = sctp_remaddr_seq_next,
+ .stop = sctp_remaddr_seq_stop,
+ .show = sctp_remaddr_seq_show,
+};
+
+/* Cleanup the proc fs entry for 'remaddr' object. */
+void sctp_remaddr_proc_exit(void)
+{
+ remove_proc_entry("remaddr", proc_net_sctp);
+}
+
+static int sctp_remaddr_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &sctp_remaddr_ops);
+}
+
+static const struct file_operations sctp_remaddr_seq_fops = {
+ .open = sctp_remaddr_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+int __init sctp_remaddr_proc_init(void)
+{
+ struct proc_dir_entry *p;
+
+ p = create_proc_entry("remaddr", S_IRUGO, proc_net_sctp);
+ if (!p)
+ return -ENOMEM;
+ p->proc_fops = &sctp_remaddr_seq_fops;
+
+ return 0;
+}
+
+void sctp_assoc_proc_exit(void)
+{
+ remove_proc_entry("remaddr", proc_net_sctp);
+}
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 0ec234b762c2..d6af466091d2 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -113,6 +113,8 @@ static __init int sctp_proc_init(void)
goto out_nomem;
if (sctp_assocs_proc_init())
goto out_nomem;
+ if (sctp_remaddr_proc_init())
+ goto out_nomem;
return 0;
@@ -129,6 +131,7 @@ static void sctp_proc_exit(void)
sctp_snmp_proc_exit();
sctp_eps_proc_exit();
sctp_assocs_proc_exit();
+ sctp_remaddr_proc_exit();
if (proc_net_sctp) {
proc_net_sctp = NULL;
@@ -470,11 +473,11 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
/* Walk through the bind address list and look for a bind
* address that matches the source address of the returned dst.
*/
+ sctp_v4_dst_saddr(&dst_saddr, dst, htons(bp->port));
rcu_read_lock();
list_for_each_entry_rcu(laddr, &bp->address_list, list) {
if (!laddr->valid || (laddr->state != SCTP_ADDR_SRC))
continue;
- sctp_v4_dst_saddr(&dst_saddr, dst, htons(bp->port));
if (sctp_v4_cmp_addr(&dst_saddr, &laddr->a))
goto out_unlock;
}
@@ -519,7 +522,8 @@ out:
/* For v4, the source address is cached in the route entry(dst). So no need
* to cache it separately and hence this is an empty routine.
*/
-static void sctp_v4_get_saddr(struct sctp_association *asoc,
+static void sctp_v4_get_saddr(struct sctp_sock *sk,
+ struct sctp_association *asoc,
struct dst_entry *dst,
union sctp_addr *daddr,
union sctp_addr *saddr)
@@ -616,6 +620,11 @@ static void sctp_v4_seq_dump_addr(struct seq_file *seq, union sctp_addr *addr)
seq_printf(seq, "%d.%d.%d.%d ", NIPQUAD(addr->v4.sin_addr));
}
+static void sctp_v4_ecn_capable(struct sock *sk)
+{
+ INET_ECN_xmit(sk);
+}
+
/* Event handler for inet address addition/deletion events.
* The sctp_local_addr_list needs to be protocted by a spin lock since
* multiple notifiers (say IPv4 and IPv6) may be running at the same
@@ -934,6 +943,7 @@ static struct sctp_af sctp_af_inet = {
.skb_iif = sctp_v4_skb_iif,
.is_ce = sctp_v4_is_ce,
.seq_dump_addr = sctp_v4_seq_dump_addr,
+ .ecn_capable = sctp_v4_ecn_capable,
.net_header_len = sizeof(struct iphdr),
.sockaddr_len = sizeof(struct sockaddr_in),
#ifdef CONFIG_COMPAT
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index 23a9f1a95b7d..b083312c725a 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -190,20 +190,28 @@ static int sctp_gen_sack(struct sctp_association *asoc, int force,
* unacknowledged DATA chunk. ...
*/
if (!asoc->peer.sack_needed) {
- /* We will need a SACK for the next packet. */
- asoc->peer.sack_needed = 1;
+ asoc->peer.sack_cnt++;
/* Set the SACK delay timeout based on the
* SACK delay for the last transport
* data was received from, or the default
* for the association.
*/
- if (trans)
+ if (trans) {
+ /* We will need a SACK for the next packet. */
+ if (asoc->peer.sack_cnt >= trans->sackfreq - 1)
+ asoc->peer.sack_needed = 1;
+
asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] =
trans->sackdelay;
- else
+ } else {
+ /* We will need a SACK for the next packet. */
+ if (asoc->peer.sack_cnt >= asoc->sackfreq - 1)
+ asoc->peer.sack_needed = 1;
+
asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] =
asoc->sackdelay;
+ }
/* Restart the SACK timer. */
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
@@ -216,6 +224,7 @@ static int sctp_gen_sack(struct sctp_association *asoc, int force,
goto nomem;
asoc->peer.sack_needed = 0;
+ asoc->peer.sack_cnt = 0;
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(sack));
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index e7e3baf7009e..253e5ea7e1e8 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -956,7 +956,8 @@ out:
*/
static int __sctp_connect(struct sock* sk,
struct sockaddr *kaddrs,
- int addrs_size)
+ int addrs_size,
+ sctp_assoc_t *assoc_id)
{
struct sctp_sock *sp;
struct sctp_endpoint *ep;
@@ -1111,6 +1112,8 @@ static int __sctp_connect(struct sock* sk,
timeo = sock_sndtimeo(sk, f_flags & O_NONBLOCK);
err = sctp_wait_for_connect(asoc, &timeo);
+ if (!err && assoc_id)
+ *assoc_id = asoc->assoc_id;
/* Don't free association on exit. */
asoc = NULL;
@@ -1128,7 +1131,8 @@ out_free:
/* Helper for tunneling sctp_connectx() requests through sctp_setsockopt()
*
* API 8.9
- * int sctp_connectx(int sd, struct sockaddr *addrs, int addrcnt);
+ * int sctp_connectx(int sd, struct sockaddr *addrs, int addrcnt,
+ * sctp_assoc_t *asoc);
*
* If sd is an IPv4 socket, the addresses passed must be IPv4 addresses.
* If the sd is an IPv6 socket, the addresses passed can either be IPv4
@@ -1144,8 +1148,10 @@ out_free:
* representation is termed a "packed array" of addresses). The caller
* specifies the number of addresses in the array with addrcnt.
*
- * On success, sctp_connectx() returns 0. On failure, sctp_connectx() returns
- * -1, and sets errno to the appropriate error code.
+ * On success, sctp_connectx() returns 0. It also sets the assoc_id to
+ * the association id of the new association. On failure, sctp_connectx()
+ * returns -1, and sets errno to the appropriate error code. The assoc_id
+ * is not touched by the kernel.
*
* For SCTP, the port given in each socket address must be the same, or
* sctp_connectx() will fail, setting errno to EINVAL.
@@ -1182,11 +1188,12 @@ out_free:
* addrs The pointer to the addresses in user land
* addrssize Size of the addrs buffer
*
- * Returns 0 if ok, <0 errno code on error.
+ * Returns >=0 if ok, <0 errno code on error.
*/
-SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk,
+SCTP_STATIC int __sctp_setsockopt_connectx(struct sock* sk,
struct sockaddr __user *addrs,
- int addrs_size)
+ int addrs_size,
+ sctp_assoc_t *assoc_id)
{
int err = 0;
struct sockaddr *kaddrs;
@@ -1209,13 +1216,46 @@ SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk,
if (__copy_from_user(kaddrs, addrs, addrs_size)) {
err = -EFAULT;
} else {
- err = __sctp_connect(sk, kaddrs, addrs_size);
+ err = __sctp_connect(sk, kaddrs, addrs_size, assoc_id);
}
kfree(kaddrs);
+
return err;
}
+/*
+ * This is an older interface. It's kept for backward compatibility
+ * to the option that doesn't provide association id.
+ */
+SCTP_STATIC int sctp_setsockopt_connectx_old(struct sock* sk,
+ struct sockaddr __user *addrs,
+ int addrs_size)
+{
+ return __sctp_setsockopt_connectx(sk, addrs, addrs_size, NULL);
+}
+
+/*
+ * New interface for the API. The since the API is done with a socket
+ * option, to make it simple we feed back the association id is as a return
+ * indication to the call. Error is always negative and association id is
+ * always positive.
+ */
+SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk,
+ struct sockaddr __user *addrs,
+ int addrs_size)
+{
+ sctp_assoc_t assoc_id = 0;
+ int err = 0;
+
+ err = __sctp_setsockopt_connectx(sk, addrs, addrs_size, &assoc_id);
+
+ if (err)
+ return err;
+ else
+ return assoc_id;
+}
+
/* API 3.1.4 close() - UDP Style Syntax
* Applications use close() to perform graceful shutdown (as described in
* Section 10.1 of [SCTP]) on ALL the associations currently represented
@@ -2305,74 +2345,98 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk,
return 0;
}
-/* 7.1.23. Delayed Ack Timer (SCTP_DELAYED_ACK_TIME)
- *
- * This options will get or set the delayed ack timer. The time is set
- * in milliseconds. If the assoc_id is 0, then this sets or gets the
- * endpoints default delayed ack timer value. If the assoc_id field is
- * non-zero, then the set or get effects the specified association.
- *
- * struct sctp_assoc_value {
- * sctp_assoc_t assoc_id;
- * uint32_t assoc_value;
- * };
+/*
+ * 7.1.23. Get or set delayed ack timer (SCTP_DELAYED_SACK)
+ *
+ * This option will effect the way delayed acks are performed. This
+ * option allows you to get or set the delayed ack time, in
+ * milliseconds. It also allows changing the delayed ack frequency.
+ * Changing the frequency to 1 disables the delayed sack algorithm. If
+ * the assoc_id is 0, then this sets or gets the endpoints default
+ * values. If the assoc_id field is non-zero, then the set or get
+ * effects the specified association for the one to many model (the
+ * assoc_id field is ignored by the one to one model). Note that if
+ * sack_delay or sack_freq are 0 when setting this option, then the
+ * current values will remain unchanged.
+ *
+ * struct sctp_sack_info {
+ * sctp_assoc_t sack_assoc_id;
+ * uint32_t sack_delay;
+ * uint32_t sack_freq;
+ * };
*
- * assoc_id - This parameter, indicates which association the
- * user is preforming an action upon. Note that if
- * this field's value is zero then the endpoints
- * default value is changed (effecting future
- * associations only).
+ * sack_assoc_id - This parameter, indicates which association the user
+ * is performing an action upon. Note that if this field's value is
+ * zero then the endpoints default value is changed (effecting future
+ * associations only).
*
- * assoc_value - This parameter contains the number of milliseconds
- * that the user is requesting the delayed ACK timer
- * be set to. Note that this value is defined in
- * the standard to be between 200 and 500 milliseconds.
+ * sack_delay - This parameter contains the number of milliseconds that
+ * the user is requesting the delayed ACK timer be set to. Note that
+ * this value is defined in the standard to be between 200 and 500
+ * milliseconds.
*
- * Note: a value of zero will leave the value alone,
- * but disable SACK delay. A non-zero value will also
- * enable SACK delay.
+ * sack_freq - This parameter contains the number of packets that must
+ * be received before a sack is sent without waiting for the delay
+ * timer to expire. The default value for this is 2, setting this
+ * value to 1 will disable the delayed sack algorithm.
*/
-static int sctp_setsockopt_delayed_ack_time(struct sock *sk,
+static int sctp_setsockopt_delayed_ack(struct sock *sk,
char __user *optval, int optlen)
{
- struct sctp_assoc_value params;
+ struct sctp_sack_info params;
struct sctp_transport *trans = NULL;
struct sctp_association *asoc = NULL;
struct sctp_sock *sp = sctp_sk(sk);
- if (optlen != sizeof(struct sctp_assoc_value))
- return - EINVAL;
+ if (optlen == sizeof(struct sctp_sack_info)) {
+ if (copy_from_user(&params, optval, optlen))
+ return -EFAULT;
- if (copy_from_user(&params, optval, optlen))
- return -EFAULT;
+ if (params.sack_delay == 0 && params.sack_freq == 0)
+ return 0;
+ } else if (optlen == sizeof(struct sctp_assoc_value)) {
+ printk(KERN_WARNING "SCTP: Use of struct sctp_sack_info "
+ "in delayed_ack socket option deprecated\n");
+ printk(KERN_WARNING "SCTP: struct sctp_sack_info instead\n");
+ if (copy_from_user(&params, optval, optlen))
+ return -EFAULT;
+
+ if (params.sack_delay == 0)
+ params.sack_freq = 1;
+ else
+ params.sack_freq = 0;
+ } else
+ return - EINVAL;
/* Validate value parameter. */
- if (params.assoc_value > 500)
+ if (params.sack_delay > 500)
return -EINVAL;
- /* Get association, if assoc_id != 0 and the socket is a one
+ /* Get association, if sack_assoc_id != 0 and the socket is a one
* to many style socket, and an association was not found, then
* the id was invalid.
*/
- asoc = sctp_id2assoc(sk, params.assoc_id);
- if (!asoc && params.assoc_id && sctp_style(sk, UDP))
+ asoc = sctp_id2assoc(sk, params.sack_assoc_id);
+ if (!asoc && params.sack_assoc_id && sctp_style(sk, UDP))
return -EINVAL;
- if (params.assoc_value) {
+ if (params.sack_delay) {
if (asoc) {
asoc->sackdelay =
- msecs_to_jiffies(params.assoc_value);
+ msecs_to_jiffies(params.sack_delay);
asoc->param_flags =
(asoc->param_flags & ~SPP_SACKDELAY) |
SPP_SACKDELAY_ENABLE;
} else {
- sp->sackdelay = params.assoc_value;
+ sp->sackdelay = params.sack_delay;
sp->param_flags =
(sp->param_flags & ~SPP_SACKDELAY) |
SPP_SACKDELAY_ENABLE;
}
- } else {
+ }
+
+ if (params.sack_freq == 1) {
if (asoc) {
asoc->param_flags =
(asoc->param_flags & ~SPP_SACKDELAY) |
@@ -2382,22 +2446,40 @@ static int sctp_setsockopt_delayed_ack_time(struct sock *sk,
(sp->param_flags & ~SPP_SACKDELAY) |
SPP_SACKDELAY_DISABLE;
}
+ } else if (params.sack_freq > 1) {
+ if (asoc) {
+ asoc->sackfreq = params.sack_freq;
+ asoc->param_flags =
+ (asoc->param_flags & ~SPP_SACKDELAY) |
+ SPP_SACKDELAY_ENABLE;
+ } else {
+ sp->sackfreq = params.sack_freq;
+ sp->param_flags =
+ (sp->param_flags & ~SPP_SACKDELAY) |
+ SPP_SACKDELAY_ENABLE;
+ }
}
/* If change is for association, also apply to each transport. */
if (asoc) {
list_for_each_entry(trans, &asoc->peer.transport_addr_list,
transports) {
- if (params.assoc_value) {
+ if (params.sack_delay) {
trans->sackdelay =
- msecs_to_jiffies(params.assoc_value);
+ msecs_to_jiffies(params.sack_delay);
trans->param_flags =
(trans->param_flags & ~SPP_SACKDELAY) |
SPP_SACKDELAY_ENABLE;
- } else {
+ }
+ if (params.sack_freq == 1) {
trans->param_flags =
(trans->param_flags & ~SPP_SACKDELAY) |
SPP_SACKDELAY_DISABLE;
+ } else if (params.sack_freq > 1) {
+ trans->sackfreq = params.sack_freq;
+ trans->param_flags =
+ (trans->param_flags & ~SPP_SACKDELAY) |
+ SPP_SACKDELAY_ENABLE;
}
}
}
@@ -3164,10 +3246,18 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
optlen, SCTP_BINDX_REM_ADDR);
break;
+ case SCTP_SOCKOPT_CONNECTX_OLD:
+ /* 'optlen' is the size of the addresses buffer. */
+ retval = sctp_setsockopt_connectx_old(sk,
+ (struct sockaddr __user *)optval,
+ optlen);
+ break;
+
case SCTP_SOCKOPT_CONNECTX:
/* 'optlen' is the size of the addresses buffer. */
- retval = sctp_setsockopt_connectx(sk, (struct sockaddr __user *)optval,
- optlen);
+ retval = sctp_setsockopt_connectx(sk,
+ (struct sockaddr __user *)optval,
+ optlen);
break;
case SCTP_DISABLE_FRAGMENTS:
@@ -3186,8 +3276,8 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
retval = sctp_setsockopt_peer_addr_params(sk, optval, optlen);
break;
- case SCTP_DELAYED_ACK_TIME:
- retval = sctp_setsockopt_delayed_ack_time(sk, optval, optlen);
+ case SCTP_DELAYED_ACK:
+ retval = sctp_setsockopt_delayed_ack(sk, optval, optlen);
break;
case SCTP_PARTIAL_DELIVERY_POINT:
retval = sctp_setsockopt_partial_delivery_point(sk, optval, optlen);
@@ -3294,7 +3384,7 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *addr,
/* Pass correct addr len to common routine (so it knows there
* is only one address being passed.
*/
- err = __sctp_connect(sk, addr, af->sockaddr_len);
+ err = __sctp_connect(sk, addr, af->sockaddr_len, NULL);
}
sctp_release_sock(sk);
@@ -3446,6 +3536,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
sp->pathmaxrxt = sctp_max_retrans_path;
sp->pathmtu = 0; // allow default discovery
sp->sackdelay = sctp_sack_timeout;
+ sp->sackfreq = 2;
sp->param_flags = SPP_HB_ENABLE |
SPP_PMTUD_ENABLE |
SPP_SACKDELAY_ENABLE;
@@ -3999,70 +4090,91 @@ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len,
return 0;
}
-/* 7.1.23. Delayed Ack Timer (SCTP_DELAYED_ACK_TIME)
- *
- * This options will get or set the delayed ack timer. The time is set
- * in milliseconds. If the assoc_id is 0, then this sets or gets the
- * endpoints default delayed ack timer value. If the assoc_id field is
- * non-zero, then the set or get effects the specified association.
- *
- * struct sctp_assoc_value {
- * sctp_assoc_t assoc_id;
- * uint32_t assoc_value;
- * };
+/*
+ * 7.1.23. Get or set delayed ack timer (SCTP_DELAYED_SACK)
+ *
+ * This option will effect the way delayed acks are performed. This
+ * option allows you to get or set the delayed ack time, in
+ * milliseconds. It also allows changing the delayed ack frequency.
+ * Changing the frequency to 1 disables the delayed sack algorithm. If
+ * the assoc_id is 0, then this sets or gets the endpoints default
+ * values. If the assoc_id field is non-zero, then the set or get
+ * effects the specified association for the one to many model (the
+ * assoc_id field is ignored by the one to one model). Note that if
+ * sack_delay or sack_freq are 0 when setting this option, then the
+ * current values will remain unchanged.
+ *
+ * struct sctp_sack_info {
+ * sctp_assoc_t sack_assoc_id;
+ * uint32_t sack_delay;
+ * uint32_t sack_freq;
+ * };
*
- * assoc_id - This parameter, indicates which association the
- * user is preforming an action upon. Note that if
- * this field's value is zero then the endpoints
- * default value is changed (effecting future
- * associations only).
+ * sack_assoc_id - This parameter, indicates which association the user
+ * is performing an action upon. Note that if this field's value is
+ * zero then the endpoints default value is changed (effecting future
+ * associations only).
*
- * assoc_value - This parameter contains the number of milliseconds
- * that the user is requesting the delayed ACK timer
- * be set to. Note that this value is defined in
- * the standard to be between 200 and 500 milliseconds.
+ * sack_delay - This parameter contains the number of milliseconds that
+ * the user is requesting the delayed ACK timer be set to. Note that
+ * this value is defined in the standard to be between 200 and 500
+ * milliseconds.
*
- * Note: a value of zero will leave the value alone,
- * but disable SACK delay. A non-zero value will also
- * enable SACK delay.
+ * sack_freq - This parameter contains the number of packets that must
+ * be received before a sack is sent without waiting for the delay
+ * timer to expire. The default value for this is 2, setting this
+ * value to 1 will disable the delayed sack algorithm.
*/
-static int sctp_getsockopt_delayed_ack_time(struct sock *sk, int len,
+static int sctp_getsockopt_delayed_ack(struct sock *sk, int len,
char __user *optval,
int __user *optlen)
{
- struct sctp_assoc_value params;
+ struct sctp_sack_info params;
struct sctp_association *asoc = NULL;
struct sctp_sock *sp = sctp_sk(sk);
- if (len < sizeof(struct sctp_assoc_value))
- return - EINVAL;
-
- len = sizeof(struct sctp_assoc_value);
+ if (len >= sizeof(struct sctp_sack_info)) {
+ len = sizeof(struct sctp_sack_info);
- if (copy_from_user(&params, optval, len))
- return -EFAULT;
+ if (copy_from_user(&params, optval, len))
+ return -EFAULT;
+ } else if (len == sizeof(struct sctp_assoc_value)) {
+ printk(KERN_WARNING "SCTP: Use of struct sctp_sack_info "
+ "in delayed_ack socket option deprecated\n");
+ printk(KERN_WARNING "SCTP: struct sctp_sack_info instead\n");
+ if (copy_from_user(&params, optval, len))
+ return -EFAULT;
+ } else
+ return - EINVAL;
- /* Get association, if assoc_id != 0 and the socket is a one
+ /* Get association, if sack_assoc_id != 0 and the socket is a one
* to many style socket, and an association was not found, then
* the id was invalid.
*/
- asoc = sctp_id2assoc(sk, params.assoc_id);
- if (!asoc && params.assoc_id && sctp_style(sk, UDP))
+ asoc = sctp_id2assoc(sk, params.sack_assoc_id);
+ if (!asoc && params.sack_assoc_id && sctp_style(sk, UDP))
return -EINVAL;
if (asoc) {
/* Fetch association values. */
- if (asoc->param_flags & SPP_SACKDELAY_ENABLE)
- params.assoc_value = jiffies_to_msecs(
+ if (asoc->param_flags & SPP_SACKDELAY_ENABLE) {
+ params.sack_delay = jiffies_to_msecs(
asoc->sackdelay);
- else
- params.assoc_value = 0;
+ params.sack_freq = asoc->sackfreq;
+
+ } else {
+ params.sack_delay = 0;
+ params.sack_freq = 1;
+ }
} else {
/* Fetch socket values. */
- if (sp->param_flags & SPP_SACKDELAY_ENABLE)
- params.assoc_value = sp->sackdelay;
- else
- params.assoc_value = 0;
+ if (sp->param_flags & SPP_SACKDELAY_ENABLE) {
+ params.sack_delay = sp->sackdelay;
+ params.sack_freq = sp->sackfreq;
+ } else {
+ params.sack_delay = 0;
+ params.sack_freq = 1;
+ }
}
if (copy_to_user(optval, &params, len))
@@ -5218,8 +5330,8 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
retval = sctp_getsockopt_peer_addr_params(sk, len, optval,
optlen);
break;
- case SCTP_DELAYED_ACK_TIME:
- retval = sctp_getsockopt_delayed_ack_time(sk, len, optval,
+ case SCTP_DELAYED_ACK:
+ retval = sctp_getsockopt_delayed_ack(sk, len, optval,
optlen);
break;
case SCTP_INITMSG:
diff --git a/net/sctp/transport.c b/net/sctp/transport.c
index f4938f6c5abe..3f34f61221ec 100644
--- a/net/sctp/transport.c
+++ b/net/sctp/transport.c
@@ -79,6 +79,7 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
peer->rttvar = 0;
peer->srtt = 0;
peer->rto_pending = 0;
+ peer->fast_recovery = 0;
peer->last_time_heard = jiffies;
peer->last_time_used = jiffies;
@@ -190,7 +191,7 @@ static void sctp_transport_destroy(struct sctp_transport *transport)
/* Start T3_rtx timer if it is not already running and update the heartbeat
* timer. This routine is called every time a DATA chunk is sent.
*/
-void sctp_transport_reset_timers(struct sctp_transport *transport)
+void sctp_transport_reset_timers(struct sctp_transport *transport, int force)
{
/* RFC 2960 6.3.2 Retransmission Timer Rules
*
@@ -200,7 +201,7 @@ void sctp_transport_reset_timers(struct sctp_transport *transport)
* address.
*/
- if (!timer_pending(&transport->T3_rtx_timer))
+ if (force || !timer_pending(&transport->T3_rtx_timer))
if (!mod_timer(&transport->T3_rtx_timer,
jiffies + transport->rto))
sctp_transport_hold(transport);
@@ -291,7 +292,7 @@ void sctp_transport_route(struct sctp_transport *transport,
if (saddr)
memcpy(&transport->saddr, saddr, sizeof(union sctp_addr));
else
- af->get_saddr(asoc, dst, daddr, &transport->saddr);
+ af->get_saddr(opt, asoc, dst, daddr, &transport->saddr);
transport->dst = dst;
if ((transport->param_flags & SPP_PMTUD_DISABLE) && transport->pathmtu) {
@@ -403,11 +404,16 @@ void sctp_transport_raise_cwnd(struct sctp_transport *transport,
cwnd = transport->cwnd;
flight_size = transport->flight_size;
+ /* See if we need to exit Fast Recovery first */
+ if (transport->fast_recovery &&
+ TSN_lte(transport->fast_recovery_exit, sack_ctsn))
+ transport->fast_recovery = 0;
+
/* The appropriate cwnd increase algorithm is performed if, and only
- * if the cumulative TSN has advanced and the congestion window is
+ * if the cumulative TSN whould advanced and the congestion window is
* being fully utilized.
*/
- if ((transport->asoc->ctsn_ack_point >= sack_ctsn) ||
+ if (TSN_lte(sack_ctsn, transport->asoc->ctsn_ack_point) ||
(flight_size < cwnd))
return;
@@ -416,17 +422,23 @@ void sctp_transport_raise_cwnd(struct sctp_transport *transport,
pmtu = transport->asoc->pathmtu;
if (cwnd <= ssthresh) {
- /* RFC 2960 7.2.1, sctpimpguide-05 2.14.2 When cwnd is less
- * than or equal to ssthresh an SCTP endpoint MUST use the
- * slow start algorithm to increase cwnd only if the current
- * congestion window is being fully utilized and an incoming
- * SACK advances the Cumulative TSN Ack Point. Only when these
- * two conditions are met can the cwnd be increased otherwise
- * the cwnd MUST not be increased. If these conditions are met
- * then cwnd MUST be increased by at most the lesser of
- * 1) the total size of the previously outstanding DATA
- * chunk(s) acknowledged, and 2) the destination's path MTU.
+ /* RFC 4960 7.2.1
+ * o When cwnd is less than or equal to ssthresh, an SCTP
+ * endpoint MUST use the slow-start algorithm to increase
+ * cwnd only if the current congestion window is being fully
+ * utilized, an incoming SACK advances the Cumulative TSN
+ * Ack Point, and the data sender is not in Fast Recovery.
+ * Only when these three conditions are met can the cwnd be
+ * increased; otherwise, the cwnd MUST not be increased.
+ * If these conditions are met, then cwnd MUST be increased
+ * by, at most, the lesser of 1) the total size of the
+ * previously outstanding DATA chunk(s) acknowledged, and
+ * 2) the destination's path MTU. This upper bound protects
+ * against the ACK-Splitting attack outlined in [SAVAGE99].
*/
+ if (transport->fast_recovery)
+ return;
+
if (bytes_acked > pmtu)
cwnd += pmtu;
else
@@ -502,6 +514,13 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport,
* cwnd = ssthresh
* partial_bytes_acked = 0
*/
+ if (transport->fast_recovery)
+ return;
+
+ /* Mark Fast recovery */
+ transport->fast_recovery = 1;
+ transport->fast_recovery_exit = transport->asoc->next_tsn - 1;
+
transport->ssthresh = max(transport->cwnd/2,
4*transport->asoc->pathmtu);
transport->cwnd = transport->ssthresh;
@@ -586,6 +605,7 @@ void sctp_transport_reset(struct sctp_transport *t)
t->flight_size = 0;
t->error_count = 0;
t->rto_pending = 0;
+ t->fast_recovery = 0;
/* Initialize the state information for SFR-CACC */
t->cacc.changeover_active = 0;
diff --git a/net/sunrpc/auth_gss/Makefile b/net/sunrpc/auth_gss/Makefile
index f3431a7e33da..4de8bcf26fa7 100644
--- a/net/sunrpc/auth_gss/Makefile
+++ b/net/sunrpc/auth_gss/Makefile
@@ -5,12 +5,12 @@
obj-$(CONFIG_SUNRPC_GSS) += auth_rpcgss.o
auth_rpcgss-objs := auth_gss.o gss_generic_token.o \
- gss_mech_switch.o svcauth_gss.o gss_krb5_crypto.o
+ gss_mech_switch.o svcauth_gss.o
obj-$(CONFIG_RPCSEC_GSS_KRB5) += rpcsec_gss_krb5.o
rpcsec_gss_krb5-objs := gss_krb5_mech.o gss_krb5_seal.o gss_krb5_unseal.o \
- gss_krb5_seqnum.o gss_krb5_wrap.o
+ gss_krb5_seqnum.o gss_krb5_wrap.o gss_krb5_crypto.o
obj-$(CONFIG_RPCSEC_GSS_SPKM3) += rpcsec_gss_spkm3.o
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index cc12d5f5d5da..1d08f08d05bf 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -33,8 +33,6 @@
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * $Id$
*/
@@ -65,7 +63,7 @@ static const struct rpc_credops gss_nullops;
#define NFS_NGROUPS 16
-#define GSS_CRED_SLACK 1024 /* XXX: unused */
+#define GSS_CRED_SLACK (RPC_MAX_AUTH_SIZE * 2)
/* length of a krb5 verifier (48), plus data added before arguments when
* using integrity (two 4-byte integers): */
#define GSS_VERF_SLACK 100
@@ -1137,15 +1135,21 @@ gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
inpages = snd_buf->pages + first;
snd_buf->pages = rqstp->rq_enc_pages;
snd_buf->page_base -= first << PAGE_CACHE_SHIFT;
- /* Give the tail its own page, in case we need extra space in the
- * head when wrapping: */
+ /*
+ * Give the tail its own page, in case we need extra space in the
+ * head when wrapping:
+ *
+ * call_allocate() allocates twice the slack space required
+ * by the authentication flavor to rq_callsize.
+ * For GSS, slack is GSS_CRED_SLACK.
+ */
if (snd_buf->page_len || snd_buf->tail[0].iov_len) {
tmp = page_address(rqstp->rq_enc_pages[rqstp->rq_enc_pages_num - 1]);
memcpy(tmp, snd_buf->tail[0].iov_base, snd_buf->tail[0].iov_len);
snd_buf->tail[0].iov_base = tmp;
}
maj_stat = gss_wrap(ctx->gc_gss_ctx, offset, snd_buf, inpages);
- /* RPC_SLACK_SPACE should prevent this ever happening: */
+ /* slack space should prevent this ever happening: */
BUG_ON(snd_buf->len > snd_buf->buflen);
status = -EIO;
/* We're assuming that when GSS_S_CONTEXT_EXPIRED, the encryption was
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c
index 1d52308ca324..d0f3371c62e2 100644
--- a/net/sunrpc/auth_gss/gss_krb5_crypto.c
+++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c
@@ -83,8 +83,6 @@ out:
return ret;
}
-EXPORT_SYMBOL(krb5_encrypt);
-
u32
krb5_decrypt(
struct crypto_blkcipher *tfm,
@@ -118,8 +116,6 @@ out:
return ret;
}
-EXPORT_SYMBOL(krb5_decrypt);
-
static int
checksummer(struct scatterlist *sg, void *data)
{
@@ -161,8 +157,6 @@ out:
return err ? GSS_S_FAILURE : 0;
}
-EXPORT_SYMBOL(make_checksum);
-
struct encryptor_desc {
u8 iv[8]; /* XXX hard-coded blocksize */
struct blkcipher_desc desc;
@@ -262,8 +256,6 @@ gss_encrypt_xdr_buf(struct crypto_blkcipher *tfm, struct xdr_buf *buf,
return ret;
}
-EXPORT_SYMBOL(gss_encrypt_xdr_buf);
-
struct decryptor_desc {
u8 iv[8]; /* XXX hard-coded blocksize */
struct blkcipher_desc desc;
@@ -335,4 +327,58 @@ gss_decrypt_xdr_buf(struct crypto_blkcipher *tfm, struct xdr_buf *buf,
return xdr_process_buf(buf, offset, buf->len - offset, decryptor, &desc);
}
-EXPORT_SYMBOL(gss_decrypt_xdr_buf);
+/*
+ * This function makes the assumption that it was ultimately called
+ * from gss_wrap().
+ *
+ * The client auth_gss code moves any existing tail data into a
+ * separate page before calling gss_wrap.
+ * The server svcauth_gss code ensures that both the head and the
+ * tail have slack space of RPC_MAX_AUTH_SIZE before calling gss_wrap.
+ *
+ * Even with that guarantee, this function may be called more than
+ * once in the processing of gss_wrap(). The best we can do is
+ * verify at compile-time (see GSS_KRB5_SLACK_CHECK) that the
+ * largest expected shift will fit within RPC_MAX_AUTH_SIZE.
+ * At run-time we can verify that a single invocation of this
+ * function doesn't attempt to use more the RPC_MAX_AUTH_SIZE.
+ */
+
+int
+shift_head_data(struct xdr_buf *buf, unsigned int base, unsigned int shiftlen)
+{
+ u8 *p;
+
+ if (shiftlen == 0)
+ return 0;
+
+ GSS_KRB5_SLACK_CHECK;
+ BUG_ON(shiftlen > RPC_MAX_AUTH_SIZE);
+
+ /*
+ * If there is a tail, and it shares a page with the head,
+ * make sure we don't clobber the tail. This is a just a
+ * defensive check.
+ */
+ if (buf->tail[0].iov_base != NULL) {
+ if ((((long)buf->tail[0].iov_base >> PAGE_CACHE_SHIFT) ==
+ ((long)buf->head[0].iov_base >> PAGE_CACHE_SHIFT)) &&
+ buf->tail[0].iov_base - buf->head[0].iov_base < shiftlen) {
+ dprintk("%s: collision: head %p:%zu, tail %p:%zu, "
+ "shiftlen %u\n",
+ __func__, buf->head[0].iov_base,
+ buf->head[0].iov_len, buf->tail[0].iov_base,
+ buf->tail[0].iov_len, shiftlen);
+ return 1;
+ }
+ }
+
+ p = buf->head[0].iov_base + base;
+
+ memmove(p + shiftlen, p, buf->head[0].iov_len - base);
+
+ buf->head[0].iov_len += shiftlen;
+ buf->len += shiftlen;
+
+ return 0;
+}
diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c
index 5f1d36dfbcf7..b8f42ef7178e 100644
--- a/net/sunrpc/auth_gss/gss_krb5_seal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_seal.c
@@ -78,7 +78,7 @@ gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text,
struct krb5_ctx *ctx = gss_ctx->internal_ctx_id;
char cksumdata[16];
struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata};
- unsigned char *ptr, *krb5_hdr, *msg_start;
+ unsigned char *ptr, *msg_start;
s32 now;
u32 seq_send;
@@ -87,36 +87,36 @@ gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text,
now = get_seconds();
- token->len = g_token_size(&ctx->mech_used, 24);
+ token->len = g_token_size(&ctx->mech_used, GSS_KRB5_TOK_HDR_LEN + 8);
ptr = token->data;
- g_make_token_header(&ctx->mech_used, 24, &ptr);
+ g_make_token_header(&ctx->mech_used, GSS_KRB5_TOK_HDR_LEN + 8, &ptr);
- *ptr++ = (unsigned char) ((KG_TOK_MIC_MSG>>8)&0xff);
- *ptr++ = (unsigned char) (KG_TOK_MIC_MSG&0xff);
+ /* ptr now at header described in rfc 1964, section 1.2.1: */
+ ptr[0] = (unsigned char) ((KG_TOK_MIC_MSG >> 8) & 0xff);
+ ptr[1] = (unsigned char) (KG_TOK_MIC_MSG & 0xff);
- /* ptr now at byte 2 of header described in rfc 1964, section 1.2.1: */
- krb5_hdr = ptr - 2;
- msg_start = krb5_hdr + 24;
+ msg_start = ptr + GSS_KRB5_TOK_HDR_LEN + 8;
- *(__be16 *)(krb5_hdr + 2) = htons(SGN_ALG_DES_MAC_MD5);
- memset(krb5_hdr + 4, 0xff, 4);
+ *(__be16 *)(ptr + 2) = htons(SGN_ALG_DES_MAC_MD5);
+ memset(ptr + 4, 0xff, 4);
- if (make_checksum("md5", krb5_hdr, 8, text, 0, &md5cksum))
+ if (make_checksum("md5", ptr, 8, text, 0, &md5cksum))
return GSS_S_FAILURE;
if (krb5_encrypt(ctx->seq, NULL, md5cksum.data,
md5cksum.data, md5cksum.len))
return GSS_S_FAILURE;
- memcpy(krb5_hdr + 16, md5cksum.data + md5cksum.len - 8, 8);
+ memcpy(ptr + GSS_KRB5_TOK_HDR_LEN, md5cksum.data + md5cksum.len - 8, 8);
spin_lock(&krb5_seq_lock);
seq_send = ctx->seq_send++;
spin_unlock(&krb5_seq_lock);
if (krb5_make_seq_num(ctx->seq, ctx->initiate ? 0 : 0xff,
- seq_send, krb5_hdr + 16, krb5_hdr + 8))
+ seq_send, ptr + GSS_KRB5_TOK_HDR_LEN,
+ ptr + 8))
return GSS_S_FAILURE;
return (ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE;
diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c
index d91a5d004803..066ec73c84d6 100644
--- a/net/sunrpc/auth_gss/gss_krb5_unseal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c
@@ -92,30 +92,30 @@ gss_verify_mic_kerberos(struct gss_ctx *gss_ctx,
read_token->len))
return GSS_S_DEFECTIVE_TOKEN;
- if ((*ptr++ != ((KG_TOK_MIC_MSG>>8)&0xff)) ||
- (*ptr++ != ( KG_TOK_MIC_MSG &0xff)) )
+ if ((ptr[0] != ((KG_TOK_MIC_MSG >> 8) & 0xff)) ||
+ (ptr[1] != (KG_TOK_MIC_MSG & 0xff)))
return GSS_S_DEFECTIVE_TOKEN;
/* XXX sanity-check bodysize?? */
- signalg = ptr[0] + (ptr[1] << 8);
+ signalg = ptr[2] + (ptr[3] << 8);
if (signalg != SGN_ALG_DES_MAC_MD5)
return GSS_S_DEFECTIVE_TOKEN;
- sealalg = ptr[2] + (ptr[3] << 8);
+ sealalg = ptr[4] + (ptr[5] << 8);
if (sealalg != SEAL_ALG_NONE)
return GSS_S_DEFECTIVE_TOKEN;
- if ((ptr[4] != 0xff) || (ptr[5] != 0xff))
+ if ((ptr[6] != 0xff) || (ptr[7] != 0xff))
return GSS_S_DEFECTIVE_TOKEN;
- if (make_checksum("md5", ptr - 2, 8, message_buffer, 0, &md5cksum))
+ if (make_checksum("md5", ptr, 8, message_buffer, 0, &md5cksum))
return GSS_S_FAILURE;
if (krb5_encrypt(ctx->seq, NULL, md5cksum.data, md5cksum.data, 16))
return GSS_S_FAILURE;
- if (memcmp(md5cksum.data + 8, ptr + 14, 8))
+ if (memcmp(md5cksum.data + 8, ptr + GSS_KRB5_TOK_HDR_LEN, 8))
return GSS_S_BAD_SIG;
/* it got through unscathed. Make sure the context is unexpired */
@@ -127,7 +127,7 @@ gss_verify_mic_kerberos(struct gss_ctx *gss_ctx,
/* do sequencing checks */
- if (krb5_get_seq_num(ctx->seq, ptr + 14, ptr + 6, &direction, &seqnum))
+ if (krb5_get_seq_num(ctx->seq, ptr + GSS_KRB5_TOK_HDR_LEN, ptr + 8, &direction, &seqnum))
return GSS_S_FAILURE;
if ((ctx->initiate && direction != 0xff) ||
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c
index b00b1b426301..a0660f5c3220 100644
--- a/net/sunrpc/auth_gss/gss_krb5_wrap.c
+++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c
@@ -87,8 +87,8 @@ out:
return 0;
}
-static inline void
-make_confounder(char *p, int blocksize)
+static void
+make_confounder(char *p, u32 conflen)
{
static u64 i = 0;
u64 *q = (u64 *)p;
@@ -102,8 +102,22 @@ make_confounder(char *p, int blocksize)
* uniqueness would mean worrying about atomicity and rollover, and I
* don't care enough. */
- BUG_ON(blocksize != 8);
- *q = i++;
+ /* initialize to random value */
+ if (i == 0) {
+ i = random32();
+ i = (i << 32) | random32();
+ }
+
+ switch (conflen) {
+ case 16:
+ *q++ = i++;
+ /* fall through */
+ case 8:
+ *q++ = i++;
+ break;
+ default:
+ BUG();
+ }
}
/* Assumptions: the head and tail of inbuf are ours to play with.
@@ -122,7 +136,7 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset,
char cksumdata[16];
struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata};
int blocksize = 0, plainlen;
- unsigned char *ptr, *krb5_hdr, *msg_start;
+ unsigned char *ptr, *msg_start;
s32 now;
int headlen;
struct page **tmp_pages;
@@ -130,6 +144,7 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset,
dprintk("RPC: gss_wrap_kerberos\n");
+ GSS_KRB5_SLACK_CHECK;
now = get_seconds();
blocksize = crypto_blkcipher_blocksize(kctx->enc);
@@ -142,33 +157,31 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset,
ptr = buf->head[0].iov_base + offset;
/* shift data to make room for header. */
+ shift_head_data(buf, offset, headlen);
+
/* XXX Would be cleverer to encrypt while copying. */
- /* XXX bounds checking, slack, etc. */
- memmove(ptr + headlen, ptr, buf->head[0].iov_len - offset);
- buf->head[0].iov_len += headlen;
- buf->len += headlen;
BUG_ON((buf->len - offset - headlen) % blocksize);
- g_make_token_header(&kctx->mech_used, 24 + plainlen, &ptr);
+ g_make_token_header(&kctx->mech_used,
+ GSS_KRB5_TOK_HDR_LEN + 8 + plainlen, &ptr);
- *ptr++ = (unsigned char) ((KG_TOK_WRAP_MSG>>8)&0xff);
- *ptr++ = (unsigned char) (KG_TOK_WRAP_MSG&0xff);
+ /* ptr now at header described in rfc 1964, section 1.2.1: */
+ ptr[0] = (unsigned char) ((KG_TOK_WRAP_MSG >> 8) & 0xff);
+ ptr[1] = (unsigned char) (KG_TOK_WRAP_MSG & 0xff);
- /* ptr now at byte 2 of header described in rfc 1964, section 1.2.1: */
- krb5_hdr = ptr - 2;
- msg_start = krb5_hdr + 24;
+ msg_start = ptr + 24;
- *(__be16 *)(krb5_hdr + 2) = htons(SGN_ALG_DES_MAC_MD5);
- memset(krb5_hdr + 4, 0xff, 4);
- *(__be16 *)(krb5_hdr + 4) = htons(SEAL_ALG_DES);
+ *(__be16 *)(ptr + 2) = htons(SGN_ALG_DES_MAC_MD5);
+ memset(ptr + 4, 0xff, 4);
+ *(__be16 *)(ptr + 4) = htons(SEAL_ALG_DES);
make_confounder(msg_start, blocksize);
/* XXXJBF: UGH!: */
tmp_pages = buf->pages;
buf->pages = pages;
- if (make_checksum("md5", krb5_hdr, 8, buf,
+ if (make_checksum("md5", ptr, 8, buf,
offset + headlen - blocksize, &md5cksum))
return GSS_S_FAILURE;
buf->pages = tmp_pages;
@@ -176,7 +189,7 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset,
if (krb5_encrypt(kctx->seq, NULL, md5cksum.data,
md5cksum.data, md5cksum.len))
return GSS_S_FAILURE;
- memcpy(krb5_hdr + 16, md5cksum.data + md5cksum.len - 8, 8);
+ memcpy(ptr + GSS_KRB5_TOK_HDR_LEN, md5cksum.data + md5cksum.len - 8, 8);
spin_lock(&krb5_seq_lock);
seq_send = kctx->seq_send++;
@@ -185,7 +198,7 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset,
/* XXX would probably be more efficient to compute checksum
* and encrypt at the same time: */
if ((krb5_make_seq_num(kctx->seq, kctx->initiate ? 0 : 0xff,
- seq_send, krb5_hdr + 16, krb5_hdr + 8)))
+ seq_send, ptr + GSS_KRB5_TOK_HDR_LEN, ptr + 8)))
return GSS_S_FAILURE;
if (gss_encrypt_xdr_buf(kctx->enc, buf, offset + headlen - blocksize,
@@ -219,38 +232,38 @@ gss_unwrap_kerberos(struct gss_ctx *ctx, int offset, struct xdr_buf *buf)
buf->len - offset))
return GSS_S_DEFECTIVE_TOKEN;
- if ((*ptr++ != ((KG_TOK_WRAP_MSG>>8)&0xff)) ||
- (*ptr++ != (KG_TOK_WRAP_MSG &0xff)) )
+ if ((ptr[0] != ((KG_TOK_WRAP_MSG >> 8) & 0xff)) ||
+ (ptr[1] != (KG_TOK_WRAP_MSG & 0xff)))
return GSS_S_DEFECTIVE_TOKEN;
/* XXX sanity-check bodysize?? */
/* get the sign and seal algorithms */
- signalg = ptr[0] + (ptr[1] << 8);
+ signalg = ptr[2] + (ptr[3] << 8);
if (signalg != SGN_ALG_DES_MAC_MD5)
return GSS_S_DEFECTIVE_TOKEN;
- sealalg = ptr[2] + (ptr[3] << 8);
+ sealalg = ptr[4] + (ptr[5] << 8);
if (sealalg != SEAL_ALG_DES)
return GSS_S_DEFECTIVE_TOKEN;
- if ((ptr[4] != 0xff) || (ptr[5] != 0xff))
+ if ((ptr[6] != 0xff) || (ptr[7] != 0xff))
return GSS_S_DEFECTIVE_TOKEN;
if (gss_decrypt_xdr_buf(kctx->enc, buf,
- ptr + 22 - (unsigned char *)buf->head[0].iov_base))
+ ptr + GSS_KRB5_TOK_HDR_LEN + 8 - (unsigned char *)buf->head[0].iov_base))
return GSS_S_DEFECTIVE_TOKEN;
- if (make_checksum("md5", ptr - 2, 8, buf,
- ptr + 22 - (unsigned char *)buf->head[0].iov_base, &md5cksum))
+ if (make_checksum("md5", ptr, 8, buf,
+ ptr + GSS_KRB5_TOK_HDR_LEN + 8 - (unsigned char *)buf->head[0].iov_base, &md5cksum))
return GSS_S_FAILURE;
if (krb5_encrypt(kctx->seq, NULL, md5cksum.data,
md5cksum.data, md5cksum.len))
return GSS_S_FAILURE;
- if (memcmp(md5cksum.data + 8, ptr + 14, 8))
+ if (memcmp(md5cksum.data + 8, ptr + GSS_KRB5_TOK_HDR_LEN, 8))
return GSS_S_BAD_SIG;
/* it got through unscathed. Make sure the context is unexpired */
@@ -262,8 +275,8 @@ gss_unwrap_kerberos(struct gss_ctx *ctx, int offset, struct xdr_buf *buf)
/* do sequencing checks */
- if (krb5_get_seq_num(kctx->seq, ptr + 14, ptr + 6, &direction,
- &seqnum))
+ if (krb5_get_seq_num(kctx->seq, ptr + GSS_KRB5_TOK_HDR_LEN, ptr + 8,
+ &direction, &seqnum))
return GSS_S_BAD_SIG;
if ((kctx->initiate && direction != 0xff) ||
@@ -274,7 +287,7 @@ gss_unwrap_kerberos(struct gss_ctx *ctx, int offset, struct xdr_buf *buf)
* better to copy and encrypt at the same time. */
blocksize = crypto_blkcipher_blocksize(kctx->enc);
- data_start = ptr + 22 + blocksize;
+ data_start = ptr + GSS_KRB5_TOK_HDR_LEN + 8 + blocksize;
orig_start = buf->head[0].iov_base + offset;
data_len = (buf->head[0].iov_base + buf->head[0].iov_len) - data_start;
memmove(orig_start, data_start, data_len);
diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c
index bce9d527af08..3cfc197b6a36 100644
--- a/net/sunrpc/auth_gss/gss_mech_switch.c
+++ b/net/sunrpc/auth_gss/gss_mech_switch.c
@@ -285,6 +285,20 @@ gss_verify_mic(struct gss_ctx *context_handle,
mic_token);
}
+/*
+ * This function is called from both the client and server code.
+ * Each makes guarantees about how much "slack" space is available
+ * for the underlying function in "buf"'s head and tail while
+ * performing the wrap.
+ *
+ * The client and server code allocate RPC_MAX_AUTH_SIZE extra
+ * space in both the head and tail which is available for use by
+ * the wrap function.
+ *
+ * Underlying functions should verify they do not use more than
+ * RPC_MAX_AUTH_SIZE of extra space in either the head or tail
+ * when performing the wrap.
+ */
u32
gss_wrap(struct gss_ctx *ctx_id,
int offset,
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index 5905d56737d6..675adeb10df4 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -1287,6 +1287,14 @@ svcauth_gss_wrap_resp_priv(struct svc_rqst *rqstp)
inpages = resbuf->pages;
/* XXX: Would be better to write some xdr helper functions for
* nfs{2,3,4}xdr.c that place the data right, instead of copying: */
+
+ /*
+ * If there is currently tail data, make sure there is
+ * room for the head, tail, and 2 * RPC_MAX_AUTH_SIZE in
+ * the page, and move the current tail data such that
+ * there is RPC_MAX_AUTH_SIZE slack space available in
+ * both the head and tail.
+ */
if (resbuf->tail[0].iov_base) {
BUG_ON(resbuf->tail[0].iov_base >= resbuf->head[0].iov_base
+ PAGE_SIZE);
@@ -1299,6 +1307,13 @@ svcauth_gss_wrap_resp_priv(struct svc_rqst *rqstp)
resbuf->tail[0].iov_len);
resbuf->tail[0].iov_base += RPC_MAX_AUTH_SIZE;
}
+ /*
+ * If there is no current tail data, make sure there is
+ * room for the head data, and 2 * RPC_MAX_AUTH_SIZE in the
+ * allotted page, and set up tail information such that there
+ * is RPC_MAX_AUTH_SIZE slack space available in both the
+ * head and tail.
+ */
if (resbuf->tail[0].iov_base == NULL) {
if (resbuf->head[0].iov_len + 2*RPC_MAX_AUTH_SIZE > PAGE_SIZE)
return -ENOMEM;
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 01c7e311b904..5a32cb7c4bb4 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -18,6 +18,7 @@
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/module.h>
+#include <linux/kthread.h>
#include <linux/sunrpc/types.h>
#include <linux/sunrpc/xdr.h>
@@ -291,15 +292,14 @@ svc_pool_map_put(void)
/*
- * Set the current thread's cpus_allowed mask so that it
+ * Set the given thread's cpus_allowed mask so that it
* will only run on cpus in the given pool.
- *
- * Returns 1 and fills in oldmask iff a cpumask was applied.
*/
-static inline int
-svc_pool_map_set_cpumask(unsigned int pidx, cpumask_t *oldmask)
+static inline void
+svc_pool_map_set_cpumask(struct task_struct *task, unsigned int pidx)
{
struct svc_pool_map *m = &svc_pool_map;
+ unsigned int node = m->pool_to[pidx];
/*
* The caller checks for sv_nrpools > 1, which
@@ -307,26 +307,17 @@ svc_pool_map_set_cpumask(unsigned int pidx, cpumask_t *oldmask)
*/
BUG_ON(m->count == 0);
- switch (m->mode)
- {
- default:
- return 0;
+ switch (m->mode) {
case SVC_POOL_PERCPU:
{
- unsigned int cpu = m->pool_to[pidx];
-
- *oldmask = current->cpus_allowed;
- set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
- return 1;
+ set_cpus_allowed_ptr(task, &cpumask_of_cpu(node));
+ break;
}
case SVC_POOL_PERNODE:
{
- unsigned int node = m->pool_to[pidx];
node_to_cpumask_ptr(nodecpumask, node);
-
- *oldmask = current->cpus_allowed;
- set_cpus_allowed_ptr(current, nodecpumask);
- return 1;
+ set_cpus_allowed_ptr(task, nodecpumask);
+ break;
}
}
}
@@ -443,7 +434,7 @@ EXPORT_SYMBOL(svc_create);
struct svc_serv *
svc_create_pooled(struct svc_program *prog, unsigned int bufsize,
void (*shutdown)(struct svc_serv *serv),
- svc_thread_fn func, int sig, struct module *mod)
+ svc_thread_fn func, struct module *mod)
{
struct svc_serv *serv;
unsigned int npools = svc_pool_map_get();
@@ -452,7 +443,6 @@ svc_create_pooled(struct svc_program *prog, unsigned int bufsize,
if (serv != NULL) {
serv->sv_function = func;
- serv->sv_kill_signal = sig;
serv->sv_module = mod;
}
@@ -461,7 +451,8 @@ svc_create_pooled(struct svc_program *prog, unsigned int bufsize,
EXPORT_SYMBOL(svc_create_pooled);
/*
- * Destroy an RPC service. Should be called with the BKL held
+ * Destroy an RPC service. Should be called with appropriate locking to
+ * protect the sv_nrthreads, sv_permsocks and sv_tempsocks.
*/
void
svc_destroy(struct svc_serv *serv)
@@ -578,46 +569,6 @@ out_enomem:
EXPORT_SYMBOL(svc_prepare_thread);
/*
- * Create a thread in the given pool. Caller must hold BKL.
- * On a NUMA or SMP machine, with a multi-pool serv, the thread
- * will be restricted to run on the cpus belonging to the pool.
- */
-static int
-__svc_create_thread(svc_thread_fn func, struct svc_serv *serv,
- struct svc_pool *pool)
-{
- struct svc_rqst *rqstp;
- int error = -ENOMEM;
- int have_oldmask = 0;
- cpumask_t uninitialized_var(oldmask);
-
- rqstp = svc_prepare_thread(serv, pool);
- if (IS_ERR(rqstp)) {
- error = PTR_ERR(rqstp);
- goto out;
- }
-
- if (serv->sv_nrpools > 1)
- have_oldmask = svc_pool_map_set_cpumask(pool->sp_id, &oldmask);
-
- error = kernel_thread((int (*)(void *)) func, rqstp, 0);
-
- if (have_oldmask)
- set_cpus_allowed(current, oldmask);
-
- if (error < 0)
- goto out_thread;
- svc_sock_update_bufs(serv);
- error = 0;
-out:
- return error;
-
-out_thread:
- svc_exit_thread(rqstp);
- goto out;
-}
-
-/*
* Choose a pool in which to create a new thread, for svc_set_num_threads
*/
static inline struct svc_pool *
@@ -674,7 +625,7 @@ found_pool:
* of threads the given number. If `pool' is non-NULL, applies
* only to threads in that pool, otherwise round-robins between
* all pools. Must be called with a svc_get() reference and
- * the BKL held.
+ * the BKL or another lock to protect access to svc_serv fields.
*
* Destroying threads relies on the service threads filling in
* rqstp->rq_task, which only the nfs ones do. Assumes the serv
@@ -686,7 +637,9 @@ found_pool:
int
svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
{
- struct task_struct *victim;
+ struct svc_rqst *rqstp;
+ struct task_struct *task;
+ struct svc_pool *chosen_pool;
int error = 0;
unsigned int state = serv->sv_nrthreads-1;
@@ -702,18 +655,34 @@ svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
/* create new threads */
while (nrservs > 0) {
nrservs--;
+ chosen_pool = choose_pool(serv, pool, &state);
+
+ rqstp = svc_prepare_thread(serv, chosen_pool);
+ if (IS_ERR(rqstp)) {
+ error = PTR_ERR(rqstp);
+ break;
+ }
+
__module_get(serv->sv_module);
- error = __svc_create_thread(serv->sv_function, serv,
- choose_pool(serv, pool, &state));
- if (error < 0) {
+ task = kthread_create(serv->sv_function, rqstp, serv->sv_name);
+ if (IS_ERR(task)) {
+ error = PTR_ERR(task);
module_put(serv->sv_module);
+ svc_exit_thread(rqstp);
break;
}
+
+ rqstp->rq_task = task;
+ if (serv->sv_nrpools > 1)
+ svc_pool_map_set_cpumask(task, chosen_pool->sp_id);
+
+ svc_sock_update_bufs(serv);
+ wake_up_process(task);
}
/* destroy old threads */
while (nrservs < 0 &&
- (victim = choose_victim(serv, pool, &state)) != NULL) {
- send_sig(serv->sv_kill_signal, victim, 1);
+ (task = choose_victim(serv, pool, &state)) != NULL) {
+ send_sig(SIGINT, task, 1);
nrservs++;
}
@@ -722,7 +691,8 @@ svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
EXPORT_SYMBOL(svc_set_num_threads);
/*
- * Called from a server thread as it's exiting. Caller must hold BKL.
+ * Called from a server thread as it's exiting. Caller must hold the BKL or
+ * the "service mutex", whichever is appropriate for the service.
*/
void
svc_exit_thread(struct svc_rqst *rqstp)
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
index d8e8d79a8451..e46c825f4954 100644
--- a/net/sunrpc/svc_xprt.c
+++ b/net/sunrpc/svc_xprt.c
@@ -6,30 +6,9 @@
#include <linux/sched.h>
#include <linux/errno.h>
-#include <linux/fcntl.h>
-#include <linux/net.h>
-#include <linux/in.h>
-#include <linux/inet.h>
-#include <linux/udp.h>
-#include <linux/tcp.h>
-#include <linux/unistd.h>
-#include <linux/slab.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <linux/file.h>
#include <linux/freezer.h>
#include <linux/kthread.h>
#include <net/sock.h>
-#include <net/checksum.h>
-#include <net/ip.h>
-#include <net/ipv6.h>
-#include <net/tcp_states.h>
-#include <linux/uaccess.h>
-#include <asm/ioctls.h>
-
-#include <linux/sunrpc/types.h>
-#include <linux/sunrpc/clnt.h>
-#include <linux/sunrpc/xdr.h>
#include <linux/sunrpc/stats.h>
#include <linux/sunrpc/svc_xprt.h>
@@ -296,8 +275,6 @@ void svc_xprt_enqueue(struct svc_xprt *xprt)
if (!(xprt->xpt_flags &
((1<<XPT_CONN)|(1<<XPT_DATA)|(1<<XPT_CLOSE)|(1<<XPT_DEFERRED))))
return;
- if (test_bit(XPT_DEAD, &xprt->xpt_flags))
- return;
cpu = get_cpu();
pool = svc_pool_for_cpu(xprt->xpt_server, cpu);
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index 3f30ee6006ae..f24800f2c098 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -278,7 +278,7 @@ static int ip_map_show(struct seq_file *m,
dom = im->m_client->h.name;
if (ipv6_addr_v4mapped(&addr)) {
- seq_printf(m, "%s" NIPQUAD_FMT "%s\n",
+ seq_printf(m, "%s " NIPQUAD_FMT " %s\n",
im->m_class,
ntohl(addr.s6_addr32[3]) >> 24 & 0xff,
ntohl(addr.s6_addr32[3]) >> 16 & 0xff,
@@ -286,7 +286,7 @@ static int ip_map_show(struct seq_file *m,
ntohl(addr.s6_addr32[3]) >> 0 & 0xff,
dom);
} else {
- seq_printf(m, "%s" NIP6_FMT "%s\n",
+ seq_printf(m, "%s " NIP6_FMT " %s\n",
im->m_class, NIP6(addr), dom);
}
return 0;
diff --git a/net/sunrpc/xprtrdma/svc_rdma.c b/net/sunrpc/xprtrdma/svc_rdma.c
index 88c0ca20bb1e..8a7d34b84e39 100644
--- a/net/sunrpc/xprtrdma/svc_rdma.c
+++ b/net/sunrpc/xprtrdma/svc_rdma.c
@@ -69,6 +69,10 @@ atomic_t rdma_stat_rq_prod;
atomic_t rdma_stat_sq_poll;
atomic_t rdma_stat_sq_prod;
+/* Temporary NFS request map and context caches */
+struct kmem_cache *svc_rdma_map_cachep = NULL;
+struct kmem_cache *svc_rdma_ctxt_cachep = NULL;
+
/*
* This function implements reading and resetting an atomic_t stat
* variable through read/write to a proc file. Any write to the file
@@ -236,11 +240,16 @@ static ctl_table svcrdma_root_table[] = {
void svc_rdma_cleanup(void)
{
dprintk("SVCRDMA Module Removed, deregister RPC RDMA transport\n");
+ flush_scheduled_work();
if (svcrdma_table_header) {
unregister_sysctl_table(svcrdma_table_header);
svcrdma_table_header = NULL;
}
svc_unreg_xprt_class(&svc_rdma_class);
+ if (svc_rdma_map_cachep)
+ kmem_cache_destroy(svc_rdma_map_cachep);
+ if (svc_rdma_ctxt_cachep)
+ kmem_cache_destroy(svc_rdma_ctxt_cachep);
}
int svc_rdma_init(void)
@@ -255,9 +264,40 @@ int svc_rdma_init(void)
svcrdma_table_header =
register_sysctl_table(svcrdma_root_table);
+ /* Create the temporary map cache */
+ svc_rdma_map_cachep = kmem_cache_create("svc_rdma_map_cache",
+ sizeof(struct svc_rdma_req_map),
+ 0,
+ SLAB_HWCACHE_ALIGN,
+ NULL);
+ if (!svc_rdma_map_cachep) {
+ printk(KERN_INFO "Could not allocate map cache.\n");
+ goto err0;
+ }
+
+ /* Create the temporary context cache */
+ svc_rdma_ctxt_cachep =
+ kmem_cache_create("svc_rdma_ctxt_cache",
+ sizeof(struct svc_rdma_op_ctxt),
+ 0,
+ SLAB_HWCACHE_ALIGN,
+ NULL);
+ if (!svc_rdma_ctxt_cachep) {
+ printk(KERN_INFO "Could not allocate WR ctxt cache.\n");
+ goto err1;
+ }
+
/* Register RDMA with the SVC transport switch */
svc_reg_xprt_class(&svc_rdma_class);
return 0;
+ err1:
+ kmem_cache_destroy(svc_rdma_map_cachep);
+ err0:
+ if (svcrdma_table_header) {
+ unregister_sysctl_table(svcrdma_table_header);
+ svcrdma_table_header = NULL;
+ }
+ return -ENOMEM;
}
MODULE_AUTHOR("Tom Tucker <tom@opengridcomputing.com>");
MODULE_DESCRIPTION("SVC RDMA Transport");
diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
index c22d6b6f2db4..b4b17f44cb29 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
@@ -112,11 +112,6 @@ static void rdma_build_arg_xdr(struct svc_rqst *rqstp,
rqstp->rq_arg.tail[0].iov_len = 0;
}
-struct chunk_sge {
- int start; /* sge no for this chunk */
- int count; /* sge count for this chunk */
-};
-
/* Encode a read-chunk-list as an array of IB SGE
*
* Assumptions:
@@ -134,8 +129,8 @@ static int rdma_rcl_to_sge(struct svcxprt_rdma *xprt,
struct svc_rqst *rqstp,
struct svc_rdma_op_ctxt *head,
struct rpcrdma_msg *rmsgp,
- struct ib_sge *sge,
- struct chunk_sge *ch_sge_ary,
+ struct svc_rdma_req_map *rpl_map,
+ struct svc_rdma_req_map *chl_map,
int ch_count,
int byte_count)
{
@@ -156,22 +151,18 @@ static int rdma_rcl_to_sge(struct svcxprt_rdma *xprt,
head->arg.head[0] = rqstp->rq_arg.head[0];
head->arg.tail[0] = rqstp->rq_arg.tail[0];
head->arg.pages = &head->pages[head->count];
- head->sge[0].length = head->count; /* save count of hdr pages */
+ head->hdr_count = head->count; /* save count of hdr pages */
head->arg.page_base = 0;
head->arg.page_len = ch_bytes;
head->arg.len = rqstp->rq_arg.len + ch_bytes;
head->arg.buflen = rqstp->rq_arg.buflen + ch_bytes;
head->count++;
- ch_sge_ary[0].start = 0;
+ chl_map->ch[0].start = 0;
while (byte_count) {
+ rpl_map->sge[sge_no].iov_base =
+ page_address(rqstp->rq_arg.pages[page_no]) + page_off;
sge_bytes = min_t(int, PAGE_SIZE-page_off, ch_bytes);
- sge[sge_no].addr =
- ib_dma_map_page(xprt->sc_cm_id->device,
- rqstp->rq_arg.pages[page_no],
- page_off, sge_bytes,
- DMA_FROM_DEVICE);
- sge[sge_no].length = sge_bytes;
- sge[sge_no].lkey = xprt->sc_phys_mr->lkey;
+ rpl_map->sge[sge_no].iov_len = sge_bytes;
/*
* Don't bump head->count here because the same page
* may be used by multiple SGE.
@@ -187,11 +178,11 @@ static int rdma_rcl_to_sge(struct svcxprt_rdma *xprt,
* SGE, move to the next SGE
*/
if (ch_bytes == 0) {
- ch_sge_ary[ch_no].count =
- sge_no - ch_sge_ary[ch_no].start;
+ chl_map->ch[ch_no].count =
+ sge_no - chl_map->ch[ch_no].start;
ch_no++;
ch++;
- ch_sge_ary[ch_no].start = sge_no;
+ chl_map->ch[ch_no].start = sge_no;
ch_bytes = ch->rc_target.rs_length;
/* If bytes remaining account for next chunk */
if (byte_count) {
@@ -220,18 +211,25 @@ static int rdma_rcl_to_sge(struct svcxprt_rdma *xprt,
return sge_no;
}
-static void rdma_set_ctxt_sge(struct svc_rdma_op_ctxt *ctxt,
- struct ib_sge *sge,
+static void rdma_set_ctxt_sge(struct svcxprt_rdma *xprt,
+ struct svc_rdma_op_ctxt *ctxt,
+ struct kvec *vec,
u64 *sgl_offset,
int count)
{
int i;
ctxt->count = count;
+ ctxt->direction = DMA_FROM_DEVICE;
for (i = 0; i < count; i++) {
- ctxt->sge[i].addr = sge[i].addr;
- ctxt->sge[i].length = sge[i].length;
- *sgl_offset = *sgl_offset + sge[i].length;
+ atomic_inc(&xprt->sc_dma_used);
+ ctxt->sge[i].addr =
+ ib_dma_map_single(xprt->sc_cm_id->device,
+ vec[i].iov_base, vec[i].iov_len,
+ DMA_FROM_DEVICE);
+ ctxt->sge[i].length = vec[i].iov_len;
+ ctxt->sge[i].lkey = xprt->sc_phys_mr->lkey;
+ *sgl_offset = *sgl_offset + vec[i].iov_len;
}
}
@@ -260,11 +258,16 @@ static int rdma_read_max_sge(struct svcxprt_rdma *xprt, int sge_count)
* On our side, we need to read into a pagelist. The first page immediately
* follows the RPC header.
*
- * This function returns 1 to indicate success. The data is not yet in
+ * This function returns:
+ * 0 - No error and no read-list found.
+ *
+ * 1 - Successful read-list processing. The data is not yet in
* the pagelist and therefore the RPC request must be deferred. The
* I/O completion will enqueue the transport again and
* svc_rdma_recvfrom will complete the request.
*
+ * <0 - Error processing/posting read-list.
+ *
* NOTE: The ctxt must not be touched after the last WR has been posted
* because the I/O completion processing may occur on another
* processor and free / modify the context. Ne touche pas!
@@ -277,50 +280,38 @@ static int rdma_read_xdr(struct svcxprt_rdma *xprt,
struct ib_send_wr read_wr;
int err = 0;
int ch_no;
- struct ib_sge *sge;
int ch_count;
int byte_count;
int sge_count;
u64 sgl_offset;
struct rpcrdma_read_chunk *ch;
struct svc_rdma_op_ctxt *ctxt = NULL;
- struct svc_rdma_op_ctxt *head;
- struct svc_rdma_op_ctxt *tmp_sge_ctxt;
- struct svc_rdma_op_ctxt *tmp_ch_ctxt;
- struct chunk_sge *ch_sge_ary;
+ struct svc_rdma_req_map *rpl_map;
+ struct svc_rdma_req_map *chl_map;
/* If no read list is present, return 0 */
ch = svc_rdma_get_read_chunk(rmsgp);
if (!ch)
return 0;
- /* Allocate temporary contexts to keep SGE */
- BUG_ON(sizeof(struct ib_sge) < sizeof(struct chunk_sge));
- tmp_sge_ctxt = svc_rdma_get_context(xprt);
- sge = tmp_sge_ctxt->sge;
- tmp_ch_ctxt = svc_rdma_get_context(xprt);
- ch_sge_ary = (struct chunk_sge *)tmp_ch_ctxt->sge;
+ /* Allocate temporary reply and chunk maps */
+ rpl_map = svc_rdma_get_req_map();
+ chl_map = svc_rdma_get_req_map();
svc_rdma_rcl_chunk_counts(ch, &ch_count, &byte_count);
+ if (ch_count > RPCSVC_MAXPAGES)
+ return -EINVAL;
sge_count = rdma_rcl_to_sge(xprt, rqstp, hdr_ctxt, rmsgp,
- sge, ch_sge_ary,
+ rpl_map, chl_map,
ch_count, byte_count);
- head = svc_rdma_get_context(xprt);
sgl_offset = 0;
ch_no = 0;
for (ch = (struct rpcrdma_read_chunk *)&rmsgp->rm_body.rm_chunks[0];
ch->rc_discrim != 0; ch++, ch_no++) {
next_sge:
- if (!ctxt)
- ctxt = head;
- else {
- ctxt->next = svc_rdma_get_context(xprt);
- ctxt = ctxt->next;
- }
- ctxt->next = NULL;
+ ctxt = svc_rdma_get_context(xprt);
ctxt->direction = DMA_FROM_DEVICE;
- clear_bit(RDMACTXT_F_READ_DONE, &ctxt->flags);
clear_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags);
/* Prepare READ WR */
@@ -333,50 +324,46 @@ next_sge:
read_wr.wr.rdma.remote_addr =
get_unaligned(&(ch->rc_target.rs_offset)) +
sgl_offset;
- read_wr.sg_list = &sge[ch_sge_ary[ch_no].start];
+ read_wr.sg_list = ctxt->sge;
read_wr.num_sge =
- rdma_read_max_sge(xprt, ch_sge_ary[ch_no].count);
- rdma_set_ctxt_sge(ctxt, &sge[ch_sge_ary[ch_no].start],
+ rdma_read_max_sge(xprt, chl_map->ch[ch_no].count);
+ rdma_set_ctxt_sge(xprt, ctxt,
+ &rpl_map->sge[chl_map->ch[ch_no].start],
&sgl_offset,
read_wr.num_sge);
if (((ch+1)->rc_discrim == 0) &&
- (read_wr.num_sge == ch_sge_ary[ch_no].count)) {
+ (read_wr.num_sge == chl_map->ch[ch_no].count)) {
/*
* Mark the last RDMA_READ with a bit to
* indicate all RPC data has been fetched from
* the client and the RPC needs to be enqueued.
*/
set_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags);
- ctxt->next = hdr_ctxt;
- hdr_ctxt->next = head;
+ ctxt->read_hdr = hdr_ctxt;
}
/* Post the read */
err = svc_rdma_send(xprt, &read_wr);
if (err) {
- printk(KERN_ERR "svcrdma: Error posting send = %d\n",
+ printk(KERN_ERR "svcrdma: Error %d posting RDMA_READ\n",
err);
- /*
- * Break the circular list so free knows when
- * to stop if the error happened to occur on
- * the last read
- */
- ctxt->next = NULL;
+ set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
+ svc_rdma_put_context(ctxt, 0);
goto out;
}
atomic_inc(&rdma_stat_read);
- if (read_wr.num_sge < ch_sge_ary[ch_no].count) {
- ch_sge_ary[ch_no].count -= read_wr.num_sge;
- ch_sge_ary[ch_no].start += read_wr.num_sge;
+ if (read_wr.num_sge < chl_map->ch[ch_no].count) {
+ chl_map->ch[ch_no].count -= read_wr.num_sge;
+ chl_map->ch[ch_no].start += read_wr.num_sge;
goto next_sge;
}
sgl_offset = 0;
- err = 0;
+ err = 1;
}
out:
- svc_rdma_put_context(tmp_sge_ctxt, 0);
- svc_rdma_put_context(tmp_ch_ctxt, 0);
+ svc_rdma_put_req_map(rpl_map);
+ svc_rdma_put_req_map(chl_map);
/* Detach arg pages. svc_recv will replenish them */
for (ch_no = 0; &rqstp->rq_pages[ch_no] < rqstp->rq_respages; ch_no++)
@@ -389,25 +376,12 @@ next_sge:
while (rqstp->rq_resused)
rqstp->rq_respages[--rqstp->rq_resused] = NULL;
- if (err) {
- printk(KERN_ERR "svcrdma : RDMA_READ error = %d\n", err);
- set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
- /* Free the linked list of read contexts */
- while (head != NULL) {
- ctxt = head->next;
- svc_rdma_put_context(head, 1);
- head = ctxt;
- }
- return 0;
- }
-
- return 1;
+ return err;
}
static int rdma_read_complete(struct svc_rqst *rqstp,
- struct svc_rdma_op_ctxt *data)
+ struct svc_rdma_op_ctxt *head)
{
- struct svc_rdma_op_ctxt *head = data->next;
int page_no;
int ret;
@@ -419,7 +393,7 @@ static int rdma_read_complete(struct svc_rqst *rqstp,
rqstp->rq_pages[page_no] = head->pages[page_no];
}
/* Point rq_arg.pages past header */
- rqstp->rq_arg.pages = &rqstp->rq_pages[head->sge[0].length];
+ rqstp->rq_arg.pages = &rqstp->rq_pages[head->hdr_count];
rqstp->rq_arg.page_len = head->arg.page_len;
rqstp->rq_arg.page_base = head->arg.page_base;
@@ -433,21 +407,12 @@ static int rdma_read_complete(struct svc_rqst *rqstp,
rqstp->rq_arg.len = head->arg.len;
rqstp->rq_arg.buflen = head->arg.buflen;
+ /* Free the context */
+ svc_rdma_put_context(head, 0);
+
/* XXX: What should this be? */
rqstp->rq_prot = IPPROTO_MAX;
-
- /*
- * Free the contexts we used to build the RDMA_READ. We have
- * to be careful here because the context list uses the same
- * next pointer used to chain the contexts associated with the
- * RDMA_READ
- */
- data->next = NULL; /* terminate circular list */
- do {
- data = head->next;
- svc_rdma_put_context(head, 0);
- head = data;
- } while (head != NULL);
+ svc_xprt_copy_addrs(rqstp, rqstp->rq_xprt);
ret = rqstp->rq_arg.head[0].iov_len
+ rqstp->rq_arg.page_len
@@ -457,8 +422,6 @@ static int rdma_read_complete(struct svc_rqst *rqstp,
ret, rqstp->rq_arg.len, rqstp->rq_arg.head[0].iov_base,
rqstp->rq_arg.head[0].iov_len);
- /* Indicate that we've consumed an RQ credit */
- rqstp->rq_xprt_ctxt = rqstp->rq_xprt;
svc_xprt_received(rqstp->rq_xprt);
return ret;
}
@@ -480,13 +443,6 @@ int svc_rdma_recvfrom(struct svc_rqst *rqstp)
dprintk("svcrdma: rqstp=%p\n", rqstp);
- /*
- * The rq_xprt_ctxt indicates if we've consumed an RQ credit
- * or not. It is used in the rdma xpo_release_rqst function to
- * determine whether or not to return an RQ WQE to the RQ.
- */
- rqstp->rq_xprt_ctxt = NULL;
-
spin_lock_bh(&rdma_xprt->sc_read_complete_lock);
if (!list_empty(&rdma_xprt->sc_read_complete_q)) {
ctxt = list_entry(rdma_xprt->sc_read_complete_q.next,
@@ -537,21 +493,22 @@ int svc_rdma_recvfrom(struct svc_rqst *rqstp)
/* If the request is invalid, reply with an error */
if (len < 0) {
if (len == -ENOSYS)
- (void)svc_rdma_send_error(rdma_xprt, rmsgp, ERR_VERS);
+ svc_rdma_send_error(rdma_xprt, rmsgp, ERR_VERS);
goto close_out;
}
- /* Read read-list data. If we would need to wait, defer
- * it. Not that in this case, we don't return the RQ credit
- * until after the read completes.
- */
- if (rdma_read_xdr(rdma_xprt, rmsgp, rqstp, ctxt)) {
+ /* Read read-list data. */
+ ret = rdma_read_xdr(rdma_xprt, rmsgp, rqstp, ctxt);
+ if (ret > 0) {
+ /* read-list posted, defer until data received from client. */
svc_xprt_received(xprt);
return 0;
}
-
- /* Indicate we've consumed an RQ credit */
- rqstp->rq_xprt_ctxt = rqstp->rq_xprt;
+ if (ret < 0) {
+ /* Post of read-list failed, free context. */
+ svc_rdma_put_context(ctxt, 1);
+ return 0;
+ }
ret = rqstp->rq_arg.head[0].iov_len
+ rqstp->rq_arg.page_len
@@ -569,11 +526,8 @@ int svc_rdma_recvfrom(struct svc_rqst *rqstp)
return ret;
close_out:
- if (ctxt) {
+ if (ctxt)
svc_rdma_put_context(ctxt, 1);
- /* Indicate we've consumed an RQ credit */
- rqstp->rq_xprt_ctxt = rqstp->rq_xprt;
- }
dprintk("svcrdma: transport %p is closing\n", xprt);
/*
* Set the close bit and enqueue it. svc_recv will see the
diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
index 981f190c1b39..015ac988a149 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
@@ -64,10 +64,9 @@
* SGE[sge_count-1] data from xdr->tail.
*
*/
-static struct ib_sge *xdr_to_sge(struct svcxprt_rdma *xprt,
- struct xdr_buf *xdr,
- struct ib_sge *sge,
- int *sge_count)
+static void xdr_to_sge(struct svcxprt_rdma *xprt,
+ struct xdr_buf *xdr,
+ struct svc_rdma_req_map *vec)
{
/* Max we need is the length of the XDR / pagesize + one for
* head + one for tail + one for RPCRDMA header
@@ -84,14 +83,10 @@ static struct ib_sge *xdr_to_sge(struct svcxprt_rdma *xprt,
sge_no = 1;
/* Head SGE */
- sge[sge_no].addr = ib_dma_map_single(xprt->sc_cm_id->device,
- xdr->head[0].iov_base,
- xdr->head[0].iov_len,
- DMA_TO_DEVICE);
+ vec->sge[sge_no].iov_base = xdr->head[0].iov_base;
sge_bytes = min_t(u32, byte_count, xdr->head[0].iov_len);
byte_count -= sge_bytes;
- sge[sge_no].length = sge_bytes;
- sge[sge_no].lkey = xprt->sc_phys_mr->lkey;
+ vec->sge[sge_no].iov_len = sge_bytes;
sge_no++;
/* pages SGE */
@@ -99,16 +94,13 @@ static struct ib_sge *xdr_to_sge(struct svcxprt_rdma *xprt,
page_bytes = xdr->page_len;
page_off = xdr->page_base;
while (byte_count && page_bytes) {
+ vec->sge[sge_no].iov_base =
+ page_address(xdr->pages[page_no]) + page_off;
sge_bytes = min_t(u32, byte_count, (PAGE_SIZE-page_off));
- sge[sge_no].addr =
- ib_dma_map_page(xprt->sc_cm_id->device,
- xdr->pages[page_no], page_off,
- sge_bytes, DMA_TO_DEVICE);
sge_bytes = min(sge_bytes, page_bytes);
byte_count -= sge_bytes;
page_bytes -= sge_bytes;
- sge[sge_no].length = sge_bytes;
- sge[sge_no].lkey = xprt->sc_phys_mr->lkey;
+ vec->sge[sge_no].iov_len = sge_bytes;
sge_no++;
page_no++;
@@ -117,23 +109,17 @@ static struct ib_sge *xdr_to_sge(struct svcxprt_rdma *xprt,
/* Tail SGE */
if (byte_count && xdr->tail[0].iov_len) {
- sge[sge_no].addr =
- ib_dma_map_single(xprt->sc_cm_id->device,
- xdr->tail[0].iov_base,
- xdr->tail[0].iov_len,
- DMA_TO_DEVICE);
+ vec->sge[sge_no].iov_base = xdr->tail[0].iov_base;
sge_bytes = min_t(u32, byte_count, xdr->tail[0].iov_len);
byte_count -= sge_bytes;
- sge[sge_no].length = sge_bytes;
- sge[sge_no].lkey = xprt->sc_phys_mr->lkey;
+ vec->sge[sge_no].iov_len = sge_bytes;
sge_no++;
}
BUG_ON(sge_no > sge_max);
BUG_ON(byte_count != 0);
- *sge_count = sge_no;
- return sge;
+ vec->count = sge_no;
}
@@ -143,9 +129,8 @@ static struct ib_sge *xdr_to_sge(struct svcxprt_rdma *xprt,
static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp,
u32 rmr, u64 to,
u32 xdr_off, int write_len,
- struct ib_sge *xdr_sge, int sge_count)
+ struct svc_rdma_req_map *vec)
{
- struct svc_rdma_op_ctxt *tmp_sge_ctxt;
struct ib_send_wr write_wr;
struct ib_sge *sge;
int xdr_sge_no;
@@ -156,23 +141,22 @@ static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp,
struct svc_rdma_op_ctxt *ctxt;
int ret = 0;
- BUG_ON(sge_count > RPCSVC_MAXPAGES);
+ BUG_ON(vec->count > RPCSVC_MAXPAGES);
dprintk("svcrdma: RDMA_WRITE rmr=%x, to=%llx, xdr_off=%d, "
- "write_len=%d, xdr_sge=%p, sge_count=%d\n",
+ "write_len=%d, vec->sge=%p, vec->count=%lu\n",
rmr, (unsigned long long)to, xdr_off,
- write_len, xdr_sge, sge_count);
+ write_len, vec->sge, vec->count);
ctxt = svc_rdma_get_context(xprt);
- ctxt->count = 0;
- tmp_sge_ctxt = svc_rdma_get_context(xprt);
- sge = tmp_sge_ctxt->sge;
+ ctxt->direction = DMA_TO_DEVICE;
+ sge = ctxt->sge;
/* Find the SGE associated with xdr_off */
- for (bc = xdr_off, xdr_sge_no = 1; bc && xdr_sge_no < sge_count;
+ for (bc = xdr_off, xdr_sge_no = 1; bc && xdr_sge_no < vec->count;
xdr_sge_no++) {
- if (xdr_sge[xdr_sge_no].length > bc)
+ if (vec->sge[xdr_sge_no].iov_len > bc)
break;
- bc -= xdr_sge[xdr_sge_no].length;
+ bc -= vec->sge[xdr_sge_no].iov_len;
}
sge_off = bc;
@@ -180,21 +164,28 @@ static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp,
sge_no = 0;
/* Copy the remaining SGE */
- while (bc != 0 && xdr_sge_no < sge_count) {
- sge[sge_no].addr = xdr_sge[xdr_sge_no].addr + sge_off;
- sge[sge_no].lkey = xdr_sge[xdr_sge_no].lkey;
+ while (bc != 0 && xdr_sge_no < vec->count) {
+ sge[sge_no].lkey = xprt->sc_phys_mr->lkey;
sge_bytes = min((size_t)bc,
- (size_t)(xdr_sge[xdr_sge_no].length-sge_off));
+ (size_t)(vec->sge[xdr_sge_no].iov_len-sge_off));
sge[sge_no].length = sge_bytes;
-
+ atomic_inc(&xprt->sc_dma_used);
+ sge[sge_no].addr =
+ ib_dma_map_single(xprt->sc_cm_id->device,
+ (void *)
+ vec->sge[xdr_sge_no].iov_base + sge_off,
+ sge_bytes, DMA_TO_DEVICE);
+ if (dma_mapping_error(sge[sge_no].addr))
+ return -EINVAL;
sge_off = 0;
sge_no++;
+ ctxt->count++;
xdr_sge_no++;
bc -= sge_bytes;
}
BUG_ON(bc != 0);
- BUG_ON(xdr_sge_no > sge_count);
+ BUG_ON(xdr_sge_no > vec->count);
/* Prepare WRITE WR */
memset(&write_wr, 0, sizeof write_wr);
@@ -210,11 +201,10 @@ static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp,
/* Post It */
atomic_inc(&rdma_stat_write);
if (svc_rdma_send(xprt, &write_wr)) {
- svc_rdma_put_context(ctxt, 1);
+ svc_rdma_put_context(ctxt, 0);
/* Fatal error, close transport */
ret = -EIO;
}
- svc_rdma_put_context(tmp_sge_ctxt, 0);
return ret;
}
@@ -222,8 +212,7 @@ static int send_write_chunks(struct svcxprt_rdma *xprt,
struct rpcrdma_msg *rdma_argp,
struct rpcrdma_msg *rdma_resp,
struct svc_rqst *rqstp,
- struct ib_sge *sge,
- int sge_count)
+ struct svc_rdma_req_map *vec)
{
u32 xfer_len = rqstp->rq_res.page_len + rqstp->rq_res.tail[0].iov_len;
int write_len;
@@ -269,8 +258,7 @@ static int send_write_chunks(struct svcxprt_rdma *xprt,
rs_offset + chunk_off,
xdr_off,
this_write,
- sge,
- sge_count);
+ vec);
if (ret) {
dprintk("svcrdma: RDMA_WRITE failed, ret=%d\n",
ret);
@@ -292,8 +280,7 @@ static int send_reply_chunks(struct svcxprt_rdma *xprt,
struct rpcrdma_msg *rdma_argp,
struct rpcrdma_msg *rdma_resp,
struct svc_rqst *rqstp,
- struct ib_sge *sge,
- int sge_count)
+ struct svc_rdma_req_map *vec)
{
u32 xfer_len = rqstp->rq_res.len;
int write_len;
@@ -341,8 +328,7 @@ static int send_reply_chunks(struct svcxprt_rdma *xprt,
rs_offset + chunk_off,
xdr_off,
this_write,
- sge,
- sge_count);
+ vec);
if (ret) {
dprintk("svcrdma: RDMA_WRITE failed, ret=%d\n",
ret);
@@ -380,7 +366,7 @@ static int send_reply(struct svcxprt_rdma *rdma,
struct page *page,
struct rpcrdma_msg *rdma_resp,
struct svc_rdma_op_ctxt *ctxt,
- int sge_count,
+ struct svc_rdma_req_map *vec,
int byte_count)
{
struct ib_send_wr send_wr;
@@ -389,11 +375,23 @@ static int send_reply(struct svcxprt_rdma *rdma,
int page_no;
int ret;
+ /* Post a recv buffer to handle another request. */
+ ret = svc_rdma_post_recv(rdma);
+ if (ret) {
+ printk(KERN_INFO
+ "svcrdma: could not post a receive buffer, err=%d."
+ "Closing transport %p.\n", ret, rdma);
+ set_bit(XPT_CLOSE, &rdma->sc_xprt.xpt_flags);
+ svc_rdma_put_context(ctxt, 0);
+ return -ENOTCONN;
+ }
+
/* Prepare the context */
ctxt->pages[0] = page;
ctxt->count = 1;
/* Prepare the SGE for the RPCRDMA Header */
+ atomic_inc(&rdma->sc_dma_used);
ctxt->sge[0].addr =
ib_dma_map_page(rdma->sc_cm_id->device,
page, 0, PAGE_SIZE, DMA_TO_DEVICE);
@@ -402,10 +400,16 @@ static int send_reply(struct svcxprt_rdma *rdma,
ctxt->sge[0].lkey = rdma->sc_phys_mr->lkey;
/* Determine how many of our SGE are to be transmitted */
- for (sge_no = 1; byte_count && sge_no < sge_count; sge_no++) {
- sge_bytes = min((size_t)ctxt->sge[sge_no].length,
- (size_t)byte_count);
+ for (sge_no = 1; byte_count && sge_no < vec->count; sge_no++) {
+ sge_bytes = min_t(size_t, vec->sge[sge_no].iov_len, byte_count);
byte_count -= sge_bytes;
+ atomic_inc(&rdma->sc_dma_used);
+ ctxt->sge[sge_no].addr =
+ ib_dma_map_single(rdma->sc_cm_id->device,
+ vec->sge[sge_no].iov_base,
+ sge_bytes, DMA_TO_DEVICE);
+ ctxt->sge[sge_no].length = sge_bytes;
+ ctxt->sge[sge_no].lkey = rdma->sc_phys_mr->lkey;
}
BUG_ON(byte_count != 0);
@@ -417,8 +421,10 @@ static int send_reply(struct svcxprt_rdma *rdma,
ctxt->pages[page_no+1] = rqstp->rq_respages[page_no];
ctxt->count++;
rqstp->rq_respages[page_no] = NULL;
+ /* If there are more pages than SGE, terminate SGE list */
+ if (page_no+1 >= sge_no)
+ ctxt->sge[page_no+1].length = 0;
}
-
BUG_ON(sge_no > rdma->sc_max_sge);
memset(&send_wr, 0, sizeof send_wr);
ctxt->wr_op = IB_WR_SEND;
@@ -462,20 +468,20 @@ int svc_rdma_sendto(struct svc_rqst *rqstp)
enum rpcrdma_proc reply_type;
int ret;
int inline_bytes;
- struct ib_sge *sge;
- int sge_count = 0;
struct page *res_page;
struct svc_rdma_op_ctxt *ctxt;
+ struct svc_rdma_req_map *vec;
dprintk("svcrdma: sending response for rqstp=%p\n", rqstp);
/* Get the RDMA request header. */
rdma_argp = xdr_start(&rqstp->rq_arg);
- /* Build an SGE for the XDR */
+ /* Build an req vec for the XDR */
ctxt = svc_rdma_get_context(rdma);
ctxt->direction = DMA_TO_DEVICE;
- sge = xdr_to_sge(rdma, &rqstp->rq_res, ctxt->sge, &sge_count);
+ vec = svc_rdma_get_req_map();
+ xdr_to_sge(rdma, &rqstp->rq_res, vec);
inline_bytes = rqstp->rq_res.len;
@@ -492,7 +498,7 @@ int svc_rdma_sendto(struct svc_rqst *rqstp)
/* Send any write-chunk data and build resp write-list */
ret = send_write_chunks(rdma, rdma_argp, rdma_resp,
- rqstp, sge, sge_count);
+ rqstp, vec);
if (ret < 0) {
printk(KERN_ERR "svcrdma: failed to send write chunks, rc=%d\n",
ret);
@@ -502,7 +508,7 @@ int svc_rdma_sendto(struct svc_rqst *rqstp)
/* Send any reply-list data and update resp reply-list */
ret = send_reply_chunks(rdma, rdma_argp, rdma_resp,
- rqstp, sge, sge_count);
+ rqstp, vec);
if (ret < 0) {
printk(KERN_ERR "svcrdma: failed to send reply chunks, rc=%d\n",
ret);
@@ -510,11 +516,13 @@ int svc_rdma_sendto(struct svc_rqst *rqstp)
}
inline_bytes -= ret;
- ret = send_reply(rdma, rqstp, res_page, rdma_resp, ctxt, sge_count,
+ ret = send_reply(rdma, rqstp, res_page, rdma_resp, ctxt, vec,
inline_bytes);
+ svc_rdma_put_req_map(vec);
dprintk("svcrdma: send_reply returns %d\n", ret);
return ret;
error:
+ svc_rdma_put_req_map(vec);
svc_rdma_put_context(ctxt, 0);
put_page(res_page);
return ret;
diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c
index af408fc12634..19ddc382b777 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c
@@ -84,67 +84,37 @@ struct svc_xprt_class svc_rdma_class = {
.xcl_max_payload = RPCSVC_MAXPAYLOAD_TCP,
};
-static int rdma_bump_context_cache(struct svcxprt_rdma *xprt)
+/* WR context cache. Created in svc_rdma.c */
+extern struct kmem_cache *svc_rdma_ctxt_cachep;
+
+struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *xprt)
{
- int target;
- int at_least_one = 0;
struct svc_rdma_op_ctxt *ctxt;
- target = min(xprt->sc_ctxt_cnt + xprt->sc_ctxt_bump,
- xprt->sc_ctxt_max);
-
- spin_lock_bh(&xprt->sc_ctxt_lock);
- while (xprt->sc_ctxt_cnt < target) {
- xprt->sc_ctxt_cnt++;
- spin_unlock_bh(&xprt->sc_ctxt_lock);
-
- ctxt = kmalloc(sizeof(*ctxt), GFP_KERNEL);
-
- spin_lock_bh(&xprt->sc_ctxt_lock);
- if (ctxt) {
- at_least_one = 1;
- ctxt->next = xprt->sc_ctxt_head;
- xprt->sc_ctxt_head = ctxt;
- } else {
- /* kmalloc failed...give up for now */
- xprt->sc_ctxt_cnt--;
+ while (1) {
+ ctxt = kmem_cache_alloc(svc_rdma_ctxt_cachep, GFP_KERNEL);
+ if (ctxt)
break;
- }
+ schedule_timeout_uninterruptible(msecs_to_jiffies(500));
}
- spin_unlock_bh(&xprt->sc_ctxt_lock);
- dprintk("svcrdma: sc_ctxt_max=%d, sc_ctxt_cnt=%d\n",
- xprt->sc_ctxt_max, xprt->sc_ctxt_cnt);
- return at_least_one;
+ ctxt->xprt = xprt;
+ INIT_LIST_HEAD(&ctxt->dto_q);
+ ctxt->count = 0;
+ atomic_inc(&xprt->sc_ctxt_used);
+ return ctxt;
}
-struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *xprt)
+static void svc_rdma_unmap_dma(struct svc_rdma_op_ctxt *ctxt)
{
- struct svc_rdma_op_ctxt *ctxt;
-
- while (1) {
- spin_lock_bh(&xprt->sc_ctxt_lock);
- if (unlikely(xprt->sc_ctxt_head == NULL)) {
- /* Try to bump my cache. */
- spin_unlock_bh(&xprt->sc_ctxt_lock);
-
- if (rdma_bump_context_cache(xprt))
- continue;
-
- printk(KERN_INFO "svcrdma: sleeping waiting for "
- "context memory on xprt=%p\n",
- xprt);
- schedule_timeout_uninterruptible(msecs_to_jiffies(500));
- continue;
- }
- ctxt = xprt->sc_ctxt_head;
- xprt->sc_ctxt_head = ctxt->next;
- spin_unlock_bh(&xprt->sc_ctxt_lock);
- ctxt->xprt = xprt;
- INIT_LIST_HEAD(&ctxt->dto_q);
- ctxt->count = 0;
- break;
+ struct svcxprt_rdma *xprt = ctxt->xprt;
+ int i;
+ for (i = 0; i < ctxt->count && ctxt->sge[i].length; i++) {
+ atomic_dec(&xprt->sc_dma_used);
+ ib_dma_unmap_single(xprt->sc_cm_id->device,
+ ctxt->sge[i].addr,
+ ctxt->sge[i].length,
+ ctxt->direction);
}
- return ctxt;
}
void svc_rdma_put_context(struct svc_rdma_op_ctxt *ctxt, int free_pages)
@@ -158,15 +128,34 @@ void svc_rdma_put_context(struct svc_rdma_op_ctxt *ctxt, int free_pages)
for (i = 0; i < ctxt->count; i++)
put_page(ctxt->pages[i]);
- for (i = 0; i < ctxt->count; i++)
- dma_unmap_single(xprt->sc_cm_id->device->dma_device,
- ctxt->sge[i].addr,
- ctxt->sge[i].length,
- ctxt->direction);
- spin_lock_bh(&xprt->sc_ctxt_lock);
- ctxt->next = xprt->sc_ctxt_head;
- xprt->sc_ctxt_head = ctxt;
- spin_unlock_bh(&xprt->sc_ctxt_lock);
+ kmem_cache_free(svc_rdma_ctxt_cachep, ctxt);
+ atomic_dec(&xprt->sc_ctxt_used);
+}
+
+/* Temporary NFS request map cache. Created in svc_rdma.c */
+extern struct kmem_cache *svc_rdma_map_cachep;
+
+/*
+ * Temporary NFS req mappings are shared across all transport
+ * instances. These are short lived and should be bounded by the number
+ * of concurrent server threads * depth of the SQ.
+ */
+struct svc_rdma_req_map *svc_rdma_get_req_map(void)
+{
+ struct svc_rdma_req_map *map;
+ while (1) {
+ map = kmem_cache_alloc(svc_rdma_map_cachep, GFP_KERNEL);
+ if (map)
+ break;
+ schedule_timeout_uninterruptible(msecs_to_jiffies(500));
+ }
+ map->count = 0;
+ return map;
+}
+
+void svc_rdma_put_req_map(struct svc_rdma_req_map *map)
+{
+ kmem_cache_free(svc_rdma_map_cachep, map);
}
/* ib_cq event handler */
@@ -228,23 +217,8 @@ static void dto_tasklet_func(unsigned long data)
list_del_init(&xprt->sc_dto_q);
spin_unlock_irqrestore(&dto_lock, flags);
- if (test_and_clear_bit(RDMAXPRT_RQ_PENDING, &xprt->sc_flags)) {
- ib_req_notify_cq(xprt->sc_rq_cq, IB_CQ_NEXT_COMP);
- rq_cq_reap(xprt);
- set_bit(XPT_DATA, &xprt->sc_xprt.xpt_flags);
- /*
- * If data arrived before established event,
- * don't enqueue. This defers RPC I/O until the
- * RDMA connection is complete.
- */
- if (!test_bit(RDMAXPRT_CONN_PENDING, &xprt->sc_flags))
- svc_xprt_enqueue(&xprt->sc_xprt);
- }
-
- if (test_and_clear_bit(RDMAXPRT_SQ_PENDING, &xprt->sc_flags)) {
- ib_req_notify_cq(xprt->sc_sq_cq, IB_CQ_NEXT_COMP);
- sq_cq_reap(xprt);
- }
+ rq_cq_reap(xprt);
+ sq_cq_reap(xprt);
svc_xprt_put(&xprt->sc_xprt);
spin_lock_irqsave(&dto_lock, flags);
@@ -263,11 +237,15 @@ static void rq_comp_handler(struct ib_cq *cq, void *cq_context)
struct svcxprt_rdma *xprt = cq_context;
unsigned long flags;
+ /* Guard against unconditional flush call for destroyed QP */
+ if (atomic_read(&xprt->sc_xprt.xpt_ref.refcount)==0)
+ return;
+
/*
* Set the bit regardless of whether or not it's on the list
* because it may be on the list already due to an SQ
* completion.
- */
+ */
set_bit(RDMAXPRT_RQ_PENDING, &xprt->sc_flags);
/*
@@ -290,6 +268,8 @@ static void rq_comp_handler(struct ib_cq *cq, void *cq_context)
*
* Take all completing WC off the CQE and enqueue the associated DTO
* context on the dto_q for the transport.
+ *
+ * Note that caller must hold a transport reference.
*/
static void rq_cq_reap(struct svcxprt_rdma *xprt)
{
@@ -297,29 +277,48 @@ static void rq_cq_reap(struct svcxprt_rdma *xprt)
struct ib_wc wc;
struct svc_rdma_op_ctxt *ctxt = NULL;
+ if (!test_and_clear_bit(RDMAXPRT_RQ_PENDING, &xprt->sc_flags))
+ return;
+
+ ib_req_notify_cq(xprt->sc_rq_cq, IB_CQ_NEXT_COMP);
atomic_inc(&rdma_stat_rq_poll);
- spin_lock_bh(&xprt->sc_rq_dto_lock);
while ((ret = ib_poll_cq(xprt->sc_rq_cq, 1, &wc)) > 0) {
ctxt = (struct svc_rdma_op_ctxt *)(unsigned long)wc.wr_id;
ctxt->wc_status = wc.status;
ctxt->byte_len = wc.byte_len;
+ svc_rdma_unmap_dma(ctxt);
if (wc.status != IB_WC_SUCCESS) {
/* Close the transport */
+ dprintk("svcrdma: transport closing putting ctxt %p\n", ctxt);
set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
svc_rdma_put_context(ctxt, 1);
+ svc_xprt_put(&xprt->sc_xprt);
continue;
}
+ spin_lock_bh(&xprt->sc_rq_dto_lock);
list_add_tail(&ctxt->dto_q, &xprt->sc_rq_dto_q);
+ spin_unlock_bh(&xprt->sc_rq_dto_lock);
+ svc_xprt_put(&xprt->sc_xprt);
}
- spin_unlock_bh(&xprt->sc_rq_dto_lock);
if (ctxt)
atomic_inc(&rdma_stat_rq_prod);
+
+ set_bit(XPT_DATA, &xprt->sc_xprt.xpt_flags);
+ /*
+ * If data arrived before established event,
+ * don't enqueue. This defers RPC I/O until the
+ * RDMA connection is complete.
+ */
+ if (!test_bit(RDMAXPRT_CONN_PENDING, &xprt->sc_flags))
+ svc_xprt_enqueue(&xprt->sc_xprt);
}
/*
* Send Queue Completion Handler - potentially called on interrupt context.
+ *
+ * Note that caller must hold a transport reference.
*/
static void sq_cq_reap(struct svcxprt_rdma *xprt)
{
@@ -328,11 +327,17 @@ static void sq_cq_reap(struct svcxprt_rdma *xprt)
struct ib_cq *cq = xprt->sc_sq_cq;
int ret;
+
+ if (!test_and_clear_bit(RDMAXPRT_SQ_PENDING, &xprt->sc_flags))
+ return;
+
+ ib_req_notify_cq(xprt->sc_sq_cq, IB_CQ_NEXT_COMP);
atomic_inc(&rdma_stat_sq_poll);
while ((ret = ib_poll_cq(cq, 1, &wc)) > 0) {
ctxt = (struct svc_rdma_op_ctxt *)(unsigned long)wc.wr_id;
xprt = ctxt->xprt;
+ svc_rdma_unmap_dma(ctxt);
if (wc.status != IB_WC_SUCCESS)
/* Close the transport */
set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
@@ -343,20 +348,25 @@ static void sq_cq_reap(struct svcxprt_rdma *xprt)
switch (ctxt->wr_op) {
case IB_WR_SEND:
- case IB_WR_RDMA_WRITE:
svc_rdma_put_context(ctxt, 1);
break;
+ case IB_WR_RDMA_WRITE:
+ svc_rdma_put_context(ctxt, 0);
+ break;
+
case IB_WR_RDMA_READ:
if (test_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags)) {
+ struct svc_rdma_op_ctxt *read_hdr = ctxt->read_hdr;
+ BUG_ON(!read_hdr);
set_bit(XPT_DATA, &xprt->sc_xprt.xpt_flags);
- set_bit(RDMACTXT_F_READ_DONE, &ctxt->flags);
spin_lock_bh(&xprt->sc_read_complete_lock);
- list_add_tail(&ctxt->dto_q,
+ list_add_tail(&read_hdr->dto_q,
&xprt->sc_read_complete_q);
spin_unlock_bh(&xprt->sc_read_complete_lock);
svc_xprt_enqueue(&xprt->sc_xprt);
}
+ svc_rdma_put_context(ctxt, 0);
break;
default:
@@ -365,6 +375,7 @@ static void sq_cq_reap(struct svcxprt_rdma *xprt)
wc.opcode, wc.status);
break;
}
+ svc_xprt_put(&xprt->sc_xprt);
}
if (ctxt)
@@ -376,11 +387,15 @@ static void sq_comp_handler(struct ib_cq *cq, void *cq_context)
struct svcxprt_rdma *xprt = cq_context;
unsigned long flags;
+ /* Guard against unconditional flush call for destroyed QP */
+ if (atomic_read(&xprt->sc_xprt.xpt_ref.refcount)==0)
+ return;
+
/*
* Set the bit regardless of whether or not it's on the list
* because it may be on the list already due to an RQ
* completion.
- */
+ */
set_bit(RDMAXPRT_SQ_PENDING, &xprt->sc_flags);
/*
@@ -398,39 +413,6 @@ static void sq_comp_handler(struct ib_cq *cq, void *cq_context)
tasklet_schedule(&dto_tasklet);
}
-static void create_context_cache(struct svcxprt_rdma *xprt,
- int ctxt_count, int ctxt_bump, int ctxt_max)
-{
- struct svc_rdma_op_ctxt *ctxt;
- int i;
-
- xprt->sc_ctxt_max = ctxt_max;
- xprt->sc_ctxt_bump = ctxt_bump;
- xprt->sc_ctxt_cnt = 0;
- xprt->sc_ctxt_head = NULL;
- for (i = 0; i < ctxt_count; i++) {
- ctxt = kmalloc(sizeof(*ctxt), GFP_KERNEL);
- if (ctxt) {
- ctxt->next = xprt->sc_ctxt_head;
- xprt->sc_ctxt_head = ctxt;
- xprt->sc_ctxt_cnt++;
- }
- }
-}
-
-static void destroy_context_cache(struct svc_rdma_op_ctxt *ctxt)
-{
- struct svc_rdma_op_ctxt *next;
- if (!ctxt)
- return;
-
- do {
- next = ctxt->next;
- kfree(ctxt);
- ctxt = next;
- } while (next);
-}
-
static struct svcxprt_rdma *rdma_create_xprt(struct svc_serv *serv,
int listener)
{
@@ -447,7 +429,6 @@ static struct svcxprt_rdma *rdma_create_xprt(struct svc_serv *serv,
spin_lock_init(&cma_xprt->sc_lock);
spin_lock_init(&cma_xprt->sc_read_complete_lock);
- spin_lock_init(&cma_xprt->sc_ctxt_lock);
spin_lock_init(&cma_xprt->sc_rq_dto_lock);
cma_xprt->sc_ord = svcrdma_ord;
@@ -456,21 +437,9 @@ static struct svcxprt_rdma *rdma_create_xprt(struct svc_serv *serv,
cma_xprt->sc_max_requests = svcrdma_max_requests;
cma_xprt->sc_sq_depth = svcrdma_max_requests * RPCRDMA_SQ_DEPTH_MULT;
atomic_set(&cma_xprt->sc_sq_count, 0);
+ atomic_set(&cma_xprt->sc_ctxt_used, 0);
- if (!listener) {
- int reqs = cma_xprt->sc_max_requests;
- create_context_cache(cma_xprt,
- reqs << 1, /* starting size */
- reqs, /* bump amount */
- reqs +
- cma_xprt->sc_sq_depth +
- RPCRDMA_MAX_THREADS + 1); /* max */
- if (!cma_xprt->sc_ctxt_head) {
- kfree(cma_xprt);
- return NULL;
- }
- clear_bit(XPT_LISTENER, &cma_xprt->sc_xprt.xpt_flags);
- } else
+ if (listener)
set_bit(XPT_LISTENER, &cma_xprt->sc_xprt.xpt_flags);
return cma_xprt;
@@ -506,6 +475,7 @@ int svc_rdma_post_recv(struct svcxprt_rdma *xprt)
BUG_ON(sge_no >= xprt->sc_max_sge);
page = svc_rdma_get_page();
ctxt->pages[sge_no] = page;
+ atomic_inc(&xprt->sc_dma_used);
pa = ib_dma_map_page(xprt->sc_cm_id->device,
page, 0, PAGE_SIZE,
DMA_FROM_DEVICE);
@@ -520,7 +490,12 @@ int svc_rdma_post_recv(struct svcxprt_rdma *xprt)
recv_wr.num_sge = ctxt->count;
recv_wr.wr_id = (u64)(unsigned long)ctxt;
+ svc_xprt_get(&xprt->sc_xprt);
ret = ib_post_recv(xprt->sc_qp, &recv_wr, &bad_recv_wr);
+ if (ret) {
+ svc_xprt_put(&xprt->sc_xprt);
+ svc_rdma_put_context(ctxt, 1);
+ }
return ret;
}
@@ -535,10 +510,11 @@ int svc_rdma_post_recv(struct svcxprt_rdma *xprt)
* will call the recvfrom method on the listen xprt which will accept the new
* connection.
*/
-static void handle_connect_req(struct rdma_cm_id *new_cma_id)
+static void handle_connect_req(struct rdma_cm_id *new_cma_id, size_t client_ird)
{
struct svcxprt_rdma *listen_xprt = new_cma_id->context;
struct svcxprt_rdma *newxprt;
+ struct sockaddr *sa;
/* Create a new transport */
newxprt = rdma_create_xprt(listen_xprt->sc_xprt.xpt_server, 0);
@@ -551,6 +527,15 @@ static void handle_connect_req(struct rdma_cm_id *new_cma_id)
dprintk("svcrdma: Creating newxprt=%p, cm_id=%p, listenxprt=%p\n",
newxprt, newxprt->sc_cm_id, listen_xprt);
+ /* Save client advertised inbound read limit for use later in accept. */
+ newxprt->sc_ord = client_ird;
+
+ /* Set the local and remote addresses in the transport */
+ sa = (struct sockaddr *)&newxprt->sc_cm_id->route.addr.dst_addr;
+ svc_xprt_set_remote(&newxprt->sc_xprt, sa, svc_addr_len(sa));
+ sa = (struct sockaddr *)&newxprt->sc_cm_id->route.addr.src_addr;
+ svc_xprt_set_local(&newxprt->sc_xprt, sa, svc_addr_len(sa));
+
/*
* Enqueue the new transport on the accept queue of the listening
* transport
@@ -581,7 +566,8 @@ static int rdma_listen_handler(struct rdma_cm_id *cma_id,
case RDMA_CM_EVENT_CONNECT_REQUEST:
dprintk("svcrdma: Connect request on cma_id=%p, xprt = %p, "
"event=%d\n", cma_id, cma_id->context, event->event);
- handle_connect_req(cma_id);
+ handle_connect_req(cma_id,
+ event->param.conn.responder_resources);
break;
case RDMA_CM_EVENT_ESTABLISHED:
@@ -627,6 +613,7 @@ static int rdma_cma_handler(struct rdma_cm_id *cma_id,
if (xprt) {
set_bit(XPT_CLOSE, &xprt->xpt_flags);
svc_xprt_enqueue(xprt);
+ svc_xprt_put(xprt);
}
break;
case RDMA_CM_EVENT_DEVICE_REMOVAL:
@@ -661,31 +648,27 @@ static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
cma_xprt = rdma_create_xprt(serv, 1);
if (!cma_xprt)
- return ERR_PTR(ENOMEM);
+ return ERR_PTR(-ENOMEM);
xprt = &cma_xprt->sc_xprt;
listen_id = rdma_create_id(rdma_listen_handler, cma_xprt, RDMA_PS_TCP);
if (IS_ERR(listen_id)) {
- svc_xprt_put(&cma_xprt->sc_xprt);
- dprintk("svcrdma: rdma_create_id failed = %ld\n",
- PTR_ERR(listen_id));
- return (void *)listen_id;
+ ret = PTR_ERR(listen_id);
+ dprintk("svcrdma: rdma_create_id failed = %d\n", ret);
+ goto err0;
}
+
ret = rdma_bind_addr(listen_id, sa);
if (ret) {
- rdma_destroy_id(listen_id);
- svc_xprt_put(&cma_xprt->sc_xprt);
dprintk("svcrdma: rdma_bind_addr failed = %d\n", ret);
- return ERR_PTR(ret);
+ goto err1;
}
cma_xprt->sc_cm_id = listen_id;
ret = rdma_listen(listen_id, RPCRDMA_LISTEN_BACKLOG);
if (ret) {
- rdma_destroy_id(listen_id);
- svc_xprt_put(&cma_xprt->sc_xprt);
dprintk("svcrdma: rdma_listen failed = %d\n", ret);
- return ERR_PTR(ret);
+ goto err1;
}
/*
@@ -696,6 +679,12 @@ static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
svc_xprt_set_local(&cma_xprt->sc_xprt, sa, salen);
return &cma_xprt->sc_xprt;
+
+ err1:
+ rdma_destroy_id(listen_id);
+ err0:
+ kfree(cma_xprt);
+ return ERR_PTR(ret);
}
/*
@@ -716,7 +705,6 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
struct rdma_conn_param conn_param;
struct ib_qp_init_attr qp_attr;
struct ib_device_attr devattr;
- struct sockaddr *sa;
int ret;
int i;
@@ -753,8 +741,12 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
(size_t)svcrdma_max_requests);
newxprt->sc_sq_depth = RPCRDMA_SQ_DEPTH_MULT * newxprt->sc_max_requests;
- newxprt->sc_ord = min((size_t)devattr.max_qp_rd_atom,
- (size_t)svcrdma_ord);
+ /*
+ * Limit ORD based on client limit, local device limit, and
+ * configured svcrdma limit.
+ */
+ newxprt->sc_ord = min_t(size_t, devattr.max_qp_rd_atom, newxprt->sc_ord);
+ newxprt->sc_ord = min_t(size_t, svcrdma_ord, newxprt->sc_ord);
newxprt->sc_pd = ib_alloc_pd(newxprt->sc_cm_id->device);
if (IS_ERR(newxprt->sc_pd)) {
@@ -826,7 +818,6 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
newxprt->sc_sq_depth = qp_attr.cap.max_send_wr;
newxprt->sc_max_requests = qp_attr.cap.max_recv_wr;
}
- svc_xprt_get(&newxprt->sc_xprt);
newxprt->sc_qp = newxprt->sc_cm_id->qp;
/* Register all of physical memory */
@@ -850,6 +841,13 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
/* Swap out the handler */
newxprt->sc_cm_id->event_handler = rdma_cma_handler;
+ /*
+ * Arm the CQs for the SQ and RQ before accepting so we can't
+ * miss the first message
+ */
+ ib_req_notify_cq(newxprt->sc_sq_cq, IB_CQ_NEXT_COMP);
+ ib_req_notify_cq(newxprt->sc_rq_cq, IB_CQ_NEXT_COMP);
+
/* Accept Connection */
set_bit(RDMAXPRT_CONN_PENDING, &newxprt->sc_flags);
memset(&conn_param, 0, sizeof conn_param);
@@ -886,58 +884,26 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
newxprt->sc_max_requests,
newxprt->sc_ord);
- /* Set the local and remote addresses in the transport */
- sa = (struct sockaddr *)&newxprt->sc_cm_id->route.addr.dst_addr;
- svc_xprt_set_remote(&newxprt->sc_xprt, sa, svc_addr_len(sa));
- sa = (struct sockaddr *)&newxprt->sc_cm_id->route.addr.src_addr;
- svc_xprt_set_local(&newxprt->sc_xprt, sa, svc_addr_len(sa));
-
- ib_req_notify_cq(newxprt->sc_sq_cq, IB_CQ_NEXT_COMP);
- ib_req_notify_cq(newxprt->sc_rq_cq, IB_CQ_NEXT_COMP);
return &newxprt->sc_xprt;
errout:
dprintk("svcrdma: failure accepting new connection rc=%d.\n", ret);
/* Take a reference in case the DTO handler runs */
svc_xprt_get(&newxprt->sc_xprt);
- if (newxprt->sc_qp && !IS_ERR(newxprt->sc_qp)) {
+ if (newxprt->sc_qp && !IS_ERR(newxprt->sc_qp))
ib_destroy_qp(newxprt->sc_qp);
- svc_xprt_put(&newxprt->sc_xprt);
- }
rdma_destroy_id(newxprt->sc_cm_id);
/* This call to put will destroy the transport */
svc_xprt_put(&newxprt->sc_xprt);
return NULL;
}
-/*
- * Post an RQ WQE to the RQ when the rqst is being released. This
- * effectively returns an RQ credit to the client. The rq_xprt_ctxt
- * will be null if the request is deferred due to an RDMA_READ or the
- * transport had no data ready (EAGAIN). Note that an RPC deferred in
- * svc_process will still return the credit, this is because the data
- * is copied and no longer consume a WQE/WC.
- */
static void svc_rdma_release_rqst(struct svc_rqst *rqstp)
{
- int err;
- struct svcxprt_rdma *rdma =
- container_of(rqstp->rq_xprt, struct svcxprt_rdma, sc_xprt);
- if (rqstp->rq_xprt_ctxt) {
- BUG_ON(rqstp->rq_xprt_ctxt != rdma);
- err = svc_rdma_post_recv(rdma);
- if (err)
- dprintk("svcrdma: failed to post an RQ WQE error=%d\n",
- err);
- }
- rqstp->rq_xprt_ctxt = NULL;
}
/*
- * When connected, an svc_xprt has at least three references:
- *
- * - A reference held by the QP. We still hold that here because this
- * code deletes the QP and puts the reference.
+ * When connected, an svc_xprt has at least two references:
*
* - A reference held by the cm_id between the ESTABLISHED and
* DISCONNECTED events. If the remote peer disconnected first, this
@@ -946,7 +912,7 @@ static void svc_rdma_release_rqst(struct svc_rqst *rqstp)
* - A reference held by the svc_recv code that called this function
* as part of close processing.
*
- * At a minimum two references should still be held.
+ * At a minimum one references should still be held.
*/
static void svc_rdma_detach(struct svc_xprt *xprt)
{
@@ -956,23 +922,50 @@ static void svc_rdma_detach(struct svc_xprt *xprt)
/* Disconnect and flush posted WQE */
rdma_disconnect(rdma->sc_cm_id);
-
- /* Destroy the QP if present (not a listener) */
- if (rdma->sc_qp && !IS_ERR(rdma->sc_qp)) {
- ib_destroy_qp(rdma->sc_qp);
- svc_xprt_put(xprt);
- }
-
- /* Destroy the CM ID */
- rdma_destroy_id(rdma->sc_cm_id);
}
-static void svc_rdma_free(struct svc_xprt *xprt)
+static void __svc_rdma_free(struct work_struct *work)
{
- struct svcxprt_rdma *rdma = (struct svcxprt_rdma *)xprt;
+ struct svcxprt_rdma *rdma =
+ container_of(work, struct svcxprt_rdma, sc_work);
dprintk("svcrdma: svc_rdma_free(%p)\n", rdma);
+
/* We should only be called from kref_put */
- BUG_ON(atomic_read(&xprt->xpt_ref.refcount) != 0);
+ BUG_ON(atomic_read(&rdma->sc_xprt.xpt_ref.refcount) != 0);
+
+ /*
+ * Destroy queued, but not processed read completions. Note
+ * that this cleanup has to be done before destroying the
+ * cm_id because the device ptr is needed to unmap the dma in
+ * svc_rdma_put_context.
+ */
+ while (!list_empty(&rdma->sc_read_complete_q)) {
+ struct svc_rdma_op_ctxt *ctxt;
+ ctxt = list_entry(rdma->sc_read_complete_q.next,
+ struct svc_rdma_op_ctxt,
+ dto_q);
+ list_del_init(&ctxt->dto_q);
+ svc_rdma_put_context(ctxt, 1);
+ }
+
+ /* Destroy queued, but not processed recv completions */
+ while (!list_empty(&rdma->sc_rq_dto_q)) {
+ struct svc_rdma_op_ctxt *ctxt;
+ ctxt = list_entry(rdma->sc_rq_dto_q.next,
+ struct svc_rdma_op_ctxt,
+ dto_q);
+ list_del_init(&ctxt->dto_q);
+ svc_rdma_put_context(ctxt, 1);
+ }
+
+ /* Warn if we leaked a resource or under-referenced */
+ WARN_ON(atomic_read(&rdma->sc_ctxt_used) != 0);
+ WARN_ON(atomic_read(&rdma->sc_dma_used) != 0);
+
+ /* Destroy the QP if present (not a listener) */
+ if (rdma->sc_qp && !IS_ERR(rdma->sc_qp))
+ ib_destroy_qp(rdma->sc_qp);
+
if (rdma->sc_sq_cq && !IS_ERR(rdma->sc_sq_cq))
ib_destroy_cq(rdma->sc_sq_cq);
@@ -985,10 +978,20 @@ static void svc_rdma_free(struct svc_xprt *xprt)
if (rdma->sc_pd && !IS_ERR(rdma->sc_pd))
ib_dealloc_pd(rdma->sc_pd);
- destroy_context_cache(rdma->sc_ctxt_head);
+ /* Destroy the CM ID */
+ rdma_destroy_id(rdma->sc_cm_id);
+
kfree(rdma);
}
+static void svc_rdma_free(struct svc_xprt *xprt)
+{
+ struct svcxprt_rdma *rdma =
+ container_of(xprt, struct svcxprt_rdma, sc_xprt);
+ INIT_WORK(&rdma->sc_work, __svc_rdma_free);
+ schedule_work(&rdma->sc_work);
+}
+
static int svc_rdma_has_wspace(struct svc_xprt *xprt)
{
struct svcxprt_rdma *rdma =
@@ -1018,7 +1021,7 @@ int svc_rdma_send(struct svcxprt_rdma *xprt, struct ib_send_wr *wr)
int ret;
if (test_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags))
- return 0;
+ return -ENOTCONN;
BUG_ON(wr->send_flags != IB_SEND_SIGNALED);
BUG_ON(((struct svc_rdma_op_ctxt *)(unsigned long)wr->wr_id)->wr_op !=
@@ -1029,7 +1032,8 @@ int svc_rdma_send(struct svcxprt_rdma *xprt, struct ib_send_wr *wr)
if (xprt->sc_sq_depth == atomic_read(&xprt->sc_sq_count)) {
spin_unlock_bh(&xprt->sc_lock);
atomic_inc(&rdma_stat_sq_starve);
- /* See if we can reap some SQ WR */
+
+ /* See if we can opportunistically reap SQ WR to make room */
sq_cq_reap(xprt);
/* Wait until SQ WR available if SQ still full */
@@ -1041,22 +1045,25 @@ int svc_rdma_send(struct svcxprt_rdma *xprt, struct ib_send_wr *wr)
continue;
}
/* Bumped used SQ WR count and post */
+ svc_xprt_get(&xprt->sc_xprt);
ret = ib_post_send(xprt->sc_qp, wr, &bad_wr);
if (!ret)
atomic_inc(&xprt->sc_sq_count);
- else
+ else {
+ svc_xprt_put(&xprt->sc_xprt);
dprintk("svcrdma: failed to post SQ WR rc=%d, "
"sc_sq_count=%d, sc_sq_depth=%d\n",
ret, atomic_read(&xprt->sc_sq_count),
xprt->sc_sq_depth);
+ }
spin_unlock_bh(&xprt->sc_lock);
break;
}
return ret;
}
-int svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
- enum rpcrdma_errcode err)
+void svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
+ enum rpcrdma_errcode err)
{
struct ib_send_wr err_wr;
struct ib_sge sge;
@@ -1073,6 +1080,7 @@ int svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
length = svc_rdma_xdr_encode_error(xprt, rmsgp, err, va);
/* Prepare SGE for local address */
+ atomic_inc(&xprt->sc_dma_used);
sge.addr = ib_dma_map_page(xprt->sc_cm_id->device,
p, 0, PAGE_SIZE, DMA_FROM_DEVICE);
sge.lkey = xprt->sc_phys_mr->lkey;
@@ -1094,9 +1102,8 @@ int svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
/* Post It */
ret = svc_rdma_send(xprt, &err_wr);
if (ret) {
- dprintk("svcrdma: Error posting send = %d\n", ret);
+ dprintk("svcrdma: Error %d posting send for protocol error\n",
+ ret);
svc_rdma_put_context(ctxt, 1);
}
-
- return ret;
}
diff --git a/net/sysctl_net.c b/net/sysctl_net.c
index b4f0525f91af..007c1a6708ee 100644
--- a/net/sysctl_net.c
+++ b/net/sysctl_net.c
@@ -4,7 +4,6 @@
* Begun April 1, 1996, Mike Shaver.
* Added /proc/sys/net directories for each protocol family. [MS]
*
- * $Log: sysctl_net.c,v $
* Revision 1.2 1996/05/08 20:24:40 shaver
* Added bits for NET_BRIDGE and the NET_IPV4_ARP stuff and
* NET_IPV4_IP_FORWARD.
@@ -40,6 +39,27 @@ static struct ctl_table_root net_sysctl_root = {
.lookup = net_ctl_header_lookup,
};
+static LIST_HEAD(net_sysctl_ro_tables);
+static struct list_head *net_ctl_ro_header_lookup(struct ctl_table_root *root,
+ struct nsproxy *namespaces)
+{
+ return &net_sysctl_ro_tables;
+}
+
+static int net_ctl_ro_header_perms(struct ctl_table_root *root,
+ struct nsproxy *namespaces, struct ctl_table *table)
+{
+ if (namespaces->net_ns == &init_net)
+ return table->mode;
+ else
+ return table->mode & ~0222;
+}
+
+static struct ctl_table_root net_sysctl_ro_root = {
+ .lookup = net_ctl_ro_header_lookup,
+ .permissions = net_ctl_ro_header_perms,
+};
+
static int sysctl_net_init(struct net *net)
{
INIT_LIST_HEAD(&net->sysctl_table_headers);
@@ -64,6 +84,7 @@ static __init int sysctl_init(void)
if (ret)
goto out;
register_sysctl_root(&net_sysctl_root);
+ register_sysctl_root(&net_sysctl_ro_root);
out:
return ret;
}
@@ -80,6 +101,14 @@ struct ctl_table_header *register_net_sysctl_table(struct net *net,
}
EXPORT_SYMBOL_GPL(register_net_sysctl_table);
+struct ctl_table_header *register_net_sysctl_rotable(const
+ struct ctl_path *path, struct ctl_table *table)
+{
+ return __register_sysctl_paths(&net_sysctl_ro_root,
+ &init_nsproxy, path, table);
+}
+EXPORT_SYMBOL_GPL(register_net_sysctl_rotable);
+
void unregister_net_sysctl_table(struct ctl_table_header *header)
{
unregister_sysctl_table(header);
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c
index e7880172ef19..a5883b1452ff 100644
--- a/net/tipc/bcast.c
+++ b/net/tipc/bcast.c
@@ -276,7 +276,7 @@ static void bclink_send_nack(struct node *n_ptr)
if (buf) {
msg = buf_msg(buf);
msg_init(msg, BCAST_PROTOCOL, STATE_MSG,
- TIPC_OK, INT_H_SIZE, n_ptr->addr);
+ INT_H_SIZE, n_ptr->addr);
msg_set_mc_netid(msg, tipc_net_id);
msg_set_bcast_ack(msg, mod(n_ptr->bclink.last_in));
msg_set_bcgap_after(msg, n_ptr->bclink.gap_after);
@@ -571,7 +571,7 @@ static int tipc_bcbearer_send(struct sk_buff *buf,
assert(tipc_cltr_bcast_nodes.count != 0);
bcbuf_set_acks(buf, tipc_cltr_bcast_nodes.count);
msg = buf_msg(buf);
- msg_set_non_seq(msg);
+ msg_set_non_seq(msg, 1);
msg_set_mc_netid(msg, tipc_net_id);
}
diff --git a/net/tipc/cluster.c b/net/tipc/cluster.c
index 4bb3404f610b..bc1db474fe01 100644
--- a/net/tipc/cluster.c
+++ b/net/tipc/cluster.c
@@ -238,7 +238,7 @@ static struct sk_buff *tipc_cltr_prepare_routing_msg(u32 data_size, u32 dest)
if (buf) {
msg = buf_msg(buf);
memset((char *)msg, 0, size);
- msg_init(msg, ROUTE_DISTRIBUTOR, 0, TIPC_OK, INT_H_SIZE, dest);
+ msg_init(msg, ROUTE_DISTRIBUTOR, 0, INT_H_SIZE, dest);
}
return buf;
}
diff --git a/net/tipc/config.c b/net/tipc/config.c
index c71337a22d33..ca3544d030c7 100644
--- a/net/tipc/config.c
+++ b/net/tipc/config.c
@@ -2,7 +2,7 @@
* net/tipc/config.c: TIPC configuration management code
*
* Copyright (c) 2002-2006, Ericsson AB
- * Copyright (c) 2004-2006, Wind River Systems
+ * Copyright (c) 2004-2007, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -293,7 +293,6 @@ static struct sk_buff *cfg_set_own_addr(void)
if (tipc_mode == TIPC_NET_MODE)
return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
" (cannot change node address once assigned)");
- tipc_own_addr = addr;
/*
* Must release all spinlocks before calling start_net() because
@@ -306,7 +305,7 @@ static struct sk_buff *cfg_set_own_addr(void)
*/
spin_unlock_bh(&config_lock);
- tipc_core_start_net();
+ tipc_core_start_net(addr);
spin_lock_bh(&config_lock);
return tipc_cfg_reply_none();
}
@@ -529,7 +528,7 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area
break;
#endif
case TIPC_CMD_SET_LOG_SIZE:
- rep_tlv_buf = tipc_log_resize(req_tlv_area, req_tlv_space);
+ rep_tlv_buf = tipc_log_resize_cmd(req_tlv_area, req_tlv_space);
break;
case TIPC_CMD_DUMP_LOG:
rep_tlv_buf = tipc_log_dump();
@@ -602,6 +601,10 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area
case TIPC_CMD_GET_NETID:
rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_net_id);
break;
+ case TIPC_CMD_NOT_NET_ADMIN:
+ rep_tlv_buf =
+ tipc_cfg_reply_error_string(TIPC_CFG_NOT_NET_ADMIN);
+ break;
default:
rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
" (unknown command)");
diff --git a/net/tipc/core.c b/net/tipc/core.c
index 740aac5cdfb6..3256bd7d398f 100644
--- a/net/tipc/core.c
+++ b/net/tipc/core.c
@@ -49,7 +49,7 @@
#include "config.h"
-#define TIPC_MOD_VER "1.6.3"
+#define TIPC_MOD_VER "1.6.4"
#ifndef CONFIG_TIPC_ZONES
#define CONFIG_TIPC_ZONES 3
@@ -117,11 +117,11 @@ void tipc_core_stop_net(void)
* start_net - start TIPC networking sub-systems
*/
-int tipc_core_start_net(void)
+int tipc_core_start_net(unsigned long addr)
{
int res;
- if ((res = tipc_net_start()) ||
+ if ((res = tipc_net_start(addr)) ||
(res = tipc_eth_media_start())) {
tipc_core_stop_net();
}
@@ -164,8 +164,7 @@ int tipc_core_start(void)
tipc_mode = TIPC_NODE_MODE;
if ((res = tipc_handler_start()) ||
- (res = tipc_ref_table_init(tipc_max_ports + tipc_max_subscriptions,
- tipc_random)) ||
+ (res = tipc_ref_table_init(tipc_max_ports, tipc_random)) ||
(res = tipc_reg_start()) ||
(res = tipc_nametbl_init()) ||
(res = tipc_k_signal((Handler)tipc_subscr_start, 0)) ||
@@ -182,7 +181,7 @@ static int __init tipc_init(void)
{
int res;
- tipc_log_reinit(CONFIG_TIPC_LOG);
+ tipc_log_resize(CONFIG_TIPC_LOG);
info("Activated (version " TIPC_MOD_VER
" compiled " __DATE__ " " __TIME__ ")\n");
@@ -209,7 +208,7 @@ static void __exit tipc_exit(void)
tipc_core_stop_net();
tipc_core_stop();
info("Deactivated\n");
- tipc_log_stop();
+ tipc_log_resize(0);
}
module_init(tipc_init);
diff --git a/net/tipc/core.h b/net/tipc/core.h
index 5a0e4878d3b7..a881f92a8537 100644
--- a/net/tipc/core.h
+++ b/net/tipc/core.h
@@ -2,7 +2,7 @@
* net/tipc/core.h: Include file for TIPC global declarations
*
* Copyright (c) 2005-2006, Ericsson AB
- * Copyright (c) 2005-2006, Wind River Systems
+ * Copyright (c) 2005-2007, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -59,84 +59,108 @@
#include <linux/vmalloc.h>
/*
- * TIPC debugging code
+ * TIPC sanity test macros
*/
#define assert(i) BUG_ON(!(i))
-struct tipc_msg;
-extern struct print_buf *TIPC_NULL, *TIPC_CONS, *TIPC_LOG;
-extern struct print_buf *TIPC_TEE(struct print_buf *, struct print_buf *);
-void tipc_msg_print(struct print_buf*,struct tipc_msg *,const char*);
-void tipc_printf(struct print_buf *, const char *fmt, ...);
-void tipc_dump(struct print_buf*,const char *fmt, ...);
-
-#ifdef CONFIG_TIPC_DEBUG
-
/*
- * TIPC debug support included:
- * - system messages are printed to TIPC_OUTPUT print buffer
- * - debug messages are printed to DBG_OUTPUT print buffer
+ * TIPC system monitoring code
*/
-#define err(fmt, arg...) tipc_printf(TIPC_OUTPUT, KERN_ERR "TIPC: " fmt, ## arg)
-#define warn(fmt, arg...) tipc_printf(TIPC_OUTPUT, KERN_WARNING "TIPC: " fmt, ## arg)
-#define info(fmt, arg...) tipc_printf(TIPC_OUTPUT, KERN_NOTICE "TIPC: " fmt, ## arg)
+/*
+ * TIPC's print buffer subsystem supports the following print buffers:
+ *
+ * TIPC_NULL : null buffer (i.e. print nowhere)
+ * TIPC_CONS : system console
+ * TIPC_LOG : TIPC log buffer
+ * &buf : user-defined buffer (struct print_buf *)
+ *
+ * Note: TIPC_LOG is configured to echo its output to the system console;
+ * user-defined buffers can be configured to do the same thing.
+ */
-#define dbg(fmt, arg...) do {if (DBG_OUTPUT != TIPC_NULL) tipc_printf(DBG_OUTPUT, fmt, ## arg);} while(0)
-#define msg_dbg(msg, txt) do {if (DBG_OUTPUT != TIPC_NULL) tipc_msg_print(DBG_OUTPUT, msg, txt);} while(0)
-#define dump(fmt, arg...) do {if (DBG_OUTPUT != TIPC_NULL) tipc_dump(DBG_OUTPUT, fmt, ##arg);} while(0)
+extern struct print_buf *const TIPC_NULL;
+extern struct print_buf *const TIPC_CONS;
+extern struct print_buf *const TIPC_LOG;
+void tipc_printf(struct print_buf *, const char *fmt, ...);
/*
- * By default, TIPC_OUTPUT is defined to be system console and TIPC log buffer,
- * while DBG_OUTPUT is the null print buffer. These defaults can be changed
- * here, or on a per .c file basis, by redefining these symbols. The following
- * print buffer options are available:
- *
- * TIPC_NULL : null buffer (i.e. print nowhere)
- * TIPC_CONS : system console
- * TIPC_LOG : TIPC log buffer
- * &buf : user-defined buffer (struct print_buf *)
- * TIPC_TEE(&buf_a,&buf_b) : list of buffers (eg. TIPC_TEE(TIPC_CONS,TIPC_LOG))
+ * TIPC_OUTPUT is the destination print buffer for system messages.
*/
#ifndef TIPC_OUTPUT
-#define TIPC_OUTPUT TIPC_TEE(TIPC_CONS,TIPC_LOG)
-#endif
-
-#ifndef DBG_OUTPUT
-#define DBG_OUTPUT TIPC_NULL
+#define TIPC_OUTPUT TIPC_LOG
#endif
-#else
-
/*
- * TIPC debug support not included:
- * - system messages are printed to system console
- * - debug messages are not printed
+ * TIPC can be configured to send system messages to TIPC_OUTPUT
+ * or to the system console only.
*/
+#ifdef CONFIG_TIPC_DEBUG
+
+#define err(fmt, arg...) tipc_printf(TIPC_OUTPUT, \
+ KERN_ERR "TIPC: " fmt, ## arg)
+#define warn(fmt, arg...) tipc_printf(TIPC_OUTPUT, \
+ KERN_WARNING "TIPC: " fmt, ## arg)
+#define info(fmt, arg...) tipc_printf(TIPC_OUTPUT, \
+ KERN_NOTICE "TIPC: " fmt, ## arg)
+
+#else
+
#define err(fmt, arg...) printk(KERN_ERR "TIPC: " fmt , ## arg)
#define info(fmt, arg...) printk(KERN_INFO "TIPC: " fmt , ## arg)
#define warn(fmt, arg...) printk(KERN_WARNING "TIPC: " fmt , ## arg)
-#define dbg(fmt, arg...) do {} while (0)
-#define msg_dbg(msg,txt) do {} while (0)
-#define dump(fmt,arg...) do {} while (0)
+#endif
+/*
+ * DBG_OUTPUT is the destination print buffer for debug messages.
+ * It defaults to the the null print buffer, but can be redefined
+ * (typically in the individual .c files being debugged) to allow
+ * selected debug messages to be generated where needed.
+ */
+
+#ifndef DBG_OUTPUT
+#define DBG_OUTPUT TIPC_NULL
+#endif
/*
- * TIPC_OUTPUT is defined to be the system console, while DBG_OUTPUT is
- * the null print buffer. Thes ensures that any system or debug messages
- * that are generated without using the above macros are handled correctly.
+ * TIPC can be configured to send debug messages to the specified print buffer
+ * (typically DBG_OUTPUT) or to suppress them entirely.
*/
-#undef TIPC_OUTPUT
-#define TIPC_OUTPUT TIPC_CONS
+#ifdef CONFIG_TIPC_DEBUG
-#undef DBG_OUTPUT
-#define DBG_OUTPUT TIPC_NULL
+#define dbg(fmt, arg...) \
+ do { \
+ if (DBG_OUTPUT != TIPC_NULL) \
+ tipc_printf(DBG_OUTPUT, fmt, ## arg); \
+ } while (0)
+#define msg_dbg(msg, txt) \
+ do { \
+ if (DBG_OUTPUT != TIPC_NULL) \
+ tipc_msg_dbg(DBG_OUTPUT, msg, txt); \
+ } while (0)
+#define dump(fmt, arg...) \
+ do { \
+ if (DBG_OUTPUT != TIPC_NULL) \
+ tipc_dump_dbg(DBG_OUTPUT, fmt, ##arg); \
+ } while (0)
+
+void tipc_msg_dbg(struct print_buf *, struct tipc_msg *, const char *);
+void tipc_dump_dbg(struct print_buf *, const char *fmt, ...);
+
+#else
+
+#define dbg(fmt, arg...) do {} while (0)
+#define msg_dbg(msg, txt) do {} while (0)
+#define dump(fmt, arg...) do {} while (0)
+
+#define tipc_msg_dbg(...) do {} while (0)
+#define tipc_dump_dbg(...) do {} while (0)
#endif
@@ -178,7 +202,7 @@ extern atomic_t tipc_user_count;
extern int tipc_core_start(void);
extern void tipc_core_stop(void);
-extern int tipc_core_start_net(void);
+extern int tipc_core_start_net(unsigned long addr);
extern void tipc_core_stop_net(void);
extern int tipc_handler_start(void);
extern void tipc_handler_stop(void);
diff --git a/net/tipc/dbg.c b/net/tipc/dbg.c
index e809d2a2ce06..29ecae851668 100644
--- a/net/tipc/dbg.c
+++ b/net/tipc/dbg.c
@@ -2,7 +2,7 @@
* net/tipc/dbg.c: TIPC print buffer routines for debugging
*
* Copyright (c) 1996-2006, Ericsson AB
- * Copyright (c) 2005-2006, Wind River Systems
+ * Copyright (c) 2005-2007, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -38,17 +38,43 @@
#include "config.h"
#include "dbg.h"
-static char print_string[TIPC_PB_MAX_STR];
-static DEFINE_SPINLOCK(print_lock);
+/*
+ * TIPC pre-defines the following print buffers:
+ *
+ * TIPC_NULL : null buffer (i.e. print nowhere)
+ * TIPC_CONS : system console
+ * TIPC_LOG : TIPC log buffer
+ *
+ * Additional user-defined print buffers are also permitted.
+ */
-static struct print_buf null_buf = { NULL, 0, NULL, NULL };
-struct print_buf *TIPC_NULL = &null_buf;
+static struct print_buf null_buf = { NULL, 0, NULL, 0 };
+struct print_buf *const TIPC_NULL = &null_buf;
-static struct print_buf cons_buf = { NULL, 0, NULL, NULL };
-struct print_buf *TIPC_CONS = &cons_buf;
+static struct print_buf cons_buf = { NULL, 0, NULL, 1 };
+struct print_buf *const TIPC_CONS = &cons_buf;
-static struct print_buf log_buf = { NULL, 0, NULL, NULL };
-struct print_buf *TIPC_LOG = &log_buf;
+static struct print_buf log_buf = { NULL, 0, NULL, 1 };
+struct print_buf *const TIPC_LOG = &log_buf;
+
+/*
+ * Locking policy when using print buffers.
+ *
+ * 1) tipc_printf() uses 'print_lock' to protect against concurrent access to
+ * 'print_string' when writing to a print buffer. This also protects against
+ * concurrent writes to the print buffer being written to.
+ *
+ * 2) tipc_dump() and tipc_log_XXX() leverage the aforementioned
+ * use of 'print_lock' to protect against all types of concurrent operations
+ * on their associated print buffer (not just write operations).
+ *
+ * Note: All routines of the form tipc_printbuf_XXX() are lock-free, and rely
+ * on the caller to prevent simultaneous use of the print buffer(s) being
+ * manipulated.
+ */
+
+static char print_string[TIPC_PB_MAX_STR];
+static DEFINE_SPINLOCK(print_lock);
#define FORMAT(PTR,LEN,FMT) \
@@ -60,27 +86,14 @@ struct print_buf *TIPC_LOG = &log_buf;
*(PTR + LEN) = '\0';\
}
-/*
- * Locking policy when using print buffers.
- *
- * The following routines use 'print_lock' for protection:
- * 1) tipc_printf() - to protect its print buffer(s) and 'print_string'
- * 2) TIPC_TEE() - to protect its print buffer(s)
- * 3) tipc_dump() - to protect its print buffer(s) and 'print_string'
- * 4) tipc_log_XXX() - to protect TIPC_LOG
- *
- * All routines of the form tipc_printbuf_XXX() rely on the caller to prevent
- * simultaneous use of the print buffer(s) being manipulated.
- */
-
/**
* tipc_printbuf_init - initialize print buffer to empty
* @pb: pointer to print buffer structure
* @raw: pointer to character array used by print buffer
* @size: size of character array
*
- * Makes the print buffer a null device that discards anything written to it
- * if the character array is too small (or absent).
+ * Note: If the character array is too small (or absent), the print buffer
+ * becomes a null device that discards anything written to it.
*/
void tipc_printbuf_init(struct print_buf *pb, char *raw, u32 size)
@@ -88,13 +101,13 @@ void tipc_printbuf_init(struct print_buf *pb, char *raw, u32 size)
pb->buf = raw;
pb->crs = raw;
pb->size = size;
- pb->next = NULL;
+ pb->echo = 0;
if (size < TIPC_PB_MIN_SIZE) {
pb->buf = NULL;
} else if (raw) {
pb->buf[0] = 0;
- pb->buf[size-1] = ~0;
+ pb->buf[size - 1] = ~0;
}
}
@@ -105,7 +118,11 @@ void tipc_printbuf_init(struct print_buf *pb, char *raw, u32 size)
void tipc_printbuf_reset(struct print_buf *pb)
{
- tipc_printbuf_init(pb, pb->buf, pb->size);
+ if (pb->buf) {
+ pb->crs = pb->buf;
+ pb->buf[0] = 0;
+ pb->buf[pb->size - 1] = ~0;
+ }
}
/**
@@ -141,7 +158,7 @@ int tipc_printbuf_validate(struct print_buf *pb)
if (pb->buf[pb->size - 1] == 0) {
cp_buf = kmalloc(pb->size, GFP_ATOMIC);
- if (cp_buf != NULL){
+ if (cp_buf) {
tipc_printbuf_init(&cb, cp_buf, pb->size);
tipc_printbuf_move(&cb, pb);
tipc_printbuf_move(pb, &cb);
@@ -179,15 +196,16 @@ void tipc_printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from)
}
if (pb_to->size < pb_from->size) {
- tipc_printbuf_reset(pb_to);
- tipc_printf(pb_to, "*** PRINT BUFFER MOVE ERROR ***");
+ strcpy(pb_to->buf, "*** PRINT BUFFER MOVE ERROR ***");
+ pb_to->buf[pb_to->size - 1] = ~0;
+ pb_to->crs = strchr(pb_to->buf, 0);
return;
}
/* Copy data from char after cursor to end (if used) */
len = pb_from->buf + pb_from->size - pb_from->crs - 2;
- if ((pb_from->buf[pb_from->size-1] == 0) && (len > 0)) {
+ if ((pb_from->buf[pb_from->size - 1] == 0) && (len > 0)) {
strcpy(pb_to->buf, pb_from->crs + 1);
pb_to->crs = pb_to->buf + len;
} else
@@ -203,8 +221,8 @@ void tipc_printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from)
}
/**
- * tipc_printf - append formatted output to print buffer chain
- * @pb: pointer to chain of print buffers (may be NULL)
+ * tipc_printf - append formatted output to print buffer
+ * @pb: pointer to print buffer
* @fmt: formatted info to be printed
*/
@@ -213,68 +231,40 @@ void tipc_printf(struct print_buf *pb, const char *fmt, ...)
int chars_to_add;
int chars_left;
char save_char;
- struct print_buf *pb_next;
spin_lock_bh(&print_lock);
+
FORMAT(print_string, chars_to_add, fmt);
if (chars_to_add >= TIPC_PB_MAX_STR)
strcpy(print_string, "*** PRINT BUFFER STRING TOO LONG ***");
- while (pb) {
- if (pb == TIPC_CONS)
- printk(print_string);
- else if (pb->buf) {
- chars_left = pb->buf + pb->size - pb->crs - 1;
- if (chars_to_add <= chars_left) {
- strcpy(pb->crs, print_string);
- pb->crs += chars_to_add;
- } else if (chars_to_add >= (pb->size - 1)) {
- strcpy(pb->buf, print_string + chars_to_add + 1
- - pb->size);
- pb->crs = pb->buf + pb->size - 1;
- } else {
- strcpy(pb->buf, print_string + chars_left);
- save_char = print_string[chars_left];
- print_string[chars_left] = 0;
- strcpy(pb->crs, print_string);
- print_string[chars_left] = save_char;
- pb->crs = pb->buf + chars_to_add - chars_left;
- }
+ if (pb->buf) {
+ chars_left = pb->buf + pb->size - pb->crs - 1;
+ if (chars_to_add <= chars_left) {
+ strcpy(pb->crs, print_string);
+ pb->crs += chars_to_add;
+ } else if (chars_to_add >= (pb->size - 1)) {
+ strcpy(pb->buf, print_string + chars_to_add + 1
+ - pb->size);
+ pb->crs = pb->buf + pb->size - 1;
+ } else {
+ strcpy(pb->buf, print_string + chars_left);
+ save_char = print_string[chars_left];
+ print_string[chars_left] = 0;
+ strcpy(pb->crs, print_string);
+ print_string[chars_left] = save_char;
+ pb->crs = pb->buf + chars_to_add - chars_left;
}
- pb_next = pb->next;
- pb->next = NULL;
- pb = pb_next;
}
- spin_unlock_bh(&print_lock);
-}
-/**
- * TIPC_TEE - perform next output operation on both print buffers
- * @b0: pointer to chain of print buffers (may be NULL)
- * @b1: pointer to print buffer to add to chain
- *
- * Returns pointer to print buffer chain.
- */
+ if (pb->echo)
+ printk(print_string);
-struct print_buf *TIPC_TEE(struct print_buf *b0, struct print_buf *b1)
-{
- struct print_buf *pb = b0;
-
- if (!b0 || (b0 == b1))
- return b1;
-
- spin_lock_bh(&print_lock);
- while (pb->next) {
- if ((pb->next == b1) || (pb->next == b0))
- pb->next = pb->next->next;
- else
- pb = pb->next;
- }
- pb->next = b1;
spin_unlock_bh(&print_lock);
- return b0;
}
+#ifdef CONFIG_TIPC_DEBUG
+
/**
* print_to_console - write string of bytes to console in multiple chunks
*/
@@ -321,72 +311,66 @@ static void printbuf_dump(struct print_buf *pb)
}
/**
- * tipc_dump - dump non-console print buffer(s) to console
- * @pb: pointer to chain of print buffers
+ * tipc_dump_dbg - dump (non-console) print buffer to console
+ * @pb: pointer to print buffer
*/
-void tipc_dump(struct print_buf *pb, const char *fmt, ...)
+void tipc_dump_dbg(struct print_buf *pb, const char *fmt, ...)
{
- struct print_buf *pb_next;
int len;
+ if (pb == TIPC_CONS)
+ return;
+
spin_lock_bh(&print_lock);
+
FORMAT(print_string, len, fmt);
printk(print_string);
- for (; pb; pb = pb->next) {
- if (pb != TIPC_CONS) {
- printk("\n---- Start of %s log dump ----\n\n",
- (pb == TIPC_LOG) ? "global" : "local");
- printbuf_dump(pb);
- tipc_printbuf_reset(pb);
- printk("\n---- End of dump ----\n");
- }
- pb_next = pb->next;
- pb->next = NULL;
- pb = pb_next;
- }
+ printk("\n---- Start of %s log dump ----\n\n",
+ (pb == TIPC_LOG) ? "global" : "local");
+ printbuf_dump(pb);
+ tipc_printbuf_reset(pb);
+ printk("\n---- End of dump ----\n");
+
spin_unlock_bh(&print_lock);
}
+#endif
+
/**
- * tipc_log_stop - free up TIPC log print buffer
+ * tipc_log_resize - change the size of the TIPC log buffer
+ * @log_size: print buffer size to use
*/
-void tipc_log_stop(void)
+int tipc_log_resize(int log_size)
{
+ int res = 0;
+
spin_lock_bh(&print_lock);
if (TIPC_LOG->buf) {
kfree(TIPC_LOG->buf);
TIPC_LOG->buf = NULL;
}
- spin_unlock_bh(&print_lock);
-}
-
-/**
- * tipc_log_reinit - (re)initialize TIPC log print buffer
- * @log_size: print buffer size to use
- */
-
-void tipc_log_reinit(int log_size)
-{
- tipc_log_stop();
-
if (log_size) {
if (log_size < TIPC_PB_MIN_SIZE)
log_size = TIPC_PB_MIN_SIZE;
- spin_lock_bh(&print_lock);
+ res = TIPC_LOG->echo;
tipc_printbuf_init(TIPC_LOG, kmalloc(log_size, GFP_ATOMIC),
log_size);
- spin_unlock_bh(&print_lock);
+ TIPC_LOG->echo = res;
+ res = !TIPC_LOG->buf;
}
+ spin_unlock_bh(&print_lock);
+
+ return res;
}
/**
- * tipc_log_resize - reconfigure size of TIPC log buffer
+ * tipc_log_resize_cmd - reconfigure size of TIPC log buffer
*/
-struct sk_buff *tipc_log_resize(const void *req_tlv_area, int req_tlv_space)
+struct sk_buff *tipc_log_resize_cmd(const void *req_tlv_area, int req_tlv_space)
{
u32 value;
@@ -397,7 +381,9 @@ struct sk_buff *tipc_log_resize(const void *req_tlv_area, int req_tlv_space)
if (value != delimit(value, 0, 32768))
return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
" (log size must be 0-32768)");
- tipc_log_reinit(value);
+ if (tipc_log_resize(value))
+ return tipc_cfg_reply_error_string(
+ "unable to create specified log (log size is now 0)");
return tipc_cfg_reply_none();
}
@@ -410,27 +396,32 @@ struct sk_buff *tipc_log_dump(void)
struct sk_buff *reply;
spin_lock_bh(&print_lock);
- if (!TIPC_LOG->buf)
+ if (!TIPC_LOG->buf) {
+ spin_unlock_bh(&print_lock);
reply = tipc_cfg_reply_ultra_string("log not activated\n");
- else if (tipc_printbuf_empty(TIPC_LOG))
+ } else if (tipc_printbuf_empty(TIPC_LOG)) {
+ spin_unlock_bh(&print_lock);
reply = tipc_cfg_reply_ultra_string("log is empty\n");
+ }
else {
struct tlv_desc *rep_tlv;
struct print_buf pb;
int str_len;
str_len = min(TIPC_LOG->size, 32768u);
+ spin_unlock_bh(&print_lock);
reply = tipc_cfg_reply_alloc(TLV_SPACE(str_len));
if (reply) {
rep_tlv = (struct tlv_desc *)reply->data;
tipc_printbuf_init(&pb, TLV_DATA(rep_tlv), str_len);
+ spin_lock_bh(&print_lock);
tipc_printbuf_move(&pb, TIPC_LOG);
+ spin_unlock_bh(&print_lock);
str_len = strlen(TLV_DATA(rep_tlv)) + 1;
skb_put(reply, TLV_SPACE(str_len));
TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
}
}
- spin_unlock_bh(&print_lock);
return reply;
}
diff --git a/net/tipc/dbg.h b/net/tipc/dbg.h
index c01b085000e0..5ef1bc8f64ef 100644
--- a/net/tipc/dbg.h
+++ b/net/tipc/dbg.h
@@ -2,7 +2,7 @@
* net/tipc/dbg.h: Include file for TIPC print buffer routines
*
* Copyright (c) 1997-2006, Ericsson AB
- * Copyright (c) 2005-2006, Wind River Systems
+ * Copyright (c) 2005-2007, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -42,14 +42,14 @@
* @buf: pointer to character array containing print buffer contents
* @size: size of character array
* @crs: pointer to first unused space in character array (i.e. final NUL)
- * @next: used to link print buffers when printing to more than one at a time
+ * @echo: echo output to system console if non-zero
*/
struct print_buf {
char *buf;
u32 size;
char *crs;
- struct print_buf *next;
+ int echo;
};
#define TIPC_PB_MIN_SIZE 64 /* minimum size for a print buffer's array */
@@ -61,10 +61,10 @@ int tipc_printbuf_empty(struct print_buf *pb);
int tipc_printbuf_validate(struct print_buf *pb);
void tipc_printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from);
-void tipc_log_reinit(int log_size);
-void tipc_log_stop(void);
+int tipc_log_resize(int log_size);
-struct sk_buff *tipc_log_resize(const void *req_tlv_area, int req_tlv_space);
+struct sk_buff *tipc_log_resize_cmd(const void *req_tlv_area,
+ int req_tlv_space);
struct sk_buff *tipc_log_dump(void);
#endif
diff --git a/net/tipc/discover.c b/net/tipc/discover.c
index 5d643e5721eb..1657f0e795ff 100644
--- a/net/tipc/discover.c
+++ b/net/tipc/discover.c
@@ -120,9 +120,8 @@ static struct sk_buff *tipc_disc_init_msg(u32 type,
if (buf) {
msg = buf_msg(buf);
- msg_init(msg, LINK_CONFIG, type, TIPC_OK, DSC_H_SIZE,
- dest_domain);
- msg_set_non_seq(msg);
+ msg_init(msg, LINK_CONFIG, type, DSC_H_SIZE, dest_domain);
+ msg_set_non_seq(msg, 1);
msg_set_req_links(msg, req_links);
msg_set_dest_domain(msg, dest_domain);
msg_set_bc_netid(msg, tipc_net_id);
@@ -156,11 +155,11 @@ static void disc_dupl_alert(struct bearer *b_ptr, u32 node_addr,
/**
* tipc_disc_recv_msg - handle incoming link setup message (request or response)
* @buf: buffer containing message
+ * @b_ptr: bearer that message arrived on
*/
-void tipc_disc_recv_msg(struct sk_buff *buf)
+void tipc_disc_recv_msg(struct sk_buff *buf, struct bearer *b_ptr)
{
- struct bearer *b_ptr = (struct bearer *)TIPC_SKB_CB(buf)->handle;
struct link *link;
struct tipc_media_addr media_addr;
struct tipc_msg *msg = buf_msg(buf);
@@ -200,9 +199,8 @@ void tipc_disc_recv_msg(struct sk_buff *buf)
dbg(" in own cluster\n");
if (n_ptr == NULL) {
n_ptr = tipc_node_create(orig);
- }
- if (n_ptr == NULL) {
- return;
+ if (!n_ptr)
+ return;
}
spin_lock_bh(&n_ptr->lock);
link = n_ptr->links[b_ptr->identity];
diff --git a/net/tipc/discover.h b/net/tipc/discover.h
index 9fd7587b143a..c36eaeb7d5d0 100644
--- a/net/tipc/discover.h
+++ b/net/tipc/discover.h
@@ -48,7 +48,7 @@ struct link_req *tipc_disc_init_link_req(struct bearer *b_ptr,
void tipc_disc_update_link_req(struct link_req *req);
void tipc_disc_stop_link_req(struct link_req *req);
-void tipc_disc_recv_msg(struct sk_buff *buf);
+void tipc_disc_recv_msg(struct sk_buff *buf, struct bearer *b_ptr);
void tipc_disc_link_event(u32 addr, char *name, int up);
#if 0
diff --git a/net/tipc/link.c b/net/tipc/link.c
index 2a26a16e269f..9784a8e963b4 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -51,6 +51,12 @@
/*
+ * Out-of-range value for link session numbers
+ */
+
+#define INVALID_SESSION 0x10000
+
+/*
* Limit for deferred reception queue:
*/
@@ -147,9 +153,21 @@ static void link_print(struct link *l_ptr, struct print_buf *buf,
#define LINK_LOG_BUF_SIZE 0
-#define dbg_link(fmt, arg...) do {if (LINK_LOG_BUF_SIZE) tipc_printf(&l_ptr->print_buf, fmt, ## arg); } while(0)
-#define dbg_link_msg(msg, txt) do {if (LINK_LOG_BUF_SIZE) tipc_msg_print(&l_ptr->print_buf, msg, txt); } while(0)
-#define dbg_link_state(txt) do {if (LINK_LOG_BUF_SIZE) link_print(l_ptr, &l_ptr->print_buf, txt); } while(0)
+#define dbg_link(fmt, arg...) \
+ do { \
+ if (LINK_LOG_BUF_SIZE) \
+ tipc_printf(&l_ptr->print_buf, fmt, ## arg); \
+ } while (0)
+#define dbg_link_msg(msg, txt) \
+ do { \
+ if (LINK_LOG_BUF_SIZE) \
+ tipc_msg_dbg(&l_ptr->print_buf, msg, txt); \
+ } while (0)
+#define dbg_link_state(txt) \
+ do { \
+ if (LINK_LOG_BUF_SIZE) \
+ link_print(l_ptr, &l_ptr->print_buf, txt); \
+ } while (0)
#define dbg_link_dump() do { \
if (LINK_LOG_BUF_SIZE) { \
tipc_printf(LOG, "\n\nDumping link <%s>:\n", l_ptr->name); \
@@ -450,9 +468,9 @@ struct link *tipc_link_create(struct bearer *b_ptr, const u32 peer,
l_ptr->pmsg = (struct tipc_msg *)&l_ptr->proto_msg;
msg = l_ptr->pmsg;
- msg_init(msg, LINK_PROTOCOL, RESET_MSG, TIPC_OK, INT_H_SIZE, l_ptr->addr);
+ msg_init(msg, LINK_PROTOCOL, RESET_MSG, INT_H_SIZE, l_ptr->addr);
msg_set_size(msg, sizeof(l_ptr->proto_msg));
- msg_set_session(msg, tipc_random);
+ msg_set_session(msg, (tipc_random & 0xffff));
msg_set_bearer_id(msg, b_ptr->identity);
strcpy((char *)msg_data(msg), if_name);
@@ -693,10 +711,10 @@ void tipc_link_reset(struct link *l_ptr)
u32 checkpoint = l_ptr->next_in_no;
int was_active_link = tipc_link_is_active(l_ptr);
- msg_set_session(l_ptr->pmsg, msg_session(l_ptr->pmsg) + 1);
+ msg_set_session(l_ptr->pmsg, ((msg_session(l_ptr->pmsg) + 1) & 0xffff));
- /* Link is down, accept any session: */
- l_ptr->peer_session = 0;
+ /* Link is down, accept any session */
+ l_ptr->peer_session = INVALID_SESSION;
/* Prepare for max packet size negotiation */
link_init_max_pkt(l_ptr);
@@ -1110,7 +1128,7 @@ int tipc_link_send_buf(struct link *l_ptr, struct sk_buff *buf)
if (bundler) {
msg_init(&bundler_hdr, MSG_BUNDLER, OPEN_MSG,
- TIPC_OK, INT_H_SIZE, l_ptr->addr);
+ INT_H_SIZE, l_ptr->addr);
skb_copy_to_linear_data(bundler, &bundler_hdr,
INT_H_SIZE);
skb_trim(bundler, INT_H_SIZE);
@@ -1374,7 +1392,7 @@ again:
msg_dbg(hdr, ">FRAGMENTING>");
msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT,
- TIPC_OK, INT_H_SIZE, msg_destnode(hdr));
+ INT_H_SIZE, msg_destnode(hdr));
msg_set_link_selector(&fragm_hdr, sender->publ.ref);
msg_set_size(&fragm_hdr, max_pkt);
msg_set_fragm_no(&fragm_hdr, 1);
@@ -1651,7 +1669,7 @@ static void link_retransmit_failure(struct link *l_ptr, struct sk_buff *buf)
struct tipc_msg *msg = buf_msg(buf);
warn("Retransmission failure on link <%s>\n", l_ptr->name);
- tipc_msg_print(TIPC_OUTPUT, msg, ">RETR-FAIL>");
+ tipc_msg_dbg(TIPC_OUTPUT, msg, ">RETR-FAIL>");
if (l_ptr->addr) {
@@ -1748,21 +1766,6 @@ void tipc_link_retransmit(struct link *l_ptr, struct sk_buff *buf,
l_ptr->retransm_queue_head = l_ptr->retransm_queue_size = 0;
}
-/*
- * link_recv_non_seq: Receive packets which are outside
- * the link sequence flow
- */
-
-static void link_recv_non_seq(struct sk_buff *buf)
-{
- struct tipc_msg *msg = buf_msg(buf);
-
- if (msg_user(msg) == LINK_CONFIG)
- tipc_disc_recv_msg(buf);
- else
- tipc_bclink_recv_pkt(buf);
-}
-
/**
* link_insert_deferred_queue - insert deferred messages back into receive chain
*/
@@ -1839,7 +1842,7 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
{
read_lock_bh(&tipc_net_lock);
while (head) {
- struct bearer *b_ptr;
+ struct bearer *b_ptr = (struct bearer *)tb_ptr;
struct node *n_ptr;
struct link *l_ptr;
struct sk_buff *crs;
@@ -1850,9 +1853,6 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
u32 released = 0;
int type;
- b_ptr = (struct bearer *)tb_ptr;
- TIPC_SKB_CB(buf)->handle = b_ptr;
-
head = head->next;
/* Ensure message is well-formed */
@@ -1871,7 +1871,10 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
msg = buf_msg(buf);
if (unlikely(msg_non_seq(msg))) {
- link_recv_non_seq(buf);
+ if (msg_user(msg) == LINK_CONFIG)
+ tipc_disc_recv_msg(buf, b_ptr);
+ else
+ tipc_bclink_recv_pkt(buf);
continue;
}
@@ -1978,8 +1981,6 @@ deliver:
if (link_recv_changeover_msg(&l_ptr, &buf)) {
msg = buf_msg(buf);
seq_no = msg_seqno(msg);
- TIPC_SKB_CB(buf)->handle
- = b_ptr;
if (type == ORIGINAL_MSG)
goto deliver;
goto protocol_check;
@@ -2263,7 +2264,8 @@ static void link_recv_proto_msg(struct link *l_ptr, struct sk_buff *buf)
switch (msg_type(msg)) {
case RESET_MSG:
- if (!link_working_unknown(l_ptr) && l_ptr->peer_session) {
+ if (!link_working_unknown(l_ptr) &&
+ (l_ptr->peer_session != INVALID_SESSION)) {
if (msg_session(msg) == l_ptr->peer_session) {
dbg("Duplicate RESET: %u<->%u\n",
msg_session(msg), l_ptr->peer_session);
@@ -2424,7 +2426,7 @@ void tipc_link_changeover(struct link *l_ptr)
}
msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL,
- ORIGINAL_MSG, TIPC_OK, INT_H_SIZE, l_ptr->addr);
+ ORIGINAL_MSG, INT_H_SIZE, l_ptr->addr);
msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id);
msg_set_msgcnt(&tunnel_hdr, msgcount);
dbg("Link changeover requires %u tunnel messages\n", msgcount);
@@ -2479,7 +2481,7 @@ void tipc_link_send_duplicate(struct link *l_ptr, struct link *tunnel)
struct tipc_msg tunnel_hdr;
msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL,
- DUPLICATE_MSG, TIPC_OK, INT_H_SIZE, l_ptr->addr);
+ DUPLICATE_MSG, INT_H_SIZE, l_ptr->addr);
msg_set_msgcnt(&tunnel_hdr, l_ptr->out_queue_size);
msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id);
iter = l_ptr->first_out;
@@ -2672,10 +2674,12 @@ int tipc_link_send_long_buf(struct link *l_ptr, struct sk_buff *buf)
u32 pack_sz = link_max_pkt(l_ptr);
u32 fragm_sz = pack_sz - INT_H_SIZE;
u32 fragm_no = 1;
- u32 destaddr = msg_destnode(inmsg);
+ u32 destaddr;
if (msg_short(inmsg))
destaddr = l_ptr->addr;
+ else
+ destaddr = msg_destnode(inmsg);
if (msg_routed(inmsg))
msg_set_prevnode(inmsg, tipc_own_addr);
@@ -2683,7 +2687,7 @@ int tipc_link_send_long_buf(struct link *l_ptr, struct sk_buff *buf)
/* Prepare reusable fragment header: */
msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT,
- TIPC_OK, INT_H_SIZE, destaddr);
+ INT_H_SIZE, destaddr);
msg_set_link_selector(&fragm_hdr, msg_link_selector(inmsg));
msg_set_long_msgno(&fragm_hdr, mod(l_ptr->long_msg_seq_no++));
msg_set_fragm_no(&fragm_hdr, fragm_no);
diff --git a/net/tipc/msg.c b/net/tipc/msg.c
index 696a8633df75..73dcd00d674e 100644
--- a/net/tipc/msg.c
+++ b/net/tipc/msg.c
@@ -41,7 +41,9 @@
#include "bearer.h"
-void tipc_msg_print(struct print_buf *buf, struct tipc_msg *msg, const char *str)
+#ifdef CONFIG_TIPC_DEBUG
+
+void tipc_msg_dbg(struct print_buf *buf, struct tipc_msg *msg, const char *str)
{
u32 usr = msg_user(msg);
tipc_printf(buf, str);
@@ -228,13 +230,10 @@ void tipc_msg_print(struct print_buf *buf, struct tipc_msg *msg, const char *str
switch (usr) {
case CONN_MANAGER:
- case NAME_DISTRIBUTOR:
case TIPC_LOW_IMPORTANCE:
case TIPC_MEDIUM_IMPORTANCE:
case TIPC_HIGH_IMPORTANCE:
case TIPC_CRITICAL_IMPORTANCE:
- if (msg_short(msg))
- break; /* No error */
switch (msg_errcode(msg)) {
case TIPC_OK:
break;
@@ -315,9 +314,11 @@ void tipc_msg_print(struct print_buf *buf, struct tipc_msg *msg, const char *str
}
tipc_printf(buf, "\n");
if ((usr == CHANGEOVER_PROTOCOL) && (msg_msgcnt(msg))) {
- tipc_msg_print(buf,msg_get_wrapped(msg)," /");
+ tipc_msg_dbg(buf, msg_get_wrapped(msg), " /");
}
if ((usr == MSG_FRAGMENTER) && (msg_type(msg) == FIRST_FRAGMENT)) {
- tipc_msg_print(buf,msg_get_wrapped(msg)," /");
+ tipc_msg_dbg(buf, msg_get_wrapped(msg), " /");
}
}
+
+#endif
diff --git a/net/tipc/msg.h b/net/tipc/msg.h
index ad487e8abcc2..7ee6ae238147 100644
--- a/net/tipc/msg.h
+++ b/net/tipc/msg.h
@@ -2,7 +2,7 @@
* net/tipc/msg.h: Include file for TIPC message header routines
*
* Copyright (c) 2000-2007, Ericsson AB
- * Copyright (c) 2005-2007, Wind River Systems
+ * Copyright (c) 2005-2008, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -75,6 +75,14 @@ static inline void msg_set_bits(struct tipc_msg *m, u32 w,
m->hdr[w] |= htonl(val);
}
+static inline void msg_swap_words(struct tipc_msg *msg, u32 a, u32 b)
+{
+ u32 temp = msg->hdr[a];
+
+ msg->hdr[a] = msg->hdr[b];
+ msg->hdr[b] = temp;
+}
+
/*
* Word 0
*/
@@ -119,9 +127,9 @@ static inline int msg_non_seq(struct tipc_msg *m)
return msg_bits(m, 0, 20, 1);
}
-static inline void msg_set_non_seq(struct tipc_msg *m)
+static inline void msg_set_non_seq(struct tipc_msg *m, u32 n)
{
- msg_set_bits(m, 0, 20, 1, 1);
+ msg_set_bits(m, 0, 20, 1, n);
}
static inline int msg_dest_droppable(struct tipc_msg *m)
@@ -224,6 +232,25 @@ static inline void msg_set_seqno(struct tipc_msg *m, u32 n)
msg_set_bits(m, 2, 0, 0xffff, n);
}
+/*
+ * TIPC may utilize the "link ack #" and "link seq #" fields of a short
+ * message header to hold the destination node for the message, since the
+ * normal "dest node" field isn't present. This cache is only referenced
+ * when required, so populating the cache of a longer message header is
+ * harmless (as long as the header has the two link sequence fields present).
+ *
+ * Note: Host byte order is OK here, since the info never goes off-card.
+ */
+
+static inline u32 msg_destnode_cache(struct tipc_msg *m)
+{
+ return m->hdr[2];
+}
+
+static inline void msg_set_destnode_cache(struct tipc_msg *m, u32 dnode)
+{
+ m->hdr[2] = dnode;
+}
/*
* Words 3-10
@@ -325,7 +352,7 @@ static inline struct tipc_msg *msg_get_wrapped(struct tipc_msg *m)
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
w0:|vers |msg usr|hdr sz |n|resrv| packet size |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- w1:|m typ|rsv=0| sequence gap | broadcast ack no |
+ w1:|m typ| sequence gap | broadcast ack no |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
w2:| link level ack no/bc_gap_from | seq no / bcast_gap_to |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -388,12 +415,12 @@ static inline struct tipc_msg *msg_get_wrapped(struct tipc_msg *m)
static inline u32 msg_seq_gap(struct tipc_msg *m)
{
- return msg_bits(m, 1, 16, 0xff);
+ return msg_bits(m, 1, 16, 0x1fff);
}
static inline void msg_set_seq_gap(struct tipc_msg *m, u32 n)
{
- msg_set_bits(m, 1, 16, 0xff, n);
+ msg_set_bits(m, 1, 16, 0x1fff, n);
}
static inline u32 msg_req_links(struct tipc_msg *m)
@@ -696,7 +723,7 @@ static inline u32 msg_tot_importance(struct tipc_msg *m)
static inline void msg_init(struct tipc_msg *m, u32 user, u32 type,
- u32 err, u32 hsize, u32 destnode)
+ u32 hsize, u32 destnode)
{
memset(m, 0, hsize);
msg_set_version(m);
@@ -705,7 +732,6 @@ static inline void msg_init(struct tipc_msg *m, u32 user, u32 type,
msg_set_size(m, hsize);
msg_set_prevnode(m, tipc_own_addr);
msg_set_type(m, type);
- msg_set_errcode(m, err);
if (!msg_short(m)) {
msg_set_orignode(m, tipc_own_addr);
msg_set_destnode(m, destnode);
diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c
index 39fd1619febf..10a69894e2fd 100644
--- a/net/tipc/name_distr.c
+++ b/net/tipc/name_distr.c
@@ -41,9 +41,6 @@
#include "msg.h"
#include "name_distr.h"
-#undef DBG_OUTPUT
-#define DBG_OUTPUT NULL
-
#define ITEM_SIZE sizeof(struct distr_item)
/**
@@ -106,8 +103,7 @@ static struct sk_buff *named_prepare_buf(u32 type, u32 size, u32 dest)
if (buf != NULL) {
msg = buf_msg(buf);
- msg_init(msg, NAME_DISTRIBUTOR, type, TIPC_OK,
- LONG_H_SIZE, dest);
+ msg_init(msg, NAME_DISTRIBUTOR, type, LONG_H_SIZE, dest);
msg_set_size(msg, LONG_H_SIZE + size);
}
return buf;
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c
index ac7dfdda7973..096f7bd240a0 100644
--- a/net/tipc/name_table.c
+++ b/net/tipc/name_table.c
@@ -74,7 +74,7 @@ struct sub_seq {
* @first_free: array index of first unused sub-sequence entry
* @ns_list: links to adjacent name sequences in hash chain
* @subscriptions: list of subscriptions for this 'type'
- * @lock: spinlock controlling access to name sequence structure
+ * @lock: spinlock controlling access to publication lists of all sub-sequences
*/
struct name_seq {
@@ -905,6 +905,9 @@ static void nameseq_list(struct name_seq *seq, struct print_buf *buf, u32 depth,
struct sub_seq *sseq;
char typearea[11];
+ if (seq->first_free == 0)
+ return;
+
sprintf(typearea, "%-10u", seq->type);
if (depth == 1) {
@@ -915,7 +918,9 @@ static void nameseq_list(struct name_seq *seq, struct print_buf *buf, u32 depth,
for (sseq = seq->sseqs; sseq != &seq->sseqs[seq->first_free]; sseq++) {
if ((lowbound <= sseq->upper) && (upbound >= sseq->lower)) {
tipc_printf(buf, "%s ", typearea);
+ spin_lock_bh(&seq->lock);
subseq_list(sseq, buf, depth, index);
+ spin_unlock_bh(&seq->lock);
sprintf(typearea, "%10s", " ");
}
}
@@ -1050,15 +1055,12 @@ void tipc_nametbl_dump(void)
int tipc_nametbl_init(void)
{
- int array_size = sizeof(struct hlist_head) * tipc_nametbl_size;
-
- table.types = kzalloc(array_size, GFP_ATOMIC);
+ table.types = kcalloc(tipc_nametbl_size, sizeof(struct hlist_head),
+ GFP_ATOMIC);
if (!table.types)
return -ENOMEM;
- write_lock_bh(&tipc_nametbl_lock);
table.local_publ_count = 0;
- write_unlock_bh(&tipc_nametbl_lock);
return 0;
}
diff --git a/net/tipc/net.c b/net/tipc/net.c
index c39c76201e8e..cc51fa483672 100644
--- a/net/tipc/net.c
+++ b/net/tipc/net.c
@@ -266,7 +266,7 @@ void tipc_net_route_msg(struct sk_buff *buf)
tipc_link_send(buf, dnode, msg_link_selector(msg));
}
-int tipc_net_start(void)
+int tipc_net_start(u32 addr)
{
char addr_string[16];
int res;
@@ -274,6 +274,10 @@ int tipc_net_start(void)
if (tipc_mode != TIPC_NODE_MODE)
return -ENOPROTOOPT;
+ tipc_subscr_stop();
+ tipc_cfg_stop();
+
+ tipc_own_addr = addr;
tipc_mode = TIPC_NET_MODE;
tipc_named_reinit();
tipc_port_reinit();
@@ -284,10 +288,10 @@ int tipc_net_start(void)
(res = tipc_bclink_init())) {
return res;
}
- tipc_subscr_stop();
- tipc_cfg_stop();
+
tipc_k_signal((Handler)tipc_subscr_start, 0);
tipc_k_signal((Handler)tipc_cfg_init, 0);
+
info("Started in network mode\n");
info("Own node address %s, network identity %u\n",
addr_string_fill(addr_string, tipc_own_addr), tipc_net_id);
diff --git a/net/tipc/net.h b/net/tipc/net.h
index a6a0e9976ac9..d154ac2bda9a 100644
--- a/net/tipc/net.h
+++ b/net/tipc/net.h
@@ -58,7 +58,7 @@ void tipc_net_route_msg(struct sk_buff *buf);
struct node *tipc_net_select_remote_node(u32 addr, u32 ref);
u32 tipc_net_select_router(u32 addr, u32 ref);
-int tipc_net_start(void);
+int tipc_net_start(u32 addr);
void tipc_net_stop(void);
#endif
diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c
index 6a7f7b4c2595..c387217bb230 100644
--- a/net/tipc/netlink.c
+++ b/net/tipc/netlink.c
@@ -2,7 +2,7 @@
* net/tipc/netlink.c: TIPC configuration handling
*
* Copyright (c) 2005-2006, Ericsson AB
- * Copyright (c) 2005, Wind River Systems
+ * Copyright (c) 2005-2007, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -45,15 +45,17 @@ static int handle_cmd(struct sk_buff *skb, struct genl_info *info)
struct nlmsghdr *req_nlh = info->nlhdr;
struct tipc_genlmsghdr *req_userhdr = info->userhdr;
int hdr_space = NLMSG_SPACE(GENL_HDRLEN + TIPC_GENL_HDRLEN);
+ u16 cmd;
if ((req_userhdr->cmd & 0xC000) && (!capable(CAP_NET_ADMIN)))
- rep_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_NET_ADMIN);
+ cmd = TIPC_CMD_NOT_NET_ADMIN;
else
- rep_buf = tipc_cfg_do_cmd(req_userhdr->dest,
- req_userhdr->cmd,
- NLMSG_DATA(req_nlh) + GENL_HDRLEN + TIPC_GENL_HDRLEN,
- NLMSG_PAYLOAD(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN),
- hdr_space);
+ cmd = req_userhdr->cmd;
+
+ rep_buf = tipc_cfg_do_cmd(req_userhdr->dest, cmd,
+ NLMSG_DATA(req_nlh) + GENL_HDRLEN + TIPC_GENL_HDRLEN,
+ NLMSG_PAYLOAD(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN),
+ hdr_space);
if (rep_buf) {
skb_push(rep_buf, hdr_space);
diff --git a/net/tipc/node.c b/net/tipc/node.c
index 598f4d3a0098..34e9a2bb7c19 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -52,16 +52,40 @@ static void node_established_contact(struct node *n_ptr);
struct node *tipc_nodes = NULL; /* sorted list of nodes within cluster */
+static DEFINE_SPINLOCK(node_create_lock);
+
u32 tipc_own_tag = 0;
+/**
+ * tipc_node_create - create neighboring node
+ *
+ * Currently, this routine is called by neighbor discovery code, which holds
+ * net_lock for reading only. We must take node_create_lock to ensure a node
+ * isn't created twice if two different bearers discover the node at the same
+ * time. (It would be preferable to switch to holding net_lock in write mode,
+ * but this is a non-trivial change.)
+ */
+
struct node *tipc_node_create(u32 addr)
{
struct cluster *c_ptr;
struct node *n_ptr;
struct node **curr_node;
+ spin_lock_bh(&node_create_lock);
+
+ for (n_ptr = tipc_nodes; n_ptr; n_ptr = n_ptr->next) {
+ if (addr < n_ptr->addr)
+ break;
+ if (addr == n_ptr->addr) {
+ spin_unlock_bh(&node_create_lock);
+ return n_ptr;
+ }
+ }
+
n_ptr = kzalloc(sizeof(*n_ptr),GFP_ATOMIC);
if (!n_ptr) {
+ spin_unlock_bh(&node_create_lock);
warn("Node creation failed, no memory\n");
return NULL;
}
@@ -71,6 +95,7 @@ struct node *tipc_node_create(u32 addr)
c_ptr = tipc_cltr_create(addr);
}
if (!c_ptr) {
+ spin_unlock_bh(&node_create_lock);
kfree(n_ptr);
return NULL;
}
@@ -91,6 +116,7 @@ struct node *tipc_node_create(u32 addr)
}
}
(*curr_node) = n_ptr;
+ spin_unlock_bh(&node_create_lock);
return n_ptr;
}
diff --git a/net/tipc/port.c b/net/tipc/port.c
index 2f5806410c64..2e0cff408ff9 100644
--- a/net/tipc/port.c
+++ b/net/tipc/port.c
@@ -211,15 +211,18 @@ exit:
}
/**
- * tipc_createport_raw - create a native TIPC port
+ * tipc_createport_raw - create a generic TIPC port
*
- * Returns local port reference
+ * Returns port reference, or 0 if unable to create it
+ *
+ * Note: The newly created port is returned in the locked state.
*/
u32 tipc_createport_raw(void *usr_handle,
u32 (*dispatcher)(struct tipc_port *, struct sk_buff *),
void (*wakeup)(struct tipc_port *),
- const u32 importance)
+ const u32 importance,
+ struct tipc_port **tp_ptr)
{
struct port *p_ptr;
struct tipc_msg *msg;
@@ -237,17 +240,12 @@ u32 tipc_createport_raw(void *usr_handle,
return 0;
}
- tipc_port_lock(ref);
p_ptr->publ.usr_handle = usr_handle;
p_ptr->publ.max_pkt = MAX_PKT_DEFAULT;
p_ptr->publ.ref = ref;
msg = &p_ptr->publ.phdr;
- msg_init(msg, TIPC_LOW_IMPORTANCE, TIPC_NAMED_MSG, TIPC_OK, LONG_H_SIZE,
- 0);
- msg_set_orignode(msg, tipc_own_addr);
- msg_set_prevnode(msg, tipc_own_addr);
+ msg_init(msg, importance, TIPC_NAMED_MSG, LONG_H_SIZE, 0);
msg_set_origport(msg, ref);
- msg_set_importance(msg,importance);
p_ptr->last_in_seqno = 41;
p_ptr->sent = 1;
INIT_LIST_HEAD(&p_ptr->wait_list);
@@ -262,7 +260,7 @@ u32 tipc_createport_raw(void *usr_handle,
INIT_LIST_HEAD(&p_ptr->port_list);
list_add_tail(&p_ptr->port_list, &ports);
spin_unlock_bh(&tipc_port_list_lock);
- tipc_port_unlock(p_ptr);
+ *tp_ptr = &p_ptr->publ;
return ref;
}
@@ -402,10 +400,10 @@ static struct sk_buff *port_build_proto_msg(u32 destport, u32 destnode,
buf = buf_acquire(LONG_H_SIZE);
if (buf) {
msg = buf_msg(buf);
- msg_init(msg, usr, type, err, LONG_H_SIZE, destnode);
+ msg_init(msg, usr, type, LONG_H_SIZE, destnode);
+ msg_set_errcode(msg, err);
msg_set_destport(msg, destport);
msg_set_origport(msg, origport);
- msg_set_destnode(msg, destnode);
msg_set_orignode(msg, orignode);
msg_set_transp_seqno(msg, seqno);
msg_set_msgcnt(msg, ack);
@@ -446,17 +444,19 @@ int tipc_reject_msg(struct sk_buff *buf, u32 err)
return data_sz;
}
rmsg = buf_msg(rbuf);
- msg_init(rmsg, imp, msg_type(msg), err, hdr_sz, msg_orignode(msg));
+ msg_init(rmsg, imp, msg_type(msg), hdr_sz, msg_orignode(msg));
+ msg_set_errcode(rmsg, err);
msg_set_destport(rmsg, msg_origport(msg));
- msg_set_prevnode(rmsg, tipc_own_addr);
msg_set_origport(rmsg, msg_destport(msg));
- if (msg_short(msg))
+ if (msg_short(msg)) {
msg_set_orignode(rmsg, tipc_own_addr);
- else
+ /* leave name type & instance as zeroes */
+ } else {
msg_set_orignode(rmsg, msg_destnode(msg));
+ msg_set_nametype(rmsg, msg_nametype(msg));
+ msg_set_nameinst(rmsg, msg_nameinst(msg));
+ }
msg_set_size(rmsg, data_sz + hdr_sz);
- msg_set_nametype(rmsg, msg_nametype(msg));
- msg_set_nameinst(rmsg, msg_nameinst(msg));
skb_copy_to_linear_data_offset(rbuf, hdr_sz, msg_data(msg), data_sz);
/* send self-abort message when rejecting on a connected port */
@@ -778,6 +778,7 @@ void tipc_port_reinit(void)
msg = &p_ptr->publ.phdr;
if (msg_orignode(msg) == tipc_own_addr)
break;
+ msg_set_prevnode(msg, tipc_own_addr);
msg_set_orignode(msg, tipc_own_addr);
}
spin_unlock_bh(&tipc_port_list_lock);
@@ -838,16 +839,13 @@ static void port_dispatcher_sigh(void *dummy)
u32 peer_node = port_peernode(p_ptr);
tipc_port_unlock(p_ptr);
+ if (unlikely(!cb))
+ goto reject;
if (unlikely(!connected)) {
- if (unlikely(published))
+ if (tipc_connect2port(dref, &orig))
goto reject;
- tipc_connect2port(dref,&orig);
- }
- if (unlikely(msg_origport(msg) != peer_port))
- goto reject;
- if (unlikely(msg_orignode(msg) != peer_node))
- goto reject;
- if (unlikely(!cb))
+ } else if ((msg_origport(msg) != peer_port) ||
+ (msg_orignode(msg) != peer_node))
goto reject;
if (unlikely(++p_ptr->publ.conn_unacked >=
TIPC_FLOW_CONTROL_WIN))
@@ -862,9 +860,7 @@ static void port_dispatcher_sigh(void *dummy)
tipc_msg_event cb = up_ptr->msg_cb;
tipc_port_unlock(p_ptr);
- if (unlikely(connected))
- goto reject;
- if (unlikely(!cb))
+ if (unlikely(!cb || connected))
goto reject;
skb_pull(buf, msg_hdr_sz(msg));
cb(usr_handle, dref, &buf, msg_data(msg),
@@ -877,11 +873,7 @@ static void port_dispatcher_sigh(void *dummy)
tipc_named_msg_event cb = up_ptr->named_msg_cb;
tipc_port_unlock(p_ptr);
- if (unlikely(connected))
- goto reject;
- if (unlikely(!cb))
- goto reject;
- if (unlikely(!published))
+ if (unlikely(!cb || connected || !published))
goto reject;
dseq.type = msg_nametype(msg);
dseq.lower = msg_nameinst(msg);
@@ -908,11 +900,10 @@ err:
u32 peer_node = port_peernode(p_ptr);
tipc_port_unlock(p_ptr);
- if (!connected || !cb)
- break;
- if (msg_origport(msg) != peer_port)
+ if (!cb || !connected)
break;
- if (msg_orignode(msg) != peer_node)
+ if ((msg_origport(msg) != peer_port) ||
+ (msg_orignode(msg) != peer_node))
break;
tipc_disconnect(dref);
skb_pull(buf, msg_hdr_sz(msg));
@@ -924,7 +915,7 @@ err:
tipc_msg_err_event cb = up_ptr->err_cb;
tipc_port_unlock(p_ptr);
- if (connected || !cb)
+ if (!cb || connected)
break;
skb_pull(buf, msg_hdr_sz(msg));
cb(usr_handle, dref, &buf, msg_data(msg),
@@ -937,7 +928,7 @@ err:
up_ptr->named_err_cb;
tipc_port_unlock(p_ptr);
- if (connected || !cb)
+ if (!cb || connected)
break;
dseq.type = msg_nametype(msg);
dseq.lower = msg_nameinst(msg);
@@ -1053,6 +1044,7 @@ int tipc_createport(u32 user_ref,
{
struct user_port *up_ptr;
struct port *p_ptr;
+ struct tipc_port *tp_ptr;
u32 ref;
up_ptr = kmalloc(sizeof(*up_ptr), GFP_ATOMIC);
@@ -1060,12 +1052,13 @@ int tipc_createport(u32 user_ref,
warn("Port creation failed, no memory\n");
return -ENOMEM;
}
- ref = tipc_createport_raw(NULL, port_dispatcher, port_wakeup, importance);
- p_ptr = tipc_port_lock(ref);
- if (!p_ptr) {
+ ref = tipc_createport_raw(NULL, port_dispatcher, port_wakeup,
+ importance, &tp_ptr);
+ if (ref == 0) {
kfree(up_ptr);
return -ENOMEM;
}
+ p_ptr = (struct port *)tp_ptr;
p_ptr->user_port = up_ptr;
up_ptr->user_ref = user_ref;
diff --git a/net/tipc/ref.c b/net/tipc/ref.c
index 89cbab24d08f..a101de86824d 100644
--- a/net/tipc/ref.c
+++ b/net/tipc/ref.c
@@ -142,9 +142,13 @@ void tipc_ref_table_stop(void)
/**
* tipc_ref_acquire - create reference to an object
*
- * Return a unique reference value which can be translated back to the pointer
- * 'object' at a later time. Also, pass back a pointer to the lock protecting
- * the object, but without locking it.
+ * Register an object pointer in reference table and lock the object.
+ * Returns a unique reference value that is used from then on to retrieve the
+ * object pointer, or to determine that the object has been deregistered.
+ *
+ * Note: The object is returned in the locked state so that the caller can
+ * register a partially initialized object, without running the risk that
+ * the object will be accessed before initialization is complete.
*/
u32 tipc_ref_acquire(void *object, spinlock_t **lock)
@@ -178,13 +182,13 @@ u32 tipc_ref_acquire(void *object, spinlock_t **lock)
ref = (next_plus_upper & ~index_mask) + index;
entry->ref = ref;
entry->object = object;
- spin_unlock_bh(&entry->lock);
*lock = &entry->lock;
}
else if (tipc_ref_table.init_point < tipc_ref_table.capacity) {
index = tipc_ref_table.init_point++;
entry = &(tipc_ref_table.entries[index]);
spin_lock_init(&entry->lock);
+ spin_lock_bh(&entry->lock);
ref = tipc_ref_table.start_mask + index;
entry->ref = ref;
entry->object = object;
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 230f9ca2ad6b..38f48795b40e 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -188,6 +188,7 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol)
const struct proto_ops *ops;
socket_state state;
struct sock *sk;
+ struct tipc_port *tp_ptr;
u32 portref;
/* Validate arguments */
@@ -225,7 +226,7 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol)
/* Allocate TIPC port for socket to use */
portref = tipc_createport_raw(sk, &dispatch, &wakeupdispatch,
- TIPC_LOW_IMPORTANCE);
+ TIPC_LOW_IMPORTANCE, &tp_ptr);
if (unlikely(portref == 0)) {
sk_free(sk);
return -ENOMEM;
@@ -241,6 +242,8 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol)
sk->sk_backlog_rcv = backlog_rcv;
tipc_sk(sk)->p = tipc_get_port(portref);
+ spin_unlock_bh(tp_ptr->lock);
+
if (sock->state == SS_READY) {
tipc_set_portunreturnable(portref, 1);
if (sock->type == SOCK_DGRAM)
diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c
index 8c01ccd3626c..0326d3060bc7 100644
--- a/net/tipc/subscr.c
+++ b/net/tipc/subscr.c
@@ -1,8 +1,8 @@
/*
- * net/tipc/subscr.c: TIPC subscription service
+ * net/tipc/subscr.c: TIPC network topology service
*
* Copyright (c) 2000-2006, Ericsson AB
- * Copyright (c) 2005, Wind River Systems
+ * Copyright (c) 2005-2007, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -36,27 +36,24 @@
#include "core.h"
#include "dbg.h"
-#include "subscr.h"
#include "name_table.h"
+#include "port.h"
#include "ref.h"
+#include "subscr.h"
/**
* struct subscriber - TIPC network topology subscriber
- * @ref: object reference to subscriber object itself
- * @lock: pointer to spinlock controlling access to subscriber object
+ * @port_ref: object reference to server port connecting to subscriber
+ * @lock: pointer to spinlock controlling access to subscriber's server port
* @subscriber_list: adjacent subscribers in top. server's list of subscribers
* @subscription_list: list of subscription objects for this subscriber
- * @port_ref: object reference to port used to communicate with subscriber
- * @swap: indicates if subscriber uses opposite endianness in its messages
*/
struct subscriber {
- u32 ref;
+ u32 port_ref;
spinlock_t *lock;
struct list_head subscriber_list;
struct list_head subscription_list;
- u32 port_ref;
- int swap;
};
/**
@@ -88,13 +85,14 @@ static struct top_srv topsrv = { 0 };
static u32 htohl(u32 in, int swap)
{
- char *c = (char *)&in;
-
- return swap ? ((c[3] << 3) + (c[2] << 2) + (c[1] << 1) + c[0]) : in;
+ return swap ? (u32)___constant_swab32(in) : in;
}
/**
* subscr_send_event - send a message containing a tipc_event to the subscriber
+ *
+ * Note: Must not hold subscriber's server port lock, since tipc_send() will
+ * try to take the lock if the message is rejected and returned!
*/
static void subscr_send_event(struct subscription *sub,
@@ -109,12 +107,12 @@ static void subscr_send_event(struct subscription *sub,
msg_sect.iov_base = (void *)&sub->evt;
msg_sect.iov_len = sizeof(struct tipc_event);
- sub->evt.event = htohl(event, sub->owner->swap);
- sub->evt.found_lower = htohl(found_lower, sub->owner->swap);
- sub->evt.found_upper = htohl(found_upper, sub->owner->swap);
- sub->evt.port.ref = htohl(port_ref, sub->owner->swap);
- sub->evt.port.node = htohl(node, sub->owner->swap);
- tipc_send(sub->owner->port_ref, 1, &msg_sect);
+ sub->evt.event = htohl(event, sub->swap);
+ sub->evt.found_lower = htohl(found_lower, sub->swap);
+ sub->evt.found_upper = htohl(found_upper, sub->swap);
+ sub->evt.port.ref = htohl(port_ref, sub->swap);
+ sub->evt.port.node = htohl(node, sub->swap);
+ tipc_send(sub->server_ref, 1, &msg_sect);
}
/**
@@ -151,13 +149,12 @@ void tipc_subscr_report_overlap(struct subscription *sub,
u32 node,
int must)
{
- dbg("Rep overlap %u:%u,%u<->%u,%u\n", sub->seq.type, sub->seq.lower,
- sub->seq.upper, found_lower, found_upper);
if (!tipc_subscr_overlap(sub, found_lower, found_upper))
return;
if (!must && !(sub->filter & TIPC_SUB_PORTS))
return;
- subscr_send_event(sub, found_lower, found_upper, event, port_ref, node);
+
+ sub->event_cb(sub, found_lower, found_upper, event, port_ref, node);
}
/**
@@ -166,20 +163,18 @@ void tipc_subscr_report_overlap(struct subscription *sub,
static void subscr_timeout(struct subscription *sub)
{
- struct subscriber *subscriber;
- u32 subscriber_ref;
+ struct port *server_port;
- /* Validate subscriber reference (in case subscriber is terminating) */
+ /* Validate server port reference (in case subscriber is terminating) */
- subscriber_ref = sub->owner->ref;
- subscriber = (struct subscriber *)tipc_ref_lock(subscriber_ref);
- if (subscriber == NULL)
+ server_port = tipc_port_lock(sub->server_ref);
+ if (server_port == NULL)
return;
/* Validate timeout (in case subscription is being cancelled) */
if (sub->timeout == TIPC_WAIT_FOREVER) {
- tipc_ref_unlock(subscriber_ref);
+ tipc_port_unlock(server_port);
return;
}
@@ -187,19 +182,21 @@ static void subscr_timeout(struct subscription *sub)
tipc_nametbl_unsubscribe(sub);
- /* Notify subscriber of timeout, then unlink subscription */
+ /* Unlink subscription from subscriber */
- subscr_send_event(sub,
- sub->evt.s.seq.lower,
- sub->evt.s.seq.upper,
- TIPC_SUBSCR_TIMEOUT,
- 0,
- 0);
list_del(&sub->subscription_list);
+ /* Release subscriber's server port */
+
+ tipc_port_unlock(server_port);
+
+ /* Notify subscriber of timeout */
+
+ subscr_send_event(sub, sub->evt.s.seq.lower, sub->evt.s.seq.upper,
+ TIPC_SUBSCR_TIMEOUT, 0, 0);
+
/* Now destroy subscription */
- tipc_ref_unlock(subscriber_ref);
k_term_timer(&sub->timer);
kfree(sub);
atomic_dec(&topsrv.subscription_count);
@@ -208,7 +205,7 @@ static void subscr_timeout(struct subscription *sub)
/**
* subscr_del - delete a subscription within a subscription list
*
- * Called with subscriber locked.
+ * Called with subscriber port locked.
*/
static void subscr_del(struct subscription *sub)
@@ -222,7 +219,7 @@ static void subscr_del(struct subscription *sub)
/**
* subscr_terminate - terminate communication with a subscriber
*
- * Called with subscriber locked. Routine must temporarily release this lock
+ * Called with subscriber port locked. Routine must temporarily release lock
* to enable subscription timeout routine(s) to finish without deadlocking;
* the lock is then reclaimed to allow caller to release it upon return.
* (This should work even in the unlikely event some other thread creates
@@ -232,14 +229,21 @@ static void subscr_del(struct subscription *sub)
static void subscr_terminate(struct subscriber *subscriber)
{
+ u32 port_ref;
struct subscription *sub;
struct subscription *sub_temp;
/* Invalidate subscriber reference */
- tipc_ref_discard(subscriber->ref);
+ port_ref = subscriber->port_ref;
+ subscriber->port_ref = 0;
spin_unlock_bh(subscriber->lock);
+ /* Sever connection to subscriber */
+
+ tipc_shutdown(port_ref);
+ tipc_deleteport(port_ref);
+
/* Destroy any existing subscriptions for subscriber */
list_for_each_entry_safe(sub, sub_temp, &subscriber->subscription_list,
@@ -253,27 +257,25 @@ static void subscr_terminate(struct subscriber *subscriber)
subscr_del(sub);
}
- /* Sever connection to subscriber */
-
- tipc_shutdown(subscriber->port_ref);
- tipc_deleteport(subscriber->port_ref);
-
/* Remove subscriber from topology server's subscriber list */
spin_lock_bh(&topsrv.lock);
list_del(&subscriber->subscriber_list);
spin_unlock_bh(&topsrv.lock);
- /* Now destroy subscriber */
+ /* Reclaim subscriber lock */
spin_lock_bh(subscriber->lock);
+
+ /* Now destroy subscriber */
+
kfree(subscriber);
}
/**
* subscr_cancel - handle subscription cancellation request
*
- * Called with subscriber locked. Routine must temporarily release this lock
+ * Called with subscriber port locked. Routine must temporarily release lock
* to enable the subscription timeout routine to finish without deadlocking;
* the lock is then reclaimed to allow caller to release it upon return.
*
@@ -316,27 +318,25 @@ static void subscr_cancel(struct tipc_subscr *s,
/**
* subscr_subscribe - create subscription for subscriber
*
- * Called with subscriber locked
+ * Called with subscriber port locked.
*/
-static void subscr_subscribe(struct tipc_subscr *s,
- struct subscriber *subscriber)
+static struct subscription *subscr_subscribe(struct tipc_subscr *s,
+ struct subscriber *subscriber)
{
struct subscription *sub;
+ int swap;
- /* Determine/update subscriber's endianness */
+ /* Determine subscriber's endianness */
- if (s->filter & (TIPC_SUB_PORTS | TIPC_SUB_SERVICE))
- subscriber->swap = 0;
- else
- subscriber->swap = 1;
+ swap = !(s->filter & (TIPC_SUB_PORTS | TIPC_SUB_SERVICE));
/* Detect & process a subscription cancellation request */
- if (s->filter & htohl(TIPC_SUB_CANCEL, subscriber->swap)) {
- s->filter &= ~htohl(TIPC_SUB_CANCEL, subscriber->swap);
+ if (s->filter & htohl(TIPC_SUB_CANCEL, swap)) {
+ s->filter &= ~htohl(TIPC_SUB_CANCEL, swap);
subscr_cancel(s, subscriber);
- return;
+ return NULL;
}
/* Refuse subscription if global limit exceeded */
@@ -345,63 +345,66 @@ static void subscr_subscribe(struct tipc_subscr *s,
warn("Subscription rejected, subscription limit reached (%u)\n",
tipc_max_subscriptions);
subscr_terminate(subscriber);
- return;
+ return NULL;
}
/* Allocate subscription object */
- sub = kzalloc(sizeof(*sub), GFP_ATOMIC);
+ sub = kmalloc(sizeof(*sub), GFP_ATOMIC);
if (!sub) {
warn("Subscription rejected, no memory\n");
subscr_terminate(subscriber);
- return;
+ return NULL;
}
/* Initialize subscription object */
- sub->seq.type = htohl(s->seq.type, subscriber->swap);
- sub->seq.lower = htohl(s->seq.lower, subscriber->swap);
- sub->seq.upper = htohl(s->seq.upper, subscriber->swap);
- sub->timeout = htohl(s->timeout, subscriber->swap);
- sub->filter = htohl(s->filter, subscriber->swap);
+ sub->seq.type = htohl(s->seq.type, swap);
+ sub->seq.lower = htohl(s->seq.lower, swap);
+ sub->seq.upper = htohl(s->seq.upper, swap);
+ sub->timeout = htohl(s->timeout, swap);
+ sub->filter = htohl(s->filter, swap);
if ((!(sub->filter & TIPC_SUB_PORTS)
== !(sub->filter & TIPC_SUB_SERVICE))
|| (sub->seq.lower > sub->seq.upper)) {
warn("Subscription rejected, illegal request\n");
kfree(sub);
subscr_terminate(subscriber);
- return;
+ return NULL;
}
- memcpy(&sub->evt.s, s, sizeof(struct tipc_subscr));
- INIT_LIST_HEAD(&sub->subscription_list);
+ sub->event_cb = subscr_send_event;
INIT_LIST_HEAD(&sub->nameseq_list);
list_add(&sub->subscription_list, &subscriber->subscription_list);
+ sub->server_ref = subscriber->port_ref;
+ sub->swap = swap;
+ memcpy(&sub->evt.s, s, sizeof(struct tipc_subscr));
atomic_inc(&topsrv.subscription_count);
if (sub->timeout != TIPC_WAIT_FOREVER) {
k_init_timer(&sub->timer,
(Handler)subscr_timeout, (unsigned long)sub);
k_start_timer(&sub->timer, sub->timeout);
}
- sub->owner = subscriber;
- tipc_nametbl_subscribe(sub);
+
+ return sub;
}
/**
* subscr_conn_shutdown_event - handle termination request from subscriber
+ *
+ * Called with subscriber's server port unlocked.
*/
static void subscr_conn_shutdown_event(void *usr_handle,
- u32 portref,
+ u32 port_ref,
struct sk_buff **buf,
unsigned char const *data,
unsigned int size,
int reason)
{
- struct subscriber *subscriber;
+ struct subscriber *subscriber = usr_handle;
spinlock_t *subscriber_lock;
- subscriber = tipc_ref_lock((u32)(unsigned long)usr_handle);
- if (subscriber == NULL)
+ if (tipc_port_lock(port_ref) == NULL)
return;
subscriber_lock = subscriber->lock;
@@ -411,6 +414,8 @@ static void subscr_conn_shutdown_event(void *usr_handle,
/**
* subscr_conn_msg_event - handle new subscription request from subscriber
+ *
+ * Called with subscriber's server port unlocked.
*/
static void subscr_conn_msg_event(void *usr_handle,
@@ -419,20 +424,46 @@ static void subscr_conn_msg_event(void *usr_handle,
const unchar *data,
u32 size)
{
- struct subscriber *subscriber;
+ struct subscriber *subscriber = usr_handle;
spinlock_t *subscriber_lock;
+ struct subscription *sub;
+
+ /*
+ * Lock subscriber's server port (& make a local copy of lock pointer,
+ * in case subscriber is deleted while processing subscription request)
+ */
- subscriber = tipc_ref_lock((u32)(unsigned long)usr_handle);
- if (subscriber == NULL)
+ if (tipc_port_lock(port_ref) == NULL)
return;
subscriber_lock = subscriber->lock;
- if (size != sizeof(struct tipc_subscr))
- subscr_terminate(subscriber);
- else
- subscr_subscribe((struct tipc_subscr *)data, subscriber);
- spin_unlock_bh(subscriber_lock);
+ if (size != sizeof(struct tipc_subscr)) {
+ subscr_terminate(subscriber);
+ spin_unlock_bh(subscriber_lock);
+ } else {
+ sub = subscr_subscribe((struct tipc_subscr *)data, subscriber);
+ spin_unlock_bh(subscriber_lock);
+ if (sub != NULL) {
+
+ /*
+ * We must release the server port lock before adding a
+ * subscription to the name table since TIPC needs to be
+ * able to (re)acquire the port lock if an event message
+ * issued by the subscription process is rejected and
+ * returned. The subscription cannot be deleted while
+ * it is being added to the name table because:
+ * a) the single-threading of the native API port code
+ * ensures the subscription cannot be cancelled and
+ * the subscriber connection cannot be broken, and
+ * b) the name table lock ensures the subscription
+ * timeout code cannot delete the subscription,
+ * so the subscription object is still protected.
+ */
+
+ tipc_nametbl_subscribe(sub);
+ }
+ }
}
/**
@@ -448,16 +479,10 @@ static void subscr_named_msg_event(void *usr_handle,
struct tipc_portid const *orig,
struct tipc_name_seq const *dest)
{
- struct subscriber *subscriber;
- struct iovec msg_sect = {NULL, 0};
- spinlock_t *subscriber_lock;
+ static struct iovec msg_sect = {NULL, 0};
- dbg("subscr_named_msg_event: orig = %x own = %x,\n",
- orig->node, tipc_own_addr);
- if (size && (size != sizeof(struct tipc_subscr))) {
- warn("Subscriber rejected, invalid subscription size\n");
- return;
- }
+ struct subscriber *subscriber;
+ u32 server_port_ref;
/* Create subscriber object */
@@ -468,17 +493,11 @@ static void subscr_named_msg_event(void *usr_handle,
}
INIT_LIST_HEAD(&subscriber->subscription_list);
INIT_LIST_HEAD(&subscriber->subscriber_list);
- subscriber->ref = tipc_ref_acquire(subscriber, &subscriber->lock);
- if (subscriber->ref == 0) {
- warn("Subscriber rejected, reference table exhausted\n");
- kfree(subscriber);
- return;
- }
- /* Establish a connection to subscriber */
+ /* Create server port & establish connection to subscriber */
tipc_createport(topsrv.user_ref,
- (void *)(unsigned long)subscriber->ref,
+ subscriber,
importance,
NULL,
NULL,
@@ -490,32 +509,36 @@ static void subscr_named_msg_event(void *usr_handle,
&subscriber->port_ref);
if (subscriber->port_ref == 0) {
warn("Subscriber rejected, unable to create port\n");
- tipc_ref_discard(subscriber->ref);
kfree(subscriber);
return;
}
tipc_connect2port(subscriber->port_ref, orig);
+ /* Lock server port (& save lock address for future use) */
+
+ subscriber->lock = tipc_port_lock(subscriber->port_ref)->publ.lock;
/* Add subscriber to topology server's subscriber list */
- tipc_ref_lock(subscriber->ref);
spin_lock_bh(&topsrv.lock);
list_add(&subscriber->subscriber_list, &topsrv.subscriber_list);
spin_unlock_bh(&topsrv.lock);
- /*
- * Subscribe now if message contains a subscription,
- * otherwise send an empty response to complete connection handshaking
- */
+ /* Unlock server port */
- subscriber_lock = subscriber->lock;
- if (size)
- subscr_subscribe((struct tipc_subscr *)data, subscriber);
- else
- tipc_send(subscriber->port_ref, 1, &msg_sect);
+ server_port_ref = subscriber->port_ref;
+ spin_unlock_bh(subscriber->lock);
- spin_unlock_bh(subscriber_lock);
+ /* Send an ACK- to complete connection handshaking */
+
+ tipc_send(server_port_ref, 1, &msg_sect);
+
+ /* Handle optional subscription request */
+
+ if (size != 0) {
+ subscr_conn_msg_event(subscriber, server_port_ref,
+ buf, data, size);
+ }
}
int tipc_subscr_start(void)
@@ -574,8 +597,8 @@ void tipc_subscr_stop(void)
list_for_each_entry_safe(subscriber, subscriber_temp,
&topsrv.subscriber_list,
subscriber_list) {
- tipc_ref_lock(subscriber->ref);
subscriber_lock = subscriber->lock;
+ spin_lock_bh(subscriber_lock);
subscr_terminate(subscriber);
spin_unlock_bh(subscriber_lock);
}
diff --git a/net/tipc/subscr.h b/net/tipc/subscr.h
index 93a8e674fac1..45d89bf4d202 100644
--- a/net/tipc/subscr.h
+++ b/net/tipc/subscr.h
@@ -1,8 +1,8 @@
/*
- * net/tipc/subscr.h: Include file for TIPC subscription service
+ * net/tipc/subscr.h: Include file for TIPC network topology service
*
* Copyright (c) 2003-2006, Ericsson AB
- * Copyright (c) 2005, Wind River Systems
+ * Copyright (c) 2005-2007, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -37,34 +37,44 @@
#ifndef _TIPC_SUBSCR_H
#define _TIPC_SUBSCR_H
+struct subscription;
+
+typedef void (*tipc_subscr_event) (struct subscription *sub,
+ u32 found_lower, u32 found_upper,
+ u32 event, u32 port_ref, u32 node);
+
/**
* struct subscription - TIPC network topology subscription object
* @seq: name sequence associated with subscription
* @timeout: duration of subscription (in ms)
* @filter: event filtering to be done for subscription
- * @evt: template for events generated by subscription
- * @subscription_list: adjacent subscriptions in subscriber's subscription list
+ * @event_cb: routine invoked when a subscription event is detected
+ * @timer: timer governing subscription duration (optional)
* @nameseq_list: adjacent subscriptions in name sequence's subscription list
- * @timer_ref: reference to timer governing subscription duration (may be NULL)
- * @owner: pointer to subscriber object associated with this subscription
+ * @subscription_list: adjacent subscriptions in subscriber's subscription list
+ * @server_ref: object reference of server port associated with subscription
+ * @swap: indicates if subscriber uses opposite endianness in its messages
+ * @evt: template for events generated by subscription
*/
struct subscription {
struct tipc_name_seq seq;
u32 timeout;
u32 filter;
- struct tipc_event evt;
- struct list_head subscription_list;
- struct list_head nameseq_list;
+ tipc_subscr_event event_cb;
struct timer_list timer;
- struct subscriber *owner;
+ struct list_head nameseq_list;
+ struct list_head subscription_list;
+ u32 server_ref;
+ int swap;
+ struct tipc_event evt;
};
-int tipc_subscr_overlap(struct subscription * sub,
+int tipc_subscr_overlap(struct subscription *sub,
u32 found_lower,
u32 found_upper);
-void tipc_subscr_report_overlap(struct subscription * sub,
+void tipc_subscr_report_overlap(struct subscription *sub,
u32 found_lower,
u32 found_upper,
u32 event,
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index e18cd3628db4..392e80e3268d 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -8,8 +8,6 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * Version: $Id: af_unix.c,v 1.133 2002/02/08 03:57:19 davem Exp $
- *
* Fixes:
* Linus Torvalds : Assorted bug cures.
* Niibe Yutaka : async I/O support.
diff --git a/net/wanrouter/wanmain.c b/net/wanrouter/wanmain.c
index 9ab31a3ce3ad..b210a88d0960 100644
--- a/net/wanrouter/wanmain.c
+++ b/net/wanrouter/wanmain.c
@@ -350,9 +350,9 @@ __be16 wanrouter_type_trans(struct sk_buff *skb, struct net_device *dev)
* o execute requested action or pass command to the device driver
*/
-int wanrouter_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+long wanrouter_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
+ struct inode *inode = file->f_path.dentry->d_inode;
int err = 0;
struct proc_dir_entry *dent;
struct wan_device *wandev;
@@ -372,6 +372,7 @@ int wanrouter_ioctl(struct inode *inode, struct file *file,
if (wandev->magic != ROUTER_MAGIC)
return -EINVAL;
+ lock_kernel();
switch (cmd) {
case ROUTER_SETUP:
err = wanrouter_device_setup(wandev, data);
@@ -403,6 +404,7 @@ int wanrouter_ioctl(struct inode *inode, struct file *file,
err = wandev->ioctl(wandev, cmd, arg);
else err = -EINVAL;
}
+ unlock_kernel();
return err;
}
diff --git a/net/wanrouter/wanproc.c b/net/wanrouter/wanproc.c
index 5bebe40bf4e6..267f7ff49827 100644
--- a/net/wanrouter/wanproc.c
+++ b/net/wanrouter/wanproc.c
@@ -278,7 +278,7 @@ static const struct file_operations wandev_fops = {
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
- .ioctl = wanrouter_ioctl,
+ .unlocked_ioctl = wanrouter_ioctl,
};
/*
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 80afacdae46c..f1da0b93bc56 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -143,8 +143,11 @@ void cfg80211_put_dev(struct cfg80211_registered_device *drv)
int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
char *newname)
{
+ struct cfg80211_registered_device *drv;
int idx, taken = -1, result, digits;
+ mutex_lock(&cfg80211_drv_mutex);
+
/* prohibit calling the thing phy%d when %d is not its number */
sscanf(newname, PHY_NAME "%d%n", &idx, &taken);
if (taken == strlen(newname) && idx != rdev->idx) {
@@ -156,14 +159,30 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
* deny the name if it is phy<idx> where <idx> is printed
* without leading zeroes. taken == strlen(newname) here
*/
+ result = -EINVAL;
if (taken == strlen(PHY_NAME) + digits)
- return -EINVAL;
+ goto out_unlock;
+ }
+
+
+ /* Ignore nop renames */
+ result = 0;
+ if (strcmp(newname, dev_name(&rdev->wiphy.dev)) == 0)
+ goto out_unlock;
+
+ /* Ensure another device does not already have this name. */
+ list_for_each_entry(drv, &cfg80211_drv_list, list) {
+ result = -EINVAL;
+ if (strcmp(newname, dev_name(&drv->wiphy.dev)) == 0)
+ goto out_unlock;
}
- /* this will check for collisions */
+ /* this will only check for collisions in sysfs
+ * which is not even always compiled in.
+ */
result = device_rename(&rdev->wiphy.dev, newname);
if (result)
- return result;
+ goto out_unlock;
if (!debugfs_rename(rdev->wiphy.debugfsdir->d_parent,
rdev->wiphy.debugfsdir,
@@ -172,9 +191,13 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
printk(KERN_ERR "cfg80211: failed to rename debugfs dir to %s!\n",
newname);
- nl80211_notify_dev_rename(rdev);
+ result = 0;
+out_unlock:
+ mutex_unlock(&cfg80211_drv_mutex);
+ if (result == 0)
+ nl80211_notify_dev_rename(rdev);
- return 0;
+ return result;
}
/* exported functions */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 2bdd4dddc0e1..fb75f265b39c 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -187,7 +187,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
return genlmsg_end(msg, hdr);
nla_put_failure:
- return genlmsg_cancel(msg, hdr);
+ genlmsg_cancel(msg, hdr);
+ return -EMSGSIZE;
}
static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
@@ -273,7 +274,8 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags,
return genlmsg_end(msg, hdr);
nla_put_failure:
- return genlmsg_cancel(msg, hdr);
+ genlmsg_cancel(msg, hdr);
+ return -EMSGSIZE;
}
static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *cb)
@@ -928,7 +930,8 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
return genlmsg_end(msg, hdr);
nla_put_failure:
- return genlmsg_cancel(msg, hdr);
+ genlmsg_cancel(msg, hdr);
+ return -EMSGSIZE;
}
static int nl80211_dump_station(struct sk_buff *skb,
@@ -1267,7 +1270,8 @@ static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq,
return genlmsg_end(msg, hdr);
nla_put_failure:
- return genlmsg_cancel(msg, hdr);
+ genlmsg_cancel(msg, hdr);
+ return -EMSGSIZE;
}
static int nl80211_dump_mpath(struct sk_buff *skb,
diff --git a/net/wireless/radiotap.c b/net/wireless/radiotap.c
index 28fbd0b0b568..f591871a7b4f 100644
--- a/net/wireless/radiotap.c
+++ b/net/wireless/radiotap.c
@@ -59,23 +59,21 @@ int ieee80211_radiotap_iterator_init(
return -EINVAL;
/* sanity check for allowed length and radiotap length field */
- if (max_length < le16_to_cpu(get_unaligned(&radiotap_header->it_len)))
+ if (max_length < get_unaligned_le16(&radiotap_header->it_len))
return -EINVAL;
iterator->rtheader = radiotap_header;
- iterator->max_length = le16_to_cpu(get_unaligned(
- &radiotap_header->it_len));
+ iterator->max_length = get_unaligned_le16(&radiotap_header->it_len);
iterator->arg_index = 0;
- iterator->bitmap_shifter = le32_to_cpu(get_unaligned(
- &radiotap_header->it_present));
+ iterator->bitmap_shifter = get_unaligned_le32(&radiotap_header->it_present);
iterator->arg = (u8 *)radiotap_header + sizeof(*radiotap_header);
iterator->this_arg = NULL;
/* find payload start allowing for extended bitmap(s) */
if (unlikely(iterator->bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT))) {
- while (le32_to_cpu(get_unaligned((__le32 *)iterator->arg)) &
- (1<<IEEE80211_RADIOTAP_EXT)) {
+ while (get_unaligned_le32(iterator->arg) &
+ (1 << IEEE80211_RADIOTAP_EXT)) {
iterator->arg += sizeof(u32);
/*
@@ -241,8 +239,8 @@ int ieee80211_radiotap_iterator_next(
if (iterator->bitmap_shifter & 1) {
/* b31 was set, there is more */
/* move to next u32 bitmap */
- iterator->bitmap_shifter = le32_to_cpu(
- get_unaligned(iterator->next_bitmap));
+ iterator->bitmap_shifter =
+ get_unaligned_le32(iterator->next_bitmap);
iterator->next_bitmap++;
} else
/* no more bitmaps: end */
diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c
index ac765dd9c7f5..23a2cc04b8cd 100644
--- a/net/xfrm/xfrm_algo.c
+++ b/net/xfrm/xfrm_algo.c
@@ -200,8 +200,8 @@ static struct xfrm_algo_desc aalg_list[] = {
}
},
{
- .name = "hmac(ripemd160)",
- .compat = "ripemd160",
+ .name = "hmac(rmd160)",
+ .compat = "rmd160",
.uinfo = {
.auth = {
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index a1b0fbe3ea35..b976d9ed10e4 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -50,19 +50,8 @@ static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type)
switch (type) {
case XFRMA_ALG_AUTH:
- if (!algp->alg_key_len &&
- strcmp(algp->alg_name, "digest_null") != 0)
- return -EINVAL;
- break;
-
case XFRMA_ALG_CRYPT:
- if (!algp->alg_key_len &&
- strcmp(algp->alg_name, "cipher_null") != 0)
- return -EINVAL;
- break;
-
case XFRMA_ALG_COMP:
- /* Zero length keys are legal. */
break;
default: