From 8bf4b8a1083694d5aac292f92705ddd3aec29be6 Mon Sep 17 00:00:00 2001
From: Herbert Xu <herbert@gondor.apana.org.au>
Date: Tue, 4 Apr 2006 12:51:05 -0700
Subject: [PATCH 01/35] [IPSEC]: Check x->encap before dereferencing it

We need to dereference x->encap before dereferencing it for encap_type.
If it's absent then the encap_type is zero.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/ipv4/xfrm4_input.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c
index e1b8f4b90d80..7a0b9524fe08 100644
--- a/net/ipv4/xfrm4_input.c
+++ b/net/ipv4/xfrm4_input.c
@@ -90,7 +90,7 @@ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
 		if (unlikely(x->km.state != XFRM_STATE_VALID))
 			goto drop_unlock;
 
-		if (x->encap->encap_type != encap_type)
+		if ((x->encap ? x->encap->encap_type : 0) != encap_type)
 			goto drop_unlock;
 
 		if (x->props.replay_window && xfrm_replay_check(x, seq))

From 550e29bc96e6f1ced2bca82dace197b009434367 Mon Sep 17 00:00:00 2001
From: Robert Olsson <robert.olsson@its.uu.se>
Date: Tue, 4 Apr 2006 12:53:35 -0700
Subject: [PATCH 02/35] [FIB_TRIE]: Fix leaf freeing.

Seems like leaf (end-nodes) has been freed by __tnode_free_rcu and not
by __leaf_free_rcu. This fixes the problem. Only tnode_free is now
used which checks for appropriate node type. free_leaf can be removed.

Signed-off-by: Robert Olsson <robert.olsson@its.uu.se>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/ipv4/fib_trie.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index ccd3efc6a173..95a639f2e3db 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -50,7 +50,7 @@
  *		Patrick McHardy <kaber@trash.net>
  */
 
-#define VERSION "0.406"
+#define VERSION "0.407"
 
 #include <linux/config.h>
 #include <asm/uaccess.h>
@@ -314,11 +314,6 @@ static void __leaf_free_rcu(struct rcu_head *head)
 	kfree(container_of(head, struct leaf, rcu));
 }
 
-static inline void free_leaf(struct leaf *leaf)
-{
-	call_rcu(&leaf->rcu, __leaf_free_rcu);
-}
-
 static void __leaf_info_free_rcu(struct rcu_head *head)
 {
 	kfree(container_of(head, struct leaf_info, rcu));
@@ -357,7 +352,12 @@ static void __tnode_free_rcu(struct rcu_head *head)
 
 static inline void tnode_free(struct tnode *tn)
 {
-	call_rcu(&tn->rcu, __tnode_free_rcu);
+	if(IS_LEAF(tn)) {
+		struct leaf *l = (struct leaf *) tn;
+		call_rcu_bh(&l->rcu, __leaf_free_rcu);
+	}
+        else
+		call_rcu(&tn->rcu, __tnode_free_rcu);
 }
 
 static struct leaf *leaf_new(void)

From 2e2f7aefa8a8ba4adb6ecee8cbb43fbe9ca4cc89 Mon Sep 17 00:00:00 2001
From: Patrick McHardy <kaber@trash.net>
Date: Tue, 4 Apr 2006 13:42:35 -0700
Subject: [PATCH 03/35] [NETFILTER]: Fix fragmentation issues with bridge
 netfilter

The conntrack code doesn't do re-fragmentation of defragmented packets
anymore but relies on fragmentation in the IP layer. Purely bridged
packets don't pass through the IP layer, so the bridge netfilter code
needs to take care of fragmentation itself.

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 include/net/ip.h          |  1 +
 net/bridge/br_netfilter.c | 13 +++++++++++--
 net/ipv4/ip_output.c      |  6 +++---
 3 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/include/net/ip.h b/include/net/ip.h
index 8fe6156ca9b0..3d2e5ca62a5a 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -95,6 +95,7 @@ extern int		ip_local_deliver(struct sk_buff *skb);
 extern int		ip_mr_input(struct sk_buff *skb);
 extern int		ip_output(struct sk_buff *skb);
 extern int		ip_mc_output(struct sk_buff *skb);
+extern int		ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *));
 extern int		ip_do_nat(struct sk_buff *skb);
 extern void		ip_send_check(struct iphdr *ip);
 extern int		ip_queue_xmit(struct sk_buff *skb, int ipfragok);
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index f29450b788be..3da9264449f7 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -765,6 +765,15 @@ static unsigned int br_nf_local_out(unsigned int hook, struct sk_buff **pskb,
 	return NF_STOLEN;
 }
 
+static int br_nf_dev_queue_xmit(struct sk_buff *skb)
+{
+	if (skb->protocol == htons(ETH_P_IP) &&
+	    skb->len > skb->dev->mtu &&
+	    !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size))
+		return ip_fragment(skb, br_dev_queue_push_xmit);
+	else
+		return br_dev_queue_push_xmit(skb);
+}
 
 /* PF_BRIDGE/POST_ROUTING ********************************************/
 static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb,
@@ -824,7 +833,7 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb,
 		realoutdev = nf_bridge->netoutdev;
 #endif
 	NF_HOOK(pf, NF_IP_POST_ROUTING, skb, NULL, realoutdev,
-		br_dev_queue_push_xmit);
+		br_nf_dev_queue_xmit);
 
 	return NF_STOLEN;
 
@@ -869,7 +878,7 @@ static unsigned int ip_sabotage_out(unsigned int hook, struct sk_buff **pskb,
 
 	if ((out->hard_start_xmit == br_dev_xmit &&
 	     okfn != br_nf_forward_finish &&
-	     okfn != br_nf_local_out_finish && okfn != br_dev_queue_push_xmit)
+	     okfn != br_nf_local_out_finish && okfn != br_nf_dev_queue_xmit)
 #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
 	    || ((out->priv_flags & IFF_802_1Q_VLAN) &&
 		VLAN_DEV_INFO(out)->real_dev->hard_start_xmit == br_dev_xmit)
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index f75ff1d96551..8dcba3887f04 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -86,8 +86,6 @@
 
 int sysctl_ip_default_ttl = IPDEFTTL;
 
-static int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*));
-
 /* Generate a checksum for an outgoing IP datagram. */
 __inline__ void ip_send_check(struct iphdr *iph)
 {
@@ -421,7 +419,7 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from)
  *	single device frame, and queue such a frame for sending.
  */
 
-static int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
+int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
 {
 	struct iphdr *iph;
 	int raw = 0;
@@ -673,6 +671,8 @@ static int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
 	return err;
 }
 
+EXPORT_SYMBOL(ip_fragment);
+
 int
 ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb)
 {

From 50fba2aa7cefa6b0e1768cb350c9e69042320c03 Mon Sep 17 00:00:00 2001
From: Herbert Xu <herbert@gondor.apana.org.au>
Date: Tue, 4 Apr 2006 13:50:45 -0700
Subject: [PATCH 04/35] [INET]: Move no-tunnel ICMP error to tunnel4/tunnel6

This patch moves the sending of ICMP messages when there are no IPv4/IPv6
tunnels present to tunnel4/tunnel6 respectively.  Please note that for now
if xfrm4_tunnel/xfrm6_tunnel is loaded then no ICMP messages will ever be
sent.  This is similar to how we handle AH/ESP/IPCOMP.

This move fixes the bug where we always send an ICMP message when there is
no ip6_tunnel device present for a given packet even if it is later handled
by IPsec.  It also causes ICMP messages to be sent when no IPIP tunnel is
present.

I've decided to use the "port unreachable" ICMP message over the current
value of "address unreachable" (and "protocol unreachable" by GRE) because
it is not ambiguous unlike the other ones which can be triggered by other
conditions.  There seems to be no standard specifying what value must be
used so this change should be OK.  In fact we should change GRE to use
this value as well.

Incidentally, this patch also fixes a fairly serious bug in xfrm6_tunnel
where we don't check whether the embedded IPv6 header is present before
dereferencing it for the inside source address.

This patch is inspired by a previous patch by Hugo Santos <hsantos@av.it.pt>.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/ipv4/ipip.c        |  4 ----
 net/ipv4/tunnel4.c     |  8 ++++++++
 net/ipv4/xfrm4_input.c |  2 --
 net/ipv6/ip6_tunnel.c  | 12 +++++-------
 net/ipv6/tunnel6.c     |  8 ++++++++
 5 files changed, 21 insertions(+), 13 deletions(-)

diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index eef07b0916a3..ea398ee43f28 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -474,9 +474,6 @@ static int ipip_rcv(struct sk_buff *skb)
 	struct iphdr *iph;
 	struct ip_tunnel *tunnel;
 
-	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
-		goto out;
-
 	iph = skb->nh.iph;
 
 	read_lock(&ipip_lock);
@@ -508,7 +505,6 @@ static int ipip_rcv(struct sk_buff *skb)
 	}
 	read_unlock(&ipip_lock);
 
-out:
 	return -1;
 }
 
diff --git a/net/ipv4/tunnel4.c b/net/ipv4/tunnel4.c
index 0d7d386dac22..8d30c48f090e 100644
--- a/net/ipv4/tunnel4.c
+++ b/net/ipv4/tunnel4.c
@@ -8,6 +8,8 @@
 #include <linux/mutex.h>
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
+#include <net/icmp.h>
+#include <net/ip.h>
 #include <net/protocol.h>
 #include <net/xfrm.h>
 
@@ -70,10 +72,16 @@ static int tunnel4_rcv(struct sk_buff *skb)
 {
 	struct xfrm_tunnel *handler;
 
+	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
+		goto drop;
+
 	for (handler = tunnel4_handlers; handler; handler = handler->next)
 		if (!handler->handler(skb))
 			return 0;
 
+	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
+
+drop:
 	kfree_skb(skb);
 	return 0;
 }
diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c
index 7a0b9524fe08..3e174c83bfe7 100644
--- a/net/ipv4/xfrm4_input.c
+++ b/net/ipv4/xfrm4_input.c
@@ -37,8 +37,6 @@ static int xfrm4_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq)
 {
 	switch (nexthdr) {
 	case IPPROTO_IPIP:
-		if (!pskb_may_pull(skb, sizeof(struct iphdr)))
-			return -EINVAL;
 		*spi = skb->nh.iph->saddr;
 		*seq = 0;
 		return 0;
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index ff9040c92556..a995796b5a57 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -519,9 +519,6 @@ ip6ip6_rcv(struct sk_buff *skb)
 	struct ipv6hdr *ipv6h;
 	struct ip6_tnl *t;
 
-	if (!pskb_may_pull(skb, sizeof (*ipv6h)))
-		goto discard;
-
 	ipv6h = skb->nh.ipv6h;
 
 	read_lock(&ip6ip6_lock);
@@ -529,8 +526,7 @@ ip6ip6_rcv(struct sk_buff *skb)
 	if ((t = ip6ip6_tnl_lookup(&ipv6h->saddr, &ipv6h->daddr)) != NULL) {
 		if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
 			read_unlock(&ip6ip6_lock);
-			kfree_skb(skb);
-			return 0;
+			goto discard;
 		}
 
 		if (!(t->parms.flags & IP6_TNL_F_CAP_RCV)) {
@@ -557,9 +553,11 @@ ip6ip6_rcv(struct sk_buff *skb)
 		return 0;
 	}
 	read_unlock(&ip6ip6_lock);
-	icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, skb->dev);
-discard:
 	return 1;
+
+discard:
+	kfree_skb(skb);
+	return 0;
 }
 
 static inline struct ipv6_txoptions *create_tel(__u8 encap_limit)
diff --git a/net/ipv6/tunnel6.c b/net/ipv6/tunnel6.c
index 5659b52284bd..0ef9a35798d1 100644
--- a/net/ipv6/tunnel6.c
+++ b/net/ipv6/tunnel6.c
@@ -19,11 +19,13 @@
  * 		YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
  */
 
+#include <linux/icmpv6.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
+#include <net/ipv6.h>
 #include <net/protocol.h>
 #include <net/xfrm.h>
 
@@ -87,10 +89,16 @@ static int tunnel6_rcv(struct sk_buff **pskb)
 	struct sk_buff *skb = *pskb;
 	struct xfrm6_tunnel *handler;
 
+	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
+		goto drop;
+
 	for (handler = tunnel6_handlers; handler; handler = handler->next)
 		if (!handler->handler(skb))
 			return 0;
 
+	icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, skb->dev);
+
+drop:
 	kfree_skb(skb);
 	return 0;
 }

From d938ab44c0c5418bb74a97b422a070e2cdccce22 Mon Sep 17 00:00:00 2001
From: Randy Dunlap <rdunlap@xenotime.net>
Date: Tue, 4 Apr 2006 20:11:56 -0700
Subject: [PATCH 05/35] [NET] netconsole: set .name in struct console

Set .name in netconsole's struct console to identify the
struct's owner.

Signed-off-by: Randy Dunlap <rdunlap@xenotime.net>
Acked-by: Matt Mackall <mpm@selenic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 drivers/net/netconsole.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 75b35ad760de..66e74f740261 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -87,6 +87,7 @@ static void write_msg(struct console *con, const char *msg, unsigned int len)
 }
 
 static struct console netconsole = {
+	.name = "netcon",
 	.flags = CON_ENABLED | CON_PRINTBUFFER,
 	.write = write_msg
 };

From e3a5cd9edff9a7a20de3c88c9d479704da98fb85 Mon Sep 17 00:00:00 2001
From: Adrian Bunk <bunk@stusta.de>
Date: Wed, 5 Apr 2006 22:19:47 -0700
Subject: [PATCH 06/35] [NET]: Fix an off-by-21-or-49 error.

This patch fixes an off-by-21-or-49 error ;-) spotted by the Coverity
checker.

Signed-off-by: Adrian Bunk <bunk@stusta.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/core/net-sysfs.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index 21b68464cabb..c12990c9c603 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -165,7 +165,7 @@ static ssize_t show_operstate(struct class_device *dev, char *buf)
 		operstate = IF_OPER_DOWN;
 	read_unlock(&dev_base_lock);
 
-	if (operstate >= sizeof(operstates))
+	if (operstate >= ARRAY_SIZE(operstates))
 		return -EINVAL; /* should not happen */
 
 	return sprintf(buf, "%s\n", operstates[operstate]);

From ad96b485b4224785bcca478cfba02d06c46ee575 Mon Sep 17 00:00:00 2001
From: Adrian Bunk <bunk@stusta.de>
Date: Wed, 5 Apr 2006 22:21:04 -0700
Subject: [PATCH 07/35] [TG3]: Fix a memory leak.

This patch fixes a memory leak (buf wasn't freed) spotted by the
Coverity checker.

Signed-off-by: Adrian Bunk <bunk@stusta.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 drivers/net/tg3.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 0b5358072172..d6047bd6805d 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -8034,9 +8034,13 @@ static int tg3_test_nvram(struct tg3 *tp)
 		for (i = 0; i < size; i++)
 			csum8 += buf8[i];
 
-		if (csum8 == 0)
-			return 0;
-		return -EIO;
+		if (csum8 == 0) {
+			err = 0;
+			goto out;
+		}
+
+		err = -EIO;
+		goto out;
 	}
 
 	/* Bootstrap checksum at offset 0x10 */

From cdee5751bf91d02616aaf30a5affef56105e3b79 Mon Sep 17 00:00:00 2001
From: Eric Sesterhenn <snakebyte@gmx.de>
Date: Wed, 5 Apr 2006 22:28:14 -0700
Subject: [PATCH 08/35] [BLUETOOTH] sco: Possible double free.

this fixes coverity bug id #1068.
hci_send_sco() frees skb if (skb->len > hdev->sco_mtu).
Since it returns a negative error value only in this case, we
can directly return here.

Signed-off-by: Eric Sesterhenn <snakebyte@gmx.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/bluetooth/sco.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index 6b61323ce23c..0c2d13ad69bb 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -255,7 +255,7 @@ static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)
 	}
 
 	if ((err = hci_send_sco(conn->hcon, skb)) < 0)
-		goto fail;
+		return err;
 
 	return count;
 

From 45af08be6d120690d379cb8421ebaf9d9f86ba52 Mon Sep 17 00:00:00 2001
From: Herbert Xu <herbert@gondor.apana.org.au>
Date: Wed, 5 Apr 2006 22:31:19 -0700
Subject: [PATCH 09/35] [INET]: Use port unreachable instead of proto for
 tunnels

This patch changes GRE and SIT to generate port unreachable instead of
protocol unreachable errors when we can't find a matching tunnel for a
packet.

This removes the ambiguity as to whether the error is caused by no
tunnel being found or by the lack of support for the given tunnel
type.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/ipv4/ip_gre.c | 2 +-
 net/ipv6/sit.c    | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 9981dcd68f11..ab99bebdcdc8 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -656,7 +656,7 @@ static int ipgre_rcv(struct sk_buff *skb)
 		read_unlock(&ipgre_lock);
 		return(0);
 	}
-	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0);
+	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
 
 drop:
 	read_unlock(&ipgre_lock);
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index c2d3e17beae6..6578c3080f47 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -397,7 +397,7 @@ static int ipip6_rcv(struct sk_buff *skb)
 		return 0;
 	}
 
-	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0);
+	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
 	kfree_skb(skb);
 	read_unlock(&ipip6_lock);
 out:

From c1e14a6ea2ae34993f431d2eb9a0f228ac3574eb Mon Sep 17 00:00:00 2001
From: Linus Walleij <triad@df.lth.se>
Date: Wed, 5 Apr 2006 22:33:59 -0700
Subject: [PATCH 10/35] [IRDA]: smcinit merged into smsc-ircc driver

This patch integrates the smcinit code into the smsc-ircc driver.
Some laptops have their smsc-ircc chip not properly configured by the
BIOS and needs some preconfiguration. Currently, this can be done from
userspace with smcinit, a utility that comes with the irda-utils
package. It messes with ioports and PCI settings, from userspace.  Now
with this patch, if we happen to be on one of the known to be faulty
laptops, we preconfigure the chip from the driver.

Patch from Linus Walleij <triad@df.lth.se>
Signed-off-by: Samuel Ortiz <samuel.ortiz@nokia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 drivers/net/irda/smsc-ircc2.c | 311 ++++++++++++++++++++++++++++++++++
 1 file changed, 311 insertions(+)

diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c
index ec94ecdb103d..bbcfc8ec35a1 100644
--- a/drivers/net/irda/smsc-ircc2.c
+++ b/drivers/net/irda/smsc-ircc2.c
@@ -11,6 +11,7 @@
  *     Copyright (c) 2002      Daniele Peri
  *     All Rights Reserved.
  *     Copyright (c) 2002      Jean Tourrilhes
+ *     Copyright (c) 2006      Linus Walleij
  *
  *
  * Based on smc-ircc.c:
@@ -61,6 +62,9 @@
 
 #include <linux/spinlock.h>
 #include <linux/pm.h>
+#ifdef CONFIG_PCI
+#include <linux/pci.h>
+#endif
 
 #include <net/irda/wrapper.h>
 #include <net/irda/irda.h>
@@ -100,6 +104,22 @@ MODULE_PARM_DESC(ircc_transceiver, "Transceiver type");
 
 /* Types */
 
+#ifdef CONFIG_PCI
+struct smsc_ircc_subsystem_configuration {
+	unsigned short vendor; /* PCI vendor ID */
+	unsigned short device; /* PCI vendor ID */
+	unsigned short subvendor; /* PCI subsystem vendor ID */
+	unsigned short subdevice; /* PCI sybsystem device ID */
+	unsigned short sir_io; /* I/O port for SIR */
+	unsigned short fir_io; /* I/O port for FIR */
+	unsigned char  fir_irq; /* FIR IRQ */
+	unsigned char  fir_dma; /* FIR DMA */
+	unsigned short cfg_base; /* I/O port for chip configuration */
+	int (*preconfigure)(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); /* Preconfig function */
+	const char *name;	/* name shown as info */
+};
+#endif
+
 struct smsc_transceiver {
 	char *name;
 	void (*set_for_speed)(int fir_base, u32 speed);
@@ -202,6 +222,16 @@ static int __init smsc_superio_flat(const struct smsc_chip *chips, unsigned shor
 static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type);
 static int __init smsc_superio_fdc(unsigned short cfg_base);
 static int __init smsc_superio_lpc(unsigned short cfg_base);
+#ifdef CONFIG_PCI
+static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf);
+static int __init preconfigure_through_82801(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf);
+static int __init preconfigure_through_ali(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf);
+static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg,
+						    unsigned short ircc_fir,
+						    unsigned short ircc_sir,
+						    unsigned char ircc_dma,
+						    unsigned char ircc_irq);
+#endif
 
 /* Transceivers specific functions */
 
@@ -353,6 +383,13 @@ static int __init smsc_ircc_init(void)
 		return ret;
 	}
 
+#ifdef CONFIG_PCI
+	if (smsc_ircc_preconfigure_subsystems(ircc_cfg, ircc_fir, ircc_sir, ircc_dma, ircc_irq) < 0) {
+		/* Ignore errors from preconfiguration */
+		IRDA_ERROR("%s, Preconfiguration failed !\n", driver_name);
+	}
+#endif
+
 	dev_count = 0;
 
 	if (ircc_fir > 0 && ircc_sir > 0) {
@@ -2285,6 +2322,280 @@ static int __init smsc_superio_lpc(unsigned short cfg_base)
 	return ret;
 }
 
+/*
+ * Look for some specific subsystem setups that need
+ * pre-configuration not properly done by the BIOS (especially laptops)
+ * This code is based in part on smcinit.c, tosh1800-smcinit.c
+ * and tosh2450-smcinit.c. The table lists the device entries
+ * for ISA bridges with an LPC (Local Peripheral Configurator)
+ * that are in turn used to configure the SMSC device with default
+ * SIR and FIR I/O ports, DMA and IRQ.
+ */
+#ifdef CONFIG_PCI
+#define PCIID_VENDOR_INTEL 0x8086
+#define PCIID_VENDOR_ALI 0x10b9
+static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __devinitdata = {
+	{
+		.vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */
+		.device = 0x24cc,
+		.subvendor = 0x103c,
+		.subdevice = 0x088c,
+		.sir_io = 0x02f8, /* Quite certain these are the same for nc8000 as for nc6000 */
+		.fir_io = 0x0130,
+		.fir_irq = 0x09,
+		.fir_dma = 0x03,
+		.cfg_base = 0x004e,
+		.preconfigure = preconfigure_through_82801,
+		.name = "HP nc8000",
+	},
+	{
+		.vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */
+		.device = 0x24cc,
+		.subvendor = 0x103c,
+		.subdevice = 0x0890,
+		.sir_io = 0x02f8,
+		.fir_io = 0x0130,
+		.fir_irq = 0x09,
+		.fir_dma = 0x03,
+		.cfg_base = 0x004e,
+		.preconfigure = preconfigure_through_82801,
+		.name = "HP nc6000",
+	},
+	{
+		.vendor = PCIID_VENDOR_INTEL, /* Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge */
+		.device = 0x24c0,
+		.subvendor = 0x1179,
+		.subdevice = 0xffff, /* 0xffff is "any", Not sure, 0x0001 or 0x0002 */
+		.sir_io = 0x03f8,
+		.fir_io = 0x0130,
+		.fir_irq = 0x07,
+		.fir_dma = 0x01,
+		.cfg_base = 0x002e,
+		.preconfigure = preconfigure_through_82801,
+		.name = "Toshiba Satellite 2450",
+	},
+	{
+		.vendor = PCIID_VENDOR_INTEL, /* Intel 82801CAM ISA bridge */
+		.device = 0x248c, /* Some use 24cc? */
+		.subvendor = 0x1179,
+		.subdevice = 0xffff, /* 0xffff is "any", Not sure, 0x0001 or 0x0002 */
+		.sir_io = 0x03f8,
+		.fir_io = 0x0130,
+		.fir_irq = 0x03,
+		.fir_dma = 0x03,
+		.cfg_base = 0x002e,
+		.preconfigure = preconfigure_through_82801,
+		.name = "Toshiba Satellite 5100/5200, Tecra 9100",
+	},
+	{
+		.vendor = PCIID_VENDOR_ALI, /* ALi M1533/M1535 PCI to ISA Bridge [Aladdin IV/V/V+] */
+		.device = 0x1533,
+		.subvendor = 0x1179,
+		.subdevice = 0xffff, /* 0xffff is "any", Not sure, 0x0001 or 0x0002 */
+		.sir_io = 0x02e8,
+		.fir_io = 0x02f8,
+		.fir_irq = 0x07,
+		.fir_dma = 0x03,
+		.cfg_base = 0x002e,
+		.preconfigure = preconfigure_through_ali,
+		.name = "Toshiba Satellite 1800",
+	},
+	{ } // Terminator
+};
+
+
+/*
+ * This sets up the basic SMSC parameters (FIR port, SIR port, FIR DMA, FIR IRQ)
+ * through the chip configuration port.
+ */
+static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf)
+{
+	unsigned short iobase = conf->cfg_base;
+	unsigned char tmpbyte;
+
+	outb(LPC47N227_CFGACCESSKEY, iobase); // enter configuration state
+	outb(SMSCSIOFLAT_DEVICEID_REG, iobase); // set for device ID
+	tmpbyte = inb(iobase +1); // Read device ID
+	IRDA_DEBUG(0, "Detected Chip id: 0x%02x, setting up registers...\n",tmpbyte);
+
+	/* Disable UART1 and set up SIR I/O port */
+	outb(0x24, iobase);  // select CR24 - UART1 base addr
+	outb(0x00, iobase + 1); // disable UART1
+	outb(SMSCSIOFLAT_UART2BASEADDR_REG, iobase);  // select CR25 - UART2 base addr
+	outb( (conf->sir_io >> 2), iobase + 1); // bits 2-9 of 0x3f8
+	tmpbyte = inb(iobase + 1);
+	if (tmpbyte != (conf->sir_io >> 2) ) {
+		IRDA_WARNING("ERROR: could not configure SIR ioport.\n");
+		return -ENXIO;
+	}
+
+	/* Set up FIR IRQ channel for UART2 */
+	outb(SMSCSIOFLAT_UARTIRQSELECT_REG, iobase); // select CR28 - UART1,2 IRQ select
+	tmpbyte = inb(iobase + 1);
+	tmpbyte &= SMSCSIOFLAT_UART1IRQSELECT_MASK; // Do not touch the UART1 portion
+	tmpbyte |= (conf->fir_irq & SMSCSIOFLAT_UART2IRQSELECT_MASK);
+	outb(tmpbyte, iobase + 1);
+	tmpbyte = inb(iobase + 1) & SMSCSIOFLAT_UART2IRQSELECT_MASK;
+	if (tmpbyte != conf->fir_irq) {
+		IRDA_WARNING("ERROR: could not configure FIR IRQ channel.\n");
+		return -ENXIO;
+	}
+
+	/* Set up FIR I/O port */
+	outb(SMSCSIOFLAT_FIRBASEADDR_REG, iobase);  // CR2B - SCE (FIR) base addr
+	outb((conf->fir_io >> 3), iobase + 1);
+	tmpbyte = inb(iobase + 1);
+	if (tmpbyte != (conf->fir_io >> 3) ) {
+		IRDA_WARNING("ERROR: could not configure FIR I/O port.\n");
+		return -ENXIO;
+	}
+
+	/* Set up FIR DMA channel */
+	outb(SMSCSIOFLAT_FIRDMASELECT_REG, iobase);  // CR2C - SCE (FIR) DMA select
+	outb((conf->fir_dma & LPC47N227_FIRDMASELECT_MASK), iobase + 1); // DMA
+	tmpbyte = inb(iobase + 1) & LPC47N227_FIRDMASELECT_MASK;
+	if (tmpbyte != (conf->fir_dma & LPC47N227_FIRDMASELECT_MASK)) {
+		IRDA_WARNING("ERROR: could not configure FIR DMA channel.\n");
+		return -ENXIO;
+	}
+
+	outb(SMSCSIOFLAT_UARTMODE0C_REG, iobase);  // CR0C - UART mode
+	tmpbyte = inb(iobase + 1);
+	tmpbyte &= ~SMSCSIOFLAT_UART2MODE_MASK | SMSCSIOFLAT_UART2MODE_VAL_IRDA;
+	outb(tmpbyte, iobase + 1); // enable IrDA (HPSIR) mode, high speed
+
+	outb(LPC47N227_APMBOOTDRIVE_REG, iobase);  // CR07 - Auto Pwr Mgt/boot drive sel
+	tmpbyte = inb(iobase + 1);
+	outb(tmpbyte | LPC47N227_UART2AUTOPWRDOWN_MASK, iobase + 1); // enable UART2 autopower down
+
+	/* This one was not part of tosh1800 */
+	outb(0x0a, iobase);  // CR0a - ecp fifo / ir mux
+	tmpbyte = inb(iobase + 1);
+	outb(tmpbyte | 0x40, iobase + 1); // send active device to ir port
+
+	outb(LPC47N227_UART12POWER_REG, iobase);  // CR02 - UART 1,2 power
+	tmpbyte = inb(iobase + 1);
+	outb(tmpbyte | LPC47N227_UART2POWERDOWN_MASK, iobase + 1); // UART2 power up mode, UART1 power down
+
+	outb(LPC47N227_FDCPOWERVALIDCONF_REG, iobase);  // CR00 - FDC Power/valid config cycle
+	tmpbyte = inb(iobase + 1);
+	outb(tmpbyte | LPC47N227_VALID_MASK, iobase + 1); // valid config cycle done
+
+	outb(LPC47N227_CFGEXITKEY, iobase);  // Exit configuration
+
+	return 0;
+}
+
+/* 82801CAM registers */
+#define VID 0x00
+#define DID 0x02
+#define PIRQA_ROUT 0x60
+#define PCI_DMA_C 0x90
+#define COM_DEC 0xe0
+#define LPC_EN 0xe6
+#define GEN2_DEC 0xec
+/*
+ * Sets up the I/O range using the 82801CAM ISA bridge, 82801DBM LPC bridge or
+ * Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge. They all work the same way!
+ */
+static int __init preconfigure_through_82801(struct pci_dev *dev,
+				  struct smsc_ircc_subsystem_configuration *conf)
+{
+	unsigned short tmpword;
+	int ret;
+
+	IRDA_MESSAGE("Setting up the SMSC device via the 82801 controller.\n");
+	pci_write_config_byte(dev, COM_DEC, 0x10);
+
+	/* Enable LPC */
+	pci_read_config_word(dev, LPC_EN, &tmpword); /* LPC_EN register */
+	tmpword &= 0xfffd; /* mask bit 1 */
+	tmpword |= 0x0001; /* set bit 0 : COMA addr range enable */
+	pci_write_config_word(dev, LPC_EN, tmpword);
+
+	/* Setup DMA */
+	pci_write_config_word(dev, PCI_DMA_C, 0xc0c0); /* LPC I/F DMA on, channel 3  -- rtm (?? PCI DMA ?) */
+	pci_write_config_word(dev, GEN2_DEC, 0x131); /* LPC I/F 2nd decode range */
+
+	/* Pre-configure chip */
+	ret = preconfigure_smsc_chip(conf);
+
+	/* Disable LPC */
+	pci_read_config_word(dev, LPC_EN, &tmpword); /* LPC_EN register */
+	tmpword &= 0xfffc; /* mask bit 1 and bit 0, COMA addr range disable */
+	pci_write_config_word(dev, LPC_EN, tmpword);
+	return ret;
+}
+
+static int __init preconfigure_through_ali(struct pci_dev *dev,
+				  struct smsc_ircc_subsystem_configuration *conf)
+{
+	/* TODO: put in ALi 1533 configuration here. */
+	IRDA_MESSAGE("SORRY: %s has an unsupported bridge controller (ALi): not pre-configured.\n", conf->name);
+	return -ENODEV;
+}
+
+static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg,
+						    unsigned short ircc_fir,
+						    unsigned short ircc_sir,
+						    unsigned char ircc_dma,
+						    unsigned char ircc_irq)
+{
+	struct pci_dev *dev = NULL;
+	unsigned short ss_vendor = 0x0000;
+	unsigned short ss_device = 0x0000;
+	int ret = 0;
+
+	dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
+
+	while (dev != NULL) {
+		struct smsc_ircc_subsystem_configuration *conf;
+
+		/*
+		 * Cache the subsystem vendor/device: some manufacturers fail to set
+		 * this for all components, so we save it in case there is just
+		 * 0x0000 0x0000 on the device we want to check.
+		 */
+		if (dev->subsystem_vendor != 0x0000U) {
+			ss_vendor = dev->subsystem_vendor;
+			ss_device = dev->subsystem_device;
+		}
+		conf = subsystem_configurations;
+		for( ; conf->subvendor; conf++) {
+			if(conf->vendor == dev->vendor &&
+			   conf->device == dev->device &&
+			   conf->subvendor == ss_vendor && /* Sometimes these are cached values */
+			   (conf->subdevice == ss_device || conf->subdevice == 0xffff)) {
+				struct smsc_ircc_subsystem_configuration tmpconf;
+
+				memcpy(&tmpconf, conf, sizeof(struct smsc_ircc_subsystem_configuration));
+
+				/* Override the default values with anything passed in as parameter */
+				if (ircc_cfg != 0)
+					tmpconf.cfg_base = ircc_cfg;
+				if (ircc_fir != 0)
+					tmpconf.fir_io = ircc_fir;
+				if (ircc_sir != 0)
+					tmpconf.sir_io = ircc_sir;
+				if (ircc_dma != 0xff)
+					tmpconf.fir_dma = ircc_dma;
+				if (ircc_irq != 0xff)
+					tmpconf.fir_irq = ircc_irq;
+
+				IRDA_MESSAGE("Detected unconfigured %s SMSC IrDA chip, pre-configuring device.\n", conf->name);
+				if (conf->preconfigure)
+					ret = conf->preconfigure(dev, &tmpconf);
+				else
+					ret = -ENODEV;
+			}
+		}
+		dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
+	}
+
+	return ret;
+}
+#endif // CONFIG_PCI
+
 /************************************************
  *
  * Transceivers specific functions

From 137dc0233fba0bfa19679bdd96eb104f0e659c5a Mon Sep 17 00:00:00 2001
From: Samuel Ortiz <samuel.ortiz@nokia.com>
Date: Wed, 5 Apr 2006 22:39:14 -0700
Subject: [PATCH 11/35] [IRDA]: Support for Sigmatel STIR421x chip

This patch enables support for the Sigmatel's STIR421x IrDA chip.
Once patched with Sigmatel's firmware, this chip "almost" follows the
USB-IrDA spec. Thus this patch is against irda-usb.[ch].

The code has been tested by Nick Fedchik on an STIR4210 chipset based
dongle.

Signed-off-by: Samuel Ortiz <samuel.ortiz@nokia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 drivers/net/irda/irda-usb.c | 363 ++++++++++++++++++++++++++++++++++--
 drivers/net/irda/irda-usb.h |  43 +++--
 2 files changed, 372 insertions(+), 34 deletions(-)

diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
index 6e2ec56cde0b..606243d11793 100644
--- a/drivers/net/irda/irda-usb.c
+++ b/drivers/net/irda/irda-usb.c
@@ -1,7 +1,7 @@
 /*****************************************************************************
  *
  * Filename:      irda-usb.c
- * Version:       0.9b
+ * Version:       0.10
  * Description:   IrDA-USB Driver
  * Status:        Experimental 
  * Author:        Dag Brattli <dag@brattli.net>
@@ -9,6 +9,9 @@
  *	Copyright (C) 2000, Roman Weissgaerber <weissg@vienna.at>
  *      Copyright (C) 2001, Dag Brattli <dag@brattli.net>
  *      Copyright (C) 2001, Jean Tourrilhes <jt@hpl.hp.com>
+ *      Copyright (C) 2004, SigmaTel, Inc. <irquality@sigmatel.com>
+ *      Copyright (C) 2005, Milan Beno <beno@pobox.sk>
+ *      Copyright (C) 2006, Nick Fedchik <nick@fedchik.org.ua>
  *          
  *	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
@@ -61,6 +64,7 @@
 #include <linux/slab.h>
 #include <linux/rtnetlink.h>
 #include <linux/usb.h>
+#include <linux/firmware.h>
 
 #include "irda-usb.h"
 
@@ -78,8 +82,12 @@ static struct usb_device_id dongles[] = {
 	{ USB_DEVICE(0x50f, 0x180), .driver_info = IUC_SPEED_BUG | IUC_NO_WINDOW },
 	/* Extended Systems, Inc.,  XTNDAccess IrDA USB (ESI-9685) */
 	{ USB_DEVICE(0x8e9, 0x100), .driver_info = IUC_SPEED_BUG | IUC_NO_WINDOW },
+	/* SigmaTel STIR4210/4220/4116 USB IrDA (VFIR) Bridge */
+	{ USB_DEVICE(0x66f, 0x4210), .driver_info = IUC_STIR_4210 | IUC_SPEED_BUG },
+	{ USB_DEVICE(0x66f, 0x4220), .driver_info = IUC_STIR_4210 | IUC_SPEED_BUG },
+	{ USB_DEVICE(0x66f, 0x4116), .driver_info = IUC_STIR_4210 | IUC_SPEED_BUG },
 	{ .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS |
-	               USB_DEVICE_ID_MATCH_INT_SUBCLASS,
+	  USB_DEVICE_ID_MATCH_INT_SUBCLASS,
 	  .bInterfaceClass = USB_CLASS_APP_SPEC,
 	  .bInterfaceSubClass = USB_CLASS_IRDA,
 	  .driver_info = IUC_DEFAULT, },
@@ -99,6 +107,7 @@ MODULE_DEVICE_TABLE(usb, dongles);
 
 /*------------------------------------------------------------------*/
 
+static void irda_usb_init_qos(struct irda_usb_cb *self) ;
 static struct irda_class_desc *irda_usb_find_class_desc(struct usb_interface *intf);
 static void irda_usb_disconnect(struct usb_interface *intf);
 static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self);
