diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index 838eea92f8f2d74c750fc968750b348d769f1f05..5bc9fe749d83388f88c6251d62c9f497aa4ab467 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -826,7 +826,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
 		 * Otherwise we could race with the device.
 		 */
 		first_eor = eor;
-		first_len = skb->len - skb->data_len;
+		first_len = skb_headlen(skb);
 		first_mapping = pci_map_single(cp->pdev, skb->data,
 					       first_len, PCI_DMA_TODEVICE);
 		cp->tx_skb[entry].skb = skb;
diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c
index e05a28c98a944b9cbbfb6c3ecf9c85d82045c4ef..502e1f0414bab25b53e42ef379545947d5fbdf71 100644
--- a/drivers/net/acenic.c
+++ b/drivers/net/acenic.c
@@ -2829,7 +2829,7 @@ static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev)
 		int i, len = 0;
 
 		mapping = ace_map_tx_skb(ap, skb, NULL, idx);
-		flagsize = ((skb->len - skb->data_len) << 16);
+		flagsize = (skb_headlen(skb) << 16);
 		if (skb->ip_summed == CHECKSUM_HW)
 			flagsize |= BD_FLG_TCP_UDP_SUM;
 #if ACENIC_DO_VLAN
diff --git a/drivers/net/e100/e100_main.c b/drivers/net/e100/e100_main.c
index d241eaa64e2e8a2f7f3f075a3b0a2bdd2be5708b..2f3f6f6b1e8da3045debbeed18bb8cbb1614a6ab 100644
--- a/drivers/net/e100/e100_main.c
+++ b/drivers/net/e100/e100_main.c
@@ -2199,10 +2199,10 @@ e100_prepare_xmit_buff(struct e100_private *bdp, struct sk_buff *skb)
 
 		(tcb->tbd_ptr)->tbd_buf_addr =
 			cpu_to_le32(pci_map_single(bdp->pdev, skb->data,
-						   (skb->len - skb->data_len),
+						   skb_headlen(skb),
 						   PCI_DMA_TODEVICE));
 		(tcb->tbd_ptr)->tbd_buf_cnt =
-			cpu_to_le16(skb->len - skb->data_len);
+			cpu_to_le16(skb_headlen(skb));
 
 		for (i = 0; i < skb_shinfo(skb)->nr_frags;
 		     i++, tbd_arr_ptr++, frag++) {
diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c
index 7c139fdafea6c3382a2031d2732ba73bc3941cf7..daeb1f39e9c81c315fafe0c9c6bba2c11b852644 100644
--- a/drivers/net/sungem.c
+++ b/drivers/net/sungem.c
@@ -894,7 +894,7 @@ static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev)
 		/* We must give this initial chunk to the device last.
 		 * Otherwise we could race with the device.
 		 */
-		first_len = skb->len - skb->data_len;
+		first_len = skb_headlen(skb);
 		first_mapping = pci_map_page(gp->pdev, virt_to_page(skb->data),
 					     ((unsigned long) skb->data & ~PAGE_MASK),
 					     first_len, PCI_DMA_TODEVICE);
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index 5b34d6ecb03bdfcf6b52d0fa057d40f1b25ad98a..631d07021d815dc0abe9920ea609e2deab3abedf 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -2319,7 +2319,7 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev)
 		/* We must give this initial chunk to the device last.
 		 * Otherwise we could race with the device.
 		 */
-		first_len = skb->len - skb->data_len;
+		first_len = skb_headlen(skb);
 		first_mapping = hme_dma_map(hp, skb->data, first_len, DMA_TODEVICE);
 		entry = NEXT_TX(entry);
 
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index ea4082646fdee480dc97f46f89a1f816386a9b5f..07a311b66d3c5000f8b3a8ee445ceada29cebdb5 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -1751,7 +1751,7 @@ static void tg3_tx(struct tg3 *tp)
 
 		pci_unmap_single(tp->pdev,
 				 pci_unmap_addr(ri, mapping),
-				 (skb->len - skb->data_len),
+				 skb_headlen(skb),
 				 PCI_DMA_TODEVICE);
 
 		ri->skb = NULL;
@@ -2316,7 +2316,7 @@ static int tigon3_4gb_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb,
 		int len;
 
 		if (i == 0)
