--- plain26/net/ipv4/udp.c.orig	2006-12-28 20:53:17.000000000 -0500
+++ plain26/net/ipv4/udp.c	2007-05-11 10:22:50.000000000 -0400
@@ -108,6 +108,7 @@
 #include <net/inet_common.h>
 #include <net/checksum.h>
 #include <net/xfrm.h>
+#include <net/xfrmudp.h>
 
 /*
  *	Snmp MIB for the UDP layer
@@ -881,6 +882,31 @@
 	sk_common_release(sk);
 }
 
+#if defined(CONFIG_XFRM) || defined(CONFIG_IPSEC_NAT_TRAVERSAL)
+
+static xfrm4_rcv_encap_t xfrm4_rcv_encap_func = NULL;
+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, xfrm4_rcv_encap_t old)
+{
+  if(xfrm4_rcv_encap_func != func)
+    return -1;
+
+  xfrm4_rcv_encap_func = old;
+  return 0;
+}
+#endif /* CONFIG_XFRM_MODULE || CONFIG_IPSEC_NAT_TRAVERSAL */
+
+
 /* return:
  * 	1  if the the UDP system should process it
  *	0  if we should drop this packet
@@ -888,9 +914,9 @@
  */
 static int udp_encap_rcv(struct sock * sk, struct sk_buff *skb)
 {
-#ifndef CONFIG_XFRM
+#if !defined(CONFIG_XFRM) && !defined(CONFIG_IPSEC_NAT_TRAVERSAL)
 	return 1; 
-#else
+#else /* either CONFIG_XFRM or CONFIG_IPSEC_NAT_TRAVERSAL */
 	struct udp_sock *up = udp_sk(sk);
   	struct udphdr *uh;
 	struct iphdr *iph;
@@ -1018,10 +1044,27 @@
 			return 0;
 		}
 		if (ret < 0) {
-			/* process the ESP packet */
-			ret = xfrm4_rcv_encap(skb, up->encap_type);
-			UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS);
-			return -ret;
+ 			if(xfrm4_rcv_encap_func != NULL)
+				ret = (*xfrm4_rcv_encap_func)(skb, up->encap_type);
+	
+			switch(ret) {
+			case 1:
+				/* FALLTHROUGH to send-up */;
+				break;
+				
+			case 0:
+                                /* PROCESSED, free it */
+				UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS);
+				return 0;
+				
+			case -1:
+				/* PACKET wasn't for _func, or no func, pass it
+				 * to stock function
+				 */
+				ret = xfrm4_rcv_encap(skb, up->encap_type);
+				UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS);
+				return -ret;
+			}
 		}
 		/* FALLTHROUGH -- it's a UDP Packet */
 	}
@@ -1110,7 +1153,6 @@
 /*
  *	All we need to do is get the socket, and then do a checksum. 
  */
- 
 int udp_rcv(struct sk_buff *skb)
 {
   	struct sock *sk;
@@ -1599,3 +1641,9 @@
 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
+
