File mipv6-daemon-umip-0.4-nepl-20080108.patch of Package mipv6d

Index: mipv6-daemon/AUTHORS
===================================================================
--- mipv6-daemon.orig/AUTHORS
+++ mipv6-daemon/AUTHORS
@@ -5,3 +5,14 @@ The core team has in the past included J
 Petander.  Code has been contributed by several individuals.  See
 THANKS for listing.  See libnetlink/README for information regarding
 libnetlink.
+
+The NEMO Basic support code is developed by Ville Nuorvala
+<vnuorval@tcs.hut.fi> in co-operation with the Nautilus6/WIDE
+project (http://www.nautilus6.org).
+
+The NEMO Basic Support code has been ported to UMIP by Romain KUNTZ
+<kuntz@lsiit.u-strasbg.fr> and received contributions from the
+following people:
+- Sebastien DECUGIS (Nautilus6): IPsec support for NEMO
+- Arnaud EBALARD (EADS): fixes for Big Endian architectures and
+  improvements of the NEMO debug messages.
Index: mipv6-daemon/BUGS
===================================================================
--- mipv6-daemon.orig/BUGS
+++ mipv6-daemon/BUGS
@@ -17,3 +17,11 @@ Mobile Node issues
 * Multihoming support hasn't been very thoroughly tested and should
   therefore be considered developmental code.  However, it is a lot
   more stable than in the Release Candidates.
+
+NEMO issues
+-----------
+
+* The Mobile Router's home address may only be on the egress interface.
+
+* Dynamic routing protocols between the Home Agent and Mobile Router
+  are not yet supported.
Index: mipv6-daemon/COPYING.NEMO
===================================================================
--- /dev/null
+++ mipv6-daemon/COPYING.NEMO
@@ -0,0 +1,13 @@
+Cisco and Nokia have both published IPR notices regarding RFC 3963
+"Network Mobility (NEMO) Basic Support Protocol."
+
+Cisco has agreed not to assert its patents against any party agreeing with the
+terms in its IPR notice.
+
+Likewise, Nokia has agreed not to assert its patents against Open Source
+implementations of the specification.
+
+For further information, please read
+licenses/cisco-ipr-draft-ietf-nemo-basic-support-03.txt and 
+licenses/nokia-ipr-draft-ietf-nemo-basic-support.txt.
+
Index: mipv6-daemon/INSTALL
===================================================================
--- mipv6-daemon.orig/INSTALL
+++ mipv6-daemon/INSTALL
@@ -45,6 +45,8 @@
    further information on how to configure your node.  Also take a
    look at the example configuration files in the extras directory.
 
+   For comments about NEMO check README.NEMO.
+
    For comments about IPsec support check README.IPsec.
 
 5. A startup script 
Index: mipv6-daemon/README
===================================================================
--- mipv6-daemon.orig/README
+++ mipv6-daemon/README
@@ -2,6 +2,9 @@ MIPL Mobile IPv6 for Linux
 
   MIPL Mobile IPv6 for Linux is an implementation of the Mobility
   Support in IP version 6 (RFC 3775).
+
+  It also supports Network Mobility with the NEMO Basic Support
+  implementation (RFC 3963).
   
   This user space part works together with Mobile IPv6 enabled Linux
   kernels.  See INSTALL and any other documents referred there for
Index: mipv6-daemon/README.NEMO
===================================================================
--- /dev/null
+++ mipv6-daemon/README.NEMO
@@ -0,0 +1,18 @@
+README for NEMO Basic Support 
+-----------------------------
+
+Here are a few things you need to keep in mind when setting up Network
+Mobility:
+
+The MR is a router so you need to set
+/proc/sys/net/ipv6/conf/all/forwarding to 1 to make sure it will forward
+packets between its ingress and egress interfaces.
+
+With static routing the HA and other routers on the home link might need some
+additional boot-strapping.  If the MR has a physical home link that it may be
+attached to, the other routers must be pre-configured with routes to the MR's
+Mobile Network Prefixes via the MR's home address.  This ensures packets will
+be forwarded correctly also when the MR is at home.
+
+To be able to support NEMO DHAAD the HA needs to have AdvHomeAgentInfo and
+AdvMobRtrSupportFlag turned on in radvd.conf.
Index: mipv6-daemon/include/netinet/icmp6.h
===================================================================
--- mipv6-daemon.orig/include/netinet/icmp6.h
+++ mipv6-daemon/include/netinet/icmp6.h
@@ -27,7 +27,13 @@ struct mip_dhaad_req {		/* Dynamic HA Ad
 #define mip_dhreq_code			mip_dhreq_hdr.icmp6_code
 #define mip_dhreq_cksum			mip_dhreq_hdr.icmp6_cksum
 #define mip_dhreq_id			mip_dhreq_hdr.icmp6_data16[0]
-#define mip_dhreq_reserved		mip_dhreq_hdr.icmp6_data16[1]
+#define mip_dhreq_flags_reserved	mip_dhreq_hdr.icmp6_data16[1]
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define MIP_DHREQ_FLAG_SUPPORT_MR	0x8000
+#else				/* BYTE_ORDER == LITTLE_ENDIAN */
+#define MIP_DHREQ_FLAG_SUPPORT_MR	0x0080
+#endif
 #endif
 
 #ifndef HAVE_STRUCT_MIP_DHAAD_REP
@@ -40,7 +46,13 @@ struct mip_dhaad_rep {		/* HA Address Di
 #define mip_dhrep_code			mip_dhrep_hdr.icmp6_code
 #define mip_dhrep_cksum			mip_dhrep_hdr.icmp6_cksum
 #define mip_dhrep_id			mip_dhrep_hdr.icmp6_data16[0]
-#define mip_dhrep_reserved		mip_dhrep_hdr.icmp6_data16[1]
+#define mip_dhrep_flags_reserved	mip_dhrep_hdr.icmp6_data16[1]
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define MIP_DHREP_FLAG_SUPPORT_MR	0x8000
+#else				/* BYTE_ORDER == LITTLE_ENDIAN */
+#define MIP_DHREP_FLAG_SUPPORT_MR	0x0080
+#endif
 #endif
 
 #ifndef HAVE_STRUCT_MIP_PREFIX_SOLICIT
@@ -89,10 +101,20 @@ struct mip_prefix_advert {	/* Mobile Pre
 struct nd_opt_homeagent_info {	/* Home Agent information */
 	uint8_t		nd_opt_hai_type;
 	uint8_t		nd_opt_hai_len;
-	uint16_t	nd_opt_hai_reserved;
+	uint16_t	nd_opt_hai_flags_reserved;
 	uint16_t	nd_opt_hai_preference;
 	uint16_t	nd_opt_hai_lifetime;
 };
 #endif
 
+#define nd_opt_hai_reserved     nd_opt_hai_flags_reserved
+
+#ifndef ND_OPT_HAI_FLAG_SUPPORT_MR
+#if BYTE_ORDER == BIG_ENDIAN
+#define ND_OPT_HAI_FLAG_SUPPORT_MR	0x8000
+#else				/* BYTE_ORDER == LITTLE_ENDIAN */
+#define ND_OPT_HAI_FLAG_SUPPORT_MR	0x0080
+#endif
+#endif
+
 #endif	/* netinet/icmp6.h */
Index: mipv6-daemon/licenses/cisco-ipr-draft-ietf-nemo-basic-support-03.txt
===================================================================
--- /dev/null
+++ mipv6-daemon/licenses/cisco-ipr-draft-ietf-nemo-basic-support-03.txt
@@ -0,0 +1,41 @@
+Title: Cisco Systems' Updated Statement about IPR claimed in
+       draft-ietf-nemo-basic-support-03.txt
+Received 25 October 2004
+From: Robert Barr <rbarr@cisco.com>
+
+This statement updates the IPR statement filed by Cisco on June 20, 2003 for
+draft-ietf-nemo-basic-support-00.txt.
+
+Cisco is the owner of US Patent No. 6,636,498 and at least one pending
+patent application
+relating to the subject matter of draft-ietf-nemo-basic-support-03.txt
+"Network Mobility (NEMO) Basic Support Protocol" .
+If a standard relating to this subject matter is adopted by IETF and any
+claims
+of any issued Cisco patents are necessary for practicing this standard, any
+party will be able to obtain a license from Cisco to use any such patent
+claims under openly specified, reasonable, non-discriminatory terms, with
+reciprocity, to implement and fully comply with the standard.
+
+The reasonable non-discriminatory terms are:
+
+If this standard is adopted, Cisco will not assert any patents owned or
+controlled by Cisco against any party for making, using, selling, importing
+or offering for sale a product that implements the standard, provided,
+however that Cisco retains the right to assert its patents (including the
+right to claim past royalties) against any party that asserts a patent it
+owns or controls (either directly or indirectly) against Cisco or any of
+Cisco's affiliates or successors in title; and Cisco retains the right to
+assert its patents against any product or portion thereof that is not
+necessary for compliance with the standard.
+
+Royalty-bearing licenses will be available to anyone who prefers that
+option.
+
+For information contact:
+
+Robert Barr
+Worldwide Patent Counsel
+Cisco Systems
+408-525-9706
+rbarr@cisco.com
Index: mipv6-daemon/licenses/nokia-ipr-draft-ietf-nemo-basic-support.txt
===================================================================
--- /dev/null
+++ mipv6-daemon/licenses/nokia-ipr-draft-ietf-nemo-basic-support.txt
@@ -0,0 +1,26 @@
+Title: Nokia Corporation's statement about IPR claimed in draft-ietf-nemo-basic-support
+Received: July 1, 2003
+From: Heikki Huttunen <heikki.a.huttunen@nokia.com>
+
+This is to advise the IETF that Nokia believes the Nokia patent application "Mobile Router 
+Support for IPv6", US10/295014, WO03/043226 may be relevant to Nemo Basic Support Protocol 
+<draft-ietf-nemo-basic-support>.
+
+Regarding internet draft "draft-ietf-nemo-basic-support", to the extent this draft is 
+included into final IETF standard specification, Nokia agrees not to assert those claims 
+in Nokia patents that apply to this draft and that are technically necessary to implement 
+the IETF standard specification against any other party in respect of its implementation of 
+the specification, if only practiced under any software distributed under the present terms 
+of GNU GENERAL PUBLIC LICENSE (http://www.fsf.org/copyleft/gpl.html) or under license terms 
+that conform to the present open source definition (http://www.opensource.org/osd.html) and 
+provided that the party relying on this commitment does not assert its patents against Nokia.
+
+Otherwise general Nokia Statement on Patent Licensing (http://www.ietf.org/ietf/IPR/NOKIA) 
+applies to this submission. 
+
+
+Heikki Huttunen
+Director, Licensing
+Nokia Corporation
+P.O Box 86, FIN-24101 Salo, Finland
+Phone: +358 (0) 7180 41202, Fax: +358 (0) 7180 44275
Index: mipv6-daemon/man/mip6d.conf.tmpl
===================================================================
--- mipv6-daemon.orig/man/mip6d.conf.tmpl
+++ mipv6-daemon/man/mip6d.conf.tmpl
@@ -1,12 +1,12 @@
 .\" $Id: mip6d.conf.tmpl 1.33 06/05/12 11:48:36+03:00 vnuorval@tcs.hut.fi $
-.TH mip6d.conf 5 "January 31, 2006" "" "Mobile IPv6 Daemon Configuration"
+.TH mip6d.conf 5 "January 31, 2006" "" "Mobile IPv6 and NEMO Daemon Configuration"
 .SH NAME
-mip6d.conf \- MIPL Mobile IPv6 Configuration file
+mip6d.conf \- MIPL Mobile IPv6 and NEMO Configuration file
 .SH SYNOPSIS
 .B %etc%/mip6d.conf
 .sp
 .SH DESCRIPTION
-MIPL Mobile IPv6 daemon's configuration file
+MIPL Mobile IPv6 and NEMO daemon's configuration file
 .P
 Below is a list of currently supported configuration options. All
 configuration lines are terminated with a semicolon.  Sub-sections are
@@ -184,10 +184,29 @@ Sets a maximum interval (in seconds) for
 Default: 86400
 
 .TP
-.BR "BindingAclPolicy " "address " "allow | deny"
+.BR "HaAcceptMobRtr enabled | disabled"
 
-Defines if a MN is allowed to register with the HA or not. The MN home address
-of the MN is given in the address field."
+Indicates if the HA accepts Mobile Router bindings.
+
+Default: disabled;
+
+.TP
+.BR "HaServedPrefix " "prefix/length" ";"
+
+Prefix is an IPv6 prefix and length is the prefix length. Defines the whole
+aggregated or extended prefix the HA serves. This option is only used for MR
+bindings and is only needed if the MRs derive their Home Addresses from their
+Mobile Network Prefixes, instead of one of the home link prefixes.
+
+.TP
+.BR "BindingAclPolicy " "address MNP list " "allow | deny"
+
+Defines if a MN is allowed to register with the HA or not. The home address
+of the MN is given in the address field.  The mobile network prefixes
+belonging a NEMO Mobile Router are listed in the MNP list. The list can either
+be an empty string or a comma separated list of network prefixes
+enclosed in braces, for example:
+.B "(3ffe:2620:6:3::/64, 3ffe:2620:6:4::/64)"
 
 .TP
 .BR "DefaultBindingAclPolicy allow | deny"
@@ -254,6 +273,13 @@ options to explicitly list the used inte
 Default: disabled
 
 .TP
+.BR "MobRtrUseExplicitMode enabled | disabled"
+
+Toggles between explicit or implicit mode home registrations in the MR.
+
+Default: enabled
+
+.TP
 .BR "UseCnBuAck " "boolean" ";"
 
 Indicates if the Acknowledge bit should be set in Binding Updates sent to
@@ -299,7 +325,7 @@ Default: disabled;
 .TP
 .nf
 .BR "MnHomeLink " "name " "{"
-.BR "	HomeAddress " "address/length" ";"
+.BR "	HomeAddress " "address/length MNP list" ";"
 .BR "	HomeAgentAddress " "address" ";"
 .BR "	MnRoPolicy ..."
 .BR "	..."
@@ -317,11 +343,14 @@ structures.  The interface names don't h
 definitions.  All the home link specific definitions are detailed below: 
 
 .TP
-.BR "HomeAddress " "address/length" ";"
+.BR "HomeAddress " "address/length MNP list" ";"
 
 Address is an IPv6 address, and length the prefix length of the
-address, usually 64.  This option must be included in a home link
-definition.
+address, usually 64.  The MNP list contains the mobile network prefixes
+belonging to that particular NEMO Mobile Router. The MNP list is of the
+same format as in
+.B "BindingAclPolicy."
+This option must be included in a home link definition.
 
 .TP
 .BR "HomeAgentAddress " "address" ";"
@@ -332,6 +361,13 @@ if it is the unspecified address ::.
 Default: ::
 
 .TP
+.BR "IsMobRtr enabled | disabled"
+
+Defines if the MN is a NEMO MR.
+
+Default: disabled
+
+.TP
 The route optimization policies are of the form:
 
 .TP
@@ -353,6 +389,49 @@ matching this entry.
 .SH EXAMPLES
 
 .TP
+.BR "A NEMO Home Agent example:"
+
+.nf
+NodeConfig HA;
+
+Interface "eth0";
+
+HaAcceptMobRtr enabled;
+
+HaServedPrefix 3ffe:2620:6::/48;
+
+DefaultBindingAclPolicy deny;
+BindingAclPolicy 3ffe:2620:6:1::1234 (3ffe:2620:6:2::/64, 3ffe:2620:6:3::/64) allow;
+BindingAclPolicy 3ffe:2620:6:1::1235 allow;
+
+UseMnHaIPsec disabled;
+.fi
+
+.TP
+.BR "A NEMO Mobile Router example:"
+
+.nf
+NodeConfig MN;
+
+DoRouteOptimizationCN disabled;
+DoRouteOptimizationMN disabled;
+
+Interface "eth0";
+
+MnRouterProbes 1;
+
+MobRtrUseExplicitMode enabled;
+
+MnHomeLink "eth0" {
+        IsMobRtr enabled;
+        HomeAgentAddress 3ffe:2620:6:1::1;
+        HomeAddress 3ffe:2620:6:1::1234/64 (3ffe:2620:6:2::/64, 3ffe:2620:6:3::/64);
+}
+
+UseMnHaIPsec disabled;
+.fi
+
+.TP
 .BR "A Correspondent Node example:"
 
 .nf
Index: mipv6-daemon/man/mip6d.tmpl
===================================================================
--- mipv6-daemon.orig/man/mip6d.tmpl
+++ mipv6-daemon/man/mip6d.tmpl
@@ -1,13 +1,13 @@
 .\" $Id: mip6d.tmpl 1.4 05/05/16 13:13:41+03:00 anttit@tcs.hut.fi $
-.TH mip6d 1 "May 16, 2005" "" "Mobile IPv6 Daemon"
+.TH mip6d 1 "May 16, 2005" "" "Mobile IPv6 and NEMO Daemon"
 .SH NAME
-mip6d \- MIPL Mobile IPv6 protocol implementation
+mip6d \- MIPL Mobile IPv6 and NEMO Basic Support protocol implementation
 .SH SYNOPSIS
 .B mip6d [options]
 .sp
 .SH DESCRIPTION
 
-Mobile IPv6 implementation
+Mobile IPv6 and NEMO Basic Support implementation
 
 .SH OPTIONS
 .IP "\fB\-V, \-\-version\fP"
@@ -41,3 +41,5 @@ RFC3775: Mobility Support in IPv6,
 .PP
 RFC3776: Using IPsec to Protect Mobile IPv6 Signaling Between Mobile
 Nodes and Home Agents
+.PP
+RFC3963: Network Mobility (NEMO) Basic Support Protocol
Index: mipv6-daemon/src/bcache.c
===================================================================
--- mipv6-daemon.orig/src/bcache.c
+++ mipv6-daemon/src/bcache.c
@@ -39,6 +39,7 @@
 #include "mh.h"
 #include "cn.h"
 #include "vt.h"
+#include "prefix.h"
 
 #define BCACHE_BUCKETS 32
 
@@ -63,6 +64,7 @@ void dump_bce(void *bce, void *os)
 {
 	struct bcentry *e = (struct bcentry *)bce;
 	FILE *out = (FILE *)os;
+	int mnpcount = 0;
 
 	fprintf(out, " == Binding Cache entry ");
 
@@ -88,6 +90,37 @@ void dump_bce(void *bce, void *os)
 	fprintf(out, " lifetime %ld\n ", e->lifetime.tv_sec);
 	fprintf(out, " seqno %d\n", e->seqno);
 
+	if (e->flags & IP6_MH_BA_MR) {
+		struct list_head *list;
+
+		/* MR registration type */
+		fprintf(out, "MR Registration type: ");
+		switch(e->nemo_type) {
+		case BCE_NEMO_EXPLICIT:
+			fprintf(out, "explicit.\n");
+			break;
+		case BCE_NEMO_IMPLICIT:
+			fprintf(out, "implicit.\n");
+			break;
+		default:
+			fprintf(out, "unknown.\n");
+		}
+
+		/* Mobile Network prefixes */
+		fprintf(out, "MR Mobile network prefixes: ");
+		list_for_each(list, &e->mob_net_prefixes) {
+			struct prefix_list_entry *p;
+			p = list_entry(list, struct prefix_list_entry, list);
+			if (mnpcount)
+				fprintf(out, "                            ");
+			fprintf(out, "%x:%x:%x:%x:%x:%x:%x:%x/%d\n",
+				NIP6ADDR(&p->ple_prefix), p->ple_plen);
+			mnpcount++;
+		}
+		if (!mnpcount)
+			fprintf(out, " none registered.\n");
+	}
+
 	fflush(out);
 }
 
@@ -144,6 +177,7 @@ struct bcentry *bcache_alloc(int type)
 		return NULL;
 	}
 	INIT_LIST_HEAD(&tmp->tqe.list);
+	INIT_LIST_HEAD(&tmp->mob_net_prefixes);
 	return tmp;
 }
 
@@ -158,6 +192,7 @@ void bcache_free(struct bcentry *bce)
 	/* This function should really return allocated space to free
 	 * pool. */
 	pthread_rwlock_destroy(&bce->lock);
+	prefix_list_free(&bce->mob_net_prefixes);
 	free(bce);
 }
 
Index: mipv6-daemon/src/bcache.h
===================================================================
--- mipv6-daemon.orig/src/bcache.h
+++ mipv6-daemon/src/bcache.h
@@ -18,7 +18,8 @@ struct bcentry {
 
 	uint16_t nonce_coa;
 	uint16_t nonce_hoa;
-	int type;			/* Entry type */
+	uint16_t type;     		/* Entry type */
+	uint16_t nemo_type;    		/* NEMO registration type */
 	int unreach;			/* ICMP dest unreach count */
 	int tunnel;			/* Tunnel interface index */
 	int link;			/* Home link interface index */
@@ -33,6 +34,8 @@ struct bcentry {
 	struct tq_elem tqe;		/* Timer queue entry for expire */
 
 	void (*cleanup)(struct bcentry *bce); /* Clean up bce data */
+
+	struct list_head mob_net_prefixes;
 };
 
 #define BCE_NONCE_BLOCK 0
@@ -41,6 +44,10 @@ struct bcentry {
 #define BCE_CACHE_DYING 3
 #define BCE_DAD 4
 
+#define BCE_NEMO_EXPLICIT 1
+#define BCE_NEMO_IMPLICIT 2
+#define BCE_NEMO_DYNAMIC 3
+
 struct bcentry *bcache_alloc(int type);
 
 void bcache_free(struct bcentry *bce);
Index: mipv6-daemon/src/bul.c
===================================================================
--- mipv6-daemon.orig/src/bul.c
+++ mipv6-daemon/src/bul.c
@@ -103,9 +103,11 @@ void dump_bule(void *bule, void *os)
 	if (e->flags & IP6_MH_BU_ACK)
 		fprintf(out, "IP6_MH_BU_ACK ");
 	if (e->flags & IP6_MH_BU_LLOCAL)
-		fprintf(out, "IP6_MH_BU_LLOCAL");
+		fprintf(out, "IP6_MH_BU_LLOCAL ");
 	if (e->flags & IP6_MH_BU_KEYM)
-		fprintf(out, "IP6_MH_BU_KEYM");
+		fprintf(out, "IP6_MH_BU_KEYM ");
+	if (e->flags & IP6_MH_BU_MR)
+		fprintf(out, "IP6_MH_BU_MR");
 
 	fprintf(out, "\n");
 	fflush(out);
@@ -184,7 +186,8 @@ int bul_add(struct bulentry *bule)
 			goto home_bul_free;
 	} else if (bule->type == NON_MIP_CN_ENTRY) {
 		if (bule->flags & IP6_MH_BU_HOME) {
-			if (xfrm_block_hoa(hai) < 0)
+			if (xfrm_block_hoa(hai) < 0 ||
+			    (hai->mob_rtr && xfrm_block_ra(hai) < 0))
 				goto home_bul_free;
 		}
 	}
@@ -231,6 +234,10 @@ void bul_delete(struct bulentry *bule)
 				xfrm_unblock_link(hai);
 			if (hai->home_block & HOME_ADDR_BLOCK)
 				xfrm_unblock_hoa(hai);
+			if (hai->home_block & NEMO_RA_BLOCK)
+				xfrm_unblock_ra(hai);
+			if (hai->home_block & NEMO_FWD_BLOCK)
+				xfrm_unblock_fwd(hai);
 		}
 	}
 	while (bule->ext_cleanup)
Index: mipv6-daemon/src/cn.c
===================================================================
--- mipv6-daemon.orig/src/cn.c
+++ mipv6-daemon/src/cn.c
@@ -177,8 +177,8 @@ void cn_recv_bu(const struct ip6_mh *mh,
 	non_ind = mh_opt(&bu->ip6mhbu_hdr, &mh_opts, IP6_MHOPT_NONCEID);
 	bce = bcache_get(out.src, out.dst);
 	if (bce) {
-		if ((bce->flags^bu_flags) & IP6_MH_BU_HOME) {
-			/* H-bit mismatch, flags changed */
+		if ((bce->flags^bu_flags) & (IP6_MH_BU_HOME|IP6_MH_BU_MR)) {
+			/* H-bit or R-bit mismatch, flags changed */
 			bcache_release_entry(bce);
 			bce = NULL;
 			status = IP6_MH_BAS_REG_NOT_ALLOWED;
@@ -221,9 +221,15 @@ void cn_recv_bu(const struct ip6_mh *mh,
 			/* else get rid of it */
 			bcache_delete(out.src, out.dst);
 		}
-	} else if (bu_flags & IP6_MH_BU_HOME) {
-		status = IP6_MH_BAS_HA_NOT_SUPPORTED;
-		goto send_nack;
+	} else {
+		if (bu_flags & IP6_MH_BU_HOME) {
+			status = IP6_MH_BAS_HA_NOT_SUPPORTED;
+			goto send_nack;
+		}
+		if (bu_flags & IP6_MH_BU_MR) {
+			status = IP6_MH_BAS_MR_OP_NOT_PERMITTED;
+			goto send_nack;
+		}
 	}
 	status = conf.pmgr.discard_binding(out.dst, out.bind_coa,
 					   out.src, bu, len);
Index: mipv6-daemon/src/conf.c
===================================================================
--- mipv6-daemon.orig/src/conf.c
+++ mipv6-daemon/src/conf.c
@@ -212,6 +212,7 @@ static void conf_default(struct mip6_con
 	INIT_LIST_HEAD(&c->home_addrs);
 	c->MoveModulePath = NULL; /* internal */
 	c->DoRouteOptimizationMN = 1;
+	c->MobRtrUseExplicitMode = 1;
 	c->SendMobPfxSols = 1;
 	c->OptimisticHandoff = 0;
 
@@ -221,6 +222,7 @@ static void conf_default(struct mip6_con
 	c->MaxMobPfxAdvInterval = 86400; /* seconds */
 	c->MinMobPfxAdvInterval = 600; /* seconds */
 	c->HaMaxBindingLife = MAX_BINDING_LIFETIME;
+	INIT_LIST_HEAD(&c->nemo_ha_served_prefixes);
 
 	/* CN bindings */
 	c->DoRouteOptimizationCN = 1;
@@ -304,6 +306,8 @@ void conf_show(struct mip6_config *c)
 	    CONF_BOOL_STR(c->MnDiscardHaParamProb));
 	dbg("SendMobPfxSols = %s\n", CONF_BOOL_STR(c->SendMobPfxSols));
 	dbg("OptimisticHandoff = %s\n", CONF_BOOL_STR(c->OptimisticHandoff));
+	dbg("MobRtrUseExplicitMode = %s\n",
+	    CONF_BOOL_STR(c->MobRtrUseExplicitMode));
 
 	/* HA options */
 	dbg("SendMobPfxAdvs = %s\n", CONF_BOOL_STR(c->SendMobPfxAdvs));
@@ -312,7 +316,8 @@ void conf_show(struct mip6_config *c)
 	dbg("MaxMobPfxAdvInterval = %u\n", c->MaxMobPfxAdvInterval);
 	dbg("MinMobPfxAdvInterval = %u\n", c->MinMobPfxAdvInterval);
 	dbg("HaMaxBindingLife = %u\n", c->HaMaxBindingLife);
-	
+	dbg("HaAcceptMobRtr = %s\n", CONF_BOOL_STR(c->HaAcceptMobRtr));
+
 	/* CN options */
 	dbg("DoRouteOptimizationCN = %s\n",
 	    CONF_BOOL_STR(c->DoRouteOptimizationCN));
Index: mipv6-daemon/src/conf.h
===================================================================
--- mipv6-daemon.orig/src/conf.h
+++ mipv6-daemon/src/conf.h
@@ -39,6 +39,7 @@ struct mip6_config {
 	struct list_head home_addrs;
 	char *MoveModulePath;
 	uint16_t CnBuAck;
+	char MobRtrUseExplicitMode;
 	char DoRouteOptimizationMN;
 	char MnUseAllInterfaces;
 	char MnDiscardHaParamProb;
@@ -46,15 +47,16 @@ struct mip6_config {
 	char OptimisticHandoff;
 
 	/* HA options */
+	char HaAcceptMobRtr;
 	char SendMobPfxAdvs;
 	char SendUnsolMobPfxAdvs;
 	unsigned int MaxMobPfxAdvInterval;
 	unsigned int MinMobPfxAdvInterval;
 	unsigned int HaMaxBindingLife;
+	struct list_head nemo_ha_served_prefixes;
 
 	/* CN options */
 	char DoRouteOptimizationCN;
-
 };
 
 struct net_iface {
Index: mipv6-daemon/src/dhaad_ha.c
===================================================================
--- mipv6-daemon.orig/src/dhaad_ha.c
+++ mipv6-daemon/src/dhaad_ha.c
@@ -83,8 +83,8 @@ static void dhaad_expire_halist(struct t
 	pthread_rwlock_unlock(&ha_lock);
 }
 
-void dhaad_insert_halist(struct ha_interface *i, 
-			 uint16_t key, uint16_t life_sec,
+void dhaad_insert_halist(struct ha_interface *i, uint16_t key,
+			 uint16_t life_sec, uint16_t flags,
 			 struct nd_opt_prefix_info *pinfo,
 			 const struct in6_addr *lladdr)
 {
@@ -110,6 +110,7 @@ void dhaad_insert_halist(struct ha_inter
 			return;
 		}
 		memset(ha, 0, sizeof(*ha));
+		ha->flags = flags;
 		ha->iface = i;
 		ha->addr = *addr;
 		INIT_LIST_HEAD(&ha->tqe.list);
@@ -136,18 +137,22 @@ void dhaad_insert_halist(struct ha_inter
 	return;
 }
 
-static int dhaad_get_halist(struct ha_interface *i, int max, struct iovec *iov)
+static int dhaad_get_halist(struct ha_interface *i, uint16_t flags,
+			    int max, struct iovec *iov)
 {
 	struct list_head *lp;
 	int n = 0;
 	list_for_each(lp, &i->ha_list) {
 		struct home_agent *h;
 		h = list_entry(lp, struct home_agent, list);
-		n++;
-		iov[n].iov_len = sizeof(struct in6_addr);
-		iov[n].iov_base = &h->addr;
-		if (n >= max)
-			break;
+		if (!(flags & MIP_DHREQ_FLAG_SUPPORT_MR) ||
+		    h->flags & ND_OPT_HAI_FLAG_SUPPORT_MR) {
+			n++;
+			iov[n].iov_len = sizeof(struct in6_addr);
+			iov[n].iov_base = &h->addr;
+			if (n >= max)
+				break;
+		}
 	}
 	return n;
 }
@@ -177,8 +182,12 @@ static void dhaad_recv_req(const struct 
 
 	rph->mip_dhrep_id = rqh->mip_dhreq_id;
 
+	if (rqh->mip_dhreq_flags_reserved & MIP_DHREQ_FLAG_SUPPORT_MR)
+		rph->mip_dhrep_flags_reserved = MIP_DHREP_FLAG_SUPPORT_MR;
+
 	pthread_rwlock_rdlock(&ha_lock);
-	iovlen = dhaad_get_halist(i, MAX_HOME_AGENTS, iov);
+	iovlen = dhaad_get_halist(i, rqh->mip_dhreq_flags_reserved,
+				  MAX_HOME_AGENTS, iov);
 	icmp6_send(i->ifindex, 64, ha_addr, src, iov, iovlen + 1);
 	pthread_rwlock_unlock(&ha_lock);
 	free_iov_data(&iov[0], 1);
Index: mipv6-daemon/src/dhaad_ha.h
===================================================================
--- mipv6-daemon.orig/src/dhaad_ha.h
+++ mipv6-daemon/src/dhaad_ha.h
@@ -17,8 +17,8 @@ void dhaad_halist_iterate(struct ha_inte
 			  int (* func)(int, void *, void *), void *arg);
 #endif
 
-void dhaad_insert_halist(struct ha_interface *i, 
-			 uint16_t key, uint16_t life_sec,
+void dhaad_insert_halist(struct ha_interface *i, uint16_t key,
+			 uint16_t life_sec, uint16_t flags,
 			 struct nd_opt_prefix_info *pinfo,
 			 const struct in6_addr *lladdr);
 
Index: mipv6-daemon/src/dhaad_mn.c
===================================================================
--- mipv6-daemon.orig/src/dhaad_mn.c
+++ mipv6-daemon/src/dhaad_mn.c
@@ -86,7 +86,8 @@ static int dhaad_append_candidate(struct
 }
 
 static int dhaad_send_request(int oif, struct in6_addr *src, 
-			      struct in6_addr *pfx, int plen)
+			      struct in6_addr *pfx, int plen,
+			      uint16_t flags)
 {
 	struct mip_dhaad_req *ih;
 	struct iovec iov;
@@ -98,6 +99,7 @@ static int dhaad_send_request(int oif, s
 	    return -1;
 	id = dhaad_id++;
 	ih->mip_dhreq_id = htons(id);
+	ih->mip_dhreq_flags_reserved = flags;
 	dhaad_gen_ha_anycast(&dst, pfx, plen);
 	icmp6_send(oif, 0, src, &dst, &iov, 1);
 	free_iov_data(&iov, 1);
@@ -121,7 +123,9 @@ static void dhaad_resend(struct tq_elem 
 		t->dhaad_id = dhaad_send_request(hai->primary_coa.iif,
 						 &hai->primary_coa.addr,
 						 &hai->home_prefix,
-						 hai->home_plen);
+						 hai->home_plen,
+						 hai->mob_rtr?
+						 MIP_DHREQ_FLAG_SUPPORT_MR:0);
 		t->dhaad_resends++;
 		tsadd(t->dhaad_delay, t->dhaad_delay, t->dhaad_delay);
 		add_task_rel(&t->dhaad_delay, &t->tqe, dhaad_resend);
@@ -139,11 +143,15 @@ static void _dhaad_start(struct home_add
 	      t->dhaad_resends == DHAAD_RETRIES))) {
 		if (!(hai->home_block & HOME_ADDR_BLOCK))
 			xfrm_block_hoa(hai);
+		if (hai->mob_rtr && !(hai->home_block & NEMO_RA_BLOCK))
+			xfrm_block_ra(hai);
 		t->dhaad_resends = 0;
 		t->dhaad_id = dhaad_send_request(hai->primary_coa.iif,
 						 &hai->primary_coa.addr,
 						 &hai->home_prefix,
-						 hai->home_plen);
+						 hai->home_plen,
+						 hai->mob_rtr?
+						 MIP_DHREQ_FLAG_SUPPORT_MR:0);
 		t->dhaad_delay = INITIAL_DHAAD_TIMEOUT_TS;
 		add_task_rel(&t->dhaad_delay, &t->tqe, dhaad_resend);
 	}
@@ -165,6 +173,8 @@ static void _dhaad_stop(struct home_addr
 	tsclear(t->dhaad_delay);
 	if (hai->home_block & HOME_ADDR_BLOCK)
 		xfrm_unblock_hoa(hai);
+	if (hai->home_block & NEMO_RA_BLOCK)
+		xfrm_unblock_ra(hai);
 }
 
 void dhaad_stop(struct home_addr_info *hai)
@@ -245,6 +255,12 @@ static void dhaad_recv_rep(const struct 
 		pthread_rwlock_unlock(&mn_lock);
 		return;
 	}
+	if (hai->mob_rtr &&
+	    !(rph->mip_dhrep_flags_reserved & MIP_DHREP_FLAG_SUPPORT_MR)) {
+		dbg("HA doesn't support MR\n");
+		pthread_rwlock_unlock(&mn_lock);
+		return;
+	}
 	ha = (struct in6_addr *)(ih + 1);
 
 	dhaad_flush_candidates(&hai->ha_list);
Index: mipv6-daemon/src/gram.y
===================================================================
--- mipv6-daemon.orig/src/gram.y
+++ mipv6-daemon/src/gram.y
@@ -30,10 +30,10 @@
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
+#include <stdio.h>
 #include <pthread.h>
 #include <netinet/in.h>
 #include <net/if.h>
-#include <stdio.h>
 #include <string.h>
 #include <stdarg.h>
 #include <netinet/ip6mh.h>
@@ -54,9 +54,24 @@ struct net_iface ni = {
 };
 	
 struct home_addr_info hai = {
-	.ro_policies = LIST_HEAD_INIT(hai.ro_policies)
+	.ro_policies = LIST_HEAD_INIT(hai.ro_policies),
+	.mob_net_prefixes = LIST_HEAD_INIT(hai.mob_net_prefixes)
 };
 
+LIST_HEAD(prefixes);
+
+int mv_prefixes(struct list_head *list)
+{
+	struct list_head *l, *n;
+	int res = 0;
+	list_for_each_safe(l, n, &prefixes) {
+		list_del(l);
+		list_add_tail(l, list);
+		res++;
+	}
+	return res;
+}
+
 struct policy_bind_acl_entry *bae = NULL;
 
 struct ipsec_policy_set {
@@ -165,6 +180,11 @@ static void uerror(const char *fmt, ...)
 %token		MNROUTERPROBETIMEOUT
 %token		MNDISCARDHAPARAMPROB
 %token		OPTIMISTICHANDOFF
+%token		HOMEPREFIX
+%token		HAACCEPTMOBRTR
+%token		ISMOBRTR
+%token		HASERVEDPREFIX
+%token		MOBRTRUSEEXPLICITMODE
 
 %token		INV_TOKEN
 
@@ -282,6 +302,19 @@ topdef		: MIP6ENTITY mip6entity ';'
 		{
 			conf.DefaultBindingAclPolicy = $2;
 		}
+		| HAACCEPTMOBRTR BOOL ';'
+		{
+			conf.HaAcceptMobRtr = $2;
+		}
+		| HASERVEDPREFIX prefixlistentry ';'
+		{
+			list_splice(&prefixes,
+				    conf.nemo_ha_served_prefixes.prev);
+		}
+		| MOBRTRUSEEXPLICITMODE BOOL ';'
+		{
+			conf.MobRtrUseExplicitMode = $2;
+		}
 		| BINDINGACLPOLICY bindaclpolicy ';' 
 		{
 			bae = NULL;
@@ -398,12 +431,16 @@ linksub		: QSTRING '{' linkdefs '}'
 			memcpy(nhai, &hai, sizeof(struct home_addr_info));
 			INIT_LIST_HEAD(&nhai->ro_policies);
 			INIT_LIST_HEAD(&nhai->ha_list.home_agents);
+			INIT_LIST_HEAD(&nhai->mob_net_prefixes);
 			nhai->ha_list.dhaad_id = -1;
 			list_splice(&hai.ro_policies, &nhai->ro_policies);
+			list_splice(&hai.mob_net_prefixes,
+				    &nhai->mob_net_prefixes);
 			list_add_tail(&nhai->list, &conf.home_addrs);
 
 			memset(&hai, 0, sizeof(struct home_addr_info));
 			INIT_LIST_HEAD(&hai.ro_policies);
+			INIT_LIST_HEAD(&hai.mob_net_prefixes);
 		}
 		;
 
@@ -415,16 +452,35 @@ linkdef		: HOMEAGENTADDRESS ADDR ';'
 		{
 			memcpy(&hai.ha_addr, &$2, sizeof(struct in6_addr));
 		}
-		| HOMEADDRESS ADDR '/' prefixlen ';'
-		{
-			hai.hoa.addr = $2;
-			hai.plen = $4;
-		}
+		| HOMEADDRESS homeaddress ';'
 		| USEALTCOA BOOL ';'
                 {
 		        hai.altcoa = $2;
 		}	  
 		| MNROPOLICY mnropolicy ';'
+		| ISMOBRTR BOOL ';'
+                {
+			if ($2)
+				hai.mob_rtr = IP6_MH_BU_MR;
+		}
+		|  HOMEPREFIX ADDR '/' prefixlen ';'
+                {
+			ipv6_addr_prefix(&hai.home_prefix, &$2, $4);
+			hai.home_plen = $4;
+		}
+		;
+
+homeaddress	: homeaddrdef prefixlistsub
+		{
+			hai.mnp_count = mv_prefixes(&hai.mob_net_prefixes);
+		}
+		;
+
+homeaddrdef	: ADDR '/' prefixlen
+		{
+			hai.hoa.addr = $1;
+			hai.plen = $3;
+		}
 		;
 
 ipsecpolicyset	: ipsechaaddrdef ipsecmnaddrdefs ipsecpolicydefs
@@ -639,7 +695,7 @@ bindaclpolval	: BOOL
 		| NUMBER { $$ = $1; }
 		;
 
-bindaclpolicy	: ADDR bindaclpolval
+bindaclpolicy	: ADDR prefixlistsub bindaclpolval
 		{
 			bae = malloc(sizeof(struct policy_bind_acl_entry));
 			if (bae == NULL) {
@@ -649,7 +705,9 @@ bindaclpolicy	: ADDR bindaclpolval
 			memset(bae, 0, sizeof(struct policy_bind_acl_entry)); 
 			bae->hoa = $1;
 			bae->plen = 128;
-			bae->bind_policy = $2;
+			INIT_LIST_HEAD(&bae->mob_net_prefixes);
+			bae->mnp_count = mv_prefixes(&bae->mob_net_prefixes);
+			bae->bind_policy = $3;
 			list_add_tail(&bae->list, &conf.bind_acl);
 		}
 		;
@@ -664,4 +722,27 @@ prefixlen	: NUMBER 
 		}
 		;
 
+prefixlistsub	:
+		| '(' prefixlist ')'
+		;
+
+prefixlist	: prefixlistentry
+		| prefixlist ',' prefixlistentry
+		;
+
+prefixlistentry	: ADDR '/' prefixlen
+		{
+			struct prefix_list_entry *p;
+			p = malloc(sizeof(struct prefix_list_entry));
+			if (p == NULL) {
+				fprintf(stderr,
+					"%s: out of memory\n", __FUNCTION__);
+				return -1;
+			}
+			memset(p, 0, sizeof(struct prefix_list_entry));
+			p->ple_prefix = $1;
+			p->ple_plen = $3;
+			list_add_tail(&p->list, &prefixes);
+		}
+		;
 %%
Index: mipv6-daemon/src/ha.c
===================================================================
--- mipv6-daemon.orig/src/ha.c
+++ mipv6-daemon/src/ha.c
@@ -79,6 +79,7 @@ static void ha_recv_ra(const struct icmp
 	struct ha_interface *iface;
 	uint16_t pref = 0;
 	uint16_t life = 0;
+	uint16_t flags = 0;
 
 	/* validity checks */
 	if (hoplimit < 255 || !IN6_IS_ADDR_LINKLOCAL(src) ||
@@ -120,6 +121,7 @@ static void ha_recv_ra(const struct icmp
 			hainfo = (struct nd_opt_homeagent_info *)opt;
 			pref = ntohs(hainfo->nd_opt_hai_preference);
 			life = ntohs(hainfo->nd_opt_hai_lifetime);
+			flags = hainfo->nd_opt_hai_flags_reserved;
 		}
 		optlen -= olen;
 		opt += olen;
@@ -129,7 +131,7 @@ static void ha_recv_ra(const struct icmp
 		if (pinfo[i]->nd_opt_pi_flags_reserved & 
 		    ND_OPT_PI_FLAG_RADDR) {
 			dhaad_insert_halist(iface, pref, life,
-					    pinfo[i], src);
+					    flags, pinfo[i], src);
 		}
 	}
 	mpd_del_expired_pinfos(iface);
@@ -499,14 +501,53 @@ static int ha_vt_init(void)
 }
 #endif
 
+
+static void nemo_ha_del_mnp_routes(struct list_head *old_mnps,
+				   struct list_head *new_mnps,
+				   int ifindex, int all)
+{
+	struct list_head *list;
+	list_for_each(list, old_mnps) {
+		struct prefix_list_entry *p;
+		p = list_entry(list, struct prefix_list_entry, list);
+		if (!all &&
+		    prefix_list_find(new_mnps, &p->ple_prefix, p->ple_plen))
+			continue;
+
+		route_del(ifindex, RT6_TABLE_MIP6, IP6_RT_PRIO_MIP6_FWD,
+			  NULL, 0, &p->ple_prefix, p->ple_plen, NULL);
+	}
+}
+
+static int nemo_ha_add_mnp_routes(struct list_head *old_mnps,
+				  struct list_head *new_mnps,
+				  int ifindex, int all)
+{
+	struct list_head *list;
+	list_for_each(list, new_mnps) {
+		struct prefix_list_entry *p;
+		p = list_entry(list, struct prefix_list_entry, list);
+		if (!all &&
+		    prefix_list_find(old_mnps, &p->ple_prefix, p->ple_plen))
+			continue;
+		if (route_add(ifindex, RT6_TABLE_MIP6, RTPROT_MIP,
+			      0, IP6_RT_PRIO_MIP6_FWD,
+			      NULL, 0, &p->ple_prefix, p->ple_plen, NULL) < 0)
+			return -1;
+	}
+	return 0;
+}
+
 struct home_tnl_ops_parm {
 	struct bcentry *bce;
 	int ba_status;
+	struct list_head mob_net_prefixes;
 };
 
 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);
 
@@ -514,17 +555,22 @@ static int home_tnl_del(int old_if, int 
 	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,
 		  IP6_RT_PRIO_MIP6_FWD, NULL, 0, peer_addr, 128, NULL);
+
+	/* delete MNP routes */
+	nemo_ha_del_mnp_routes(&p->bce->mob_net_prefixes,
+			       &p->mob_net_prefixes, old_if, 1);
 	/* update tunnel interface */
 	p->bce->tunnel = new_if;
 
@@ -534,17 +580,29 @@ static int home_tnl_del(int old_if, int 
 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);
 
 	our_addr = &p->bce->our_addr;
 	peer_addr = &p->bce->peer_addr;
 	coa = &p->bce->coa;
-	old_coa = &p->bce->peer_addr;
+	old_coa = IN6_ARE_ADDR_EQUAL(&p->bce->old_coa, &in6addr_any) ?
+		&p->bce->peer_addr : &p->bce->old_coa;
+	mnp = &p->mob_net_prefixes;
 
 	/* update tunnel interface */
 	p->bce->tunnel = new_if;
 
+	/* add MNP routes */
+	if (nemo_ha_add_mnp_routes(&p->bce->mob_net_prefixes,
+				   &p->mob_net_prefixes, new_if, 1) < 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;
+		goto err;
+	}
 	/* add HoA route */
 	if (route_add(new_if, RT6_TABLE_MAIN,
 		      RTPROT_MIP, 0, IP6_RT_PRIO_MIP6_FWD,
@@ -555,13 +613,13 @@ static int home_tnl_add(int old_if, int 
 	/* 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;
 		}
@@ -578,17 +636,51 @@ static int home_tnl_chg(int old_if, int 
 
 	if (old_if == new_if) {
 		const struct in6_addr *our_addr, *peer_addr, *coa, *old_coa;
+		struct list_head *mnp;
 
 		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)) {
+
+			/* Remove old policies and install new ones */
+			if (conf.UseMnHaIPsec) {
+				ha_ipsec_mnp_pol_del(our_addr, peer_addr,
+						     &p->bce->mob_net_prefixes,
+						     &p->mob_net_prefixes,
+						     p->bce->tunnel);
+				ha_ipsec_mnp_pol_add(our_addr, peer_addr,
+						     &p->bce->mob_net_prefixes,
+						     &p->mob_net_prefixes,
+						     p->bce->tunnel);
+			}
+
+			/* Do the same for routes */
+			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) &&
 		    ha_ipsec_tnl_update(our_addr, peer_addr, coa, old_coa,
-					p->bce->tunnel) < 0) {
+					p->bce->tunnel, mnp) < 0) {
 			return -1;
 		}
 	} else { 
@@ -634,6 +726,61 @@ static void home_cleanup(struct bcentry 
 	}
 }
 
+
+static int ha_extract_mnps(const struct ip6_mh_binding_update *bu,
+			   const struct mh_options *opts,
+			   struct list_head *mob_net_prefixes)
+{
+	struct ip6_mh_opt_mob_net_prefix *op;
+	int prefix_count = 0;
+	for (op = mh_opt(&bu->ip6mhbu_hdr, opts, IP6_MHOPT_MOB_NET_PRFX);
+	     op != NULL;
+	     op = mh_opt_next(&bu->ip6mhbu_hdr, opts, op)) {
+		struct prefix_list_entry *p;
+		p = malloc(sizeof(struct prefix_list_entry));
+		if (p == NULL) {
+			prefix_list_free(mob_net_prefixes);
+			return -1;
+		}
+		memset(p, 0, sizeof(struct prefix_list_entry));
+		p->ple_plen = op->ip6mnp_prefix_len;
+		p->ple_prefix = op->ip6mnp_prefix;
+		list_add_tail(&p->list, mob_net_prefixes);
+		prefix_count++;
+	}
+	return prefix_count;
+}
+
+static int ha_get_mnps(const struct in6_addr *hoa,
+		       struct list_head *mob_net_prefixes)
+{
+	struct nd_opt_prefix_info *mnps;
+	int mnp_count = conf.pmgr.get_mnp_count(hoa);
+	int i;
+
+	if (mnp_count <= 0)
+		return mnp_count;
+
+	mnps = calloc(mnp_count, sizeof(struct nd_opt_prefix_info));
+	if (mnps == NULL)
+		return -1;
+
+	mnp_count = conf.pmgr.get_mnps(hoa, mnp_count, mnps);
+	for (i = 0; i < mnp_count; i++) {
+		struct prefix_list_entry *p;
+		p = malloc(sizeof(struct prefix_list_entry));
+		if (p == NULL) {
+			prefix_list_free(mob_net_prefixes);
+			free(mnps);
+			return -1;
+		}
+		p->pinfo = *(mnps + i);
+		list_add_tail(&p->list, mob_net_prefixes);
+	}
+	free(mnps);
+	return mnp_count;
+}
+
 struct ha_recv_bu_args {
 	struct list_head list;
 	struct in6_addr src;
@@ -684,8 +831,9 @@ restart:	
 	bce = bcache_get(out.src, out.dst);
 	if (bce) {
 		if (bce->type != BCE_NONCE_BLOCK) {
-			if (!(bce->flags & IP6_MH_BU_HOME)) {
-				/* H-bit mismatch, flags changed */
+			/* H-bit or R-bit mismatch, flags changed */
+			if ((bce->flags ^ bu_flags) &
+			    (IP6_MH_BU_HOME | IP6_MH_BU_MR)) {
 				bcache_release_entry(bce);
 				bce = NULL;
 				status = IP6_MH_BAS_REG_NOT_ALLOWED;
@@ -733,9 +881,15 @@ restart:	
 	}
 	if ((status = mpd_prefix_check(out.src, out.dst,
 				       &lft, &home_ifindex, new)) < 0) {
-		/* not home agent for this subnet */
-		status = IP6_MH_BAS_NOT_HOME_SUBNET;
-		goto send_nack;
+		if (!(bu_flags & IP6_MH_BU_MR) ||
+		    home_ifindex == 0 ||
+		    !prefix_list_find(&conf.nemo_ha_served_prefixes,
+		     		      out.dst, 0)) {
+			/* not home agent for this subnet */
+			status = IP6_MH_BAS_NOT_HOME_SUBNET;
+			goto send_nack;
+		}
+		status = IP6_MH_BAS_ACCEPTED;
 	}
 	status = conf.pmgr.discard_binding(out.dst, out.bind_coa,
 					   out.src, arg->bu, arg->len);
@@ -787,6 +941,25 @@ restart:	
 		}
 		new = 1;
 	}
+	INIT_LIST_HEAD(&p.mob_net_prefixes);
+	if (bu_flags & IP6_MH_BU_MR && tsisset(lft)) {
+		if (mh_opt(&arg->bu->ip6mhbu_hdr,
+			   &arg->mh_opts, IP6_MHOPT_MOB_NET_PRFX) != NULL) {
+			if (ha_extract_mnps(arg->bu,
+					    &arg->mh_opts,
+					    &p.mob_net_prefixes) < 0) {
+				status = IP6_MH_BAS_INVAL_PRFX;
+				goto send_nack;
+			}
+			bce->nemo_type = BCE_NEMO_EXPLICIT;
+		} else if (ha_get_mnps(out.dst, &p.mob_net_prefixes) > 0) {
+			bce->nemo_type = BCE_NEMO_IMPLICIT;
+		} else {
+			/* Todo: dynamic routing */
+			status = IP6_MH_BAS_FWDING_FAILED;
+			goto send_nack;
+		}
+	}
 	p.bce = bce;
 	p.ba_status = status;
 	bce->seqno = seqno;
@@ -801,6 +974,9 @@ restart:	
 				status = IP6_MH_BAS_INSUFFICIENT;
 			goto send_nack;
 		}
+		/* Now save the MNP list in the BCE */
+		list_splice(&p.mob_net_prefixes, &bce->mob_net_prefixes);
+
 		bce->cleanup = home_cleanup;
 
 		if (route_add(bce->link, RT6_TABLE_MIP6,
@@ -829,6 +1005,10 @@ restart:	
 				status = IP6_MH_BAS_INSUFFICIENT;
 			goto send_nack;
 		}
+		/* Now update the MNP list in the BCE */
+		prefix_list_free(&bce->mob_net_prefixes);
+		list_splice(&p.mob_net_prefixes, &bce->mob_net_prefixes);
+
 		bcache_update_expire(bce);
 	}
 	/* bce is always valid here */
@@ -855,6 +1035,9 @@ restart:	
 		 * have a binding before sending this Binding Update,
 		 * discard the connections to the home address. */
 	}
+ 	if (status < IP6_MH_BAS_UNSPECIFIED && bu_flags & IP6_MH_BU_MR)
+ 		ba_flags |= IP6_MH_BA_MR;
+
 	if (!(arg->flags & HA_BU_F_SKIP_BA))
 		mh_send_ba(&out, status, ba_flags, seqno, &lft, NULL, iif);
 	if (new && tsisset(lft))
Index: mipv6-daemon/src/ha.h
===================================================================
--- mipv6-daemon.orig/src/ha.h
+++ mipv6-daemon/src/ha.h
@@ -23,6 +23,7 @@ struct home_agent {
 	struct list_head list;
 	struct in6_addr addr;
 	uint16_t preference;
+	uint16_t flags;
 	struct timespec lifetime;
 	struct ha_interface *iface;
 	struct tq_elem tqe;
Index: mipv6-daemon/src/ipsec.c
===================================================================
--- mipv6-daemon.orig/src/ipsec.c
+++ mipv6-daemon/src/ipsec.c
@@ -81,7 +81,9 @@ static void _set_sp(struct xfrm_userpoli
 		    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 @@ static void _set_sp(struct xfrm_userpoli
 	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) {
@@ -347,6 +352,7 @@ struct ha_ipsec_tnl_update {
 	int tunnel;
 	struct in6_addr coa;
 	struct in6_addr old_coa;
+	struct list_head *mnp;
 };
 
 /*
@@ -365,6 +371,7 @@ static int _ha_tnl_update(const struct i
 	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;
@@ -399,13 +406,14 @@ static int _ha_tnl_update(const struct i
 	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);
 
 	/* 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 +423,7 @@ static int _ha_tnl_update(const struct i
 	/* 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,13 +433,56 @@ static int _ha_tnl_update(const struct i
 	/* 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");
         	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;
 }
@@ -440,15 +491,178 @@ int ha_ipsec_tnl_update(const struct in6
 			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);
 }
 
+struct ha_ipsec_mnp_update {
+	int tunnel;
+	struct list_head *old_mnps;
+	struct list_head *new_mnps;
+};
+
+/*
+ *   Add/Delete MNP IPsec Security Policy
+ */
+static int _ha_mnp_pol_mod(const struct in6_addr *haaddr,
+			   const struct in6_addr *hoa,
+			   struct ipsec_policy_entry *e,
+			   void *arg,
+			   int add)
+{
+	int err = 0;
+	struct ha_ipsec_mnp_update *parms = (struct ha_ipsec_mnp_update *)arg;
+	struct xfrm_userpolicy_info sp;
+	struct xfrm_user_tmpl tmpl;
+	u_int16_t ipsec_proto;
+	struct list_head *list, *old_mnps, *new_mnps, *main_mnps, *ref_mnps;
+	int ifindex;
+
+	assert(haaddr);
+	assert(hoa);
+	assert(e);
+	assert(arg);
+
+	ifindex = parms->tunnel;
+	old_mnps = parms->old_mnps;
+	new_mnps = parms->new_mnps;
+
+	if (e->type != IPSEC_POLICY_TYPE_TUNNELPAYLOAD)
+		goto end;
+
+	/* XXX Limitation: Single IPsec proto can only be applied */
+	if (ipsec_use_esp(e))
+		ipsec_proto = IPPROTO_ESP;
+	else if (ipsec_use_ah(e))
+		ipsec_proto = IPPROTO_AH;
+	else if (ipsec_use_ipcomp(e))
+		ipsec_proto = IPPROTO_COMP;
+	else {
+		dbg("invalid ipsec proto\n");
+		goto end;
+	}
+
+	/* Reverse the search logic on lists based on expected
+	 * action (add/del) */
+	main_mnps = add ? new_mnps : old_mnps;
+	ref_mnps = add ? old_mnps : new_mnps;
+
+	if (main_mnps == NULL)
+		goto end;
+
+	/* We have to add/delete rules to protect traffic to
+	   and from MNP's, the same way as HoA */
+	list_for_each(list, main_mnps) {
+		struct prefix_list_entry *p;
+		p = list_entry(list, struct prefix_list_entry, list);
+
+		if (ref_mnps &&
+		    prefix_list_find(ref_mnps, &p->ple_prefix, p->ple_plen))
+			continue;
+
+		/* 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;
+}
+
+
+/*
+ *   Add SP entry (for MNP on HA)
+ *
+ *   NOTE:
+ *   - This is a hook routine to ipsec_policy_apply()
+ */
+static int _ha_mnp_pol_add(const struct in6_addr *haaddr,
+			   const struct in6_addr *hoa,
+			   struct ipsec_policy_entry *e,
+			   void *arg)
+{
+	return _ha_mnp_pol_mod(haaddr, hoa, e, arg, 1);
+}
+
+int ha_ipsec_mnp_pol_add(const struct in6_addr *our_addr,
+			 const struct in6_addr *peer_addr,
+			 struct list_head *old_mnps,
+			 struct list_head *new_mnps,
+			 int tunnel)
+{
+	struct ha_ipsec_mnp_update b;
+	b.tunnel = tunnel;
+	b.old_mnps = old_mnps;
+	b.new_mnps = new_mnps;
+
+	return ipsec_policy_apply(our_addr, peer_addr, _ha_mnp_pol_add, &b);
+}
+
+/*
+ *   Delete SP entry (for MNP on HA)
+ *
+ *   NOTE:
+ *   - This is a hook routine to ipsec_policy_apply()
+ */
+static int _ha_mnp_pol_del(const struct in6_addr *haaddr,
+			   const struct in6_addr *hoa,
+			   struct ipsec_policy_entry *e,
+			   void *arg)
+{
+	return _ha_mnp_pol_mod(haaddr, hoa, e, arg, 0);
+}
+
+int ha_ipsec_mnp_pol_del(const struct in6_addr *our_addr,
+			 const struct in6_addr *peer_addr,
+			 struct list_head *old_mnps,
+			 struct list_head *new_mnps,
+			 int tunnel)
+{
+	struct ha_ipsec_mnp_update b;
+	b.tunnel = tunnel;
+	b.old_mnps = old_mnps;
+	b.new_mnps = new_mnps;
+
+	return ipsec_policy_apply(our_addr, peer_addr,
+				  _ha_mnp_pol_del, &b);
+}
+
 /*
  *   Add/Delete IPsec Security Policy 
  */
@@ -459,7 +673,9 @@ static int _ha_tnl_pol_mod(const struct 
 			   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;
@@ -469,6 +685,9 @@ static int _ha_tnl_pol_mod(const struct 
 	assert(e);
 	assert(arg);
 
+	ifindex = parms->tunnel;
+	mnp = parms->mnp;
+
 	switch (e->type) {
 	case IPSEC_POLICY_TYPE_TUNNELHOMETESTING:
 	case IPSEC_POLICY_TYPE_TUNNELMH:
@@ -493,7 +712,7 @@ static int _ha_tnl_pol_mod(const struct 
 	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 +723,7 @@ static int _ha_tnl_pol_mod(const struct 
 	}
 
 	/* 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 +734,7 @@ static int _ha_tnl_pol_mod(const struct 
 	}
 
 	/* 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);
@@ -525,6 +744,16 @@ static int _ha_tnl_pol_mod(const struct 
 		goto end;
 	}
 
+	/* Mobile Router case */
+	if ((e->type == IPSEC_POLICY_TYPE_TUNNELPAYLOAD) && mnp) {
+		struct ha_ipsec_mnp_update b;
+
+		b.tunnel = ifindex;
+		b.old_mnps = add ? NULL : mnp;
+		b.new_mnps = add ? mnp : NULL;
+
+		err = _ha_mnp_pol_mod(haaddr, hoa, e, (void *)&b, add);
+	}
  end:
 	return err;
 }
@@ -545,11 +774,14 @@ static int _ha_tnl_pol_add(const struct 
 
 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);
 }
 
 /*
@@ -568,12 +800,15 @@ static int _ha_tnl_pol_del(const struct 
 
 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);
 }
 
 /*
@@ -631,7 +866,7 @@ static int _mn_tnl_update(const struct i
 	/* 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 +876,7 @@ static int _mn_tnl_update(const struct i
 	/* 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 +892,7 @@ static int _mn_tnl_update(const struct i
 		/* 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;
@@ -669,6 +904,52 @@ static int _mn_tnl_update(const struct i
 		}
 	}
 
+	/*
+	 * 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;
 }
@@ -724,7 +1005,7 @@ static int _mn_tnl_pol_mod(const struct 
 	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 +1016,7 @@ static int _mn_tnl_pol_mod(const struct 
 	}
 		
 	/* 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);
@@ -761,6 +1042,54 @@ static int _mn_tnl_pol_mod(const struct 
 		}
 	}
 
+	/*
+	 * 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;
 }
Index: mipv6-daemon/src/ipsec.h
===================================================================
--- mipv6-daemon.orig/src/ipsec.h
+++ mipv6-daemon/src/ipsec.h
@@ -82,16 +82,31 @@ int ha_ipsec_tnl_update(const struct in6
 			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, 
+int ha_ipsec_mnp_pol_del(const struct in6_addr *our_addr,
 			 const struct in6_addr *peer_addr,
+			 struct list_head *old_mnps,
+			 struct list_head *new_mnps,
 			 int tunnel);
 
-int ha_ipsec_tnl_pol_del(const struct in6_addr *our_addr, 
+int ha_ipsec_mnp_pol_add(const struct in6_addr *our_addr,
 			 const struct in6_addr *peer_addr,
+			 struct list_head *old_mnps,
+			 struct list_head *new_mnps,
 			 int tunnel);
 
+int ha_ipsec_tnl_pol_add(const struct in6_addr *our_addr, 
+			 const struct in6_addr *peer_addr,
+			 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,
+			 struct list_head *mnp);
+
 int mn_ipsec_tnl_update(const struct in6_addr *haaddr,
 			const struct in6_addr *hoa,
 			void *arg);
Index: mipv6-daemon/src/mh.c
===================================================================
--- mipv6-daemon.orig/src/mh.c
+++ mipv6-daemon/src/mh.c
@@ -51,6 +51,7 @@
 #include "conf.h"
 #include "bcache.h"
 #include "keygen.h"
+#include "prefix.h"
 
 #define MH_DEBUG_LEVEL 1
 
@@ -75,6 +76,7 @@ int mh_opts_dup_ok[] = {
 	0, /* Alternate CoA */
 	0, /* Nonce Index */
 	0, /* Binding Auth Data */
+	1, /* Mobile Network Prefix */
 };
 
 #define __MH_SENTINEL (IP6_MH_TYPE_MAX + 1)
@@ -401,6 +403,46 @@ static int create_opt_pad(struct iovec *
 	return 0;
 }
 
+int mh_create_opt_mob_net_prefix(struct iovec *iov, int mnp_count,
+				 struct list_head *mnps)
+{
+	int optlen = (mnp_count * sizeof(struct ip6_mh_opt_mob_net_prefix) +
+		      (mnp_count - 1) * sizeof(_pad4));
+	struct list_head *l;
+	int i = 0;
+	uint8_t *data;
+	iov->iov_base = malloc(optlen);
+	iov->iov_len = optlen;
+
+	if (iov->iov_base == NULL)
+		return -ENOMEM;
+
+	memset(iov->iov_base, 0, iov->iov_len);
+	data = (uint8_t *)iov->iov_base;
+
+	list_for_each(l, mnps) {
+		struct prefix_list_entry *p;
+		struct ip6_mh_opt_mob_net_prefix *mnp;
+
+		p = list_entry(l, struct prefix_list_entry, list);
+		mnp = (struct ip6_mh_opt_mob_net_prefix *)data;
+
+		mnp->ip6mnp_type = IP6_MHOPT_MOB_NET_PRFX;
+		mnp->ip6mnp_len = 18;
+		mnp->ip6mnp_prefix_len = p->ple_plen;
+		mnp->ip6mnp_prefix = p->ple_prefix;
+
+		data += sizeof(struct ip6_mh_opt_mob_net_prefix);
+
+		/* do internal padding here, so one iovec for MNPs is enough */
+		if (++i < mnp_count) {
+		  memcpy(data, _pad4, sizeof(_pad4));
+		  data += sizeof(_pad4);
+		}
+	}
+	return 0;
+}
+
 static size_t mh_length(struct iovec *vec, int count)
 {
 	size_t len = 0;
@@ -442,6 +484,9 @@ static int mh_try_pad(const struct iovec
 		case IP6_MHOPT_BAUTH:
 			pad = optpad(8, 2, len); /* 8n+2 */
 			break;
+		case IP6_MHOPT_MOB_NET_PRFX:
+			pad = optpad(8, 4, len); /* 8n+4 */
+			break;
 		}
 		if (pad > 0) {
 			create_opt_pad(&out[n++], pad);
@@ -694,6 +739,8 @@ static int mh_opt_len_chk(uint8_t type, 
 		return len != sizeof(struct ip6_mh_opt_nonce_index);
 	case IP6_MHOPT_BAUTH:
 		return len != sizeof(struct ip6_mh_opt_auth_data);
+	case IP6_MHOPT_MOB_NET_PRFX:
+		return len != sizeof(struct ip6_mh_opt_mob_net_prefix);
 	case IP6_MHOPT_PADN:
 	default:
 		return 0;
Index: mipv6-daemon/src/mh.h
===================================================================
--- mipv6-daemon.orig/src/mh.h
+++ mipv6-daemon/src/mh.h
@@ -10,7 +10,7 @@
 
 /* If new types or options appear, these should be updated. */
 #define IP6_MH_TYPE_MAX IP6_MH_TYPE_BERROR
-#define IP6_MHOPT_MAX IP6_MHOPT_BAUTH
+#define IP6_MHOPT_MAX IP6_MHOPT_MOB_NET_PRFX
 
 struct in6_addr_bundle {
 	struct in6_addr *src;
@@ -74,6 +74,11 @@ int mh_create_opt_nonce_index(struct iov
 
 int mh_create_opt_auth_data(struct iovec *iov);
 
+struct list_head;
+
+int mh_create_opt_mob_net_prefix(struct iovec *iov, int mnp_count,
+				 struct list_head *mnps);
+
 static inline void *mh_opt(const struct ip6_mh *mh,
 			   const struct mh_options *mh_opts, uint8_t type)
 {
Index: mipv6-daemon/src/mn.c
===================================================================
--- mipv6-daemon.orig/src/mn.c
+++ mipv6-daemon/src/mn.c
@@ -326,7 +326,17 @@ static int mn_send_bu_msg(struct bulentr
 		free_iov_data(iov, iov_ind);
 		return -ENOMEM;
 	}
-	if (!(bule->flags & IP6_MH_BU_HOME)) {
+	if (bule->flags & IP6_MH_BU_HOME) {
+		struct home_addr_info *hai = bule->home;
+		if (bule->flags & IP6_MH_BU_MR && bu->ip6mhbu_lifetime &&
+		    bule->home->mnp_count > 0 && conf.MobRtrUseExplicitMode &&
+		    mh_create_opt_mob_net_prefix(&iov[iov_ind++],
+						 hai->mnp_count,
+						 &hai->mob_net_prefixes) < 0) {
+			free_iov_data(iov, iov_ind);
+			return -ENOMEM;
+		}
+	} else {
 		if (mh_create_opt_nonce_index(&iov[iov_ind++], bule->rr.ho_ni,
 					      bule->rr.co_ni) ||
 		    mh_create_opt_auth_data(&iov[iov_ind++])) {
@@ -616,6 +626,34 @@ static int mv_hoa(struct ifaddrmsg *ifa,
 	return 0;
 }
 
+int nemo_mr_tnl_routes_add(struct home_addr_info *hai, int ifindex)
+{
+	struct list_head *l;
+	struct prefix_list_entry *pe;
+	list_for_each(l, &hai->mob_net_prefixes) {
+		struct prefix_list_entry *p;
+		p = list_entry(l, struct prefix_list_entry, list);
+		if (route_add(ifindex, RT6_TABLE_MIP6, RTPROT_MIP,
+			      0, IP6_RT_PRIO_MIP6_FWD,
+			      &p->ple_prefix, p->ple_plen,
+			      &in6addr_any, 0, NULL) < 0) {
+			pe = p;
+			goto undo;
+		}
+	}
+	return 0;
+undo:
+	list_for_each(l, &hai->mob_net_prefixes) {
+		struct prefix_list_entry *p;
+		p = list_entry(l, struct prefix_list_entry, list);
+		route_del(ifindex, RT6_TABLE_MIP6, IP6_RT_PRIO_MIP6_FWD,
+			  &p->ple_prefix, p->ple_plen, &in6addr_any, 0, NULL);
+		if (p == pe)
+			break;
+	}
+	return -1;
+}
+
 static int mn_tnl_state_add(struct home_addr_info *hai, int ifindex, int all)
 {
 	int err = 0;
@@ -628,12 +666,31 @@ static int mn_tnl_state_add(struct home_
 			mn_ro_pol_del(hai, ifindex, all);
 		}
 	}
+	if (hai->mob_rtr &&
+	    (err = nemo_mr_tnl_routes_add(hai, ifindex)) < 0) {
+		route_del(ifindex, RT6_TABLE_MIP6, IP6_RT_PRIO_MIP6_OUT,
+			  &hai->hoa.addr, 128, &in6addr_any, 0, NULL);
+		mn_ro_pol_del(hai, ifindex, all);
+	}
 	return err;
 }
 
+static void nemo_mr_tnl_routes_del(struct home_addr_info *hai, int ifindex)
+{
+	struct list_head *l;
+	list_for_each(l, &hai->mob_net_prefixes) {
+		struct prefix_list_entry *p;
+		p = list_entry(l, struct prefix_list_entry, list);
+		route_del(ifindex, RT6_TABLE_MIP6, IP6_RT_PRIO_MIP6_FWD,
+			  &p->ple_prefix, p->ple_plen, &in6addr_any, 0, NULL);
+	}
+}
+
 static void mn_tnl_state_del(struct home_addr_info *hai, int ifindex, int all)
 {
 	if (hai->home_reg_status != HOME_REG_NONE) {
+		if (hai->mob_rtr)
+			nemo_mr_tnl_routes_del(hai, ifindex);
 		route_del(ifindex, RT6_TABLE_MIP6, IP6_RT_PRIO_MIP6_OUT, 
 			  &hai->hoa.addr, 128, &in6addr_any, 0, NULL);
 		mn_ro_pol_del(hai, ifindex, all);
@@ -674,7 +731,8 @@ static int process_first_home_bu(struct 
 {
 	int err = 0;
 	bule->type = BUL_ENTRY;
-	bule->flags = IP6_MH_BU_HOME | IP6_MH_BU_ACK | hai->lladdr_comp;
+	bule->flags = (IP6_MH_BU_HOME | IP6_MH_BU_ACK |
+		       hai->lladdr_comp | hai->mob_rtr);
 	bule->coa_changed = -1;
 	bule->coa = hai->primary_coa.addr;
 	bule->if_coa = hai->primary_coa.iif;
@@ -1086,6 +1144,18 @@ static void mn_recv_ba(const struct ip6_
 	if (bule->flags & IP6_MH_BU_HOME) {
 		struct home_addr_info *hai = bule->home;
 		struct ip6_mh_opt_refresh_advice *bra;
+
+		if (bule->flags & IP6_MH_BU_MR &&
+		    !(ba->ip6mhba_flags & IP6_MH_BA_MR)) {
+			if (hai->use_dhaad) {
+				mn_change_ha(hai);
+			} else {
+				int one = 1;
+				bul_iterate(&hai->bul, mn_dereg, &one);
+			}
+			pthread_rwlock_unlock(&mn_lock);
+			return;
+		}
 		if (!tsisset(ba_lifetime)) {
 			int type = FLUSH_FAILED;
 			mn_dereg_home(hai);
@@ -1259,12 +1329,73 @@ static int flag_hoa(struct ifaddrmsg *if
 	return 0;
 }
 
+static void nemo_mr_rules_del(struct home_addr_info *hinfo)
+{
+	struct list_head *l;
+
+	list_for_each(l, &hinfo->mob_net_prefixes) {
+		struct prefix_list_entry *p = NULL;
+		p = list_entry(l, struct prefix_list_entry, list);
+		rule_del(NULL, RT6_TABLE_MIP6,
+			 IP6_RULE_PRIO_MIP6_FWD, RTN_UNICAST,
+			 &p->ple_prefix, p->ple_plen, &in6addr_any, 0, 0);
+		rule_del(NULL, RT6_TABLE_MAIN,
+			 IP6_RULE_PRIO_MIP6_MNP_IN, RTN_UNICAST,
+			 &in6addr_any, 0, &p->ple_prefix, p->ple_plen, 0);
+	}
+}
+
+static int nemo_mr_rules_add(struct home_addr_info *hinfo)
+{
+	struct prefix_list_entry *pe = NULL;
+	struct list_head *l;
+
+	list_for_each(l, &hinfo->mob_net_prefixes) {
+		struct prefix_list_entry *p = NULL;
+		p = list_entry(l, struct prefix_list_entry, list);
+		if (rule_add(NULL, RT6_TABLE_MAIN,
+			     IP6_RULE_PRIO_MIP6_MNP_IN, RTN_UNICAST,
+			     &in6addr_any, 0,
+			     &p->ple_prefix, p->ple_plen, 0) < 0) {
+			pe = p;
+			goto undo;
+		}
+		if (rule_add(NULL, RT6_TABLE_MIP6,
+			     IP6_RULE_PRIO_MIP6_FWD, RTN_UNICAST,
+			     &p->ple_prefix, p->ple_plen,
+			     &in6addr_any, 0, 0) < 0) {
+			rule_del(NULL, RT6_TABLE_MAIN,
+				 IP6_RULE_PRIO_MIP6_MNP_IN, RTN_UNICAST,
+				 &in6addr_any, 0, &p->ple_prefix, p->ple_plen, 0);
+			pe = p;
+			goto undo;
+		}
+	}
+	return 0;
+undo:
+	list_for_each(l, &hinfo->mob_net_prefixes) {
+		struct prefix_list_entry *p = NULL;
+		p = list_entry(l, struct prefix_list_entry, list);
+		rule_del(NULL, RT6_TABLE_MIP6,
+			 IP6_RULE_PRIO_MIP6_FWD,  RTN_UNICAST,
+			 &p->ple_prefix, p->ple_plen, &in6addr_any, 0, 0);
+		rule_del(NULL, RT6_TABLE_MAIN,
+			 IP6_RULE_PRIO_MIP6_MNP_IN, RTN_UNICAST,
+			 &in6addr_any, 0, &p->ple_prefix, p->ple_plen, 0);
+		if (p == pe)
+			break;
+	}
+	return -1;
+}
+
 static void clean_home_addr_info(struct home_addr_info *hai)
 {
 	struct flag_hoa_args arg;
 	int plen = (hai->hoa.iif == hai->if_tunnel ? 128 : hai->plen);
 
 	list_del(&hai->list);
+	if (hai->mob_rtr)
+		nemo_mr_rules_del(hai);
 	arg.target = hai;
 	arg.flag = 0;
 	addr_do(&hai->hoa.addr, plen,
@@ -1318,13 +1449,23 @@ static struct home_addr_info *hai_copy(s
 
 		if (pthread_mutex_init(&hai->ha_list.c_lock, NULL))
 			goto undo;
+
+		INIT_LIST_HEAD(&hai->mob_net_prefixes);
+		if (hai->mob_rtr &&
+		    prefix_list_copy(&conf_hai->mob_net_prefixes,
+				     &hai->mob_net_prefixes) < 0)
+			goto mutex_undo;
+
 		INIT_LIST_HEAD(&hai->ro_policies);
 		if (rpl_copy(&conf_hai->ro_policies, &hai->ro_policies) < 0)
-			goto mutex_undo;
+			goto mnp_undo;
+
 		INIT_LIST_HEAD(&hai->ha_list.tqe.list);
 		INIT_LIST_HEAD(&hai->ha_list.home_agents);
 	}
 	return hai;
+mnp_undo:
+	prefix_list_free(&hai->mob_net_prefixes);
 mutex_undo:
 	pthread_mutex_destroy(&hai->ha_list.c_lock);
 undo:
@@ -1345,6 +1486,15 @@ static int conf_home_addr_info(struct ho
 	if  ((hai = hai_copy(conf_hai)) == NULL)
 		goto err;
 
+	if (hai->mob_rtr) {
+		MDBG("is Mobile Router\n");
+		list_for_each(list, &hai->mob_net_prefixes) {
+			struct prefix_list_entry *p;
+			p = list_entry(list, struct prefix_list_entry, list);
+			MDBG("Mobile Network Prefix %x:%x:%x:%x:%x:%x:%x:%x/%d\n",
+			     NIP6ADDR(&p->ple_prefix), p->ple_plen);
+		}
+	}
 	if (IN6_IS_ADDR_UNSPECIFIED(&hai->ha_addr)) {
 		hai->use_dhaad = 1;
 	} else {
@@ -1388,6 +1538,9 @@ static int conf_home_addr_info(struct ho
 		    hai->if_tunnel, &arg, flag_hoa) < 0) {
 		goto clean_err;
 	}
+	if (hai->mob_rtr && nemo_mr_rules_add(hai) < 0) {
+		goto clean_err;
+	}
 	hai->at_home = hai->hoa.iif == hai->if_home;
 	pthread_rwlock_wrlock(&mn_lock);
 	list_add(&hai->list, &home_addr_list);
Index: mipv6-daemon/src/mn.h
===================================================================
--- mipv6-daemon.orig/src/mn.h
+++ mipv6-daemon/src/mn.h
@@ -45,9 +45,11 @@ struct ha_candidate_list {
 	pthread_mutex_t c_lock;
 };
 
-#define	HOME_LINK_BLOCK	0x1
-#define	HOME_ADDR_BLOCK	0x2
-#define	HOME_ADDR_RULE_BLOCK	0x4
+#define	HOME_LINK_BLOCK	0x01
+#define	HOME_ADDR_BLOCK	0x02
+#define	HOME_ADDR_RULE_BLOCK	0x04
+#define	NEMO_RA_BLOCK	0x08
+#define	NEMO_FWD_BLOCK	0x10
 
 struct mn_addr {
 	struct in6_addr addr;
@@ -84,7 +86,10 @@ struct home_addr_info {
 	int if_block;
 	short hwalen;
 	uint8_t altcoa;
+	uint16_t mob_rtr;
 	char name[IF_NAMESIZE];
+	int mnp_count;
+	struct list_head mob_net_prefixes;
 };
 
 enum {
Index: mipv6-daemon/src/movement.c
===================================================================
--- mipv6-daemon.orig/src/movement.c
+++ mipv6-daemon/src/movement.c
@@ -78,6 +78,7 @@ static int conf_default_ra_defrtr = 1;
 static int conf_default_rs = 3;
 static int conf_default_rs_ival = 4;
 
+static int conf_forwarding = 0;
 static int conf_autoconf = 1;
 static int conf_ra_defrtr = 0;
 static int conf_rs = 0;
@@ -177,6 +178,12 @@ static void __md_free_router(struct md_r
 
 		route_del(rtr->ifindex, RT_TABLE_MAIN, 0,
 			  &in6addr_any, 0, &in6addr_any, 0, &rtr->lladdr);
+
+		/* delete default route for the packets coming from the
+		 * Mobile Network
+		 */
+		route_del(rtr->ifindex, RT6_TABLE_MIP6, 0,
+			  &in6addr_any, 0, &in6addr_any, 0, &rtr->lladdr);
 	}
 	list_for_each_safe(l, n, &rtr->prefixes) {
 		struct prefix_list_entry *p;
@@ -231,8 +238,31 @@ static void md_expire_coa(struct md_inet
 	list_add_tail(&coa->list, &iface->expired_coas);
 }
 
+static void md_reset_egress_forward(void)
+{
+	struct list_head *l;
+	int forward = 0;;
+
+	if (list_empty(&ifaces))
+		return;
+
+	list_for_each(l, &ifaces) {
+		struct md_inet6_iface *i;
+		i = list_entry(l, struct md_inet6_iface, list);
+		forward |= i->home_link;
+	}
+	list_for_each(l, &ifaces) {
+		struct md_inet6_iface *i;
+		i = list_entry(l, struct md_inet6_iface, list);
+		set_iface_proc_entry(PROC_SYS_IP6_FORWARDING,
+				     i->name, forward);
+	}
+}
+
 static void md_reset_home_link(struct md_inet6_iface *i)
 {
+	if (i->home_link)
+		md_reset_egress_forward();
 	i->home_link = 0;
 	i->ll_dad_unsafe = 0;
 }
@@ -648,6 +678,8 @@ md_create_inet6_iface(struct ifinfomsg *
 
 static void iface_proc_entries_init(struct md_inet6_iface *iface)
 {
+	set_iface_proc_entry(PROC_SYS_IP6_FORWARDING, iface->name,
+			     conf_forwarding);
 	set_iface_proc_entry(PROC_SYS_IP6_AUTOCONF, iface->name,
 			     conf_autoconf);
 	set_iface_proc_entry(PROC_SYS_IP6_ACCEPT_RA_DEFRTR, iface->name, conf_ra_defrtr);
@@ -878,6 +910,8 @@ static void md_check_home_link(struct md
 			ll_dad_unsafe |= hai->lladdr_comp;
 		}
 	}
+	if (i->home_link != home_link)
+		md_reset_egress_forward();
 	i->home_link = home_link;
 	i->ll_dad_unsafe = ll_dad_unsafe;
 }
@@ -1189,6 +1223,11 @@ static void md_update_router_stats(struc
 		  RTF_DEFAULT|RTF_ADDRCONF, 1024,
 		  &in6addr_any, 0, &in6addr_any, 0, &rtr->lladdr);
 	
+	/* default route for the packet coming from the Mobile Network */
+	route_add(rtr->ifindex, RT6_TABLE_MIP6, RTPROT_MIP,
+		  0, IP6_RT_PRIO_MIP6_FWD,
+		  &in6addr_any, 0, &in6addr_any, 0, &rtr->lladdr);
+
 	list_for_each(list, &rtr->prefixes) {
 		struct prefix_list_entry *p;
 		p = list_entry(list, struct prefix_list_entry, list);
@@ -1737,6 +1776,8 @@ static void iface_default_proc_entries_c
 
 static void iface_proc_entries_cleanup(struct md_inet6_iface *iface)
 {
+	set_iface_proc_entry(PROC_SYS_IP6_FORWARDING, iface->name,
+			     iface->devconf[DEVCONF_FORWARDING]);
 	set_iface_proc_entry(PROC_SYS_IP6_AUTOCONF, iface->name,
 			     iface->devconf[DEVCONF_AUTOCONF]);
 	set_iface_proc_entry(PROC_SYS_IP6_ACCEPT_RA_DEFRTR, iface->name,
Index: mipv6-daemon/src/ndisc.c
===================================================================
--- mipv6-daemon.orig/src/ndisc.c
+++ mipv6-daemon/src/ndisc.c
@@ -106,7 +106,7 @@ int proxy_nd_start(int ifindex, struct i
 {
 	struct in6_addr lladdr;
 	int err;
-	int nd_flags = 0;
+	int nd_flags = bu_flags&IP6_MH_BU_MR ? NTF_ROUTER : 0;
 
 	err = pneigh_add(ifindex, nd_flags, target);
 
@@ -117,7 +117,9 @@ int proxy_nd_start(int ifindex, struct i
 			pneigh_del(ifindex, target);
 	}
 	if (!err) {
-		uint32_t na_flags = ND_NA_FLAG_OVERRIDE;
+		uint32_t na_flags = (ND_NA_FLAG_OVERRIDE |
+				     nd_flags ? ND_NA_FLAG_ROUTER : 0);
+
 		ndisc_send_na(ifindex, src, &in6addr_all_nodes_mc,
 			      target, na_flags);
 
Index: mipv6-daemon/src/policy.c
===================================================================
--- mipv6-daemon.orig/src/policy.c
+++ mipv6-daemon/src/policy.c
@@ -107,6 +107,23 @@ int default_max_binding_life(const struc
 	return 0;
 }
 
+static inline int
+policy_check_mob_net_prefix(const struct policy_bind_acl_entry *acl,
+			    const struct ip6_mh_binding_update *bu,
+			    const struct mh_options *opts)
+{
+	struct ip6_mh_opt_mob_net_prefix *op;
+	for (op = mh_opt(&bu->ip6mhbu_hdr, opts, IP6_MHOPT_MOB_NET_PRFX);
+	     op != NULL;
+	     op = mh_opt_next(&bu->ip6mhbu_hdr, opts, op)) {
+		if (!prefix_list_get(&acl->mob_net_prefixes,
+				     &op->ip6mnp_prefix,
+				     op->ip6mnp_prefix_len))
+			return IP6_MH_BAS_NOT_AUTH_FOR_PRFX;
+	}
+	return IP6_MH_BAS_ACCEPTED;
+}
+
 /**
  * default_discard_binding - check for discard policy
  * @remote_hoa: remote MN's home address
@@ -127,10 +144,20 @@ int default_discard_binding(const struct
 	int ret = def_bind_policy;
 	struct policy_bind_acl_entry *acl;
 
+	if (bu->ip6mhbu_flags & IP6_MH_BU_MR && !conf.HaAcceptMobRtr)
+		return IP6_MH_BAS_MR_OP_NOT_PERMITTED;
+
 	pthread_rwlock_rdlock(&policy_lock);
 	acl = hash_get(&policy_bind_acl_hash, NULL, remote_hoa);
 	if (acl != NULL) {
 		ret = acl->bind_policy;
+		if (ret < IP6_MH_BAS_UNSPECIFIED &&
+		    bu->ip6mhbu_flags & IP6_MH_BU_MR) {
+			struct mh_options opts;
+			mh_opt_parse(&bu->ip6mhbu_hdr, len,
+				     sizeof(*bu), &opts);
+			ret = policy_check_mob_net_prefix(acl, bu, &opts);
+		}
 	}
 	pthread_rwlock_unlock(&policy_lock);
 	return ret;
@@ -227,6 +254,42 @@ int default_best_ro_coa(const struct in6
 	return 0;
 }
 
+int default_get_mnp_count(const struct in6_addr *hoa)
+{
+	int ret = 0;
+	struct policy_bind_acl_entry *acl;
+	pthread_rwlock_rdlock(&policy_lock);
+	acl = hash_get(&policy_bind_acl_hash, NULL, hoa);
+	if (acl != NULL)
+		ret = acl->mnp_count;
+	pthread_rwlock_unlock(&policy_lock);
+	return ret;
+
+}
+
+int default_get_mnps(const struct in6_addr *hoa,
+		     const int mnp_count,
+		     struct nd_opt_prefix_info *mnps)
+{
+	int i = 0;
+	struct policy_bind_acl_entry *acl;
+
+	pthread_rwlock_rdlock(&policy_lock);
+	acl = hash_get(&policy_bind_acl_hash, NULL, hoa);
+	if (acl != NULL) {
+		struct list_head *l;
+		list_for_each(l, &acl->mob_net_prefixes) {
+			struct prefix_list_entry *e;
+			if (i >= mnp_count)
+				break;
+			e = list_entry(l, struct prefix_list_entry, list);
+			mnps[i++] = e->pinfo;
+		}
+	}
+	pthread_rwlock_unlock(&policy_lock);
+	return i;
+}
+
 static int policy_bind_acle_cleanup(void *data, void *arg)
 {
 	struct policy_bind_acl_entry *acl = data;
Index: mipv6-daemon/src/policy.h
===================================================================
--- mipv6-daemon.orig/src/policy.h
+++ mipv6-daemon/src/policy.h
@@ -10,12 +10,15 @@
 
 struct ip6_mh_binding_update;
 struct nd_router_advert;
+struct nd_opt_prefix_info;
 
 struct policy_bind_acl_entry {
 	struct list_head list;
 	struct in6_addr hoa;
 	int plen;
 	int bind_policy;
+	int mnp_count;
+	struct list_head mob_net_prefixes;
 };
 
 /**
@@ -147,6 +150,12 @@ int default_best_ro_coa(const struct in6
 			const struct in6_addr *cn,
 			struct in6_addr *coa);
 
+int default_get_mnp_count(const struct in6_addr *hoa);
+
+int default_get_mnps(const struct in6_addr *hoa,
+		     const int mnp_count,
+		     struct nd_opt_prefix_info *mnps);
+
 void policy_cleanup(void);
 
 int policy_init(void);
Index: mipv6-daemon/src/proc_sys.h
===================================================================
--- mipv6-daemon.orig/src/proc_sys.h
+++ mipv6-daemon/src/proc_sys.h
@@ -14,6 +14,7 @@
 #define PROC_SYS_IP6_APP_SOLICIT "/proc/sys/net/ipv6/neigh/%s/app_solicit"
 #define PROC_SYS_IP6_BASEREACHTIME_MS "/proc/sys/net/ipv6/neigh/%s/base_reachable_time_ms"
 #define PROC_SYS_IP6_RETRANSTIMER_MS "/proc/sys/net/ipv6/neigh/%s/retrans_time_ms"
+#define PROC_SYS_IP6_FORWARDING "/proc/sys/net/ipv6/conf/%s/forwarding"
 
 int set_iface_proc_entry(const char *tmpl, const char *if_name, int val);
 
Index: mipv6-daemon/src/rtnl.h
===================================================================
--- mipv6-daemon.orig/src/rtnl.h
+++ mipv6-daemon/src/rtnl.h
@@ -16,6 +16,7 @@
 #define IP6_RT_PRIO_MIP6_FWD 192
 #define IP6_RT_PRIO_ADDRCONF 256
 
+#define IP6_RULE_PRIO_MIP6_MNP_IN    1000
 #define IP6_RULE_PRIO_MIP6_HOA_OUT   1001
 #define IP6_RULE_PRIO_MIP6_COA_OUT   1002
 #define IP6_RULE_PRIO_MIP6_BLOCK     1003
Index: mipv6-daemon/src/scan.l
===================================================================
--- mipv6-daemon.orig/src/scan.l
+++ mipv6-daemon/src/scan.l
@@ -136,6 +136,11 @@ MnRouterProbes			{ return MNROUTERPROBES
 MnRouterProbeTimeout		{ return MNROUTERPROBETIMEOUT; }
 MnDiscardHaParamProb		{ return MNDISCARDHAPARAMPROB; }
 OptimisticHandoff		{ return OPTIMISTICHANDOFF; }
+HaAcceptMobRtr   		{ return HAACCEPTMOBRTR; }
+IsMobRtr       			{ return ISMOBRTR; }
+HaServedPrefix       	       	{ return HASERVEDPREFIX; }
+HomePrefix     			{ return HOMEPREFIX; }
+MobRtrUseExplicitMode    	{ return MOBRTRUSEEXPLICITMODE; }
 internal			{ return INTERNAL; }
 
 {addr}		{
Index: mipv6-daemon/src/vt.c
===================================================================
--- mipv6-daemon.orig/src/vt.c
+++ mipv6-daemon/src/vt.c
@@ -678,6 +678,16 @@ static int bcache_vt_dump(void *data, vo
 
 	fprintf(vh->vh_stream, "\n");
 
+	/* Dump the registered MNP */
+	{
+		struct list_head *l;
+		list_for_each(l, &bce->mob_net_prefixes) {
+			struct prefix_list_entry *p;
+			p = list_entry(l, struct prefix_list_entry, list);
+			fprintf(vh->vh_stream, " MNP: %x:%x:%x:%x:%x:%x:%x:%x/%d\n", NIP6ADDR(&p->ple_prefix), p->ple_plen);
+		}
+	}
+
 	return 0;
 }
 
Index: mipv6-daemon/src/xfrm.c
===================================================================
--- mipv6-daemon.orig/src/xfrm.c
+++ mipv6-daemon/src/xfrm.c
@@ -679,6 +679,64 @@ static int _mn_ha_ipsec_bypass_init(cons
 	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.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;
@@ -686,6 +744,9 @@ static inline int mn_ha_ipsec_init(void)
 	/* 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);
 
 	return err;
@@ -787,10 +848,65 @@ static int _mn_ha_ipsec_bypass_cleanup(c
 	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.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);
 }
 
@@ -1721,6 +1837,8 @@ int xfrm_pre_bu_add_bule(struct bulentry
 		if (hai->home_block & HOME_LINK_BLOCK)
 			xfrm_unblock_link(hai);
 		xfrm_block_link(hai);
+		if (hai->mob_rtr && !(hai->home_block & NEMO_FWD_BLOCK))
+			xfrm_block_fwd(hai);
 	}
 	if (IN6_ARE_ADDR_EQUAL(&bule->hoa, &bule->coa)) {
 		if (rdata)
@@ -1786,6 +1904,8 @@ int xfrm_post_ba_mod_bule(struct bulentr
 		struct home_addr_info *hai = bule->home;
 		if (hai->home_block & HOME_LINK_BLOCK)
 			xfrm_unblock_link(hai);
+		if (hai->home_block & NEMO_FWD_BLOCK)
+			xfrm_unblock_fwd(hai);
 	}
 	/* check if XFRM policies and states have already been cleaned up */
 	if (IN6_ARE_ADDR_EQUAL(&bule->hoa, &bule->coa))
@@ -2060,6 +2180,50 @@ void xfrm_unblock_hoa(struct home_addr_i
 	hai->home_block &= ~HOME_ADDR_BLOCK;
 }
 
+/* block all RA messages sent by MR */
+int xfrm_block_ra(struct home_addr_info *hai)
+{
+	int ret = 0;
+	struct xfrm_selector sel;
+	hai->home_block |= NEMO_RA_BLOCK;
+	set_selector(&in6addr_any, &in6addr_any, IPPROTO_ICMPV6,
+		     ND_ROUTER_ADVERT, 0, 0, &sel);
+	if ((ret = xfrm_mip_policy_add(&sel, 0, XFRM_POLICY_OUT, XFRM_POLICY_BLOCK,
+				   MIP6_PRIO_HOME_BLOCK, NULL, 0)))
+		return ret;
+	return ret;
+}
+
+void xfrm_unblock_ra(struct home_addr_info *hai)
+{
+	struct xfrm_selector sel;
+	set_selector(&in6addr_any, &in6addr_any, IPPROTO_ICMPV6,
+		     ND_ROUTER_ADVERT, 0, 0, &sel);
+	xfrm_mip_policy_del(&sel, XFRM_POLICY_OUT);
+	hai->home_block &= ~NEMO_RA_BLOCK;
+}
+
+/* block all forwarded packets */
+int xfrm_block_fwd(struct home_addr_info *hai)
+{
+	int ret = 0;
+	struct xfrm_selector sel;
+	hai->home_block |= NEMO_FWD_BLOCK;
+	set_selector(&in6addr_any, &in6addr_any, 0, 0, 0, 0, &sel);
+	if ((ret = xfrm_mip_policy_add(&sel, 0, XFRM_POLICY_FWD, XFRM_POLICY_BLOCK,
+				   MIP6_PRIO_HOME_BLOCK, NULL, 0)))
+		return ret;
+	return ret;
+}
+
+void xfrm_unblock_fwd(struct home_addr_info *hai)
+{
+	struct xfrm_selector sel;
+	set_selector(&in6addr_any, &in6addr_any, 0, 0, 0, 0, &sel);
+	xfrm_mip_policy_del(&sel, XFRM_POLICY_FWD);
+	hai->home_block &= ~NEMO_FWD_BLOCK;
+}
+
 int mn_ipsec_recv_bu_tnl_pol_add(struct bulentry *bule, int ifindex, 
 				 struct ipsec_policy_entry *e)
 {
Index: mipv6-daemon/src/xfrm.h
===================================================================
--- mipv6-daemon.orig/src/xfrm.h
+++ mipv6-daemon/src/xfrm.h
@@ -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
@@ -88,6 +89,12 @@ void xfrm_unblock_link(struct home_addr_
 int xfrm_block_hoa(struct home_addr_info *hai);
 void xfrm_unblock_hoa(struct home_addr_info *hai);
 
+int xfrm_block_ra(struct home_addr_info *hai);
+void xfrm_unblock_ra(struct home_addr_info *hai);
+
+int xfrm_block_fwd(struct home_addr_info *hai);
+void xfrm_unblock_fwd(struct home_addr_info *hai);
+
 int ha_mn_ipsec_pol_mod(struct in6_addr *haaddr,
 			struct in6_addr *hoa);
 
openSUSE Build Service is sponsored by