@@ -141,7 +150,24 @@ static void irda_usb_build_header(struct irda_usb_cb *self,
 				  __u8 *header,
 				  int	force)
 {
-	/* Set the negotiated link speed */
+	/* Here we check if we have an STIR421x chip,
+	 * and if either speed or xbofs (or both) needs
+	 * to be changed.
+	 */
+	if (self->capability & IUC_STIR_4210 &&
+	    ((self->new_speed != -1) || (self->new_xbofs != -1))) {
+
+		/* With STIR421x, speed and xBOFs must be set at the same
+		 * time, even if only one of them changes.
+		 */
+		if (self->new_speed == -1)
+			self->new_speed = self->speed ;
+
+		if (self->new_xbofs == -1)
+			self->new_xbofs = self->xbofs ;
+	}
+
+	/* Set the link speed */
 	if (self->new_speed != -1) {
 		/* Hum... Ugly hack :-(
 		 * Some device are not compliant with the spec and change
@@ -191,7 +217,11 @@ static void irda_usb_build_header(struct irda_usb_cb *self,
 		        *header = SPEED_4000000;
 			self->new_xbofs = 0;
 			break;
-		}
+		case 16000000:
+			*header = SPEED_16000000;
+  			self->new_xbofs = 0;
+  			break;
+  		}
 	} else
 		/* No change */
 		*header = 0;
@@ -235,6 +265,32 @@ static void irda_usb_build_header(struct irda_usb_cb *self,
 	}
 }
 
+/*
+*   calculate turnaround time for SigmaTel header
+*/
+static __u8 get_turnaround_time(struct sk_buff *skb)
+{
+	int turnaround_time = irda_get_mtt(skb);
+
+	if ( turnaround_time == 0 )
+		return 0;
+	else if ( turnaround_time <= 10 )
+		return 1;
+	else if ( turnaround_time <= 50 )
+		return 2;
+	else if ( turnaround_time <= 100 )
+		return 3;
+	else if ( turnaround_time <= 500 )
+		return 4;
+	else if ( turnaround_time <= 1000 )
+		return 5;
+	else if ( turnaround_time <= 5000 )
+		return 6;
+	else
+		return 7;
+}
+
+
 /*------------------------------------------------------------------*/
 /*
  * Send a command to change the speed of the dongle
@@ -262,12 +318,18 @@ static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self)
 	/* Set the new speed and xbofs in this fake frame */
 	irda_usb_build_header(self, frame, 1);
 
+	if ( self->capability & IUC_STIR_4210 ) {
+		if (frame[0] == 0) return ; // do nothing if no change
+		frame[1] = 0; // other parameters don't change here
+		frame[2] = 0;
+	}
+
 	/* Submit the 0 length IrDA frame to trigger new speed settings */
         usb_fill_bulk_urb(urb, self->usbdev,
 		      usb_sndbulkpipe(self->usbdev, self->bulk_out_ep),
                       frame, IRDA_USB_SPEED_MTU,
                       speed_bulk_callback, self);
-	urb->transfer_buffer_length = USB_IRDA_HEADER;
+	urb->transfer_buffer_length = self->header_length;
 	urb->transfer_flags = 0;
 
 	/* Irq disabled -> GFP_ATOMIC */
@@ -383,16 +445,35 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
 	 * allocation will be done lower in skb_push().
 	 * Also, we don't use directly skb_cow(), because it require
 	 * headroom >= 16, which force unnecessary copies - Jean II */
-	if (skb_headroom(skb) < USB_IRDA_HEADER) {
+	if (skb_headroom(skb) < self->header_length) {
 		IRDA_DEBUG(0, "%s(), Insuficient skb headroom.\n", __FUNCTION__);
-		if (skb_cow(skb, USB_IRDA_HEADER)) {
+		if (skb_cow(skb, self->header_length)) {
 			IRDA_WARNING("%s(), failed skb_cow() !!!\n", __FUNCTION__);
 			goto drop;
 		}
 	}
 
 	/* Change setting for next frame */
-	irda_usb_build_header(self, skb_push(skb, USB_IRDA_HEADER), 0);
+
+	if ( self->capability & IUC_STIR_4210 ) {
+		__u8 turnaround_time;
+		__u8* frame;
+		turnaround_time = get_turnaround_time( skb );
+		frame= skb_push(skb, self->header_length);
+		irda_usb_build_header(self, frame, 0);
+		frame[2] = turnaround_time;
+		if ((skb->len != 0) &&
+		    ((skb->len % 128) == 0) &&
+		    ((skb->len % 512) != 0)) {
+			/* add extra byte for special SigmaTel feature */
+			frame[1] = 1;
+			skb_put(skb, 1);
+		} else {
+			frame[1] = 0;
+		}
+	} else {
+		irda_usb_build_header(self, skb_push(skb, self->header_length), 0);
+	}
 
 	/* FIXME: Make macro out of this one */
 	((struct irda_skb_cb *)skb->cb)->context = self;
@@ -795,7 +876,7 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs)
 	}
 	
 	/* Check for empty frames */
-	if (urb->actual_length <= USB_IRDA_HEADER) {
+	if (urb->actual_length <= self->header_length) {
 		IRDA_WARNING("%s(), empty frame!\n", __FUNCTION__);
 		goto done;
 	}
@@ -816,7 +897,11 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs)
 	docopy = (urb->actual_length < IRDA_RX_COPY_THRESHOLD);
 
 	/* Allocate a new skb */
-	newskb = dev_alloc_skb(docopy ? urb->actual_length : IRDA_SKB_MAX_MTU);
+	if ( self->capability & IUC_STIR_4210 )
+		newskb = dev_alloc_skb(docopy ? urb->actual_length : IRDA_SKB_MAX_MTU + USB_IRDA_SIGMATEL_HEADER);
+	else
+		newskb = dev_alloc_skb(docopy ? urb->actual_length : IRDA_SKB_MAX_MTU);
+
 	if (!newskb)  {
 		self->stats.rx_dropped++;
 		/* We could deliver the current skb, but this would stall
@@ -845,7 +930,7 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs)
 
 	/* Set proper length on skb & remove USB-IrDA header */
 	skb_put(dataskb, urb->actual_length);
-	skb_pull(dataskb, USB_IRDA_HEADER);
+	skb_pull(dataskb, self->header_length);
 
 	/* Ask the networking layer to queue the packet for the IrDA stack */
 	dataskb->dev = self->netdev;
@@ -937,6 +1022,191 @@ static int irda_usb_is_receiving(struct irda_usb_cb *self)
 	return 0; /* For now */
 }
 
+
+#define STIR421X_PATCH_PRODUCT_VERSION_STR       "Product Version: "
+#define STIR421X_PATCH_COMPONENT_VERSION_STR     "Component Version: "
+#define STIR421X_PATCH_DATA_TAG_STR              "STMP"
+#define STIR421X_PATCH_FILE_VERSION_MAX_OFFSET   512     /* version info is before here */
+#define STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET     512     /* patch image starts before here */
+#define STIR421X_PATCH_FILE_END_OF_HEADER_TAG    0x1A    /* marks end of patch file header (PC DOS text file EOF character) */
+
+/*
+ * Known firmware patches for STIR421x dongles
+ */
+static char * stir421x_patches[] = {
+	"42101001.sb",
+	"42101002.sb",
+};
+
+static int stir421x_get_patch_version(unsigned char * patch, const unsigned long patch_len)
+{
+	unsigned int version_offset;
+	unsigned long version_major, version_minor, version_build;
+	unsigned char * version_start;
+	int version_found = 0;
+
+	for (version_offset = 0;
+	     version_offset < STIR421X_PATCH_FILE_END_OF_HEADER_TAG;
+	     version_offset++) {
+		if (!memcmp(patch + version_offset,
+			    STIR421X_PATCH_PRODUCT_VERSION_STR,
+			    sizeof(STIR421X_PATCH_PRODUCT_VERSION_STR) - 1)) {
+				    version_found = 1;
+				    version_start = patch +
+					    version_offset +
+					    sizeof(STIR421X_PATCH_PRODUCT_VERSION_STR) - 1;
+				    break;
+		}
+	}
+
+	/* We couldn't find a product version on this patch */
+	if (!version_found)
+		return -EINVAL;
+
+	/* Let's check if the product version is dotted */
+	if (version_start[3] != '.' ||
+	    version_start[7] != '.')
+		return -EINVAL;
+
+	version_major = simple_strtoul(version_start, NULL, 10);
+	version_minor = simple_strtoul(version_start + 4, NULL, 10);
+	version_build = simple_strtoul(version_start + 8, NULL, 10);
+
+	IRDA_DEBUG(2, "%s(), Major: %ld Minor: %ld Build: %ld\n",
+		   __FUNCTION__,
+		   version_major, version_minor, version_build);
+
+	return (((version_major) << 12) +
+		((version_minor) << 8) +
+		((version_build / 10) << 4) +
+		(version_build % 10));
+
+}
+
+
+static int stir421x_upload_patch (struct irda_usb_cb *self,
+				  unsigned char * patch,
+				  const unsigned int patch_len)
+{
+    int retval = 0;
+    int actual_len;
+    unsigned int i = 0, download_amount = 0;
+    unsigned char * patch_chunk;
+
+    IRDA_DEBUG (2, "%s(), Uploading STIR421x Patch\n", __FUNCTION__);
+
+    patch_chunk = kzalloc(STIR421X_MAX_PATCH_DOWNLOAD_SIZE, GFP_KERNEL);
+    if (patch_chunk == NULL)
+	    return -ENOMEM;
+
+    /* break up patch into 1023-byte sections */
+    for (i = 0; retval >= 0 && i < patch_len; i += download_amount) {
+	    download_amount = patch_len - i;
+	    if (download_amount > STIR421X_MAX_PATCH_DOWNLOAD_SIZE)
+		    download_amount = STIR421X_MAX_PATCH_DOWNLOAD_SIZE;
+
+	    /* download the patch section */
+	    memcpy(patch_chunk, patch + i, download_amount);
+
+	    retval = usb_bulk_msg (self->usbdev,
+				   usb_sndbulkpipe (self->usbdev,
+						    self->bulk_out_ep),
+				   patch_chunk, download_amount,
+				   &actual_len, msecs_to_jiffies (500));
+	    IRDA_DEBUG (2, "%s(), Sent %u bytes\n", __FUNCTION__,
+			actual_len);
+	    if (retval == 0)
+		    mdelay(10);
+    }
+
+    kfree(patch_chunk);
+
+    if (i != patch_len) {
+	    IRDA_ERROR ("%s(), Pushed %d bytes (!= patch_len (%d))\n",
+		       __FUNCTION__, i, patch_len);
+	    retval = -EIO;
+    }
+
+    if (retval < 0)
+	    /* todo - mark device as not ready */
+	    IRDA_ERROR ("%s(), STIR421x patch upload failed (%d)\n",
+			__FUNCTION__, retval);
+
+    return retval;
+}
+
+
+static int stir421x_patch_device(struct irda_usb_cb *self)
+{
+	unsigned int i, patch_found = 0, data_found = 0, data_offset;
+	int patch_version, ret = 0;
+	const struct firmware *fw_entry;
+
+	for (i = 0; i < ARRAY_SIZE(stir421x_patches); i++) {
+		if(request_firmware(&fw_entry, stir421x_patches[i], &self->usbdev->dev) != 0) {
+			IRDA_ERROR( "%s(), Patch %s is not available\n", __FUNCTION__, stir421x_patches[i]);
+			continue;
+		}
+
+                /* We found a patch from userspace */
+		patch_version = stir421x_get_patch_version (fw_entry->data, fw_entry->size);
+
+		if (patch_version < 0) {
+			/* Couldn't fetch a version, let's move on to the next file */
+			IRDA_ERROR("%s(), version parsing failed\n", __FUNCTION__);
+			ret = patch_version;
+			release_firmware(fw_entry);
+			continue;
+		}
+
+		if (patch_version != self->usbdev->descriptor.bcdDevice) {
+			/* Patch version and device don't match */
+			IRDA_ERROR ("%s(), wrong patch version (%d <-> %d)\n",
+				    __FUNCTION__,
+				    patch_version, self->usbdev->descriptor.bcdDevice);
+			ret = -EINVAL;
+			release_firmware(fw_entry);
+			continue;
+		}
+
+		/* If we're here, we've found a correct patch */
+		patch_found = 1;
+		break;
+
+	}
+
+	/* We couldn't find a valid firmware, let's leave */
+	if (!patch_found)
+		return ret;
+
+	/* The actual image starts after the "STMP" keyword */
+	for (data_offset = 0; data_offset < STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET; data_offset++) {
+		if (!memcmp(fw_entry->data + data_offset,
+			    STIR421X_PATCH_DATA_TAG_STR,
+			    sizeof(STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET))) {
+			IRDA_DEBUG(2, "%s(), found patch data for STIR421x at offset %d\n",
+				   __FUNCTION__, data_offset);
+			data_found = 1;
+			break;
+		}
+	}
+
+	/* We couldn't find "STMP" from the header */
+	if (!data_found)
+		return -EINVAL;
+
+	/* Let's upload the patch to the target */
+	ret = stir421x_upload_patch(self,
+				    &fw_entry->data[data_offset + sizeof(STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET)],
+				    fw_entry->size - (data_offset + sizeof(STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET)));
+
+	release_firmware(fw_entry);
+
+	return ret;
+
+}
+
+
 /********************** IRDA DEVICE CALLBACKS **********************/
 /*
  * Main calls from the IrDA/Network subsystem.
@@ -972,6 +1242,11 @@ static int irda_usb_net_open(struct net_device *netdev)
 		return -1;
 	}
 
+	if(self->needspatch) {
+		IRDA_WARNING("%s(), device needs patch\n", __FUNCTION__) ;
+		return -EIO ;
+	}
+
 	/* Initialise default speed and xbofs value
 	 * (IrLAP will change that soon) */
 	self->speed = -1;
@@ -1050,7 +1325,7 @@ static int irda_usb_net_close(struct net_device *netdev)
 	del_timer(&self->rx_defer_timer);
 
 	/* Deallocate all the Rx path buffers (URBs and skb) */
-	for (i = 0; i < IU_MAX_RX_URBS; i++) {
+	for (i = 0; i < self->max_rx_urb; i++) {
 		struct urb *urb = self->rx_urb[i];
 		struct sk_buff *skb = (struct sk_buff *) urb->context;
 		/* Cancel the receive command */
@@ -1426,8 +1701,22 @@ static int irda_usb_probe(struct usb_interface *intf,
 	spin_lock_init(&self->lock);
 	init_timer(&self->rx_defer_timer);
 
+	self->capability = id->driver_info;
+	self->needspatch = ((self->capability & IUC_STIR_4210) != 0) ;
+
 	/* Create all of the needed urbs */
-	for (i = 0; i < IU_MAX_RX_URBS; i++) {
+	if (self->capability & IUC_STIR_4210) {
+		self->max_rx_urb = IU_SIGMATEL_MAX_RX_URBS;
+		self->header_length = USB_IRDA_SIGMATEL_HEADER;
+	} else {
+		self->max_rx_urb = IU_MAX_RX_URBS;
+		self->header_length = USB_IRDA_HEADER;
+	}
+
+	self->rx_urb = kzalloc(self->max_rx_urb * sizeof(struct urb *),
+				GFP_KERNEL);
+
+	for (i = 0; i < self->max_rx_urb; i++) {
 		self->rx_urb[i] = usb_alloc_urb(0, GFP_KERNEL);
 		if (!self->rx_urb[i]) {
 			goto err_out_1;
@@ -1479,17 +1768,28 @@ static int irda_usb_probe(struct usb_interface *intf,
 		goto err_out_3;
 	}
 
+	self->usbdev = dev;
+
 	/* Find IrDA class descriptor */
 	irda_desc = irda_usb_find_class_desc(intf);
 	ret = -ENODEV;
 	if (irda_desc == NULL)
 		goto err_out_3;
 
+	if (self->needspatch) {
+		ret = usb_control_msg (self->usbdev, usb_sndctrlpipe (self->usbdev, 0),
+				       0x02, 0x40, 0, 0, 0, 0, msecs_to_jiffies(500));
+		if (ret < 0) {
+			IRDA_DEBUG (0, "usb_control_msg failed %d\n", ret);
+			goto err_out_3;
+		} else {
+			mdelay(10);
+		}
+	}
+
 	self->irda_desc =  irda_desc;
 	self->present = 1;
 	self->netopen = 0;
-	self->capability = id->driver_info;
-	self->usbdev = dev;
 	self->usbintf = intf;
 
 	/* Allocate the buffer for speed changes */
@@ -1508,6 +1808,28 @@ static int irda_usb_probe(struct usb_interface *intf,
 
 	IRDA_MESSAGE("IrDA: Registered device %s\n", net->name);
 	usb_set_intfdata(intf, self);
+
+	if (self->needspatch) {
+		/* Now we fetch and upload the firmware patch */
+		ret = stir421x_patch_device(self);
+		self->needspatch = (ret < 0);
+		if (ret < 0) {
+			printk("patch_device failed\n");
+			goto err_out_4;
+		}
+
+		/* replace IrDA class descriptor with what patched device is now reporting */
+		irda_desc = irda_usb_find_class_desc (self->usbintf);
+		if (irda_desc == NULL) {
+			ret = -ENODEV;
+			goto err_out_4;
+		}
+		if (self->irda_desc)
+			kfree (self->irda_desc);
+		self->irda_desc = irda_desc;
+		irda_usb_init_qos(self);
+	}
+
 	return 0;
 
 err_out_4:
@@ -1518,7 +1840,7 @@ static int irda_usb_probe(struct usb_interface *intf,
 err_out_2:
 	usb_free_urb(self->tx_urb);
 err_out_1:
-	for (i = 0; i < IU_MAX_RX_URBS; i++) {
+	for (i = 0; i < self->max_rx_urb; i++) {
 		if (self->rx_urb[i])
 			usb_free_urb(self->rx_urb[i]);
 	}
@@ -1571,7 +1893,7 @@ static void irda_usb_disconnect(struct usb_interface *intf)
 		/*netif_device_detach(self->netdev);*/
 		netif_stop_queue(self->netdev);
 		/* Stop all the receive URBs. Must be synchronous. */
-		for (i = 0; i < IU_MAX_RX_URBS; i++)
+		for (i = 0; i < self->max_rx_urb; i++)
 			usb_kill_urb(self->rx_urb[i]);
 		/* Cancel Tx and speed URB.
 		 * Make sure it's synchronous to avoid races. */
@@ -1586,8 +1908,9 @@ static void irda_usb_disconnect(struct usb_interface *intf)
 	self->usbintf = NULL;
 
 	/* Clean up our urbs */
-	for (i = 0; i < IU_MAX_RX_URBS; i++)
+	for (i = 0; i < self->max_rx_urb; i++)
 		usb_free_urb(self->rx_urb[i]);
+	kfree(self->rx_urb);
 	/* Clean up Tx and speed URB */
 	usb_free_urb(self->tx_urb);
 	usb_free_urb(self->speed_urb);
@@ -1648,6 +1971,6 @@ module_exit(usb_irda_cleanup);
  */
 module_param(qos_mtt_bits, int, 0);
 MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time");
-MODULE_AUTHOR("Roman Weissgaerber <weissg@vienna.at>, Dag Brattli <dag@brattli.net> and Jean Tourrilhes <jt@hpl.hp.com>");
-MODULE_DESCRIPTION("IrDA-USB Dongle Driver"); 
+MODULE_AUTHOR("Roman Weissgaerber <weissg@vienna.at>, Dag Brattli <dag@brattli.net>, Jean Tourrilhes <jt@hpl.hp.com> and Nick Fedchik <nick@fedchik.org.ua>");
+MODULE_DESCRIPTION("IrDA-USB Dongle Driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/net/irda/irda-usb.h b/drivers/net/irda/irda-usb.h
index 4026af42dd47..d833db52cebf 100644
--- a/drivers/net/irda/irda-usb.h
+++ b/drivers/net/irda/irda-usb.h
@@ -1,7 +1,7 @@
 /*****************************************************************************
  *
  * Filename:      irda-usb.h
- * Version:       0.9b
+ * Version:       0.10
  * Description:   IrDA-USB Driver
  * Status:        Experimental 
  * Author:        Dag Brattli <dag@brattli.net>
@@ -9,6 +9,9 @@
  *	Copyright (C) 2001, Roman Weissgaerber <weissg@vienna.at>
  *      Copyright (C) 2000, Dag Brattli <dag@brattli.net>
  *      Copyright (C) 2001, Jean Tourrilhes <jt@hpl.hp.com>
+ *      Copyright (C) 2004, SigmaTel, Inc. <irquality@sigmatel.com>
+ *      Copyright (C) 2005, Milan Beno <beno@pobox.sk>
+ *      Copyright (C) 2006, Nick FEdchik <nick@fedchik.org.ua>
  *          
  *	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
@@ -31,6 +34,9 @@
 #include <net/irda/irda.h>
 #include <net/irda/irda_device.h>      /* struct irlap_cb */
 
+#define PATCH_FILE_SIZE_MAX     65536
+#define PATCH_FILE_SIZE_MIN     80
+
 #define RX_COPY_THRESHOLD 200
 #define IRDA_USB_MAX_MTU 2051
 #define IRDA_USB_SPEED_MTU 64		/* Weird, but work like this */
@@ -79,15 +85,16 @@
 /* Inbound header */
 #define MEDIA_BUSY    0x80
 
-#define SPEED_2400    0x01
-#define SPEED_9600    0x02
-#define SPEED_19200   0x03
-#define SPEED_38400   0x04
-#define SPEED_57600   0x05
-#define SPEED_115200  0x06
-#define SPEED_576000  0x07
-#define SPEED_1152000 0x08
-#define SPEED_4000000 0x09
+#define SPEED_2400     0x01
+#define SPEED_9600     0x02
+#define SPEED_19200    0x03
+#define SPEED_38400    0x04
+#define SPEED_57600    0x05
+#define SPEED_115200   0x06
+#define SPEED_576000   0x07
+#define SPEED_1152000  0x08
+#define SPEED_4000000  0x09
+#define SPEED_16000000 0x0a
 
 /* Basic capabilities */
 #define IUC_DEFAULT	0x00	/* Basic device compliant with 1.0 spec */
@@ -100,11 +107,14 @@
 #define IUC_SMALL_PKT	0x10	/* Device doesn't behave with big Rx packets */
 #define IUC_MAX_WINDOW	0x20	/* Device underestimate the Rx window */
 #define IUC_MAX_XBOFS	0x40	/* Device need more xbofs than advertised */
+#define IUC_STIR_4210	0x80	/* SigmaTel 4210/4220/4116 VFIR */
 
 /* USB class definitions */
-#define USB_IRDA_HEADER   0x01
-#define USB_CLASS_IRDA    0x02 /* USB_CLASS_APP_SPEC subclass */ 
-#define USB_DT_IRDA       0x21
+#define USB_IRDA_HEADER            0x01
+#define USB_CLASS_IRDA             0x02 /* USB_CLASS_APP_SPEC subclass */
+#define USB_DT_IRDA                0x21
+#define USB_IRDA_SIGMATEL_HEADER   0x03
+#define IU_SIGMATEL_MAX_RX_URBS    (IU_MAX_ACTIVE_RX_URBS + USB_IRDA_SIGMATEL_HEADER)
 
 struct irda_class_desc {
 	__u8  bLength;
@@ -123,6 +133,7 @@ struct irda_class_desc {
  * (6.2.5, USB-IrDA class spec 1.0) */
 
 #define IU_REQ_GET_CLASS_DESC	0x06
+#define STIR421X_MAX_PATCH_DOWNLOAD_SIZE 1023
 
 struct irda_usb_cb {
 	struct irda_class_desc *irda_desc;
@@ -136,7 +147,8 @@ struct irda_usb_cb {
 	__u16 bulk_out_mtu;		/* Max Tx packet size in bytes */
 	__u8  bulk_int_ep;		/* Interrupt Endpoint assignments */
 
-	struct urb *rx_urb[IU_MAX_RX_URBS];	/* URBs used to receive data frames */
+	__u8  max_rx_urb;
+	struct urb **rx_urb;	        /* URBs used to receive data frames */
 	struct urb *idle_rx_urb;	/* Pointer to idle URB in Rx path */
 	struct urb *tx_urb;		/* URB used to send data frames */
 	struct urb *speed_urb;		/* URB used to send speed commands */
@@ -157,6 +169,9 @@ struct irda_usb_cb {
 	__u32 speed;			/* Current speed */
 	__s32 new_speed;		/* speed we need to set */
 
+	__u8 header_length;             /* USB-IrDA frame header size */
+	int needspatch;        		/* device needs firmware patch */
+
 	struct timer_list rx_defer_timer;	/* Wait for Rx error to clear */
 };
 

From 972d1cb1427946f4980240363aac4e73fb375290 Mon Sep 17 00:00:00 2001
From: Patrick McHardy <kaber@trash.net>
Date: Thu, 6 Apr 2006 14:09:12 -0700
Subject: [PATCH 12/35] [NETFILTER]: Add helper functions for mass hook
 registration/unregistration

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 include/linux/netfilter.h |  2 ++
 net/netfilter/core.c      | 28 ++++++++++++++++++++++++++++
 2 files changed, 30 insertions(+)

diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index 412e52ca9720..5aa931607923 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -110,6 +110,8 @@ struct nf_info
 /* Function to register/unregister hook points. */
 int nf_register_hook(struct nf_hook_ops *reg);
 void nf_unregister_hook(struct nf_hook_ops *reg);
+int nf_register_hooks(struct nf_hook_ops *reg, unsigned int n);
+void nf_unregister_hooks(struct nf_hook_ops *reg, unsigned int n);
 
 /* Functions to register get/setsockopt ranges (non-inclusive).  You
    need to check permissions yourself! */
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index 1ceb1a6c254b..645d62105571 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -63,6 +63,34 @@ void nf_unregister_hook(struct nf_hook_ops *reg)
 }
 EXPORT_SYMBOL(nf_unregister_hook);
 
+int nf_register_hooks(struct nf_hook_ops *reg, unsigned int n)
+{
+	unsigned int i;
+	int err = 0;
+
+	for (i = 0; i < n; i++) {
+		err = nf_register_hook(&reg[i]);
+		if (err)
+			goto err;
+	}
+	return err;
+
+err:
+	if (i > 0)
+		nf_unregister_hooks(reg, i);
+	return err;
+}
+EXPORT_SYMBOL(nf_register_hooks);
+
+void nf_unregister_hooks(struct nf_hook_ops *reg, unsigned int n)
+{
+	unsigned int i;
+
+	for (i = 0; i < n; i++)
+		nf_unregister_hook(&reg[i]);
+}
+EXPORT_SYMBOL(nf_unregister_hooks);
+
 unsigned int nf_iterate(struct list_head *head,
 			struct sk_buff **skb,
 			int hook,

From 964ddaa10de8f3aeed12bc2a30726514ff309e64 Mon Sep 17 00:00:00 2001
From: Patrick McHardy <kaber@trash.net>
Date: Thu, 6 Apr 2006 14:09:49 -0700
Subject: [PATCH 13/35] [NETFILTER]: Clean up hook registration

Clean up hook registration by makeing use of the new mass registration and
unregistration helpers.

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/ipv4/netfilter/arptable_filter.c          |  19 +-
 net/ipv4/netfilter/ip_conntrack_standalone.c  | 180 ++++++-----------
 net/ipv4/netfilter/ip_nat_standalone.c        | 143 +++++--------
 net/ipv4/netfilter/iptable_filter.c           |  21 +-
 net/ipv4/netfilter/iptable_mangle.c           |  33 +--
 net/ipv4/netfilter/iptable_raw.c              |  35 ++--
 .../netfilter/nf_conntrack_l3proto_ipv4.c     | 189 ++++++------------
 net/ipv6/netfilter/ip6table_filter.c          |  21 +-
 net/ipv6/netfilter/ip6table_mangle.c          |  33 +--
 net/ipv6/netfilter/ip6table_raw.c             |  15 +-
 .../netfilter/nf_conntrack_l3proto_ipv6.c     | 143 +++++--------
 11 files changed, 253 insertions(+), 579 deletions(-)

diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c
index d0d379c7df9a..d7c472faa53b 100644
--- a/net/ipv4/netfilter/arptable_filter.c
+++ b/net/ipv4/netfilter/arptable_filter.c
@@ -181,33 +181,26 @@ static struct nf_hook_ops arpt_ops[] = {
 
 static int __init arptable_filter_init(void)
 {
-	int ret, i;
+	int ret;
 
 	/* Register table */
 	ret = arpt_register_table(&packet_filter, &initial_table.repl);
 	if (ret < 0)
 		return ret;
 
-	for (i = 0; i < ARRAY_SIZE(arpt_ops); i++)
-		if ((ret = nf_register_hook(&arpt_ops[i])) < 0)
-			goto cleanup_hooks;
+	ret = nf_register_hooks(arpt_ops, ARRAY_SIZE(arpt_ops));
+	if (ret < 0)
+		goto cleanup_table;
 	return ret;
 
-cleanup_hooks:
-	while (--i >= 0)
-		nf_unregister_hook(&arpt_ops[i]);
-
+cleanup_table:
 	arpt_unregister_table(&packet_filter);
 	return ret;
 }
 
 static void __exit arptable_filter_fini(void)
 {
-	unsigned int i;
-
-	for (i = 0; i < ARRAY_SIZE(arpt_ops); i++)
-		nf_unregister_hook(&arpt_ops[i]);
-
+	nf_unregister_hooks(arpt_ops, ARRAY_SIZE(arpt_ops));
 	arpt_unregister_table(&packet_filter);
 }
 
diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c
index 52076026db36..adc1a0f66409 100644
--- a/net/ipv4/netfilter/ip_conntrack_standalone.c
+++ b/net/ipv4/netfilter/ip_conntrack_standalone.c
@@ -469,70 +469,63 @@ static unsigned int ip_conntrack_local(unsigned int hooknum,
 
 /* Connection tracking may drop packets, but never alters them, so
    make it the first hook. */
-static struct nf_hook_ops ip_conntrack_defrag_ops = {
-	.hook		= ip_conntrack_defrag,
-	.owner		= THIS_MODULE,
-	.pf		= PF_INET,
-	.hooknum	= NF_IP_PRE_ROUTING,
-	.priority	= NF_IP_PRI_CONNTRACK_DEFRAG,
-};
-
-static struct nf_hook_ops ip_conntrack_in_ops = {
-	.hook		= ip_conntrack_in,
-	.owner		= THIS_MODULE,
-	.pf		= PF_INET,
-	.hooknum	= NF_IP_PRE_ROUTING,
-	.priority	= NF_IP_PRI_CONNTRACK,
-};
-
-static struct nf_hook_ops ip_conntrack_defrag_local_out_ops = {
-	.hook		= ip_conntrack_defrag,
-	.owner		= THIS_MODULE,
-	.pf		= PF_INET,
-	.hooknum	= NF_IP_LOCAL_OUT,
-	.priority	= NF_IP_PRI_CONNTRACK_DEFRAG,
-};
-
-static struct nf_hook_ops ip_conntrack_local_out_ops = {
-	.hook		= ip_conntrack_local,
-	.owner		= THIS_MODULE,
-	.pf		= PF_INET,
-	.hooknum	= NF_IP_LOCAL_OUT,
-	.priority	= NF_IP_PRI_CONNTRACK,
-};
-
-/* helpers */
-static struct nf_hook_ops ip_conntrack_helper_out_ops = {
-	.hook		= ip_conntrack_help,
-	.owner		= THIS_MODULE,
-	.pf		= PF_INET,
-	.hooknum	= NF_IP_POST_ROUTING,
-	.priority	= NF_IP_PRI_CONNTRACK_HELPER,
-};
-
-static struct nf_hook_ops ip_conntrack_helper_in_ops = {
-	.hook		= ip_conntrack_help,
-	.owner		= THIS_MODULE,
-	.pf		= PF_INET,
-	.hooknum	= NF_IP_LOCAL_IN,
-	.priority	= NF_IP_PRI_CONNTRACK_HELPER,
-};
-
-/* Refragmenter; last chance. */
-static struct nf_hook_ops ip_conntrack_out_ops = {
-	.hook		= ip_confirm,
-	.owner		= THIS_MODULE,
-	.pf		= PF_INET,
-	.hooknum	= NF_IP_POST_ROUTING,
-	.priority	= NF_IP_PRI_CONNTRACK_CONFIRM,
-};
-
-static struct nf_hook_ops ip_conntrack_local_in_ops = {
-	.hook		= ip_confirm,
-	.owner		= THIS_MODULE,
-	.pf		= PF_INET,
-	.hooknum	= NF_IP_LOCAL_IN,
-	.priority	= NF_IP_PRI_CONNTRACK_CONFIRM,
+static struct nf_hook_ops ip_conntrack_ops[] = {
+	{
+		.hook		= ip_conntrack_defrag,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET,
+		.hooknum	= NF_IP_PRE_ROUTING,
+		.priority	= NF_IP_PRI_CONNTRACK_DEFRAG,
+	},
+	{
+		.hook		= ip_conntrack_in,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET,
+		.hooknum	= NF_IP_PRE_ROUTING,
+		.priority	= NF_IP_PRI_CONNTRACK,
+	},
+	{
+		.hook		= ip_conntrack_defrag,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET,
+		.hooknum	= NF_IP_LOCAL_OUT,
+		.priority	= NF_IP_PRI_CONNTRACK_DEFRAG,
+	},
+	{
+		.hook		= ip_conntrack_local,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET,
+		.hooknum	= NF_IP_LOCAL_OUT,
+		.priority	= NF_IP_PRI_CONNTRACK,
+	},
+	{
+		.hook		= ip_conntrack_help,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET,
+		.hooknum	= NF_IP_POST_ROUTING,
+		.priority	= NF_IP_PRI_CONNTRACK_HELPER,
+	},
+	{
+		.hook		= ip_conntrack_help,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET,
+		.hooknum	= NF_IP_LOCAL_IN,
+		.priority	= NF_IP_PRI_CONNTRACK_HELPER,
+	},
+	{
+		.hook		= ip_confirm,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET,
+		.hooknum	= NF_IP_POST_ROUTING,
+		.priority	= NF_IP_PRI_CONNTRACK_CONFIRM,
+	},
+	{
+		.hook		= ip_confirm,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET,
+		.hooknum	= NF_IP_LOCAL_IN,
+		.priority	= NF_IP_PRI_CONNTRACK_CONFIRM,
+	},
 };
 
 /* Sysctl support */
@@ -813,52 +806,17 @@ static int init_or_cleanup(int init)
 	proc_stat->owner = THIS_MODULE;
 #endif
 
-	ret = nf_register_hook(&ip_conntrack_defrag_ops);
+	ret = nf_register_hooks(ip_conntrack_ops, ARRAY_SIZE(ip_conntrack_ops));
 	if (ret < 0) {
-		printk("ip_conntrack: can't register pre-routing defrag hook.\n");
+		printk("ip_conntrack: can't register hooks.\n");
 		goto cleanup_proc_stat;
 	}
-	ret = nf_register_hook(&ip_conntrack_defrag_local_out_ops);
-	if (ret < 0) {
-		printk("ip_conntrack: can't register local_out defrag hook.\n");
-		goto cleanup_defragops;
-	}
-	ret = nf_register_hook(&ip_conntrack_in_ops);
-	if (ret < 0) {
-		printk("ip_conntrack: can't register pre-routing hook.\n");
-		goto cleanup_defraglocalops;
-	}
-	ret = nf_register_hook(&ip_conntrack_local_out_ops);
-	if (ret < 0) {
-		printk("ip_conntrack: can't register local out hook.\n");
-		goto cleanup_inops;
-	}
-	ret = nf_register_hook(&ip_conntrack_helper_in_ops);
-	if (ret < 0) {
-		printk("ip_conntrack: can't register local in helper hook.\n");
-		goto cleanup_inandlocalops;
-	}
-	ret = nf_register_hook(&ip_conntrack_helper_out_ops);
-	if (ret < 0) {
-		printk("ip_conntrack: can't register postrouting helper hook.\n");
-		goto cleanup_helperinops;
-	}
-	ret = nf_register_hook(&ip_conntrack_out_ops);
-	if (ret < 0) {
-		printk("ip_conntrack: can't register post-routing hook.\n");
-		goto cleanup_helperoutops;
-	}
-	ret = nf_register_hook(&ip_conntrack_local_in_ops);
-	if (ret < 0) {
-		printk("ip_conntrack: can't register local in hook.\n");
-		goto cleanup_inoutandlocalops;
-	}
 #ifdef CONFIG_SYSCTL
 	ip_ct_sysctl_header = register_sysctl_table(ip_ct_net_table, 0);
 	if (ip_ct_sysctl_header == NULL) {
 		printk("ip_conntrack: can't register to sysctl.\n");
 		ret = -ENOMEM;
-		goto cleanup_localinops;
+		goto cleanup_hooks;
 	}
 #endif
 
@@ -868,23 +826,9 @@ static int init_or_cleanup(int init)
 	synchronize_net();
 #ifdef CONFIG_SYSCTL
  	unregister_sysctl_table(ip_ct_sysctl_header);
- cleanup_localinops:
+ cleanup_hooks:
 #endif
-	nf_unregister_hook(&ip_conntrack_local_in_ops);
- cleanup_inoutandlocalops:
-	nf_unregister_hook(&ip_conntrack_out_ops);
- cleanup_helperoutops:
-	nf_unregister_hook(&ip_conntrack_helper_out_ops);
- cleanup_helperinops:
-	nf_unregister_hook(&ip_conntrack_helper_in_ops);
- cleanup_inandlocalops:
-	nf_unregister_hook(&ip_conntrack_local_out_ops);
- cleanup_inops:
-	nf_unregister_hook(&ip_conntrack_in_ops);
- cleanup_defraglocalops:
-	nf_unregister_hook(&ip_conntrack_defrag_local_out_ops);
- cleanup_defragops:
-	nf_unregister_hook(&ip_conntrack_defrag_ops);
+	nf_unregister_hooks(ip_conntrack_ops, ARRAY_SIZE(ip_conntrack_ops));
  cleanup_proc_stat:
 #ifdef CONFIG_PROC_FS
 	remove_proc_entry("ip_conntrack", proc_net_stat);
diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c
index 3505b0de2e04..5f02f439b07e 100644
--- a/net/ipv4/netfilter/ip_nat_standalone.c
+++ b/net/ipv4/netfilter/ip_nat_standalone.c
@@ -299,61 +299,57 @@ ip_nat_adjust(unsigned int hooknum,
 
 /* We must be after connection tracking and before packet filtering. */
 
-/* Before packet filtering, change destination */
-static struct nf_hook_ops ip_nat_in_ops = {
-	.hook		= ip_nat_in,
-	.owner		= THIS_MODULE,
-	.pf		= PF_INET,
-	.hooknum	= NF_IP_PRE_ROUTING,
-	.priority	= NF_IP_PRI_NAT_DST,
+static struct nf_hook_ops ip_nat_ops[] = {
+	/* Before packet filtering, change destination */
+	{
+		.hook		= ip_nat_in,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET,
+		.hooknum	= NF_IP_PRE_ROUTING,
+		.priority	= NF_IP_PRI_NAT_DST,
+	},
+	/* After packet filtering, change source */
+	{
+		.hook		= ip_nat_out,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET,
+		.hooknum	= NF_IP_POST_ROUTING,
+		.priority	= NF_IP_PRI_NAT_SRC,
+	},
+	/* After conntrack, adjust sequence number */
+	{
+		.hook		= ip_nat_adjust,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET,
+		.hooknum	= NF_IP_POST_ROUTING,
+		.priority	= NF_IP_PRI_NAT_SEQ_ADJUST,
+	},
+	/* Before packet filtering, change destination */
+	{
+		.hook		= ip_nat_local_fn,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET,
+		.hooknum	= NF_IP_LOCAL_OUT,
+		.priority	= NF_IP_PRI_NAT_DST,
+	},
+	/* After packet filtering, change source */
+	{
+		.hook		= ip_nat_fn,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET,
+		.hooknum	= NF_IP_LOCAL_IN,
+		.priority	= NF_IP_PRI_NAT_SRC,
+	},
+	/* After conntrack, adjust sequence number */
+	{
+		.hook		= ip_nat_adjust,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET,
+		.hooknum	= NF_IP_LOCAL_IN,
+		.priority	= NF_IP_PRI_NAT_SEQ_ADJUST,
+	},
 };
 
-/* After packet filtering, change source */
-static struct nf_hook_ops ip_nat_out_ops = {
-	.hook		= ip_nat_out,
-	.owner		= THIS_MODULE,
-	.pf		= PF_INET,
-	.hooknum	= NF_IP_POST_ROUTING,
-	.priority	= NF_IP_PRI_NAT_SRC,
-};
-
-/* After conntrack, adjust sequence number */
-static struct nf_hook_ops ip_nat_adjust_out_ops = {
-	.hook		= ip_nat_adjust,
-	.owner		= THIS_MODULE,
-	.pf		= PF_INET,
-	.hooknum	= NF_IP_POST_ROUTING,
-	.priority	= NF_IP_PRI_NAT_SEQ_ADJUST,
-};
-
-/* Before packet filtering, change destination */
-static struct nf_hook_ops ip_nat_local_out_ops = {
-	.hook		= ip_nat_local_fn,
-	.owner		= THIS_MODULE,
-	.pf		= PF_INET,
-	.hooknum	= NF_IP_LOCAL_OUT,
-	.priority	= NF_IP_PRI_NAT_DST,
-};
-
-/* After packet filtering, change source for reply packets of LOCAL_OUT DNAT */
-static struct nf_hook_ops ip_nat_local_in_ops = {
-	.hook		= ip_nat_fn,
-	.owner		= THIS_MODULE,
-	.pf		= PF_INET,
-	.hooknum	= NF_IP_LOCAL_IN,
-	.priority	= NF_IP_PRI_NAT_SRC,
-};
-
-/* After conntrack, adjust sequence number */
-static struct nf_hook_ops ip_nat_adjust_in_ops = {
-	.hook		= ip_nat_adjust,
-	.owner		= THIS_MODULE,
-	.pf		= PF_INET,
-	.hooknum	= NF_IP_LOCAL_IN,
-	.priority	= NF_IP_PRI_NAT_SEQ_ADJUST,
-};
-
-
 static int init_or_cleanup(int init)
 {
 	int ret = 0;
@@ -371,50 +367,15 @@ static int init_or_cleanup(int init)
 		printk("ip_nat_init: can't setup rules.\n");
 		goto cleanup_decode_session;
 	}
-	ret = nf_register_hook(&ip_nat_in_ops);
+	ret = nf_register_hooks(ip_nat_ops, ARRAY_SIZE(ip_nat_ops));
 	if (ret < 0) {
-		printk("ip_nat_init: can't register in hook.\n");
+		printk("ip_nat_init: can't register hooks.\n");
 		goto cleanup_rule_init;
 	}
-	ret = nf_register_hook(&ip_nat_out_ops);
-	if (ret < 0) {
-		printk("ip_nat_init: can't register out hook.\n");
-		goto cleanup_inops;
-	}
-	ret = nf_register_hook(&ip_nat_adjust_in_ops);
-	if (ret < 0) {
-		printk("ip_nat_init: can't register adjust in hook.\n");
-		goto cleanup_outops;
-	}
-	ret = nf_register_hook(&ip_nat_adjust_out_ops);
-	if (ret < 0) {
-		printk("ip_nat_init: can't register adjust out hook.\n");
-		goto cleanup_adjustin_ops;
-	}
-	ret = nf_register_hook(&ip_nat_local_out_ops);
-	if (ret < 0) {
-		printk("ip_nat_init: can't register local out hook.\n");
-		goto cleanup_adjustout_ops;
-	}
-	ret = nf_register_hook(&ip_nat_local_in_ops);
-	if (ret < 0) {
-		printk("ip_nat_init: can't register local in hook.\n");
-		goto cleanup_localoutops;
-	}
 	return ret;
 
  cleanup:
-	nf_unregister_hook(&ip_nat_local_in_ops);
- cleanup_localoutops:
-	nf_unregister_hook(&ip_nat_local_out_ops);
- cleanup_adjustout_ops:
-	nf_unregister_hook(&ip_nat_adjust_out_ops);
- cleanup_adjustin_ops:
-	nf_unregister_hook(&ip_nat_adjust_in_ops);
- cleanup_outops:
-	nf_unregister_hook(&ip_nat_out_ops);
- cleanup_inops:
-	nf_unregister_hook(&ip_nat_in_ops);
+	nf_unregister_hooks(ip_nat_ops, ARRAY_SIZE(ip_nat_ops));
  cleanup_rule_init:
 	ip_nat_rule_cleanup();
  cleanup_decode_session:
diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c
index 3d80aefe9cfa..7f417484bfbf 100644
--- a/net/ipv4/netfilter/iptable_filter.c
+++ b/net/ipv4/netfilter/iptable_filter.c
@@ -157,37 +157,20 @@ static int __init iptable_filter_init(void)
 		return ret;
 
 	/* Register hooks */
-	ret = nf_register_hook(&ipt_ops[0]);
+	ret = nf_register_hooks(ipt_ops, ARRAY_SIZE(ipt_ops));
 	if (ret < 0)
 		goto cleanup_table;
 
-	ret = nf_register_hook(&ipt_ops[1]);
-	if (ret < 0)
-		goto cleanup_hook0;
-
-	ret = nf_register_hook(&ipt_ops[2]);
-	if (ret < 0)
-		goto cleanup_hook1;
-
 	return ret;
 
- cleanup_hook1:
-	nf_unregister_hook(&ipt_ops[1]);
- cleanup_hook0:
-	nf_unregister_hook(&ipt_ops[0]);
  cleanup_table:
 	ipt_unregister_table(&packet_filter);
-
 	return ret;
 }
 
 static void __exit iptable_filter_fini(void)
 {
-	unsigned int i;
-
-	for (i = 0; i < sizeof(ipt_ops)/sizeof(struct nf_hook_ops); i++)
-		nf_unregister_hook(&ipt_ops[i]);
-
+	nf_unregister_hooks(ipt_ops, ARRAY_SIZE(ipt_ops));
 	ipt_unregister_table(&packet_filter);
 }
 
diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c
index 412fc96cc896..397b95cc026b 100644
--- a/net/ipv4/netfilter/iptable_mangle.c
+++ b/net/ipv4/netfilter/iptable_mangle.c
@@ -211,49 +211,20 @@ static int __init iptable_mangle_init(void)
 		return ret;
 
 	/* Register hooks */
-	ret = nf_register_hook(&ipt_ops[0]);
+	ret = nf_register_hooks(ipt_ops, ARRAY_SIZE(ipt_ops));
 	if (ret < 0)
 		goto cleanup_table;
 
-	ret = nf_register_hook(&ipt_ops[1]);
-	if (ret < 0)
-		goto cleanup_hook0;
-
-	ret = nf_register_hook(&ipt_ops[2]);
-	if (ret < 0)
-		goto cleanup_hook1;
-
-	ret = nf_register_hook(&ipt_ops[3]);
-	if (ret < 0)
-		goto cleanup_hook2;
-
-	ret = nf_register_hook(&ipt_ops[4]);
-	if (ret < 0)
-		goto cleanup_hook3;
-
 	return ret;
 
- cleanup_hook3:
-        nf_unregister_hook(&ipt_ops[3]);
- cleanup_hook2:
-        nf_unregister_hook(&ipt_ops[2]);
- cleanup_hook1:
-	nf_unregister_hook(&ipt_ops[1]);
- cleanup_hook0:
-	nf_unregister_hook(&ipt_ops[0]);
  cleanup_table:
 	ipt_unregister_table(&packet_mangler);
-
 	return ret;
 }
 
 static void __exit iptable_mangle_fini(void)
 {
-	unsigned int i;
-
-	for (i = 0; i < sizeof(ipt_ops)/sizeof(struct nf_hook_ops); i++)
-		nf_unregister_hook(&ipt_ops[i]);
-
+	nf_unregister_hooks(ipt_ops, ARRAY_SIZE(ipt_ops));
 	ipt_unregister_table(&packet_mangler);
 }
 
diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c
index 03cc79a6160a..7912cce1e1b8 100644
--- a/net/ipv4/netfilter/iptable_raw.c
+++ b/net/ipv4/netfilter/iptable_raw.c
@@ -101,18 +101,18 @@ ipt_hook(unsigned int hook,
 /* 'raw' is the very first table. */
 static struct nf_hook_ops ipt_ops[] = {
 	{
-	  .hook = ipt_hook, 
-	  .pf = PF_INET, 
-	  .hooknum = NF_IP_PRE_ROUTING, 
-	  .priority = NF_IP_PRI_RAW,
-	  .owner = THIS_MODULE,
+		.hook = ipt_hook,
+		.pf = PF_INET,
+		.hooknum = NF_IP_PRE_ROUTING,
+		.priority = NF_IP_PRI_RAW,
+		.owner = THIS_MODULE,
 	},
 	{
-	  .hook = ipt_hook, 
-	  .pf = PF_INET, 
-	  .hooknum = NF_IP_LOCAL_OUT, 
-	  .priority = NF_IP_PRI_RAW,
-	  .owner = THIS_MODULE,
+		.hook = ipt_hook,
+		.pf = PF_INET,
+		.hooknum = NF_IP_LOCAL_OUT,
+		.priority = NF_IP_PRI_RAW,
+		.owner = THIS_MODULE,
 	},
 };
 
@@ -126,31 +126,20 @@ static int __init iptable_raw_init(void)
 		return ret;
 
 	/* Register hooks */
-	ret = nf_register_hook(&ipt_ops[0]);
+	ret = nf_register_hooks(ipt_ops, ARRAY_SIZE(ipt_ops));
 	if (ret < 0)
 		goto cleanup_table;
 
-	ret = nf_register_hook(&ipt_ops[1]);
-	if (ret < 0)
-		goto cleanup_hook0;
-
 	return ret;
 
- cleanup_hook0:
-	nf_unregister_hook(&ipt_ops[0]);
  cleanup_table:
 	ipt_unregister_table(&packet_raw);
-
 	return ret;
 }
 
 static void __exit iptable_raw_fini(void)
 {
-	unsigned int i;
-
-	for (i = 0; i < sizeof(ipt_ops)/sizeof(struct nf_hook_ops); i++)
-		nf_unregister_hook(&ipt_ops[i]);
-
+	nf_unregister_hooks(ipt_ops, ARRAY_SIZE(ipt_ops));
 	ipt_unregister_table(&packet_raw);
 }
 
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index 4afbc699d3ba..3fadaccbc582 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -210,71 +210,63 @@ static unsigned int ipv4_conntrack_local(unsigned int hooknum,
 
 /* Connection tracking may drop packets, but never alters them, so
    make it the first hook. */
-static struct nf_hook_ops ipv4_conntrack_defrag_ops = {
-	.hook		= ipv4_conntrack_defrag,
-	.owner		= THIS_MODULE,
-	.pf		= PF_INET,
-	.hooknum	= NF_IP_PRE_ROUTING,
-	.priority	= NF_IP_PRI_CONNTRACK_DEFRAG,
-};
-
-static struct nf_hook_ops ipv4_conntrack_in_ops = {
-	.hook		= ipv4_conntrack_in,
-	.owner		= THIS_MODULE,
-	.pf		= PF_INET,
-	.hooknum	= NF_IP_PRE_ROUTING,
-	.priority	= NF_IP_PRI_CONNTRACK,
-};
-
-static struct nf_hook_ops ipv4_conntrack_defrag_local_out_ops = {
-	.hook           = ipv4_conntrack_defrag,
-	.owner          = THIS_MODULE,
-	.pf             = PF_INET,
-	.hooknum        = NF_IP_LOCAL_OUT,
-	.priority       = NF_IP_PRI_CONNTRACK_DEFRAG,
-};
-
-static struct nf_hook_ops ipv4_conntrack_local_out_ops = {
-	.hook		= ipv4_conntrack_local,
-	.owner		= THIS_MODULE,
-	.pf		= PF_INET,
-	.hooknum	= NF_IP_LOCAL_OUT,
-	.priority	= NF_IP_PRI_CONNTRACK,
-};
-
-/* helpers */
-static struct nf_hook_ops ipv4_conntrack_helper_out_ops = {
-	.hook		= ipv4_conntrack_help,
-	.owner		= THIS_MODULE,
-	.pf		= PF_INET,
-	.hooknum	= NF_IP_POST_ROUTING,
-	.priority	= NF_IP_PRI_CONNTRACK_HELPER,
-};
-
-static struct nf_hook_ops ipv4_conntrack_helper_in_ops = {
-	.hook		= ipv4_conntrack_help,
-	.owner		= THIS_MODULE,
-	.pf		= PF_INET,
-	.hooknum	= NF_IP_LOCAL_IN,
-	.priority	= NF_IP_PRI_CONNTRACK_HELPER,
-};
-
-
-/* Refragmenter; last chance. */
-static struct nf_hook_ops ipv4_conntrack_out_ops = {
-	.hook		= ipv4_confirm,
-	.owner		= THIS_MODULE,
-	.pf		= PF_INET,
-	.hooknum	= NF_IP_POST_ROUTING,
-	.priority	= NF_IP_PRI_CONNTRACK_CONFIRM,
-};
-
-static struct nf_hook_ops ipv4_conntrack_local_in_ops = {
-	.hook		= ipv4_confirm,
-	.owner		= THIS_MODULE,
-	.pf		= PF_INET,
-	.hooknum	= NF_IP_LOCAL_IN,
-	.priority	= NF_IP_PRI_CONNTRACK_CONFIRM,
+static struct nf_hook_ops ipv4_conntrack_ops[] = {
+	{
+		.hook		= ipv4_conntrack_defrag,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET,
+		.hooknum	= NF_IP_PRE_ROUTING,
+		.priority	= NF_IP_PRI_CONNTRACK_DEFRAG,
+	},
+	{
+		.hook		= ipv4_conntrack_in,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET,
+		.hooknum	= NF_IP_PRE_ROUTING,
+		.priority	= NF_IP_PRI_CONNTRACK,
+	},
+	{
+		.hook           = ipv4_conntrack_defrag,
+		.owner          = THIS_MODULE,
+		.pf             = PF_INET,
+		.hooknum        = NF_IP_LOCAL_OUT,
+		.priority       = NF_IP_PRI_CONNTRACK_DEFRAG,
+	},
+	{
+		.hook		= ipv4_conntrack_local,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET,
+		.hooknum	= NF_IP_LOCAL_OUT,
+		.priority	= NF_IP_PRI_CONNTRACK,
+	},
+	{
+		.hook		= ipv4_conntrack_help,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET,
+		.hooknum	= NF_IP_POST_ROUTING,
+		.priority	= NF_IP_PRI_CONNTRACK_HELPER,
+	},
+	{
+		.hook		= ipv4_conntrack_help,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET,
+		.hooknum	= NF_IP_LOCAL_IN,
+		.priority	= NF_IP_PRI_CONNTRACK_HELPER,
+	},
+	{
+		.hook		= ipv4_confirm,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET,
+		.hooknum	= NF_IP_POST_ROUTING,
+		.priority	= NF_IP_PRI_CONNTRACK_CONFIRM,
+	},
+	{
+		.hook		= ipv4_confirm,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET,
+		.hooknum	= NF_IP_LOCAL_IN,
+		.priority	= NF_IP_PRI_CONNTRACK_CONFIRM,
+	},
 };
 
 #ifdef CONFIG_SYSCTL
@@ -476,59 +468,18 @@ static int init_or_cleanup(int init)
 		goto cleanup_icmp;
 	}
 
-	ret = nf_register_hook(&ipv4_conntrack_defrag_ops);
+	ret = nf_register_hooks(ipv4_conntrack_ops,
+				ARRAY_SIZE(ipv4_conntrack_ops));
 	if (ret < 0) {
-		printk("nf_conntrack_ipv4: can't register pre-routing defrag hook.\n");
+		printk("nf_conntrack_ipv4: can't register hooks.\n");
 		goto cleanup_ipv4;
 	}
-	ret = nf_register_hook(&ipv4_conntrack_defrag_local_out_ops);
-	if (ret < 0) {
-		printk("nf_conntrack_ipv4: can't register local_out defrag hook.\n");
-		goto cleanup_defragops;
-	}
-
-	ret = nf_register_hook(&ipv4_conntrack_in_ops);
-	if (ret < 0) {
-		printk("nf_conntrack_ipv4: can't register pre-routing hook.\n");
-		goto cleanup_defraglocalops;
-	}
-
-	ret = nf_register_hook(&ipv4_conntrack_local_out_ops);
-	if (ret < 0) {
-		printk("nf_conntrack_ipv4: can't register local out hook.\n");
-		goto cleanup_inops;
-	}
-
-	ret = nf_register_hook(&ipv4_conntrack_helper_in_ops);
-	if (ret < 0) {
-		printk("nf_conntrack_ipv4: can't register local helper hook.\n");
-		goto cleanup_inandlocalops;
-	}
-
-	ret = nf_register_hook(&ipv4_conntrack_helper_out_ops);
-	if (ret < 0) {
-		printk("nf_conntrack_ipv4: can't register postrouting helper hook.\n");
-		goto cleanup_helperinops;
-	}
-
-	ret = nf_register_hook(&ipv4_conntrack_out_ops);
-	if (ret < 0) {
-		printk("nf_conntrack_ipv4: can't register post-routing hook.\n");
-		goto cleanup_helperoutops;
-	}
-
-	ret = nf_register_hook(&ipv4_conntrack_local_in_ops);
-	if (ret < 0) {
-		printk("nf_conntrack_ipv4: can't register local in hook.\n");
-		goto cleanup_inoutandlocalops;
-	}
-
 #ifdef CONFIG_SYSCTL
 	nf_ct_ipv4_sysctl_header = register_sysctl_table(nf_ct_net_table, 0);
 	if (nf_ct_ipv4_sysctl_header == NULL) {
 		printk("nf_conntrack: can't register to sysctl.\n");
 		ret = -ENOMEM;
-		goto cleanup_localinops;
+		goto cleanup_hooks;
 	}
 #endif
 	return ret;
@@ -537,23 +488,9 @@ static int init_or_cleanup(int init)
 	synchronize_net();
 #ifdef CONFIG_SYSCTL
  	unregister_sysctl_table(nf_ct_ipv4_sysctl_header);
- cleanup_localinops:
+ cleanup_hooks:
 #endif
-	nf_unregister_hook(&ipv4_conntrack_local_in_ops);
- cleanup_inoutandlocalops:
-	nf_unregister_hook(&ipv4_conntrack_out_ops);
- cleanup_helperoutops:
-	nf_unregister_hook(&ipv4_conntrack_helper_out_ops);
- cleanup_helperinops:
-	nf_unregister_hook(&ipv4_conntrack_helper_in_ops);
- cleanup_inandlocalops:
-	nf_unregister_hook(&ipv4_conntrack_local_out_ops);
- cleanup_inops:
-	nf_unregister_hook(&ipv4_conntrack_in_ops);
- cleanup_defraglocalops:
-	nf_unregister_hook(&ipv4_conntrack_defrag_local_out_ops);
- cleanup_defragops:
-	nf_unregister_hook(&ipv4_conntrack_defrag_ops);
+	nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops));
  cleanup_ipv4:
 	nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv4);
  cleanup_icmp:
diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c
index e5e724d9ee60..60976c0c58e8 100644
--- a/net/ipv6/netfilter/ip6table_filter.c
+++ b/net/ipv6/netfilter/ip6table_filter.c
@@ -177,37 +177,20 @@ static int __init ip6table_filter_init(void)
 		return ret;
 
 	/* Register hooks */
-	ret = nf_register_hook(&ip6t_ops[0]);
+	ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops));
 	if (ret < 0)
 		goto cleanup_table;
 
-	ret = nf_register_hook(&ip6t_ops[1]);
-	if (ret < 0)
-		goto cleanup_hook0;
-
-	ret = nf_register_hook(&ip6t_ops[2]);
-	if (ret < 0)
-		goto cleanup_hook1;
-
 	return ret;
 
- cleanup_hook1:
-	nf_unregister_hook(&ip6t_ops[1]);
- cleanup_hook0:
-	nf_unregister_hook(&ip6t_ops[0]);
  cleanup_table:
 	ip6t_unregister_table(&packet_filter);
-
 	return ret;
 }
 
 static void __exit ip6table_filter_fini(void)
 {
-	unsigned int i;
-
-	for (i = 0; i < sizeof(ip6t_ops)/sizeof(struct nf_hook_ops); i++)
-		nf_unregister_hook(&ip6t_ops[i]);
-
+	nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops));
 	ip6t_unregister_table(&packet_filter);
 }
 
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c
index e1f0f6ae9841..03a13eab1dae 100644
--- a/net/ipv6/netfilter/ip6table_mangle.c
+++ b/net/ipv6/netfilter/ip6table_mangle.c
@@ -238,49 +238,20 @@ static int __init ip6table_mangle_init(void)
 		return ret;
 
 	/* Register hooks */
-	ret = nf_register_hook(&ip6t_ops[0]);
+	ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops));
 	if (ret < 0)
 		goto cleanup_table;
 
-	ret = nf_register_hook(&ip6t_ops[1]);
-	if (ret < 0)
-		goto cleanup_hook0;
-
-	ret = nf_register_hook(&ip6t_ops[2]);
-	if (ret < 0)
-		goto cleanup_hook1;
-
-	ret = nf_register_hook(&ip6t_ops[3]);
-	if (ret < 0)
-		goto cleanup_hook2;
-
-	ret = nf_register_hook(&ip6t_ops[4]);
-	if (ret < 0)
-		goto cleanup_hook3;
-
 	return ret;
 
- cleanup_hook3:
-        nf_unregister_hook(&ip6t_ops[3]);
- cleanup_hook2:
-	nf_unregister_hook(&ip6t_ops[2]);
- cleanup_hook1:
-	nf_unregister_hook(&ip6t_ops[1]);
- cleanup_hook0:
-	nf_unregister_hook(&ip6t_ops[0]);
  cleanup_table:
 	ip6t_unregister_table(&packet_mangler);
-
 	return ret;
 }
 
 static void __exit ip6table_mangle_fini(void)
 {
-	unsigned int i;
-
-	for (i = 0; i < sizeof(ip6t_ops)/sizeof(struct nf_hook_ops); i++)
-		nf_unregister_hook(&ip6t_ops[i]);
-
+	nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops));
 	ip6t_unregister_table(&packet_mangler);
 }
 
diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c
index 54d1fffd62ba..61a7c58e99f8 100644
--- a/net/ipv6/netfilter/ip6table_raw.c
+++ b/net/ipv6/netfilter/ip6table_raw.c
@@ -152,31 +152,20 @@ static int __init ip6table_raw_init(void)
 		return ret;
 
 	/* Register hooks */
-	ret = nf_register_hook(&ip6t_ops[0]);
+	ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops));
 	if (ret < 0)
 		goto cleanup_table;
 
-	ret = nf_register_hook(&ip6t_ops[1]);
-	if (ret < 0)
-		goto cleanup_hook0;
-
 	return ret;
 
- cleanup_hook0:
-	nf_unregister_hook(&ip6t_ops[0]);
  cleanup_table:
 	ip6t_unregister_table(&packet_raw);
-
 	return ret;
 }
 
 static void __exit ip6table_raw_fini(void)
 {
-	unsigned int i;
-
-	for (i = 0; i < sizeof(ip6t_ops)/sizeof(struct nf_hook_ops); i++)
-		nf_unregister_hook(&ip6t_ops[i]);
-
+	nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops));
 	ip6t_unregister_table(&packet_raw);
 }
 
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index c8b5a96cbb0f..0426ed0e9c1d 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -286,55 +286,49 @@ static unsigned int ipv6_conntrack_local(unsigned int hooknum,
 	return ipv6_conntrack_in(hooknum, pskb, in, out, okfn);
 }
 
-/* Connection tracking may drop packets, but never alters them, so
-   make it the first hook. */
-static struct nf_hook_ops ipv6_conntrack_defrag_ops = {
-	.hook		= ipv6_defrag,
-	.owner		= THIS_MODULE,
-	.pf		= PF_INET6,
-	.hooknum	= NF_IP6_PRE_ROUTING,
-	.priority	= NF_IP6_PRI_CONNTRACK_DEFRAG,
-};
-
-static struct nf_hook_ops ipv6_conntrack_in_ops = {
-	.hook		= ipv6_conntrack_in,
-	.owner		= THIS_MODULE,
-	.pf		= PF_INET6,
-	.hooknum	= NF_IP6_PRE_ROUTING,
-	.priority	= NF_IP6_PRI_CONNTRACK,
-};
-
-static struct nf_hook_ops ipv6_conntrack_local_out_ops = {
-	.hook		= ipv6_conntrack_local,
-	.owner		= THIS_MODULE,
-	.pf		= PF_INET6,
-	.hooknum	= NF_IP6_LOCAL_OUT,
-	.priority	= NF_IP6_PRI_CONNTRACK,
-};
-
-static struct nf_hook_ops ipv6_conntrack_defrag_local_out_ops = {
-	.hook		= ipv6_defrag,
-	.owner		= THIS_MODULE,
-	.pf		= PF_INET6,
-	.hooknum	= NF_IP6_LOCAL_OUT,
-	.priority	= NF_IP6_PRI_CONNTRACK_DEFRAG,
-};
-
-/* Refragmenter; last chance. */
-static struct nf_hook_ops ipv6_conntrack_out_ops = {
-	.hook		= ipv6_confirm,
-	.owner		= THIS_MODULE,
-	.pf		= PF_INET6,
-	.hooknum	= NF_IP6_POST_ROUTING,
-	.priority	= NF_IP6_PRI_LAST,
-};
-
-static struct nf_hook_ops ipv6_conntrack_local_in_ops = {
-	.hook		= ipv6_confirm,
-	.owner		= THIS_MODULE,
-	.pf		= PF_INET6,
-	.hooknum	= NF_IP6_LOCAL_IN,
-	.priority	= NF_IP6_PRI_LAST-1,
+static struct nf_hook_ops ipv6_conntrack_ops[] = {
+	{
+		.hook		= ipv6_defrag,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET6,
+		.hooknum	= NF_IP6_PRE_ROUTING,
+		.priority	= NF_IP6_PRI_CONNTRACK_DEFRAG,
+	},
+	{
+		.hook		= ipv6_conntrack_in,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET6,
+		.hooknum	= NF_IP6_PRE_ROUTING,
+		.priority	= NF_IP6_PRI_CONNTRACK,
+	},
+	{
+		.hook		= ipv6_conntrack_local,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET6,
+		.hooknum	= NF_IP6_LOCAL_OUT,
+		.priority	= NF_IP6_PRI_CONNTRACK,
+	},
+	{
+		.hook		= ipv6_defrag,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET6,
+		.hooknum	= NF_IP6_LOCAL_OUT,
+		.priority	= NF_IP6_PRI_CONNTRACK_DEFRAG,
+	},
+	{
+		.hook		= ipv6_confirm,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET6,
+		.hooknum	= NF_IP6_POST_ROUTING,
+		.priority	= NF_IP6_PRI_LAST,
+	},
+	{
+		.hook		= ipv6_confirm,
+		.owner		= THIS_MODULE,
+		.pf		= PF_INET6,
+		.hooknum	= NF_IP6_LOCAL_IN,
+		.priority	= NF_IP6_PRI_LAST-1,
+	},
 };
 
 #ifdef CONFIG_SYSCTL
@@ -505,50 +499,19 @@ static int init_or_cleanup(int init)
 		goto cleanup_icmpv6;
 	}
 
-	ret = nf_register_hook(&ipv6_conntrack_defrag_ops);
+	ret = nf_register_hooks(ipv6_conntrack_ops,
+				ARRAY_SIZE(ipv6_conntrack_ops));
 	if (ret < 0) {
 		printk("nf_conntrack_ipv6: can't register pre-routing defrag "
 		       "hook.\n");
 		goto cleanup_ipv6;
 	}
-
-	ret = nf_register_hook(&ipv6_conntrack_defrag_local_out_ops);
-	if (ret < 0) {
-		printk("nf_conntrack_ipv6: can't register local_out defrag "
-		       "hook.\n");
-		goto cleanup_defragops;
-	}
-
-	ret = nf_register_hook(&ipv6_conntrack_in_ops);
-	if (ret < 0) {
-		printk("nf_conntrack_ipv6: can't register pre-routing hook.\n");
-		goto cleanup_defraglocalops;
-	}
-
-	ret = nf_register_hook(&ipv6_conntrack_local_out_ops);
-	if (ret < 0) {
-		printk("nf_conntrack_ipv6: can't register local out hook.\n");
-		goto cleanup_inops;
-	}
-
-	ret = nf_register_hook(&ipv6_conntrack_out_ops);
-	if (ret < 0) {
-		printk("nf_conntrack_ipv6: can't register post-routing hook.\n");
-		goto cleanup_inandlocalops;
-	}
-
-	ret = nf_register_hook(&ipv6_conntrack_local_in_ops);
-	if (ret < 0) {
-		printk("nf_conntrack_ipv6: can't register local in hook.\n");
-		goto cleanup_inoutandlocalops;
-	}
-
 #ifdef CONFIG_SYSCTL
 	nf_ct_ipv6_sysctl_header = register_sysctl_table(nf_ct_net_table, 0);
 	if (nf_ct_ipv6_sysctl_header == NULL) {
 		printk("nf_conntrack: can't register to sysctl.\n");
 		ret = -ENOMEM;
-		goto cleanup_localinops;
+		goto cleanup_hooks;
 	}
 #endif
 	return ret;
@@ -557,19 +520,9 @@ static int init_or_cleanup(int init)
 	synchronize_net();
 #ifdef CONFIG_SYSCTL
  	unregister_sysctl_table(nf_ct_ipv6_sysctl_header);
- cleanup_localinops:
+ cleanup_hooks:
 #endif
-	nf_unregister_hook(&ipv6_conntrack_local_in_ops);
- cleanup_inoutandlocalops:
-	nf_unregister_hook(&ipv6_conntrack_out_ops);
- cleanup_inandlocalops:
-	nf_unregister_hook(&ipv6_conntrack_local_out_ops);
- cleanup_inops:
-	nf_unregister_hook(&ipv6_conntrack_in_ops);
- cleanup_defraglocalops:
-	nf_unregister_hook(&ipv6_conntrack_defrag_local_out_ops);
- cleanup_defragops:
-	nf_unregister_hook(&ipv6_conntrack_defrag_ops);
+	nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops));
  cleanup_ipv6:
 	nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv6);
  cleanup_icmpv6:

From 32292a7ff1d9306841a8da6ea286847b1070cc6a Mon Sep 17 00:00:00 2001
From: Patrick McHardy <kaber@trash.net>
Date: Thu, 6 Apr 2006 14:11:30 -0700
Subject: [PATCH 14/35] [NETFILTER]: Fix section mismatch warnings

Fix section mismatch warnings caused by netfilter's init_or_cleanup
functions used in many places by splitting the init from the cleanup
parts.

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/ipv4/netfilter/ip_conntrack_standalone.c  |  90 +++++++-------
 net/ipv4/netfilter/ip_nat_standalone.c        |  18 ++-
 net/ipv4/netfilter/ip_queue.c                 |  31 +++--
 net/ipv4/netfilter/ipt_CLUSTERIP.c            |  42 +++----
 .../netfilter/nf_conntrack_l3proto_ipv4.c     |  36 +++---
 net/ipv6/netfilter/ip6_queue.c                |  31 +++--
 .../netfilter/nf_conntrack_l3proto_ipv6.c     |  38 +++---
 net/netfilter/nf_conntrack_standalone.c       | 115 +++++++++---------
 net/netfilter/nfnetlink_log.c                 |  25 ++--
 net/netfilter/nfnetlink_queue.c               |  27 ++--
 10 files changed, 204 insertions(+), 249 deletions(-)

diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c
index adc1a0f66409..929d61f7be91 100644
--- a/net/ipv4/netfilter/ip_conntrack_standalone.c
+++ b/net/ipv4/netfilter/ip_conntrack_standalone.c
@@ -776,18 +776,46 @@ static ctl_table ip_ct_net_table[] = {
 EXPORT_SYMBOL(ip_ct_log_invalid);
 #endif /* CONFIG_SYSCTL */
 
-static int init_or_cleanup(int init)
+/* FIXME: Allow NULL functions and sub in pointers to generic for
+   them. --RR */
+int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto)
+{
+	int ret = 0;
+
+	write_lock_bh(&ip_conntrack_lock);
+	if (ip_ct_protos[proto->proto] != &ip_conntrack_generic_protocol) {
+		ret = -EBUSY;
+		goto out;
+	}
+	ip_ct_protos[proto->proto] = proto;
+ out:
+	write_unlock_bh(&ip_conntrack_lock);
+	return ret;
+}
+
+void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto)
+{
+	write_lock_bh(&ip_conntrack_lock);
+	ip_ct_protos[proto->proto] = &ip_conntrack_generic_protocol;
+	write_unlock_bh(&ip_conntrack_lock);
+
+	/* Somebody could be still looking at the proto in bh. */
+	synchronize_net();
+
+	/* Remove all contrack entries for this protocol */
+	ip_ct_iterate_cleanup(kill_proto, &proto->proto);
+}
+
+static int __init ip_conntrack_standalone_init(void)
 {
 #ifdef CONFIG_PROC_FS
 	struct proc_dir_entry *proc, *proc_exp, *proc_stat;
 #endif
 	int ret = 0;
 
-	if (!init) goto cleanup;
-
 	ret = ip_conntrack_init();
 	if (ret < 0)
-		goto cleanup_nothing;
+		return ret;
 
 #ifdef CONFIG_PROC_FS
 	ret = -ENOMEM;
@@ -819,16 +847,12 @@ static int init_or_cleanup(int init)
 		goto cleanup_hooks;
 	}
 #endif
-
 	return ret;
 
- cleanup:
-	synchronize_net();
 #ifdef CONFIG_SYSCTL
- 	unregister_sysctl_table(ip_ct_sysctl_header);
  cleanup_hooks:
-#endif
 	nf_unregister_hooks(ip_conntrack_ops, ARRAY_SIZE(ip_conntrack_ops));
+#endif
  cleanup_proc_stat:
 #ifdef CONFIG_PROC_FS
 	remove_proc_entry("ip_conntrack", proc_net_stat);
@@ -839,48 +863,22 @@ static int init_or_cleanup(int init)
  cleanup_init:
 #endif /* CONFIG_PROC_FS */
 	ip_conntrack_cleanup();
- cleanup_nothing:
 	return ret;
 }
 
-/* FIXME: Allow NULL functions and sub in pointers to generic for
-   them. --RR */
-int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto)
-{
-	int ret = 0;
-
-	write_lock_bh(&ip_conntrack_lock);
-	if (ip_ct_protos[proto->proto] != &ip_conntrack_generic_protocol) {
-		ret = -EBUSY;
-		goto out;
-	}
-	ip_ct_protos[proto->proto] = proto;
- out:
-	write_unlock_bh(&ip_conntrack_lock);
-	return ret;
-}
-
-void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto)
-{
-	write_lock_bh(&ip_conntrack_lock);
-	ip_ct_protos[proto->proto] = &ip_conntrack_generic_protocol;
-	write_unlock_bh(&ip_conntrack_lock);
-	
-	/* Somebody could be still looking at the proto in bh. */
-	synchronize_net();
-
-	/* Remove all contrack entries for this protocol */
-	ip_ct_iterate_cleanup(kill_proto, &proto->proto);
-}
-
-static int __init ip_conntrack_standalone_init(void)
-{
-	return init_or_cleanup(1);
-}
-
 static void __exit ip_conntrack_standalone_fini(void)
 {
-	init_or_cleanup(0);
+	synchronize_net();
+#ifdef CONFIG_SYSCTL
+	unregister_sysctl_table(ip_ct_sysctl_header);
+#endif
+	nf_unregister_hooks(ip_conntrack_ops, ARRAY_SIZE(ip_conntrack_ops));
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry("ip_conntrack", proc_net_stat);
+	proc_net_remove("ip_conntrack_expect");
+	proc_net_remove("ip_conntrack");
+#endif /* CONFIG_PROC_FS */
+	ip_conntrack_cleanup();
 }
 
 module_init(ip_conntrack_standalone_init);
diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c
index 5f02f439b07e..8f760b28617e 100644
--- a/net/ipv4/netfilter/ip_nat_standalone.c
+++ b/net/ipv4/netfilter/ip_nat_standalone.c
@@ -350,14 +350,12 @@ static struct nf_hook_ops ip_nat_ops[] = {
 	},
 };
 
-static int init_or_cleanup(int init)
+static int __init ip_nat_standalone_init(void)
 {
 	int ret = 0;
 
 	need_conntrack();
 
-	if (!init) goto cleanup;
-
 #ifdef CONFIG_XFRM
 	BUG_ON(ip_nat_decode_session != NULL);
 	ip_nat_decode_session = nat_decode_session;
@@ -374,8 +372,6 @@ static int init_or_cleanup(int init)
 	}
 	return ret;
 
- cleanup:
-	nf_unregister_hooks(ip_nat_ops, ARRAY_SIZE(ip_nat_ops));
  cleanup_rule_init:
 	ip_nat_rule_cleanup();
  cleanup_decode_session:
@@ -386,14 +382,14 @@ static int init_or_cleanup(int init)
 	return ret;
 }
 
-static int __init ip_nat_standalone_init(void)
-{
-	return init_or_cleanup(1);
-}
-
 static void __exit ip_nat_standalone_fini(void)
 {
-	init_or_cleanup(0);
+	nf_unregister_hooks(ip_nat_ops, ARRAY_SIZE(ip_nat_ops));
+	ip_nat_rule_cleanup();
+#ifdef CONFIG_XFRM
+	ip_nat_decode_session = NULL;
+	synchronize_net();
+#endif
 }
 
 module_init(ip_nat_standalone_init);
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c
index 896a244f8f91..b93f0494362f 100644
--- a/net/ipv4/netfilter/ip_queue.c
+++ b/net/ipv4/netfilter/ip_queue.c
@@ -662,15 +662,11 @@ static struct nf_queue_handler nfqh = {
 	.outfn	= &ipq_enqueue_packet,
 };
 
-static int
-init_or_cleanup(int init)
+static int __init ip_queue_init(void)
 {
 	int status = -ENOMEM;
 	struct proc_dir_entry *proc;
 	
-	if (!init)
-		goto cleanup;
-
 	netlink_register_notifier(&ipq_nl_notifier);
 	ipqnl = netlink_kernel_create(NETLINK_FIREWALL, 0, ipq_rcv_sk,
 				      THIS_MODULE);
@@ -697,11 +693,6 @@ init_or_cleanup(int init)
 	}
 	return status;
 
-cleanup:
-	nf_unregister_queue_handlers(&nfqh);
-	synchronize_net();
-	ipq_flush(NF_DROP);
-	
 cleanup_sysctl:
 	unregister_sysctl_table(ipq_sysctl_header);
 	unregister_netdevice_notifier(&ipq_dev_notifier);
@@ -717,15 +708,21 @@ init_or_cleanup(int init)
 	return status;
 }
 
-static int __init ip_queue_init(void)
-{
-	
-	return init_or_cleanup(1);
-}
-
 static void __exit ip_queue_fini(void)
 {
-	init_or_cleanup(0);
+	nf_unregister_queue_handlers(&nfqh);
+	synchronize_net();
+	ipq_flush(NF_DROP);
+
+	unregister_sysctl_table(ipq_sysctl_header);
+	unregister_netdevice_notifier(&ipq_dev_notifier);
+	proc_net_remove(IPQ_PROC_FS_NAME);
+
+	sock_release(ipqnl->sk_socket);
+	mutex_lock(&ipqnl_mutex);
+	mutex_unlock(&ipqnl_mutex);
+
+	netlink_unregister_notifier(&ipq_nl_notifier);
 }
 
 MODULE_DESCRIPTION("IPv4 packet queue handler");
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index e4768a31718b..aad9d28c8d71 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -725,22 +725,17 @@ static struct file_operations clusterip_proc_fops = {
 
 #endif /* CONFIG_PROC_FS */
 
-static int init_or_cleanup(int fini)
+static int __init ipt_clusterip_init(void)
 {
 	int ret;
 
-	if (fini)
-		goto cleanup;
+	ret = ipt_register_target(&clusterip_tgt);
+	if (ret < 0)
+		return ret;
 
-	if (ipt_register_target(&clusterip_tgt)) {
-		ret = -EINVAL;
-		goto cleanup_none;
-	}
-
-	if (nf_register_hook(&cip_arp_ops) < 0) {
-		ret = -EINVAL;
+	ret = nf_register_hook(&cip_arp_ops);
+	if (ret < 0)
 		goto cleanup_target;
-	}
 
 #ifdef CONFIG_PROC_FS
 	clusterip_procdir = proc_mkdir("ipt_CLUSTERIP", proc_net);
@@ -753,31 +748,24 @@ static int init_or_cleanup(int fini)
 
 	printk(KERN_NOTICE "ClusterIP Version %s loaded successfully\n",
 		CLUSTERIP_VERSION);
-
 	return 0;
 
-cleanup:
+cleanup_hook:
+	nf_unregister_hook(&cip_arp_ops);
+cleanup_target:
+	ipt_unregister_target(&clusterip_tgt);
+	return ret;
+}
+
+static void __exit ipt_clusterip_fini(void)
+{
 	printk(KERN_NOTICE "ClusterIP Version %s unloading\n",
 		CLUSTERIP_VERSION);
 #ifdef CONFIG_PROC_FS
 	remove_proc_entry(clusterip_procdir->name, clusterip_procdir->parent);
 #endif
-cleanup_hook:
 	nf_unregister_hook(&cip_arp_ops);
-cleanup_target:
 	ipt_unregister_target(&clusterip_tgt);
-cleanup_none:
-	return -EINVAL;
-}
-
-static int __init ipt_clusterip_init(void)
-{
-	return init_or_cleanup(0);
-}
-
-static void __exit ipt_clusterip_fini(void)
-{
-	init_or_cleanup(1);
 }
 
 module_init(ipt_clusterip_init);
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index 3fadaccbc582..5bc9f64d7b5b 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -432,16 +432,20 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 = {
 extern struct nf_conntrack_protocol nf_conntrack_protocol_tcp4;
 extern struct nf_conntrack_protocol nf_conntrack_protocol_udp4;
 extern struct nf_conntrack_protocol nf_conntrack_protocol_icmp;
-static int init_or_cleanup(int init)
+
+MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET));
+MODULE_LICENSE("GPL");
+
+static int __init nf_conntrack_l3proto_ipv4_init(void)
 {
 	int ret = 0;
 
-	if (!init) goto cleanup;
+	need_conntrack();
 
 	ret = nf_register_sockopt(&so_getorigdst);
 	if (ret < 0) {
 		printk(KERN_ERR "Unable to register netfilter socket option\n");
-		goto cleanup_nothing;
+		return ret;
 	}
 
 	ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_tcp4);
@@ -484,13 +488,10 @@ static int init_or_cleanup(int init)
 #endif
 	return ret;
 
- cleanup:
-	synchronize_net();
 #ifdef CONFIG_SYSCTL
- 	unregister_sysctl_table(nf_ct_ipv4_sysctl_header);
  cleanup_hooks:
-#endif
 	nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops));
+#endif
  cleanup_ipv4:
 	nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv4);
  cleanup_icmp:
@@ -501,22 +502,21 @@ static int init_or_cleanup(int init)
 	nf_conntrack_protocol_unregister(&nf_conntrack_protocol_tcp4);
  cleanup_sockopt:
 	nf_unregister_sockopt(&so_getorigdst);
- cleanup_nothing:
 	return ret;
 }
 
-MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET));
-MODULE_LICENSE("GPL");
-
-static int __init nf_conntrack_l3proto_ipv4_init(void)
-{
-	need_conntrack();
-	return init_or_cleanup(1);
-}
-
 static void __exit nf_conntrack_l3proto_ipv4_fini(void)
 {
-	init_or_cleanup(0);
+	synchronize_net();
+#ifdef CONFIG_SYSCTL
+ 	unregister_sysctl_table(nf_ct_ipv4_sysctl_header);
+#endif
+	nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops));
+	nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv4);
+	nf_conntrack_protocol_unregister(&nf_conntrack_protocol_icmp);
+	nf_conntrack_protocol_unregister(&nf_conntrack_protocol_udp4);
+	nf_conntrack_protocol_unregister(&nf_conntrack_protocol_tcp4);
+	nf_unregister_sockopt(&so_getorigdst);
 }
 
 module_init(nf_conntrack_l3proto_ipv4_init);
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c
index e81c6a9dab81..b4b7d441af25 100644
--- a/net/ipv6/netfilter/ip6_queue.c
+++ b/net/ipv6/netfilter/ip6_queue.c
@@ -658,15 +658,11 @@ static struct nf_queue_handler nfqh = {
 	.outfn	= &ipq_enqueue_packet,
 };
 
-static int
-init_or_cleanup(int init)
+static int __init ip6_queue_init(void)
 {
 	int status = -ENOMEM;
 	struct proc_dir_entry *proc;
 	
-	if (!init)
-		goto cleanup;
-
 	netlink_register_notifier(&ipq_nl_notifier);
 	ipqnl = netlink_kernel_create(NETLINK_IP6_FW, 0, ipq_rcv_sk,
 	                              THIS_MODULE);
@@ -693,11 +689,6 @@ init_or_cleanup(int init)
 	}
 	return status;
 
-cleanup:
-	nf_unregister_queue_handlers(&nfqh);
-	synchronize_net();
-	ipq_flush(NF_DROP);
-	
 cleanup_sysctl:
 	unregister_sysctl_table(ipq_sysctl_header);
 	unregister_netdevice_notifier(&ipq_dev_notifier);
@@ -713,15 +704,21 @@ init_or_cleanup(int init)
 	return status;
 }
 
-static int __init ip6_queue_init(void)
-{
-	
-	return init_or_cleanup(1);
-}
-
 static void __exit ip6_queue_fini(void)
 {
-	init_or_cleanup(0);
+	nf_unregister_queue_handlers(&nfqh);
+	synchronize_net();
+	ipq_flush(NF_DROP);
+
+	unregister_sysctl_table(ipq_sysctl_header);
+	unregister_netdevice_notifier(&ipq_dev_notifier);
+	proc_net_remove(IPQ_PROC_FS_NAME);
+
+	sock_release(ipqnl->sk_socket);
+	mutex_lock(&ipqnl_mutex);
+	mutex_unlock(&ipqnl_mutex);
+
+	netlink_unregister_notifier(&ipq_nl_notifier);
 }
 
 MODULE_DESCRIPTION("IPv6 packet queue handler");
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index 0426ed0e9c1d..93bae36f2663 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -464,16 +464,21 @@ extern struct nf_conntrack_protocol nf_conntrack_protocol_udp6;
 extern struct nf_conntrack_protocol nf_conntrack_protocol_icmpv6;
 extern int nf_ct_frag6_init(void);
 extern void nf_ct_frag6_cleanup(void);
-static int init_or_cleanup(int init)
+
+MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET6));
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI <yasuyuki.kozakai@toshiba.co.jp>");
+
+static int __init nf_conntrack_l3proto_ipv6_init(void)
 {
 	int ret = 0;
 
-	if (!init) goto cleanup;
+	need_conntrack();
 
 	ret = nf_ct_frag6_init();
 	if (ret < 0) {
 		printk("nf_conntrack_ipv6: can't initialize frag6.\n");
-		goto cleanup_nothing;
+		return ret;
 	}
 	ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_tcp6);
 	if (ret < 0) {
@@ -516,13 +521,10 @@ static int init_or_cleanup(int init)
 #endif
 	return ret;
 
- cleanup:
-	synchronize_net();
 #ifdef CONFIG_SYSCTL
- 	unregister_sysctl_table(nf_ct_ipv6_sysctl_header);
  cleanup_hooks:
-#endif
 	nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops));
+#endif
  cleanup_ipv6:
 	nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv6);
  cleanup_icmpv6:
@@ -533,23 +535,21 @@ static int init_or_cleanup(int init)
 	nf_conntrack_protocol_unregister(&nf_conntrack_protocol_tcp6);
  cleanup_frag6:
 	nf_ct_frag6_cleanup();
- cleanup_nothing:
 	return ret;
 }
 
-MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET6));
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI <yasuyuki.kozakai@toshiba.co.jp>");
-
-static int __init nf_conntrack_l3proto_ipv6_init(void)
-{
-	need_conntrack();
-	return init_or_cleanup(1);
-}
-
 static void __exit nf_conntrack_l3proto_ipv6_fini(void)
 {
-	init_or_cleanup(0);
+	synchronize_net();
+#ifdef CONFIG_SYSCTL
+ 	unregister_sysctl_table(nf_ct_ipv6_sysctl_header);
+#endif
+	nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops));
+	nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv6);
+	nf_conntrack_protocol_unregister(&nf_conntrack_protocol_icmpv6);
+	nf_conntrack_protocol_unregister(&nf_conntrack_protocol_udp6);
+	nf_conntrack_protocol_unregister(&nf_conntrack_protocol_tcp6);
+	nf_ct_frag6_cleanup();
 }
 
 module_init(nf_conntrack_l3proto_ipv6_init);
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
index c72aa3cd22e4..408960c6a544 100644
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -649,63 +649,6 @@ static ctl_table nf_ct_net_table[] = {
 EXPORT_SYMBOL(nf_ct_log_invalid);
 #endif /* CONFIG_SYSCTL */
 
-static int init_or_cleanup(int init)
-{
-#ifdef CONFIG_PROC_FS
-	struct proc_dir_entry *proc, *proc_exp, *proc_stat;
-#endif
-	int ret = 0;
-
-	if (!init) goto cleanup;
-
-	ret = nf_conntrack_init();
-	if (ret < 0)
-		goto cleanup_nothing;
-
-#ifdef CONFIG_PROC_FS
-	proc = proc_net_fops_create("nf_conntrack", 0440, &ct_file_ops);
-	if (!proc) goto cleanup_init;
-
-	proc_exp = proc_net_fops_create("nf_conntrack_expect", 0440,
-					&exp_file_ops);
-	if (!proc_exp) goto cleanup_proc;
-
-	proc_stat = create_proc_entry("nf_conntrack", S_IRUGO, proc_net_stat);
-	if (!proc_stat)
-		goto cleanup_proc_exp;
-
-	proc_stat->proc_fops = &ct_cpu_seq_fops;
-	proc_stat->owner = THIS_MODULE;
-#endif
-#ifdef CONFIG_SYSCTL
-	nf_ct_sysctl_header = register_sysctl_table(nf_ct_net_table, 0);
-	if (nf_ct_sysctl_header == NULL) {
-		printk("nf_conntrack: can't register to sysctl.\n");
-		ret = -ENOMEM;
-		goto cleanup_proc_stat;
-	}
-#endif
-
-	return ret;
-
- cleanup:
-#ifdef CONFIG_SYSCTL
- 	unregister_sysctl_table(nf_ct_sysctl_header);
- cleanup_proc_stat:
-#endif
-#ifdef CONFIG_PROC_FS
-	remove_proc_entry("nf_conntrack", proc_net_stat);
- cleanup_proc_exp:
-	proc_net_remove("nf_conntrack_expect");
- cleanup_proc:
-	proc_net_remove("nf_conntrack");
- cleanup_init:
-#endif /* CNFIG_PROC_FS */
-	nf_conntrack_cleanup();
- cleanup_nothing:
-	return ret;
-}
-
 int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto)
 {
 	int ret = 0;
@@ -808,12 +751,66 @@ void nf_conntrack_protocol_unregister(struct nf_conntrack_protocol *proto)
 
 static int __init nf_conntrack_standalone_init(void)
 {
-	return init_or_cleanup(1);
+#ifdef CONFIG_PROC_FS
+	struct proc_dir_entry *proc, *proc_exp, *proc_stat;
+#endif
+	int ret = 0;
+
+	ret = nf_conntrack_init();
+	if (ret < 0)
+		return ret;
+
+#ifdef CONFIG_PROC_FS
+	proc = proc_net_fops_create("nf_conntrack", 0440, &ct_file_ops);
+	if (!proc) goto cleanup_init;
+
+	proc_exp = proc_net_fops_create("nf_conntrack_expect", 0440,
+					&exp_file_ops);
+	if (!proc_exp) goto cleanup_proc;
+
+	proc_stat = create_proc_entry("nf_conntrack", S_IRUGO, proc_net_stat);
+	if (!proc_stat)
+		goto cleanup_proc_exp;
+
+	proc_stat->proc_fops = &ct_cpu_seq_fops;
+	proc_stat->owner = THIS_MODULE;
+#endif
+#ifdef CONFIG_SYSCTL
+	nf_ct_sysctl_header = register_sysctl_table(nf_ct_net_table, 0);
+	if (nf_ct_sysctl_header == NULL) {
+		printk("nf_conntrack: can't register to sysctl.\n");
+		ret = -ENOMEM;
+		goto cleanup_proc_stat;
+	}
+#endif
+	return ret;
+
+#ifdef CONFIG_SYSCTL
+ cleanup_proc_stat:
+#endif
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry("nf_conntrack", proc_net_stat);
+ cleanup_proc_exp:
+	proc_net_remove("nf_conntrack_expect");
+ cleanup_proc:
+	proc_net_remove("nf_conntrack");
+ cleanup_init:
+#endif /* CNFIG_PROC_FS */
+	nf_conntrack_cleanup();
+	return ret;
 }
 
 static void __exit nf_conntrack_standalone_fini(void)
 {
-	init_or_cleanup(0);
+#ifdef CONFIG_SYSCTL
+ 	unregister_sysctl_table(nf_ct_sysctl_header);
+#endif
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry("nf_conntrack", proc_net_stat);
+	proc_net_remove("nf_conntrack_expect");
+	proc_net_remove("nf_conntrack");
+#endif /* CNFIG_PROC_FS */
+	nf_conntrack_cleanup();
 }
 
 module_init(nf_conntrack_standalone_init);
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index 3e3f5448bacb..c60273cad778 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -1033,17 +1033,13 @@ static struct file_operations nful_file_ops = {
 
 #endif /* PROC_FS */
 
-static int
-init_or_cleanup(int init)
+static int __init nfnetlink_log_init(void)
 {
 	int i, status = -ENOMEM;
 #ifdef CONFIG_PROC_FS
 	struct proc_dir_entry *proc_nful;
 #endif
 	
-	if (!init)
-		goto cleanup;
-
 	for (i = 0; i < INSTANCE_BUCKETS; i++)
 		INIT_HLIST_HEAD(&instance_table[i]);
 	
@@ -1066,30 +1062,25 @@ init_or_cleanup(int init)
 		goto cleanup_subsys;
 	proc_nful->proc_fops = &nful_file_ops;
 #endif
-
 	return status;
 
-cleanup:
-	nf_log_unregister_logger(&nfulnl_logger);
 #ifdef CONFIG_PROC_FS
-	remove_proc_entry("nfnetlink_log", proc_net_netfilter);
 cleanup_subsys:
-#endif
 	nfnetlink_subsys_unregister(&nfulnl_subsys);
+#endif
 cleanup_netlink_notifier:
 	netlink_unregister_notifier(&nfulnl_rtnl_notifier);
 	return status;
 }
 
-static int __init nfnetlink_log_init(void)
-{
-	
-	return init_or_cleanup(1);
-}
-
 static void __exit nfnetlink_log_fini(void)
 {
-	init_or_cleanup(0);
+	nf_log_unregister_logger(&nfulnl_logger);
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry("nfnetlink_log", proc_net_netfilter);
+#endif
+	nfnetlink_subsys_unregister(&nfulnl_subsys);
+	netlink_unregister_notifier(&nfulnl_rtnl_notifier);
 }
 
 MODULE_DESCRIPTION("netfilter userspace logging");
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index d0e62f68139f..86a4ac33de34 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -1071,17 +1071,13 @@ static struct file_operations nfqnl_file_ops = {
 
 #endif /* PROC_FS */
 
-static int
-init_or_cleanup(int init)
+static int __init nfnetlink_queue_init(void)
 {
 	int i, status = -ENOMEM;
 #ifdef CONFIG_PROC_FS
 	struct proc_dir_entry *proc_nfqueue;
 #endif
 	
-	if (!init)
-		goto cleanup;
-
 	for (i = 0; i < INSTANCE_BUCKETS; i++)
 		INIT_HLIST_HEAD(&instance_table[i]);
 
@@ -1101,31 +1097,26 @@ init_or_cleanup(int init)
 #endif
 
 	register_netdevice_notifier(&nfqnl_dev_notifier);
-
 	return status;
 
-cleanup:
-	nf_unregister_queue_handlers(&nfqh);
-	unregister_netdevice_notifier(&nfqnl_dev_notifier);
 #ifdef CONFIG_PROC_FS
-	remove_proc_entry("nfnetlink_queue", proc_net_netfilter);
 cleanup_subsys:
-#endif	
 	nfnetlink_subsys_unregister(&nfqnl_subsys);
+#endif
 cleanup_netlink_notifier:
 	netlink_unregister_notifier(&nfqnl_rtnl_notifier);
 	return status;
 }
 
-static int __init nfnetlink_queue_init(void)
-{
-	
-	return init_or_cleanup(1);
-}
-
 static void __exit nfnetlink_queue_fini(void)
 {
-	init_or_cleanup(0);
+	nf_unregister_queue_handlers(&nfqh);
+	unregister_netdevice_notifier(&nfqnl_dev_notifier);
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry("nfnetlink_queue", proc_net_netfilter);
+#endif
+	nfnetlink_subsys_unregister(&nfqnl_subsys);
+	netlink_unregister_notifier(&nfqnl_rtnl_notifier);
 }
 
 MODULE_DESCRIPTION("netfilter packet queue handler");

From 48bfee5fad0e46f4f18d46285efceba39e897482 Mon Sep 17 00:00:00 2001
From: Jing Min Zhao <zhaojingmin@users.sourceforge.net>
Date: Thu, 6 Apr 2006 14:13:42 -0700
Subject: [PATCH 15/35] [NETFILTER]: H.323 helper: move some function
 prototypes to ip_conntrack_h323.h

Move prototypes of NAT callbacks to ip_conntrack_h323.h. Because the
use of typedefs as arguments, some header files need to be moved as
well.

Signed-off-by: Jing Min Zhao <zhaojingmin@users.sourceforge.net>
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 .../linux/netfilter_ipv4/ip_conntrack_h323.h  | 52 ++++++++++++++++++
 .../ip_conntrack_helper_h323_asn1.h           |  0
 .../ip_conntrack_helper_h323_types.h          |  0
 net/ipv4/netfilter/ip_conntrack_helper_h323.c |  2 -
 .../netfilter/ip_conntrack_helper_h323_asn1.c |  2 +-
 net/ipv4/netfilter/ip_nat_helper_h323.c       | 53 -------------------
 6 files changed, 53 insertions(+), 56 deletions(-)
 rename {net/ipv4/netfilter => include/linux/netfilter_ipv4}/ip_conntrack_helper_h323_asn1.h (100%)
 rename {net/ipv4/netfilter => include/linux/netfilter_ipv4}/ip_conntrack_helper_h323_types.h (100%)

diff --git a/include/linux/netfilter_ipv4/ip_conntrack_h323.h b/include/linux/netfilter_ipv4/ip_conntrack_h323.h
index 0987cea53840..eace86bd2adb 100644
--- a/include/linux/netfilter_ipv4/ip_conntrack_h323.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack_h323.h
@@ -3,6 +3,8 @@
 
 #ifdef __KERNEL__
 
+#include <linux/netfilter_ipv4/ip_conntrack_helper_h323_asn1.h>
+
 #define RAS_PORT 1719
 #define Q931_PORT 1720
 #define H323_RTP_CHANNEL_MAX 4	/* Audio, video, FAX and other */
@@ -25,6 +27,56 @@ struct ip_ct_h323_master {
 	};
 };
 
+struct ip_conntrack_expect;
+
+extern int get_h225_addr(unsigned char *data, TransportAddress * addr,
+			 u_int32_t * ip, u_int16_t * port);
+extern void ip_conntrack_h245_expect(struct ip_conntrack *new,
+				     struct ip_conntrack_expect *this);
+extern void ip_conntrack_q931_expect(struct ip_conntrack *new,
+				     struct ip_conntrack_expect *this);
+extern int (*set_h245_addr_hook) (struct sk_buff ** pskb,
+				  unsigned char **data, int dataoff,
+				  H245_TransportAddress * addr,
+				  u_int32_t ip, u_int16_t port);
+extern int (*set_h225_addr_hook) (struct sk_buff ** pskb,
+				  unsigned char **data, int dataoff,
+				  TransportAddress * addr,
+				  u_int32_t ip, u_int16_t port);
+extern int (*set_sig_addr_hook) (struct sk_buff ** pskb,
+				 struct ip_conntrack * ct,
+				 enum ip_conntrack_info ctinfo,
+				 unsigned char **data,
+				 TransportAddress * addr, int count);
+extern int (*set_ras_addr_hook) (struct sk_buff ** pskb,
+				 struct ip_conntrack * ct,
+				 enum ip_conntrack_info ctinfo,
+				 unsigned char **data,
+				 TransportAddress * addr, int count);
+extern int (*nat_rtp_rtcp_hook) (struct sk_buff ** pskb,
+				 struct ip_conntrack * ct,
+				 enum ip_conntrack_info ctinfo,
+				 unsigned char **data, int dataoff,
+				 H245_TransportAddress * addr,
+				 u_int16_t port, u_int16_t rtp_port,
+				 struct ip_conntrack_expect * rtp_exp,
+				 struct ip_conntrack_expect * rtcp_exp);
+extern int (*nat_t120_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct,
+			     enum ip_conntrack_info ctinfo,
+			     unsigned char **data, int dataoff,
+			     H245_TransportAddress * addr, u_int16_t port,
+			     struct ip_conntrack_expect * exp);
+extern int (*nat_h245_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct,
+			     enum ip_conntrack_info ctinfo,
+			     unsigned char **data, int dataoff,
+			     TransportAddress * addr, u_int16_t port,
+			     struct ip_conntrack_expect * exp);
+extern int (*nat_q931_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct,
+			     enum ip_conntrack_info ctinfo,
+			     unsigned char **data, TransportAddress * addr,
+			     int idx, u_int16_t port,
+			     struct ip_conntrack_expect * exp);
+
 #endif
 
 #endif
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.h b/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_asn1.h
similarity index 100%
rename from net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.h
rename to include/linux/netfilter_ipv4/ip_conntrack_helper_h323_asn1.h
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323_types.h b/include/linux/netfilter_ipv4/ip_conntrack_helper_h323_types.h
similarity index 100%
rename from net/ipv4/netfilter/ip_conntrack_helper_h323_types.h
rename to include/linux/netfilter_ipv4/ip_conntrack_helper_h323_types.h
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323.c b/net/ipv4/netfilter/ip_conntrack_helper_h323.c
index daeb1395faa4..fc817fd46caa 100644
--- a/net/ipv4/netfilter/ip_conntrack_helper_h323.c
+++ b/net/ipv4/netfilter/ip_conntrack_helper_h323.c
@@ -54,8 +54,6 @@
 #include <linux/netfilter_ipv4/ip_conntrack_h323.h>
 #include <linux/moduleparam.h>
 
-#include "ip_conntrack_helper_h323_asn1.h"
-
 #if 0
 #define DEBUGP printk
 #else
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c b/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c
index afa525129b51..48078002e450 100644
--- a/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c
+++ b/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c
@@ -15,7 +15,7 @@
 #else
 #include <stdio.h>
 #endif
-#include "ip_conntrack_helper_h323_asn1.h"
+#include <linux/netfilter_ipv4/ip_conntrack_helper_h323_asn1.h>
 
 /* Trace Flag */
 #ifndef H323_TRACE
diff --git a/net/ipv4/netfilter/ip_nat_helper_h323.c b/net/ipv4/netfilter/ip_nat_helper_h323.c
index a0bc883928c0..6f19c20b34cf 100644
--- a/net/ipv4/netfilter/ip_nat_helper_h323.c
+++ b/net/ipv4/netfilter/ip_nat_helper_h323.c
@@ -41,65 +41,12 @@
 #include <linux/netfilter_ipv4/ip_conntrack_h323.h>
 #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
 
-#include "ip_conntrack_helper_h323_asn1.h"
-
 #if 0
 #define DEBUGP printk
 #else
 #define DEBUGP(format, args...)
 #endif
 
-extern int get_h245_addr(unsigned char *data, H245_TransportAddress * addr,
-			 u_int32_t * ip, u_int16_t * port);
-extern int get_h225_addr(unsigned char *data, TransportAddress * addr,
-			 u_int32_t * ip, u_int16_t * port);
-extern void ip_conntrack_h245_expect(struct ip_conntrack *new,
-				     struct ip_conntrack_expect *this);
-extern void ip_conntrack_q931_expect(struct ip_conntrack *new,
-				     struct ip_conntrack_expect *this);
-extern int (*set_h245_addr_hook) (struct sk_buff ** pskb,
-				  unsigned char **data, int dataoff,
-				  H245_TransportAddress * addr,
-				  u_int32_t ip, u_int16_t port);
-extern int (*set_h225_addr_hook) (struct sk_buff ** pskb,
-				  unsigned char **data, int dataoff,
-				  TransportAddress * addr,
-				  u_int32_t ip, u_int16_t port);
-extern int (*set_sig_addr_hook) (struct sk_buff ** pskb,
-				 struct ip_conntrack * ct,
-				 enum ip_conntrack_info ctinfo,
-				 unsigned char **data,
-				 TransportAddress * addr, int count);
-extern int (*set_ras_addr_hook) (struct sk_buff ** pskb,
-				 struct ip_conntrack * ct,
-				 enum ip_conntrack_info ctinfo,
-				 unsigned char **data,
-				 TransportAddress * addr, int count);
-extern int (*nat_rtp_rtcp_hook) (struct sk_buff ** pskb,
-				 struct ip_conntrack * ct,
-				 enum ip_conntrack_info ctinfo,
-				 unsigned char **data, int dataoff,
-				 H245_TransportAddress * addr,
-				 u_int16_t port, u_int16_t rtp_port,
-				 struct ip_conntrack_expect * rtp_exp,
-				 struct ip_conntrack_expect * rtcp_exp);
-extern int (*nat_t120_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct,
-			     enum ip_conntrack_info ctinfo,
-			     unsigned char **data, int dataoff,
-			     H245_TransportAddress * addr, u_int16_t port,
-			     struct ip_conntrack_expect * exp);
-extern int (*nat_h245_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct,
-			     enum ip_conntrack_info ctinfo,
-			     unsigned char **data, int dataoff,
-			     TransportAddress * addr, u_int16_t port,
-			     struct ip_conntrack_expect * exp);
-extern int (*nat_q931_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct,
-			     enum ip_conntrack_info ctinfo,
-			     unsigned char **data, TransportAddress * addr,
-			     int idx, u_int16_t port,
-			     struct ip_conntrack_expect * exp);
-
-
 /****************************************************************************/
 static int set_addr(struct sk_buff **pskb,
 		    unsigned char **data, int dataoff,

From 0f249685fde399c01e51a63f2bdfe4a667db083c Mon Sep 17 00:00:00 2001
From: Jing Min Zhao <zhaojingmin@users.sourceforge.net>
Date: Thu, 6 Apr 2006 14:14:11 -0700
Subject: [PATCH 16/35] [NETFILTER]: H.323 helper: change EXPORT_SYMBOL to
 EXPORT_SYMBOL_GPL

Signed-off-by: Jing Min Zhao <zhaojingmin@users.sourceforge.net>
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/ipv4/netfilter/ip_conntrack_helper_h323.c | 23 +++++++++----------
 1 file changed, 11 insertions(+), 12 deletions(-)

diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323.c b/net/ipv4/netfilter/ip_conntrack_helper_h323.c
index fc817fd46caa..83140d2c05f9 100644
--- a/net/ipv4/netfilter/ip_conntrack_helper_h323.c
+++ b/net/ipv4/netfilter/ip_conntrack_helper_h323.c
@@ -1711,18 +1711,17 @@ static int __init init(void)
 module_init(init);
 module_exit(fini);
 
-EXPORT_SYMBOL(get_h245_addr);
-EXPORT_SYMBOL(get_h225_addr);
-EXPORT_SYMBOL(ip_conntrack_h245_expect);
-EXPORT_SYMBOL(ip_conntrack_q931_expect);
-EXPORT_SYMBOL(set_h245_addr_hook);
-EXPORT_SYMBOL(set_h225_addr_hook);
-EXPORT_SYMBOL(set_sig_addr_hook);
-EXPORT_SYMBOL(set_ras_addr_hook);
-EXPORT_SYMBOL(nat_rtp_rtcp_hook);
-EXPORT_SYMBOL(nat_t120_hook);
-EXPORT_SYMBOL(nat_h245_hook);
-EXPORT_SYMBOL(nat_q931_hook);
+EXPORT_SYMBOL_GPL(get_h225_addr);
+EXPORT_SYMBOL_GPL(ip_conntrack_h245_expect);
+EXPORT_SYMBOL_GPL(ip_conntrack_q931_expect);
+EXPORT_SYMBOL_GPL(set_h245_addr_hook);
+EXPORT_SYMBOL_GPL(set_h225_addr_hook);
+EXPORT_SYMBOL_GPL(set_sig_addr_hook);
+EXPORT_SYMBOL_GPL(set_ras_addr_hook);
+EXPORT_SYMBOL_GPL(nat_rtp_rtcp_hook);
+EXPORT_SYMBOL_GPL(nat_t120_hook);
+EXPORT_SYMBOL_GPL(nat_h245_hook);
+EXPORT_SYMBOL_GPL(nat_q931_hook);
 
 MODULE_AUTHOR("Jing Min Zhao <zhaojingmin@users.sourceforge.net>");
 MODULE_DESCRIPTION("H.323 connection tracking helper");

From 51d42f5e4ee43fc98aa0c7a2a104808bb602276f Mon Sep 17 00:00:00 2001
From: Jing Min Zhao <zhaojingmin@users.sourceforge.net>
Date: Thu, 6 Apr 2006 14:14:59 -0700
Subject: [PATCH 17/35] [NETFILTER]: H.323 helper: make get_h245_addr() static

Signed-off-by: Jing Min Zhao <zhaojingmin@users.sourceforge.net>
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/ipv4/netfilter/ip_conntrack_helper_h323.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323.c b/net/ipv4/netfilter/ip_conntrack_helper_h323.c
index 83140d2c05f9..11c652fa3046 100644
--- a/net/ipv4/netfilter/ip_conntrack_helper_h323.c
+++ b/net/ipv4/netfilter/ip_conntrack_helper_h323.c
@@ -220,8 +220,8 @@ static int get_tpkt_data(struct sk_buff **pskb, struct ip_conntrack *ct,
 }
 
 /****************************************************************************/
-int get_h245_addr(unsigned char *data, H245_TransportAddress * addr,
-		  u_int32_t * ip, u_int16_t * port)
+static int get_h245_addr(unsigned char *data, H245_TransportAddress * addr,
+			 u_int32_t * ip, u_int16_t * port)
 {
 	unsigned char *p;
 

From a0b7db5e86d30f470dc1849f4fa44ff77a813091 Mon Sep 17 00:00:00 2001
From: Jing Min Zhao <zhaojingmin@users.sourceforge.net>
Date: Thu, 6 Apr 2006 14:15:33 -0700
Subject: [PATCH 18/35] [NETFILTER]: H.323 helper: add parameter
 'default_rrq_ttl'

default_rrq_ttl is used when no TTL is included in the RRQ.

Signed-off-by: Jing Min Zhao <zhaojingmin@users.sourceforge.net>
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/ipv4/netfilter/ip_conntrack_helper_h323.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323.c b/net/ipv4/netfilter/ip_conntrack_helper_h323.c
index 11c652fa3046..dccc6c301efd 100644
--- a/net/ipv4/netfilter/ip_conntrack_helper_h323.c
+++ b/net/ipv4/netfilter/ip_conntrack_helper_h323.c
@@ -61,6 +61,10 @@
 #endif
 
 /* Parameters */
+static unsigned int default_rrq_ttl = 300;
+module_param(default_rrq_ttl, uint, 0600);
+MODULE_PARM_DESC(default_rrq_ttl, "use this TTL if it's missing in RRQ");
+
 static int gkrouted_only = 1;
 module_param(gkrouted_only, int, 0600);
 MODULE_PARM_DESC(gkrouted_only, "only accept calls from gatekeeper");
@@ -1300,7 +1304,7 @@ static int process_rrq(struct sk_buff **pskb, struct ip_conntrack *ct,
 		DEBUGP("ip_ct_ras: RRQ TTL = %u seconds\n", rrq->timeToLive);
 		info->timeout = rrq->timeToLive;
 	} else
-		info->timeout = 0;
+		info->timeout = default_rrq_ttl;
 
 	return 0;
 }

From a0aed49bdb2bbb4234789f241cffb607fd2e213d Mon Sep 17 00:00:00 2001
From: Patrick McHardy <kaber@trash.net>
Date: Thu, 6 Apr 2006 14:17:27 -0700
Subject: [PATCH 19/35] [NETFILTER]: Fix IP_NF_CONNTRACK_NETLINK dependency

When NAT is built as a module, ip_conntrack_netlink can not be linked
statically.

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/ipv4/netfilter/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 77855ccd6b43..c60fd5c4ea1e 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -69,6 +69,7 @@ config IP_NF_CONNTRACK_NETLINK
 	tristate 'Connection tracking netlink interface (EXPERIMENTAL)'
 	depends on EXPERIMENTAL && IP_NF_CONNTRACK && NETFILTER_NETLINK
 	depends on IP_NF_CONNTRACK!=y || NETFILTER_NETLINK!=m
+	depends on IP_NF_NAT=n || IP_NF_NAT
 	help
 	  This option enables support for a netlink-based userspace interface
 

From bce8032ef3cc58170ab3550e9e271dba7b4c4764 Mon Sep 17 00:00:00 2001
From: Patrick McHardy <kaber@trash.net>
Date: Thu, 6 Apr 2006 14:18:09 -0700
Subject: [PATCH 20/35] [NETFILTER]: Introduce infrastructure for address
 family specific operations

Change the queue rerouter intrastructure to a generic usable
infrastructure for address family specific operations as a base for
some cleanups.

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 include/linux/netfilter.h | 23 ++++++++++++------
 net/ipv4/netfilter.c      | 17 +++++++-------
 net/ipv6/netfilter.c      | 17 +++++++-------
 net/netfilter/core.c      | 23 ++++++++++++++++++
 net/netfilter/nf_queue.c  | 49 +++++++++++----------------------------
 5 files changed, 70 insertions(+), 59 deletions(-)

diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index 5aa931607923..6ee168c4978a 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -283,16 +283,25 @@ extern void nf_invalidate_cache(int pf);
    Returns true or false. */
 extern int skb_make_writable(struct sk_buff **pskb, unsigned int writable_len);
 
-struct nf_queue_rerouter {
-	void (*save)(const struct sk_buff *skb, struct nf_info *info);
-	int (*reroute)(struct sk_buff **skb, const struct nf_info *info);
-	int rer_size;
+struct nf_afinfo {
+	unsigned short	family;
+	void		(*saveroute)(const struct sk_buff *skb,
+				     struct nf_info *info);
+	int		(*reroute)(struct sk_buff **skb,
+				   const struct nf_info *info);
+	int		route_key_size;
 };
 
-#define nf_info_reroute(x) ((void *)x + sizeof(struct nf_info))
+extern struct nf_afinfo *nf_afinfo[];
+static inline struct nf_afinfo *nf_get_afinfo(unsigned short family)
+{
+	return rcu_dereference(nf_afinfo[family]);
+}
 
-extern int nf_register_queue_rerouter(int pf, struct nf_queue_rerouter *rer);
-extern int nf_unregister_queue_rerouter(int pf);
+extern int nf_register_afinfo(struct nf_afinfo *afinfo);
+extern void nf_unregister_afinfo(struct nf_afinfo *afinfo);
+
+#define nf_info_reroute(x) ((void *)x + sizeof(struct nf_info))
 
 #include <net/flow.h>
 extern void (*ip_nat_decode_session)(struct sk_buff *, struct flowi *);
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c
index b5ad9ac2fbcc..b25339c11ea0 100644
--- a/net/ipv4/netfilter.c
+++ b/net/ipv4/netfilter.c
@@ -133,7 +133,7 @@ struct ip_rt_info {
 	u_int8_t tos;
 };
 
-static void queue_save(const struct sk_buff *skb, struct nf_info *info)
+static void nf_ip_saveroute(const struct sk_buff *skb, struct nf_info *info)
 {
 	struct ip_rt_info *rt_info = nf_info_reroute(info);
 
@@ -146,7 +146,7 @@ static void queue_save(const struct sk_buff *skb, struct nf_info *info)
 	}
 }
 
-static int queue_reroute(struct sk_buff **pskb, const struct nf_info *info)
+static int nf_ip_reroute(struct sk_buff **pskb, const struct nf_info *info)
 {
 	const struct ip_rt_info *rt_info = nf_info_reroute(info);
 
@@ -161,20 +161,21 @@ static int queue_reroute(struct sk_buff **pskb, const struct nf_info *info)
 	return 0;
 }
 
-static struct nf_queue_rerouter ip_reroute = {
-	.rer_size	= sizeof(struct ip_rt_info),
-	.save		= queue_save,
-	.reroute	= queue_reroute,
+static struct nf_afinfo nf_ip_afinfo = {
+	.family		= AF_INET,
+	.saveroute	= nf_ip_saveroute,
+	.reroute	= nf_ip_reroute,
+	.route_key_size	= sizeof(struct ip_rt_info),
 };
 
 static int ipv4_netfilter_init(void)
 {
-	return nf_register_queue_rerouter(PF_INET, &ip_reroute);
+	return nf_register_afinfo(&nf_ip_afinfo);
 }
 
 static void ipv4_netfilter_fini(void)
 {
-	nf_unregister_queue_rerouter(PF_INET);
+	nf_unregister_afinfo(&nf_ip_afinfo);
 }
 
 module_init(ipv4_netfilter_init);
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c
index d750cfc019dc..f514a0113b9f 100644
--- a/net/ipv6/netfilter.c
+++ b/net/ipv6/netfilter.c
@@ -54,7 +54,7 @@ struct ip6_rt_info {
 	struct in6_addr saddr;
 };
 
-static void save(const struct sk_buff *skb, struct nf_info *info)
+static void nf_ip6_saveroute(const struct sk_buff *skb, struct nf_info *info)
 {
 	struct ip6_rt_info *rt_info = nf_info_reroute(info);
 
@@ -66,7 +66,7 @@ static void save(const struct sk_buff *skb, struct nf_info *info)
 	}
 }
 
-static int reroute(struct sk_buff **pskb, const struct nf_info *info)
+static int nf_ip6_reroute(struct sk_buff **pskb, const struct nf_info *info)
 {
 	struct ip6_rt_info *rt_info = nf_info_reroute(info);
 
@@ -79,15 +79,16 @@ static int reroute(struct sk_buff **pskb, const struct nf_info *info)
 	return 0;
 }
 
-static struct nf_queue_rerouter ip6_reroute = {
-	.rer_size	= sizeof(struct ip6_rt_info),
-	.save 		= &save,
-	.reroute	= &reroute,
+static struct nf_afinfo nf_ip6_afinfo = {
+	.family		= AF_INET6,
+	.saveroute	= nf_ip6_saveroute,
+	.reroute	= nf_ip6_reroute,
+	.route_key_size	= sizeof(struct ip6_rt_info),
 };
 
 int __init ipv6_netfilter_init(void)
 {
-	return nf_register_queue_rerouter(PF_INET6, &ip6_reroute);
+	return nf_register_afinfo(&nf_ip6_afinfo);
 }
 
 /* This can be called from inet6_init() on errors, so it cannot
@@ -95,5 +96,5 @@ int __init ipv6_netfilter_init(void)
  */
 void ipv6_netfilter_fini(void)
 {
-	nf_unregister_queue_rerouter(PF_INET6);
+	nf_unregister_afinfo(&nf_ip6_afinfo);
 }
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index 645d62105571..8455a32ea5c4 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -27,6 +27,29 @@
 
 #include "nf_internals.h"
 
+static DEFINE_SPINLOCK(afinfo_lock);
+
+struct nf_afinfo *nf_afinfo[NPROTO];
+EXPORT_SYMBOL(nf_afinfo);
+
+int nf_register_afinfo(struct nf_afinfo *afinfo)
+{
+	spin_lock(&afinfo_lock);
+	rcu_assign_pointer(nf_afinfo[afinfo->family], afinfo);
+	spin_unlock(&afinfo_lock);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nf_register_afinfo);
+
+void nf_unregister_afinfo(struct nf_afinfo *afinfo)
+{
+	spin_lock(&afinfo_lock);
+	rcu_assign_pointer(nf_afinfo[afinfo->family], NULL);
+	spin_unlock(&afinfo_lock);
+	synchronize_rcu();
+}
+EXPORT_SYMBOL_GPL(nf_unregister_afinfo);
+
 /* In this code, we can be waiting indefinitely for userspace to
  * service a packet if a hook returns NF_QUEUE.  We could keep a count
  * of skbuffs queued for userspace, and not deregister a hook unless
diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c
index d9f0d7ef103b..ee8f70889f47 100644
--- a/net/netfilter/nf_queue.c
+++ b/net/netfilter/nf_queue.c
@@ -17,7 +17,6 @@
  * for queueing and must reinject all packets it receives, no matter what.
  */
 static struct nf_queue_handler *queue_handler[NPROTO];
-static struct nf_queue_rerouter *queue_rerouter[NPROTO];
 
 static DEFINE_RWLOCK(queue_handler_lock);
 
@@ -59,32 +58,6 @@ int nf_unregister_queue_handler(int pf)
 }
 EXPORT_SYMBOL(nf_unregister_queue_handler);
 
-int nf_register_queue_rerouter(int pf, struct nf_queue_rerouter *rer)
-{
-	if (pf >= NPROTO)
-		return -EINVAL;
-
-	write_lock_bh(&queue_handler_lock);
-	rcu_assign_pointer(queue_rerouter[pf], rer);
-	write_unlock_bh(&queue_handler_lock);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(nf_register_queue_rerouter);
-
-int nf_unregister_queue_rerouter(int pf)
-{
-	if (pf >= NPROTO)
-		return -EINVAL;
-
-	write_lock_bh(&queue_handler_lock);
-	rcu_assign_pointer(queue_rerouter[pf], NULL);
-	write_unlock_bh(&queue_handler_lock);
-	synchronize_rcu();
-	return 0;
-}
-EXPORT_SYMBOL_GPL(nf_unregister_queue_rerouter);
-
 void nf_unregister_queue_handlers(struct nf_queue_handler *qh)
 {
 	int pf;
@@ -116,7 +89,7 @@ int nf_queue(struct sk_buff **skb,
 	struct net_device *physindev = NULL;
 	struct net_device *physoutdev = NULL;
 #endif
-	struct nf_queue_rerouter *rerouter;
+	struct nf_afinfo *afinfo;
 
 	/* QUEUE == DROP if noone is waiting, to be safe. */
 	read_lock(&queue_handler_lock);
@@ -126,7 +99,14 @@ int nf_queue(struct sk_buff **skb,
 		return 1;
 	}
 
-	info = kmalloc(sizeof(*info)+queue_rerouter[pf]->rer_size, GFP_ATOMIC);
+	afinfo = nf_get_afinfo(pf);
+	if (!afinfo) {
+		read_unlock(&queue_handler_lock);
+		kfree_skb(*skb);
+		return 1;
+	}
+
+	info = kmalloc(sizeof(*info) + afinfo->route_key_size, GFP_ATOMIC);
 	if (!info) {
 		if (net_ratelimit())
 			printk(KERN_ERR "OOM queueing packet %p\n",
@@ -158,10 +138,7 @@ int nf_queue(struct sk_buff **skb,
 		if (physoutdev) dev_hold(physoutdev);
 	}
 #endif
-	rerouter = rcu_dereference(queue_rerouter[pf]);
-	if (rerouter)
-		rerouter->save(*skb, info);
-
+	afinfo->saveroute(*skb, info);
 	status = queue_handler[pf]->outfn(*skb, info, queuenum,
 					  queue_handler[pf]->data);
 
@@ -190,7 +167,7 @@ void nf_reinject(struct sk_buff *skb, struct nf_info *info,
 {
 	struct list_head *elem = &info->elem->list;
 	struct list_head *i;
-	struct nf_queue_rerouter *rerouter;
+	struct nf_afinfo *afinfo;
 
 	rcu_read_lock();
 
@@ -228,8 +205,8 @@ void nf_reinject(struct sk_buff *skb, struct nf_info *info,
 	}
 
 	if (verdict == NF_ACCEPT) {
-		rerouter = rcu_dereference(queue_rerouter[info->pf]);
-		if (rerouter && rerouter->reroute(&skb, info) < 0)
+		afinfo = nf_get_afinfo(info->pf);
+		if (!afinfo || afinfo->reroute(&skb, info) < 0)
 			verdict = NF_DROP;
 	}
 

From 422c346fad806e2abaeffac686860ebc98dfe33e Mon Sep 17 00:00:00 2001
From: Patrick McHardy <kaber@trash.net>
Date: Thu, 6 Apr 2006 14:18:43 -0700
Subject: [PATCH 21/35] [NETFILTER]: Add address family specific checksum
 helpers

Add checksum operation which takes care of verifying the checksum and
dealing with HW checksum errors and avoids multiple checksum
operations by setting ip_summed to CHECKSUM_UNNECESSARY after
successful verification.

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 include/linux/netfilter.h      | 17 +++++++++++++++++
 include/linux/netfilter_ipv4.h |  2 ++
 include/linux/netfilter_ipv6.h |  3 +++
 net/ipv4/netfilter.c           | 33 +++++++++++++++++++++++++++++++++
 net/ipv6/netfilter.c           | 34 ++++++++++++++++++++++++++++++++++
 5 files changed, 89 insertions(+)

diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index 6ee168c4978a..b31a9bca9361 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -285,6 +285,8 @@ extern int skb_make_writable(struct sk_buff **pskb, unsigned int writable_len);
 
 struct nf_afinfo {
 	unsigned short	family;
+	unsigned int	(*checksum)(struct sk_buff *skb, unsigned int hook,
+				    unsigned int dataoff, u_int8_t protocol);
 	void		(*saveroute)(const struct sk_buff *skb,
 				     struct nf_info *info);
 	int		(*reroute)(struct sk_buff **skb,
@@ -298,6 +300,21 @@ static inline struct nf_afinfo *nf_get_afinfo(unsigned short family)
 	return rcu_dereference(nf_afinfo[family]);
 }
 
+static inline unsigned int
+nf_checksum(struct sk_buff *skb, unsigned int hook, unsigned int dataoff,
+	    u_int8_t protocol, unsigned short family)
+{
+	struct nf_afinfo *afinfo;
+	unsigned int csum = 0;
+
+	rcu_read_lock();
+	afinfo = nf_get_afinfo(family);
+	if (afinfo)
+		csum = afinfo->checksum(skb, hook, dataoff, protocol);
+	rcu_read_unlock();
+	return csum;
+}
+
 extern int nf_register_afinfo(struct nf_afinfo *afinfo);
 extern void nf_unregister_afinfo(struct nf_afinfo *afinfo);
 
diff --git a/include/linux/netfilter_ipv4.h b/include/linux/netfilter_ipv4.h
index 43c09d790b83..85301c5e8d24 100644
--- a/include/linux/netfilter_ipv4.h
+++ b/include/linux/netfilter_ipv4.h
@@ -80,6 +80,8 @@ enum nf_ip_hook_priorities {
 #ifdef __KERNEL__
 extern int ip_route_me_harder(struct sk_buff **pskb);
 extern int ip_xfrm_me_harder(struct sk_buff **pskb);
+extern unsigned int nf_ip_checksum(struct sk_buff *skb, unsigned int hook,
+				   unsigned int dataoff, u_int8_t protocol);
 #endif /*__KERNEL__*/
 
 #endif /*__LINUX_IP_NETFILTER_H*/
diff --git a/include/linux/netfilter_ipv6.h b/include/linux/netfilter_ipv6.h
index 14f2bd010884..52a7b9e76428 100644
--- a/include/linux/netfilter_ipv6.h
+++ b/include/linux/netfilter_ipv6.h
@@ -73,6 +73,9 @@ enum nf_ip6_hook_priorities {
 };
 
 #ifdef CONFIG_NETFILTER
+extern unsigned int nf_ip6_checksum(struct sk_buff *skb, unsigned int hook,
+				    unsigned int dataoff, u_int8_t protocol);
+
 extern int ipv6_netfilter_init(void);
 extern void ipv6_netfilter_fini(void);
 #else /* CONFIG_NETFILTER */
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c
index b25339c11ea0..6a9e34b794bc 100644
--- a/net/ipv4/netfilter.c
+++ b/net/ipv4/netfilter.c
@@ -161,8 +161,41 @@ static int nf_ip_reroute(struct sk_buff **pskb, const struct nf_info *info)
 	return 0;
 }
 
+unsigned int nf_ip_checksum(struct sk_buff *skb, unsigned int hook,
+			    unsigned int dataoff, u_int8_t protocol)
+{
+	struct iphdr *iph = skb->nh.iph;
+	unsigned int csum = 0;
+
+	switch (skb->ip_summed) {
+	case CHECKSUM_HW:
+		if (hook != NF_IP_PRE_ROUTING && hook != NF_IP_LOCAL_IN)
+			break;
+		if ((protocol == 0 && !(u16)csum_fold(skb->csum)) ||
+		    !csum_tcpudp_magic(iph->saddr, iph->daddr,
+			    	       skb->len - dataoff, protocol,
+				       skb->csum)) {
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
+			break;
+		}
+		/* fall through */
+	case CHECKSUM_NONE:
+		if (protocol == 0)
+			skb->csum = 0;
+		else
+			skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr,
+						       skb->len - dataoff,
+						       protocol, 0);
+		csum = __skb_checksum_complete(skb);
+	}
+	return csum;
+}
+
+EXPORT_SYMBOL(nf_ip_checksum);
+
 static struct nf_afinfo nf_ip_afinfo = {
 	.family		= AF_INET,
+	.checksum	= nf_ip_checksum,
 	.saveroute	= nf_ip_saveroute,
 	.reroute	= nf_ip_reroute,
 	.route_key_size	= sizeof(struct ip_rt_info),
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c
index f514a0113b9f..3e9ecfaf67e2 100644
--- a/net/ipv6/netfilter.c
+++ b/net/ipv6/netfilter.c
@@ -79,8 +79,42 @@ static int nf_ip6_reroute(struct sk_buff **pskb, const struct nf_info *info)
 	return 0;
 }
 
+unsigned int nf_ip6_checksum(struct sk_buff *skb, unsigned int hook,
+			     unsigned int dataoff, u_int8_t protocol)
+{
+	struct ipv6hdr *ip6h = skb->nh.ipv6h;
+	unsigned int csum = 0;
+
+	switch (skb->ip_summed) {
+	case CHECKSUM_HW:
+		if (hook != NF_IP6_PRE_ROUTING && hook != NF_IP6_LOCAL_IN)
+			break;
+		if (!csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
+			    	     skb->len - dataoff, protocol,
+				     csum_sub(skb->csum,
+					      skb_checksum(skb, 0,
+							   dataoff, 0)))) {
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
+			break;
+		}
+		/* fall through */
+	case CHECKSUM_NONE:
+		skb->csum = ~csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
+					     skb->len - dataoff,
+					     protocol,
+					     csum_sub(0,
+						      skb_checksum(skb, 0,
+							           dataoff, 0)));
+		csum = __skb_checksum_complete(skb);
+	}
+	return csum;
+}
+
+EXPORT_SYMBOL(nf_ip6_checksum);
+
 static struct nf_afinfo nf_ip6_afinfo = {
 	.family		= AF_INET6,
+	.checksum	= nf_ip6_checksum,
 	.saveroute	= nf_ip6_saveroute,
 	.reroute	= nf_ip6_reroute,
 	.route_key_size	= sizeof(struct ip6_rt_info),

From 96f6bf82ea3abc77d255d5d554df5f349651f6de Mon Sep 17 00:00:00 2001
From: Patrick McHardy <kaber@trash.net>
Date: Thu, 6 Apr 2006 14:19:24 -0700
Subject: [PATCH 22/35] [NETFILTER]: Convert conntrack/ipt_REJECT to new
 checksumming functions

Besides removing lots of duplicate code, all converted users benefit
from improved HW checksum error handling. Tested with and without HW
checksums in almost all combinations.

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/ipv4/netfilter/ip_conntrack_proto_icmp.c  | 23 +++------
 net/ipv4/netfilter/ip_conntrack_proto_tcp.c   |  7 +--
 net/ipv4/netfilter/ip_conntrack_proto_udp.c   |  7 +--
 net/ipv4/netfilter/ipt_REJECT.c               |  9 +---
 net/ipv4/netfilter/nf_conntrack_proto_icmp.c  | 20 +-------
 .../netfilter/nf_conntrack_proto_icmpv6.c     | 12 +----
 net/netfilter/nf_conntrack_proto_tcp.c        | 50 ++-----------------
 net/netfilter/nf_conntrack_proto_udp.c        | 50 ++-----------------
 8 files changed, 25 insertions(+), 153 deletions(-)

diff --git a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
index 3021af0910f1..d8b14a9010a6 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
@@ -224,25 +224,14 @@ icmp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo,
 	}
 
 	/* See ip_conntrack_proto_tcp.c */
-	if (hooknum != NF_IP_PRE_ROUTING)
-		goto checksum_skipped;
-
-	switch (skb->ip_summed) {
-	case CHECKSUM_HW:
-		if (!(u16)csum_fold(skb->csum)) 
-			break;
-		/* fall through */
-	case CHECKSUM_NONE:
-		skb->csum = 0;
-		if (__skb_checksum_complete(skb)) {
-			if (LOG_INVALID(IPPROTO_ICMP))
-				nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
-					      "ip_ct_icmp: bad ICMP checksum ");
-			return -NF_ACCEPT;
-		}
+	if (hooknum == NF_IP_PRE_ROUTING &&
+	    nf_ip_checksum(skb, hooknum, skb->nh.iph->ihl * 4, 0)) {
+		if (LOG_INVALID(IPPROTO_ICMP))
+			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
+				      "ip_ct_icmp: bad ICMP checksum ");
+		return -NF_ACCEPT;
 	}
 
-checksum_skipped:
 	/*
 	 *	18 is the highest 'known' ICMP type. Anything else is a mystery
 	 *
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
index e0dc37063545..062b252b58ad 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
@@ -870,11 +870,8 @@ static int tcp_error(struct sk_buff *skb,
 	 * and moreover root might send raw packets.
 	 */
 	/* FIXME: Source route IP option packets --RR */
-	if (hooknum == NF_IP_PRE_ROUTING
-	    && skb->ip_summed != CHECKSUM_UNNECESSARY
-	    && csum_tcpudp_magic(iph->saddr, iph->daddr, tcplen, IPPROTO_TCP,
-			         skb->ip_summed == CHECKSUM_HW ? skb->csum
-			      	 : skb_checksum(skb, iph->ihl*4, tcplen, 0))) {
+	if (hooknum == NF_IP_PRE_ROUTING &&
+	    nf_ip_checksum(skb, hooknum, iph->ihl * 4, IPPROTO_TCP)) {
 		if (LOG_INVALID(IPPROTO_TCP))
 			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
 				  "ip_ct_tcp: bad TCP checksum ");
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_udp.c b/net/ipv4/netfilter/ip_conntrack_proto_udp.c
index 55b7d3210adf..70899868783b 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_udp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_udp.c
@@ -120,11 +120,8 @@ static int udp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo,
 	 * because the semantic of CHECKSUM_HW is different there 
 	 * and moreover root might send raw packets.
 	 * FIXME: Source route IP option packets --RR */
-	if (hooknum == NF_IP_PRE_ROUTING
-	    && skb->ip_summed != CHECKSUM_UNNECESSARY
-	    && csum_tcpudp_magic(iph->saddr, iph->daddr, udplen, IPPROTO_UDP,
-			         skb->ip_summed == CHECKSUM_HW ? skb->csum
-			      	 : skb_checksum(skb, iph->ihl*4, udplen, 0))) {
+	if (hooknum == NF_IP_PRE_ROUTING &&
+	    nf_ip_checksum(skb, hooknum, iph->ihl * 4, IPPROTO_UDP)) {
 		if (LOG_INVALID(IPPROTO_UDP))
 			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
 				  "ip_ct_udp: bad UDP checksum ");
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c
index 4269a5440d43..0bba3c2bb786 100644
--- a/net/ipv4/netfilter/ipt_REJECT.c
+++ b/net/ipv4/netfilter/ipt_REJECT.c
@@ -106,7 +106,6 @@ static void send_reset(struct sk_buff *oldskb, int hook)
 	struct rtable *rt;
 	u_int16_t tmp_port;
 	u_int32_t tmp_addr;
-	unsigned int tcplen;
 	int needs_ack;
 	int hh_len;
 
@@ -124,13 +123,7 @@ static void send_reset(struct sk_buff *oldskb, int hook)
 		return;
 
 	/* Check checksum */
-	tcplen = oldskb->len - iph->ihl * 4;
-	if (((hook != NF_IP_LOCAL_IN && oldskb->ip_summed != CHECKSUM_HW) ||
-	     (hook == NF_IP_LOCAL_IN &&
-	      oldskb->ip_summed != CHECKSUM_UNNECESSARY)) &&
-	    csum_tcpudp_magic(iph->saddr, iph->daddr, tcplen, IPPROTO_TCP,
-	                      oldskb->ip_summed == CHECKSUM_HW ? oldskb->csum :
-	                      skb_checksum(oldskb, iph->ihl * 4, tcplen, 0)))
+	if (nf_ip_checksum(oldskb, hook, iph->ihl * 4, IPPROTO_TCP))
 		return;
 
 	if ((rt = route_reverse(oldskb, oth, hook)) == NULL)
diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
index 52dc175be39a..4b0d361cc6e6 100644
--- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
+++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
@@ -235,30 +235,14 @@ icmp_error(struct sk_buff *skb, unsigned int dataoff,
 	}
 
 	/* See ip_conntrack_proto_tcp.c */
-	if (hooknum != NF_IP_PRE_ROUTING)
-		goto checksum_skipped;
-
-	switch (skb->ip_summed) {
-	case CHECKSUM_HW:
-		if (!(u16)csum_fold(skb->csum))
-			break;
+	if (hooknum == NF_IP_PRE_ROUTING &&
+	    nf_ip_checksum(skb, hooknum, dataoff, 0)) {
 		if (LOG_INVALID(IPPROTO_ICMP))
 			nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
 				      "nf_ct_icmp: bad HW ICMP checksum ");
 		return -NF_ACCEPT;
-	case CHECKSUM_NONE:
-		if ((u16)csum_fold(skb_checksum(skb, 0, skb->len, 0))) {
-			if (LOG_INVALID(IPPROTO_ICMP))
-				nf_log_packet(PF_INET, 0, skb, NULL, NULL,
-					      NULL,
-					      "nf_ct_icmp: bad ICMP checksum ");
-			return -NF_ACCEPT;
-		}
-	default:
-		break;
 	}
 
-checksum_skipped:
 	/*
 	 *	18 is the highest 'known' ICMP type. Anything else is a mystery
 	 *
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
index 09945c333055..86c6703265d0 100644
--- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
@@ -233,21 +233,13 @@ icmpv6_error(struct sk_buff *skb, unsigned int dataoff,
 		return -NF_ACCEPT;
 	}
 
-	if (hooknum != NF_IP6_PRE_ROUTING)
-		goto skipped;
-
-	/* Ignore it if the checksum's bogus. */
-	if (csum_ipv6_magic(&skb->nh.ipv6h->saddr, &skb->nh.ipv6h->daddr,
-			    skb->len - dataoff, IPPROTO_ICMPV6,
-			    skb_checksum(skb, dataoff,
-					 skb->len - dataoff, 0))) {
+	if (hooknum == NF_IP6_PRE_ROUTING &&
+	    nf_ip6_checksum(skb, hooknum, dataoff, IPPROTO_ICMPV6)) {
 		nf_log_packet(PF_INET6, 0, skb, NULL, NULL, NULL,
 			      "nf_ct_icmpv6: ICMPv6 checksum failed\n");
 		return -NF_ACCEPT;
 	}
 
-skipped:
-
 	/* is not error message ? */
 	if (icmp6h->icmp6_type >= 128)
 		return NF_ACCEPT;
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index 6492ed66fb3c..69899f27d26a 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -799,8 +799,7 @@ static int tcp_error(struct sk_buff *skb,
 		     unsigned int dataoff,
 		     enum ip_conntrack_info *ctinfo,
 		     int pf,
-		     unsigned int hooknum,
-		     int(*csum)(const struct sk_buff *,unsigned int))
+		     unsigned int hooknum)
 {
 	struct tcphdr _tcph, *th;
 	unsigned int tcplen = skb->len - dataoff;
@@ -830,9 +829,8 @@ static int tcp_error(struct sk_buff *skb,
 	 */
 	/* FIXME: Source route IP option packets --RR */
 	if (((pf == PF_INET && hooknum == NF_IP_PRE_ROUTING) ||
-	     (pf == PF_INET6 && hooknum  == NF_IP6_PRE_ROUTING))
-	    && skb->ip_summed != CHECKSUM_UNNECESSARY
-	    && csum(skb, dataoff)) {
+	     (pf == PF_INET6 && hooknum  == NF_IP6_PRE_ROUTING)) &&
+	    nf_checksum(skb, hooknum, dataoff, IPPROTO_TCP, pf)) {
 		if (LOG_INVALID(IPPROTO_TCP))
 			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
 				  "nf_ct_tcp: bad TCP checksum ");
@@ -851,44 +849,6 @@ static int tcp_error(struct sk_buff *skb,
 	return NF_ACCEPT;
 }
 
-static int csum4(const struct sk_buff *skb, unsigned int dataoff)
-{
-	return csum_tcpudp_magic(skb->nh.iph->saddr, skb->nh.iph->daddr,
-				 skb->len - dataoff, IPPROTO_TCP,
-			         skb->ip_summed == CHECKSUM_HW ? skb->csum
-			      	 : skb_checksum(skb, dataoff,
-						skb->len - dataoff, 0));
-}
-
-static int csum6(const struct sk_buff *skb, unsigned int dataoff)
-{
-	return csum_ipv6_magic(&skb->nh.ipv6h->saddr, &skb->nh.ipv6h->daddr,
-			       skb->len - dataoff, IPPROTO_TCP,
-			       skb->ip_summed == CHECKSUM_HW
-			       ? csum_sub(skb->csum,
-					  skb_checksum(skb, 0, dataoff, 0))
-			       : skb_checksum(skb, dataoff, skb->len - dataoff,
-					      0));
-}
-
-static int tcp_error4(struct sk_buff *skb,
-		      unsigned int dataoff,
-		      enum ip_conntrack_info *ctinfo,
-		      int pf,
-		      unsigned int hooknum)
-{
-	return tcp_error(skb, dataoff, ctinfo, pf, hooknum, csum4);
-}
-
-static int tcp_error6(struct sk_buff *skb,
-		      unsigned int dataoff,
-		      enum ip_conntrack_info *ctinfo,
-		      int pf,
-		      unsigned int hooknum)
-{
-	return tcp_error(skb, dataoff, ctinfo, pf, hooknum, csum6);
-}
-
 /* Returns verdict for packet, or -1 for invalid. */
 static int tcp_packet(struct nf_conn *conntrack,
 		      const struct sk_buff *skb,
@@ -1218,7 +1178,7 @@ struct nf_conntrack_protocol nf_conntrack_protocol_tcp4 =
 	.print_conntrack 	= tcp_print_conntrack,
 	.packet 		= tcp_packet,
 	.new 			= tcp_new,
-	.error			= tcp_error4,
+	.error			= tcp_error,
 #if defined(CONFIG_NF_CT_NETLINK) || \
     defined(CONFIG_NF_CT_NETLINK_MODULE)
 	.to_nfattr		= tcp_to_nfattr,
@@ -1239,7 +1199,7 @@ struct nf_conntrack_protocol nf_conntrack_protocol_tcp6 =
 	.print_conntrack 	= tcp_print_conntrack,
 	.packet 		= tcp_packet,
 	.new 			= tcp_new,
-	.error			= tcp_error6,
+	.error			= tcp_error,
 #if defined(CONFIG_NF_CT_NETLINK) || \
     defined(CONFIG_NF_CT_NETLINK_MODULE)
 	.to_nfattr		= tcp_to_nfattr,
diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c
index 831d206344e0..d93edbfde9e3 100644
--- a/net/netfilter/nf_conntrack_proto_udp.c
+++ b/net/netfilter/nf_conntrack_proto_udp.c
@@ -103,8 +103,7 @@ static int udp_new(struct nf_conn *conntrack, const struct sk_buff *skb,
 static int udp_error(struct sk_buff *skb, unsigned int dataoff,
 		     enum ip_conntrack_info *ctinfo,
 		     int pf,
-		     unsigned int hooknum,
-		     int (*csum)(const struct sk_buff *, unsigned int))
+		     unsigned int hooknum)
 {
 	unsigned int udplen = skb->len - dataoff;
 	struct udphdr _hdr, *hdr;
@@ -136,9 +135,8 @@ static int udp_error(struct sk_buff *skb, unsigned int dataoff,
 	 * and moreover root might send raw packets.
 	 * FIXME: Source route IP option packets --RR */
 	if (((pf == PF_INET && hooknum == NF_IP_PRE_ROUTING) ||
-	     (pf == PF_INET6 && hooknum == NF_IP6_PRE_ROUTING))
-	    && skb->ip_summed != CHECKSUM_UNNECESSARY
-	    && csum(skb, dataoff)) {
+	     (pf == PF_INET6 && hooknum == NF_IP6_PRE_ROUTING)) &&
+	    nf_checksum(skb, hooknum, dataoff, IPPROTO_UDP, pf)) {
 		if (LOG_INVALID(IPPROTO_UDP))
 			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
 				"nf_ct_udp: bad UDP checksum ");
@@ -148,44 +146,6 @@ static int udp_error(struct sk_buff *skb, unsigned int dataoff,
 	return NF_ACCEPT;
 }
 
-static int csum4(const struct sk_buff *skb, unsigned int dataoff)
-{
-	return csum_tcpudp_magic(skb->nh.iph->saddr, skb->nh.iph->daddr,
-				 skb->len - dataoff, IPPROTO_UDP,
-				 skb->ip_summed == CHECKSUM_HW ? skb->csum
-				 : skb_checksum(skb, dataoff,
-						skb->len - dataoff, 0));
-}
-
-static int csum6(const struct sk_buff *skb, unsigned int dataoff)
-{
-	return csum_ipv6_magic(&skb->nh.ipv6h->saddr, &skb->nh.ipv6h->daddr,
-			       skb->len - dataoff, IPPROTO_UDP,
-			       skb->ip_summed == CHECKSUM_HW
-			       ? csum_sub(skb->csum,
-					  skb_checksum(skb, 0, dataoff, 0))
-			       : skb_checksum(skb, dataoff, skb->len - dataoff,
-					      0));
-}
-
-static int udp_error4(struct sk_buff *skb,
-		      unsigned int dataoff,
-		      enum ip_conntrack_info *ctinfo,
-		      int pf,
-		      unsigned int hooknum)
-{
-	return udp_error(skb, dataoff, ctinfo, pf, hooknum, csum4);
-}
-
-static int udp_error6(struct sk_buff *skb,
-		      unsigned int dataoff,
-		      enum ip_conntrack_info *ctinfo,
-		      int pf,
-		      unsigned int hooknum)
-{
-	return udp_error(skb, dataoff, ctinfo, pf, hooknum, csum6);
-}
-
 struct nf_conntrack_protocol nf_conntrack_protocol_udp4 =
 {
 	.l3proto		= PF_INET,
@@ -197,7 +157,7 @@ struct nf_conntrack_protocol nf_conntrack_protocol_udp4 =
 	.print_conntrack	= udp_print_conntrack,
 	.packet			= udp_packet,
 	.new			= udp_new,
-	.error			= udp_error4,
+	.error			= udp_error,
 #if defined(CONFIG_NF_CT_NETLINK) || \
     defined(CONFIG_NF_CT_NETLINK_MODULE)
 	.tuple_to_nfattr	= nf_ct_port_tuple_to_nfattr,
@@ -216,7 +176,7 @@ struct nf_conntrack_protocol nf_conntrack_protocol_udp6 =
 	.print_conntrack	= udp_print_conntrack,
 	.packet			= udp_packet,
 	.new			= udp_new,
-	.error			= udp_error6,
+	.error			= udp_error,
 #if defined(CONFIG_NF_CT_NETLINK) || \
     defined(CONFIG_NF_CT_NETLINK_MODULE)
 	.tuple_to_nfattr	= nf_ct_port_tuple_to_nfattr,

From 7a43c9955178f1cc88374abe1186c0f2ef21e040 Mon Sep 17 00:00:00 2001
From: Patrick McHardy <kaber@trash.net>
Date: Thu, 6 Apr 2006 16:16:51 -0700
Subject: [PATCH 23/35] [NETFILTER]: H.323 helper: remove changelog

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/ipv4/netfilter/ip_conntrack_helper_h323.c | 31 -------------------
 net/ipv4/netfilter/ip_nat_helper_h323.c       | 18 -----------
 2 files changed, 49 deletions(-)

diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323.c b/net/ipv4/netfilter/ip_conntrack_helper_h323.c
index dccc6c301efd..2c2fb700d835 100644
--- a/net/ipv4/netfilter/ip_conntrack_helper_h323.c
+++ b/net/ipv4/netfilter/ip_conntrack_helper_h323.c
@@ -9,37 +9,6 @@
  * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
  *
  * For more information, please see http://nath323.sourceforge.net/
- *
- * Changes:
- * 	2006-02-01 - initial version 0.1
- *
- *	2006-02-20 - version 0.2
- *	  1. Changed source format to follow kernel conventions
- *	  2. Deleted some unnecessary structures
- *	  3. Minor fixes
- *
- * 	2006-03-10 - version 0.3
- * 	  1. Added support for multiple TPKTs in one packet (suggested by
- * 	     Patrick McHardy)
- * 	  2. Avoid excessive stack usage (based on Patrick McHardy's patch)
- * 	  3. Added support for non-linear skb (based on Patrick McHardy's patch)
- * 	  4. Fixed missing H.245 module owner (Patrick McHardy)
- * 	  5. Avoid long RAS expectation chains (Patrick McHardy)
- * 	  6. Fixed incorrect __exit attribute (Patrick McHardy)
- * 	  7. Eliminated unnecessary return code
- * 	  8. Fixed incorrect use of NAT data from conntrack code (suggested by
- * 	     Patrick McHardy)
- * 	  9. Fixed TTL calculation error in RCF
- * 	  10. Added TTL support in RRQ
- * 	  11. Better support for separate TPKT header and data
- *
- * 	2006-03-15 - version 0.4
- * 	  1. Added support for T.120 channels
- * 	  2. Added parameter gkrouted_only (suggested by Patrick McHardy)
- * 	  3. Splitted ASN.1 code and data (suggested by Patrick McHardy)
- * 	  4. Sort ASN.1 data to avoid forwarding declarations (suggested by
- * 	     Patrick McHardy)
- * 	  5. Reset next TPKT data length in get_tpkt_data()
  */
 
 #include <linux/config.h>
diff --git a/net/ipv4/netfilter/ip_nat_helper_h323.c b/net/ipv4/netfilter/ip_nat_helper_h323.c
index 6f19c20b34cf..d45663d137a7 100644
--- a/net/ipv4/netfilter/ip_nat_helper_h323.c
+++ b/net/ipv4/netfilter/ip_nat_helper_h323.c
@@ -7,24 +7,6 @@
  *
  * Based on the 'brute force' H.323 NAT module by
  * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
- *
- * Changes:
- *	2006-02-01 - initial version 0.1
- *
- *	2006-02-20 - version 0.2
- *	  1. Changed source format to follow kernel conventions
- *	  2. Deleted some unnecessary structures
- *	  3. Minor fixes
- *
- * 	2006-03-10 - version 0.3
- * 	  1. Added support for multiple TPKTs in one packet (suggested by
- * 	     Patrick McHardy)
- * 	  2. Added support for non-linear skb (based on Patrick McHardy's patch)
- * 	  3. Eliminated unnecessary return code
- *
- * 	2006-03-15 - version 0.4
- * 	  1. Added support for T.120 channels
- * 	  2. Added parameter gkrouted_only (suggested by Patrick McHardy)
  */
 
 #include <linux/module.h>

From d2d746f83b74022a50d28f7f0f496842c9cde330 Mon Sep 17 00:00:00 2001
From: Michael Chan <mchan@broadcom.com>
Date: Thu, 6 Apr 2006 21:45:39 -0700
Subject: [PATCH 24/35] [TG3]: Kill some less useful flags

Kill the TG3_FLAG_NO_{TX|RX}_PSEUDO_CSUM flags because they are not
very useful. This will free up some bits for new flags.

Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 drivers/net/tg3.c | 21 ++++++++-------------
 drivers/net/tg3.h |  2 --
 2 files changed, 8 insertions(+), 15 deletions(-)

diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index d6047bd6805d..376d8e776936 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -5828,10 +5828,14 @@ static int tg3_reset_hw(struct tg3 *tp)
 			  GRC_MODE_NO_TX_PHDR_CSUM |
 			  GRC_MODE_NO_RX_PHDR_CSUM);
 	tp->grc_mode |= GRC_MODE_HOST_SENDBDS;
-	if (tp->tg3_flags & TG3_FLAG_NO_TX_PSEUDO_CSUM)
-		tp->grc_mode |= GRC_MODE_NO_TX_PHDR_CSUM;
-	if (tp->tg3_flags & TG3_FLAG_NO_RX_PSEUDO_CSUM)
-		tp->grc_mode |= GRC_MODE_NO_RX_PHDR_CSUM;
+
+	/* Pseudo-header checksum is done by hardware logic and not
+	 * the offload processers, so make the chip do the pseudo-
+	 * header checksums on receive.  For transmit it is more
+	 * convenient to do the pseudo-header checksum in software
+	 * as Linux does that on transmit for us in all cases.
+	 */
+	tp->grc_mode |= GRC_MODE_NO_TX_PHDR_CSUM;
 
 	tw32(GRC_MODE,
 	     tp->grc_mode |
@@ -10303,15 +10307,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
 	if (tp->pci_chip_rev_id == CHIPREV_ID_5700_B0)
 		tp->tg3_flags |= TG3_FLAG_BROKEN_CHECKSUMS;
 
-	/* Pseudo-header checksum is done by hardware logic and not
-	 * the offload processers, so make the chip do the pseudo-
-	 * header checksums on receive.  For transmit it is more
-	 * convenient to do the pseudo-header checksum in software
-	 * as Linux does that on transmit for us in all cases.
-	 */
-	tp->tg3_flags |= TG3_FLAG_NO_TX_PSEUDO_CSUM;
-	tp->tg3_flags &= ~TG3_FLAG_NO_RX_PSEUDO_CSUM;
-
 	/* Derive initial jumbo mode from MTU assigned in
 	 * ether_setup() via the alloc_etherdev() call
 	 */
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index c43cc3264202..b6484420e874 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -2171,8 +2171,6 @@ struct tg3 {
 #define TG3_FLAG_PCIX_MODE		0x00020000
 #define TG3_FLAG_PCI_HIGH_SPEED		0x00040000
 #define TG3_FLAG_PCI_32BIT		0x00080000
-#define TG3_FLAG_NO_TX_PSEUDO_CSUM	0x00100000
-#define TG3_FLAG_NO_RX_PSEUDO_CSUM	0x00200000
 #define TG3_FLAG_SERDES_WOL_CAP		0x00400000
 #define TG3_FLAG_JUMBO_RING_ENABLE	0x00800000
 #define TG3_FLAG_10_100_ONLY		0x01000000

From bbadf503d7c7e6efe0a4cd731f8855ba08276215 Mon Sep 17 00:00:00 2001
From: Michael Chan <mchan@broadcom.com>
Date: Thu, 6 Apr 2006 21:46:34 -0700
Subject: [PATCH 25/35] [TG3]: Speed up SRAM access (2nd version)

Speed up SRAM read and write functions if possible by using MMIO
instead of config. cycles. With this change, the post reset signature
done at the end of D3 power change must now be moved before the D3
power change.

IBM reported a problem on powerpc blades during ethtool self test that
was caused by the memory test taking excessively long. Config.  cycles
are very slow on powerpc and the memory test can take more than 10
seconds to complete using config. cycles.

David Miller informed me that an earlier version of the patch caused
problems on sparc64 systems with built-in tg3 chips. This version
fixes the problem by excluding all SUN built-in tg3 chips from doing
MMIO SRAM access.

TG3_FLAG_EEPROM_WRITE_PROT is also set unconditionally when
TG3_FLG2_SUN_570X is set. This should be sane as all SUN chips are
built-in and do not require Vaux switching.

Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 drivers/net/tg3.c | 69 ++++++++++++++++++++++++++++-------------------
 drivers/net/tg3.h |  1 +
 2 files changed, 43 insertions(+), 27 deletions(-)

diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 376d8e776936..73e271e59c6a 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -497,33 +497,40 @@ static void tg3_write_mem(struct tg3 *tp, u32 off, u32 val)
 	unsigned long flags;
 
 	spin_lock_irqsave(&tp->indirect_lock, flags);
-	pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
-	pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);
+	if (tp->tg3_flags & TG3_FLAG_SRAM_USE_CONFIG) {
+		pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
+		pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);
 
-	/* Always leave this as zero. */
-	pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
+		/* Always leave this as zero. */
+		pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
+	} else {
+		tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, off);
+		tw32_f(TG3PCI_MEM_WIN_DATA, val);
+
+		/* Always leave this as zero. */
+		tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, 0);
+	}
 	spin_unlock_irqrestore(&tp->indirect_lock, flags);
 }
 
-static void tg3_write_mem_fast(struct tg3 *tp, u32 off, u32 val)
-{
-	/* If no workaround is needed, write to mem space directly */
-	if (tp->write32 != tg3_write_indirect_reg32)
-		tw32(NIC_SRAM_WIN_BASE + off, val);
-	else
-		tg3_write_mem(tp, off, val);
-}
-
 static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val)
 {
 	unsigned long flags;
 
 	spin_lock_irqsave(&tp->indirect_lock, flags);
-	pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
-	pci_read_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);
+	if (tp->tg3_flags & TG3_FLAG_SRAM_USE_CONFIG) {
+		pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
+		pci_read_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);
 
-	/* Always leave this as zero. */
-	pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
+		/* Always leave this as zero. */
+		pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
+	} else {
+		tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, off);
+		*val = tr32(TG3PCI_MEM_WIN_DATA);
+
+		/* Always leave this as zero. */
+		tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, 0);
+	}
 	spin_unlock_irqrestore(&tp->indirect_lock, flags);
 }
 
@@ -1367,12 +1374,12 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
 		}
 	}
 
+	tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN);
+
 	/* Finally, set the new power state. */
 	pci_write_config_word(tp->pdev, pm + PCI_PM_CTRL, power_control);
 	udelay(100);	/* Delay after power state change */
 
-	tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN);
-
 	return 0;
 }
 
@@ -6539,11 +6546,11 @@ static void tg3_timer(unsigned long __opaque)
 		if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
 			u32 val;
 
-			tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_MBOX,
-					   FWCMD_NICDRV_ALIVE2);
-			tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4);
+			tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX,
+				      FWCMD_NICDRV_ALIVE2);
+			tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4);
 			/* 5 seconds timeout */
