linux kernel support for ns-3-dce-umip
authorHajime Tazaki <tazaki@nict.go.jp>
Wed, 11 Jul 2012 20:31:37 +0900
changeset 61 84912269f151
parent 60 c435b32c2aa7
child 62 0f845b1aee21
linux kernel support for ns-3-dce-umip
Makefile
kernel-dsmip6.patch
sim/defconfig
sim/security.c
sim/tasklet-hrtimer.c
sim/tasklet.c
--- a/Makefile	Fri Jul 06 17:06:34 2012 +0900
+++ b/Makefile	Wed Jul 11 20:31:37 2012 +0900
@@ -133,7 +133,7 @@
 ALL_OBJS=$(OBJS) $(KERNEL_LIB) $(modules) $(all-obj-for-clean)
 clean: unpatch
 	@for f in $(foreach m,$(modules),$($(m))) ; do rm -f $$f 2>/dev/null; done
-	@for f in $(OBJS) $(KERNEL_LIB) $(modules); do rm -f $$f; done 2>/dev/null
+	@for f in $(OBJS) $(KERNEL_LIB) $(modules) $(all-obj-for-clean); do rm -f $$f; done 2>/dev/null
 	@rm -rf linker.lds $(AUTOCONF) objs.mk $(KERNEL_DIR)/.config timeconst.h 2>/dev/null
 
 $(KERNEL_LIB): setup objs.mk $(AUTOCONF) $(OBJS) linker.lds
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel-dsmip6.patch	Wed Jul 11 20:31:37 2012 +0900
@@ -0,0 +1,635 @@
+diff --git a/include/linux/in.h b/include/linux/in.h
+index 41d88a4..8eeb176 100644
+--- a/include/linux/in.h
++++ b/include/linux/in.h
+@@ -47,6 +47,8 @@ enum {
+   IPPROTO_SCTP   = 132,		/* Stream Control Transport Protocol	*/
+   IPPROTO_UDPLITE = 136,	/* UDP-Lite (RFC 3828)			*/
+ 
++#define  IPPROTO_UDP_ENCAPSULATION	166 /* IPv6 in UDP pseudo protocol for DSMIP */
++
+   IPPROTO_RAW	 = 255,		/* Raw IP packets			*/
+   IPPROTO_MAX
+ };
+diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
+index d89876b..e154c41 100644
+--- a/include/linux/skbuff.h
++++ b/include/linux/skbuff.h
+@@ -309,6 +309,7 @@ typedef unsigned char *sk_buff_data_t;
+  *		done by skb DMA functions
+  *	@secmark: security marking
+  *	@vlan_tci: vlan tag control information
++ *	@udp_encap_info: IPv4 source address and UDP port for NAT-traversal
+  */
+ 
+ struct sk_buff {
+@@ -367,6 +368,12 @@ struct sk_buff {
+ #ifdef CONFIG_BRIDGE_NETFILTER
+ 	struct nf_bridge_info	*nf_bridge;
+ #endif
++#ifdef CONFIG_INET_XFRM_UDP_ENCAP_NATT
++	struct	{
++		__be32		saddr;
++		__be16		sport;
++	}			udp_encap_info;
++#endif
+ 
+ 	int			skb_iif;
+ #ifdef CONFIG_NET_SCHED
+diff --git a/include/linux/udp.h b/include/linux/udp.h
+index 03f72a2..09d176c 100644
+--- a/include/linux/udp.h
++++ b/include/linux/udp.h
+@@ -34,6 +34,8 @@ struct udphdr {
+ #define UDP_ENCAP_ESPINUDP_NON_IKE	1 /* draft-ietf-ipsec-nat-t-ike-00/01 */
+ #define UDP_ENCAP_ESPINUDP	2 /* draft-ietf-ipsec-udp-encaps-06 */
+ #define UDP_ENCAP_L2TPINUDP	3 /* rfc2661 */
++#define UDP_ENCAP_IP_VANILLA	4 /* draft-ietf-mext-nemo-v4traversal-01 */
++#define UDP_ENCAP_TLV		5 /* draft-ietf-mext-nemo-v4traversal-01 */
+ 
+ #ifdef __KERNEL__
+ #include <net/inet_sock.h>
+diff --git a/include/net/xfrm.h b/include/net/xfrm.h
+index fc8f36d..31b5f29 100644
+--- a/include/net/xfrm.h
++++ b/include/net/xfrm.h
+@@ -35,6 +35,7 @@
+ #define XFRM_PROTO_IPV6		41
+ #define XFRM_PROTO_ROUTING	IPPROTO_ROUTING
+ #define XFRM_PROTO_DSTOPTS	IPPROTO_DSTOPTS
++#define XFRM_PROTO_UDP_ENCAPS	IPPROTO_UDP_ENCAPSULATION
+ 
+ #define XFRM_ALIGN8(len)	(((len) + 7) & ~7)
+ #define MODULE_ALIAS_XFRM_MODE(family, encap) \
+diff --git a/net/core/skbuff.c b/net/core/skbuff.c
+index 7da58a2..8890bf8 100644
+--- a/net/core/skbuff.c
++++ b/net/core/skbuff.c
+@@ -537,6 +537,10 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
+ 	new->ipvs_property	= old->ipvs_property;
+ #endif
+ 	new->protocol		= old->protocol;
++#ifdef CONFIG_INET_XFRM_UDP_ENCAP_NATT
++	new->udp_encap_info.saddr = old->udp_encap_info.saddr;
++	new->udp_encap_info.sport = old->udp_encap_info.sport;
++#endif
+ 	new->mark		= old->mark;
+ 	new->skb_iif		= old->skb_iif;
+ 	__nf_copy(new, old);
+diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
+index 7c3a7d1..cf20185 100644
+--- a/net/ipv4/Kconfig
++++ b/net/ipv4/Kconfig
+@@ -375,6 +375,25 @@ config INET_IPCOMP
+ 
+ 	  If unsure, say Y.
+ 
++config INET_XFRM_UDP_ENCAP
++	tristate "IP: UDP Encapsulation transformation"
++	select XFRM
++	select INET_XFRM_TUNNEL
++	---help---
++	  Support for UDP encapsulation over IPv4,
++    	  typically needed for DSMIPv6
++	  
++	  If unsure, say Y.
++
++config INET_XFRM_UDP_ENCAP_NATT
++	bool "IP: UDP Encapsulation transformation - NAT Traversal support"
++	depends on INET_XFRM_UDP_ENCAP
++	---help---
++	  Allow reporting of IP address and UDP port source of UDP encapsulated
++	  messages received on raw socket. Typical use is DSMIPv6 NAT Traversal.
++	  
++	  If unsure, say Y.
++
+ config INET_XFRM_TUNNEL
+ 	tristate
+ 	select INET_TUNNEL
+diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
+index 80ff87c..1372243 100644
+--- a/net/ipv4/Makefile
++++ b/net/ipv4/Makefile
+@@ -25,6 +25,7 @@ obj-$(CONFIG_SYN_COOKIES) += syncookies.o
+ obj-$(CONFIG_INET_AH) += ah4.o
+ obj-$(CONFIG_INET_ESP) += esp4.o
+ obj-$(CONFIG_INET_IPCOMP) += ipcomp.o
++obj-$(CONFIG_INET_XFRM_UDP_ENCAP) += xfrm4_udp_encap.o
+ obj-$(CONFIG_INET_XFRM_TUNNEL) += xfrm4_tunnel.o
+ obj-$(CONFIG_INET_XFRM_MODE_BEET) += xfrm4_mode_beet.o
+ obj-$(CONFIG_INET_LRO) += inet_lro.o
+diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
+index 32e0bef..acec4ed 100644
+--- a/net/ipv4/udp.c
++++ b/net/ipv4/udp.c
+@@ -1667,6 +1667,8 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
+ 		case 0:
+ 		case UDP_ENCAP_ESPINUDP:
+ 		case UDP_ENCAP_ESPINUDP_NON_IKE:
++		case UDP_ENCAP_IP_VANILLA:
++		case UDP_ENCAP_TLV:
+ 			up->encap_rcv = xfrm4_udp_encap_rcv;
+ 			/* FALLTHROUGH */
+ 		case UDP_ENCAP_L2TPINUDP:
+diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c
+index 06814b6..cbf1752 100644
+--- a/net/ipv4/xfrm4_input.c
++++ b/net/ipv4/xfrm4_input.c
+@@ -125,6 +125,15 @@ int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
+ 			/* Must be an IKE packet.. pass it through */
+ 			return 1;
+ 		break;
++	case UDP_ENCAP_IP_VANILLA:
++	case UDP_ENCAP_TLV:
++		/* Note: The keep-alive packets are real BU packets in DSMIPv6 */
++
++		/* Save the encapsulation type in skb control buffer */
++		*(int *)skb->cb = encap_type;
++
++		/* Let's parse the packet in a different handler */
++		return -IPPROTO_UDP_ENCAPSULATION;
+ 	}
+ 
+ 	/* At this point we are sure that this is an ESPinUDP packet,
+diff --git a/net/ipv4/xfrm4_udp_encap.c b/net/ipv4/xfrm4_udp_encap.c
+new file mode 100644
+index 0000000..7b69054
+--- /dev/null
++++ b/net/ipv4/xfrm4_udp_encap.c
+@@ -0,0 +1,434 @@
++#include <linux/err.h>
++#include <linux/module.h>
++#include <net/ip.h>
++#include <net/xfrm.h>
++#include <asm/scatterlist.h>
++#include <linux/kernel.h>
++#include <linux/pfkeyv2.h>
++#include <linux/random.h>
++#include <net/icmp.h>
++#include <net/protocol.h>
++#include <net/udp.h>
++#include <net/inet_ecn.h>
++#include <linux/netfilter.h>
++#include <linux/netfilter_ipv4.h>
++#include <linux/in.h>
++
++/* TLV as defined in draft-ietf-mext-nemo-v4traversal-01 */
++struct tlvhdr {
++	__u8		type;
++	__u8		length;	/* Note that this is probably too small and will be changed */
++	__u16		reserved;
++};
++
++enum tlv_type_t {
++	UDP_ENCAP_TLV_IPV4	= 1,
++	UDP_ENCAP_TLV_IPV6	= 2,
++	UDP_ENCAP_TLV_IPSEC	= 3,
++	UDP_ENCAP_TLV_GRE	= 4
++};
++
++/* Compute the type value for TLV from the packet inside.
++  - Only IPv4 and IPv6 are supported yet.
++  Returns 0 on success, <0 on error.
++*/
++static int get_tlv_type_from_packet(__u8 * type, __u8 * packet)
++{
++	struct iphdr * ip = (struct iphdr *)packet;
++	/* There is maybe a better way to find the protocol, in the skb struct for example... */
++	switch (ip->version) {
++		case 4:
++			*type = UDP_ENCAP_TLV_IPV4;
++			break;
++
++		case 6:
++			*type = UDP_ENCAP_TLV_IPV6;
++			break;
++
++		default:
++			printk(KERN_INFO "Unrecognized packet in %s: %x\n", __FUNCTION__, *packet);
++			return -EINVAL;
++	}
++
++	return 0;
++}
++
++
++static int udp_encap_output(struct xfrm_state *x, struct sk_buff *skb)
++{
++	struct udphdr *uh;
++	struct iphdr *top_iph;
++
++	printk(KERN_INFO "xfrm_type: udp_encap_output entered\n");
++
++	skb_push(skb, -skb_network_offset(skb));
++
++        //	top_iph = (struct iphdr *) skb->network_header;
++        top_iph = ip_hdr(skb);
++	top_iph->tot_len = htons(skb->len);
++	/* this is non-NULL only with UDP Encapsulation */
++	if (x->encap) {
++		struct xfrm_encap_tmpl *encap = x->encap;
++
++		uh = (struct udphdr *) (top_iph + 1);
++		uh->source = encap->encap_sport;
++		uh->dest = encap->encap_dport;
++		uh->len = htons(skb->len - top_iph->ihl*4);
++		uh->check = 0;
++
++		top_iph->protocol = IPPROTO_UDP;
++
++		if (encap->encap_type == UDP_ENCAP_TLV) {
++			/* We must also add the TLV header here */
++			struct tlvhdr * tlvh = (struct tlvhdr *)(uh + 1);
++
++			if (get_tlv_type_from_packet(&tlvh->type,(__u8 *)(tlvh+1)))
++				return -EINVAL;
++
++			tlvh->length = skb->len - x->props.header_len;
++			tlvh->reserved = 0;
++		}
++	}
++
++	ip_send_check(top_iph);
++
++	return 0;
++}
++
++static int udp_encap_input(struct xfrm_state *x, struct sk_buff *skb)
++{
++	printk(KERN_INFO "udp_encap_input should not have been called\n");
++	return 0;
++}
++
++static u32 udp_encap_get_mtu(struct xfrm_state *x, int mtu)
++{ /* XXX : check if sizeof(udphdr) is accounted for */
++	return mtu + x->props.header_len;
++}
++
++static void udp_encap_proto_err(struct sk_buff *skb, u32 info)
++{
++	printk("udp_encap error : got an error by udp_encap_err...\n");
++}
++
++/* This function will reset some flags on the skb and resubmit as IP packet
++ * It is inspired from ipip_rcv
++ * Return 0 on success, -1 if packet must be dropped.
++ */
++static int resubmit_as_ip(struct sk_buff *skb, struct iphdr *top_iph)
++{
++	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
++		return -1;	/* No space for IP header. */
++
++	secpath_reset(skb);
++
++	skb->protocol = htons(ETH_P_IP);
++	skb->pkt_type = PACKET_HOST;
++
++	dst_release(skb_dst(skb));
++	skb_dst_set (skb, NULL);
++	nf_reset(skb);
++
++	if (INET_ECN_is_ce(top_iph->tos))
++		IP_ECN_set_ce(ip_hdr(skb));
++
++	netif_rx(skb);
++
++	return 0;
++}
++/* This function will reset some flags on the skb and resubmit as IPv6 packet
++ * It is inspired from ipip6_rcv
++ * Return 0 on success, -1 if packet must be dropped.
++ */
++static int resubmit_as_ipv6(struct sk_buff *skb, struct iphdr *top_iph)
++{
++	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
++		return -1;	/* No space for IPv6 header. */
++
++	secpath_reset(skb);
++
++	IPCB(skb)->flags = 0;
++	skb->protocol = htons(ETH_P_IPV6);
++	skb->pkt_type = PACKET_HOST;
++
++	dst_release(skb_dst(skb));
++	skb_dst_set (skb, NULL);
++	nf_reset(skb);
++
++	if (INET_ECN_is_ce(top_iph->tos))
++		IP6_ECN_set_ce(ipv6_hdr(skb));
++
++	netif_rx(skb);
++
++	return 0;
++}
++
++/* This function tries to find what kind of packet is in the UDP payload.
++ * It returns the IPPROTO_* value of the protocol, or -1 on error.
++ */
++static int find_inside_proto(struct sk_buff *skb)
++{
++	struct tlvhdr * tlvh;
++
++	switch (*(int *)skb->cb) {
++		case UDP_ENCAP_IP_VANILLA:
++			if (!pskb_may_pull(skb, sizeof(__u8)))
++				return -1; /* No space for anything. */
++
++			switch (ip_hdr(skb)->version) {
++				case 4: /* IP in the UDP vanilla encapsulation */
++					return IPPROTO_IP;
++
++				case 6: /* IPv6 in the UDP packet */
++					return IPPROTO_IPV6;
++
++				default:
++					printk(KERN_DEBUG "Unexpected UDP content (start with %x), dropped\n", *(int *)ip_hdr(skb));
++			}
++			break;
++
++		case UDP_ENCAP_TLV:
++			if (!pskb_may_pull(skb, sizeof(struct tlvhdr)))
++				return -1; /* No space for TLV header. */
++
++			tlvh = (struct tlvhdr *)skb_network_header(skb);
++
++			/* Eat the TLV header */
++			skb_pull(skb, sizeof(struct tlvhdr));
++			skb_reset_network_header(skb);
++
++			switch (tlvh->type) {
++				case UDP_ENCAP_TLV_IPV4:
++					return IPPROTO_IP;
++
++				case UDP_ENCAP_TLV_IPV6:
++					return IPPROTO_IPV6;
++
++				case UDP_ENCAP_TLV_IPSEC:
++					return IPPROTO_ESP;
++
++				case UDP_ENCAP_TLV_GRE:
++					return IPPROTO_GRE;
++
++				default:
++					printk(KERN_DEBUG "Unexpected type in TLV (%d), dropped\n", tlvh->type);
++			}
++			break;
++
++		default:
++			printk(KERN_DEBUG "Unexpected encap_type (%x)\n", *(int *)skb->cb);
++	}
++	/* Protocol not found */
++	return -1;
++}
++
++/* Eat the routing headers and ip options of IPv6 packet to find the next protocol */
++static int find_ipv6_payload_type (struct sk_buff *skb, __u8 *next)
++{
++	struct ipv6hdr * ip6h = ipv6_hdr(skb);
++	size_t hdrlen = sizeof(struct ipv6hdr);
++	__u8 * p = (__u8 *)(ip6h+1);
++
++	printk(KERN_DEBUG "%s:%d - %s ( inspecting packet )\n", __FILE__, __LINE__, __FUNCTION__);
++
++	if (!pskb_may_pull(skb, hdrlen))
++		return -1;	/* No space for IPv6 header. */
++
++	*next = ip6h->nexthdr;
++
++next_hdr:
++	switch (*next) {
++		case IPPROTO_HOPOPTS:	/* IPv6 hop-by-hop options	*/
++		case IPPROTO_ROUTING:	/* IPv6 routing header		*/
++		/* case IPPROTO_FRAGMENT:*/	/* IPv6 fragmentation header	*/
++		case IPPROTO_DSTOPTS:	/* IPv6 destination options	*/
++		/* We have to eat this and go on */
++			if (!pskb_may_pull(skb, hdrlen + 2))
++				return -1;	/* could not get to hdr len. */
++			if (!pskb_may_pull(skb, hdrlen + ipv6_optlen((struct ipv6_opt_hdr *)p)))
++				return -1;	/* could not get the full option. */
++			*next = *p;
++			hdrlen 	+= ipv6_optlen((struct ipv6_opt_hdr *)p);
++			p 	+= ipv6_optlen((struct ipv6_opt_hdr *)p);
++			goto next_hdr;
++	}
++	/* We found the last header, return this */
++	printk(KERN_DEBUG "%s:%d - %s ( final header: %d )\n", __FILE__, __LINE__, __FUNCTION__, *next);
++	return 0;
++}
++
++
++static int udp_encap_proto_input(struct sk_buff *skb)
++{
++	struct net *net = sock_net(skb->sk);
++	struct iphdr *top_iph = ip_hdr(skb);
++	int proto=0;
++	struct xfrm_state *x;
++	int accept=0;
++	__u8 next=0;
++#ifdef CONFIG_INET_XFRM_UDP_ENCAP_NATT
++	__be32 saddr = top_iph->saddr;
++	struct udphdr *uh = udp_hdr(skb);
++#endif
++
++	/* This function was called by ip_local_deliver_finish after
++	    udp_rcv has resubmitted the skb */
++	printk(KERN_DEBUG "%s:%d - %s ( enter )\n", __FILE__, __LINE__, __FUNCTION__);
++
++	/* Check it's a real UDP packet that was resubmitted */
++	if (top_iph->protocol != IPPROTO_UDP) {
++		printk(KERN_DEBUG "Bad packet, dropped (proto %d)\n", top_iph->protocol);
++		goto drop;
++	}
++
++	/* We know here the packet has gone through UDP checks and is valid. */
++
++	/* Let's find if we have some XFRM state for this packet. */
++	x = xfrm_state_lookup_byaddr(	net, skb->mark, (xfrm_address_t *)&top_iph->daddr,
++					(xfrm_address_t *)&top_iph->saddr,
++					IPPROTO_UDP_ENCAPSULATION,
++					AF_INET);
++	if (x != NULL) {
++		printk(KERN_DEBUG "%s:%d - %s ( state found: accept packet )\n", __FILE__, __LINE__, __FUNCTION__);
++		/* We have a valid state for this packet, it means that the v4 coa of MN is registered */
++		accept = 1;
++		xfrm_state_put(x);
++	}
++
++	/* Let's eat the UDP header -- TLV will be eaten later */
++	skb_pull(skb, sizeof(struct udphdr));
++
++	/* And update the internal skb pointers */
++	skb->mac_header = skb->network_header;
++	skb_reset_network_header(skb);
++
++#ifdef CONFIG_INET_XFRM_UDP_ENCAP_NATT
++	/* We must save saddr and ntohs(uh->source) as ancialliary data here */
++	printk(KERN_DEBUG "Saving source %u.%u.%u.%u:%u into skb\n", NIPQUAD(saddr), ntohs(uh->source));
++	skb->udp_encap_info.saddr = saddr;
++	skb->udp_encap_info.sport = uh->source;
++#endif
++
++	/* Now the inside is either IP or IPv6. We will do as in ipip_rcv or ipip6_rcv accordingly */
++	proto = find_inside_proto(skb);
++	switch (proto) {
++		case IPPROTO_IP: /* IP in the UDP vanilla encapsulation */
++			if (!accept)
++				goto drop;
++			goto ipv4;
++
++		case IPPROTO_IPV6: /* IPv6 in the UDP packet */
++			if (!accept)
++				goto look_inside;
++			goto ipv6;
++
++		default:
++			printk(KERN_DEBUG "Unsupported protocol (%d), dropped\n", proto);
++	}
++	goto drop;
++ipv4:
++	if (resubmit_as_ip(skb, top_iph) < 0)
++		goto drop;
++	goto end;
++
++look_inside:
++	/* We have received a new packet from unknown source. We check it contains
++	   either ESP or MH; otherwise we discard it. */
++	if (find_ipv6_payload_type (skb, &next) < 0)
++		goto drop;
++	switch (next) {
++		case IPPROTO_MH:	/* we accept all MH */
++		case IPPROTO_ESP:	/* We also accept ESP and AH since they will be */
++		case IPPROTO_AH:	/* discarded if no IPsec policy corresponds */
++			break;
++		default:
++			printk(KERN_DEBUG "Unsupported inside protocol (%d), dropped\n", next);
++			goto drop;
++	}
++
++ipv6:
++	if (resubmit_as_ipv6(skb, top_iph) < 0)
++		goto drop;
++	goto end;
++
++drop:
++	kfree_skb(skb);
++end:
++	return 0;
++}
++
++static void udp_encap_destroy(struct xfrm_state *x)
++{
++        return;
++}
++
++static int udp_encap_init_state(struct xfrm_state *x)
++{
++	if (x->props.mode != XFRM_MODE_TUNNEL)
++	        return -EINVAL;
++
++	if (!x->encap) /* Is this possible? */
++		return -EINVAL;
++
++	switch (x->encap->encap_type) {
++		case UDP_ENCAP_IP_VANILLA:
++			x->props.header_len = sizeof(struct iphdr) + sizeof(struct udphdr);
++			break;
++		case UDP_ENCAP_TLV:
++			x->props.header_len = sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(struct tlvhdr);
++		default:
++		        return -EINVAL;
++	}
++
++	return 0;
++}
++
++
++static struct xfrm_type udp_encap_type =
++{
++	.description	= "UDP4",
++	.owner		= THIS_MODULE,
++	.proto	     	= IPPROTO_UDP_ENCAPSULATION,
++	.init_state	= udp_encap_init_state,
++	.destructor	= udp_encap_destroy,
++	.get_mtu	= udp_encap_get_mtu,
++	.input		= udp_encap_input, /* can we remove this? */
++	.output		= udp_encap_output
++};
++
++static struct net_protocol udp_encap_protocol = {
++	.handler	=	udp_encap_proto_input,
++	.err_handler	=	udp_encap_proto_err,
++	.no_policy	=	1,
++};
++
++static int __init udp_encap_init(void)
++{
++	printk(KERN_INFO "registering udp_encap type and protocol handler\n");
++
++	if (xfrm_register_type(&udp_encap_type, AF_INET) < 0) {
++		printk(KERN_INFO "ip udp_encap init: can't add xfrm type\n");
++		return -EAGAIN;
++	}
++
++	if (inet_add_protocol(&udp_encap_protocol, IPPROTO_UDP_ENCAPSULATION) < 0) {
++ 		printk(KERN_INFO "ip udp_encap init: can't add protocol\n");
++ 		xfrm_unregister_type(&udp_encap_type, AF_INET);
++ 		return -EAGAIN;
++ 	}
++
++	return 0;
++}
++
++static void __exit udp_encap_fini(void)
++{
++ 	if (inet_del_protocol(&udp_encap_protocol, IPPROTO_UDP_ENCAPSULATION) < 0)
++ 		printk(KERN_INFO "ip udp_encap close: can't remove protocol\n");
++	if (xfrm_unregister_type(&udp_encap_type, AF_INET) < 0)
++		printk(KERN_INFO "ip udp_encap close: can't remove xfrm type\n");
++}
++
++module_init(udp_encap_init);
++module_exit(udp_encap_fini);
++MODULE_LICENSE("GPL");
++MODULE_ALIAS_XFRM_TYPE(AF_INET, XFRM_PROTO_UDP_ENCAPS);
+diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
+index 7d929a2..b325d7a 100644
+--- a/net/ipv6/datagram.c
++++ b/net/ipv6/datagram.c
+@@ -543,6 +543,16 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
+ 			off += len;
+ 		}
+ 	}
++#ifdef CONFIG_INET_XFRM_UDP_ENCAP_NATT
++	if (skb->udp_encap_info.saddr != 0) {
++		struct sockaddr_in sin;
++		sin.sin_family      = AF_INET;
++		sin.sin_port        = skb->udp_encap_info.sport;
++		sin.sin_addr.s_addr = skb->udp_encap_info.saddr;
++		printk("Seb: %s:%d/%s: %u.%u.%u.%u:%d\n", __FILE__, __LINE__,__FUNCTION__, NIPQUAD(skb->udp_encap_info.saddr), ntohs(skb->udp_encap_info.sport));
++		put_cmsg(msg, IPPROTO_UDP_ENCAPSULATION, 0, sizeof(sin), &sin);
++	}
++#endif
+ 
+ 	/* socket options in old style */
+ 	if (np->rxopt.bits.rxoinfo) {
+diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
+index ba59983..3c9938b 100644
+--- a/net/xfrm/xfrm_user.c
++++ b/net/xfrm/xfrm_user.c
+@@ -176,6 +176,16 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
+ 			goto out;
+ 		break;
+ 
++	case IPPROTO_UDP_ENCAPSULATION:
++		if (attrs[XFRMA_ALG_COMP]	||
++		    attrs[XFRMA_ALG_AUTH]	||
++		    attrs[XFRMA_ALG_CRYPT]	||
++		    !attrs[XFRMA_ENCAP]		||
++		    attrs[XFRMA_SEC_CTX]	||
++		    attrs[XFRMA_COADDR])
++			goto out;
++		break;
++
+ #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ 	case IPPROTO_DSTOPTS:
+ 	case IPPROTO_ROUTING:
--- a/sim/defconfig	Fri Jul 06 17:06:34 2012 +0900
+++ b/sim/defconfig	Wed Jul 11 20:31:37 2012 +0900
@@ -38,11 +38,15 @@
 # Networking options
 #
 CONFIG_PACKET=y
-CONFIG_UNIX=m
+CONFIG_UNIX=y
 CONFIG_XFRM=y
-CONFIG_XFRM_USER=m
-CONFIG_XFRM_IPCOMP=m
-CONFIG_NET_KEY=m
+CONFIG_XFRM_USER=y
+CONFIG_XFRM_IPCOMP=y
+CONFIG_XFRM_SUB_POLICY=y
+CONFIG_XFRM_MIGRATE=y
+CONFIG_XFRM_STATISTICS=y
+CONFIG_NET_KEY=y
+CONFIG_NET_KEY_MIGRATE=y
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
 CONFIG_IP_ADVANCED_ROUTER=y
@@ -65,11 +69,13 @@
 CONFIG_INET_AH=m
 CONFIG_INET_ESP=m
 CONFIG_INET_IPCOMP=m
-CONFIG_INET_XFRM_TUNNEL=m
-CONFIG_INET_TUNNEL=m
-CONFIG_INET_XFRM_MODE_TRANSPORT=m
-CONFIG_INET_XFRM_MODE_TUNNEL=m
-CONFIG_INET_XFRM_MODE_BEET=m
+CONFIG_INET_XFRM_TUNNEL=y
+CONFIG_INET_TUNNEL=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_XFRM_UDP_ENCAP=y
+CONFIG_INET_XFRM_UDP_ENCAP_NATT=y
 # CONFIG_INET_LRO is not set
 CONFIG_INET_DIAG=m
 CONFIG_INET_TCP_DIAG=m
@@ -93,14 +99,19 @@
 CONFIG_INET6_AH=m
 CONFIG_INET6_ESP=m
 CONFIG_INET6_IPCOMP=m
-CONFIG_INET6_XFRM_TUNNEL=m
-CONFIG_INET6_TUNNEL=m
-CONFIG_INET6_XFRM_MODE_TRANSPORT=m
-CONFIG_INET6_XFRM_MODE_TUNNEL=m
-CONFIG_INET6_XFRM_MODE_BEET=m
-CONFIG_IPV6_SIT=m
+CONFIG_INET6_XFRM_TUNNEL=y
+CONFIG_INET6_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_BEET=y
+CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=y
+CONFIG_IPV6_SIT=y
 CONFIG_IPV6_NDISC_NODETYPE=y
-CONFIG_IPV6_TUNNEL=m
+CONFIG_IPV6_TUNNEL=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+
 # CONFIG_NETWORK_SECMARK is not set
 # CONFIG_NETFILTER is not set
 CONFIG_ATM=m
--- a/sim/security.c	Fri Jul 06 17:06:34 2012 +0900
+++ b/sim/security.c	Wed Jul 11 20:31:37 2012 +0900
@@ -9,6 +9,7 @@
   {
     case CAP_NET_RAW:
     case CAP_NET_BIND_SERVICE:
+    case CAP_NET_ADMIN:
 	 return 1;
 
     default: break;
--- a/sim/tasklet-hrtimer.c	Fri Jul 06 17:06:34 2012 +0900
+++ b/sim/tasklet-hrtimer.c	Wed Jul 11 20:31:37 2012 +0900
@@ -1,5 +1,24 @@
 #include <linux/interrupt.h>
+#include "sim.h"
 #include "sim-assert.h"
+
+static enum hrtimer_restart __hrtimer_tasklet_trampoline(struct hrtimer *timer)
+{
+  struct tasklet_hrtimer *ttimer =
+    container_of(timer, struct tasklet_hrtimer, timer);
+
+  tasklet_schedule(&ttimer->tasklet);
+  return HRTIMER_NORESTART;
+}
+static void __tasklet_hrtimer_trampoline(unsigned long data)
+{
+  struct tasklet_hrtimer *ttimer = (void *)data;
+  enum hrtimer_restart restart;
+
+  restart = ttimer->function(&ttimer->timer);
+  if (restart != HRTIMER_NORESTART)
+    hrtimer_restart(&ttimer->timer);
+}
 /**
  * tasklet_hrtimer_init - Init a tasklet/hrtimer combo for softirq callbacks
  * @ttimer:      tasklet_hrtimer which is initialized
@@ -11,12 +30,18 @@
                           enum hrtimer_restart (*function)(struct hrtimer *),
                           clockid_t which_clock, enum hrtimer_mode mode)
 {
-  sim_assert (false);
-#if 0
   hrtimer_init(&ttimer->timer, which_clock, mode);
   ttimer->timer.function = __hrtimer_tasklet_trampoline;
   tasklet_init(&ttimer->tasklet, __tasklet_hrtimer_trampoline,
 	       (unsigned long)ttimer);
   ttimer->function = function;
-#endif
 }
+
+void __tasklet_hi_schedule(struct tasklet_struct *t)
+{
+  // Note: no need to set TASKLET_STATE_SCHED because it is set by caller.
+  sim_assert (t->next == 0);
+  // run the tasklet at the next immediately available opportunity.
+  void *event = sim_event_schedule_ns (0, (void *)&t->func, (void *)t->data);
+  t->next = event;
+}
--- a/sim/tasklet.c	Fri Jul 06 17:06:34 2012 +0900
+++ b/sim/tasklet.c	Wed Jul 11 20:31:37 2012 +0900
@@ -14,8 +14,6 @@
 
 void tasklet_kill(struct tasklet_struct *t)
 {
-  sim_assert (false);
-#if 0
   // theoretically, called from user context
   while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {
     do {
@@ -23,7 +21,6 @@
     } while (test_bit(TASKLET_STATE_SCHED, &t->state));
   }
   clear_bit(TASKLET_STATE_SCHED, &t->state);
-#endif
 }
 static void trampoline (void *context)
 {