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