-			tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 5);
+			tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 5);
 			val = tr32(GRC_RX_CPU_EVENT);
 			val |= (1 << 14);
 			tw32(GRC_RX_CPU_EVENT, val);
@@ -9539,8 +9546,11 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
 	tp->led_ctrl = LED_CTRL_MODE_PHY_1;
 
 	/* Do not even try poking around in here on Sun parts.  */
-	if (tp->tg3_flags2 & TG3_FLG2_SUN_570X)
+	if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) {
+		/* All SUN chips are built-in LOMs. */
+		tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT;
 		return;
+	}
 
 	tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val);
 	if (val == NIC_SRAM_DATA_SIG_MAGIC) {
@@ -9638,9 +9648,7 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
 		    tp->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL)
 			tp->led_ctrl = LED_CTRL_MODE_PHY_2;
 
-		if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700) &&
-		    (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) &&
-		    (nic_cfg & NIC_SRAM_DATA_CFG_EEPROM_WP))
+		if (nic_cfg & NIC_SRAM_DATA_CFG_EEPROM_WP)
 			tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT;
 
 		if (nic_cfg & NIC_SRAM_DATA_CFG_ASF_ENABLE) {
@@ -10265,6 +10273,13 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
 		pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd);
 	}
 
+	if (tp->write32 == tg3_write_indirect_reg32 ||
+	    ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) &&
+	     (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
+	      GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) ||
+	    (tp->tg3_flags2 & TG3_FLG2_SUN_570X))
+		tp->tg3_flags |= TG3_FLAG_SRAM_USE_CONFIG;
+
 	/* Get eeprom hw config before calling tg3_set_power_state().
 	 * In particular, the TG3_FLAG_EEPROM_WRITE_PROT flag must be
 	 * determined before calling tg3_set_power_state() so that
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index b6484420e874..8c8b987d1250 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -2171,6 +2171,7 @@ struct tg3 {
 #define TG3_FLAG_PCIX_MODE		0x00020000
 #define TG3_FLAG_PCI_HIGH_SPEED		0x00040000
 #define TG3_FLAG_PCI_32BIT		0x00080000
+#define TG3_FLAG_SRAM_USE_CONFIG	0x00100000
 #define TG3_FLAG_SERDES_WOL_CAP		0x00400000
 #define TG3_FLAG_JUMBO_RING_ENABLE	0x00800000
 #define TG3_FLAG_10_100_ONLY		0x01000000

From 83b950c89c8cc0dcc1b079c638be25915c9945f1 Mon Sep 17 00:00:00 2001
From: Jamal Hadi Salim <hadi@cyberus.ca>
Date: Thu, 6 Apr 2006 22:24:22 -0700
Subject: [PATCH 26/35] [PKT_SCHED] act_police: Rename methods.

Rename policer specific _generic_ methods to be specific to
_act_police_

Signed-off-by: Jamal Hadi Salim <hadi@cyberus.ca>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/sched/act_police.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/net/sched/act_police.c b/net/sched/act_police.c
index fa877f8f652c..24c348fa8922 100644
--- a/net/sched/act_police.c
+++ b/net/sched/act_police.c
@@ -66,7 +66,7 @@ static __inline__ struct tcf_police * tcf_police_lookup(u32 index)
 }
 
 #ifdef CONFIG_NET_CLS_ACT
-static int tcf_generic_walker(struct sk_buff *skb, struct netlink_callback *cb,
+static int tcf_act_police_walker(struct sk_buff *skb, struct netlink_callback *cb,
                               int type, struct tc_action *a)
 {
 	struct tcf_police *p;
@@ -113,7 +113,7 @@ static int tcf_generic_walker(struct sk_buff *skb, struct netlink_callback *cb,
 }
 
 static inline int
-tcf_hash_search(struct tc_action *a, u32 index)
+tcf_act_police_hash_search(struct tc_action *a, u32 index)
 {
 	struct tcf_police *p = tcf_police_lookup(index);
 
@@ -387,9 +387,9 @@ static struct tc_action_ops act_police_ops = {
 	.act		=	tcf_act_police,
 	.dump		=	tcf_act_police_dump,
 	.cleanup	=	tcf_act_police_cleanup,
-	.lookup		=	tcf_hash_search,
+	.lookup		=	tcf_act_police_hash_search,
 	.init		=	tcf_act_police_locate,
-	.walk		=	tcf_generic_walker
+	.walk		=	tcf_act_police_walker
 };
 
 static int __init

From 31380de95cc3183bbb379339e67f83d69e56fbd6 Mon Sep 17 00:00:00 2001
From: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Date: Thu, 6 Apr 2006 22:38:28 -0700
Subject: [PATCH 27/35] [NET] kzalloc: use in alloc_netdev

Noticed this use, fixed it.

Signed-off-by: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/core/dev.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/net/core/dev.c b/net/core/dev.c
index 434220d093aa..dfb62998866a 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3100,12 +3100,11 @@ struct net_device *alloc_netdev(int sizeof_priv, const char *name,
 	alloc_size = (sizeof(*dev) + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST;
 	alloc_size += sizeof_priv + NETDEV_ALIGN_CONST;
 
-	p = kmalloc(alloc_size, GFP_KERNEL);
+	p = kzalloc(alloc_size, GFP_KERNEL);
 	if (!p) {
 		printk(KERN_ERR "alloc_dev: Unable to allocate device.\n");
 		return NULL;
 	}
-	memset(p, 0, alloc_size);
 
 	dev = (struct net_device *)
 		(((long)p + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST);

From 77d04bd957ddca9d48a664e28b40f33993f4550e Mon Sep 17 00:00:00 2001
From: Andrew Morton <akpm@osdl.org>
Date: Fri, 7 Apr 2006 14:52:59 -0700
Subject: [PATCH 28/35] [NET]: More kzalloc conversions.

Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/core/dv.c            |  5 +----
 net/core/flow.c          |  4 +---
 net/core/gen_estimator.c |  3 +--
 net/core/neighbour.c     | 14 ++++----------
 net/core/request_sock.c  |  4 +---
 5 files changed, 8 insertions(+), 22 deletions(-)

diff --git a/net/core/dv.c b/net/core/dv.c
index cf581407538c..29ee77f15932 100644
--- a/net/core/dv.c
+++ b/net/core/dv.c
@@ -55,15 +55,12 @@ int alloc_divert_blk(struct net_device *dev)
 
 	dev->divert = NULL;
 	if (dev->type == ARPHRD_ETHER) {
-		dev->divert = (struct divert_blk *)
-			kmalloc(alloc_size, GFP_KERNEL);
+		dev->divert = kzalloc(alloc_size, GFP_KERNEL);
 		if (dev->divert == NULL) {
 			printk(KERN_INFO "divert: unable to allocate divert_blk for %s\n",
 			       dev->name);
 			return -ENOMEM;
 		}
-
-		memset(dev->divert, 0, sizeof(struct divert_blk));
 		dev_hold(dev);
 	}
 
diff --git a/net/core/flow.c b/net/core/flow.c
index 55789f832eda..885a2f655db0 100644
--- a/net/core/flow.c
+++ b/net/core/flow.c
@@ -318,12 +318,10 @@ static void __devinit flow_cache_cpu_prepare(int cpu)
 		/* NOTHING */;
 
 	flow_table(cpu) = (struct flow_cache_entry **)
