[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

(usagi-users 03970) Patch for NEMO IPsec



# Sorry for cross-posting, I don't know which list is most appropriate
for NEMO patches.

Hi all,

This is a patch to apply on top of NEMO BS patch [1]. Currently, when
TunnelPayload protection is set in the Mobile Router mip6d.conf file,
the traffic to the MR is protected, but traffic that is directed to a
MNN is sent in clear between MR and HA.

The attached patch fixes this by adding IPsec policies to protect also
the traffic to and from the MNP.

Pre-compiled binaries of the mip6d daemon including this patch (and
others) can be found on the Nautilus6 repository [2].

Best regards,
Sebastien.

[1] NEPL patch http://software.nautilus6.org/NEPL-UMIP/
[2] http://software.nautilus6.org/packages/gutsy/

PS: The patch is splitted in three files:

(NEMO-IPsec-common.patch)
Adds the ability to specify prefix length in selectors in ipsec.c

(NEMO-IPsec-HA.patch)
The modifications needed on the HA to insert the following rules when
a MR registers with some MNP.
		prio=10 dir=OUT src=ANY dst=MNP IPsec
		prio=10 dir=FWD src=MNP dst=ANY IPsec
		prio=10 dir=IN  src=MNP dst=ANY IPsec

(NEMO-IPsec-MR.patch)
The modifications needed on the MR to insert the following rules
When the MR starts:
		prio=09 dir=OUT src=ANY dst=MNP None (bypass)
		prio=09 dir=FWD src=MNP dst=ANY None (bypass)
		prio=09 dir=IN  src=MNP dst=ANY None (bypass)
When the MR is in foreign link:
		prio=10 dir=OUT src=MNP dst=ANY IPsec
		prio=10 dir=FWD src=ANY dst=MNP IPsec
		prio=10 dir=IN  src=ANY dst=MNP IPsec




-- 
Sebastien Decugis
http://www.nautilus6.org
diff -Nur trunk.ori/src/ipsec.c trunk.common-mod/src/ipsec.c
--- trunk.ori/src/ipsec.c	2007-10-12 16:19:30.000000000 +0900
+++ trunk.common-mod/src/ipsec.c	2007-10-16 11:42:33.000000000 +0900
@@ -81,7 +81,9 @@
 		    struct ipsec_policy_entry *e,
 		    int dir,
 		    const struct in6_addr *in6_dst,
+		    int  dst_len,
 		    const struct in6_addr *in6_src,
+		    int src_len,
 		    int ifindex,
 		    int nodetype)
 {
@@ -97,10 +99,13 @@
 	sp->action = e->action;
 	memcpy(&sp->sel.saddr.a6, in6_src, sizeof(sp->sel.saddr.a6));
 	memcpy(&sp->sel.daddr.a6, in6_dst, sizeof(sp->sel.daddr.a6));
-	sp->sel.prefixlen_s = IN6_ARE_ADDR_EQUAL(in6_src, &in6addr_any) ?
-				0 : 128;
-	sp->sel.prefixlen_d = IN6_ARE_ADDR_EQUAL(in6_dst, &in6addr_any) ?
-				0 : 128;
+	sp->sel.prefixlen_s = src_len;
+	if (!src_len && (!IN6_ARE_ADDR_EQUAL(in6_src, &in6addr_any)))
+		sp->sel.prefixlen_s = 128;
+	sp->sel.prefixlen_d = dst_len;
+	if (!dst_len && (!IN6_ARE_ADDR_EQUAL(in6_dst, &in6addr_any)))
+		sp->sel.prefixlen_d = 128;
+	
 	sp->sel.ifindex = 0;
 
 	switch (e->type) {
@@ -405,7 +410,7 @@
 	/* inbound */
 	_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
 		  haaddr, oldcoa, e->reqid_toha);
-	_set_sp(&sp, e, XFRM_POLICY_IN, &in6addr_any, hoa,
+	_set_sp(&sp, e, XFRM_POLICY_IN, &in6addr_any, 0, hoa, 0,
 		ifindex, MIP6_ENTITY_HA);
 	if ((err = xfrm_sendmigrate(&sp, &tmpl, haaddr, newcoa)) < 0) {
 		dbg("migrate for INBOUND policy failed\n");
@@ -415,7 +420,7 @@
 	/* forward */
 	_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
 		  haaddr, oldcoa, e->reqid_toha);
-	_set_sp(&sp, e, XFRM_POLICY_FWD, &in6addr_any, hoa,
+	_set_sp(&sp, e, XFRM_POLICY_FWD, &in6addr_any, 0, hoa, 0,
 		ifindex, MIP6_ENTITY_HA);
 	if ((err = xfrm_sendmigrate(&sp, &tmpl, haaddr, newcoa)) < 0) {
 		dbg("migrate for FORWARD policy failed\n");
@@ -425,7 +430,7 @@
 	/* outbound */
 	_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
 		  oldcoa, haaddr, e->reqid_tomn);
-	_set_sp(&sp, e, XFRM_POLICY_OUT, hoa, &in6addr_any,
+	_set_sp(&sp, e, XFRM_POLICY_OUT, hoa, 0, &in6addr_any, 0,
 		ifindex, MIP6_ENTITY_HA);
 	if ((err = xfrm_sendmigrate(&sp, &tmpl, newcoa, haaddr)) < 0) {
 		dbg("migrate for OUTBOUND policy failed\n");
@@ -493,7 +498,7 @@
 	dump_migrate(ifindex, ipsec_proto, hoa, haaddr, NULL, NULL);
 
 	/* inbound */
-	_set_sp(&sp, e, XFRM_POLICY_IN, &in6addr_any, hoa,
+	_set_sp(&sp, e, XFRM_POLICY_IN, &in6addr_any, 0, hoa, 0,
 		ifindex, MIP6_ENTITY_HA);
 	_set_tmpl(&tmpl, AF_INET6, ipsec_proto, XFRM_MODE_TUNNEL,
 		  haaddr, hoa, e->reqid_toha);
@@ -504,7 +509,7 @@
 	}
 
 	/* forward */
-	_set_sp(&sp, e, XFRM_POLICY_FWD, &in6addr_any, hoa,
+	_set_sp(&sp, e, XFRM_POLICY_FWD, &in6addr_any, 0, hoa, 0,
 		ifindex, MIP6_ENTITY_HA);
 	_set_tmpl(&tmpl, AF_INET6, ipsec_proto, XFRM_MODE_TUNNEL,
 		  haaddr, hoa, e->reqid_toha);
@@ -515,7 +520,7 @@
 	}
 
 	/* outbound */
-	_set_sp(&sp, e, XFRM_POLICY_OUT, hoa, &in6addr_any,
+	_set_sp(&sp, e, XFRM_POLICY_OUT, hoa, 0, &in6addr_any, 0,
 		ifindex, MIP6_ENTITY_HA);
 	_set_tmpl(&tmpl, AF_INET6, ipsec_proto, XFRM_MODE_TUNNEL,
 		  hoa, haaddr, e->reqid_tomn);
@@ -631,7 +636,7 @@
 	/* outbound */
 	_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
 		  haaddr, oldcoa, e->reqid_toha);
-	_set_sp(&sp, e, XFRM_POLICY_OUT, &in6addr_any, hoa,
+	_set_sp(&sp, e, XFRM_POLICY_OUT, &in6addr_any, 0, hoa, 0,
 		ifindex, MIP6_ENTITY_MN);
 	if ((err = xfrm_sendmigrate(&sp, &tmpl, haaddr, newcoa)) < 0) {
 		dbg("migrate for OUTBOUND policy failed\n");
@@ -641,7 +646,7 @@
 	/* inbound */
 	_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
 		  oldcoa, haaddr, e->reqid_tomn);
-	_set_sp(&sp, e, XFRM_POLICY_IN, hoa, &in6addr_any,
+	_set_sp(&sp, e, XFRM_POLICY_IN, hoa, 0, &in6addr_any, 0,
 		ifindex, MIP6_ENTITY_MN);
 	if ((err = xfrm_sendmigrate(&sp, &tmpl, newcoa, haaddr)) < 0) {
 		dbg("migrate for INBOUND policy (1) failed\n");
@@ -657,7 +662,7 @@
 		/* template */
 		_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
 			  oldcoa, haaddr, e->reqid_tomn);
-		_set_sp(&sp, e, XFRM_POLICY_IN, hoa, &in6addr_any,
+		_set_sp(&sp, e, XFRM_POLICY_IN, hoa, 0, &in6addr_any, 0,
 			ifindex, MIP6_ENTITY_MN);
 		/* additional settings */
 		sp.priority = MIP6_PRIO_RO_SIG_IPSEC;
@@ -724,7 +729,7 @@
 	dump_migrate(ifindex, ipsec_proto, hoa, haaddr, NULL, NULL);
 
 	/* inbound */
-	_set_sp(&sp, e, XFRM_POLICY_IN, hoa, &in6addr_any,
+	_set_sp(&sp, e, XFRM_POLICY_IN, hoa, 0, &in6addr_any, 0,
 		ifindex, MIP6_ENTITY_MN);
 	_set_tmpl(&tmpl, AF_INET6, ipsec_proto, XFRM_MODE_TUNNEL,
 		  hoa, haaddr, e->reqid_tomn);
@@ -735,7 +740,7 @@
 	}
 		
 	/* outbound */
-	_set_sp(&sp, e, XFRM_POLICY_OUT, &in6addr_any, hoa,
+	_set_sp(&sp, e, XFRM_POLICY_OUT, &in6addr_any, 0, hoa, 0,
 		ifindex, MIP6_ENTITY_MN);
 	_set_tmpl(&tmpl, AF_INET6, ipsec_proto, XFRM_MODE_TUNNEL,
 		  haaddr, hoa, e->reqid_toha);
diff -Nur trunk.common-mod/src/ha.c trunk.ha/src/ha.c
--- trunk.common-mod/src/ha.c	2007-10-15 17:54:32.000000000 +0900
+++ trunk.ha/src/ha.c	2007-10-15 17:45:35.000000000 +0900
@@ -547,6 +547,7 @@
 static int home_tnl_del(int old_if, int new_if, struct home_tnl_ops_parm *p)
 {
 	const struct in6_addr *our_addr, *peer_addr, *coa, *old_coa;
+	struct list_head *mnp;
 
 	assert(old_if);
 
@@ -554,13 +555,14 @@
 	peer_addr = &p->bce->peer_addr;
 	coa = &p->bce->peer_addr;
 	old_coa = &p->bce->coa;
+	mnp = &(p->bce->mob_net_prefixes);
 
 	if (conf.UseMnHaIPsec) {
 		/* migrate */ 
 		ha_ipsec_tnl_update(our_addr, peer_addr,
-				    coa, old_coa, p->bce->tunnel);
+				    coa, old_coa, p->bce->tunnel, mnp);
 		/* delete SP entry */ 
-		ha_ipsec_tnl_pol_del(our_addr, peer_addr, p->bce->tunnel);
+		ha_ipsec_tnl_pol_del(our_addr, peer_addr, p->bce->tunnel, mnp);
 	}
 	/* delete HoA route */
 	route_del(old_if, RT6_TABLE_MAIN,
@@ -578,6 +580,7 @@
 static int home_tnl_add(int old_if, int new_if, struct home_tnl_ops_parm *p)
 {
 	const struct in6_addr *our_addr, *peer_addr, *coa, *old_coa;
+	struct list_head *mnp;
 
 	assert(new_if);
 
@@ -585,6 +588,7 @@
 	peer_addr = &p->bce->peer_addr;
 	coa = &p->bce->coa;
 	old_coa = &p->bce->peer_addr;
+	mnp = &(p->mob_net_prefixes);
 
 	/* update tunnel interface */
 	p->bce->tunnel = new_if;
@@ -608,13 +612,13 @@
 	/* add SP entry */	
 	if (conf.UseMnHaIPsec) {
 		if (ha_ipsec_tnl_pol_add(our_addr, peer_addr,
-					 p->bce->tunnel) < 0) {
+					 p->bce->tunnel, mnp) < 0) {
 			p->ba_status = IP6_MH_BAS_INSUFFICIENT;
 			goto err;
 		}
 		/* migrate */ 
 		if (ha_ipsec_tnl_update(our_addr, peer_addr, coa, old_coa,
-					p->bce->tunnel) < 0) {
+					p->bce->tunnel, mnp) < 0) {
 			p->ba_status = IP6_MH_BAS_INSUFFICIENT;
 			goto err;
 		}
@@ -629,36 +633,23 @@
 {
 	assert(old_if && new_if);
 
-	if (old_if == new_if) {
+	if ((old_if == new_if) && (!prefix_list_cmp(&p->bce->mob_net_prefixes,
+				    &p->mob_net_prefixes))) {
 		const struct in6_addr *our_addr, *peer_addr, *coa, *old_coa;
+		struct list_head *mnp;
+		int mnpdiff = 0;
 
 		our_addr = &p->bce->our_addr;
 		peer_addr = &p->bce->peer_addr;
 		coa = &p->bce->coa;
 		old_coa = &p->bce->old_coa;
+		mnp = &(p->mob_net_prefixes);
 
-		/* if interface hasn't changed, at least check if the
-		   MR's MNPs have changed */
-		if (prefix_list_cmp(&p->bce->mob_net_prefixes,
-				    &p->mob_net_prefixes)) {
-			nemo_ha_del_mnp_routes(&p->bce->mob_net_prefixes,
-					       &p->mob_net_prefixes, 
-					       old_if, 0);
-			if (nemo_ha_add_mnp_routes(&p->bce->mob_net_prefixes,
-						   &p->mob_net_prefixes, 
-						   new_if, 0) < 0) {
-				if (p->bce->nemo_type == BCE_NEMO_EXPLICIT)
-					p->ba_status = IP6_MH_BAS_INVAL_PRFX;
-				else
-					p->ba_status = IP6_MH_BAS_FWDING_FAILED;
-				return -1;	
-			}
-		}
 		/* migrate */ 
 		if (conf.UseMnHaIPsec &&
-		    !IN6_ARE_ADDR_EQUAL(old_coa, coa) &&
+		    (mnpdiff || !IN6_ARE_ADDR_EQUAL(old_coa, coa)) &&
 		    ha_ipsec_tnl_update(our_addr, peer_addr, coa, old_coa,
-					p->bce->tunnel) < 0) {
+					p->bce->tunnel, mnp) < 0) {
 			return -1;
 		}
 	} else { 
diff -Nur trunk.common-mod/src/ipsec.c trunk.ha/src/ipsec.c
--- trunk.common-mod/src/ipsec.c	2007-10-16 11:42:33.000000000 +0900
+++ trunk.ha/src/ipsec.c	2007-10-16 11:42:42.000000000 +0900
@@ -352,6 +352,7 @@
 	int tunnel;
 	struct in6_addr coa;
 	struct in6_addr old_coa;
+	struct list_head *mnp;
 };
 
 /*
@@ -370,6 +371,7 @@
 	int ifindex;
 	const struct in6_addr *oldcoa, *newcoa;
 	const struct in6_addr *peer_addr = hoa;
+	struct list_head *mnp;
 	u_int8_t ipsec_proto;
 	struct xfrm_user_tmpl tmpl;
 	struct xfrm_userpolicy_info sp;
@@ -404,6 +406,7 @@
 	oldcoa = IN6_ARE_ADDR_EQUAL(&info->old_coa, &in6addr_any) ?
 		peer_addr : &info->old_coa;
 	newcoa = &info->coa;
+	mnp = info->mnp;
 
 	dump_migrate(ifindex, ipsec_proto, hoa, haaddr, oldcoa, newcoa);
 
@@ -436,6 +439,52 @@
 		dbg("migrate for OUTBOUND policy failed\n");
         	goto end;
 	}
+	
+	/* Mobile router case */
+	if ( (e->type == IPSEC_POLICY_TYPE_TUNNELPAYLOAD) && mnp)
+	{
+		struct list_head *list;
+
+		/* We have to modify rules to protect traffic to and from MNP's, the same way as HoA */
+		list_for_each(list, mnp) 
+		{
+			struct prefix_list_entry *p;
+			p = list_entry(list, struct prefix_list_entry, list);
+			
+			
+			/* inbound */
+			_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
+				  haaddr, oldcoa, e->reqid_toha);
+			_set_sp(&sp, e, XFRM_POLICY_IN, &in6addr_any, 0, &p->ple_prefix, p->ple_plen,
+				ifindex, MIP6_ENTITY_HA);
+			if ((err = xfrm_sendmigrate(&sp, &tmpl, haaddr, newcoa)) < 0) {
+				dbg("migrate for INBOUND policy failed\n");
+        			goto end;
+			}
+
+			/* forward */
+			_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
+				  haaddr, oldcoa, e->reqid_toha);
+			_set_sp(&sp, e, XFRM_POLICY_FWD, &in6addr_any, 0, &p->ple_prefix, p->ple_plen,
+				ifindex, MIP6_ENTITY_HA);
+			if ((err = xfrm_sendmigrate(&sp, &tmpl, haaddr, newcoa)) < 0) {
+				dbg("migrate for FORWARD policy failed\n");
+				goto end;
+			}
+
+			/* outbound */
+			_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
+				  oldcoa, haaddr, e->reqid_tomn);
+			_set_sp(&sp, e, XFRM_POLICY_OUT, &p->ple_prefix, p->ple_plen, &in6addr_any, 0,
+				ifindex, MIP6_ENTITY_HA);
+			if ((err = xfrm_sendmigrate(&sp, &tmpl, newcoa, haaddr)) < 0) {
+				dbg("migrate for OUTBOUND policy failed\n");
+        			goto end;
+			}
+	
+			
+		}
+	}
 
  end:
 	return err;
@@ -445,12 +494,14 @@
 			const struct in6_addr *hoa,
 			const struct in6_addr *coa,
 			const struct in6_addr *old_coa,
-			int tunnel)
+			int tunnel,
+			struct list_head *mnp)
 {
 	struct ha_ipsec_tnl_update b;
 	b.coa = *coa;
 	b.old_coa = *old_coa;
 	b.tunnel = tunnel;
+	b.mnp = mnp;
 	return ipsec_policy_apply(haaddr, hoa, _ha_tnl_update, &b);
 }
 
@@ -464,7 +515,9 @@
 			   int add)
 {
 	int err = 0;
-	int ifindex = *(int *)arg;
+	struct ha_ipsec_tnl_update *parms = (struct ha_ipsec_tnl_update *)arg;
+	int ifindex;
+	struct list_head *mnp;
 	struct xfrm_userpolicy_info sp;
 	struct xfrm_user_tmpl tmpl;
 	u_int16_t ipsec_proto;
@@ -474,6 +527,9 @@
 	assert(e);
 	assert(arg);
 
+	ifindex = parms->tunnel;
+	mnp = parms->mnp;
+
 	switch (e->type) {
 	case IPSEC_POLICY_TYPE_TUNNELHOMETESTING:
 	case IPSEC_POLICY_TYPE_TUNNELMH:
@@ -529,6 +585,52 @@
 		err = -1;
 		goto end;
 	}
+	
+	/* Mobile router case */
+	if ( (e->type == IPSEC_POLICY_TYPE_TUNNELPAYLOAD) && mnp)
+	{
+		struct list_head *list;
+
+		/* We have to add/delete rules to protect traffic to and from MNP's, the same way as HoA */
+		list_for_each(list, mnp) 
+		{
+			struct prefix_list_entry *p;
+			p = list_entry(list, struct prefix_list_entry, list);
+			
+			/* inbound */
+			_set_sp(&sp, e, XFRM_POLICY_IN, &in6addr_any, 0, &p->ple_prefix, p->ple_plen,
+				ifindex, MIP6_ENTITY_HA);
+			_set_tmpl(&tmpl, AF_INET6, ipsec_proto, XFRM_MODE_TUNNEL,
+				  haaddr, hoa, e->reqid_toha);
+			if (xfrm_ipsec_policy_mod(&sp, &tmpl, 1, add) < 0) {
+				dbg("modifying INBOUND policy failed\n");
+				err = -1;
+				goto end;
+			}
+
+			/* forward */
+			_set_sp(&sp, e, XFRM_POLICY_FWD, &in6addr_any, 0, &p->ple_prefix, p->ple_plen,
+				ifindex, MIP6_ENTITY_HA);
+			_set_tmpl(&tmpl, AF_INET6, ipsec_proto, XFRM_MODE_TUNNEL,
+				  haaddr, hoa, e->reqid_toha);
+			if (xfrm_ipsec_policy_mod(&sp, &tmpl, 1, add) < 0) {
+				dbg("modifying FORWARD policy failed\n");
+				err = -1;
+				goto end;
+			}
+
+			/* outbound */
+			_set_sp(&sp, e, XFRM_POLICY_OUT, &p->ple_prefix, p->ple_plen, &in6addr_any, 0,
+				ifindex, MIP6_ENTITY_HA);
+			_set_tmpl(&tmpl, AF_INET6, ipsec_proto, XFRM_MODE_TUNNEL,
+				  hoa, haaddr, e->reqid_tomn);
+			if (xfrm_ipsec_policy_mod(&sp, &tmpl, 1, add) < 0) {
+				dbg("modifying OUTBOUND policy failed\n");
+				err = -1;
+				goto end;
+			}
+		}
+	}
 
  end:
 	return err;
@@ -550,11 +652,14 @@
 
 int ha_ipsec_tnl_pol_add(const struct in6_addr *our_addr, 
 			 const struct in6_addr *peer_addr,
-			 int tunnel)
+			 int tunnel,
+			 struct list_head *mnp)
 {
-	int t = tunnel;
+	struct ha_ipsec_tnl_update b;
+	b.tunnel = tunnel;
+	b.mnp = mnp;
 
-	return ipsec_policy_apply(our_addr, peer_addr, _ha_tnl_pol_add, &t);
+	return ipsec_policy_apply(our_addr, peer_addr, _ha_tnl_pol_add, &b);
 }
 
 /*
@@ -573,12 +678,15 @@
 
 int ha_ipsec_tnl_pol_del(const struct in6_addr *our_addr, 
 			 const struct in6_addr *peer_addr,
-			 int tunnel)
+			 int tunnel,
+			 struct list_head *mnp)
 {
-	int t = tunnel;
+	struct ha_ipsec_tnl_update b;
+	b.tunnel = tunnel;
+	b.mnp = mnp;
 
 	return ipsec_policy_apply(our_addr, peer_addr,
-				  _ha_tnl_pol_del, &t);
+				  _ha_tnl_pol_del, &b);
 }
 
 /*
diff -Nur trunk.common-mod/src/ipsec.h trunk.ha/src/ipsec.h
--- trunk.common-mod/src/ipsec.h	2007-10-15 17:54:32.000000000 +0900
+++ trunk.ha/src/ipsec.h	2007-10-15 17:45:35.000000000 +0900
@@ -82,15 +82,18 @@
 			const struct in6_addr *hoa,
 			const struct in6_addr *coa,
 			const struct in6_addr *old_coa,
-			int tunnel);
+			int tunnel,
+			struct list_head *mnp);
 
 int ha_ipsec_tnl_pol_add(const struct in6_addr *our_addr, 
 			 const struct in6_addr *peer_addr,
-			 int tunnel);
+			 int tunnel,
+			 struct list_head *mnp);
 
 int ha_ipsec_tnl_pol_del(const struct in6_addr *our_addr, 
 			 const struct in6_addr *peer_addr,
-			 int tunnel);
+			 int tunnel,
+			 struct list_head *mnp);
 
 int mn_ipsec_tnl_update(const struct in6_addr *haaddr,
 			const struct in6_addr *hoa,
diff -Nur trunk.common-mod/src/ipsec.c trunk.mr/src/ipsec.c
--- trunk.common-mod/src/ipsec.c	2007-10-16 11:42:33.000000000 +0900
+++ trunk.mr/src/ipsec.c	2007-10-16 11:59:58.000000000 +0900
@@ -673,6 +673,53 @@
 			goto end;
 		}
 	}
+	
+	/*
+	 * If we are a Mobile Router, we also need to migrate IN/FWD/OUT rules
+	 * for forwarded traffic in case we have TUNNELPAYLOAD protection.
+	 */
+	if ((e->type == IPSEC_POLICY_TYPE_TUNNELPAYLOAD) && (bule->home->mob_rtr))
+	{
+		struct list_head *mnp;
+		
+		list_for_each(mnp, &bule->home->mob_net_prefixes) 
+		{
+			struct prefix_list_entry *p;
+			p = list_entry(mnp, struct prefix_list_entry, list);
+			
+			/* outbound */
+			_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
+				  haaddr, oldcoa, e->reqid_toha);
+			_set_sp(&sp, e, XFRM_POLICY_OUT, &in6addr_any, 0, &p->ple_prefix, p->ple_plen,
+				ifindex, MIP6_ENTITY_MN);
+			if ((err = xfrm_sendmigrate(&sp, &tmpl, haaddr, newcoa)) < 0) {
+				dbg("migrate for OUTBOUND policy failed\n");
+				goto end;
+			}
+
+			/* forwarded */
+			_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
+				  oldcoa, haaddr, e->reqid_tomn);
+			_set_sp(&sp, e, XFRM_POLICY_IN, &p->ple_prefix, p->ple_plen, &in6addr_any, 0,
+				ifindex, MIP6_ENTITY_MN);
+			if ((err = xfrm_sendmigrate(&sp, &tmpl, newcoa, haaddr)) < 0) {
+				dbg("migrate for INBOUND policy (1) failed\n");
+				goto end;
+			}
+
+			/* inbound */
+			_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
+				  oldcoa, haaddr, e->reqid_tomn);
+			_set_sp(&sp, e, XFRM_POLICY_IN, &p->ple_prefix, p->ple_plen, &in6addr_any, 0,
+				ifindex, MIP6_ENTITY_MN);
+			if ((err = xfrm_sendmigrate(&sp, &tmpl, newcoa, haaddr)) < 0) {
+				dbg("migrate for INBOUND policy (1) failed\n");
+				goto end;
+			}
+
+		}
+	}
+	
 
  end:
 	return err;
@@ -765,6 +812,56 @@
 			err = cn_wildrecv_bu_pol_add();
 		}
 	}