-			len = skb->len - skb->data_len;
+			len = skb_headlen(skb);
 		else
 			len = skb_shinfo(skb)->frags[i-1].size;
 		pci_unmap_single(tp->pdev,
@@ -2401,7 +2401,7 @@ static int tg3_start_xmit_4gbug(struct sk_buff *skb, struct net_device *dev)
 	int would_hit_hwbug;
 	unsigned long flags;
 
-	len = (skb->len - skb->data_len);
+	len = skb_headlen(skb);
 
 	/* No BH disabling for tx_lock here.  We are running in BH disabled
 	 * context and TX reclaim runs via tp->poll inside of a software
@@ -2520,7 +2520,7 @@ static int tg3_start_xmit_4gbug(struct sk_buff *skb, struct net_device *dev)
 		i = 0;
 		while (entry != last_plus_one) {
 			if (i == 0)
-				len = skb->len - skb->data_len;
+				len = skb_headlen(skb);
 			else
 				len = skb_shinfo(skb)->frags[i-1].size;
 
@@ -2593,7 +2593,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	u32 len, entry, base_flags, mss;
 	unsigned long flags;
 
-	len = (skb->len - skb->data_len);
+	len = skb_headlen(skb);
 
 	/* No BH disabling for tx_lock here.  We are running in BH disabled
 	 * context and TX reclaim runs via tp->poll inside of a software
@@ -2829,7 +2829,7 @@ static void tg3_free_rings(struct tg3 *tp)
 
 		pci_unmap_single(tp->pdev,
 				 pci_unmap_addr(txp, mapping),
-				 (skb->len - skb->data_len),
+				 skb_headlen(skb),
 				 PCI_DMA_TODEVICE);
 		txp->skb = NULL;
 
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index e6c46f2f41a0ddcc8cc458627c23f5810079545d..6a6a8eb72c10e5141ca97edab6a724c0e7662a67 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -844,7 +844,7 @@ typhoon_start_tx(struct sk_buff *skb, struct net_device *dev)
 	} else {
 		int i, len;
 
-		len = skb->len - skb->data_len;
+		len = skb_headlen(skb);
 		skb_dma = pci_map_single(tp->tx_pdev, skb->data, len,
 				         PCI_DMA_TODEVICE);
 		txd->flags = TYPHOON_FRAG_DESC | TYPHOON_DESC_VALID;
diff --git a/include/linux/irda.h b/include/linux/irda.h
index bdf23baa5483b92277ead5dc8e6f60d7f6b28627..948488ece2a8e9d7bd9f5107249370b3399571c6 100644
--- a/include/linux/irda.h
+++ b/include/linux/irda.h
@@ -25,6 +25,8 @@
 #ifndef KERNEL_IRDA_H
 #define KERNEL_IRDA_H
 
+#include <linux/socket.h> /* only for sa_family_t */
+
 /* Hint bit positions for first hint byte */
 #define HINT_PNP         0x01
 #define HINT_PDA         0x02
diff --git a/include/linux/net.h b/include/linux/net.h
index 55083c9382982c58c6d2e59f943818b28874816e..6ba6e10385211963c52b408947dcf828d14598b0 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -19,7 +19,6 @@
 #define _LINUX_NET_H
 
 #include <linux/config.h>
-#include <linux/socket.h>
 #include <linux/wait.h>
 
 struct poll_table_struct;
@@ -88,6 +87,8 @@ struct socket {
 struct vm_area_struct;
 struct page;
 struct kiocb;
+struct sockaddr;
+struct msghdr;
 
 struct proto_ops {
 	int		family;
@@ -136,6 +137,8 @@ struct net_proto_family {
 	short	encrypt_net;
 };
 
+struct iovec;
+
 extern int	     sock_wake_async(struct socket *sk, int how, int band);
 extern int	     sock_register(struct net_proto_family *fam);
 extern int	     sock_unregister(int family);
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index 69346c394563ef687481234e3ef3e6140d9dbde4..30de192de7a9587bb54ab52393ea9ebf12f9087b 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -1,6 +1,8 @@
 #ifndef __LINUX_NETLINK_H
 #define __LINUX_NETLINK_H
 
+#include <linux/socket.h> /* for sa_family_t */
+
 #define NETLINK_ROUTE		0	/* Routing/device hook				*/
 #define NETLINK_SKIP		1	/* Reserved for ENskip  			*/
 #define NETLINK_USERSOCK	2	/* Reserved for user mode socket protocols 	*/
diff --git a/include/net/tcp.h b/include/net/tcp.h
index b652650286fee9a8555766ab6df167dcb25e8395..8844d3f3d8f95c36ff6b7e125838a2b785de8927 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -31,6 +31,7 @@
 #include <linux/percpu.h>
 #include <net/checksum.h>
 #include <net/sock.h>
+#include <net/snmp.h>
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
 #include <linux/ipv6.h>
 #endif
@@ -639,6 +640,8 @@ DECLARE_SNMP_STAT(struct tcp_mib, tcp_statistics);
 #define TCP_INC_STATS_BH(field)		SNMP_INC_STATS_BH(tcp_statistics, field)
 #define TCP_INC_STATS_USER(field) 	SNMP_INC_STATS_USER(tcp_statistics, field)
 #define TCP_DEC_STATS(field)		SNMP_DEC_STATS(tcp_statistics, field)
+#define TCP_ADD_STATS_BH(field, val)	SNMP_ADD_STATS_BH(tcp_statistics, field, val)
+#define TCP_ADD_STATS_USER(field, val)	SNMP_ADD_STATS_USER(tcp_statistics, field, val)
 
 extern __inline__ void		tcp_put_port(struct sock *sk);
 extern void			tcp_inherit_port(struct sock *sk, struct sock *child);
@@ -1398,6 +1401,9 @@ static __inline__ void tcp_set_state(struct sock *sk, int state)
 		break;
 
 	case TCP_CLOSE:
+		if (oldstate == TCP_CLOSE_WAIT || oldstate == TCP_ESTABLISHED)
+			TCP_INC_STATS(TcpEstabResets);
+
 		sk->prot->unhash(sk);
 		if (sk->prev && !(sk->userlocks&SOCK_BINDPORT_LOCK))
 			tcp_put_port(sk);
@@ -1878,4 +1884,13 @@ static inline int tcp_use_frto(const struct sock *sk)
 		       tp->snd_una + tp->snd_wnd));
 }
 
+static inline void tcp_mib_init(void)
+{
+	/* See RFC 2012 */
+	TCP_ADD_STATS_USER(TcpRtoAlgorithm, 1);
+	TCP_ADD_STATS_USER(TcpRtoMin, TCP_RTO_MIN*1000/HZ);
+	TCP_ADD_STATS_USER(TcpRtoMax, TCP_RTO_MAX*1000/HZ);
+	TCP_ADD_STATS_USER(TcpMaxConn, -1);
+}
+
 #endif	/* _TCP_H */
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index fe32e5c323541c1dc810861a5d59b0daa84c5125..b75d2651adf06323a74eb910d25bb05558acdbad 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -84,6 +84,7 @@ extern struct semaphore xfrm_cfg_sem;
 /* Full description of state of transformer. */
 struct xfrm_state
 {
+	/* Note: bydst is re-used during gc */
 	struct list_head	bydst;
 	struct list_head	byspi;
 
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index 25562366d4c0700c3faac01abc427b18bbf1fb6b..fc59bfc7a8bb9abeb205f6091eb176bf9e6cde76 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -29,7 +29,6 @@
 #include <net/p8022.h>
 #include <net/arp.h>
 #include <linux/rtnetlink.h>
-#include <linux/brlock.h>
 #include <linux/notifier.h>
 
 #include <linux/if_vlan.h>
@@ -68,7 +67,6 @@ static struct packet_type vlan_packet_type = {
 	.dev =NULL,
 	.func = vlan_skb_recv, /* VLAN receive method */
 	.data = (void *)(-1),  /* Set here '(void *)1' when this code can SHARE SKBs */
-	.next = NULL
 };
 
 /* End of global variables definitions. */
@@ -231,9 +229,8 @@ static int unregister_vlan_dev(struct net_device *real_dev,
 				real_dev->vlan_rx_kill_vid(real_dev, vlan_id);
 			}
 
-			br_write_lock(BR_NETPROTO_LOCK);
 			grp->vlan_devices[vlan_id] = NULL;
-			br_write_unlock(BR_NETPROTO_LOCK);
+			synchronize_net();
 
 
 			/* Caller unregisters (and if necessary, puts)
@@ -266,7 +263,7 @@ static int unregister_vlan_dev(struct net_device *real_dev,
 				ret = 1;
 			}
 
-			MOD_DEC_USE_COUNT;
+			module_put(THIS_MODULE);
 		}
 	}
 
@@ -433,6 +430,7 @@ static struct net_device *register_vlan_device(const char *eth_IF_name,
 	/* set up method calls */
 	new_dev->init = vlan_dev_init;
 	new_dev->destructor = vlan_dev_destruct;
+	new_dev->owner = THIS_MODULE;
 	    
 	/* new_dev->ifindex = 0;  it will be set when added to
 	 * the global list.
@@ -540,16 +538,22 @@ static struct net_device *register_vlan_device(const char *eth_IF_name,
 	register_netdevice(new_dev);
 
 	rtnl_unlock();
-	    
+
 	/* NOTE:  We have a reference to the real device,
 	 * so hold on to the reference.
 	 */
-	MOD_INC_USE_COUNT; /* Add was a success!! */
+	if (!try_module_get(THIS_MODULE))
+		goto out_module_dying;
+
 #ifdef VLAN_DEBUG
 	printk(VLAN_DBG "Allocated new device successfully, returning.\n");
 #endif
 	return new_dev;
 
+out_module_dying:
+	rtnl_lock();
+	unregister_netdevice(new_dev);
+
 out_free_newdev_priv:
 	kfree(new_dev->priv);
 
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 907073996bc77d3e88f8b44b82a2925b0ab4fc69..24a4462cc152f1aec78492923b7c5f3656773871 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -31,7 +31,6 @@
 #include <net/datalink.h>
 #include <net/p8022.h>
 #include <net/arp.h>
-#include <linux/brlock.h>
 
 #include "vlan.h"
 #include "vlanproc.h"
diff --git a/net/core/datagram.c b/net/core/datagram.c
index f83189e52b130399eaf8980b26817a7742549c20..7474e087fa122c5c49bdedfc6997d796ae6ea279 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -220,7 +220,7 @@ int skb_copy_datagram(const struct sk_buff *skb, int offset, char *to, int size)
 int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset,
 			    struct iovec *to, int len)
 {
-	int start = skb->len - skb->data_len;
+	int start = skb_headlen(skb);
 	int i, copy = start - offset;
 
 	/* Copy header. */
@@ -295,7 +295,7 @@ int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset,
 int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset,
 			       u8 *to, int len, unsigned int *csump)
 {
-	int start = skb->len - skb->data_len;
+	int start = skb_headlen(skb);
 	int pos = 0;
 	int i, copy = start - offset;
 
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index c909a7d3f00a3f5931b3cc30f3ffa2b49e2c0eab..bb68b12b00471d230088995afd5a4108836662d2 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -932,7 +932,7 @@ unsigned char *__pskb_pull_tail(struct sk_buff *skb, int delta)
 int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len)
 {
 	int i, copy;
-	int start = skb->len - skb->data_len;
+	int start = skb_headlen(skb);
 
 	if (offset > (int)skb->len - len)
 		goto fault;
@@ -1009,7 +1009,7 @@ int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len)
 unsigned int skb_checksum(const struct sk_buff *skb, int offset,
 			  int len, unsigned int csum)
 {
-	int start = skb->len - skb->data_len;
+	int start = skb_headlen(skb);
 	int i, copy = start - offset;
 	int pos = 0;
 
@@ -1085,7 +1085,7 @@ unsigned int skb_checksum(const struct sk_buff *skb, int offset,
 unsigned int skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
 				    u8 *to, int len, unsigned int csum)
 {
-	int start = skb->len - skb->data_len;
+	int start = skb_headlen(skb);
 	int i, copy = start - offset;
 	int pos = 0;
 
@@ -1170,9 +1170,9 @@ void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to)
 	if (skb->ip_summed == CHECKSUM_HW)
 		csstart = skb->h.raw - skb->data;
 	else
-		csstart = skb->len - skb->data_len;
+		csstart = skb_headlen(skb);
 
-	if (csstart > skb->len - skb->data_len)
+	if (csstart > skb_headlen(skb))
 		BUG();
 
 	memcpy(to, skb->data, csstart);
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 2082abcdc2d3f869b3a71cf7a4c3ca3f9597ed60..390c24c2a45be009bc1e1133a07a480433fcd90d 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1108,6 +1108,8 @@ static int __init init_ipv4_mibs(void)
 		}
 	}
 
