nepl.patch
author kuntz@fry.local
Sun Nov 30 23:25:43 2008 +0100 (3 years ago)
changeset 61 38b92671ecb3
parent 533141b56ec71
permissions -rw-r--r--
Updated NEPL patch
moved cleanup_trailing_spaces.patches after the nepl patch
        1 This patch adds the NEMO basic support.
        2 See http://software.nautilus6.org/NEPL-UMIP/ for detail.
        3 
        4 Contact: Romain KUNTZ
        5 
        6 diff -r c04f74757df5 AUTHORS
        7 --- a/AUTHORS	Sun Nov 30 23:14:35 2008 +0100
        8 +++ b/AUTHORS	Sun Nov 30 23:14:48 2008 +0100
        9 @@ -5,3 +5,15 @@
       10  Petander.  Code has been contributed by several individuals.  See
       11  THANKS for listing.  See libnetlink/README for information regarding
       12  libnetlink.
       13 +
       14 +The NEMO Basic support code is developed by Ville Nuorvala
       15 +<vnuorval@tcs.hut.fi> in co-operation with the Nautilus6/WIDE
       16 +project (http://www.nautilus6.org).
       17 +
       18 +The NEMO Basic Support code has been ported to UMIP by Romain KUNTZ
       19 +<kuntz@lsiit.u-strasbg.fr> and received contributions from the
       20 +following people:
       21 +- Sebastien DECUGIS (Nautilus6): IPsec support for NEMO
       22 +- Arnaud EBALARD (EADS): fixes for Big Endian architectures,
       23 +  improvements of the NEMO debug messages, improvements in the 
       24 +  IPsec support code for NEMO.
       25 diff -r c04f74757df5 BUGS
       26 --- a/BUGS	Sun Nov 30 23:14:35 2008 +0100
       27 +++ b/BUGS	Sun Nov 30 23:14:48 2008 +0100
       28 @@ -17,3 +17,11 @@
       29  * Multihoming support hasn't been very thoroughly tested and should
       30    therefore be considered developmental code.  However, it is a lot
       31    more stable than in the Release Candidates.
       32 +
       33 +NEMO issues
       34 +-----------
       35 +
       36 +* The Mobile Router's home address may only be on the egress interface.
       37 +
       38 +* Dynamic routing protocols between the Home Agent and Mobile Router
       39 +  are not yet supported.
       40 diff -r c04f74757df5 COPYING.NEMO
       41 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
       42 +++ b/COPYING.NEMO	Sun Nov 30 23:14:48 2008 +0100
       43 @@ -0,0 +1,13 @@
       44 +Cisco and Nokia have both published IPR notices regarding RFC 3963
       45 +"Network Mobility (NEMO) Basic Support Protocol."
       46 +
       47 +Cisco has agreed not to assert its patents against any party agreeing with the
       48 +terms in its IPR notice.
       49 +
       50 +Likewise, Nokia has agreed not to assert its patents against Open Source
       51 +implementations of the specification.
       52 +
       53 +For further information, please read
       54 +licenses/cisco-ipr-draft-ietf-nemo-basic-support-03.txt and 
       55 +licenses/nokia-ipr-draft-ietf-nemo-basic-support.txt.
       56 +
       57 diff -r c04f74757df5 INSTALL
       58 --- a/INSTALL	Sun Nov 30 23:14:35 2008 +0100
       59 +++ b/INSTALL	Sun Nov 30 23:14:48 2008 +0100
       60 @@ -45,6 +45,8 @@
       61     further information on how to configure your node.  Also take a
       62     look at the example configuration files in the extras directory.
       63  
       64 +   For comments about NEMO check README.NEMO.
       65 +
       66     For comments about IPsec support check README.IPsec.
       67  
       68  5. A startup script 
       69 diff -r c04f74757df5 README
       70 --- a/README	Sun Nov 30 23:14:35 2008 +0100
       71 +++ b/README	Sun Nov 30 23:14:48 2008 +0100
       72 @@ -2,6 +2,9 @@
       73  
       74    MIPL Mobile IPv6 for Linux is an implementation of the Mobility
       75    Support in IP version 6 (RFC 3775).
       76 +
       77 +  It also supports Network Mobility with the NEMO Basic Support
       78 +  implementation (RFC 3963).
       79    
       80    This user space part works together with Mobile IPv6 enabled Linux
       81    kernels.  See INSTALL and any other documents referred there for
       82 diff -r c04f74757df5 README.NEMO
       83 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
       84 +++ b/README.NEMO	Sun Nov 30 23:14:48 2008 +0100
       85 @@ -0,0 +1,18 @@
       86 +README for NEMO Basic Support 
       87 +-----------------------------
       88 +
       89 +Here are a few things you need to keep in mind when setting up Network
       90 +Mobility:
       91 +
       92 +The MR is a router so you need to set
       93 +/proc/sys/net/ipv6/conf/all/forwarding to 1 to make sure it will forward
       94 +packets between its ingress and egress interfaces.
       95 +
       96 +With static routing the HA and other routers on the home link might need some
       97 +additional boot-strapping.  If the MR has a physical home link that it may be
       98 +attached to, the other routers must be pre-configured with routes to the MR's
       99 +Mobile Network Prefixes via the MR's home address.  This ensures packets will
      100 +be forwarded correctly also when the MR is at home.
      101 +
      102 +To be able to support NEMO DHAAD the HA needs to have AdvHomeAgentInfo and
      103 +AdvMobRtrSupportFlag turned on in radvd.conf.
      104 diff -r c04f74757df5 extras/example-nemo-ha.conf
      105 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
      106 +++ b/extras/example-nemo-ha.conf	Sun Nov 30 23:14:48 2008 +0100
      107 @@ -0,0 +1,86 @@
      108 +# This is an example of NEMO-enabled Home Agent configuration file
      109 +
      110 +NodeConfig HA;
      111 +
      112 +## If set to > 0, will not detach from tty
      113 +DebugLevel 10;
      114 +
      115 +## List of interfaces where we serve as Home Agent
      116 +Interface "eth0";
      117 +#Interface "eth1";
      118 +
      119 +HaAcceptMobRtr enabled;
      120 +
      121 +HaServedPrefix 3ffe:2620:6::/48;
      122 +
      123 +DefaultBindingAclPolicy deny;
      124 +
      125 +BindingAclPolicy 3ffe:2620:6:1::1234 (3ffe:2620:6:2::/64, 3ffe:2620:6:3::/64) allow;
      126 +BindingAclPolicy 3ffe:2620:6:1::1235 allow;
      127 +
      128 +
      129 +##
      130 +## IPsec configuration
      131 +##
      132 +
      133 +UseMnHaIPsec enabled;
      134 +
      135 +## Key Management Mobility Capability
      136 +#KeyMngMobCapability disabled;
      137 +
      138 +IPsecPolicySet {
      139 +	HomeAgentAddress 3ffe:2620:6:1::1;
      140 +
      141 +	HomeAddress 3ffe:2620:6:1::1234/64;
      142 +	HomeAddress 3ffe:2620:6:1::1235/64;
      143 +
      144 +	IPsecPolicy Mh UseESP;
      145 +	IPsecPolicy TunnelMh UseESP;
      146 +
      147 +#	IPsecPolicy Mh UseESP 1 2;
      148 +#	IPsecPolicy ICMP UseESP 5;
      149 +#	IPsecPolicy TunnelMh UseESP 3 4;
      150 +}
      151 +
      152 +##
      153 +## It is possible to specify multiple IPsecPolicySet in order to configure
      154 +## different value for such address.
      155 +#IPsecPolicySet {
      156 +#
      157 +## One HA is for one IPsecPolicySet.
      158 +#	HomeAgentAddress 3ffe:2620:6:1::1;
      159 +#
      160 +## It is possible to specify multiple home addresses when they use
      161 +## the same configuration.
      162 +#	HomeAddress 3ffe:2620:6:1::1236/64;
      163 +#	HomeAddress 3ffe:2620:6:1::1237/64;
      164 +#
      165 +## IPsec protocol syntax: IPsecPolicy TYPE IPSEC_PROTO [ REQID_SET ] [ ACTION ]
      166 +##	TYPE (for transport) := Mh | HomeRegBinding | ICMP | MobPfxDisc | any
      167 +##	TYPE (for tunnel) := TunnelMh | TunnelHomeTesting | TunnelPayload
      168 +##	IPSEC_PROTO := UseESP (UseAH and UseIPCOMP aren't currently supported)
      169 +##	REQID_SET := REQID(both-dir) | REQID(to-HA-dir) REQID(to-MN-dir)
      170 +##
      171 +##	REQID is a number. "to-HA-dir" is for packet from MN to HA e.g.
      172 +##	BU, MPS, or HoTI (it depends on TYPE).
      173 +##	REQID should be used when more than one configuration for transport
      174 +##	and tunnel respectively. The default value is zero.
      175 +#
      176 +## Transport MH protection
      177 +#	IPsecPolicy Mh UseESP 1 2;
      178 +#	## To protect only BU/BA exactly in MH, use below instead.
      179 +#	#IPsecPolicy HomeRegBinding UseESP 1 2;
      180 +#
      181 +## Transport ICMP protection
      182 +#	IPsecPolicy ICMP UseESP 5 6;
      183 +#	## To protect only MPD exactly in ICMP, use below instead.
      184 +#	#IPsecPolicy MobPfxDisc UseESP 5 6;
      185 +#
      186 +## Tunnel HoTI/HoT protection
      187 +#	IPsecPolicy TunnelMh UseESP 3 4;
      188 +#	## To protect only HoTI/HoT exactly in MH, use below instead.
      189 +#	#IPsecPolicy TunnelHomeTesting UseESP 3 4;
      190 +#
      191 +## Tunnel payload protection
      192 +#	#IPsecPolicy TunnelPayload UseESP 7 8;
      193 +#}
      194 diff -r c04f74757df5 extras/example-nemo-mn.conf
      195 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
      196 +++ b/extras/example-nemo-mn.conf	Sun Nov 30 23:14:48 2008 +0100
      197 @@ -0,0 +1,51 @@
      198 +# This is an example of NEMO Mobile Router configuration file
      199 +
      200 +NodeConfig MN;
      201 +
      202 +## If set to > 0, will not detach from tty
      203 +DebugLevel 10;
      204 +
      205 +## Support route optimization with other MNs
      206 +DoRouteOptimizationCN enabled;
      207 +
      208 +## Use route optimization with CNs
      209 +DoRouteOptimizationMN enabled;
      210 +
      211 +UseCnBuAck disabled;
      212 +
      213 +MnDiscardHaParamProb enabled;
      214 +
      215 +Interface "eth0";
      216 +
      217 +#Interface "eth1" { 
      218 +#	MnIfPreference 2;
      219 +#}
      220 +
      221 +MnRouterProbes 1;
      222 +
      223 +MnHomeLink "eth0" {
      224 +	IsMobRtr enabled;
      225 +	HomeAgentAddress 3ffe:2620:6:1::1;
      226 +	HomeAddress 3ffe:2620:6:1::1234/64 (3ffe:2620:6:2::/64, 3ffe:2620:6:3::/64);	
      227 +}
      228 +
      229 +##
      230 +## IPsec configuration
      231 +##
      232 +
      233 +UseMnHaIPsec enabled;
      234 +
      235 +## Key Management Mobility Capability
      236 +KeyMngMobCapability disabled;
      237 +
      238 +IPsecPolicySet {
      239 +	HomeAgentAddress 3ffe:2620:6:1::1;
      240 +	HomeAddress 3ffe:2620:6:1::1234/64;
      241 +
      242 +	IPsecPolicy Mh UseESP;
      243 +	IPsecPolicy TunnelMh UseESP;
      244 +
      245 +#	IPsecPolicy Mh UseESP 1 2;
      246 +#	IPsecPolicy ICMP UseESP 5;
      247 +#	IPsecPolicy TunnelMh UseESP 3 4;
      248 +}
      249 diff -r c04f74757df5 include/netinet/icmp6.h
      250 --- a/include/netinet/icmp6.h	Sun Nov 30 23:14:35 2008 +0100
      251 +++ b/include/netinet/icmp6.h	Sun Nov 30 23:14:48 2008 +0100
      252 @@ -27,7 +27,13 @@
      253  #define mip_dhreq_code			mip_dhreq_hdr.icmp6_code
      254  #define mip_dhreq_cksum			mip_dhreq_hdr.icmp6_cksum
      255  #define mip_dhreq_id			mip_dhreq_hdr.icmp6_data16[0]
      256 -#define mip_dhreq_reserved		mip_dhreq_hdr.icmp6_data16[1]
      257 +#define mip_dhreq_flags_reserved	mip_dhreq_hdr.icmp6_data16[1]
      258 +
      259 +#if BYTE_ORDER == BIG_ENDIAN
      260 +#define MIP_DHREQ_FLAG_SUPPORT_MR	0x8000
      261 +#else				/* BYTE_ORDER == LITTLE_ENDIAN */
      262 +#define MIP_DHREQ_FLAG_SUPPORT_MR	0x0080
      263 +#endif
      264  #endif
      265  
      266  #ifndef HAVE_STRUCT_MIP_DHAAD_REP
      267 @@ -40,7 +46,13 @@
      268  #define mip_dhrep_code			mip_dhrep_hdr.icmp6_code
      269  #define mip_dhrep_cksum			mip_dhrep_hdr.icmp6_cksum
      270  #define mip_dhrep_id			mip_dhrep_hdr.icmp6_data16[0]
      271 -#define mip_dhrep_reserved		mip_dhrep_hdr.icmp6_data16[1]
      272 +#define mip_dhrep_flags_reserved	mip_dhrep_hdr.icmp6_data16[1]
      273 +
      274 +#if BYTE_ORDER == BIG_ENDIAN
      275 +#define MIP_DHREP_FLAG_SUPPORT_MR	0x8000
      276 +#else				/* BYTE_ORDER == LITTLE_ENDIAN */
      277 +#define MIP_DHREP_FLAG_SUPPORT_MR	0x0080
      278 +#endif
      279  #endif
      280  
      281  #ifndef HAVE_STRUCT_MIP_PREFIX_SOLICIT
      282 @@ -89,10 +101,20 @@
      283  struct nd_opt_homeagent_info {	/* Home Agent information */
      284  	uint8_t		nd_opt_hai_type;
      285  	uint8_t		nd_opt_hai_len;
      286 -	uint16_t	nd_opt_hai_reserved;
      287 +	uint16_t	nd_opt_hai_flags_reserved;
      288  	uint16_t	nd_opt_hai_preference;
      289  	uint16_t	nd_opt_hai_lifetime;
      290  };
      291  #endif
      292  
      293 +#define nd_opt_hai_reserved     nd_opt_hai_flags_reserved
      294 +
      295 +#ifndef ND_OPT_HAI_FLAG_SUPPORT_MR
      296 +#if BYTE_ORDER == BIG_ENDIAN
      297 +#define ND_OPT_HAI_FLAG_SUPPORT_MR	0x8000
      298 +#else				/* BYTE_ORDER == LITTLE_ENDIAN */
      299 +#define ND_OPT_HAI_FLAG_SUPPORT_MR	0x0080
      300 +#endif
      301 +#endif
      302 +
      303  #endif	/* netinet/icmp6.h */
      304 diff -r c04f74757df5 licenses/cisco-ipr-draft-ietf-nemo-basic-support-03.txt
      305 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
      306 +++ b/licenses/cisco-ipr-draft-ietf-nemo-basic-support-03.txt	Sun Nov 30 23:14:48 2008 +0100
      307 @@ -0,0 +1,41 @@
      308 +Title: Cisco Systems' Updated Statement about IPR claimed in
      309 +       draft-ietf-nemo-basic-support-03.txt
      310 +Received 25 October 2004
      311 +From: Robert Barr <rbarr@cisco.com>
      312 +
      313 +This statement updates the IPR statement filed by Cisco on June 20, 2003 for
      314 +draft-ietf-nemo-basic-support-00.txt.
      315 +
      316 +Cisco is the owner of US Patent No. 6,636,498 and at least one pending
      317 +patent application
      318 +relating to the subject matter of draft-ietf-nemo-basic-support-03.txt
      319 +"Network Mobility (NEMO) Basic Support Protocol" .
      320 +If a standard relating to this subject matter is adopted by IETF and any
      321 +claims
      322 +of any issued Cisco patents are necessary for practicing this standard, any
      323 +party will be able to obtain a license from Cisco to use any such patent
      324 +claims under openly specified, reasonable, non-discriminatory terms, with
      325 +reciprocity, to implement and fully comply with the standard.
      326 +
      327 +The reasonable non-discriminatory terms are:
      328 +
      329 +If this standard is adopted, Cisco will not assert any patents owned or
      330 +controlled by Cisco against any party for making, using, selling, importing
      331 +or offering for sale a product that implements the standard, provided,
      332 +however that Cisco retains the right to assert its patents (including the
      333 +right to claim past royalties) against any party that asserts a patent it
      334 +owns or controls (either directly or indirectly) against Cisco or any of
      335 +Cisco's affiliates or successors in title; and Cisco retains the right to
      336 +assert its patents against any product or portion thereof that is not
      337 +necessary for compliance with the standard.
      338 +
      339 +Royalty-bearing licenses will be available to anyone who prefers that
      340 +option.
      341 +
      342 +For information contact:
      343 +
      344 +Robert Barr
      345 +Worldwide Patent Counsel
      346 +Cisco Systems
      347 +408-525-9706
      348 +rbarr@cisco.com
      349 diff -r c04f74757df5 licenses/nokia-ipr-draft-ietf-nemo-basic-support.txt
      350 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
      351 +++ b/licenses/nokia-ipr-draft-ietf-nemo-basic-support.txt	Sun Nov 30 23:14:48 2008 +0100
      352 @@ -0,0 +1,26 @@
      353 +Title: Nokia Corporation's statement about IPR claimed in draft-ietf-nemo-basic-support
      354 +Received: July 1, 2003
      355 +From: Heikki Huttunen <heikki.a.huttunen@nokia.com>
      356 +
      357 +This is to advise the IETF that Nokia believes the Nokia patent application "Mobile Router 
      358 +Support for IPv6", US10/295014, WO03/043226 may be relevant to Nemo Basic Support Protocol 
      359 +<draft-ietf-nemo-basic-support>.
      360 +
      361 +Regarding internet draft "draft-ietf-nemo-basic-support", to the extent this draft is 
      362 +included into final IETF standard specification, Nokia agrees not to assert those claims 
      363 +in Nokia patents that apply to this draft and that are technically necessary to implement 
      364 +the IETF standard specification against any other party in respect of its implementation of 
      365 +the specification, if only practiced under any software distributed under the present terms 
      366 +of GNU GENERAL PUBLIC LICENSE (http://www.fsf.org/copyleft/gpl.html) or under license terms 
      367 +that conform to the present open source definition (http://www.opensource.org/osd.html) and 
      368 +provided that the party relying on this commitment does not assert its patents against Nokia.
      369 +
      370 +Otherwise general Nokia Statement on Patent Licensing (http://www.ietf.org/ietf/IPR/NOKIA) 
      371 +applies to this submission. 
      372 +
      373 +
      374 +Heikki Huttunen
      375 +Director, Licensing
      376 +Nokia Corporation
      377 +P.O Box 86, FIN-24101 Salo, Finland
      378 +Phone: +358 (0) 7180 41202, Fax: +358 (0) 7180 44275
      379 diff -r c04f74757df5 man/mip6d.conf.tmpl
      380 --- a/man/mip6d.conf.tmpl	Sun Nov 30 23:14:35 2008 +0100
      381 +++ b/man/mip6d.conf.tmpl	Sun Nov 30 23:14:48 2008 +0100
      382 @@ -1,12 +1,12 @@
      383  .\" $Id: mip6d.conf.tmpl 1.33 06/05/12 11:48:36+03:00 vnuorval@tcs.hut.fi $
      384 -.TH mip6d.conf 5 "January 31, 2006" "" "Mobile IPv6 Daemon Configuration"
      385 +.TH mip6d.conf 5 "January 31, 2006" "" "Mobile IPv6 and NEMO Daemon Configuration"
      386  .SH NAME
      387 -mip6d.conf \- MIPL Mobile IPv6 Configuration file
      388 +mip6d.conf \- MIPL Mobile IPv6 and NEMO Configuration file
      389  .SH SYNOPSIS
      390  .B %etc%/mip6d.conf
      391  .sp
      392  .SH DESCRIPTION
      393 -MIPL Mobile IPv6 daemon's configuration file
      394 +MIPL Mobile IPv6 and NEMO daemon's configuration file
      395  .P
      396  Below is a list of currently supported configuration options. All
      397  configuration lines are terminated with a semicolon.  Sub-sections are
      398 @@ -184,10 +184,29 @@
      399  Default: 86400
      400  
      401  .TP
      402 -.BR "BindingAclPolicy " "address " "allow | deny"
      403 +.BR "HaAcceptMobRtr enabled | disabled"
      404  
      405 -Defines if a MN is allowed to register with the HA or not. The MN home address
      406 -of the MN is given in the address field."
      407 +Indicates if the HA accepts Mobile Router bindings.
      408 +
      409 +Default: disabled;
      410 +
      411 +.TP
      412 +.BR "HaServedPrefix " "prefix/length" ";"
      413 +
      414 +Prefix is an IPv6 prefix and length is the prefix length. Defines the whole
      415 +aggregated or extended prefix the HA serves. This option is only used for MR
      416 +bindings and is only needed if the MRs derive their Home Addresses from their
      417 +Mobile Network Prefixes, instead of one of the home link prefixes.
      418 +
      419 +.TP
      420 +.BR "BindingAclPolicy " "address MNP list " "allow | deny"
      421 +
      422 +Defines if a MN is allowed to register with the HA or not. The home address
      423 +of the MN is given in the address field.  The mobile network prefixes
      424 +belonging a NEMO Mobile Router are listed in the MNP list. The list can either
      425 +be an empty string or a comma separated list of network prefixes
      426 +enclosed in braces, for example:
      427 +.B "(3ffe:2620:6:3::/64, 3ffe:2620:6:4::/64)"
      428  
      429  .TP
      430  .BR "DefaultBindingAclPolicy allow | deny"
      431 @@ -254,6 +273,13 @@
      432  Default: disabled
      433  
      434  .TP
      435 +.BR "MobRtrUseExplicitMode enabled | disabled"
      436 +
      437 +Toggles between explicit or implicit mode home registrations in the MR.
      438 +
      439 +Default: enabled
      440 +
      441 +.TP
      442  .BR "UseCnBuAck " "boolean" ";"
      443  
      444  Indicates if the Acknowledge bit should be set in Binding Updates sent to
      445 @@ -299,7 +325,7 @@
      446  .TP
      447  .nf
      448  .BR "MnHomeLink " "name " "{"
      449 -.BR "	HomeAddress " "address/length" ";"
      450 +.BR "	HomeAddress " "address/length MNP list" ";"
      451  .BR "	HomeAgentAddress " "address" ";"
      452  .BR "	MnRoPolicy ..."
      453  .BR "	..."
      454 @@ -317,11 +343,14 @@
      455  definitions.  All the home link specific definitions are detailed below: 
      456  
      457  .TP
      458 -.BR "HomeAddress " "address/length" ";"
      459 +.BR "HomeAddress " "address/length MNP list" ";"
      460  
      461  Address is an IPv6 address, and length the prefix length of the
      462 -address, usually 64.  This option must be included in a home link
      463 -definition.
      464 +address, usually 64.  The MNP list contains the mobile network prefixes
      465 +belonging to that particular NEMO Mobile Router. The MNP list is of the
      466 +same format as in
      467 +.B "BindingAclPolicy."
      468 +This option must be included in a home link definition.
      469  
      470  .TP
      471  .BR "HomeAgentAddress " "address" ";"
      472 @@ -332,6 +361,13 @@
      473  Default: ::
      474  
      475  .TP
      476 +.BR "IsMobRtr enabled | disabled"
      477 +
      478 +Defines if the MN is a NEMO MR.
      479 +
      480 +Default: disabled
      481 +
      482 +.TP
      483  The route optimization policies are of the form:
      484  
      485  .TP
      486 @@ -353,6 +389,49 @@
      487  .SH EXAMPLES
      488  
      489  .TP
      490 +.BR "A NEMO Home Agent example:"
      491 +
      492 +.nf
      493 +NodeConfig HA;
      494 +
      495 +Interface "eth0";
      496 +
      497 +HaAcceptMobRtr enabled;
      498 +
      499 +HaServedPrefix 3ffe:2620:6::/48;
      500 +
      501 +DefaultBindingAclPolicy deny;
      502 +BindingAclPolicy 3ffe:2620:6:1::1234 (3ffe:2620:6:2::/64, 3ffe:2620:6:3::/64) allow;
      503 +BindingAclPolicy 3ffe:2620:6:1::1235 allow;
      504 +
      505 +UseMnHaIPsec disabled;
      506 +.fi
      507 +
      508 +.TP
      509 +.BR "A NEMO Mobile Router example:"
      510 +
      511 +.nf
      512 +NodeConfig MN;
      513 +
      514 +DoRouteOptimizationCN disabled;
      515 +DoRouteOptimizationMN disabled;
      516 +
      517 +Interface "eth0";
      518 +
      519 +MnRouterProbes 1;
      520 +
      521 +MobRtrUseExplicitMode enabled;
      522 +
      523 +MnHomeLink "eth0" {
      524 +        IsMobRtr enabled;
      525 +        HomeAgentAddress 3ffe:2620:6:1::1;
      526 +        HomeAddress 3ffe:2620:6:1::1234/64 (3ffe:2620:6:2::/64, 3ffe:2620:6:3::/64);
      527 +}
      528 +
      529 +UseMnHaIPsec disabled;
      530 +.fi
      531 +
      532 +.TP
      533  .BR "A Correspondent Node example:"
      534  
      535  .nf
      536 diff -r c04f74757df5 man/mip6d.tmpl
      537 --- a/man/mip6d.tmpl	Sun Nov 30 23:14:35 2008 +0100
      538 +++ b/man/mip6d.tmpl	Sun Nov 30 23:14:48 2008 +0100
      539 @@ -1,13 +1,13 @@
      540  .\" $Id: mip6d.tmpl 1.4 05/05/16 13:13:41+03:00 anttit@tcs.hut.fi $
      541 -.TH mip6d 1 "May 16, 2005" "" "Mobile IPv6 Daemon"
      542 +.TH mip6d 1 "May 16, 2005" "" "Mobile IPv6 and NEMO Daemon"
      543  .SH NAME
      544 -mip6d \- MIPL Mobile IPv6 protocol implementation
      545 +mip6d \- MIPL Mobile IPv6 and NEMO Basic Support protocol implementation
      546  .SH SYNOPSIS
      547  .B mip6d [options]
      548  .sp
      549  .SH DESCRIPTION
      550  
      551 -Mobile IPv6 implementation
      552 +Mobile IPv6 and NEMO Basic Support implementation
      553  
      554  .SH OPTIONS
      555  .IP "\fB\-V, \-\-version\fP"
      556 @@ -41,3 +41,5 @@
      557  .PP
      558  RFC3776: Using IPsec to Protect Mobile IPv6 Signaling Between Mobile
      559  Nodes and Home Agents
      560 +.PP
      561 +RFC3963: Network Mobility (NEMO) Basic Support Protocol
      562 diff -r c04f74757df5 src/bcache.c
      563 --- a/src/bcache.c	Sun Nov 30 23:14:35 2008 +0100
      564 +++ b/src/bcache.c	Sun Nov 30 23:14:48 2008 +0100
      565 @@ -39,6 +39,7 @@
      566  #include "mh.h"
      567  #include "cn.h"
      568  #include "vt.h"
      569 +#include "prefix.h"
      570  
      571  #define BCACHE_BUCKETS 32
      572  
      573 @@ -88,6 +89,38 @@
      574  	fprintf(out, " lifetime %ld\n ", e->lifetime.tv_sec);
      575  	fprintf(out, " seqno %d\n", e->seqno);
      576  
      577 +	if (e->flags & IP6_MH_BA_MR) {
      578 +		struct list_head *list;
      579 +		int mnpcount = 0;
      580 +
      581 +		/* MR registration type */
      582 +		fprintf(out, "MR Registration type: ");
      583 +		switch(e->nemo_type) {
      584 +		case BCE_NEMO_EXPLICIT:
      585 +			fprintf(out, "explicit.\n");
      586 +			break;
      587 +		case BCE_NEMO_IMPLICIT:
      588 +			fprintf(out, "implicit.\n");
      589 +			break;
      590 +		default:
      591 +			fprintf(out, "unknown.\n");
      592 +		}
      593 +
      594 +		/* Mobile Network prefixes */
      595 +		fprintf(out, "MR Mobile network prefixes: ");
      596 +		list_for_each(list, &e->mob_net_prefixes) {
      597 +			struct prefix_list_entry *p;
      598 +			p = list_entry(list, struct prefix_list_entry, list);
      599 +			if (mnpcount)
      600 +				fprintf(out, "                            ");
      601 +			fprintf(out, "%x:%x:%x:%x:%x:%x:%x:%x/%d\n",
      602 +				NIP6ADDR(&p->ple_prefix), p->ple_plen);
      603 +			mnpcount++;
      604 +		}
      605 +		if (!mnpcount)
      606 +			fprintf(out, " none registered.\n");
      607 +	}
      608 +
      609  	fflush(out);
      610  }
      611  
      612 @@ -144,6 +177,7 @@
      613  		return NULL;
      614  	}
      615  	INIT_LIST_HEAD(&tmp->tqe.list);
      616 +	INIT_LIST_HEAD(&tmp->mob_net_prefixes);
      617  	return tmp;
      618  }
      619  
      620 @@ -158,6 +192,7 @@
      621  	/* This function should really return allocated space to free
      622  	 * pool. */
      623  	pthread_rwlock_destroy(&bce->lock);
      624 +	prefix_list_free(&bce->mob_net_prefixes);
      625  	free(bce);
      626  }
      627  
      628 diff -r c04f74757df5 src/bcache.h
      629 --- a/src/bcache.h	Sun Nov 30 23:14:35 2008 +0100
      630 +++ b/src/bcache.h	Sun Nov 30 23:14:48 2008 +0100
      631 @@ -18,7 +18,8 @@
      632  
      633  	uint16_t nonce_coa;
      634  	uint16_t nonce_hoa;
      635 -	int type;			/* Entry type */
      636 +	uint16_t type;     		/* Entry type */
      637 +	uint16_t nemo_type;    		/* NEMO registration type */
      638  	int unreach;			/* ICMP dest unreach count */
      639  	int tunnel;			/* Tunnel interface index */
      640  	int link;			/* Home link interface index */
      641 @@ -33,6 +34,8 @@
      642  	struct tq_elem tqe;		/* Timer queue entry for expire */
      643  
      644  	void (*cleanup)(struct bcentry *bce); /* Clean up bce data */
      645 +
      646 +	struct list_head mob_net_prefixes;
      647  };
      648  
      649  #define BCE_NONCE_BLOCK 0
      650 @@ -41,6 +44,10 @@
      651  #define BCE_CACHE_DYING 3
      652  #define BCE_DAD 4
      653  
      654 +#define BCE_NEMO_EXPLICIT 1
      655 +#define BCE_NEMO_IMPLICIT 2
      656 +#define BCE_NEMO_DYNAMIC 3
      657 +
      658  struct bcentry *bcache_alloc(int type);
      659  
      660  void bcache_free(struct bcentry *bce);
      661 diff -r c04f74757df5 src/bul.c
      662 --- a/src/bul.c	Sun Nov 30 23:14:35 2008 +0100
      663 +++ b/src/bul.c	Sun Nov 30 23:14:48 2008 +0100
      664 @@ -103,9 +103,11 @@
      665  	if (e->flags & IP6_MH_BU_ACK)
      666  		fprintf(out, "IP6_MH_BU_ACK ");
      667  	if (e->flags & IP6_MH_BU_LLOCAL)
      668 -		fprintf(out, "IP6_MH_BU_LLOCAL");
      669 +		fprintf(out, "IP6_MH_BU_LLOCAL ");
      670  	if (e->flags & IP6_MH_BU_KEYM)
      671 -		fprintf(out, "IP6_MH_BU_KEYM");
      672 +		fprintf(out, "IP6_MH_BU_KEYM ");
      673 +	if (e->flags & IP6_MH_BU_MR)
      674 +		fprintf(out, "IP6_MH_BU_MR");
      675  
      676  	fprintf(out, "\n");
      677  	fflush(out);
      678 @@ -184,7 +186,8 @@
      679  			goto home_bul_free;
      680  	} else if (bule->type == NON_MIP_CN_ENTRY) {
      681  		if (bule->flags & IP6_MH_BU_HOME) {
      682 -			if (xfrm_block_hoa(hai) < 0)
      683 +			if (xfrm_block_hoa(hai) < 0 ||
      684 +			    (hai->mob_rtr && xfrm_block_ra(hai) < 0))
      685  				goto home_bul_free;
      686  		}
      687  	}
      688 @@ -231,6 +234,10 @@
      689  				xfrm_unblock_link(hai);
      690  			if (hai->home_block & HOME_ADDR_BLOCK)
      691  				xfrm_unblock_hoa(hai);
      692 +			if (hai->home_block & NEMO_RA_BLOCK)
      693 +				xfrm_unblock_ra(hai);
      694 +			if (hai->home_block & NEMO_FWD_BLOCK)
      695 +				xfrm_unblock_fwd(hai);
      696  		}
      697  	}
      698  	while (bule->ext_cleanup)
      699 diff -r c04f74757df5 src/cn.c
      700 --- a/src/cn.c	Sun Nov 30 23:14:35 2008 +0100
      701 +++ b/src/cn.c	Sun Nov 30 23:14:48 2008 +0100
      702 @@ -177,8 +177,8 @@
      703  	non_ind = mh_opt(&bu->ip6mhbu_hdr, &mh_opts, IP6_MHOPT_NONCEID);
      704  	bce = bcache_get(out.src, out.dst);
      705  	if (bce) {
      706 -		if ((bce->flags^bu_flags) & IP6_MH_BU_HOME) {
      707 -			/* H-bit mismatch, flags changed */
      708 +		if ((bce->flags^bu_flags) & (IP6_MH_BU_HOME|IP6_MH_BU_MR)) {
      709 +			/* H-bit or R-bit mismatch, flags changed */
      710  			bcache_release_entry(bce);
      711  			bce = NULL;
      712  			status = IP6_MH_BAS_REG_NOT_ALLOWED;
      713 @@ -221,9 +221,15 @@
      714  			/* else get rid of it */
      715  			bcache_delete(out.src, out.dst);
      716  		}
      717 -	} else if (bu_flags & IP6_MH_BU_HOME) {
      718 -		status = IP6_MH_BAS_HA_NOT_SUPPORTED;
      719 -		goto send_nack;
      720 +	} else {
      721 +		if (bu_flags & IP6_MH_BU_HOME) {
      722 +			status = IP6_MH_BAS_HA_NOT_SUPPORTED;
      723 +			goto send_nack;
      724 +		}
      725 +		if (bu_flags & IP6_MH_BU_MR) {
      726 +			status = IP6_MH_BAS_MR_OP_NOT_PERMITTED;
      727 +			goto send_nack;
      728 +		}
      729  	}
      730  	status = conf.pmgr.discard_binding(out.dst, out.bind_coa,
      731  					   out.src, bu, len);
      732 diff -r c04f74757df5 src/conf.c
      733 --- a/src/conf.c	Sun Nov 30 23:14:35 2008 +0100
      734 +++ b/src/conf.c	Sun Nov 30 23:14:48 2008 +0100
      735 @@ -212,6 +212,7 @@
      736  	INIT_LIST_HEAD(&c->home_addrs);
      737  	c->MoveModulePath = NULL; /* internal */
      738  	c->DoRouteOptimizationMN = 1;
      739 +	c->MobRtrUseExplicitMode = 1;
      740  	c->SendMobPfxSols = 1;
      741  	c->OptimisticHandoff = 0;
      742  
      743 @@ -221,6 +222,7 @@
      744  	c->MaxMobPfxAdvInterval = 86400; /* seconds */
      745  	c->MinMobPfxAdvInterval = 600; /* seconds */
      746  	c->HaMaxBindingLife = MAX_BINDING_LIFETIME;
      747 +	INIT_LIST_HEAD(&c->nemo_ha_served_prefixes);
      748  
      749  	/* CN bindings */
      750  	c->DoRouteOptimizationCN = 1;
      751 @@ -304,6 +306,8 @@
      752  	    CONF_BOOL_STR(c->MnDiscardHaParamProb));
      753  	dbg("SendMobPfxSols = %s\n", CONF_BOOL_STR(c->SendMobPfxSols));
      754  	dbg("OptimisticHandoff = %s\n", CONF_BOOL_STR(c->OptimisticHandoff));
      755 +	dbg("MobRtrUseExplicitMode = %s\n",
      756 +	    CONF_BOOL_STR(c->MobRtrUseExplicitMode));
      757  
      758  	/* HA options */
      759  	dbg("SendMobPfxAdvs = %s\n", CONF_BOOL_STR(c->SendMobPfxAdvs));
      760 @@ -312,7 +316,8 @@
      761  	dbg("MaxMobPfxAdvInterval = %u\n", c->MaxMobPfxAdvInterval);
      762  	dbg("MinMobPfxAdvInterval = %u\n", c->MinMobPfxAdvInterval);
      763  	dbg("HaMaxBindingLife = %u\n", c->HaMaxBindingLife);
      764 -	
      765 +	dbg("HaAcceptMobRtr = %s\n", CONF_BOOL_STR(c->HaAcceptMobRtr));
      766 +
      767  	/* CN options */
      768  	dbg("DoRouteOptimizationCN = %s\n",
      769  	    CONF_BOOL_STR(c->DoRouteOptimizationCN));
      770 diff -r c04f74757df5 src/conf.h
      771 --- a/src/conf.h	Sun Nov 30 23:14:35 2008 +0100
      772 +++ b/src/conf.h	Sun Nov 30 23:14:48 2008 +0100
      773 @@ -39,6 +39,7 @@
      774  	struct list_head home_addrs;
      775  	char *MoveModulePath;
      776  	uint16_t CnBuAck;
      777 +	char MobRtrUseExplicitMode;
      778  	char DoRouteOptimizationMN;
      779  	char MnUseAllInterfaces;
      780  	char MnDiscardHaParamProb;
      781 @@ -46,15 +47,16 @@
      782  	char OptimisticHandoff;
      783  
      784  	/* HA options */
      785 +	char HaAcceptMobRtr;
      786  	char SendMobPfxAdvs;
      787  	char SendUnsolMobPfxAdvs;
      788  	unsigned int MaxMobPfxAdvInterval;
      789  	unsigned int MinMobPfxAdvInterval;
      790  	unsigned int HaMaxBindingLife;
      791 +	struct list_head nemo_ha_served_prefixes;
      792  
      793  	/* CN options */
      794  	char DoRouteOptimizationCN;
      795 -
      796  };
      797  
      798  struct net_iface {
      799 diff -r c04f74757df5 src/dhaad_ha.c
      800 --- a/src/dhaad_ha.c	Sun Nov 30 23:14:35 2008 +0100
      801 +++ b/src/dhaad_ha.c	Sun Nov 30 23:14:48 2008 +0100
      802 @@ -83,8 +83,8 @@
      803  	pthread_rwlock_unlock(&ha_lock);
      804  }
      805  
      806 -void dhaad_insert_halist(struct ha_interface *i, 
      807 -			 uint16_t key, uint16_t life_sec,
      808 +void dhaad_insert_halist(struct ha_interface *i, uint16_t key,
      809 +			 uint16_t life_sec, uint16_t flags,
      810  			 struct nd_opt_prefix_info *pinfo,
      811  			 const struct in6_addr *lladdr)
      812  {
      813 @@ -110,6 +110,7 @@
      814  			return;
      815  		}
      816  		memset(ha, 0, sizeof(*ha));
      817 +		ha->flags = flags;
      818  		ha->iface = i;
      819  		ha->addr = *addr;
      820  		INIT_LIST_HEAD(&ha->tqe.list);
      821 @@ -136,18 +137,22 @@
      822  	return;
      823  }
      824  
      825 -static int dhaad_get_halist(struct ha_interface *i, int max, struct iovec *iov)
      826 +static int dhaad_get_halist(struct ha_interface *i, uint16_t flags,
      827 +			    int max, struct iovec *iov)
      828  {
      829  	struct list_head *lp;
      830  	int n = 0;
      831  	list_for_each(lp, &i->ha_list) {
      832  		struct home_agent *h;
      833  		h = list_entry(lp, struct home_agent, list);
      834 -		n++;
      835 -		iov[n].iov_len = sizeof(struct in6_addr);
      836 -		iov[n].iov_base = &h->addr;
      837 -		if (n >= max)
      838 -			break;
      839 +		if (!(flags & MIP_DHREQ_FLAG_SUPPORT_MR) ||
      840 +		    h->flags & ND_OPT_HAI_FLAG_SUPPORT_MR) {
      841 +			n++;
      842 +			iov[n].iov_len = sizeof(struct in6_addr);
      843 +			iov[n].iov_base = &h->addr;
      844 +			if (n >= max)
      845 +				break;
      846 +		}
      847  	}
      848  	return n;
      849  }
      850 @@ -177,8 +182,12 @@
      851  
      852  	rph->mip_dhrep_id = rqh->mip_dhreq_id;
      853  
      854 +	if (rqh->mip_dhreq_flags_reserved & MIP_DHREQ_FLAG_SUPPORT_MR)
      855 +		rph->mip_dhrep_flags_reserved = MIP_DHREP_FLAG_SUPPORT_MR;
      856 +
      857  	pthread_rwlock_rdlock(&ha_lock);
      858 -	iovlen = dhaad_get_halist(i, MAX_HOME_AGENTS, iov);
      859 +	iovlen = dhaad_get_halist(i, rqh->mip_dhreq_flags_reserved,
      860 +				  MAX_HOME_AGENTS, iov);
      861  	icmp6_send(i->ifindex, 64, ha_addr, src, iov, iovlen + 1);
      862  	pthread_rwlock_unlock(&ha_lock);
      863  	free_iov_data(&iov[0], 1);
      864 diff -r c04f74757df5 src/dhaad_ha.h
      865 --- a/src/dhaad_ha.h	Sun Nov 30 23:14:35 2008 +0100
      866 +++ b/src/dhaad_ha.h	Sun Nov 30 23:14:48 2008 +0100
      867 @@ -17,8 +17,8 @@
      868  			  int (* func)(int, void *, void *), void *arg);
      869  #endif
      870  
      871 -void dhaad_insert_halist(struct ha_interface *i, 
      872 -			 uint16_t key, uint16_t life_sec,
      873 +void dhaad_insert_halist(struct ha_interface *i, uint16_t key,
      874 +			 uint16_t life_sec, uint16_t flags,
      875  			 struct nd_opt_prefix_info *pinfo,
      876  			 const struct in6_addr *lladdr);
      877  
      878 diff -r c04f74757df5 src/dhaad_mn.c
      879 --- a/src/dhaad_mn.c	Sun Nov 30 23:14:35 2008 +0100
      880 +++ b/src/dhaad_mn.c	Sun Nov 30 23:14:48 2008 +0100
      881 @@ -86,7 +86,8 @@
      882  }
      883  
      884  static int dhaad_send_request(int oif, struct in6_addr *src, 
      885 -			      struct in6_addr *pfx, int plen)
      886 +			      struct in6_addr *pfx, int plen,
      887 +			      uint16_t flags)
      888  {
      889  	struct mip_dhaad_req *ih;
      890  	struct iovec iov;
      891 @@ -98,6 +99,7 @@
      892  	    return -1;
      893  	id = dhaad_id++;
      894  	ih->mip_dhreq_id = htons(id);
      895 +	ih->mip_dhreq_flags_reserved = flags;
      896  	dhaad_gen_ha_anycast(&dst, pfx, plen);
      897  	icmp6_send(oif, 0, src, &dst, &iov, 1);
      898  	free_iov_data(&iov, 1);
      899 @@ -121,7 +123,9 @@
      900  		t->dhaad_id = dhaad_send_request(hai->primary_coa.iif,
      901  						 &hai->primary_coa.addr,
      902  						 &hai->home_prefix,
      903 -						 hai->home_plen);
      904 +						 hai->home_plen,
      905 +						 hai->mob_rtr?
      906 +						 MIP_DHREQ_FLAG_SUPPORT_MR:0);
      907  		t->dhaad_resends++;
      908  		tsadd(t->dhaad_delay, t->dhaad_delay, t->dhaad_delay);
      909  		add_task_rel(&t->dhaad_delay, &t->tqe, dhaad_resend);
      910 @@ -139,11 +143,15 @@
      911  	      t->dhaad_resends == DHAAD_RETRIES))) {
      912  		if (!(hai->home_block & HOME_ADDR_BLOCK))
      913  			xfrm_block_hoa(hai);
      914 +		if (hai->mob_rtr && !(hai->home_block & NEMO_RA_BLOCK))
      915 +			xfrm_block_ra(hai);
      916  		t->dhaad_resends = 0;
      917  		t->dhaad_id = dhaad_send_request(hai->primary_coa.iif,
      918  						 &hai->primary_coa.addr,
      919  						 &hai->home_prefix,
      920 -						 hai->home_plen);
      921 +						 hai->home_plen,
      922 +						 hai->mob_rtr?
      923 +						 MIP_DHREQ_FLAG_SUPPORT_MR:0);
      924  		t->dhaad_delay = INITIAL_DHAAD_TIMEOUT_TS;
      925  		add_task_rel(&t->dhaad_delay, &t->tqe, dhaad_resend);
      926  	}
      927 @@ -165,6 +173,8 @@
      928  	tsclear(t->dhaad_delay);
      929  	if (hai->home_block & HOME_ADDR_BLOCK)
      930  		xfrm_unblock_hoa(hai);
      931 +	if (hai->home_block & NEMO_RA_BLOCK)
      932 +		xfrm_unblock_ra(hai);
      933  }
      934  
      935  void dhaad_stop(struct home_addr_info *hai)
      936 @@ -245,6 +255,12 @@
      937  		pthread_rwlock_unlock(&mn_lock);
      938  		return;
      939  	}
      940 +	if (hai->mob_rtr &&
      941 +	    !(rph->mip_dhrep_flags_reserved & MIP_DHREP_FLAG_SUPPORT_MR)) {
      942 +		dbg("HA doesn't support MR\n");
      943 +		pthread_rwlock_unlock(&mn_lock);
      944 +		return;
      945 +	}
      946  	ha = (struct in6_addr *)(ih + 1);
      947  
      948  	dhaad_flush_candidates(&hai->ha_list);
      949 diff -r c04f74757df5 src/gram.y
      950 --- a/src/gram.y	Sun Nov 30 23:14:35 2008 +0100
      951 +++ b/src/gram.y	Sun Nov 30 23:14:48 2008 +0100
      952 @@ -30,10 +30,10 @@
      953  #ifdef HAVE_CONFIG_H
      954  #include <config.h>
      955  #endif
      956 +#include <stdio.h>
      957  #include <pthread.h>
      958  #include <netinet/in.h>
      959  #include <net/if.h>
      960 -#include <stdio.h>
      961  #include <string.h>
      962  #include <stdarg.h>
      963  #include <netinet/ip6mh.h>
      964 @@ -54,9 +54,24 @@
      965  };
      966  	
      967  struct home_addr_info hai = {
      968 -	.ro_policies = LIST_HEAD_INIT(hai.ro_policies)
      969 +	.ro_policies = LIST_HEAD_INIT(hai.ro_policies),
      970 +	.mob_net_prefixes = LIST_HEAD_INIT(hai.mob_net_prefixes)
      971  };
      972  
      973 +LIST_HEAD(prefixes);
      974 +
      975 +int mv_prefixes(struct list_head *list)
      976 +{
      977 +	struct list_head *l, *n;
      978 +	int res = 0;
      979 +	list_for_each_safe(l, n, &prefixes) {
      980 +		list_del(l);
      981 +		list_add_tail(l, list);
      982 +		res++;
      983 +	}
      984 +	return res;
      985 +}
      986 +
      987  struct policy_bind_acl_entry *bae = NULL;
      988  
      989  struct ipsec_policy_set {
      990 @@ -165,6 +180,11 @@
      991  %token		MNROUTERPROBETIMEOUT
      992  %token		MNDISCARDHAPARAMPROB
      993  %token		OPTIMISTICHANDOFF
      994 +%token		HOMEPREFIX
      995 +%token		HAACCEPTMOBRTR
      996 +%token		ISMOBRTR
      997 +%token		HASERVEDPREFIX
      998 +%token		MOBRTRUSEEXPLICITMODE
      999  
     1000  %token		INV_TOKEN
     1001  
     1002 @@ -282,6 +302,19 @@
     1003  		{
     1004  			conf.DefaultBindingAclPolicy = $2;
     1005  		}
     1006 +		| HAACCEPTMOBRTR BOOL ';'
     1007 +		{
     1008 +			conf.HaAcceptMobRtr = $2;
     1009 +		}
     1010 +		| HASERVEDPREFIX prefixlistentry ';'
     1011 +		{
     1012 +			list_splice(&prefixes,
     1013 +				    conf.nemo_ha_served_prefixes.prev);
     1014 +		}
     1015 +		| MOBRTRUSEEXPLICITMODE BOOL ';'
     1016 +		{
     1017 +			conf.MobRtrUseExplicitMode = $2;
     1018 +		}
     1019  		| BINDINGACLPOLICY bindaclpolicy ';' 
     1020  		{
     1021  			bae = NULL;
     1022 @@ -398,12 +431,16 @@
     1023  			memcpy(nhai, &hai, sizeof(struct home_addr_info));
     1024  			INIT_LIST_HEAD(&nhai->ro_policies);
     1025  			INIT_LIST_HEAD(&nhai->ha_list.home_agents);
     1026 +			INIT_LIST_HEAD(&nhai->mob_net_prefixes);
     1027  			nhai->ha_list.dhaad_id = -1;
     1028  			list_splice(&hai.ro_policies, &nhai->ro_policies);
     1029 +			list_splice(&hai.mob_net_prefixes,
     1030 +				    &nhai->mob_net_prefixes);
     1031  			list_add_tail(&nhai->list, &conf.home_addrs);
     1032  
     1033  			memset(&hai, 0, sizeof(struct home_addr_info));
     1034  			INIT_LIST_HEAD(&hai.ro_policies);
     1035 +			INIT_LIST_HEAD(&hai.mob_net_prefixes);
     1036  		}
     1037  		;
     1038  
     1039 @@ -415,16 +452,35 @@
     1040  		{
     1041  			memcpy(&hai.ha_addr, &$2, sizeof(struct in6_addr));
     1042  		}
     1043 -		| HOMEADDRESS ADDR '/' prefixlen ';'
     1044 -		{
     1045 -			hai.hoa.addr = $2;
     1046 -			hai.plen = $4;
     1047 -		}
     1048 +		| HOMEADDRESS homeaddress ';'
     1049  		| USEALTCOA BOOL ';'
     1050                  {
     1051  		        hai.altcoa = $2;
     1052  		}	  
     1053  		| MNROPOLICY mnropolicy ';'
     1054 +		| ISMOBRTR BOOL ';'
     1055 +                {
     1056 +			if ($2)
     1057 +				hai.mob_rtr = IP6_MH_BU_MR;
     1058 +		}
     1059 +		|  HOMEPREFIX ADDR '/' prefixlen ';'
     1060 +                {
     1061 +			ipv6_addr_prefix(&hai.home_prefix, &$2, $4);
     1062 +			hai.home_plen = $4;
     1063 +		}
     1064 +		;
     1065 +
     1066 +homeaddress	: homeaddrdef prefixlistsub
     1067 +		{
     1068 +			hai.mnp_count = mv_prefixes(&hai.mob_net_prefixes);
     1069 +		}
     1070 +		;
     1071 +
     1072 +homeaddrdef	: ADDR '/' prefixlen
     1073 +		{
     1074 +			hai.hoa.addr = $1;
     1075 +			hai.plen = $3;
     1076 +		}
     1077  		;
     1078  
     1079  ipsecpolicyset	: ipsechaaddrdef ipsecmnaddrdefs ipsecpolicydefs
     1080 @@ -639,7 +695,7 @@
     1081  		| NUMBER { $$ = $1; }
     1082  		;
     1083  
     1084 -bindaclpolicy	: ADDR bindaclpolval
     1085 +bindaclpolicy	: ADDR prefixlistsub bindaclpolval
     1086  		{
     1087  			bae = malloc(sizeof(struct policy_bind_acl_entry));
     1088  			if (bae == NULL) {
     1089 @@ -649,7 +705,9 @@
     1090  			memset(bae, 0, sizeof(struct policy_bind_acl_entry)); 
     1091  			bae->hoa = $1;
     1092  			bae->plen = 128;
     1093 -			bae->bind_policy = $2;
     1094 +			INIT_LIST_HEAD(&bae->mob_net_prefixes);
     1095 +			bae->mnp_count = mv_prefixes(&bae->mob_net_prefixes);
     1096 +			bae->bind_policy = $3;
     1097  			list_add_tail(&bae->list, &conf.bind_acl);
     1098  		}
     1099  		;
     1100 @@ -664,4 +722,27 @@
     1101  		}
     1102  		;
     1103  
     1104 +prefixlistsub	:
     1105 +		| '(' prefixlist ')'
     1106 +		;
     1107 +
     1108 +prefixlist	: prefixlistentry
     1109 +		| prefixlist ',' prefixlistentry
     1110 +		;
     1111 +
     1112 +prefixlistentry	: ADDR '/' prefixlen
     1113 +		{
     1114 +			struct prefix_list_entry *p;
     1115 +			p = malloc(sizeof(struct prefix_list_entry));
     1116 +			if (p == NULL) {
     1117 +				fprintf(stderr,
     1118 +					"%s: out of memory\n", __FUNCTION__);
     1119 +				return -1;
     1120 +			}
     1121 +			memset(p, 0, sizeof(struct prefix_list_entry));
     1122 +			p->ple_prefix = $1;
     1123 +			p->ple_plen = $3;
     1124 +			list_add_tail(&p->list, &prefixes);
     1125 +		}
     1126 +		;
     1127  %%
     1128 diff -r c04f74757df5 src/ha.c
     1129 --- a/src/ha.c	Sun Nov 30 23:14:35 2008 +0100
     1130 +++ b/src/ha.c	Sun Nov 30 23:14:48 2008 +0100
     1131 @@ -79,6 +79,7 @@
     1132  	struct ha_interface *iface;
     1133  	uint16_t pref = 0;
     1134  	uint16_t life = 0;
     1135 +	uint16_t flags = 0;
     1136  
     1137  	/* validity checks */
     1138  	if (hoplimit < 255 || !IN6_IS_ADDR_LINKLOCAL(src) ||
     1139 @@ -120,6 +121,7 @@
     1140  			hainfo = (struct nd_opt_homeagent_info *)opt;
     1141  			pref = ntohs(hainfo->nd_opt_hai_preference);
     1142  			life = ntohs(hainfo->nd_opt_hai_lifetime);
     1143 +			flags = hainfo->nd_opt_hai_flags_reserved;
     1144  		}
     1145  		optlen -= olen;
     1146  		opt += olen;
     1147 @@ -129,7 +131,7 @@
     1148  		if (pinfo[i]->nd_opt_pi_flags_reserved & 
     1149  		    ND_OPT_PI_FLAG_RADDR) {
     1150  			dhaad_insert_halist(iface, pref, life,
     1151 -					    pinfo[i], src);
     1152 +					    flags, pinfo[i], src);
     1153  		}
     1154  	}
     1155  	mpd_del_expired_pinfos(iface);
     1156 @@ -499,14 +501,53 @@
     1157  }
     1158  #endif
     1159  
     1160 +
     1161 +static void nemo_ha_del_mnp_routes(struct list_head *old_mnps,
     1162 +				   struct list_head *new_mnps,
     1163 +				   int ifindex, int all)
     1164 +{
     1165 +	struct list_head *list;
     1166 +	list_for_each(list, old_mnps) {
     1167 +		struct prefix_list_entry *p;
     1168 +		p = list_entry(list, struct prefix_list_entry, list);
     1169 +		if (!all &&
     1170 +		    prefix_list_find(new_mnps, &p->ple_prefix, p->ple_plen))
     1171 +			continue;
     1172 +
     1173 +		route_del(ifindex, RT6_TABLE_MIP6, IP6_RT_PRIO_MIP6_FWD,
     1174 +			  NULL, 0, &p->ple_prefix, p->ple_plen, NULL);
     1175 +	}
     1176 +}
     1177 +
     1178 +static int nemo_ha_add_mnp_routes(struct list_head *old_mnps,
     1179 +				  struct list_head *new_mnps,
     1180 +				  int ifindex, int all)
     1181 +{
     1182 +	struct list_head *list;
     1183 +	list_for_each(list, new_mnps) {
     1184 +		struct prefix_list_entry *p;
     1185 +		p = list_entry(list, struct prefix_list_entry, list);
     1186 +		if (!all &&
     1187 +		    prefix_list_find(old_mnps, &p->ple_prefix, p->ple_plen))
     1188 +			continue;
     1189 +		if (route_add(ifindex, RT6_TABLE_MIP6, RTPROT_MIP,
     1190 +			      0, IP6_RT_PRIO_MIP6_FWD,
     1191 +			      NULL, 0, &p->ple_prefix, p->ple_plen, NULL) < 0)
     1192 +			return -1;
     1193 +	}
     1194 +	return 0;
     1195 +}
     1196 +
     1197  struct home_tnl_ops_parm {
     1198  	struct bcentry *bce;
     1199  	int ba_status;
     1200 +	struct list_head mob_net_prefixes;
     1201  };
     1202  
     1203  static int home_tnl_del(int old_if, int new_if, struct home_tnl_ops_parm *p)
     1204  {
     1205  	const struct in6_addr *our_addr, *peer_addr, *coa, *old_coa;
     1206 +	struct list_head *mnp;
     1207  
     1208  	assert(old_if);
     1209  
     1210 @@ -514,17 +555,22 @@
     1211  	peer_addr = &p->bce->peer_addr;
     1212  	coa = &p->bce->peer_addr;
     1213  	old_coa = &p->bce->coa;
     1214 +	mnp = &p->bce->mob_net_prefixes;
     1215  
     1216  	if (conf.UseMnHaIPsec) {
     1217  		/* migrate */ 
     1218  		ha_ipsec_tnl_update(our_addr, peer_addr,
     1219 -				    coa, old_coa, p->bce->tunnel);
     1220 +				    coa, old_coa, p->bce->tunnel, mnp);
     1221  		/* delete SP entry */ 
     1222 -		ha_ipsec_tnl_pol_del(our_addr, peer_addr, p->bce->tunnel);
     1223 +		ha_ipsec_tnl_pol_del(our_addr, peer_addr, p->bce->tunnel, mnp);
     1224  	}
     1225  	/* delete HoA route */
     1226  	route_del(old_if, RT6_TABLE_MAIN,
     1227  		  IP6_RT_PRIO_MIP6_FWD, NULL, 0, peer_addr, 128, NULL);
     1228 +
     1229 +	/* delete MNP routes */
     1230 +	nemo_ha_del_mnp_routes(&p->bce->mob_net_prefixes,
     1231 +			       &p->mob_net_prefixes, old_if, 1);
     1232  	/* update tunnel interface */
     1233  	p->bce->tunnel = new_if;
     1234  
     1235 @@ -534,17 +580,29 @@
     1236  static int home_tnl_add(int old_if, int new_if, struct home_tnl_ops_parm *p)
     1237  {
     1238  	const struct in6_addr *our_addr, *peer_addr, *coa, *old_coa;
     1239 +	struct list_head *mnp;
     1240  
     1241  	assert(new_if);
     1242  
     1243  	our_addr = &p->bce->our_addr;
     1244  	peer_addr = &p->bce->peer_addr;
     1245  	coa = &p->bce->coa;
     1246 -	old_coa = &p->bce->peer_addr;
     1247 +	old_coa = IN6_ARE_ADDR_EQUAL(&p->bce->old_coa, &in6addr_any) ?
     1248 +		&p->bce->peer_addr : &p->bce->old_coa;
     1249 +	mnp = &p->mob_net_prefixes;
     1250  
     1251  	/* update tunnel interface */
     1252  	p->bce->tunnel = new_if;
     1253  
     1254 +	/* add MNP routes */
     1255 +	if (nemo_ha_add_mnp_routes(&p->bce->mob_net_prefixes,
     1256 +				   &p->mob_net_prefixes, new_if, 1) < 0) {
     1257 +		if (p->bce->nemo_type == BCE_NEMO_EXPLICIT)
     1258 +			p->ba_status = IP6_MH_BAS_INVAL_PRFX;
     1259 +		else
     1260 +			p->ba_status = IP6_MH_BAS_FWDING_FAILED;
     1261 +		goto err;
     1262 +	}
     1263  	/* add HoA route */
     1264  	if (route_add(new_if, RT6_TABLE_MAIN,
     1265  		      RTPROT_MIP, 0, IP6_RT_PRIO_MIP6_FWD,
     1266 @@ -555,13 +613,13 @@
     1267  	/* add SP entry */	
     1268  	if (conf.UseMnHaIPsec) {
     1269  		if (ha_ipsec_tnl_pol_add(our_addr, peer_addr,
     1270 -					 p->bce->tunnel) < 0) {
     1271 +					 p->bce->tunnel, mnp) < 0) {
     1272  			p->ba_status = IP6_MH_BAS_INSUFFICIENT;
     1273  			goto err;
     1274  		}
     1275  		/* migrate */ 
     1276  		if (ha_ipsec_tnl_update(our_addr, peer_addr, coa, old_coa,
     1277 -					p->bce->tunnel) < 0) {
     1278 +					p->bce->tunnel, mnp) < 0) {
     1279  			p->ba_status = IP6_MH_BAS_INSUFFICIENT;
     1280  			goto err;
     1281  		}
     1282 @@ -578,17 +636,51 @@
     1283  
     1284  	if (old_if == new_if) {
     1285  		const struct in6_addr *our_addr, *peer_addr, *coa, *old_coa;
     1286 +		struct list_head *mnp;
     1287  
     1288  		our_addr = &p->bce->our_addr;
     1289  		peer_addr = &p->bce->peer_addr;
     1290  		coa = &p->bce->coa;
     1291  		old_coa = &p->bce->old_coa;
     1292 +		mnp = &p->mob_net_prefixes;
     1293 +
     1294 +		/* if interface hasn't changed, at least check if the
     1295 +		   MR's MNPs have changed */
     1296 +		if (!prefix_list_cmp(&p->bce->mob_net_prefixes,
     1297 +				     &p->mob_net_prefixes)) {
     1298 +
     1299 +			/* Remove old policies and install new ones */
     1300 +			if (conf.UseMnHaIPsec) {
     1301 +				ha_ipsec_mnp_pol_del(our_addr, peer_addr,
     1302 +						     &p->bce->mob_net_prefixes,
     1303 +						     &p->mob_net_prefixes,
     1304 +						     p->bce->tunnel);
     1305 +				ha_ipsec_mnp_pol_add(our_addr, peer_addr,
     1306 +						     &p->bce->mob_net_prefixes,
     1307 +						     &p->mob_net_prefixes,
     1308 +						     p->bce->tunnel);
     1309 +			}
     1310 +
     1311 +			/* Do the same for routes */
     1312 +			nemo_ha_del_mnp_routes(&p->bce->mob_net_prefixes,
     1313 +					       &p->mob_net_prefixes,
     1314 +					       old_if, 0);
     1315 +			if (nemo_ha_add_mnp_routes(&p->bce->mob_net_prefixes,
     1316 +						   &p->mob_net_prefixes,
     1317 +						   new_if, 0) < 0) {
     1318 +				if (p->bce->nemo_type == BCE_NEMO_EXPLICIT)
     1319 +					p->ba_status = IP6_MH_BAS_INVAL_PRFX;
     1320 +				else
     1321 +					p->ba_status = IP6_MH_BAS_FWDING_FAILED;
     1322 +				return -1;
     1323 +			}
     1324 +		}
     1325  
     1326  		/* migrate */ 
     1327  		if (conf.UseMnHaIPsec &&
     1328  		    !IN6_ARE_ADDR_EQUAL(old_coa, coa) &&
     1329  		    ha_ipsec_tnl_update(our_addr, peer_addr, coa, old_coa,
     1330 -					p->bce->tunnel) < 0) {
     1331 +					p->bce->tunnel, mnp) < 0) {
     1332  			return -1;
     1333  		}
     1334  	} else { 
     1335 @@ -634,6 +726,61 @@
     1336  	}
     1337  }
     1338  
     1339 +
     1340 +static int ha_extract_mnps(const struct ip6_mh_binding_update *bu,
     1341 +			   const struct mh_options *opts,
     1342 +			   struct list_head *mob_net_prefixes)
     1343 +{
     1344 +	struct ip6_mh_opt_mob_net_prefix *op;
     1345 +	int prefix_count = 0;
     1346 +	for (op = mh_opt(&bu->ip6mhbu_hdr, opts, IP6_MHOPT_MOB_NET_PRFX);
     1347 +	     op != NULL;
     1348 +	     op = mh_opt_next(&bu->ip6mhbu_hdr, opts, op)) {
     1349 +		struct prefix_list_entry *p;
     1350 +		p = malloc(sizeof(struct prefix_list_entry));
     1351 +		if (p == NULL) {
     1352 +			prefix_list_free(mob_net_prefixes);
     1353 +			return -1;
     1354 +		}
     1355 +		memset(p, 0, sizeof(struct prefix_list_entry));
     1356 +		p->ple_plen = op->ip6mnp_prefix_len;
     1357 +		p->ple_prefix = op->ip6mnp_prefix;
     1358 +		list_add_tail(&p->list, mob_net_prefixes);
     1359 +		prefix_count++;
     1360 +	}
     1361 +	return prefix_count;
     1362 +}
     1363 +
     1364 +static int ha_get_mnps(const struct in6_addr *hoa,
     1365 +		       struct list_head *mob_net_prefixes)
     1366 +{
     1367 +	struct nd_opt_prefix_info *mnps;
     1368 +	int mnp_count = conf.pmgr.get_mnp_count(hoa);
     1369 +	int i;
     1370 +
     1371 +	if (mnp_count <= 0)
     1372 +		return mnp_count;
     1373 +
     1374 +	mnps = calloc(mnp_count, sizeof(struct nd_opt_prefix_info));
     1375 +	if (mnps == NULL)
     1376 +		return -1;
     1377 +
     1378 +	mnp_count = conf.pmgr.get_mnps(hoa, mnp_count, mnps);
     1379 +	for (i = 0; i < mnp_count; i++) {
     1380 +		struct prefix_list_entry *p;
     1381 +		p = malloc(sizeof(struct prefix_list_entry));
     1382 +		if (p == NULL) {
     1383 +			prefix_list_free(mob_net_prefixes);
     1384 +			free(mnps);
     1385 +			return -1;
     1386 +		}
     1387 +		p->pinfo = *(mnps + i);
     1388 +		list_add_tail(&p->list, mob_net_prefixes);
     1389 +	}
     1390 +	free(mnps);
     1391 +	return mnp_count;
     1392 +}
     1393 +
     1394  struct ha_recv_bu_args {
     1395  	struct list_head list;
     1396  	struct in6_addr src;
     1397 @@ -684,8 +831,9 @@
     1398  	bce = bcache_get(out.src, out.dst);
     1399  	if (bce) {
     1400  		if (bce->type != BCE_NONCE_BLOCK) {
     1401 -			if (!(bce->flags & IP6_MH_BU_HOME)) {
     1402 -				/* H-bit mismatch, flags changed */
     1403 +			/* H-bit or R-bit mismatch, flags changed */
     1404 +			if ((bce->flags ^ bu_flags) &
     1405 +			    (IP6_MH_BU_HOME | IP6_MH_BU_MR)) {
     1406  				bcache_release_entry(bce);
     1407  				bce = NULL;
     1408  				status = IP6_MH_BAS_REG_NOT_ALLOWED;
     1409 @@ -733,9 +881,15 @@
     1410  	}
     1411  	if ((status = mpd_prefix_check(out.src, out.dst,
     1412  				       &lft, &home_ifindex, new)) < 0) {
     1413 -		/* not home agent for this subnet */
     1414 -		status = IP6_MH_BAS_NOT_HOME_SUBNET;
     1415 -		goto send_nack;
     1416 +		if (!(bu_flags & IP6_MH_BU_MR) ||
     1417 +		    home_ifindex == 0 ||
     1418 +		    !prefix_list_find(&conf.nemo_ha_served_prefixes,
     1419 +		     		      out.dst, 0)) {
     1420 +			/* not home agent for this subnet */
     1421 +			status = IP6_MH_BAS_NOT_HOME_SUBNET;
     1422 +			goto send_nack;
     1423 +		}
     1424 +		status = IP6_MH_BAS_ACCEPTED;
     1425  	}
     1426  	status = conf.pmgr.discard_binding(out.dst, out.bind_coa,
     1427  					   out.src, arg->bu, arg->len);
     1428 @@ -787,6 +941,25 @@
     1429  		}
     1430  		new = 1;
     1431  	}
     1432 +	INIT_LIST_HEAD(&p.mob_net_prefixes);
     1433 +	if (bu_flags & IP6_MH_BU_MR && tsisset(lft)) {
     1434 +		if (mh_opt(&arg->bu->ip6mhbu_hdr,
     1435 +			   &arg->mh_opts, IP6_MHOPT_MOB_NET_PRFX) != NULL) {
     1436 +			if (ha_extract_mnps(arg->bu,
     1437 +					    &arg->mh_opts,
     1438 +					    &p.mob_net_prefixes) < 0) {
     1439 +				status = IP6_MH_BAS_INVAL_PRFX;
     1440 +				goto send_nack;
     1441 +			}
     1442 +			bce->nemo_type = BCE_NEMO_EXPLICIT;
     1443 +		} else if (ha_get_mnps(out.dst, &p.mob_net_prefixes) > 0) {
     1444 +			bce->nemo_type = BCE_NEMO_IMPLICIT;
     1445 +		} else {
     1446 +			/* Todo: dynamic routing */
     1447 +			status = IP6_MH_BAS_FWDING_FAILED;
     1448 +			goto send_nack;
     1449 +		}
     1450 +	}
     1451  	p.bce = bce;
     1452  	p.ba_status = status;
     1453  	bce->seqno = seqno;
     1454 @@ -801,6 +974,9 @@
     1455  				status = IP6_MH_BAS_INSUFFICIENT;
     1456  			goto send_nack;
     1457  		}
     1458 +		/* Now save the MNP list in the BCE */
     1459 +		list_splice(&p.mob_net_prefixes, &bce->mob_net_prefixes);
     1460 +
     1461  		bce->cleanup = home_cleanup;
     1462  
     1463  		if (route_add(bce->link, RT6_TABLE_MIP6,
     1464 @@ -829,6 +1005,10 @@
     1465  				status = IP6_MH_BAS_INSUFFICIENT;
     1466  			goto send_nack;
     1467  		}
     1468 +		/* Now update the MNP list in the BCE */
     1469 +		prefix_list_free(&bce->mob_net_prefixes);
     1470 +		list_splice(&p.mob_net_prefixes, &bce->mob_net_prefixes);
     1471 +
     1472  		bcache_update_expire(bce);
     1473  	}
     1474  	/* bce is always valid here */
     1475 @@ -867,6 +1047,9 @@
     1476  		 * have a binding before sending this Binding Update,
     1477  		 * discard the connections to the home address. */
     1478  	}
     1479 + 	if (status < IP6_MH_BAS_UNSPECIFIED && bu_flags & IP6_MH_BU_MR)
     1480 + 		ba_flags |= IP6_MH_BA_MR;
     1481 +
     1482  	if (!(arg->flags & HA_BU_F_SKIP_BA))
     1483  		mh_send_ba(&out, status, ba_flags, seqno, &lft, NULL, iif);
     1484  	if (new && tsisset(lft))
     1485 diff -r c04f74757df5 src/ha.h
     1486 --- a/src/ha.h	Sun Nov 30 23:14:35 2008 +0100
     1487 +++ b/src/ha.h	Sun Nov 30 23:14:48 2008 +0100
     1488 @@ -23,6 +23,7 @@
     1489  	struct list_head list;
     1490  	struct in6_addr addr;
     1491  	uint16_t preference;
     1492 +	uint16_t flags;
     1493  	struct timespec lifetime;
     1494  	struct ha_interface *iface;
     1495  	struct tq_elem tqe;
     1496 diff -r c04f74757df5 src/ipsec.c
     1497 --- a/src/ipsec.c	Sun Nov 30 23:14:35 2008 +0100
     1498 +++ b/src/ipsec.c	Sun Nov 30 23:14:48 2008 +0100
     1499 @@ -81,7 +81,9 @@
     1500  		    struct ipsec_policy_entry *e,
     1501  		    int dir,
     1502  		    const struct in6_addr *in6_dst,
     1503 +		    int  dst_len,
     1504  		    const struct in6_addr *in6_src,
     1505 +		    int src_len,
     1506  		    int ifindex,
     1507  		    int nodetype)
     1508  {
     1509 @@ -97,10 +99,13 @@
     1510  	sp->action = e->action;
     1511  	memcpy(&sp->sel.saddr.a6, in6_src, sizeof(sp->sel.saddr.a6));
     1512  	memcpy(&sp->sel.daddr.a6, in6_dst, sizeof(sp->sel.daddr.a6));
     1513 -	sp->sel.prefixlen_s = IN6_ARE_ADDR_EQUAL(in6_src, &in6addr_any) ?
     1514 -				0 : 128;
     1515 -	sp->sel.prefixlen_d = IN6_ARE_ADDR_EQUAL(in6_dst, &in6addr_any) ?
     1516 -				0 : 128;
     1517 +	sp->sel.prefixlen_s = src_len;
     1518 +	if (!src_len && (!IN6_ARE_ADDR_EQUAL(in6_src, &in6addr_any)))
     1519 +		sp->sel.prefixlen_s = 128;
     1520 +	sp->sel.prefixlen_d = dst_len;
     1521 +	if (!dst_len && (!IN6_ARE_ADDR_EQUAL(in6_dst, &in6addr_any)))
     1522 +		sp->sel.prefixlen_d = 128;
     1523 +
     1524  	sp->sel.ifindex = 0;
     1525  
     1526  	switch (e->type) {
     1527 @@ -347,6 +352,7 @@
     1528  	int tunnel;
     1529  	struct in6_addr coa;
     1530  	struct in6_addr old_coa;
     1531 +	struct list_head *mnp;
     1532  };
     1533  
     1534  /*
     1535 @@ -365,6 +371,7 @@
     1536  	int ifindex;
     1537  	const struct in6_addr *oldcoa, *newcoa;
     1538  	const struct in6_addr *peer_addr = hoa;
     1539 +	struct list_head *mnp;
     1540  	u_int8_t ipsec_proto;
     1541  	struct xfrm_user_tmpl tmpl;
     1542  	struct xfrm_userpolicy_info sp;
     1543 @@ -399,13 +406,14 @@
     1544  	oldcoa = IN6_ARE_ADDR_EQUAL(&info->old_coa, &in6addr_any) ?
     1545  		peer_addr : &info->old_coa;
     1546  	newcoa = &info->coa;
     1547 +	mnp = info->mnp;
     1548  
     1549  	dump_migrate(ifindex, ipsec_proto, hoa, haaddr, oldcoa, newcoa);
     1550  
     1551  	/* inbound */
     1552  	_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
     1553  		  haaddr, oldcoa, e->reqid_toha);
     1554 -	_set_sp(&sp, e, XFRM_POLICY_IN, &in6addr_any, hoa,
     1555 +	_set_sp(&sp, e, XFRM_POLICY_IN, &in6addr_any, 0, hoa, 0,
     1556  		ifindex, MIP6_ENTITY_HA);
     1557  	if ((err = xfrm_sendmigrate(&sp, &tmpl, haaddr, newcoa)) < 0) {
     1558  		dbg("migrate for INBOUND policy failed\n");
     1559 @@ -415,7 +423,7 @@
     1560  	/* forward */
     1561  	_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
     1562  		  haaddr, oldcoa, e->reqid_toha);
     1563 -	_set_sp(&sp, e, XFRM_POLICY_FWD, &in6addr_any, hoa,
     1564 +	_set_sp(&sp, e, XFRM_POLICY_FWD, &in6addr_any, 0, hoa, 0,
     1565  		ifindex, MIP6_ENTITY_HA);
     1566  	if ((err = xfrm_sendmigrate(&sp, &tmpl, haaddr, newcoa)) < 0) {
     1567  		dbg("migrate for FORWARD policy failed\n");
     1568 @@ -425,13 +433,56 @@
     1569  	/* outbound */
     1570  	_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
     1571  		  oldcoa, haaddr, e->reqid_tomn);
     1572 -	_set_sp(&sp, e, XFRM_POLICY_OUT, hoa, &in6addr_any,
     1573 +	_set_sp(&sp, e, XFRM_POLICY_OUT, hoa, 0, &in6addr_any, 0,
     1574  		ifindex, MIP6_ENTITY_HA);
     1575  	if ((err = xfrm_sendmigrate(&sp, &tmpl, newcoa, haaddr)) < 0) {
     1576  		dbg("migrate for OUTBOUND policy failed\n");
     1577          	goto end;
     1578  	}
     1579  
     1580 +	/* Mobile router case */
     1581 +	if ( (e->type == IPSEC_POLICY_TYPE_TUNNELPAYLOAD) && mnp)
     1582 +	{
     1583 +		struct list_head *list;
     1584 +
     1585 +		/* We have to modify rules to protect traffic to and from MNP's, the same way as HoA */
     1586 +		list_for_each(list, mnp)
     1587 +		{
     1588 +			struct prefix_list_entry *p;
     1589 +			p = list_entry(list, struct prefix_list_entry, list);
     1590 +
     1591 +			/* inbound */
     1592 +			_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
     1593 +				  haaddr, oldcoa, e->reqid_toha);
     1594 +			_set_sp(&sp, e, XFRM_POLICY_IN, &in6addr_any, 0, &p->ple_prefix, p->ple_plen,
     1595 +				ifindex, MIP6_ENTITY_HA);
     1596 +			if ((err = xfrm_sendmigrate(&sp, &tmpl, haaddr, newcoa)) < 0) {
     1597 +				dbg("migrate for INBOUND policy failed\n");
     1598 +        			goto end;
     1599 +			}
     1600 +
     1601 +			/* forward */
     1602 +			_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
     1603 +				  haaddr, oldcoa, e->reqid_toha);
     1604 +			_set_sp(&sp, e, XFRM_POLICY_FWD, &in6addr_any, 0, &p->ple_prefix, p->ple_plen,
     1605 +				ifindex, MIP6_ENTITY_HA);
     1606 +			if ((err = xfrm_sendmigrate(&sp, &tmpl, haaddr, newcoa)) < 0) {
     1607 +				dbg("migrate for FORWARD policy failed\n");
     1608 +				goto end;
     1609 +			}
     1610 +
     1611 +			/* outbound */
     1612 +			_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
     1613 +				  oldcoa, haaddr, e->reqid_tomn);
     1614 +			_set_sp(&sp, e, XFRM_POLICY_OUT, &p->ple_prefix, p->ple_plen, &in6addr_any, 0,
     1615 +				ifindex, MIP6_ENTITY_HA);
     1616 +			if ((err = xfrm_sendmigrate(&sp, &tmpl, newcoa, haaddr)) < 0) {
     1617 +				dbg("migrate for OUTBOUND policy failed\n");
     1618 +        			goto end;
     1619 +			}
     1620 +		}
     1621 +	}
     1622 +
     1623   end:
     1624  	return err;
     1625  }
     1626 @@ -440,15 +491,178 @@
     1627  			const struct in6_addr *hoa,
     1628  			const struct in6_addr *coa,
     1629  			const struct in6_addr *old_coa,
     1630 -			int tunnel)
     1631 +			int tunnel,
     1632 +			struct list_head *mnp)
     1633  {
     1634  	struct ha_ipsec_tnl_update b;
     1635  	b.coa = *coa;
     1636  	b.old_coa = *old_coa;
     1637  	b.tunnel = tunnel;
     1638 +	b.mnp = mnp;
     1639  	return ipsec_policy_apply(haaddr, hoa, _ha_tnl_update, &b);
     1640  }
     1641  
     1642 +struct ha_ipsec_mnp_update {
     1643 +	int tunnel;
     1644 +	struct list_head *old_mnps;
     1645 +	struct list_head *new_mnps;
     1646 +};
     1647 +
     1648 +/*
     1649 + *   Add/Delete MNP IPsec Security Policy
     1650 + */
     1651 +static int _ha_mnp_pol_mod(const struct in6_addr *haaddr,
     1652 +			   const struct in6_addr *hoa,
     1653 +			   struct ipsec_policy_entry *e,
     1654 +			   void *arg,
     1655 +			   int add)
     1656 +{
     1657 +	int err = 0;
     1658 +	struct ha_ipsec_mnp_update *parms = (struct ha_ipsec_mnp_update *)arg;
     1659 +	struct xfrm_userpolicy_info sp;
     1660 +	struct xfrm_user_tmpl tmpl;
     1661 +	u_int16_t ipsec_proto;
     1662 +	struct list_head *list, *old_mnps, *new_mnps, *main_mnps, *ref_mnps;
     1663 +	int ifindex;
     1664 +
     1665 +	assert(haaddr);
     1666 +	assert(hoa);
     1667 +	assert(e);
     1668 +	assert(arg);
     1669 +
     1670 +	ifindex = parms->tunnel;
     1671 +	old_mnps = parms->old_mnps;
     1672 +	new_mnps = parms->new_mnps;
     1673 +
     1674 +	if (e->type != IPSEC_POLICY_TYPE_TUNNELPAYLOAD)
     1675 +		goto end;
     1676 +
     1677 +	/* XXX Limitation: Single IPsec proto can only be applied */
     1678 +	if (ipsec_use_esp(e))
     1679 +		ipsec_proto = IPPROTO_ESP;
     1680 +	else if (ipsec_use_ah(e))
     1681 +		ipsec_proto = IPPROTO_AH;
     1682 +	else if (ipsec_use_ipcomp(e))
     1683 +		ipsec_proto = IPPROTO_COMP;
     1684 +	else {
     1685 +		dbg("invalid ipsec proto\n");
     1686 +		goto end;
     1687 +	}
     1688 +
     1689 +	/* Reverse the search logic on lists based on expected
     1690 +	 * action (add/del) */
     1691 +	main_mnps = add ? new_mnps : old_mnps;
     1692 +	ref_mnps = add ? old_mnps : new_mnps;
     1693 +
     1694 +	if (main_mnps == NULL)
     1695 +		goto end;
     1696 +
     1697 +	/* We have to add/delete rules to protect traffic to
     1698 +	   and from MNP's, the same way as HoA */
     1699 +	list_for_each(list, main_mnps) {
     1700 +		struct prefix_list_entry *p;
     1701 +		p = list_entry(list, struct prefix_list_entry, list);
     1702 +
     1703 +		if (ref_mnps &&
     1704 +		    prefix_list_find(ref_mnps, &p->ple_prefix, p->ple_plen))
     1705 +			continue;
     1706 +
     1707 +		/* inbound */
     1708 +		_set_sp(&sp, e, XFRM_POLICY_IN, &in6addr_any, 0, &p->ple_prefix, p->ple_plen,
     1709 +			ifindex, MIP6_ENTITY_HA);
     1710 +		_set_tmpl(&tmpl, AF_INET6, ipsec_proto, XFRM_MODE_TUNNEL,
     1711 +			  haaddr, hoa, e->reqid_toha);
     1712 +		if (xfrm_ipsec_policy_mod(&sp, &tmpl, 1, add) < 0) {
     1713 +			dbg("modifying INBOUND policy failed\n");
     1714 +			err = -1;
     1715 +			goto end;
     1716 +		}
     1717 +
     1718 +		/* forward */
     1719 +		_set_sp(&sp, e, XFRM_POLICY_FWD, &in6addr_any, 0, &p->ple_prefix, p->ple_plen,
     1720 +			ifindex, MIP6_ENTITY_HA);
     1721 +		_set_tmpl(&tmpl, AF_INET6, ipsec_proto, XFRM_MODE_TUNNEL,
     1722 +			  haaddr, hoa, e->reqid_toha);
     1723 +		if (xfrm_ipsec_policy_mod(&sp, &tmpl, 1, add) < 0) {
     1724 +			dbg("modifying FORWARD policy failed\n");
     1725 +			err = -1;
     1726 +			goto end;
     1727 +		}
     1728 +
     1729 +		/* outbound */
     1730 +		_set_sp(&sp, e, XFRM_POLICY_OUT, &p->ple_prefix, p->ple_plen, &in6addr_any, 0,
     1731 +			ifindex, MIP6_ENTITY_HA);
     1732 +		_set_tmpl(&tmpl, AF_INET6, ipsec_proto, XFRM_MODE_TUNNEL,
     1733 +			  hoa, haaddr, e->reqid_tomn);
     1734 +		if (xfrm_ipsec_policy_mod(&sp, &tmpl, 1, add) < 0) {
     1735 +			dbg("modifying OUTBOUND policy failed\n");
     1736 +			err = -1;
     1737 +			goto end;
     1738 +		}
     1739 +	}
     1740 +
     1741 + end:
     1742 +	return err;
     1743 +}
     1744 +
     1745 +
     1746 +/*
     1747 + *   Add SP entry (for MNP on HA)
     1748 + *
     1749 + *   NOTE:
     1750 + *   - This is a hook routine to ipsec_policy_apply()
     1751 + */
     1752 +static int _ha_mnp_pol_add(const struct in6_addr *haaddr,
     1753 +			   const struct in6_addr *hoa,
     1754 +			   struct ipsec_policy_entry *e,
     1755 +			   void *arg)
     1756 +{
     1757 +	return _ha_mnp_pol_mod(haaddr, hoa, e, arg, 1);
     1758 +}
     1759 +
     1760 +int ha_ipsec_mnp_pol_add(const struct in6_addr *our_addr,
     1761 +			 const struct in6_addr *peer_addr,
     1762 +			 struct list_head *old_mnps,
     1763 +			 struct list_head *new_mnps,
     1764 +			 int tunnel)
     1765 +{
     1766 +	struct ha_ipsec_mnp_update b;
     1767 +	b.tunnel = tunnel;
     1768 +	b.old_mnps = old_mnps;
     1769 +	b.new_mnps = new_mnps;
     1770 +
     1771 +	return ipsec_policy_apply(our_addr, peer_addr, _ha_mnp_pol_add, &b);
     1772 +}
     1773 +
     1774 +/*
     1775 + *   Delete SP entry (for MNP on HA)
     1776 + *
     1777 + *   NOTE:
     1778 + *   - This is a hook routine to ipsec_policy_apply()
     1779 + */
     1780 +static int _ha_mnp_pol_del(const struct in6_addr *haaddr,
     1781 +			   const struct in6_addr *hoa,
     1782 +			   struct ipsec_policy_entry *e,
     1783 +			   void *arg)
     1784 +{
     1785 +	return _ha_mnp_pol_mod(haaddr, hoa, e, arg, 0);
     1786 +}
     1787 +
     1788 +int ha_ipsec_mnp_pol_del(const struct in6_addr *our_addr,
     1789 +			 const struct in6_addr *peer_addr,
     1790 +			 struct list_head *old_mnps,
     1791 +			 struct list_head *new_mnps,
     1792 +			 int tunnel)
     1793 +{
     1794 +	struct ha_ipsec_mnp_update b;
     1795 +	b.tunnel = tunnel;
     1796 +	b.old_mnps = old_mnps;
     1797 +	b.new_mnps = new_mnps;
     1798 +
     1799 +	return ipsec_policy_apply(our_addr, peer_addr,
     1800 +				  _ha_mnp_pol_del, &b);
     1801 +}
     1802 +
     1803  /*
     1804   *   Add/Delete IPsec Security Policy 
     1805   */
     1806 @@ -459,7 +673,9 @@
     1807  			   int add)
     1808  {
     1809  	int err = 0;
     1810 -	int ifindex = *(int *)arg;
     1811 +	struct ha_ipsec_tnl_update *parms = (struct ha_ipsec_tnl_update *)arg;
     1812 +	int ifindex;
     1813 +	struct list_head *mnp;
     1814  	struct xfrm_userpolicy_info sp;
     1815  	struct xfrm_user_tmpl tmpl;
     1816  	u_int16_t ipsec_proto;
     1817 @@ -469,6 +685,9 @@
     1818  	assert(e);
     1819  	assert(arg);
     1820  
     1821 +	ifindex = parms->tunnel;
     1822 +	mnp = parms->mnp;
     1823 +
     1824  	switch (e->type) {
     1825  	case IPSEC_POLICY_TYPE_TUNNELHOMETESTING:
     1826  	case IPSEC_POLICY_TYPE_TUNNELMH:
     1827 @@ -493,7 +712,7 @@
     1828  	dump_migrate(ifindex, ipsec_proto, hoa, haaddr, NULL, NULL);
     1829  
     1830  	/* inbound */
     1831 -	_set_sp(&sp, e, XFRM_POLICY_IN, &in6addr_any, hoa,
     1832 +	_set_sp(&sp, e, XFRM_POLICY_IN, &in6addr_any, 0, hoa, 0,
     1833  		ifindex, MIP6_ENTITY_HA);
     1834  	_set_tmpl(&tmpl, AF_INET6, ipsec_proto, XFRM_MODE_TUNNEL,
     1835  		  haaddr, hoa, e->reqid_toha);
     1836 @@ -504,7 +723,7 @@
     1837  	}
     1838  
     1839  	/* forward */
     1840 -	_set_sp(&sp, e, XFRM_POLICY_FWD, &in6addr_any, hoa,
     1841 +	_set_sp(&sp, e, XFRM_POLICY_FWD, &in6addr_any, 0, hoa, 0,
     1842  		ifindex, MIP6_ENTITY_HA);
     1843  	_set_tmpl(&tmpl, AF_INET6, ipsec_proto, XFRM_MODE_TUNNEL,
     1844  		  haaddr, hoa, e->reqid_toha);
     1845 @@ -515,7 +734,7 @@
     1846  	}
     1847  
     1848  	/* outbound */
     1849 -	_set_sp(&sp, e, XFRM_POLICY_OUT, hoa, &in6addr_any,
     1850 +	_set_sp(&sp, e, XFRM_POLICY_OUT, hoa, 0, &in6addr_any, 0,
     1851  		ifindex, MIP6_ENTITY_HA);
     1852  	_set_tmpl(&tmpl, AF_INET6, ipsec_proto, XFRM_MODE_TUNNEL,
     1853  		  hoa, haaddr, e->reqid_tomn);
     1854 @@ -525,6 +744,16 @@
     1855  		goto end;
     1856  	}
     1857  
     1858 +	/* Mobile Router case */
     1859 +	if ((e->type == IPSEC_POLICY_TYPE_TUNNELPAYLOAD) && mnp) {
     1860 +		struct ha_ipsec_mnp_update b;
     1861 +
     1862 +		b.tunnel = ifindex;
     1863 +		b.old_mnps = add ? NULL : mnp;
     1864 +		b.new_mnps = add ? mnp : NULL;
     1865 +
     1866 +		err = _ha_mnp_pol_mod(haaddr, hoa, e, (void *)&b, add);
     1867 +	}
     1868   end:
     1869  	return err;
     1870  }
     1871 @@ -545,11 +774,14 @@
     1872  
     1873  int ha_ipsec_tnl_pol_add(const struct in6_addr *our_addr, 
     1874  			 const struct in6_addr *peer_addr,
     1875 -			 int tunnel)
     1876 +			 int tunnel,
     1877 +			 struct list_head *mnp)
     1878  {
     1879 -	int t = tunnel;
     1880 +	struct ha_ipsec_tnl_update b;
     1881 +	b.tunnel = tunnel;
     1882 +	b.mnp = mnp;
     1883  
     1884 -	return ipsec_policy_apply(our_addr, peer_addr, _ha_tnl_pol_add, &t);
     1885 +	return ipsec_policy_apply(our_addr, peer_addr, _ha_tnl_pol_add, &b);
     1886  }
     1887  
     1888  /*
     1889 @@ -568,12 +800,15 @@
     1890  
     1891  int ha_ipsec_tnl_pol_del(const struct in6_addr *our_addr, 
     1892  			 const struct in6_addr *peer_addr,
     1893 -			 int tunnel)
     1894 +			 int tunnel,
     1895 +			 struct list_head *mnp)
     1896  {
     1897 -	int t = tunnel;
     1898 +	struct ha_ipsec_tnl_update b;
     1899 +	b.tunnel = tunnel;
     1900 +	b.mnp = mnp;
     1901  
     1902  	return ipsec_policy_apply(our_addr, peer_addr,
     1903 -				  _ha_tnl_pol_del, &t);
     1904 +				  _ha_tnl_pol_del, &b);
     1905  }
     1906  
     1907  /*
     1908 @@ -631,7 +866,7 @@
     1909  	/* outbound */
     1910  	_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
     1911  		  haaddr, oldcoa, e->reqid_toha);
     1912 -	_set_sp(&sp, e, XFRM_POLICY_OUT, &in6addr_any, hoa,
     1913 +	_set_sp(&sp, e, XFRM_POLICY_OUT, &in6addr_any, 0, hoa, 0,
     1914  		ifindex, MIP6_ENTITY_MN);
     1915  	if ((err = xfrm_sendmigrate(&sp, &tmpl, haaddr, newcoa)) < 0) {
     1916  		dbg("migrate for OUTBOUND policy failed\n");
     1917 @@ -641,7 +876,7 @@
     1918  	/* inbound */
     1919  	_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
     1920  		  oldcoa, haaddr, e->reqid_tomn);
     1921 -	_set_sp(&sp, e, XFRM_POLICY_IN, hoa, &in6addr_any,
     1922 +	_set_sp(&sp, e, XFRM_POLICY_IN, hoa, 0, &in6addr_any, 0,
     1923  		ifindex, MIP6_ENTITY_MN);
     1924  	if ((err = xfrm_sendmigrate(&sp, &tmpl, newcoa, haaddr)) < 0) {
     1925  		dbg("migrate for INBOUND policy (1) failed\n");
     1926 @@ -657,7 +892,7 @@
     1927  		/* template */
     1928  		_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
     1929  			  oldcoa, haaddr, e->reqid_tomn);
     1930 -		_set_sp(&sp, e, XFRM_POLICY_IN, hoa, &in6addr_any,
     1931 +		_set_sp(&sp, e, XFRM_POLICY_IN, hoa, 0, &in6addr_any, 0,
     1932  			ifindex, MIP6_ENTITY_MN);
     1933  		/* additional settings */
     1934  		sp.priority = MIP6_PRIO_RO_SIG_IPSEC;
     1935 @@ -669,6 +904,52 @@
     1936  		}
     1937  	}
     1938  
     1939 +	/*
     1940 +	 * If we are a Mobile Router, we also need to migrate IN/FWD/OUT rules
     1941 +	 * for forwarded traffic in case we have TUNNELPAYLOAD protection.
     1942 +	 */
     1943 +	if ((e->type == IPSEC_POLICY_TYPE_TUNNELPAYLOAD) && (bule->home->mob_rtr))
     1944 +	{
     1945 +		struct list_head *mnp;
     1946 +
     1947 +		list_for_each(mnp, &bule->home->mob_net_prefixes)
     1948 +		{
     1949 +			struct prefix_list_entry *p;
     1950 +			p = list_entry(mnp, struct prefix_list_entry, list);
     1951 +
     1952 +			/* outbound */
     1953 +			_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
     1954 +				  haaddr, oldcoa, e->reqid_toha);
     1955 +			_set_sp(&sp, e, XFRM_POLICY_OUT, &in6addr_any, 0, &p->ple_prefix, p->ple_plen,
     1956 +				ifindex, MIP6_ENTITY_MN);
     1957 +			if ((err = xfrm_sendmigrate(&sp, &tmpl, haaddr, newcoa)) < 0) {
     1958 +				dbg("migrate for OUTBOUND policy failed\n");
     1959 +				goto end;
     1960 +			}
     1961 +
     1962 +			/* forwarded */
     1963 +			_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
     1964 +				  oldcoa, haaddr, e->reqid_tomn);
     1965 +			_set_sp(&sp, e, XFRM_POLICY_IN, &p->ple_prefix, p->ple_plen, &in6addr_any, 0,
     1966 +				ifindex, MIP6_ENTITY_MN);
     1967 +			if ((err = xfrm_sendmigrate(&sp, &tmpl, newcoa, haaddr)) < 0) {
     1968 +				dbg("migrate for INBOUND policy (1) failed\n");
     1969 +				goto end;
     1970 +			}
     1971 +
     1972 +			/* inbound */
     1973 +			_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
     1974 +				  oldcoa, haaddr, e->reqid_tomn);
     1975 +			_set_sp(&sp, e, XFRM_POLICY_IN, &p->ple_prefix, p->ple_plen, &in6addr_any, 0,
     1976 +				ifindex, MIP6_ENTITY_MN);
     1977 +			if ((err = xfrm_sendmigrate(&sp, &tmpl, newcoa, haaddr)) < 0) {
     1978 +				dbg("migrate for INBOUND policy (1) failed\n");
     1979 +				goto end;
     1980 +			}
     1981 +
     1982 +		}
     1983 +	}
     1984 +
     1985   end:
     1986  	return err;
     1987  }
     1988 @@ -724,7 +1005,7 @@
     1989  	dump_migrate(ifindex, ipsec_proto, hoa, haaddr, NULL, NULL);
     1990  
     1991  	/* inbound */
     1992 -	_set_sp(&sp, e, XFRM_POLICY_IN, hoa, &in6addr_any,
     1993 +	_set_sp(&sp, e, XFRM_POLICY_IN, hoa, 0, &in6addr_any, 0,
     1994  		ifindex, MIP6_ENTITY_MN);
     1995  	_set_tmpl(&tmpl, AF_INET6, ipsec_proto, XFRM_MODE_TUNNEL,
     1996  		  hoa, haaddr, e->reqid_tomn);
     1997 @@ -735,7 +1016,7 @@
     1998  	}
     1999  		
     2000  	/* outbound */
     2001 -	_set_sp(&sp, e, XFRM_POLICY_OUT, &in6addr_any, hoa,
     2002 +	_set_sp(&sp, e, XFRM_POLICY_OUT, &in6addr_any, 0, hoa, 0,
     2003  		ifindex, MIP6_ENTITY_MN);
     2004  	_set_tmpl(&tmpl, AF_INET6, ipsec_proto, XFRM_MODE_TUNNEL,
     2005  		  haaddr, hoa, e->reqid_toha);
     2006 @@ -761,6 +1042,54 @@
     2007  		}
     2008  	}
     2009  
     2010 +	/*
     2011 +	 * If we are a Mobile Router, we also need to create IN/FWD/OUT rules
     2012 +	 * for forwarded traffic in case we have TUNNELPAYLOAD protection.
     2013 +	 */
     2014 +	if ((e->type == IPSEC_POLICY_TYPE_TUNNELPAYLOAD) && (bule->home->mob_rtr))
     2015 +	{
     2016 +		struct list_head *mnp;
     2017 +
     2018 +		list_for_each(mnp, &bule->home->mob_net_prefixes)
     2019 +		{
     2020 +			struct prefix_list_entry *p;
     2021 +			p = list_entry(mnp, struct prefix_list_entry, list);
     2022 +
     2023 +			/* inbound */
     2024 +			_set_sp(&sp, e, XFRM_POLICY_IN, &p->ple_prefix, p->ple_plen, &in6addr_any, 0,
     2025 +				ifindex, MIP6_ENTITY_MN);
     2026 +			_set_tmpl(&tmpl, AF_INET6, ipsec_proto, XFRM_MODE_TUNNEL,
     2027 +				  hoa, haaddr, e->reqid_tomn);
     2028 +			if (xfrm_ipsec_policy_mod(&sp, &tmpl, 1, add) < 0) {
     2029 +				dbg("modifying INBOUND policy failed.\n");
     2030 +				err = -1;
     2031 +				goto end;
     2032 +			}
     2033 +
     2034 +			/* forward */
     2035 +			_set_sp(&sp, e, XFRM_POLICY_FWD, &p->ple_prefix, p->ple_plen, &in6addr_any, 0,
     2036 +				ifindex, MIP6_ENTITY_MN);
     2037 +			_set_tmpl(&tmpl, AF_INET6, ipsec_proto, XFRM_MODE_TUNNEL,
     2038 +				  hoa, haaddr, e->reqid_tomn);
     2039 +			if (xfrm_ipsec_policy_mod(&sp, &tmpl, 1, add) < 0) {
     2040 +				dbg("modifying INBOUND policy failed.\n");
     2041 +				err = -1;
     2042 +				goto end;
     2043 +			}
     2044 +
     2045 +			/* outbound */
     2046 +			_set_sp(&sp, e, XFRM_POLICY_OUT, &in6addr_any, 0, &p->ple_prefix, p->ple_plen,
     2047 +				ifindex, MIP6_ENTITY_MN);
     2048 +			_set_tmpl(&tmpl, AF_INET6, ipsec_proto, XFRM_MODE_TUNNEL,
     2049 +				  haaddr, hoa, e->reqid_toha);
     2050 +			if (xfrm_ipsec_policy_mod(&sp, &tmpl, 1, add) < 0) {
     2051 +				dbg("modifying OUTBOUND policy failed.\n");
     2052 +				err = -1;
     2053 +				goto end;
     2054 +			}
     2055 +		}
     2056 +	}
     2057 +
     2058   end:
     2059  	return err;
     2060  }
     2061 diff -r c04f74757df5 src/ipsec.h
     2062 --- a/src/ipsec.h	Sun Nov 30 23:14:35 2008 +0100
     2063 +++ b/src/ipsec.h	Sun Nov 30 23:14:48 2008 +0100
     2064 @@ -82,15 +82,30 @@
     2065  			const struct in6_addr *hoa,
     2066  			const struct in6_addr *coa,
     2067  			const struct in6_addr *old_coa,
     2068 -			int tunnel);
     2069 +			int tunnel,
     2070 +			struct list_head *mnp);
     2071 +
     2072 +int ha_ipsec_mnp_pol_del(const struct in6_addr *our_addr,
     2073 +			 const struct in6_addr *peer_addr,
     2074 +			 struct list_head *old_mnps,
     2075 +			 struct list_head *new_mnps,
     2076 +			 int tunnel);
     2077 +
     2078 +int ha_ipsec_mnp_pol_add(const struct in6_addr *our_addr,
     2079 +			 const struct in6_addr *peer_addr,
     2080 +			 struct list_head *old_mnps,
     2081 +			 struct list_head *new_mnps,
     2082 +			 int tunnel);
     2083  
     2084  int ha_ipsec_tnl_pol_add(const struct in6_addr *our_addr, 
     2085  			 const struct in6_addr *peer_addr,
     2086 -			 int tunnel);
     2087 +			 int tunnel,
     2088 +			 struct list_head *mnp);
     2089  
     2090  int ha_ipsec_tnl_pol_del(const struct in6_addr *our_addr, 
     2091  			 const struct in6_addr *peer_addr,
     2092 -			 int tunnel);
     2093 +			 int tunnel,
     2094 +			 struct list_head *mnp);
     2095  
     2096  int mn_ipsec_tnl_update(const struct in6_addr *haaddr,
     2097  			const struct in6_addr *hoa,
     2098 diff -r c04f74757df5 src/mh.c
     2099 --- a/src/mh.c	Sun Nov 30 23:14:35 2008 +0100
     2100 +++ b/src/mh.c	Sun Nov 30 23:14:48 2008 +0100
     2101 @@ -51,6 +51,7 @@
     2102  #include "conf.h"
     2103  #include "bcache.h"
     2104  #include "keygen.h"
     2105 +#include "prefix.h"
     2106  
     2107  #define MH_DEBUG_LEVEL 1
     2108  
     2109 @@ -75,6 +76,7 @@
     2110  	0, /* Alternate CoA */
     2111  	0, /* Nonce Index */
     2112  	0, /* Binding Auth Data */
     2113 +	1, /* Mobile Network Prefix */
     2114  };
     2115  
     2116  #define __MH_SENTINEL (IP6_MH_TYPE_MAX + 1)
     2117 @@ -401,6 +403,46 @@
     2118  	return 0;
     2119  }
     2120  
     2121 +int mh_create_opt_mob_net_prefix(struct iovec *iov, int mnp_count,
     2122 +				 struct list_head *mnps)
     2123 +{
     2124 +	int optlen = (mnp_count * sizeof(struct ip6_mh_opt_mob_net_prefix) +
     2125 +		      (mnp_count - 1) * sizeof(_pad4));
     2126 +	struct list_head *l;
     2127 +	int i = 0;
     2128 +	uint8_t *data;
     2129 +	iov->iov_base = malloc(optlen);
     2130 +	iov->iov_len = optlen;
     2131 +
     2132 +	if (iov->iov_base == NULL)
     2133 +		return -ENOMEM;
     2134 +
     2135 +	memset(iov->iov_base, 0, iov->iov_len);
     2136 +	data = (uint8_t *)iov->iov_base;
     2137 +
     2138 +	list_for_each(l, mnps) {
     2139 +		struct prefix_list_entry *p;
     2140 +		struct ip6_mh_opt_mob_net_prefix *mnp;
     2141 +
     2142 +		p = list_entry(l, struct prefix_list_entry, list);
     2143 +		mnp = (struct ip6_mh_opt_mob_net_prefix *)data;
     2144 +
     2145 +		mnp->ip6mnp_type = IP6_MHOPT_MOB_NET_PRFX;
     2146 +		mnp->ip6mnp_len = 18;
     2147 +		mnp->ip6mnp_prefix_len = p->ple_plen;
     2148 +		mnp->ip6mnp_prefix = p->ple_prefix;
     2149 +
     2150 +		data += sizeof(struct ip6_mh_opt_mob_net_prefix);
     2151 +
     2152 +		/* do internal padding here, so one iovec for MNPs is enough */
     2153 +		if (++i < mnp_count) {
     2154 +		  memcpy(data, _pad4, sizeof(_pad4));
     2155 +		  data += sizeof(_pad4);
     2156 +		}
     2157 +	}
     2158 +	return 0;
     2159 +}
     2160 +
     2161  static size_t mh_length(struct iovec *vec, int count)
     2162  {
     2163  	size_t len = 0;
     2164 @@ -442,6 +484,9 @@
     2165  		case IP6_MHOPT_BAUTH:
     2166  			pad = optpad(8, 2, len); /* 8n+2 */
     2167  			break;
     2168 +		case IP6_MHOPT_MOB_NET_PRFX:
     2169 +			pad = optpad(8, 4, len); /* 8n+4 */
     2170 +			break;
     2171  		}
     2172  		if (pad > 0) {
     2173  			create_opt_pad(&out[n++], pad);
     2174 @@ -694,6 +739,8 @@
     2175  		return len != sizeof(struct ip6_mh_opt_nonce_index);
     2176  	case IP6_MHOPT_BAUTH:
     2177  		return len != sizeof(struct ip6_mh_opt_auth_data);
     2178 +	case IP6_MHOPT_MOB_NET_PRFX:
     2179 +		return len != sizeof(struct ip6_mh_opt_mob_net_prefix);
     2180  	case IP6_MHOPT_PADN:
     2181  	default:
     2182  		return 0;
     2183 diff -r c04f74757df5 src/mh.h
     2184 --- a/src/mh.h	Sun Nov 30 23:14:35 2008 +0100
     2185 +++ b/src/mh.h	Sun Nov 30 23:14:48 2008 +0100
     2186 @@ -10,7 +10,7 @@
     2187  
     2188  /* If new types or options appear, these should be updated. */
     2189  #define IP6_MH_TYPE_MAX IP6_MH_TYPE_BERROR
     2190 -#define IP6_MHOPT_MAX IP6_MHOPT_BAUTH
     2191 +#define IP6_MHOPT_MAX IP6_MHOPT_MOB_NET_PRFX
     2192  
     2193  struct in6_addr_bundle {
     2194  	struct in6_addr *src;
     2195 @@ -74,6 +74,11 @@
     2196  
     2197  int mh_create_opt_auth_data(struct iovec *iov);
     2198  
     2199 +struct list_head;
     2200 +
     2201 +int mh_create_opt_mob_net_prefix(struct iovec *iov, int mnp_count,
     2202 +				 struct list_head *mnps);
     2203 +
     2204  static inline void *mh_opt(const struct ip6_mh *mh,
     2205  			   const struct mh_options *mh_opts, uint8_t type)
     2206  {
     2207 diff -r c04f74757df5 src/mn.c
     2208 --- a/src/mn.c	Sun Nov 30 23:14:35 2008 +0100
     2209 +++ b/src/mn.c	Sun Nov 30 23:14:48 2008 +0100
     2210 @@ -326,7 +326,17 @@
     2211  		free_iov_data(iov, iov_ind);
     2212  		return -ENOMEM;
     2213  	}
     2214 -	if (!(bule->flags & IP6_MH_BU_HOME)) {
     2215 +	if (bule->flags & IP6_MH_BU_HOME) {
     2216 +		struct home_addr_info *hai = bule->home;
     2217 +		if (bule->flags & IP6_MH_BU_MR && bu->ip6mhbu_lifetime &&
     2218 +		    bule->home->mnp_count > 0 && conf.MobRtrUseExplicitMode &&
     2219 +		    mh_create_opt_mob_net_prefix(&iov[iov_ind++],
     2220 +						 hai->mnp_count,
     2221 +						 &hai->mob_net_prefixes) < 0) {
     2222 +			free_iov_data(iov, iov_ind);
     2223 +			return -ENOMEM;
     2224 +		}
     2225 +	} else {
     2226  		if (mh_create_opt_nonce_index(&iov[iov_ind++], bule->rr.ho_ni,
     2227  					      bule->rr.co_ni) ||
     2228  		    mh_create_opt_auth_data(&iov[iov_ind++])) {
     2229 @@ -616,6 +626,34 @@
     2230  	return 0;
     2231  }
     2232  
     2233 +int nemo_mr_tnl_routes_add(struct home_addr_info *hai, int ifindex)
     2234 +{
     2235 +	struct list_head *l;
     2236 +	struct prefix_list_entry *pe;
     2237 +	list_for_each(l, &hai->mob_net_prefixes) {
     2238 +		struct prefix_list_entry *p;
     2239 +		p = list_entry(l, struct prefix_list_entry, list);
     2240 +		if (route_add(ifindex, RT6_TABLE_MIP6, RTPROT_MIP,
     2241 +			      0, IP6_RT_PRIO_MIP6_FWD,
     2242 +			      &p->ple_prefix, p->ple_plen,
     2243 +			      &in6addr_any, 0, NULL) < 0) {
     2244 +			pe = p;
     2245 +			goto undo;
     2246 +		}
     2247 +	}
     2248 +	return 0;
     2249 +undo:
     2250 +	list_for_each(l, &hai->mob_net_prefixes) {
     2251 +		struct prefix_list_entry *p;
     2252 +		p = list_entry(l, struct prefix_list_entry, list);
     2253 +		route_del(ifindex, RT6_TABLE_MIP6, IP6_RT_PRIO_MIP6_FWD,
     2254 +			  &p->ple_prefix, p->ple_plen, &in6addr_any, 0, NULL);
     2255 +		if (p == pe)
     2256 +			break;
     2257 +	}
     2258 +	return -1;
     2259 +}
     2260 +
     2261  static int mn_tnl_state_add(struct home_addr_info *hai, int ifindex, int all)
     2262  {
     2263  	int err = 0;
     2264 @@ -628,12 +666,31 @@
     2265  			mn_ro_pol_del(hai, ifindex, all);
     2266  		}
     2267  	}
     2268 +	if (hai->mob_rtr &&
     2269 +	    (err = nemo_mr_tnl_routes_add(hai, ifindex)) < 0) {
     2270 +		route_del(ifindex, RT6_TABLE_MIP6, IP6_RT_PRIO_MIP6_OUT,
     2271 +			  &hai->hoa.addr, 128, &in6addr_any, 0, NULL);
     2272 +		mn_ro_pol_del(hai, ifindex, all);
     2273 +	}
     2274  	return err;
     2275  }
     2276  
     2277 +static void nemo_mr_tnl_routes_del(struct home_addr_info *hai, int ifindex)
     2278 +{
     2279 +	struct list_head *l;
     2280 +	list_for_each(l, &hai->mob_net_prefixes) {
     2281 +		struct prefix_list_entry *p;
     2282 +		p = list_entry(l, struct prefix_list_entry, list);
     2283 +		route_del(ifindex, RT6_TABLE_MIP6, IP6_RT_PRIO_MIP6_FWD,
     2284 +			  &p->ple_prefix, p->ple_plen, &in6addr_any, 0, NULL);
     2285 +	}
     2286 +}
     2287 +
     2288  static void mn_tnl_state_del(struct home_addr_info *hai, int ifindex, int all)
     2289  {
     2290  	if (hai->home_reg_status != HOME_REG_NONE) {
     2291 +		if (hai->mob_rtr)
     2292 +			nemo_mr_tnl_routes_del(hai, ifindex);
     2293  		route_del(ifindex, RT6_TABLE_MIP6, IP6_RT_PRIO_MIP6_OUT, 
     2294  			  &hai->hoa.addr, 128, &in6addr_any, 0, NULL);
     2295  		mn_ro_pol_del(hai, ifindex, all);
     2296 @@ -674,7 +731,8 @@
     2297  {
     2298  	int err = 0;
     2299  	bule->type = BUL_ENTRY;
     2300 -	bule->flags = IP6_MH_BU_HOME | IP6_MH_BU_ACK | hai->lladdr_comp;
     2301 +	bule->flags = (IP6_MH_BU_HOME | IP6_MH_BU_ACK |
     2302 +		       hai->lladdr_comp | hai->mob_rtr);
     2303  	if (conf.UseMnHaIPsec && conf.KeyMngMobCapability)
     2304  		bule->flags |= IP6_MH_BU_KEYM;
     2305  	bule->coa_changed = -1;
     2306 @@ -1086,6 +1144,18 @@
     2307  	if (bule->flags & IP6_MH_BU_HOME) {
     2308  		struct home_addr_info *hai = bule->home;
     2309  		struct ip6_mh_opt_refresh_advice *bra;
     2310 +
     2311 +		if (bule->flags & IP6_MH_BU_MR &&
     2312 +		    !(ba->ip6mhba_flags & IP6_MH_BA_MR)) {
     2313 +			if (hai->use_dhaad) {
     2314 +				mn_change_ha(hai);
     2315 +			} else {
     2316 +				int one = 1;
     2317 +				bul_iterate(&hai->bul, mn_dereg, &one);
     2318 +			}
     2319 +			pthread_rwlock_unlock(&mn_lock);
     2320 +			return;
     2321 +		}
     2322  		if (!tsisset(ba_lifetime)) {
     2323  			int type = FLUSH_FAILED;
     2324  			mn_dereg_home(hai);
     2325 @@ -1261,12 +1331,73 @@
     2326  	return 0;
     2327  }
     2328  
     2329 +static void nemo_mr_rules_del(struct home_addr_info *hinfo)
     2330 +{
     2331 +	struct list_head *l;
     2332 +
     2333 +	list_for_each(l, &hinfo->mob_net_prefixes) {
     2334 +		struct prefix_list_entry *p = NULL;
     2335 +		p = list_entry(l, struct prefix_list_entry, list);
     2336 +		rule_del(NULL, RT6_TABLE_MIP6,
     2337 +			 IP6_RULE_PRIO_MIP6_FWD, RTN_UNICAST,
     2338 +			 &p->ple_prefix, p->ple_plen, &in6addr_any, 0, 0);
     2339 +		rule_del(NULL, RT6_TABLE_MAIN,
     2340 +			 IP6_RULE_PRIO_MIP6_MNP_IN, RTN_UNICAST,
     2341 +			 &in6addr_any, 0, &p->ple_prefix, p->ple_plen, 0);
     2342 +	}
     2343 +}
     2344 +
     2345 +static int nemo_mr_rules_add(struct home_addr_info *hinfo)
     2346 +{
     2347 +	struct prefix_list_entry *pe = NULL;
     2348 +	struct list_head *l;
     2349 +
     2350 +	list_for_each(l, &hinfo->mob_net_prefixes) {
     2351 +		struct prefix_list_entry *p = NULL;
     2352 +		p = list_entry(l, struct prefix_list_entry, list);
     2353 +		if (rule_add(NULL, RT6_TABLE_MAIN,
     2354 +			     IP6_RULE_PRIO_MIP6_MNP_IN, RTN_UNICAST,
     2355 +			     &in6addr_any, 0,
     2356 +			     &p->ple_prefix, p->ple_plen, 0) < 0) {
     2357 +			pe = p;
     2358 +			goto undo;
     2359 +		}
     2360 +		if (rule_add(NULL, RT6_TABLE_MIP6,
     2361 +			     IP6_RULE_PRIO_MIP6_FWD, RTN_UNICAST,
     2362 +			     &p->ple_prefix, p->ple_plen,
     2363 +			     &in6addr_any, 0, 0) < 0) {
     2364 +			rule_del(NULL, RT6_TABLE_MAIN,
     2365 +				 IP6_RULE_PRIO_MIP6_MNP_IN, RTN_UNICAST,
     2366 +				 &in6addr_any, 0, &p->ple_prefix, p->ple_plen, 0);
     2367 +			pe = p;
     2368 +			goto undo;
     2369 +		}
     2370 +	}
     2371 +	return 0;
     2372 +undo:
     2373 +	list_for_each(l, &hinfo->mob_net_prefixes) {
     2374 +		struct prefix_list_entry *p = NULL;
     2375 +		p = list_entry(l, struct prefix_list_entry, list);
     2376 +		rule_del(NULL, RT6_TABLE_MIP6,
     2377 +			 IP6_RULE_PRIO_MIP6_FWD,  RTN_UNICAST,
     2378 +			 &p->ple_prefix, p->ple_plen, &in6addr_any, 0, 0);
     2379 +		rule_del(NULL, RT6_TABLE_MAIN,
     2380 +			 IP6_RULE_PRIO_MIP6_MNP_IN, RTN_UNICAST,
     2381 +			 &in6addr_any, 0, &p->ple_prefix, p->ple_plen, 0);
     2382 +		if (p == pe)
     2383 +			break;
     2384 +	}
     2385 +	return -1;
     2386 +}
     2387 +
     2388  static void clean_home_addr_info(struct home_addr_info *hai)
     2389  {
     2390  	struct flag_hoa_args arg;
     2391  	int plen = (hai->hoa.iif == hai->if_tunnel ? 128 : hai->plen);
     2392  
     2393  	list_del(&hai->list);
     2394 +	if (hai->mob_rtr)
     2395 +		nemo_mr_rules_del(hai);
     2396  	arg.target = hai;
     2397  	arg.flag = 0;
     2398  	addr_do(&hai->hoa.addr, plen,
     2399 @@ -1320,13 +1451,23 @@
     2400  
     2401  		if (pthread_mutex_init(&hai->ha_list.c_lock, NULL))
     2402  			goto undo;
     2403 +
     2404 +		INIT_LIST_HEAD(&hai->mob_net_prefixes);
     2405 +		if (hai->mob_rtr &&
     2406 +		    prefix_list_copy(&conf_hai->mob_net_prefixes,
     2407 +				     &hai->mob_net_prefixes) < 0)
     2408 +			goto mutex_undo;
     2409 +
     2410  		INIT_LIST_HEAD(&hai->ro_policies);
     2411  		if (rpl_copy(&conf_hai->ro_policies, &hai->ro_policies) < 0)
     2412 -			goto mutex_undo;
     2413 +			goto mnp_undo;
     2414 +
     2415  		INIT_LIST_HEAD(&hai->ha_list.tqe.list);
     2416  		INIT_LIST_HEAD(&hai->ha_list.home_agents);
     2417  	}
     2418  	return hai;
     2419 +mnp_undo:
     2420 +	prefix_list_free(&hai->mob_net_prefixes);
     2421  mutex_undo:
     2422  	pthread_mutex_destroy(&hai->ha_list.c_lock);
     2423  undo:
     2424 @@ -1347,6 +1488,15 @@
     2425  	if  ((hai = hai_copy(conf_hai)) == NULL)
     2426  		goto err;
     2427  
     2428 +	if (hai->mob_rtr) {
     2429 +		MDBG("is Mobile Router\n");
     2430 +		list_for_each(list, &hai->mob_net_prefixes) {
     2431 +			struct prefix_list_entry *p;
     2432 +			p = list_entry(list, struct prefix_list_entry, list);
     2433 +			MDBG("Mobile Network Prefix %x:%x:%x:%x:%x:%x:%x:%x/%d\n",
     2434 +			     NIP6ADDR(&p->ple_prefix), p->ple_plen);
     2435 +		}
     2436 +	}
     2437  	if (IN6_IS_ADDR_UNSPECIFIED(&hai->ha_addr)) {
     2438  		hai->use_dhaad = 1;
     2439  	} else {
     2440 @@ -1391,6 +1541,9 @@
     2441  		    hai->if_tunnel, &arg, flag_hoa) < 0) {
     2442  		goto clean_err;
     2443  	}
     2444 +	if (hai->mob_rtr && nemo_mr_rules_add(hai) < 0) {
     2445 +		goto clean_err;
     2446 +	}
     2447  	hai->at_home = hai->hoa.iif == hai->if_home;
     2448  	pthread_rwlock_wrlock(&mn_lock);
     2449  	list_add(&hai->list, &home_addr_list);
     2450 diff -r c04f74757df5 src/mn.h
     2451 --- a/src/mn.h	Sun Nov 30 23:14:35 2008 +0100
     2452 +++ b/src/mn.h	Sun Nov 30 23:14:48 2008 +0100
     2453 @@ -45,9 +45,11 @@
     2454  	pthread_mutex_t c_lock;
     2455  };
     2456  
     2457 -#define	HOME_LINK_BLOCK	0x1
     2458 -#define	HOME_ADDR_BLOCK	0x2
     2459 -#define	HOME_ADDR_RULE_BLOCK	0x4
     2460 +#define	HOME_LINK_BLOCK	0x01
     2461 +#define	HOME_ADDR_BLOCK	0x02
     2462 +#define	HOME_ADDR_RULE_BLOCK	0x04
     2463 +#define	NEMO_RA_BLOCK	0x08
     2464 +#define	NEMO_FWD_BLOCK	0x10
     2465  
     2466  struct mn_addr {
     2467  	struct in6_addr addr;
     2468 @@ -84,7 +86,10 @@
     2469  	int if_block;
     2470  	short hwalen;
     2471  	uint8_t altcoa;
     2472 +	uint16_t mob_rtr;
     2473  	char name[IF_NAMESIZE];
     2474 +	int mnp_count;
     2475 +	struct list_head mob_net_prefixes;
     2476  };
     2477  
     2478  enum {
     2479 diff -r c04f74757df5 src/movement.c
     2480 --- a/src/movement.c	Sun Nov 30 23:14:35 2008 +0100
     2481 +++ b/src/movement.c	Sun Nov 30 23:14:48 2008 +0100
     2482 @@ -78,6 +78,7 @@
     2483  static int conf_default_rs = 3;
     2484  static int conf_default_rs_ival = 4;
     2485  
     2486 +static int conf_forwarding = 0;
     2487  static int conf_autoconf = 1;
     2488  static int conf_ra_defrtr = 0;
     2489  static int conf_rs = 0;
     2490 @@ -177,6 +178,12 @@
     2491  
     2492  		route_del(rtr->ifindex, RT_TABLE_MAIN, 0,
     2493  			  &in6addr_any, 0, &in6addr_any, 0, &rtr->lladdr);
     2494 +
     2495 +		/* delete default route for the packets coming from the
     2496 +		 * Mobile Network
     2497 +		 */
     2498 +		route_del(rtr->ifindex, RT6_TABLE_MIP6, 0,
     2499 +			  &in6addr_any, 0, &in6addr_any, 0, &rtr->lladdr);
     2500  	}
     2501  	list_for_each_safe(l, n, &rtr->prefixes) {
     2502  		struct prefix_list_entry *p;
     2503 @@ -231,8 +238,31 @@
     2504  	list_add_tail(&coa->list, &iface->expired_coas);
     2505  }
     2506  
     2507 +static void md_reset_egress_forward(void)
     2508 +{
     2509 +	struct list_head *l;
     2510 +	int forward = 0;;
     2511 +
     2512 +	if (list_empty(&ifaces))
     2513 +		return;
     2514 +
     2515 +	list_for_each(l, &ifaces) {
     2516 +		struct md_inet6_iface *i;
     2517 +		i = list_entry(l, struct md_inet6_iface, list);
     2518 +		forward |= i->home_link;
     2519 +	}
     2520 +	list_for_each(l, &ifaces) {
     2521 +		struct md_inet6_iface *i;
     2522 +		i = list_entry(l, struct md_inet6_iface, list);
     2523 +		set_iface_proc_entry(PROC_SYS_IP6_FORWARDING,
     2524 +				     i->name, forward);
     2525 +	}
     2526 +}
     2527 +
     2528  static void md_reset_home_link(struct md_inet6_iface *i)
     2529  {
     2530 +	if (i->home_link)
     2531 +		md_reset_egress_forward();
     2532  	i->home_link = 0;
     2533  	i->ll_dad_unsafe = 0;
     2534  }
     2535 @@ -648,6 +678,8 @@
     2536  
     2537  static void iface_proc_entries_init(struct md_inet6_iface *iface)
     2538  {
     2539 +	set_iface_proc_entry(PROC_SYS_IP6_FORWARDING, iface->name,
     2540 +			     conf_forwarding);
     2541  	set_iface_proc_entry(PROC_SYS_IP6_AUTOCONF, iface->name,
     2542  			     conf_autoconf);
     2543  	set_iface_proc_entry(PROC_SYS_IP6_ACCEPT_RA_DEFRTR, iface->name, conf_ra_defrtr);
     2544 @@ -878,6 +910,8 @@
     2545  			ll_dad_unsafe |= hai->lladdr_comp;
     2546  		}
     2547  	}
     2548 +	if (i->home_link != home_link)
     2549 +		md_reset_egress_forward();
     2550  	i->home_link = home_link;
     2551  	i->ll_dad_unsafe = ll_dad_unsafe;
     2552  }
     2553 @@ -1189,6 +1223,11 @@
     2554  		  RTF_DEFAULT|RTF_ADDRCONF, 1024,
     2555  		  &in6addr_any, 0, &in6addr_any, 0, &rtr->lladdr);
     2556  	
     2557 +	/* default route for the packet coming from the Mobile Network */
     2558 +	route_add(rtr->ifindex, RT6_TABLE_MIP6, RTPROT_MIP,
     2559 +		  0, IP6_RT_PRIO_MIP6_FWD,
     2560 +		  &in6addr_any, 0, &in6addr_any, 0, &rtr->lladdr);
     2561 +
     2562  	list_for_each(list, &rtr->prefixes) {
     2563  		struct prefix_list_entry *p;
     2564  		p = list_entry(list, struct prefix_list_entry, list);
     2565 @@ -1737,6 +1776,8 @@
     2566  
     2567  static void iface_proc_entries_cleanup(struct md_inet6_iface *iface)
     2568  {
     2569 +	set_iface_proc_entry(PROC_SYS_IP6_FORWARDING, iface->name,
     2570 +			     iface->devconf[DEVCONF_FORWARDING]);
     2571  	set_iface_proc_entry(PROC_SYS_IP6_AUTOCONF, iface->name,
     2572  			     iface->devconf[DEVCONF_AUTOCONF]);
     2573  	set_iface_proc_entry(PROC_SYS_IP6_ACCEPT_RA_DEFRTR, iface->name,
     2574 diff -r c04f74757df5 src/ndisc.c
     2575 --- a/src/ndisc.c	Sun Nov 30 23:14:35 2008 +0100
     2576 +++ b/src/ndisc.c	Sun Nov 30 23:14:48 2008 +0100
     2577 @@ -106,7 +106,7 @@
     2578  {
     2579  	struct in6_addr lladdr;
     2580  	int err;
     2581 -	int nd_flags = 0;
     2582 +	int nd_flags = bu_flags&IP6_MH_BU_MR ? NTF_ROUTER : 0;
     2583  
     2584  	err = pneigh_add(ifindex, nd_flags, target);
     2585  
     2586 @@ -117,7 +117,9 @@
     2587  			pneigh_del(ifindex, target);
     2588  	}
     2589  	if (!err) {
     2590 -		uint32_t na_flags = ND_NA_FLAG_OVERRIDE;
     2591 +		uint32_t na_flags = (ND_NA_FLAG_OVERRIDE |
     2592 +				     nd_flags ? ND_NA_FLAG_ROUTER : 0);
     2593 +
     2594  		ndisc_send_na(ifindex, src, &in6addr_all_nodes_mc,
     2595  			      target, na_flags);
     2596  
     2597 diff -r c04f74757df5 src/policy.c
     2598 --- a/src/policy.c	Sun Nov 30 23:14:35 2008 +0100
     2599 +++ b/src/policy.c	Sun Nov 30 23:14:48 2008 +0100
     2600 @@ -107,6 +107,23 @@
     2601  	return 0;
     2602  }
     2603  
     2604 +static inline int
     2605 +policy_check_mob_net_prefix(const struct policy_bind_acl_entry *acl,
     2606 +			    const struct ip6_mh_binding_update *bu,
     2607 +			    const struct mh_options *opts)
     2608 +{
     2609 +	struct ip6_mh_opt_mob_net_prefix *op;
     2610 +	for (op = mh_opt(&bu->ip6mhbu_hdr, opts, IP6_MHOPT_MOB_NET_PRFX);
     2611 +	     op != NULL;
     2612 +	     op = mh_opt_next(&bu->ip6mhbu_hdr, opts, op)) {
     2613 +		if (!prefix_list_get(&acl->mob_net_prefixes,
     2614 +				     &op->ip6mnp_prefix,
     2615 +				     op->ip6mnp_prefix_len))
     2616 +			return IP6_MH_BAS_NOT_AUTH_FOR_PRFX;
     2617 +	}
     2618 +	return IP6_MH_BAS_ACCEPTED;
     2619 +}
     2620 +
     2621  /**
     2622   * default_discard_binding - check for discard policy
     2623   * @remote_hoa: remote MN's home address
     2624 @@ -127,10 +144,20 @@
     2625  	int ret = def_bind_policy;
     2626  	struct policy_bind_acl_entry *acl;
     2627  
     2628 +	if (bu->ip6mhbu_flags & IP6_MH_BU_MR && !conf.HaAcceptMobRtr)
     2629 +		return IP6_MH_BAS_MR_OP_NOT_PERMITTED;
     2630 +
     2631  	pthread_rwlock_rdlock(&policy_lock);
     2632  	acl = hash_get(&policy_bind_acl_hash, NULL, remote_hoa);
     2633  	if (acl != NULL) {
     2634  		ret = acl->bind_policy;
     2635 +		if (ret < IP6_MH_BAS_UNSPECIFIED &&
     2636 +		    bu->ip6mhbu_flags & IP6_MH_BU_MR) {
     2637 +			struct mh_options opts;
     2638 +			mh_opt_parse(&bu->ip6mhbu_hdr, len,
     2639 +				     sizeof(*bu), &opts);
     2640 +			ret = policy_check_mob_net_prefix(acl, bu, &opts);
     2641 +		}
     2642  	}
     2643  	pthread_rwlock_unlock(&policy_lock);
     2644  	return ret;
     2645 @@ -227,6 +254,42 @@
     2646  	return 0;
     2647  }
     2648  
     2649 +int default_get_mnp_count(const struct in6_addr *hoa)
     2650 +{
     2651 +	int ret = 0;
     2652 +	struct policy_bind_acl_entry *acl;
     2653 +	pthread_rwlock_rdlock(&policy_lock);
     2654 +	acl = hash_get(&policy_bind_acl_hash, NULL, hoa);
     2655 +	if (acl != NULL)
     2656 +		ret = acl->mnp_count;
     2657 +	pthread_rwlock_unlock(&policy_lock);
     2658 +	return ret;
     2659 +
     2660 +}
     2661 +
     2662 +int default_get_mnps(const struct in6_addr *hoa,
     2663 +		     const int mnp_count,
     2664 +		     struct nd_opt_prefix_info *mnps)
     2665 +{
     2666 +	int i = 0;
     2667 +	struct policy_bind_acl_entry *acl;
     2668 +
     2669 +	pthread_rwlock_rdlock(&policy_lock);
     2670 +	acl = hash_get(&policy_bind_acl_hash, NULL, hoa);
     2671 +	if (acl != NULL) {
     2672 +		struct list_head *l;
     2673 +		list_for_each(l, &acl->mob_net_prefixes) {
     2674 +			struct prefix_list_entry *e;
     2675 +			if (i >= mnp_count)
     2676 +				break;
     2677 +			e = list_entry(l, struct prefix_list_entry, list);
     2678 +			mnps[i++] = e->pinfo;
     2679 +		}
     2680 +	}
     2681 +	pthread_rwlock_unlock(&policy_lock);
     2682 +	return i;
     2683 +}
     2684 +
     2685  static int policy_bind_acle_cleanup(void *data, void *arg)
     2686  {
     2687  	struct policy_bind_acl_entry *acl = data;
     2688 diff -r c04f74757df5 src/policy.h
     2689 --- a/src/policy.h	Sun Nov 30 23:14:35 2008 +0100
     2690 +++ b/src/policy.h	Sun Nov 30 23:14:48 2008 +0100
     2691 @@ -10,12 +10,15 @@
     2692  
     2693  struct ip6_mh_binding_update;
     2694  struct nd_router_advert;
     2695 +struct nd_opt_prefix_info;
     2696  
     2697  struct policy_bind_acl_entry {
     2698  	struct list_head list;
     2699  	struct in6_addr hoa;
     2700  	int plen;
     2701  	int bind_policy;
     2702 +	int mnp_count;
     2703 +	struct list_head mob_net_prefixes;
     2704  };
     2705  
     2706  /**
     2707 @@ -147,6 +150,12 @@
     2708  			const struct in6_addr *cn,
     2709  			struct in6_addr *coa);
     2710  
     2711 +int default_get_mnp_count(const struct in6_addr *hoa);
     2712 +
     2713 +int default_get_mnps(const struct in6_addr *hoa,
     2714 +		     const int mnp_count,
     2715 +		     struct nd_opt_prefix_info *mnps);
     2716 +
     2717  void policy_cleanup(void);
     2718  
     2719  int policy_init(void);
     2720 diff -r c04f74757df5 src/proc_sys.h
     2721 --- a/src/proc_sys.h	Sun Nov 30 23:14:35 2008 +0100
     2722 +++ b/src/proc_sys.h	Sun Nov 30 23:14:48 2008 +0100
     2723 @@ -14,6 +14,7 @@
     2724  #define PROC_SYS_IP6_APP_SOLICIT "/proc/sys/net/ipv6/neigh/%s/app_solicit"
     2725  #define PROC_SYS_IP6_BASEREACHTIME_MS "/proc/sys/net/ipv6/neigh/%s/base_reachable_time_ms"
     2726  #define PROC_SYS_IP6_RETRANSTIMER_MS "/proc/sys/net/ipv6/neigh/%s/retrans_time_ms"
     2727 +#define PROC_SYS_IP6_FORWARDING "/proc/sys/net/ipv6/conf/%s/forwarding"
     2728  
     2729  int set_iface_proc_entry(const char *tmpl, const char *if_name, int val);
     2730  
     2731 diff -r c04f74757df5 src/rtnl.h
     2732 --- a/src/rtnl.h	Sun Nov 30 23:14:35 2008 +0100
     2733 +++ b/src/rtnl.h	Sun Nov 30 23:14:48 2008 +0100
     2734 @@ -16,6 +16,7 @@
     2735  #define IP6_RT_PRIO_MIP6_FWD 192
     2736  #define IP6_RT_PRIO_ADDRCONF 256
     2737  
     2738 +#define IP6_RULE_PRIO_MIP6_MNP_IN    1000
     2739  #define IP6_RULE_PRIO_MIP6_HOA_OUT   1001
     2740  #define IP6_RULE_PRIO_MIP6_COA_OUT   1002
     2741  #define IP6_RULE_PRIO_MIP6_BLOCK     1003
     2742 diff -r c04f74757df5 src/scan.l
     2743 --- a/src/scan.l	Sun Nov 30 23:14:35 2008 +0100
     2744 +++ b/src/scan.l	Sun Nov 30 23:14:48 2008 +0100
     2745 @@ -136,6 +136,11 @@
     2746  MnRouterProbeTimeout		{ return MNROUTERPROBETIMEOUT; }
     2747  MnDiscardHaParamProb		{ return MNDISCARDHAPARAMPROB; }
     2748  OptimisticHandoff		{ return OPTIMISTICHANDOFF; }
     2749 +HaAcceptMobRtr   		{ return HAACCEPTMOBRTR; }
     2750 +IsMobRtr       			{ return ISMOBRTR; }
     2751 +HaServedPrefix       	       	{ return HASERVEDPREFIX; }
     2752 +HomePrefix     			{ return HOMEPREFIX; }
     2753 +MobRtrUseExplicitMode    	{ return MOBRTRUSEEXPLICITMODE; }
     2754  internal			{ return INTERNAL; }
     2755  
     2756  {addr}		{
     2757 diff -r c04f74757df5 src/vt.c
     2758 --- a/src/vt.c	Sun Nov 30 23:14:35 2008 +0100
     2759 +++ b/src/vt.c	Sun Nov 30 23:14:48 2008 +0100
     2760 @@ -678,6 +678,17 @@
     2761  
     2762  	fprintf(vh->vh_stream, "\n");
     2763  
     2764 +	/* Dump the registered MNP */
     2765 +	{
     2766 +		struct list_head *l;
     2767 +		list_for_each(l, &bce->mob_net_prefixes) {
     2768 +			struct prefix_list_entry *p;
     2769 +			p = list_entry(l, struct prefix_list_entry, list);
     2770 +			fprintf(vh->vh_stream, " MNP: %x:%x:%x:%x:%x:%x:%x:%x/%d\n", 
     2771 +                    NIP6ADDR(&p->ple_prefix), p->ple_plen);
     2772 +		}
     2773 +	}
     2774 +
     2775  	return 0;
     2776  }
     2777  
     2778 diff -r c04f74757df5 src/xfrm.c
     2779 --- a/src/xfrm.c	Sun Nov 30 23:14:35 2008 +0100
     2780 +++ b/src/xfrm.c	Sun Nov 30 23:14:48 2008 +0100
     2781 @@ -257,6 +257,30 @@
     2782  		sel->prefixlen_s = 128;
     2783  }
     2784  
     2785 +/* NEMO specific version of set_selector(): set xfrm_selector
     2786 + * fields for IPsec policies and states. If NULL is passed as
     2787 + * src or dst prefix, any is used, i.e. ::/0 */
     2788 +static void mr_set_selector(const struct prefix_list_entry *src,
     2789 +			    const struct prefix_list_entry *dst,
     2790 +			    uid_t uid, struct xfrm_selector *sel)
     2791 +{
     2792 +	memset(sel, 0, sizeof(*sel));
     2793 +	sel->family = AF_INET6;
     2794 +	sel->user = uid;
     2795 +
     2796 +	if (src != NULL) {
     2797 +		memcpy(&sel->saddr.a6, &src->ple_prefix,
     2798 +		       sizeof(sel->saddr.a6));
     2799 +		sel->prefixlen_s = src->ple_plen;
     2800 +	}
     2801 +
     2802 +	if (dst != NULL) {
     2803 +		memcpy(&sel->daddr.a6, &dst->ple_prefix,
     2804 +		       sizeof(sel->daddr.a6));
     2805 +		sel->prefixlen_d = dst->ple_plen;
     2806 +	}
     2807 +}
     2808 +
     2809  /** 
     2810   * xfrm_last_used - when was a binding  last used
     2811   * @daddr: destination address (home address)
     2812 @@ -679,6 +703,56 @@
     2813  	return err;
     2814  }
     2815  
     2816 +static int mr_ipsec_bypass_init(void)
     2817 +{
     2818 +	struct list_head *home;
     2819 +	struct list_head *mnps;
     2820 +	int err=0;
     2821 +
     2822 +	/* Loop for each HomeAddress info */
     2823 +	list_for_each(home, &conf.home_addrs)
     2824 +	{
     2825 +		struct home_addr_info *hai;
     2826 +		hai = list_entry(home, struct home_addr_info, list);
     2827 +
     2828 +		/* If Mobile Router for this link, loop for each MNP */
     2829 +		if (hai->mob_rtr)
     2830 +		{
     2831 +			/* Add bypass policies to and from the MNP link */
     2832 +			list_for_each(mnps, &hai->mob_net_prefixes)
     2833 +			{
     2834 +				struct prefix_list_entry * mnp;
     2835 +				struct xfrm_selector sel;
     2836 +				uid_t uid = getuid();
     2837 +
     2838 +				mnp = list_entry(mnps, struct prefix_list_entry, list);
     2839 +
     2840 +				/* IN, src = MNP , dst = any */
     2841 +				mr_set_selector(mnp, NULL, uid, &sel);
     2842 +				err = xfrm_ipsec_policy_add(&sel, 0, XFRM_POLICY_IN,
     2843 +                                XFRM_POLICY_ALLOW,
     2844 +							    MIP6_PRIO_MR_LOCAL_DATA_BYPASS,
     2845 +							    NULL, 0);
     2846 +
     2847 +				/* FWD, src = MNP , dst = any */
     2848 +				err = xfrm_ipsec_policy_add(&sel, 0, XFRM_POLICY_FWD,
     2849 +                                XFRM_POLICY_ALLOW,
     2850 +							    MIP6_PRIO_MR_LOCAL_DATA_BYPASS,
     2851 +							    NULL, 0);
     2852 +
     2853 +				/* OUT, src = any , dst = MNP */
     2854 +				mr_set_selector(NULL, mnp, uid, &sel);
     2855 +				err = xfrm_ipsec_policy_add(&sel, 0, XFRM_POLICY_OUT,
     2856 +                                XFRM_POLICY_ALLOW,
     2857 +							    MIP6_PRIO_MR_LOCAL_DATA_BYPASS,
     2858 +							    NULL, 0);
     2859 +			}
     2860 +		}
     2861 +	}
     2862 +
     2863 +	return err;
     2864 +}
     2865 +
     2866  static inline int mn_ha_ipsec_init(void)
     2867  {
     2868  	int err;
     2869 @@ -686,6 +760,9 @@
     2870  	/* insert bypass policy */
     2871  	err = ipsec_policy_walk(_mn_ha_ipsec_bypass_init, NULL);
     2872  
     2873 +	/* insert NEMO-related bypass */
     2874 +	err = mr_ipsec_bypass_init();
     2875 +
     2876  	err = ipsec_policy_walk(_mn_ha_ipsec_init, NULL);
     2877  
     2878  	return err;
     2879 @@ -787,10 +864,54 @@
     2880  	return err;
     2881  }
     2882  
     2883 +static int mr_ipsec_bypass_cleanup(void)
     2884 +{
     2885 +	struct list_head *home;
     2886 +	struct list_head *mnps;
     2887 +	int err=0;
     2888 +
     2889 +	/* Loop for each HomeAddress info */
     2890 +	list_for_each(home, &conf.home_addrs)
     2891 +	{
     2892 +		struct home_addr_info *hai;
     2893 +		hai = list_entry(home, struct home_addr_info, list);
     2894 +
     2895 +		/* If Mobile Router for this link, loop for each MNP */
     2896 +		if (hai->mob_rtr)
     2897 +		{
     2898 +			/* Delete bypass policies to and from the MNP link */
     2899 +			list_for_each(mnps, &hai->mob_net_prefixes)
     2900 +			{
     2901 +				struct prefix_list_entry * mnp;
     2902 +				struct xfrm_selector sel;
     2903 +				uid_t uid = getuid();
     2904 +
     2905 +				mnp = list_entry(mnps, struct prefix_list_entry, list);
     2906 +
     2907 +				/* IN, src = MNP , dst = any */
     2908 +				mr_set_selector(mnp, NULL, uid, &sel);
     2909 +				err = xfrm_ipsec_policy_del(&sel, XFRM_POLICY_IN);
     2910 +
     2911 +				/* FWD, src = MNP , dst = any */
     2912 +				err = xfrm_ipsec_policy_del(&sel, XFRM_POLICY_FWD);
     2913 +
     2914 +				/* OUT, src = any , dst = MNP */
     2915 +				mr_set_selector(NULL, mnp, uid, &sel);
     2916 +				err = xfrm_ipsec_policy_del(&sel, XFRM_POLICY_OUT);
     2917 +			}
     2918 +		}
     2919 +	}
     2920 +
     2921 +	return err;
     2922 +}
     2923 +
     2924 +
     2925  static inline void mn_ha_ipsec_cleanup(void)
     2926  {
     2927  	ipsec_policy_walk(_mn_ha_ipsec_bypass_cleanup, NULL);
     2928  
     2929 +	(void)mr_ipsec_bypass_cleanup();
     2930 +
     2931  	ipsec_policy_walk(_mn_ha_ipsec_cleanup, NULL);
     2932  }
     2933  
     2934 @@ -1719,6 +1840,8 @@
     2935  		if (hai->home_block & HOME_LINK_BLOCK)
     2936  			xfrm_unblock_link(hai);
     2937  		xfrm_block_link(hai);
     2938 +		if (hai->mob_rtr && !(hai->home_block & NEMO_FWD_BLOCK))
     2939 +			xfrm_block_fwd(hai);
     2940  	}
     2941  	if (IN6_ARE_ADDR_EQUAL(&bule->hoa, &bule->coa)) {
     2942  		if (rdata)
     2943 @@ -1784,6 +1907,8 @@
     2944  		struct home_addr_info *hai = bule->home;
     2945  		if (hai->home_block & HOME_LINK_BLOCK)
     2946  			xfrm_unblock_link(hai);
     2947 +		if (hai->home_block & NEMO_FWD_BLOCK)
     2948 +			xfrm_unblock_fwd(hai);
     2949  	}
     2950  	/* check if XFRM policies and states have already been cleaned up */
     2951  	if (IN6_ARE_ADDR_EQUAL(&bule->hoa, &bule->coa))
     2952 @@ -2058,6 +2183,50 @@
     2953  	hai->home_block &= ~HOME_ADDR_BLOCK;
     2954  }
     2955  
     2956 +/* block all RA messages sent by MR */
     2957 +int xfrm_block_ra(struct home_addr_info *hai)
     2958 +{
     2959 +	int ret = 0;
     2960 +	struct xfrm_selector sel;
     2961 +	hai->home_block |= NEMO_RA_BLOCK;
     2962 +	set_selector(&in6addr_any, &in6addr_any, IPPROTO_ICMPV6,
     2963 +		     ND_ROUTER_ADVERT, 0, 0, &sel);
     2964 +	if ((ret = xfrm_mip_policy_add(&sel, 0, XFRM_POLICY_OUT, XFRM_POLICY_BLOCK,
     2965 +				   MIP6_PRIO_HOME_BLOCK, NULL, 0)))
     2966 +		return ret;
     2967 +	return ret;
     2968 +}
     2969 +
     2970 +void xfrm_unblock_ra(struct home_addr_info *hai)
     2971 +{
     2972 +	struct xfrm_selector sel;
     2973 +	set_selector(&in6addr_any, &in6addr_any, IPPROTO_ICMPV6,
     2974 +		     ND_ROUTER_ADVERT, 0, 0, &sel);
     2975 +	xfrm_mip_policy_del(&sel, XFRM_POLICY_OUT);
     2976 +	hai->home_block &= ~NEMO_RA_BLOCK;
     2977 +}
     2978 +
     2979 +/* block all forwarded packets */
     2980 +int xfrm_block_fwd(struct home_addr_info *hai)
     2981 +{
     2982 +	int ret = 0;
     2983 +	struct xfrm_selector sel;
     2984 +	hai->home_block |= NEMO_FWD_BLOCK;
     2985 +	set_selector(&in6addr_any, &in6addr_any, 0, 0, 0, 0, &sel);
     2986 +	if ((ret = xfrm_mip_policy_add(&sel, 0, XFRM_POLICY_FWD, XFRM_POLICY_BLOCK,
     2987 +				   MIP6_PRIO_HOME_BLOCK, NULL, 0)))
     2988 +		return ret;
     2989 +	return ret;
     2990 +}
     2991 +
     2992 +void xfrm_unblock_fwd(struct home_addr_info *hai)
     2993 +{
     2994 +	struct xfrm_selector sel;
     2995 +	set_selector(&in6addr_any, &in6addr_any, 0, 0, 0, 0, &sel);
     2996 +	xfrm_mip_policy_del(&sel, XFRM_POLICY_FWD);
     2997 +	hai->home_block &= ~NEMO_FWD_BLOCK;
     2998 +}
     2999 +
     3000  int mn_ipsec_recv_bu_tnl_pol_add(struct bulentry *bule, int ifindex, 
     3001  				 struct ipsec_policy_entry *e)
     3002  {
     3003 diff -r c04f74757df5 src/xfrm.h
     3004 --- a/src/xfrm.h	Sun Nov 30 23:14:35 2008 +0100
     3005 +++ b/src/xfrm.h	Sun Nov 30 23:14:48 2008 +0100
     3006 @@ -15,6 +15,7 @@
     3007  #define MIP6_PRIO_RO_SIG_IPSEC		7	/* XXX: BU between MN-MN with IPsec */
     3008  #define MIP6_PRIO_RO_SIG		8	/* XXX: BU between MN-CN */
     3009  #define MIP6_PRIO_RO_SIG_ANY		9
     3010 +#define MIP6_PRIO_MR_LOCAL_DATA_BYPASS	9	/* Bypass rule for local traffic in mobile network */
     3011  #define MIP6_PRIO_RO_SIG_RR		10	/* XXX: MH(or HoTI/HoT) between MN-CN */
     3012  #define MIP6_PRIO_RO_BLOCK		11
     3013  #define MIP6_PRIO_NO_RO_SIG_ANY		12
     3014 @@ -87,6 +88,12 @@
     3015  int xfrm_block_hoa(struct home_addr_info *hai);
     3016  void xfrm_unblock_hoa(struct home_addr_info *hai);
     3017  
     3018 +int xfrm_block_ra(struct home_addr_info *hai);
     3019 +void xfrm_unblock_ra(struct home_addr_info *hai);
     3020 +
     3021 +int xfrm_block_fwd(struct home_addr_info *hai);
     3022 +void xfrm_unblock_fwd(struct home_addr_info *hai);
     3023 +
     3024  int ha_mn_ipsec_pol_mod(struct in6_addr *haaddr,
     3025  			struct in6_addr *hoa);
     3026