+	
+	/*
+	 * If we are a Mobile Router, we also need to create IN/FWD/OUT rules
+	 * for forwarded traffic in case we have TUNNELPAYLOAD protection.
+	 */
+	if ((e->type == IPSEC_POLICY_TYPE_TUNNELPAYLOAD) && (bule->home->mob_rtr))
+	{
+		struct list_head *mnp;
+		
+		list_for_each(mnp, &bule->home->mob_net_prefixes) 
+		{
+			struct prefix_list_entry *p;
+			p = list_entry(mnp, struct prefix_list_entry, list);
+			
+			/* inbound */
+			_set_sp(&sp, e, XFRM_POLICY_IN, &p->ple_prefix, p->ple_plen, &in6addr_any, 0,
+				ifindex, MIP6_ENTITY_MN);
+			_set_tmpl(&tmpl, AF_INET6, ipsec_proto, XFRM_MODE_TUNNEL,
+				  hoa, haaddr, e->reqid_tomn);
+			if (xfrm_ipsec_policy_mod(&sp, &tmpl, 1, add) < 0) {
+				dbg("modifying INBOUND policy failed.\n");
+				err = -1;
+				goto end;
+			}
+
+			/* forward */
+			_set_sp(&sp, e, XFRM_POLICY_FWD, &p->ple_prefix, p->ple_plen, &in6addr_any, 0,
+				ifindex, MIP6_ENTITY_MN);
+			_set_tmpl(&tmpl, AF_INET6, ipsec_proto, XFRM_MODE_TUNNEL,
+				  hoa, haaddr, e->reqid_tomn);
+			if (xfrm_ipsec_policy_mod(&sp, &tmpl, 1, add) < 0) {
+				dbg("modifying INBOUND policy failed.\n");
+				err = -1;
+				goto end;
+			}
+
+			/* outbound */
+			_set_sp(&sp, e, XFRM_POLICY_OUT, &in6addr_any, 0, &p->ple_prefix, p->ple_plen,
+				ifindex, MIP6_ENTITY_MN);
+			_set_tmpl(&tmpl, AF_INET6, ipsec_proto, XFRM_MODE_TUNNEL,
+				  haaddr, hoa, e->reqid_toha);
+			if (xfrm_ipsec_policy_mod(&sp, &tmpl, 1, add) < 0) {
+				dbg("modifying OUTBOUND policy failed.\n");
+				err = -1;
+				goto end;
+			}
+		}
+	}
+			
+		
 
  end:
 	return err;
