diff -r -c -N linux-2.6.22/include/net/xfrmudp.h linux-2.6.22-natt/include/net/xfrmudp.h
*** linux-2.6.22/include/net/xfrmudp.h	Wed Dec 31 19:00:00 1969
--- linux-2.6.22-natt/include/net/xfrmudp.h	Wed May  7 20:21:20 2008
***************
*** 0 ****
--- 1,10 ----
+ /*
+  * pointer to function for type that xfrm4_input wants, to permit
+  * decoupling of XFRM from udp.c
+  */
+ #define HAVE_XFRM4_UDP_REGISTER
+ 
+ typedef int (*xfrm4_rcv_encap_t)(struct sk_buff *skb, __u16 encap_type);
+ extern int udp4_register_esp_rcvencap(xfrm4_rcv_encap_t func
+ 				      , xfrm4_rcv_encap_t *oldfunc);
+ extern int udp4_unregister_esp_rcvencap(xfrm4_rcv_encap_t func);
diff -r -c -N linux-2.6.22/net/ipv4/Kconfig linux-2.6.22-natt/net/ipv4/Kconfig
*** linux-2.6.22/net/ipv4/Kconfig	Sun Jul  8 19:32:17 2007
--- linux-2.6.22-natt/net/ipv4/Kconfig	Wed May  7 20:21:20 2008
***************
*** 409,414 ****
--- 409,420 ----
  	tristate
  	default n
  
+ config IPSEC_NAT_TRAVERSAL
+ 	bool "IPSEC NAT-Traversal (KLIPS compatible)"
+ 	depends on INET
+ 	---help---
+           Includes support for RFC3947/RFC3948 NAT-Traversal of ESP over UDP.
+ 
  config INET_XFRM_MODE_TRANSPORT
  	tristate "IP: IPsec transport mode"
  	default y
diff -r -c -N linux-2.6.22/net/ipv4/udp.c linux-2.6.22-natt/net/ipv4/udp.c
*** linux-2.6.22/net/ipv4/udp.c	Sun Jul  8 19:32:17 2007
--- linux-2.6.22-natt/net/ipv4/udp.c	Wed May  7 22:13:19 2008
***************
*** 101,106 ****
--- 101,107 ----
  #include <net/route.h>
  #include <net/checksum.h>
  #include <net/xfrm.h>