+	(void) tcp_mib_init();
+
 	return 0;
 }
 
diff --git a/net/ipv4/ah.c b/net/ipv4/ah.c
index 1f4830a9431900b1ef623d902e936e6051a53f1f..02f08aa24437662fbd3bce87324c35ec1d4f9af7 100644
--- a/net/ipv4/ah.c
+++ b/net/ipv4/ah.c
@@ -314,12 +314,14 @@ static void ah_destroy(struct xfrm_state *x)
 		crypto_free_tfm(ahp->tfm);
 		ahp->tfm = NULL;
 	}
+	kfree(ahp);
 }
 
 
 static struct xfrm_type ah_type =
 {
 	.description	= "AH4",
+	.owner		= THIS_MODULE,
 	.proto	     	= IPPROTO_AH,
 	.init_state	= ah_init_state,
 	.destructor	= ah_destroy,
@@ -335,7 +337,6 @@ static struct inet_protocol ah4_protocol = {
 
 static int __init ah4_init(void)
 {
-	SET_MODULE_OWNER(&ah_type);
 	if (xfrm_register_type(&ah_type, AF_INET) < 0) {
 		printk(KERN_INFO "ip ah init: can't add xfrm type\n");
 		return -EAGAIN;
diff --git a/net/ipv4/esp.c b/net/ipv4/esp.c
index 2fe10539c3713970216ea730f7321f363658681b..db29b32b118e6a869ae2846bbc9d75eaec49b2b5 100644
--- a/net/ipv4/esp.c
+++ b/net/ipv4/esp.c
@@ -452,6 +452,7 @@ void esp_destroy(struct xfrm_state *x)
 		kfree(esp->auth.work_icv);
 		esp->auth.work_icv = NULL;
 	}
+	kfree(esp);
 }
 
 int esp_init_state(struct xfrm_state *x, void *args)
@@ -552,6 +553,7 @@ int esp_init_state(struct xfrm_state *x, void *args)
 static struct xfrm_type esp_type =
 {
 	.description	= "ESP4",
+	.owner		= THIS_MODULE,
 	.proto	     	= IPPROTO_ESP,
 	.init_state	= esp_init_state,
 	.destructor	= esp_destroy,
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c
index c78c0ac544b62543a883f4450fef4118076bda9d..d07556385a0b390d743c0d17156739553214a61a 100644
--- a/net/ipv4/proc.c
+++ b/net/ipv4/proc.c
@@ -143,9 +143,15 @@ static int snmp_seq_show(struct seq_file *seq, void *v)
 			"InSegs OutSegs RetransSegs InErrs OutRsts\nTcp:");
 
 	for (i = 0;
-	     i < offsetof(struct tcp_mib, __pad) / sizeof(unsigned long); i++)
-		seq_printf(seq, " %lu",
-			   fold_field((void **) tcp_statistics, i));
+	     i < offsetof(struct tcp_mib, __pad) / sizeof(unsigned long); i++) {
+		if (i == (offsetof(struct tcp_mib, TcpMaxConn) / sizeof(unsigned long)))
+			/* MaxConn field is negative, RFC 2012 */
+			seq_printf(seq, " %ld", 
+				   fold_field((void **) tcp_statistics, i));
+		else
+			seq_printf(seq, " %lu", 
+				   fold_field((void **) tcp_statistics, i));
+	}
 
 	seq_printf(seq, "\nUdp: InDatagrams NoPorts InErrors OutDatagrams\n"
 			"Udp:");
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index fd3baeb58b8fdbaaa25c0aac70b4ad17599e9757..344353ac7a6fbaa9770c000bed0a599821902393 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -354,7 +354,7 @@ void tcp_push_one(struct sock *sk, unsigned cur_mss)
 static void skb_split(struct sk_buff *skb, struct sk_buff *skb1, u32 len)
 {
 	int i;
-	int pos = skb->len - skb->data_len;
+	int pos = skb_headlen(skb);
 
 	if (len < pos) {
 		/* Split line is inside header. */
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index 0130c3b7889b297e581da9e2facabb5ed8057c2b..746dc9697b15ac58d5691c1a94b278eead65c619 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -313,11 +313,13 @@ static void ah6_destroy(struct xfrm_state *x)
 		crypto_free_tfm(ahp->tfm);
 		ahp->tfm = NULL;
 	}
+	kfree(ahp);
 }
 
 static struct xfrm_type ah6_type =
 {
 	.description	= "AH6",
+	.owner		= THIS_MODULE,
 	.proto	     	= IPPROTO_AH,
 	.init_state	= ah6_init_state,
 	.destructor	= ah6_destroy,
@@ -333,8 +335,6 @@ static struct inet6_protocol ah6_protocol = {
 
 int __init ah6_init(void)
 {
-	SET_MODULE_OWNER(&ah6_type);
-
 	if (xfrm_register_type(&ah6_type, AF_INET6) < 0) {
 		printk(KERN_INFO "ipv6 ah init: can't add xfrm type\n");
 		return -EAGAIN;
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index 5f9275aabf0f57c2172b58aa0396e2c27c6cadcd..764a5d8ac1ea7290a93c06e1b629b8a7ad65c836 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -406,6 +406,7 @@ void esp6_destroy(struct xfrm_state *x)
 		kfree(esp->auth.work_icv);
 		esp->auth.work_icv = NULL;
 	}
+	kfree(esp);
 }
 
 int esp6_init_state(struct xfrm_state *x, void *args)
@@ -488,6 +489,7 @@ int esp6_init_state(struct xfrm_state *x, void *args)
 static struct xfrm_type esp6_type =
 {
 	.description	= "ESP6",
+	.owner	     	= THIS_MODULE,
 	.proto	     	= IPPROTO_ESP,
 	.init_state	= esp6_init_state,
 	.destructor	= esp6_destroy,
@@ -504,7 +506,6 @@ static struct inet6_protocol esp6_protocol = {
 
 int __init esp6_init(void)
 {
-	SET_MODULE_OWNER(&esp6_type);
 	if (xfrm_register_type(&esp6_type, AF_INET6) < 0) {
 		printk(KERN_INFO "ipv6 esp init: can't add xfrm type\n");
 		return -EAGAIN;
diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c
index d01a6fd0245612979d4eba1df006d240eb897d8c..b850f0285cf2e73308770d0a749096d327c29ebd 100644
--- a/net/xfrm/xfrm_algo.c
+++ b/net/xfrm/xfrm_algo.c
@@ -445,7 +445,7 @@ int xfrm_count_enc_supported(void)
 void skb_icv_walk(const struct sk_buff *skb, struct crypto_tfm *tfm,
 		  int offset, int len, icv_update_fn_t icv_update)
 {
-	int start = skb->len - skb->data_len;
+	int start = skb_headlen(skb);
 	int i, copy = start - offset;
 	struct scatterlist sg;
 
@@ -521,7 +521,7 @@ void skb_icv_walk(const struct sk_buff *skb, struct crypto_tfm *tfm,
 int
 skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
 {
-	int start = skb->len - skb->data_len;
+	int start = skb_headlen(skb);
 	int i, copy = start - offset;
 	int elt = 0;
 
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index b0460abbde2d085947e5fda34196d9aed9083302..321858bf3af23f57ff52a8c8e33f17c0ed2a14e5 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -963,6 +963,8 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
 			 * are implied between each two transformations.
 			 */
 			for (i = pol->xfrm_nr-1, k = 0; i >= 0; i--) {
+				if (pol->xfrm_vec[i].optional)
+					continue;
 				k = xfrm_policy_ok(pol->xfrm_vec+i, sp, k, family);
 				if (k < 0)
 					goto reject;
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 162fa975f05062a5ac797255c1b77022e7dc5a87..8f435d8e51faa95e538197719bb941f24553f4ba 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -13,6 +13,7 @@
  * 	
  */
 
+#include <linux/workqueue.h>
 #include <net/xfrm.h>
 #include <linux/pfkeyv2.h>
 #include <linux/ipsec.h>
@@ -41,8 +42,48 @@ DECLARE_WAIT_QUEUE_HEAD(km_waitq);
 static rwlock_t xfrm_state_afinfo_lock = RW_LOCK_UNLOCKED;
 static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO];
 
+static struct work_struct xfrm_state_gc_work;
+static struct list_head xfrm_state_gc_list = LIST_HEAD_INIT(xfrm_state_gc_list);
+static spinlock_t xfrm_state_gc_lock = SPIN_LOCK_UNLOCKED;
+
 static void __xfrm_state_delete(struct xfrm_state *x);
 
+static void xfrm_state_gc_destroy(struct xfrm_state *x)
+{
+	if (del_timer(&x->timer))
+		BUG();
+	if (x->aalg)
+		kfree(x->aalg);
+	if (x->ealg)
+		kfree(x->ealg);
+	if (x->calg)
+		kfree(x->calg);
+	if (x->encap)
+		kfree(x->encap);
+	if (x->type) {
+		x->type->destructor(x);
+		xfrm_put_type(x->type);
+	}
+	kfree(x);
+	wake_up(&km_waitq);
+}
+
+static void xfrm_state_gc_task(void *data)
+{
+	struct xfrm_state *x;
+	struct list_head *entry, *tmp;
+	struct list_head gc_list = LIST_HEAD_INIT(gc_list);
+
+	spin_lock_bh(&xfrm_state_gc_lock);
+	list_splice_init(&xfrm_state_gc_list, &gc_list);
+	spin_unlock_bh(&xfrm_state_gc_lock);
+
+	list_for_each_safe(entry, tmp, &gc_list) {
+		x = list_entry(entry, struct xfrm_state, bydst);
+		xfrm_state_gc_destroy(x);
+	}
+}
+
 static inline unsigned long make_jiffies(long secs)
 {
 	if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ)
@@ -149,28 +190,17 @@ struct xfrm_state *xfrm_state_alloc(void)
 void __xfrm_state_destroy(struct xfrm_state *x)
 {
 	BUG_TRAP(x->km.state == XFRM_STATE_DEAD);
-	if (del_timer(&x->timer))
-		BUG();
-	if (x->aalg)
-		kfree(x->aalg);
-	if (x->ealg)
-		kfree(x->ealg);
-	if (x->calg)
-		kfree(x->calg);
-	if (x->encap)
-		kfree(x->encap);
-	if (x->type)
-		xfrm_put_type(x->type);
-	kfree(x);
+
+	spin_lock_bh(&xfrm_state_gc_lock);
+	list_add(&x->bydst, &xfrm_state_gc_list);
+	spin_unlock_bh(&xfrm_state_gc_lock);
+	schedule_work(&xfrm_state_gc_work);
 }
 
 static void __xfrm_state_delete(struct xfrm_state *x)
 {
-	int kill = 0;
-
 	if (x->km.state != XFRM_STATE_DEAD) {
 		x->km.state = XFRM_STATE_DEAD;
-		kill = 1;
 		spin_lock(&xfrm_state_lock);
 		list_del(&x->bydst);
 		atomic_dec(&x->refcnt);
@@ -189,22 +219,17 @@ static void __xfrm_state_delete(struct xfrm_state *x)
 		 */
 		if (atomic_read(&x->refcnt) > 2)
 			xfrm_flush_bundles(x);
-	}
 
-	/* All xfrm_state objects are created by one of two possible
-	 * paths:
-	 *
-	 * 1) xfrm_state_alloc --> xfrm_state_insert
-	 * 2) xfrm_state_lookup --> xfrm_state_insert
-	 *
-	 * The xfrm_state_lookup or xfrm_state_alloc call gives a
-	 * reference, and that is what we are dropping here.
-	 */
-	atomic_dec(&x->refcnt);
-
-	if (kill && x->type)
-		x->type->destructor(x);
-	wake_up(&km_waitq);
+		/* All xfrm_state objects are created by one of two possible
+		 * paths:
+		 *
+		 * 2) xfrm_state_lookup --> xfrm_state_insert
+		 *
+		 * The xfrm_state_lookup or xfrm_state_alloc call gives a
+		 * reference, and that is what we are dropping here.
+		 */
+		atomic_dec(&x->refcnt);
+	}
 }
 
 void xfrm_state_delete(struct xfrm_state *x)
@@ -773,5 +798,6 @@ void __init xfrm_state_init(void)
 		INIT_LIST_HEAD(&xfrm_state_bydst[i]);
 		INIT_LIST_HEAD(&xfrm_state_byspi[i]);
 	}
+	INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task, NULL);
 }