diff -Nur trunk.common-mod/src/xfrm.c trunk.mr/src/xfrm.c
--- trunk.common-mod/src/xfrm.c	2007-10-15 17:54:32.000000000 +0900
+++ trunk.mr/src/xfrm.c	2007-10-16 11:59:58.000000000 +0900
@@ -679,12 +679,76 @@
 	return err;
 }
 
+static int mr_ipsec_bypass_init(void)
+{
+	struct list_head *home;
+	struct list_head *mnps;
+	int err=0;
+	
+	/* Loop for each HomeAddress info */
+	list_for_each(home, &conf_parsed->home_addrs)
+	{
+		struct home_addr_info *hai;
+		hai = list_entry(home, struct home_addr_info, list); 
+	
+		/* If Mobile Router for this link, loop for each MNP */
+		if (hai->mob_rtr)
+		{
+			/* Add bypass policies to and from the MNP link */
+			list_for_each(mnps, &hai->mob_net_prefixes) 
+			{
+				struct prefix_list_entry * mnp;
+				struct xfrm_selector sel;
+				
+				mnp = list_entry(mnps, struct prefix_list_entry, list);
+				
+				memset(&sel, 0, sizeof(sel));
+				sel.family = AF_INET6;
+				sel.user = getuid();
+				
+				/* IN, src = MNP , dst = any */
+				memcpy(&sel.saddr.a6, &mnp->ple_prefix, sizeof(sel.saddr.a6));
+				sel.prefixlen_s = mnp->ple_plen;
+				
+				err = xfrm_ipsec_policy_add(&sel, 0, XFRM_POLICY_IN,
+				        		    XFRM_POLICY_ALLOW, MIP6_PRIO_MR_LOCAL_DATA_BYPASS,
+							    NULL, 0);
+							    
+				/* XXX: what should we do in case of error? */
+				
+				/* FWD, src = MNP , dst = any */
+				err = xfrm_ipsec_policy_add(&sel, 0, XFRM_POLICY_FWD,
+				        		    XFRM_POLICY_ALLOW, MIP6_PRIO_MR_LOCAL_DATA_BYPASS,
+							    NULL, 0);
+				
+				
+				/* OUT, src = any , dst = MNP */
+				memset(&sel.saddr.a6, 0, sizeof(sel.saddr.a6));
+				sel.prefixlen_s = 0;
+				memcpy(&sel.daddr.a6, &mnp->ple_prefix, sizeof(sel.daddr.a6));
+				sel.prefixlen_d = mnp->ple_plen;
+
+				err = xfrm_ipsec_policy_add(&sel, 0, XFRM_POLICY_OUT,
+				        		    XFRM_POLICY_ALLOW, MIP6_PRIO_MR_LOCAL_DATA_BYPASS,
+							    NULL, 0);
+				
+			}
+		}
+	}
+	
+	return err;
+	
+}
+
 static inline int mn_ha_ipsec_init(void)
 {
 	int err;
 
 	/* insert bypass policy */
 	err = ipsec_policy_walk(_mn_ha_ipsec_bypass_init, NULL);
+	
+	/* insert NEMO-related bypass */
+	err = mr_ipsec_bypass_init();
 
 	err = ipsec_policy_walk(_mn_ha_ipsec_init, NULL);
 
@@ -787,9 +851,67 @@
 	return err;
 }
 