+ #include <net/xfrmudp.h>
  #include "udp_impl.h"
  
  /*
***************
*** 1017,1022 ****
--- 1018,1145 ----
  #endif
  }
  
+ #if defined(CONFIG_XFRM) || defined(CONFIG_IPSEC_NAT_TRAVERSAL)
+ 
+ static xfrm4_rcv_encap_t xfrm4_rcv_encap_func = NULL;
+ 
+ /*
+  * de-encapsulate and pass to the registered xfrm4_rcv_encap_func function.
+  * Most of this code stolen from net/ipv4/xfrm4_input.c
+  * which is attributed to YOSHIFUJI Hideaki @USAGI, and
+  * Derek Atkins <derek@ihtfp.com>
+  */
+ 
+ static int xfrm4_udp_encap_rcv_wrapper(struct sock *sk, struct sk_buff *skb)
+ {
+ 	struct udp_sock *up = udp_sk(sk);
+ 	struct udphdr *uh;
+ 	struct iphdr *iph;
+ 	int iphlen, len;
+ 	int ret;
+ 
+ 	__u8 *udpdata;
+ 	__be32 *udpdata32;
+ 	__u16 encap_type = up->encap_type;
+ 
+ 	/* if this is not encapsulated socket, then just return now */
+ 	if (!encap_type && !xfrm4_rcv_encap_func)
+ 		return 1;
+ 
+ 	/* If this is a paged skb, make sure we pull up
+ 	 * whatever data we need to look at. */
+ 	len = skb->len - sizeof(struct udphdr);
+ 	if (!pskb_may_pull(skb, sizeof(struct udphdr) + min(len, 8)))
+ 		return 1;
+ 
+ 	/* Now we can get the pointers */
+ 	uh = udp_hdr(skb);
+ 	udpdata = (__u8 *)uh + sizeof(struct udphdr);
+ 	udpdata32 = (__be32 *)udpdata;
+ 
+ 	switch (encap_type) {
+ 	default:
+ 	case UDP_ENCAP_ESPINUDP:
+ 		/* Check if this is a keepalive packet.  If so, eat it. */
+ 		if (len == 1 && udpdata[0] == 0xff) {
+ 			goto drop;
+ 		} else if (len > sizeof(struct ip_esp_hdr) && udpdata32[0] != 0) {
+ 			/* ESP Packet without Non-ESP header */
+ 			len = sizeof(struct udphdr);
+ 		} else
+ 			/* Must be an IKE packet.. pass it through */
+ 			return 1;
+ 		break;
+ 	case UDP_ENCAP_ESPINUDP_NON_IKE:
+ 		/* Check if this is a keepalive packet.  If so, eat it. */
+ 		if (len == 1 && udpdata[0] == 0xff) {
+ 			goto drop;
+ 		} else if (len > 2 * sizeof(u32) + sizeof(struct ip_esp_hdr) &&
+ 			   udpdata32[0] == 0 && udpdata32[1] == 0) {
+ 
+ 			/* ESP Packet with Non-IKE marker */
+ 			len = sizeof(struct udphdr) + 2 * sizeof(u32);
+ 		} else
+ 			/* Must be an IKE packet.. pass it through */
+ 			return 1;
+ 		break;
+ 	}
+ 
+ 	/* At this point we are sure that this is an ESPinUDP packet,
+ 	 * so we need to remove 'len' bytes from the packet (the UDP
+ 	 * header and optional ESP marker bytes) and then modify the
+ 	 * protocol to ESP, and then call into the transform receiver.
+ 	 */
+ 	if (skb_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+ 		goto drop;
+ 
+ 	/* Now we can update and verify the packet length... */
+ 	iph = ip_hdr(skb);
+ 	iphlen = iph->ihl << 2;
+ 	iph->tot_len = htons(ntohs(iph->tot_len) - len);
+ 	if (skb->len < iphlen + len) {
+ 		/* packet is too small!?! */
+ 		goto drop;
+ 	}
+ 
+ 	/* pull the data buffer up to the ESP header and set the
+ 	 * transport header to point to ESP.  Keep UDP on the stack
+ 	 * for later.
+ 	 */
+ 	__skb_pull(skb, len);
+ 	skb_reset_transport_header(skb);
+ 
+ 	/* modify the protocol (it's ESP!) */
+ 	iph->protocol = IPPROTO_ESP;
+ 
+ 	/* process ESP */
+ 	ret = (*xfrm4_rcv_encap_func)(skb, encap_type);
+ 	return ret;
+ 
+ drop:
+ 	kfree_skb(skb);
+ 	return 0;
+ }
+ 
+ int udp4_register_esp_rcvencap(xfrm4_rcv_encap_t func,
+ 		xfrm4_rcv_encap_t *oldfunc)
+ {
+ 	if (oldfunc != NULL)
+ 		*oldfunc = xfrm4_rcv_encap_func;
+ 	xfrm4_rcv_encap_func = func;
+ 	return 0;
+ }
+ 
+ int udp4_unregister_esp_rcvencap(xfrm4_rcv_encap_t func)
+ {
+ 	if (xfrm4_rcv_encap_func != func)
+ 		return -1;
+ 
+ 	xfrm4_rcv_encap_func = NULL;
+ 	return 0;
+ }
+ 
+ #endif /* CONFIG_XFRM_MODULE || CONFIG_IPSEC_NAT_TRAVERSAL */
+ 
  /* returns:
   *  -1: error
   *   0: success
***************
*** 1349,1355 ****
  		case 0:
  		case UDP_ENCAP_ESPINUDP:
  		case UDP_ENCAP_ESPINUDP_NON_IKE:
! 			up->encap_type = val;
  			break;
  		default:
  			err = -ENOPROTOOPT;
--- 1472,1483 ----
  		case 0:
  		case UDP_ENCAP_ESPINUDP:
  		case UDP_ENCAP_ESPINUDP_NON_IKE:
! #if defined(CONFIG_XFRM) || defined(CONFIG_IPSEC_NAT_TRAVERSAL)
! 			if (xfrm4_rcv_encap_func)
! 				up->encap_rcv = xfrm4_udp_encap_rcv_wrapper;
! 			else
! #endif
! 				up->encap_type = val;
  			break;
  		default:
  			err = -ENOPROTOOPT;
***************
*** 1742,1744 ****
--- 1870,1878 ----
  EXPORT_SYMBOL(udp_proc_register);
  EXPORT_SYMBOL(udp_proc_unregister);
  #endif
+ 
+ #if defined(CONFIG_IPSEC_NAT_TRAVERSAL)
+ EXPORT_SYMBOL(udp4_register_esp_rcvencap);
+ EXPORT_SYMBOL(udp4_unregister_esp_rcvencap);
+ #endif
+ 