-		__get_free_pages(GFP_KERNEL, order);
+		__get_free_pages(GFP_KERNEL|__GFP_ZERO, order);
 	if (!flow_table(cpu))
 		panic("NET: failed to allocate flow cache order %lu\n", order);
 
-	memset(flow_table(cpu), 0, PAGE_SIZE << order);
-
 	flow_hash_rnd_recalc(cpu) = 1;
 	flow_count(cpu) = 0;
 
diff --git a/net/core/gen_estimator.c b/net/core/gen_estimator.c
index b07c029e8219..3cad026764f0 100644
--- a/net/core/gen_estimator.c
+++ b/net/core/gen_estimator.c
@@ -159,11 +159,10 @@ int gen_new_estimator(struct gnet_stats_basic *bstats,
 	if (parm->interval < -2 || parm->interval > 3)
 		return -EINVAL;
 
-	est = kmalloc(sizeof(*est), GFP_KERNEL);
+	est = kzalloc(sizeof(*est), GFP_KERNEL);
 	if (est == NULL)
 		return -ENOBUFS;
 
-	memset(est, 0, sizeof(*est));
 	est->interval = parm->interval + 2;
 	est->bstats = bstats;
 	est->rate_est = rate_est;
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 0c8666872d10..2ec8693fb778 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -284,14 +284,11 @@ static struct neighbour **neigh_hash_alloc(unsigned int entries)
 	struct neighbour **ret;
 
 	if (size <= PAGE_SIZE) {
-		ret = kmalloc(size, GFP_ATOMIC);
+		ret = kzalloc(size, GFP_ATOMIC);
 	} else {
 		ret = (struct neighbour **)
-			__get_free_pages(GFP_ATOMIC, get_order(size));
+		      __get_free_pages(GFP_ATOMIC|__GFP_ZERO, get_order(size));
 	}
-	if (ret)
-		memset(ret, 0, size);
-
 	return ret;
 }
 
@@ -1089,8 +1086,7 @@ static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst,
 		if (hh->hh_type == protocol)
 			break;
 
-	if (!hh && (hh = kmalloc(sizeof(*hh), GFP_ATOMIC)) != NULL) {
-		memset(hh, 0, sizeof(struct hh_cache));
+	if (!hh && (hh = kzalloc(sizeof(*hh), GFP_ATOMIC)) != NULL) {
 		rwlock_init(&hh->hh_lock);
 		hh->hh_type = protocol;
 		atomic_set(&hh->hh_refcnt, 0);
@@ -1366,13 +1362,11 @@ void neigh_table_init(struct neigh_table *tbl)
 	tbl->hash_buckets = neigh_hash_alloc(tbl->hash_mask + 1);
 
 	phsize = (PNEIGH_HASHMASK + 1) * sizeof(struct pneigh_entry *);
-	tbl->phash_buckets = kmalloc(phsize, GFP_KERNEL);
+	tbl->phash_buckets = kzalloc(phsize, GFP_KERNEL);
 
 	if (!tbl->hash_buckets || !tbl->phash_buckets)
 		panic("cannot allocate neighbour cache hashes");
 
-	memset(tbl->phash_buckets, 0, phsize);
-
 	get_random_bytes(&tbl->hash_rnd, sizeof(tbl->hash_rnd));
 
 	rwlock_init(&tbl->lock);
diff --git a/net/core/request_sock.c b/net/core/request_sock.c
index 1e44eda1fda9..79ebd75fbe4d 100644
--- a/net/core/request_sock.c
+++ b/net/core/request_sock.c
@@ -38,13 +38,11 @@ int reqsk_queue_alloc(struct request_sock_queue *queue,
 {
 	const int lopt_size = sizeof(struct listen_sock) +
 			      nr_table_entries * sizeof(struct request_sock *);
-	struct listen_sock *lopt = kmalloc(lopt_size, GFP_KERNEL);
+	struct listen_sock *lopt = kzalloc(lopt_size, GFP_KERNEL);
 
 	if (lopt == NULL)
 		return -ENOMEM;
 
-	memset(lopt, 0, lopt_size);
-
 	for (lopt->max_qlen_log = 6;
 	     (1 << lopt->max_qlen_log) < sysctl_max_syn_backlog;
 	     lopt->max_qlen_log++);

From 503e4faad18baa62bb818537b920ad939749823e Mon Sep 17 00:00:00 2001
From: Brian Haley <brian.haley@hp.com>
Date: Fri, 7 Apr 2006 15:00:06 -0700
Subject: [PATCH 29/35] [NETFILTER]: Fix build with CONFIG_NETFILTER=y/m on
 IA64

Can't build with CONFIG_NETFILTER=y/m on IA64, there's a missing
#include in net/ipv6/netfilter.c

net/ipv6/netfilter.c: In function `nf_ip6_checksum':
net/ipv6/netfilter.c:92: warning: implicit declaration of function
`csum_ipv6_magic'

Signed-off-by: Brian Haley <brian.haley@hp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/ipv6/netfilter.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c
index 3e9ecfaf67e2..395a417ba955 100644
--- a/net/ipv6/netfilter.c
+++ b/net/ipv6/netfilter.c
@@ -7,6 +7,7 @@
 #include <net/ipv6.h>
 #include <net/ip6_route.h>
 #include <net/xfrm.h>
+#include <net/ip6_checksum.h>
 
 int ip6_route_me_harder(struct sk_buff *skb)
 {

From 30aaa154fc21ad1ee4400e28009732a04a80862f Mon Sep 17 00:00:00 2001
From: Adrian Bunk <bunk@stusta.de>
Date: Sun, 9 Apr 2006 22:29:17 -0700
Subject: [PATCH 30/35] [IPV6]: Unexport secure_ipv6_port_ephemeral

This patch removes the unused EXPORT_SYMBOL(secure_ipv6_port_ephemeral).

Signed-off-by: Adrian Bunk <bunk@stusta.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 drivers/char/random.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/char/random.c b/drivers/char/random.c
index 86be04b241e1..58f3512c52e1 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -1584,7 +1584,6 @@ u32 secure_ipv6_port_ephemeral(const __u32 *saddr, const __u32 *daddr, __u16 dpo
 
 	return twothirdsMD4Transform(daddr, hash);
 }
-EXPORT_SYMBOL(secure_ipv6_port_ephemeral);
 #endif
 
 #if defined(CONFIG_IP_DCCP) || defined(CONFIG_IP_DCCP_MODULE)

From 9469d458b90bfb9117cbb488cfa645d94c3921b1 Mon Sep 17 00:00:00 2001
From: Sergey Vlasov <vsu@altlinux.ru>
Date: Sun, 9 Apr 2006 22:32:48 -0700
Subject: [PATCH 31/35] [NET]: Fix hotplug race during device registration.

From: Thomas de Grenier de Latour <degrenier@easyconnect.fr>

On Sun, 9 Apr 2006 21:56:59 +0400,
Sergey Vlasov <vsu@altlinux.ru> wrote:

> However, show_address() does not output anything unless
> dev->reg_state == NETREG_REGISTERED - and this state is set by
> netdev_run_todo() only after netdev_register_sysfs() returns, so in
> the meantime (while netdev_register_sysfs() is busy adding the
> "statistics" attribute group) some process may see an empty "address"
> attribute.

I've tried the attached patch, suggested by Sergey Vlasov on
hotplug-devel@, and as far as i can test it works just fine.

Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/core/dev.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/core/dev.c b/net/core/dev.c
index dfb62998866a..2731570eba5b 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3042,11 +3042,11 @@ void netdev_run_todo(void)
 
 		switch(dev->reg_state) {
 		case NETREG_REGISTERING:
+			dev->reg_state = NETREG_REGISTERED;
 			err = netdev_register_sysfs(dev);
 			if (err)
 				printk(KERN_ERR "%s: failed sysfs registration (%d)\n",
 				       dev->name, err);
-			dev->reg_state = NETREG_REGISTERED;
 			break;
 
 		case NETREG_UNREGISTERING:

From 9b591cbd4e0fc2911d105d88d354124467b2cc08 Mon Sep 17 00:00:00 2001
From: "David S. Miller" <davem@sunset.davemloft.net>
Date: Sun, 9 Apr 2006 22:37:18 -0700
Subject: [PATCH 32/35] [X25]: Restore skb->dev setting in x25_type_trans().

Noticed by Pascal Schlafer.

Signed-off-by: David S. Miller <davem@davemloft.net>
---
 include/net/x25device.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/net/x25device.h b/include/net/x25device.h
index 1a318374faef..1d10c879f7e2 100644
--- a/include/net/x25device.h
+++ b/include/net/x25device.h
@@ -8,6 +8,7 @@
 static inline __be16 x25_type_trans(struct sk_buff *skb, struct net_device *dev)
 {
 	skb->mac.raw = skb->data;
+	skb->dev = dev;
 	skb->pkt_type = PACKET_HOST;
 	
 	return htons(ETH_P_X25);

From 19910d1aec0b2b96ff4b4a93e2aed0d32643e850 Mon Sep 17 00:00:00 2001
From: Patrick McHardy <kaber@trash.net>
Date: Sun, 9 Apr 2006 22:38:29 -0700
Subject: [PATCH 33/35] [NETFILTER]: Fix DNAT in LOCAL_OUT

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/ipv4/netfilter/ip_nat_rule.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/ipv4/netfilter/ip_nat_rule.c b/net/ipv4/netfilter/ip_nat_rule.c
index efba8c4e42e0..1aba926c1cb0 100644
--- a/net/ipv4/netfilter/ip_nat_rule.c
+++ b/net/ipv4/netfilter/ip_nat_rule.c
@@ -279,7 +279,7 @@ static struct ipt_target ipt_dnat_reg = {
 	.target		= ipt_dnat_target,
 	.targetsize	= sizeof(struct ip_nat_multi_range_compat),
 	.table		= "nat",
-	.hooks		= 1 << NF_IP_PRE_ROUTING,
+	.hooks		= (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT),
 	.checkentry	= ipt_dnat_checkentry,
 };
 

From 55c0022e53452360064ea264c41410c70565d9f8 Mon Sep 17 00:00:00 2001
From: "David S. Miller" <davem@sunset.davemloft.net>
Date: Sun, 9 Apr 2006 22:43:55 -0700
Subject: [PATCH 34/35] [IPV4] ip_fragment: Always compute hash with
 ipfrag_lock held.

Otherwise we could compute an inaccurate hash due to the
random seed changing.

Noticed by Zach Brown and patch is based upon some feedback
from Herbert Xu.

Signed-off-by: David S. Miller <davem@davemloft.net>
---
 net/ipv4/ip_fragment.c | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 2a8adda15e11..da734c439179 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -304,13 +304,17 @@ static void ip_expire(unsigned long arg)
 
 /* Creation primitives. */
 
-static struct ipq *ip_frag_intern(unsigned int hash, struct ipq *qp_in)
+static struct ipq *ip_frag_intern(struct ipq *qp_in)
 {
 	struct ipq *qp;
 #ifdef CONFIG_SMP
 	struct hlist_node *n;
 #endif
+	unsigned int hash;
+
 	write_lock(&ipfrag_lock);
+	hash = ipqhashfn(qp_in->id, qp_in->saddr, qp_in->daddr,
+			 qp_in->protocol);
 #ifdef CONFIG_SMP
 	/* With SMP race we have to recheck hash table, because
 	 * such entry could be created on other cpu, while we
@@ -345,7 +349,7 @@ static struct ipq *ip_frag_intern(unsigned int hash, struct ipq *qp_in)
 }
 
 /* Add an entry to the 'ipq' queue for a newly received IP datagram. */
-static struct ipq *ip_frag_create(unsigned hash, struct iphdr *iph, u32 user)
+static struct ipq *ip_frag_create(struct iphdr *iph, u32 user)
 {
 	struct ipq *qp;
 
@@ -371,7 +375,7 @@ static struct ipq *ip_frag_create(unsigned hash, struct iphdr *iph, u32 user)
 	spin_lock_init(&qp->lock);
 	atomic_set(&qp->refcnt, 1);
 
-	return ip_frag_intern(hash, qp);
+	return ip_frag_intern(qp);
 
 out_nomem:
 	LIMIT_NETDEBUG(KERN_ERR "ip_frag_create: no memory left !\n");
@@ -387,11 +391,12 @@ static inline struct ipq *ip_find(struct iphdr *iph, u32 user)
 	__u32 saddr = iph->saddr;
 	__u32 daddr = iph->daddr;
 	__u8 protocol = iph->protocol;
-	unsigned int hash = ipqhashfn(id, saddr, daddr, protocol);
+	unsigned int hash;
 	struct ipq *qp;
 	struct hlist_node *n;
 
 	read_lock(&ipfrag_lock);
+	hash = ipqhashfn(id, saddr, daddr, protocol);
 	hlist_for_each_entry(qp, n, &ipq_hash[hash], list) {
 		if(qp->id == id		&&
 		   qp->saddr == saddr	&&
@@ -405,7 +410,7 @@ static inline struct ipq *ip_find(struct iphdr *iph, u32 user)
 	}
 	read_unlock(&ipfrag_lock);
 
-	return ip_frag_create(hash, iph, user);
+	return ip_frag_create(iph, user);
 }
 
 /* Is the fragment too far ahead to be part of ipq? */

From b1a7ffcb7a047e99ab02424e651e0492f36095f7 Mon Sep 17 00:00:00 2001
From: Denis Vlasenko <vda@ilport.com.ua>
Date: Sun, 9 Apr 2006 22:48:59 -0700
Subject: [PATCH 35/35] [IPV6]: Deinline few large functions in inet6 code

Deinline a few functions which produce 200+ bytes of code.

Size  Uses Wasted Name and definition
===== ==== ====== ================================================
  429    3    818 __inet6_lookup        include/net/inet6_hashtables.h
  404    2    384 __inet6_lookup_established    include/net/inet6_hashtables.h
  206    3    372 __inet6_hash  include/net/inet6_hashtables.h

Signed-off-by: Denis Vlasenko <vda@ilport.com.ua>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 include/net/inet6_hashtables.h | 70 ++---------------------------
 net/ipv6/inet6_hashtables.c    | 80 ++++++++++++++++++++++++++++++++++
 2 files changed, 83 insertions(+), 67 deletions(-)

diff --git a/include/net/inet6_hashtables.h b/include/net/inet6_hashtables.h
index 25f708ff020e..59f0c83d55a2 100644
--- a/include/net/inet6_hashtables.h
+++ b/include/net/inet6_hashtables.h
@@ -48,31 +48,7 @@ static inline int inet6_sk_ehashfn(const struct sock *sk)
 	return inet6_ehashfn(laddr, lport, faddr, fport);
 }
 
-static inline void __inet6_hash(struct inet_hashinfo *hashinfo,
-				struct sock *sk)
-{
-	struct hlist_head *list;
-	rwlock_t *lock;
-
-	BUG_TRAP(sk_unhashed(sk));
-
-	if (sk->sk_state == TCP_LISTEN) {
-		list = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)];
-		lock = &hashinfo->lhash_lock;
-		inet_listen_wlock(hashinfo);
-	} else {
-		unsigned int hash;
-		sk->sk_hash = hash = inet6_sk_ehashfn(sk);
-		hash &= (hashinfo->ehash_size - 1);
-		list = &hashinfo->ehash[hash].chain;
-		lock = &hashinfo->ehash[hash].lock;
-		write_lock(lock);
-	}
-
-	__sk_add_node(sk, list);
-	sock_prot_inc_use(sk->sk_prot);
-	write_unlock(lock);
-}
+extern void __inet6_hash(struct inet_hashinfo *hashinfo, struct sock *sk);
 
 /*
  * Sockets in TCP_CLOSE state are _always_ taken out of the hash, so
@@ -80,52 +56,12 @@ static inline void __inet6_hash(struct inet_hashinfo *hashinfo,
  *
  * The sockhash lock must be held as a reader here.
  */
-static inline struct sock *
-		__inet6_lookup_established(struct inet_hashinfo *hashinfo,
+extern struct sock *__inet6_lookup_established(struct inet_hashinfo *hashinfo,
 					   const struct in6_addr *saddr,
 					   const u16 sport,
 					   const struct in6_addr *daddr,
 					   const u16 hnum,
-					   const int dif)
-{
-	struct sock *sk;
-	const struct hlist_node *node;
-	const __u32 ports = INET_COMBINED_PORTS(sport, hnum);
-	/* Optimize here for direct hit, only listening connections can
-	 * have wildcards anyways.
-	 */
-	unsigned int hash = inet6_ehashfn(daddr, hnum, saddr, sport);
-	struct inet_ehash_bucket *head = inet_ehash_bucket(hashinfo, hash);
-
-	prefetch(head->chain.first);
-	read_lock(&head->lock);
-	sk_for_each(sk, node, &head->chain) {
-		/* For IPV6 do the cheaper port and family tests first. */
-		if (INET6_MATCH(sk, hash, saddr, daddr, ports, dif))
-			goto hit; /* You sunk my battleship! */
-	}
-	/* Must check for a TIME_WAIT'er before going to listener hash. */
-	sk_for_each(sk, node, &(head + hashinfo->ehash_size)->chain) {
-		const struct inet_timewait_sock *tw = inet_twsk(sk);
-
-		if(*((__u32 *)&(tw->tw_dport))	== ports	&&
-		   sk->sk_family		== PF_INET6) {
-			const struct inet6_timewait_sock *tw6 = inet6_twsk(sk);
-
-			if (ipv6_addr_equal(&tw6->tw_v6_daddr, saddr)	&&
-			    ipv6_addr_equal(&tw6->tw_v6_rcv_saddr, daddr)	&&
-			    (!sk->sk_bound_dev_if || sk->sk_bound_dev_if == dif))
-				goto hit;
-		}
-	}
-	read_unlock(&head->lock);
-	return NULL;
-
-hit:
-	sock_hold(sk);
-	read_unlock(&head->lock);
-	return sk;
-}
+					   const int dif);
 
 extern struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo,
 					  const struct in6_addr *daddr,
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c
index bb8ffb8a14c5..2ae84c961678 100644
--- a/net/ipv6/inet6_hashtables.c
+++ b/net/ipv6/inet6_hashtables.c
@@ -23,6 +23,86 @@
 #include <net/inet6_hashtables.h>
 #include <net/ip.h>
 
+void __inet6_hash(struct inet_hashinfo *hashinfo,
+				struct sock *sk)
+{
+	struct hlist_head *list;
+	rwlock_t *lock;
+
+	BUG_TRAP(sk_unhashed(sk));
+
+	if (sk->sk_state == TCP_LISTEN) {
+		list = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)];
+		lock = &hashinfo->lhash_lock;
+		inet_listen_wlock(hashinfo);
+	} else {
+		unsigned int hash;
+		sk->sk_hash = hash = inet6_sk_ehashfn(sk);
+		hash &= (hashinfo->ehash_size - 1);
+		list = &hashinfo->ehash[hash].chain;
+		lock = &hashinfo->ehash[hash].lock;
+		write_lock(lock);
+	}
+
+	__sk_add_node(sk, list);
+	sock_prot_inc_use(sk->sk_prot);
+	write_unlock(lock);
+}
+EXPORT_SYMBOL(__inet6_hash);
+
+/*
+ * Sockets in TCP_CLOSE state are _always_ taken out of the hash, so
+ * we need not check it for TCP lookups anymore, thanks Alexey. -DaveM
+ *
+ * The sockhash lock must be held as a reader here.
+ */
+struct sock *__inet6_lookup_established(struct inet_hashinfo *hashinfo,
+					   const struct in6_addr *saddr,
+					   const u16 sport,
+					   const struct in6_addr *daddr,
+					   const u16 hnum,
+					   const int dif)
+{
+	struct sock *sk;
+	const struct hlist_node *node;
+	const __u32 ports = INET_COMBINED_PORTS(sport, hnum);
+	/* Optimize here for direct hit, only listening connections can
+	 * have wildcards anyways.
+	 */
+	unsigned int hash = inet6_ehashfn(daddr, hnum, saddr, sport);
+	struct inet_ehash_bucket *head = inet_ehash_bucket(hashinfo, hash);
+
+	prefetch(head->chain.first);
+	read_lock(&head->lock);
+	sk_for_each(sk, node, &head->chain) {
+		/* For IPV6 do the cheaper port and family tests first. */
+		if (INET6_MATCH(sk, hash, saddr, daddr, ports, dif))
+			goto hit; /* You sunk my battleship! */
+	}
+	/* Must check for a TIME_WAIT'er before going to listener hash. */
+	sk_for_each(sk, node, &(head + hashinfo->ehash_size)->chain) {
+		const struct inet_timewait_sock *tw = inet_twsk(sk);
+
+		if(*((__u32 *)&(tw->tw_dport))	== ports	&&
+		   sk->sk_family		== PF_INET6) {
+			const struct inet6_timewait_sock *tw6 = inet6_twsk(sk);
+
+			if (ipv6_addr_equal(&tw6->tw_v6_daddr, saddr)	&&
+			    ipv6_addr_equal(&tw6->tw_v6_rcv_saddr, daddr)	&&
+			    (!sk->sk_bound_dev_if || sk->sk_bound_dev_if == dif))
+				goto hit;
+		}
+	}
+	read_unlock(&head->lock);
+	return NULL;
+
+hit:
+	sock_hold(sk);
+	read_unlock(&head->lock);
+	return sk;
+}
+EXPORT_SYMBOL(__inet6_lookup_established);
+
 struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo,
 				   const struct in6_addr *daddr,
 				   const unsigned short hnum, const int dif)