+static int mr_ipsec_bypass_cleanup(void)
+{
+	struct list_head *home;
+	struct list_head *mnps;
+	int err=0;
+	
+	/* Loop for each HomeAddress info */
+	list_for_each(home, &conf_parsed->home_addrs)
+	{
+		struct home_addr_info *hai;
+		hai = list_entry(home, struct home_addr_info, list); 
+	
+		/* If Mobile Router for this link, loop for each MNP */
+		if (hai->mob_rtr)
+		{
+			/* Delete bypass policies to and from the MNP link */
+			list_for_each(mnps, &hai->mob_net_prefixes) 
+			{
+				struct prefix_list_entry * mnp;
+				struct xfrm_selector sel;
+				
+				mnp = list_entry(mnps, struct prefix_list_entry, list);
+				
+				memset(&sel, 0, sizeof(sel));
+				sel.family = AF_INET6;
+				sel.user = getuid();
+				
+				/* IN, src = MNP , dst = any */
+				memcpy(&sel.saddr.a6, &mnp->ple_prefix, sizeof(sel.saddr.a6));
+				sel.prefixlen_s = mnp->ple_plen;
+				
+				err = xfrm_ipsec_policy_del(&sel, XFRM_POLICY_IN);
+							    
+				/* XXX: what should we do in case of error? */
+				
+				/* FWD, src = MNP , dst = any */
+				err = xfrm_ipsec_policy_del(&sel, XFRM_POLICY_FWD);
+				
+				
+				/* OUT, src = any , dst = MNP */
+				memset(&sel.saddr.a6, 0, sizeof(sel.saddr.a6));
+				sel.prefixlen_s = 0;
+				memcpy(&sel.daddr.a6, &mnp->ple_prefix, sizeof(sel.daddr.a6));
+				sel.prefixlen_d = mnp->ple_plen;
+
+				err = xfrm_ipsec_policy_del(&sel, XFRM_POLICY_OUT);
+				
+			}
+		}
+	}
+	
+	return err;
+	
+}
+
+
 static inline void mn_ha_ipsec_cleanup(void)
 {
 	ipsec_policy_walk(_mn_ha_ipsec_bypass_cleanup, NULL);
+	
+	(void)mr_ipsec_bypass_cleanup();
 
 	ipsec_policy_walk(_mn_ha_ipsec_cleanup, NULL);
 }
diff -Nur trunk.common-mod/src/xfrm.h trunk.mr/src/xfrm.h
--- trunk.common-mod/src/xfrm.h	2007-10-15 17:54:32.000000000 +0900
+++ trunk.mr/src/xfrm.h	2007-10-16 11:59:58.000000000 +0900
@@ -15,6 +15,7 @@
 #define MIP6_PRIO_RO_SIG_IPSEC		7	/* XXX: BU between MN-MN with IPsec */
 #define MIP6_PRIO_RO_SIG		8	/* XXX: BU between MN-CN */
 #define MIP6_PRIO_RO_SIG_ANY		9
+#define MIP6_PRIO_MR_LOCAL_DATA_BYPASS	9	/* Bypass rule for local traffic in mobile network */
 #define MIP6_PRIO_RO_SIG_RR		10	/* XXX: MH(or HoTI/HoT) between MN-CN */
 #define MIP6_PRIO_RO_BLOCK		11
 #define MIP6_PRIO_NO_RO_SIG_ANY		12