Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Evergreen:11.2
mipv6d
mipv6-daemon-umip-0.4-nepl-20080108.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
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);
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor