diff -Nur mipv6-daemon-umip-0.3-nepl/include/netinet/ip6mh.h mipv6-daemon-umip-0.3-nepl-mcoa/include/netinet/ip6mh.h
--- mipv6-daemon-umip-0.3-nepl/include/netinet/ip6mh.h 2007-06-13 10:36:09.000000000 +0200
+++ mipv6-daemon-umip-0.3-nepl-mcoa/include/netinet/ip6mh.h 2007-06-13 16:11:09.000000000 +0200
@@ -146,6 +146,25 @@
} __attribute__ ((packed));
/*
+ * MCoA registration
+ * Binding Unique Identifier sub-option
+ */
+struct ip6_mh_opt_bid {
+ uint8_t ip6mobid_type;
+ uint8_t ip6mobid_len;
+ uint16_t ip6mobid_bid;
+ uint8_t ip6mobid_priority;
+ uint8_t ip6mobid_reserved;
+} __attribute__((packed));
+
+/* Binding Unique Identifier sub-option flags */
+#if BYTE_ORDER == BIG_ENDIAN
+#define IP6_OPT_BID_BULK 0x80 /* Bulk Registration */
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+#define IP6_OPT_BID_BULK 0x80 /* Bulk Registration */
+#endif
+
+/*
* Mobility Header Message Types
*/
#define IP6_MH_TYPE_BRR 0 /* Binding Refresh Request */
@@ -167,6 +186,7 @@
#define IP6_MHOPT_NONCEID 0x04 /* Nonce Index */
#define IP6_MHOPT_BAUTH 0x05 /* Binding Auth Data */
#define IP6_MHOPT_MOB_NET_PRFX 0x06 /* Mobile Network Prefix */
+#define IP6_MHOPT_BID 0x07 /* Binding Unique Identifier */
/*
* Status values accompanied with Mobility Binding Acknowledgement
@@ -191,6 +211,9 @@
#define IP6_MH_BAS_INVAL_PRFX 141 /* Invalid Prefix */
#define IP6_MH_BAS_NOT_AUTH_FOR_PRFX 142 /* Not Authorized for Prefix */
#define IP6_MH_BAS_FWDING_FAILED 143 /* Forwarding Setup failed */
+#define IP6_MH_BAS_CONFLICT_BINDING 144 /* (TBD) MCoA Conflict between bindings */
+#define IP6_MH_BAS_MCOA_BULK_FAILED 145 /* (TBD) MCoA Bulk registration failed */
+
/*
* Status values for the Binding Error mobility messages
*/
diff -Nur mipv6-daemon-umip-0.3-nepl/man/mip6d.conf.tmpl mipv6-daemon-umip-0.3-nepl-mcoa/man/mip6d.conf.tmpl
--- mipv6-daemon-umip-0.3-nepl/man/mip6d.conf.tmpl 2007-06-13 10:36:38.000000000 +0200
+++ mipv6-daemon-umip-0.3-nepl-mcoa/man/mip6d.conf.tmpl 2007-06-13 16:11:09.000000000 +0200
@@ -57,6 +57,9 @@
.BR "Interface " "name" " {"
.BR " MnIfPreference " "number" ";"
.BR " IfType " "CN | HA | MN" ";"
+.BR " Bid " "number" ";"
+.BR " BidPriority " "number" ";"
+.BR " Reliable " "boolean" ";"
.B }
.fi
@@ -74,9 +77,10 @@
sets the interface preference value for an interface in a multi-homed
Mobile Node. The most preferred intefaces have preference 1, the
second most preferred have 2, etc. A preference of zero means the
-interface will not be used.
+interface will not be used. Do not use this option if you use the Multiple
+Care-of Address registration on your Mobile Node with this interface.
-Default: 5
+Default: 0
.B IfType
overrides the default node behavior for this interface. If a MN doesn't
@@ -86,6 +90,43 @@
Default: same as
.B NodeConfig
+.B Bid
+Sets the BID for this interface. The BID must be unique within all
+interface definitions. This BID will be used as an Interface Identifier
+that the user can use for policy routing. If this option is defined,
+also set the
+.B BidPriority
+option, and do not set the
+.B MnIfPreference
+option.
+.B Bid
+must be set between 1 and 251 (this is one of the current limitation
+with this MCoA implementation).
+
+Default: 0 (no BID)
+
+.B BidPriority
+Sets the priority of the binding (the higher the better). When no
+policies are define for some flows, the binding with the higher
+preference is used. If this option is defined, do not set the
+.B MnIfPreference
+option for this interface.
+.B BidPriority
+must be set between 1 and 255.
+
+Default: 0
+
+.B Reliable
+allows you to specify if the interface can be considered as reliable
+when using MCoA. If set to false, the traffic will be redirected to
+another interface during the BU-BAck exchange. You can thus use the
+BU as a heartbeat (by specifying a small
+.B MnMaxHaBindingLife
+), which can be pretty useful when one of your MR-HA path is not
+reliable: traffic is redirected to the interface with the best
+priority as long as no BAck is received.
+
+Default: true
.TP
.BR "UseMnHaIPsec " "boolean" ";"
@@ -191,6 +232,13 @@
Default: disabled;
.TP
+.BR "HaAcceptMCoAReg enabled | disabled"
+
+Indicates if the HA accepts Multiple Care-of Addresses registration.
+
+Default: disabled;
+
+.TP
.BR "HaServedPrefix " "prefix/length" ";"
Prefix is an IPv6 prefix and length is the prefix length. Defines the whole
@@ -199,7 +247,7 @@
Mobile Network Prefixes, instead of one of the home link prefixes.
.TP
-.BR "BindingAclPolicy " "address MNP list " "allow | deny"
+.BR "BindingAclPolicy " "address MNP list " "MCoAReg | NoMCoAReg " "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
@@ -207,6 +255,12 @@
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)"
+The HA can forbid or allow the MN to register Multiple Care-of Addresses by
+setting the
+.B NoMCoAReg
+or
+.B MCoAReg
+flag.
.TP
.BR "DefaultBindingAclPolicy allow | deny"
@@ -368,6 +422,31 @@
Default: disabled
.TP
+.BR "RegMultipleCoA enabled | disabled"
+
+Defines if the Mobile Node should try to register Multiple Care-of
+Addresses to its Home Agent. If enabled, use also the
+.B IfMultipleCoA
+option. If disabled, the node will only register one CoA at a time.
+
+Default: disabled;
+
+.TP
+.BR "IfMultipleCoA " "name1, name2, ..." ";"
+
+Defines the list of interfaces that will be used for Multiple Care-of
+Addresses registration. This list must be composed with the names
+(enclosed in double quotes) of the interfaces (eg. "eth1"), separated
+with a coma. Each interface listed must have an
+.B Interface
+definition properly filled with the Multiple Care-of Address options
+(
+.B Bid
+and
+.B BidPriority
+).
+
+.TP
The route optimization policies are of the form:
.TP
@@ -389,7 +468,7 @@
.SH EXAMPLES
.TP
-.BR "A NEMO Home Agent example:"
+.BR "A NEMO Home Agent example with MCoA support:"
.nf
NodeConfig HA;
@@ -397,18 +476,19 @@
Interface "eth0";
HaAcceptMobRtr enabled;
+HaAcceptMCoAReg 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::1234 (3ffe:2620:6:2::/64, 3ffe:2620:6:3::/64) MCoAReg allow;
BindingAclPolicy 3ffe:2620:6:1::1235 allow;
UseMnHaIPsec disabled;
.fi
.TP
-.BR "A NEMO Mobile Router example:"
+.BR "A NEMO Mobile Router example with MCoA support:"
.nf
NodeConfig MN;
@@ -416,7 +496,15 @@
DoRouteOptimizationCN disabled;
DoRouteOptimizationMN disabled;
-Interface "eth0";
+Interface "eth0" {
+ Bid 111;
+ BidPriority 10;
+};
+
+Interface "eth1" {
+ Bid 222;
+ BidPriority 5;
+};
MnRouterProbes 1;
@@ -426,6 +514,8 @@
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);
+ RegMultipleCoA enabled;
+ IfMultipleCoA "eth0", "eth1";
}
UseMnHaIPsec disabled;
diff -Nur mipv6-daemon-umip-0.3-nepl/NEWS.MCOA mipv6-daemon-umip-0.3-nepl-mcoa/NEWS.MCOA
--- mipv6-daemon-umip-0.3-nepl/NEWS.MCOA 1970-01-01 01:00:00.000000000 +0100
+++ mipv6-daemon-umip-0.3-nepl-mcoa/NEWS.MCOA 2007-06-15 12:02:43.000000000 +0200
@@ -0,0 +1,86 @@
+mipv6-daemon-umip-0.3-nepl-mcoa-20070613.patch
+News and Bugfixes list since nemo-0.2-mcoa-beta2-20060630:
+
+* Ported the code to UMIP. MCoA now runs on a 2.6.21.3 kernel,
+ with an UMIP-based code for the userland.
+* MCoA is now provided as a patch for the UMIP userland.
+* The MCoA kernel patch is not needed anymore as it has been
+ integrated in the mainline kernel.
+* No new functionnalities were added.
+
+-----------------------------------------------------------------------
+nemo-0.2-mcoa-beta3-20070118
+News and Bugfixes list since nemo-0.2-mcoa-beta2-20060630:
+
+* Base code:
+- Userland runs on a 2.6.16 kernel
+- Upgraded fwmark patch for 2.6.16 kernel
+- MCoA userland code updated to nemo-20060725
+
+* Features:
+- New "Reliable" option that allows to use the BU as a
+ heartbeat, and to automatically divert the traffic to
+ another interface when one MR-HA path fails.
+ See the manpage for details.
+- MPS/MPA can now be used with MCoA.
+- When handover occurs on an interface, forwarded traffic is now
+ blocked only for the interface performing the handover (whereas
+ it was blocked globally before). The local traffic is also
+ blocked for the interface that performs the handover, whereas
+ it was blocked for the HoA interface before.
+- Merged patch to support HoA from MNP (for Mobile Routers)
+- Merged patch to support SIT tunnels
+- Merged patch to fix the MR behaviour in the Home Network
+ (the MR was not correctly forwarding packets from the MNNs)
+
+* Bugfixes:
+- The source address used to send the BU was sometimes outdated
+ because the CoA was not correctly updated in the XFRM kernel
+ state.
+- When packets originated from the MR were sent to the HA, the
+ HA did not behave correctly because the source address of the
+ packet may not match the one in the kernel XFRM state (that
+ can only store one CoA). Thus the MR behaviour has been
+ slightly changed to NOT use HAO dest. option when sending
+ packet to the HA (This behaviour seems to respect the MIP6
+ spec).
+- When packets originated from the MR were sent to the HA, and
+ the MR handoffs, the HA still sent replied packets to the
+ old CoA (using Routing Header Type 2). The HA now updates
+ correctly the CoA stored in the kernel, but as the kernel
+ can only store 1 CoA at a time, when the HA replies to the
+ MR the path may be asymetric.
+- Added more checks in the configuration file grammar to
+ avoid configuration errors for MCoA.
+- Solved infinite loop when interface was declared as Interface
+ but not in IfMultipleCoA.
+- Fixed some bugs when MCoA was disabled. It now works fine when
+ not using MCoA. Interface prefence works also fine.
+- Fixed bugs when one entry was invalidated: rules are now
+ correctly deleted.
+- Fixed bugs when choosing the default rule: invalid BULE are
+ not looked up when searching for the default rule.
+- Improved the MR and HA behaviour regarding error management.
+
+
+-----------------------------------------------------------------------
+nemo-0.2-mcoa-beta2-20060630
+News and Bugfixes list since nemo-0.2-mcoa-beta1-20060531:
+
+- The MR was in some cases installing the same rules twice.
+- The MR had a problem to install some rules after recovering a failure.
+- The MR was stuck in an infinite loop at startup if MCoA was disabled
+- The MR could not clean properly tunnels if registration failed with HA
+- Policy issues when Returning home with a usual MR but using MCoA code
+- When the MR only have 1 active interface, handoff policy is different
+ (rules not erased and dereg bu not send during handoff time)
+- When the MR receives a BAck without BID option, whereas it sent a BU
+ with a BID option, the MR only registers the prefered interface
+
+- If HA is not configured for MCoA, or MCoA not allowed for the HoA, then
+ BU is accepted but no BID option is sent in BAck
+
+- Merged the OptimisticHandoff patch
+- Merged the PPP patch
+
+-----------------------------------------------------------------------
diff -Nur mipv6-daemon-umip-0.3-nepl/README.MCOA mipv6-daemon-umip-0.3-nepl-mcoa/README.MCOA
--- mipv6-daemon-umip-0.3-nepl/README.MCOA 1970-01-01 01:00:00.000000000 +0100
+++ mipv6-daemon-umip-0.3-nepl-mcoa/README.MCOA 2007-06-15 12:09:01.000000000 +0200
@@ -0,0 +1,154 @@
+--------------------------------------------
+Multiple CoA implementation on UMIP
+
+ver. 20070613
+--------------------------------------------
+Romain KUNTZ
+Jean LORCHAT
+Nautilus6 Project
+--------------------------------------------
+
+
+1. What is Multiple CoA?
+------------------------
+
+Multiple CoA (Multiple Care-of Addresses Registration, MCoA) allows
+a Mobile Node to register multiple Care-of Addresses at the same
+time to its Home Agent. Main benefits, amongst others, are policy
+routing and fault tolerance for the Mobile Router.
+
+The current implementation is based on
+draft-ietf-monami6-multiplecoa-01 and is shipped as a tarball
+that contains kernel patches and the userland.
+
+This implementation is based on UMIP, a Mobility platform on Linux.
+More information about UMIP can be found on
+
+
+
+2. Limitations
+--------------
+
+Due to its early stage of development, the MCoA implementation still
+have some important limitations. Please read them carefully to
+understand what you cannot do with this implementation:
+
+- IPsec is not yet supported. It will in the future, but we now
+ concentrate on the non-IPsec part.
+
+- Returning home is not supported. Do not try to boot your MN at home
+ or to return home with one of its interface, this will not work.
+ This feature will be available in the future.
+
+- Once the MN has established multiple tunnels, the policy routing
+ only works FOR THE FORWARDED TRAFFIC. The traffic generated by the
+ MN itself will not be routed according to your policies. Only the
+ traffic from the MNN, routed via the Mobile Router, will be routed
+ according to the policies you installed on the MR. You can expect
+ some improvements in the next releases.
+
+- CN are not supported, ie the MN cannot register multiple CoA to
+ the CN.
+
+- The BID for each interface must be chosen between 1 and 251. This
+ limitation is due to the implementation design. We will try to
+ improve this point in the future.
+
+- This implementation does not support yet the Bulk Registration,
+ mainly because Bulk registration is still under discussion at
+ the IETF.
+
+
+3. Known Bugs
+-------------
+
+- Binding Refresh Request do not include the BID option
+- Binding Error do not include the BID option
+- The BU is sometimes sent via another interface than expected.
+- Certainly many others!
+
+4. Instructions
+---------------
+
+a. Testbed Setup
+----------------
+
+Testbed setup, kernel and userlan compilation, configuration
+files etc. are explained in the NEPL Howto available on:
+http://www.nautilus6.org/doc/nepl-howto/
+
+Please check this document (especially section 6) to setup
+your MCoA testbed.
+
+b. Policy Routing
+-----------------
+
+Once your MN has registered multiple CoA to your Home Agent, it can
+use its multiple MN-HA tunnel for policy routing.
+
+The policy routing part is managed with ip6tables. Be sure to install
+this tool on both your HA and MN.
+
+- How does it work?
+-------------------
+
+The BID that you assigned to each interface will be used to mark the
+packets. Packets marked with BID X will be routed through the
+interface whose BID is X. If this interface is not available (because
+it is down), then the packet will be routed through the most prefered
+interface (the one with the best BidPriority).
+
+NOTE:
+At the moment, ONLY PACKETS FORWARDED BY THE MR (ie packets sent by MNN)
+can benefit from the policy routing. Packets generated by the MR itself
+will not be routed according to your rules. We are currently working to
+improve the current situation to also allow the MR to benefit from the
+policy routing.
+
+
+- How to mark a packet?
+-----------------------
+
+Use the ip6tables tool and the MARK target to mark your packets with
+the BID. Ip6tables rules must be done in the PREROUTING chain, in the
+mangle table.
+
+For example, on the MN, to mark as 100 all icmpv6 packets whose
+destination is 2001:a:b::1000, you can do:
+
+ip6tables -A PREROUTING -t mangle
+ -p icmpv6 --destination 2001:a:b::1000
+ -j MARK --set-mark 100
+
+Those packets will be sent through the interface whose BID is 100.
+You will also need to create the "symetric" rule on the Home Agent:
+
+ip6tables -A PREROUTING -t mangle
+ -p icmpv6 --source 2001:a:b::1000
+ -j MARK --set-mark 100
+
+As you see, one current limitation is that each rules created on the
+MN must be also created on the Home Agent. We plan to support in the
+future some policy exchange mechanism between the MN and the HA in
+order to configure automatically the HA.
+
+Read carefully the ip6tables manpage. You will be able to create
+rules based on many parameters, and thus create a very subtle policy
+routing on your MN.
+
+
+5. Support
+----------
+
+The MCoA implementation is not supported by the UMIP team, so please
+do not complain on their Mailing List. If you have any questions
+regarding this work, or any BUG report, feel free to subscribe to
+our support and announce mailing lists:
+
+http://www.nautilus6.org/ml.php
+
+--------------------------------------------
+Romain KUNTZ
+Jean LORCHAT
+Nautilus6 Project
+--------------------------------------------
diff -Nur mipv6-daemon-umip-0.3-nepl/src/bcache.c mipv6-daemon-umip-0.3-nepl-mcoa/src/bcache.c
--- mipv6-daemon-umip-0.3-nepl/src/bcache.c 2007-06-13 10:36:38.000000000 +0200
+++ mipv6-daemon-umip-0.3-nepl-mcoa/src/bcache.c 2007-06-13 16:11:09.000000000 +0200
@@ -39,6 +39,7 @@
#include "mh.h"
#include "cn.h"
#include "vt.h"
+#include "prefix.h"
#define BCACHE_BUCKETS 32
@@ -48,6 +49,8 @@
pthread_rwlock_t bc_lock; /* Protects binding cache */
+int bce_next_entry(void *bce_v, void *next_bce_v);
+
/**
* get_bcache_count - returns number of home and cache entries
* @type: HOMEREGENTRY, CACHEENTRY or ANY
@@ -88,6 +91,12 @@
fprintf(out, " lifetime %ld\n ", e->lifetime.tv_sec);
fprintf(out, " seqno %d\n", e->seqno);
+ if (e->bid)
+ fprintf(out, " BID = %d, Priority = %d\n",
+ e->bid, e->priority);
+ else
+ fprintf(out, " No BID assigned\n");
+
fflush(out);
}
@@ -167,6 +176,7 @@
* @hinfo: home address info, optional if our_addr is present
* @our_addr: local address (home address)
* @peer_addr: address of CN
+ * @bid: BID of the bce
*
* Returns reference to non-null entry on success and null on failure.
* If caller adjusts lifetime of entry, caller must call
@@ -174,7 +184,8 @@
* call bcache_release_entry() after entry is not used anymore.
**/
struct bcentry *bcache_get(const struct in6_addr *our_addr,
- const struct in6_addr *peer_addr)
+ const struct in6_addr *peer_addr,
+ uint16_t bid)
{
struct bcentry *bce;
@@ -182,7 +193,7 @@
pthread_rwlock_rdlock(&bc_lock);
- bce = hash_get(&bc_hash, our_addr, peer_addr);
+ bce = hash_get(&bc_hash, our_addr, peer_addr, bid);
if (bce)
pthread_rwlock_wrlock(&bce->lock);
@@ -206,16 +217,19 @@
* bce_type - get type of binding cache entry
* @our_addr: our IPv6 address
* @peer_addr: peer's IPv6 address
+ * @bid: BID of the bce
*
* Looks up entry from binding cache and returns its type. If not
* found, returns -%ENOENT.
**/
-int bce_type(const struct in6_addr *our_addr, const struct in6_addr *peer_addr)
+int bce_type(const struct in6_addr *our_addr,
+ const struct in6_addr *peer_addr,
+ uint16_t bid)
{
struct bcentry *bce;
int type;
- bce = bcache_get(our_addr, peer_addr);
+ bce = bcache_get(our_addr, peer_addr, bid);
if (bce == NULL)
return -ENOENT;
@@ -230,7 +244,9 @@
{
int ret;
- ret = hash_add(&bc_hash, bce, &bce->our_addr, &bce->peer_addr);
+ ret = hash_add(&bc_hash, bce, &bce->our_addr,
+ &bce->peer_addr, &bce->bid);
+
if (ret)
return ret;
@@ -248,7 +264,15 @@
bce->type == BCE_HOMEREG ? bce->lifetime : tmp,
expires);
add_task_abs(&expires, &bce->tqe, _expire);
- xfrm_add_bce(&bce->our_addr, &bce->peer_addr, &bce->coa, 0);
+ /* MCoA
+ * Due to the BID, the BC may have several entries with the
+ * same peer_addr. Thus we add states and policies only if
+ * there are no entries yet for the our_addr/peer_addr pair
+ * (see bce->xfrm_create).
+ */
+ xfrm_add_bce(&bce->our_addr, &bce->peer_addr, &bce->coa, 0,
+ bce->xfrm_create);
+
return 0;
}
@@ -316,22 +340,26 @@
}
tsadd(expires, bce->add_time, expires);
add_task_abs(&expires, &bce->tqe, _expire);
- xfrm_add_bce(&bce->our_addr, &bce->peer_addr, &bce->coa, 1);
+ xfrm_add_bce(&bce->our_addr, &bce->peer_addr, &bce->coa, 1, 0);
return 0;
}
/**
* bcache_delete - deletes a bul entry
+ * If bid == 0, all entries that match our_addr/peer_addr are deleted
**/
void bcache_delete(const struct in6_addr *our_addr,
- const struct in6_addr *peer_addr)
+ const struct in6_addr *peer_addr,
+ uint16_t bid)
{
struct bcentry *bce;
pthread_rwlock_wrlock(&bc_lock);
- bce = hash_get(&bc_hash, our_addr, peer_addr);
- if (bce)
- bce_delete(bce, 0);
+ while ((bce = hash_get(&bc_hash, our_addr, peer_addr, bid))) {
+ if (bce)
+ bce_delete(bce, 0);
+ }
+
pthread_rwlock_unlock(&bc_lock);
}
@@ -364,8 +392,27 @@
pthread_rwlock_wrlock(&bce->lock);
if (bce->type != BCE_DAD) {
del_task(&bce->tqe);
- if (bce->type != BCE_NONCE_BLOCK)
- xfrm_del_bce(&bce->our_addr, &bce->peer_addr);
+ if (bce->type != BCE_NONCE_BLOCK) {
+ /* MCoA
+ * Due to the BID, the BC can have several entries
+ * with the same our_addr/peer_addr pair. We delete
+ * the xfrm data if we do not have any BCE for
+ * this peer_addr anymore, or we update it (we need
+ * to update the kernel's CoA to a valid one).
+ */
+ if(mcoa_bce_count(&bce->peer_addr) == 1)
+ xfrm_del_bce(&bce->our_addr, &bce->peer_addr);
+ else {
+ struct bcentry *next = bce;
+ /* Look for another valid BCE */
+ bcache_iterate_in(&bce->peer_addr,
+ bce_next_entry, &next);
+ /* Replace the CoA */
+ xfrm_add_bce(&next->our_addr,
+ &next->peer_addr,
+ &next->coa, 1, 0);
+ }
+ }
}
if (bce->cleanup)
bce->cleanup(bce);
@@ -380,7 +427,7 @@
}
}
bcache_count--;
- hash_delete(&bc_hash, &bce->our_addr, &bce->peer_addr);
+ hash_delete(&bc_hash, &bce->our_addr, &bce->peer_addr, bce->bid);
pthread_rwlock_unlock(&bce->lock);
bcache_free(bce);
}
@@ -424,3 +471,105 @@
pthread_rwlock_unlock(&bc_lock);
return err;
}
+
+/**
+ * bcache_iterate_in - apply function to every BC entry that match peer_addr
+ * @peer_addr: the peer_addr of the hash
+ * @func: function to apply
+ * @arg: extra data for @func
+ *
+ * Iterates through binding cache, calling @func for each entry that
+ * match peer_addr. Extra data may be passed to @func in @arg. @func
+ * takes a bcentry as its first argument and @arg as second argument.
+ *
+ * Be sure that bc_lock is locked before using this function, and
+ * unlocked after using it.
+ **/
+int bcache_iterate_in(const struct in6_addr *peer_addr,
+ int (* func)(void *, void *),
+ void *arg)
+{
+ int err;
+ err = hash_iterate_in(&bc_hash, peer_addr, func, arg);
+ return err;
+}
+
+int bce_highest_priority(void *bce_v, void *best_bce_v)
+{
+ struct bcentry *bce = bce_v;
+ struct bcentry **best_bce = best_bce_v;
+
+ assert(bce);
+ assert(best_bce);
+
+ if (!(*best_bce) || (bce->priority > (*best_bce)->priority))
+ (*best_bce) = bce;
+
+ return 0;
+}
+
+int bce_next_entry(void *bce_v, void *next_bce_v)
+{
+ struct bcentry *bce = bce_v;
+ struct bcentry **next_bce = next_bce_v;
+
+ assert(bce);
+ assert(next_bce);
+
+ if (bce->bid != (*next_bce)->bid) {
+ (*next_bce) = bce;
+ return 1;
+ }
+
+ return 0;
+}
+
+int mcoa_bce_inc_counter(void *bule_v, void *counter_v)
+{
+ int *counter = counter_v;
+ (*counter)++;
+ return 0;
+}
+
+int mcoa_bce_count(const struct in6_addr *peer_addr)
+{
+ int count = 0;
+ bcache_iterate_in(peer_addr, mcoa_bce_inc_counter, &count);
+
+ return count;
+}
+
+/**
+ * bcache_add_mnps - Add MNPs to the bcache entry
+ * @bce: the bcache entry where we add the MNPs
+ * @mnps: the mnp list to add to the bce
+ *
+ * MNPs are added only if the entry does not exists yet in the BCE's
+ * MNP list. Returns the number of MNPs added.
+ **/
+int bce_add_mnps(struct bcentry *bce, struct list_head *mnps)
+{
+ struct list_head *list;
+ int counter = 0;
+
+ list_for_each(list, mnps) {
+ struct prefix_list_entry *p1, *p2;
+ p1 = list_entry(list, struct prefix_list_entry, list);
+ if (prefix_list_find(&bce->mob_net_prefixes,
+ &p1->ple_prefix, p1->ple_plen))
+ continue;
+
+ p2 = malloc(sizeof(struct prefix_list_entry));
+ if (p2 == NULL) {
+ prefix_list_free(&bce->mob_net_prefixes);
+ return -1;
+ }
+
+ memcpy(p2, p1, sizeof(struct prefix_list_entry));
+ list_add_tail(&p2->list, &bce->mob_net_prefixes);
+ counter++;
+ }
+
+ return counter;
+}
+
diff -Nur mipv6-daemon-umip-0.3-nepl/src/bcache.h mipv6-daemon-umip-0.3-nepl-mcoa/src/bcache.h
--- mipv6-daemon-umip-0.3-nepl/src/bcache.h 2007-06-13 10:36:38.000000000 +0200
+++ mipv6-daemon-umip-0.3-nepl-mcoa/src/bcache.h 2007-06-13 16:11:09.000000000 +0200
@@ -20,6 +20,12 @@
uint16_t nonce_hoa;
uint16_t type; /* Entry type */
uint16_t nemo_type; /* NEMO registration type */
+ uint16_t bid; /* MCoA: Binding Identifier */
+ uint8_t priority; /* MCoA: BID priority */
+ int table; /* MCoA: Table id to where are stored
+ the routes */
+ int xfrm_create; /* MCoA: If xfrm policies/states must
+ be created */
int unreach; /* ICMP dest unreach count */
int tunnel; /* Tunnel interface index */
int link; /* Home link interface index */
@@ -48,12 +54,16 @@
#define BCE_NEMO_IMPLICIT 2
#define BCE_NEMO_DYNAMIC 3
+#define BCE_TABLE_MIN 1
+#define BCE_TABLE_MAX 251
+
struct bcentry *bcache_alloc(int type);
void bcache_free(struct bcentry *bce);
struct bcentry *bcache_get(const struct in6_addr *our_addr,
- const struct in6_addr *peer_addr);
+ const struct in6_addr *peer_addr,
+ uint16_t bid);
int bcache_add(struct bcentry *bce);
@@ -63,28 +73,38 @@
int bcache_update_expire(struct bcentry *bce);
void bcache_delete(const struct in6_addr *our_addr,
- const struct in6_addr *peer_addr);
+ const struct in6_addr *peer_addr,
+ uint16_t bid);
int bcache_init(void);
void bcache_flush(void);
void bcache_cleanup(void);
int bcache_iterate(int (* func)(void *, void *), void *arg);
+int bcache_iterate_in(const struct in6_addr *peer_addr,
+ int (* func)(void *, void *),
+ void *arg);
void bcache_release_entry(struct bcentry *bce);
int bce_type(const struct in6_addr *our_addr,
- const struct in6_addr *peer_addr);
+ const struct in6_addr *peer_addr,
+ uint16_t bid);
static inline int bce_exists(const struct in6_addr *our_addr,
- const struct in6_addr *peer_addr)
+ const struct in6_addr *peer_addr,
+ uint16_t bid)
{
- return bce_type(our_addr, peer_addr) >= BCE_NONCE_BLOCK;
+ return bce_type(our_addr, peer_addr, bid) >= BCE_NONCE_BLOCK;
}
+int bce_add_mnps(struct bcentry *bce, struct list_head *mnps);
+int bce_highest_priority(void *bce_v, void *best_bce_v);
+
void dump_bce(void *bce, void *os);
int get_bcache_count(int type);
+int mcoa_bce_count(const struct in6_addr *peer_addr);
extern pthread_rwlock_t bc_lock; /* Protects binding cache */
diff -Nur mipv6-daemon-umip-0.3-nepl/src/bul.c mipv6-daemon-umip-0.3-nepl-mcoa/src/bul.c
--- mipv6-daemon-umip-0.3-nepl/src/bul.c 2007-06-13 10:36:38.000000000 +0200
+++ mipv6-daemon-umip-0.3-nepl-mcoa/src/bul.c 2007-07-16 14:58:39.000000000 +0200
@@ -38,6 +38,8 @@
#include "xfrm.h"
#include "debug.h"
#include "retrout.h"
+#include "tunnelctl.h"
+#include "rtnl.h"
#ifdef ENABLE_VT
#include "vt.h"
#endif
@@ -55,7 +57,8 @@
static struct hash bul_hash;
struct bulentry *create_bule(const struct in6_addr *hoa,
- const struct in6_addr *cn_addr)
+ const struct in6_addr *cn_addr,
+ u_int16_t bid)
{
struct bulentry *bule;
if ((bule = malloc(sizeof(*bule))) != NULL) {
@@ -63,6 +66,11 @@
bule->hoa = *hoa;
bule->last_coa = *hoa;
bule->peer_addr = *cn_addr;
+ bule->bid = bid;
+ bule->if_tunnel = 0;
+ bule->rules = 0;
+ bule->home_block = 0;
+ bule->mcoa_dereg = 1;
INIT_LIST_HEAD(&bule->tqe.list);
bule->seq = random();
}
@@ -97,6 +105,11 @@
NIP6ADDR(&e->peer_addr));
fprintf(out, " lifetime = %ld, ", e->lifetime.tv_sec);
fprintf(out, " delay = %ld\n", tstomsec(e->delay));
+ if (e->bid)
+ fprintf(out, " BID = %d, Priority = %d\n",
+ e->bid, e->priority);
+ else
+ fprintf(out, " No BID assigned\n");
fprintf(out, " flags: ");
if (e->flags & IP6_MH_BU_HOME)
fprintf(out, "IP6_MH_BU_HOME ");
@@ -116,21 +129,23 @@
* @hinfo: home address info, optional if our_addr is present
* @our_addr: local address (home address)
* @peer_addr: address of CN
+ * @bid: Binding Unique Identifier
*
* Returns non-null entry on success and null on failure. Caller must
* call del_task and add_task, if lifetime of the entry is changed.
**/
struct bulentry *bul_get(struct home_addr_info *hinfo,
const struct in6_addr *our_addr,
- const struct in6_addr *peer_addr)
+ const struct in6_addr *peer_addr,
+ u_int16_t bid)
{
struct bulentry *bule;
assert(hinfo || our_addr);
if (hinfo)
- bule = hash_get(&hinfo->bul, NULL, peer_addr);
- else bule = hash_get(&bul_hash, our_addr, peer_addr);
+ bule = hash_get(&hinfo->bul, NULL, peer_addr, bid);
+ else bule = hash_get(&bul_hash, our_addr, peer_addr, bid);
return bule;
}
@@ -173,9 +188,11 @@
assert(bule && tsisset(bule->lifetime) && hai);
- if ((ret = hash_add(&bul_hash, bule, &bule->hoa, &bule->peer_addr)) < 0)
+ if ((ret = hash_add(&bul_hash, bule, &bule->hoa, &bule->peer_addr,
+ &bule->bid)) < 0)
return ret;
- if ((ret = hash_add(&hai->bul, bule, NULL, &bule->peer_addr)) < 0)
+ if ((ret = hash_add(&hai->bul, bule, NULL, &bule->peer_addr,
+ &bule->bid)) < 0)
goto bul_free;
clock_gettime(CLOCK_REALTIME, &bule->lastsent);
@@ -195,9 +212,9 @@
add_task_abs(&timer_expire, &bule->tqe, bule->callback);
return 0;
home_bul_free:
- hash_delete(&hai->bul, &bule->hoa, &bule->peer_addr);
+ hash_delete(&hai->bul, &bule->hoa, &bule->peer_addr, bule->bid);
bul_free:
- hash_delete(&bul_hash, &bule->hoa, &bule->peer_addr);
+ hash_delete(&bul_hash, &bule->hoa, &bule->peer_addr, bule->bid);
return ret;
}
@@ -207,8 +224,8 @@
struct home_addr_info *hai = bule->home;
del_task(&bule->tqe);
- hash_delete(&bul_hash, &bule->hoa, &bule->peer_addr);
- hash_delete(&hai->bul, NULL, &bule->peer_addr);
+ hash_delete(&bul_hash, &bule->hoa, &bule->peer_addr, bule->bid);
+ hash_delete(&hai->bul, NULL, &bule->peer_addr, bule->bid);
if (!IN6_ARE_ADDR_EQUAL(&bule->hoa, &bule->coa)) {
bule->last_coa = bule->coa;
@@ -220,6 +237,7 @@
if (!(bule->flags & IP6_MH_BU_HOME))
mn_rr_delete_bule(bule);
}
+
if (bule->flags & IP6_MH_BU_HOME) {
if (bule->type == UNREACH_ENTRY) {
pthread_mutex_lock(&hai->ha_list.c_lock);
@@ -230,16 +248,28 @@
} else {
if (hai->home_block & HOME_LINK_BLOCK)
xfrm_unblock_link(hai);
+ if (bule->home_block & HOME_LINK_BLOCK)
+ xfrm_unblock_bule_link(bule);
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);
+ if (bule->home_block & NEMO_FWD_BLOCK)
+ bule_unblock_fwd(bule);
}
}
while (bule->ext_cleanup)
bule->ext_cleanup(bule);
+
+ /* MCoA
+ * If MCoA is used, the tunnel related to this BULE
+ * has to be deleted.
+ */
+ if (bule->home->reg_mcoa && bule->type != NON_MIP_CN_ENTRY)
+ tunnel_del(bule->if_tunnel, NULL, NULL);
+
dbg("Deleting bule\n");
dbg_func(bule, dump_bule);
free_bule(bule);
@@ -310,3 +340,129 @@
struct hash *tmp = h ? h : &bul_hash;
return hash_iterate(tmp, func, arg);
}
+
+/**
+ * bul_iterate_in - apply function to every BUL entry that match peer_addr
+ * @peer_addr: the peer_addr of the hash
+ * @func: function to apply
+ * @arg: extra data for @func
+ *
+ * Iterates through binding update list, calling @func for each entry that
+ * match peer_addr. Extra data may be passed to @func in @arg. @func
+ * takes a BUL entry as its first argument and @arg as second argument.
+ **/
+int bul_iterate_in(struct in6_addr *peer_addr,
+ int (* func)(void *, void *),
+ void *arg)
+{
+ return hash_iterate_in(&bul_hash, peer_addr, func, arg);
+}
+
+int bul_highest_priority(void *bule_v, void *best_bule_v)
+{
+ struct bulentry *bule = bule_v;
+ struct bulentry **best_bule = best_bule_v;
+
+ assert(bule);
+ assert(best_bule);
+
+ if(bule->type == NON_MIP_CN_ENTRY ||
+ bule->type == UNREACH_ENTRY)
+ return 0;
+
+ if (!(*best_bule)
+ || (bule->priority > (*best_bule)->priority
+ && bule->rules))
+ (*best_bule) = bule;
+
+ return 0;
+}
+
+int mcoa_bule_inc_counter(void *bule_v, void *counter_v)
+{
+ struct bulentry *bule = bule_v;
+ int *counter = counter_v;
+ assert(counter);
+
+ if(bule->type != NON_MIP_CN_ENTRY)
+ (*counter)++;
+ return 0;
+}
+
+/**
+ * mcoa_bule_count - count the number of entry (!NON_MIP_CN_ENTRY)
+ * with the same peer_addr.
+ * @bule: the bule where to pick up the peer address
+ **/
+
+int mcoa_bule_count(struct bulentry *bule)
+{
+ int count = 0;
+ assert(bule);
+ bul_iterate_in(&bule->peer_addr, mcoa_bule_inc_counter, &count);
+ return count;
+}
+
+
+int mcoa_bule_setdereg(void *bule_v, void *dereg_v)
+{
+ int *dereg = dereg_v;
+ struct bulentry *bule = bule_v;
+
+ assert(dereg);
+ bule->mcoa_dereg = *(dereg);
+ return 0;
+}
+
+/**
+ * mcoa_bule_dereg - Set the BULE mcoa_dereg flag to value for
+ * all entries that match bule->peer_addr.
+ * @bule: the bule where to pick up the peer address
+ * @value: the value to set
+ **/
+int mcoa_bule_dereg(struct bulentry *bule, int value)
+{
+ bul_iterate_in(&bule->peer_addr, mcoa_bule_setdereg, &value);
+ return 0;
+}
+
+/**
+ * bule_block_fwd - Block forwarding for all MNPs
+ * via the fwmark (BID) of the bule
+ * @bule: the bule
+ */
+void bule_block_fwd(struct bulentry *bule)
+{
+ struct list_head *l;
+ if (!bule->rules)
+ return;
+ bule->home_block |= NEMO_FWD_BLOCK;
+ list_for_each(l, &bule->home->mob_net_prefixes) {
+ struct prefix_list_entry *p = NULL;
+ p = list_entry(l, struct prefix_list_entry, list);
+ rule_add(NULL, 0, IP6_RULE_PRIO_MIP6_BLOCK,
+ /*fwmark*/ bule->bid, RTN_BLACKHOLE,
+ &p->ple_prefix, p->ple_plen,
+ &in6addr_any, 0, 0);
+ }
+}
+
+/**
+ * bule_unblock_fwd - unblock forwarding for all MNPs
+ * via the fwmark (BID) of the bule
+ * @bule: the bule
+ */
+void bule_unblock_fwd(struct bulentry *bule)
+{
+ struct list_head *l;
+ bule->home_block &= ~NEMO_FWD_BLOCK;
+ list_for_each(l, &bule->home->mob_net_prefixes) {
+ struct prefix_list_entry *p = NULL;
+ p = list_entry(l, struct prefix_list_entry, list);
+ rule_del(NULL, 0, IP6_RULE_PRIO_MIP6_BLOCK,
+ /*fwmark*/ bule->bid, RTN_BLACKHOLE,
+ &p->ple_prefix, p->ple_plen,
+ &in6addr_any, 0, 0);
+ }
+}
+
diff -Nur mipv6-daemon-umip-0.3-nepl/src/bul.h mipv6-daemon-umip-0.3-nepl-mcoa/src/bul.h
--- mipv6-daemon-umip-0.3-nepl/src/bul.h 2007-06-13 10:36:09.000000000 +0200
+++ mipv6-daemon-umip-0.3-nepl-mcoa/src/bul.h 2007-06-13 16:11:09.000000000 +0200
@@ -10,6 +10,9 @@
#include "hash.h"
#include "list.h"
+#define BULE_TABLE_MIN 1
+#define BULE_TABLE_MAX 251
+
struct home_addr_info;
struct retrout_info {
@@ -31,10 +34,16 @@
struct in6_addr hoa;
struct in6_addr coa; /* care-of address of the sent BU */
int if_coa;
+ int if_tunnel; /* MCoA: Tunnel iface for the BCE */
+ int table; /* MCoA: Routing table where are
+ stored the routes */
+ int rules; /* MCoA: if rules are installed for
+ this BULE */
int type; /* BUL / NON_MIP_CN / UNREACH */
uint16_t seq; /* sequence number of the latest BU */
uint16_t flags; /* BU send flags */
- struct in6_addr last_coa; /* Last good coa */
+ uint16_t bid; /* MCoA: Binding Identifier */
+ struct in6_addr last_coa; /* Last good coa */
struct timespec lastsent;
struct timespec lifetime; /* lifetime sent in this BU */
struct timespec delay; /* call back time in ms*/
@@ -47,7 +56,11 @@
uint8_t use_alt_coa; /* Whether to use alt. CoA option */
uint8_t dereg; /* for calculating BSA key */
uint8_t do_send_bu; /* send bu / not send bu */
-
+ uint8_t priority; /* MCoA: BID priority */
+ uint8_t home_block; /* MCoA: NEMO_FWD_BLOCK, ... */
+ uint8_t mcoa_dereg; /* MCoA: if BCE needs to be
+ deregistered with a BU */
+
/* Information for return routability */
struct retrout_info rr;
uint8_t Kbm[HMAC_SHA1_KEY_SIZE];
@@ -84,7 +97,8 @@
struct bulentry *bul_get(struct home_addr_info *hinfo,
const struct in6_addr *our_addr,
- const struct in6_addr *peer_addr);
+ const struct in6_addr *peer_addr,
+ u_int16_t bid);
int bul_add(struct bulentry *bule);
@@ -94,7 +108,11 @@
void bul_update_expire(struct bulentry *bule);
int bul_iterate(struct hash *h, int (* func)(void *bule, void *arg), void *arg);
+int bul_iterate_in(struct in6_addr *peer_addr,
+ int (* func)(void *, void *),
+ void *arg);
+int bul_highest_priority(void *bule_v, void *best_bule_v);
int bul_init(void);
int bul_home_init(struct home_addr_info *home);
void bul_home_cleanup(struct hash *bul);
@@ -102,7 +120,12 @@
void bul_cleanup(void);
void dump_bule(void *bule, void *os);
struct bulentry *create_bule(const struct in6_addr *hoa,
- const struct in6_addr *cn_addr);
+ const struct in6_addr *cn_addr,
+ u_int16_t bid);
void free_bule(struct bulentry *bule);
+int mcoa_bule_count(struct bulentry *bule);
+int mcoa_bule_dereg(struct bulentry *bule_v, int value);
+void bule_block_fwd(struct bulentry *bule);
+void bule_unblock_fwd(struct bulentry *bule);
#endif
diff -Nur mipv6-daemon-umip-0.3-nepl/src/cn.c mipv6-daemon-umip-0.3-nepl-mcoa/src/cn.c
--- mipv6-daemon-umip-0.3-nepl/src/cn.c 2007-06-13 10:36:38.000000000 +0200
+++ mipv6-daemon-umip-0.3-nepl-mcoa/src/cn.c 2007-06-13 16:11:09.000000000 +0200
@@ -67,7 +67,11 @@
if (icmp6_parse_data(ip6h, optlen, &laddr, &raddr) < 0)
return;
- bce = bcache_get(laddr, raddr);
+ /* MCoA TODO2
+ * Add MCoA support for the CN
+ * MCOA_NO_BID must be replaced with the BUI's BID
+ */
+ bce = bcache_get(laddr, raddr, MCOA_NO_BID);
if (bce == NULL)
return;
@@ -76,7 +80,7 @@
if (bce->unreach > ICMP_ERROR_PERSISTENT_THRESHOLD &&
bce->type != BCE_HOMEREG) {
bcache_release_entry(bce);
- bcache_delete(laddr, raddr);
+ bcache_delete(laddr, raddr, MCOA_NO_BID);
dbg("BCE for %x:%x:%x:%x:%x:%x:%x:%x deleted "
"due to receipt of ICMPv6 destination unreach\n",
NIP6ADDR(raddr));
@@ -156,6 +160,7 @@
struct in6_addr_bundle out;
struct ip6_mh_binding_update *bu;
struct ip6_mh_opt_nonce_index *non_ind;
+ struct ip6_mh_opt_bid *bid_opt = NULL;
struct bcentry *bce = NULL;
struct timespec lft;
int status, new = 0;
@@ -175,7 +180,18 @@
bu_flags = bu->ip6mhbu_flags;
non_ind = mh_opt(&bu->ip6mhbu_hdr, &mh_opts, IP6_MHOPT_NONCEID);
- bce = bcache_get(out.src, out.dst);
+ /* MCoA TODO2
+ * MCoA support for CN is not implemented yet
+ * At the moment we ignore the BUs with BUI option
+ */
+ if ((bid_opt = mh_opt(&bu->ip6mhbu_hdr, &mh_opts, IP6_MHOPT_BID))) {
+ dbg("Received BU with BUI sub-option, but CN doesn't "
+ "support MCoA registration. BU skipped.\n");
+ status = IP6_MH_BAS_REG_NOT_ALLOWED;
+ goto send_nack;
+ }
+
+ bce = bcache_get(out.src, out.dst, MCOA_NO_BID);
if (bce) {
if ((bce->flags^bu_flags) & (IP6_MH_BU_HOME|IP6_MH_BU_MR)) {
/* H-bit or R-bit mismatch, flags changed */
@@ -219,7 +235,7 @@
goto send_nack;
}
/* else get rid of it */
- bcache_delete(out.src, out.dst);
+ bcache_delete(out.src, out.dst, MCOA_NO_BID);
}
} else {
if (bu_flags & IP6_MH_BU_HOME) {
@@ -281,18 +297,18 @@
}
/* dereg, success */
bcache_release_entry(bce);
- bcache_delete(out.src, out.dst);
+ bcache_delete(out.src, out.dst, MCOA_NO_BID);
status = IP6_MH_BAS_ACCEPTED;
}
if (bu_flags & IP6_MH_BU_ACK)
- mh_send_ba(&out, status, 0, seqno, &lft, key, iif);
+ mh_send_ba(&out, status, 0, seqno, &lft, 0, 0, key, iif);
return;
send_nack:
if (bce) {
bcache_release_entry(bce);
- bcache_delete(out.src, out.dst);
+ bcache_delete(out.src, out.dst, MCOA_NO_BID);
}
- mh_send_ba_err(&out, status, 0, seqno, pkey, iif);
+ mh_send_ba_err(&out, status, 0, seqno, 0, 0, pkey, iif);
}
static struct mh_handler cn_bu_handler =
diff -Nur mipv6-daemon-umip-0.3-nepl/src/conf.c mipv6-daemon-umip-0.3-nepl-mcoa/src/conf.c
--- mipv6-daemon-umip-0.3-nepl/src/conf.c 2007-06-13 10:36:38.000000000 +0200
+++ mipv6-daemon-umip-0.3-nepl-mcoa/src/conf.c 2007-06-13 16:11:09.000000000 +0200
@@ -74,6 +74,7 @@
{
fprintf(stderr,
"%s (%s) %s\n"
+ "With Multiple Care-of Addresses registration support\n"
"%s\n"
"This is free software; see the source for copying conditions. There is NO\n"
"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
@@ -218,6 +219,7 @@
/* HA options */
c->SendMobPfxAdvs = 1;
+ c->HaAcceptMCoAReg = 0;
c->SendUnsolMobPfxAdvs = 1;
c->MaxMobPfxAdvInterval = 86400; /* seconds */
c->MinMobPfxAdvInterval = 600; /* seconds */
@@ -314,8 +316,90 @@
dbg("MaxMobPfxAdvInterval = %u\n", c->MaxMobPfxAdvInterval);
dbg("MinMobPfxAdvInterval = %u\n", c->MinMobPfxAdvInterval);
dbg("HaMaxBindingLife = %u\n", c->HaMaxBindingLife);
-
+ dbg("HaAcceptMobRtr = %d\n", c->HaAcceptMobRtr);
+ dbg("HaAcceptMCoAReg = %d\n", c->HaAcceptMCoAReg);
+
/* CN options */
dbg("DoRouteOptimizationCN = %s\n",
CONF_BOOL_STR(c->DoRouteOptimizationCN));
}
+
+/*
+ * get_reliable_from_ifindex - return the reliability value
+ * from the interface index
+ * @iif: the interface index
+ */
+int get_reliable_from_ifindex(int iif)
+{
+ struct list_head *list;
+
+ list_for_each(list, &conf.net_ifaces) {
+ struct net_iface *nif;
+ nif = list_entry(list, struct net_iface, list);
+ if (nif->ifindex == iif) {
+ if (is_if_mn(nif))
+ return nif->mn_if_reliable;
+ return -1;
+ }
+ }
+ return -1;
+}
+
+/*
+ * get_bid_from_ifindex - return the bid from the interface index
+ * @iif: the interface index
+ */
+uint16_t get_bid_from_ifindex(int iif)
+{
+ struct list_head *list;
+
+ list_for_each(list, &conf.net_ifaces) {
+ struct net_iface *nif;
+ nif = list_entry(list, struct net_iface, list);
+ if (nif->ifindex == iif) {
+ if (is_if_mn(nif))
+ return nif->mn_if_bid;
+ return 0;
+ }
+ }
+ return 0;
+}
+
+/*
+ * get_prio_from_bid - return the priority from the bid
+ * @bid: the bid of the interface
+ */
+uint8_t get_prio_from_bid(uint16_t bid)
+{
+ struct list_head *list;
+
+ list_for_each(list, &conf.net_ifaces) {
+ struct net_iface *nif;
+ nif = list_entry(list, struct net_iface, list);
+ if (nif->mn_if_bid == bid) {
+ if (is_if_mn(nif))
+ return nif->mn_if_bidprio;
+ return 0;
+ }
+ }
+ return 0;
+}
+
+/*
+ * get_highest_prio - return the highest BID priority from the
+ * interface list
+ */
+uint8_t get_highest_prio()
+{
+ struct list_head *list;
+ int priority = 0;
+
+ list_for_each(list, &conf.net_ifaces) {
+ struct net_iface *nif;
+ nif = list_entry(list, struct net_iface, list);
+ if (nif->mn_if_bidprio >= priority)
+ priority = nif->mn_if_bidprio;
+ }
+ return priority;
+}
+
diff -Nur mipv6-daemon-umip-0.3-nepl/src/conf.h mipv6-daemon-umip-0.3-nepl-mcoa/src/conf.h
--- mipv6-daemon-umip-0.3-nepl/src/conf.h 2007-06-13 10:36:38.000000000 +0200
+++ mipv6-daemon-umip-0.3-nepl-mcoa/src/conf.h 2007-06-13 16:11:09.000000000 +0200
@@ -48,6 +48,7 @@
/* HA options */
char HaAcceptMobRtr;
+ char HaAcceptMCoAReg;
char SendMobPfxAdvs;
char SendUnsolMobPfxAdvs;
unsigned int MaxMobPfxAdvInterval;
@@ -66,6 +67,9 @@
int is_rtr;
int mip6_if_entity;
int mn_if_preference;
+ uint16_t mn_if_bid;
+ uint8_t mn_if_bidprio;
+ int mn_if_reliable;
};
extern struct mip6_config conf;
@@ -119,6 +123,11 @@
void conf_show(struct mip6_config *c);
+int get_reliable_from_ifindex(int iif);
+uint16_t get_bid_from_ifindex(int iif);
+uint8_t get_prio_from_bid(uint16_t bid);
+uint8_t get_highest_prio();
+
int yyparse(void);
int yylex(void);
diff -Nur mipv6-daemon-umip-0.3-nepl/src/dhaad_mn.c mipv6-daemon-umip-0.3-nepl-mcoa/src/dhaad_mn.c
--- mipv6-daemon-umip-0.3-nepl/src/dhaad_mn.c 2007-06-13 10:36:38.000000000 +0200
+++ mipv6-daemon-umip-0.3-nepl-mcoa/src/dhaad_mn.c 2007-06-13 16:11:09.000000000 +0200
@@ -120,8 +120,9 @@
pthread_rwlock_unlock(&mn_lock);
return;
}
- t->dhaad_id = dhaad_send_request(hai->primary_coa.iif,
- &hai->primary_coa.addr,
+ assert(hai->current_coa);
+ t->dhaad_id = dhaad_send_request(hai->current_coa->iif,
+ &hai->current_coa->addr,
&hai->home_prefix,
hai->home_plen,
hai->mob_rtr?
@@ -146,8 +147,9 @@
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,
+ assert(hai->current_coa);
+ t->dhaad_id = dhaad_send_request(hai->current_coa->iif,
+ &hai->current_coa->addr,
&hai->home_prefix,
hai->home_plen,
hai->mob_rtr?
diff -Nur mipv6-daemon-umip-0.3-nepl/src/gram.y mipv6-daemon-umip-0.3-nepl-mcoa/src/gram.y
--- mipv6-daemon-umip-0.3-nepl/src/gram.y 2007-06-13 10:36:38.000000000 +0200
+++ mipv6-daemon-umip-0.3-nepl-mcoa/src/gram.y 2007-06-13 16:11:09.000000000 +0200
@@ -47,15 +47,20 @@
#include "util.h"
#include "ipsec.h"
#include "rtnl.h"
+#include "bul.h"
struct net_iface ni = {
.mip6_if_entity = MIP6_ENTITY_NO,
.mn_if_preference = POL_MN_IF_DEF_PREFERENCE,
+ .mn_if_bid = POL_MN_IF_DEF_BID,
+ .mn_if_bidprio = POL_MN_IF_DEF_BID_PRIORITY,
+ .mn_if_reliable = POL_MN_IF_DEF_RELIABLE
};
struct home_addr_info hai = {
.ro_policies = LIST_HEAD_INIT(hai.ro_policies),
- .mob_net_prefixes = LIST_HEAD_INIT(hai.mob_net_prefixes)
+ .mob_net_prefixes = LIST_HEAD_INIT(hai.mob_net_prefixes),
+ .mcoa = LIST_HEAD_INIT(hai.mcoa)
};
LIST_HEAD(prefixes);
@@ -185,6 +190,14 @@
%token ISMOBRTR
%token HASERVEDPREFIX
%token MOBRTRUSEEXPLICITMODE
+%token HAACCEPTMCOAREG
+%token MCOAREG
+%token NOMCOAREG
+%token BID
+%token BIDPRIORITY
+%token RELIABLE
+%token REGMULTIPLECOA
+%token IFMULTIPLECOA
%token INV_TOKEN
@@ -197,6 +210,7 @@
%type mnropolicyaddr
%type dorouteopt
%type bindaclpolval
+%type mcoapolval
%type prefixlen
%type mip6entity
%type xfrmaction
@@ -306,6 +320,10 @@
{
conf.HaAcceptMobRtr = $2;
}
+ | HAACCEPTMCOAREG BOOL ';'
+ {
+ conf.HaAcceptMCoAReg = $2;
+ }
| HASERVEDPREFIX prefixlistentry ';'
{
list_splice(&prefixes,
@@ -375,6 +393,9 @@
memset(&ni, 0, sizeof(struct net_iface));
ni.mip6_if_entity = MIP6_ENTITY_NO;
ni.mn_if_preference = POL_MN_IF_DEF_PREFERENCE;
+ ni.mn_if_bid = POL_MN_IF_DEF_BID;
+ ni.mn_if_bidprio = POL_MN_IF_DEF_BID_PRIORITY;
+ ni.mn_if_reliable = POL_MN_IF_DEF_RELIABLE;
}
;
@@ -392,7 +413,44 @@
}
| MNIFPREFERENCE NUMBER ';'
{
- ni.mn_if_preference = $2;
+ if (ni.mn_if_bid) {
+ uerror("You cannot set MnIfPreference if BID "
+ "is set. Use BidPriority instead.");
+ return -1;
+ }
+ ni.mn_if_preference = $2;
+ }
+ | BID NUMBER ';'
+ {
+ if (ni.mn_if_preference) {
+ uerror("If BID is set, you cannot set "
+ "MnIfPreference. Use BidPriority instead.");
+ return -1;
+ }
+ if ($2 < BULE_TABLE_MIN || $2 > BULE_TABLE_MAX) {
+ uerror("BID error (%d <= Bid <= %d)",
+ BULE_TABLE_MIN, BULE_TABLE_MAX);
+ return -1;
+ }
+ ni.mn_if_bid = $2;
+ }
+ | BIDPRIORITY NUMBER ';'
+ {
+ if (ni.mn_if_preference) {
+ uerror("You cannot set BidPriority if "
+ "MnIfPreference is set.");
+ return -1;
+ }
+ if ($2 < 1 || $2 > 255) {
+ uerror("BidPriotity error "
+ "(%d <= BidPriority <= %d)",1, 255);
+ return -1;
+ }
+ ni.mn_if_bidprio = $2;
+ }
+ | RELIABLE BOOL ';'
+ {
+ ni.mn_if_reliable = $2;
}
;
@@ -432,15 +490,28 @@
INIT_LIST_HEAD(&nhai->ro_policies);
INIT_LIST_HEAD(&nhai->ha_list.home_agents);
INIT_LIST_HEAD(&nhai->mob_net_prefixes);
+ INIT_LIST_HEAD(&nhai->mcoa);
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_splice(&hai.mcoa, &nhai->mcoa);
+ if (!hai.reg_mcoa) {
+ /* If MCoA registration is not used, we
+ * initialize nhai->current_coa
+ */
+ nhai->current_coa = malloc(sizeof(struct mn_addr));
+ if (nhai->current_coa == NULL) {
+ uerror("out of memory");
+ return -1;
+ }
+ }
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);
+ INIT_LIST_HEAD(&hai.mcoa);
}
;
@@ -468,6 +539,11 @@
ipv6_addr_prefix(&hai.home_prefix, &$2, $4);
hai.home_plen = $4;
}
+ | REGMULTIPLECOA BOOL ';'
+ {
+ hai.reg_mcoa = $2;
+ }
+ | IFMULTIPLECOA iflist ';'
;
homeaddress : homeaddrdef prefixlistsub
@@ -695,7 +771,12 @@
| NUMBER { $$ = $1; }
;
-bindaclpolicy : ADDR prefixlistsub bindaclpolval
+mcoapolval : MCOAREG { $$ = 1; }
+ | NOMCOAREG { $$ = 0; }
+ | '' { $$ = 0; }
+ ;
+
+bindaclpolicy : ADDR prefixlistsub mcoapolval bindaclpolval
{
bae = malloc(sizeof(struct policy_bind_acl_entry));
if (bae == NULL) {
@@ -707,7 +788,8 @@
bae->plen = 128;
INIT_LIST_HEAD(&bae->mob_net_prefixes);
bae->mnp_count = mv_prefixes(&bae->mob_net_prefixes);
- bae->bind_policy = $3;
+ bae->mcoa_reg = $3;
+ bae->bind_policy = $4;
list_add_tail(&bae->list, &conf.bind_acl);
}
;
@@ -745,4 +827,58 @@
list_add_tail(&p->list, &prefixes);
}
;
+
+iflist : iflistentry
+ | iflist ',' iflistentry
+ ;
+
+iflistentry : QSTRING
+ {
+ struct mn_addr *mncoa;
+ struct list_head *l;
+ int declared = 0, bid = 0;
+
+ /* Check that this interface has been
+ * previously declared as "Interface" */
+ list_for_each(l, &conf.net_ifaces) {
+ struct net_iface *ni;
+ ni = list_entry(l, struct net_iface,
+ list);
+
+ if(if_nametoindex($1) == ni->ifindex) {
+ declared = 1;
+ bid = ni->mn_if_bid;
+ break;
+ }
+ }
+
+ if(!declared) {
+ uerror("Interface %s has not been "
+ "declared as Interface\n", $1);
+ return -1;
+ }
+
+ if(!bid) {
+ uerror("Interface %s has no BID "
+ "although you declared it in "
+ "IfMultipleCoA\n", $1);
+ return -1;
+ }
+
+ mncoa = malloc(sizeof(struct mn_addr));
+ if (mncoa == NULL) {
+ fprintf(stderr, "%s: out of memory\n",
+ __FUNCTION__);
+ return -1;
+ }
+ memset(mncoa, 0, sizeof(struct mn_addr));
+ if ((mncoa->iif = if_nametoindex($1)) == 0) {
+ fprintf(stderr, "%s: %s is not a valid "
+ "interface name\n", __FUNCTION__, $1);
+ return -1;
+ }
+ free($1);
+ list_add_tail(&mncoa->list, &hai.mcoa);
+ }
+ ;
%%
diff -Nur mipv6-daemon-umip-0.3-nepl/src/ha.c mipv6-daemon-umip-0.3-nepl-mcoa/src/ha.c
--- mipv6-daemon-umip-0.3-nepl/src/ha.c 2007-06-13 10:36:38.000000000 +0200
+++ mipv6-daemon-umip-0.3-nepl-mcoa/src/ha.c 2007-07-16 14:58:39.000000000 +0200
@@ -60,6 +60,14 @@
#include "ndisc.h"
#include "prefix.h"
+#define HA_DEBUG_LEVEL 1
+
+#if HA_DEBUG_LEVEL >= 1
+#define MDBG dbg
+#else
+#define MDBG(...)
+#endif /* MDBG */
+
static pthread_mutex_t bu_worker_mutex;
static volatile unsigned long bu_worker_count = 0;
static pthread_cond_t cond;
@@ -504,7 +512,7 @@
static void nemo_ha_del_mnp_routes(struct list_head *old_mnps,
struct list_head *new_mnps,
- int ifindex, int all)
+ int table, int ifindex, int all)
{
struct list_head *list;
list_for_each(list, old_mnps) {
@@ -514,14 +522,22 @@
prefix_list_find(new_mnps, &p->ple_prefix, p->ple_plen))
continue;
- route_del(ifindex, RT6_TABLE_MIP6, IP6_RT_PRIO_MIP6_FWD,
+ route_del(ifindex, table, IP6_RT_PRIO_MIP6_FWD,
NULL, 0, &p->ple_prefix, p->ple_plen, NULL);
+
+ /* MCoA
+ * Delete the MNP fwmark rule
+ */
+ if(table != RT6_TABLE_MIP6)
+ rule_del(NULL, table, IP6_RULE_PRIO_MIP6_FWD_FWM,
+ table, RTN_UNICAST, &in6addr_any, 0,
+ &p->ple_prefix, p->ple_plen, 0);
}
}
static int nemo_ha_add_mnp_routes(struct list_head *old_mnps,
struct list_head *new_mnps,
- int ifindex, int all)
+ int table, int ifindex, int all)
{
struct list_head *list;
list_for_each(list, new_mnps) {
@@ -530,14 +546,129 @@
if (!all &&
prefix_list_find(old_mnps, &p->ple_prefix, p->ple_plen))
continue;
- if (route_add(ifindex, RT6_TABLE_MIP6, RTPROT_MIP,
+ if (route_add(ifindex, table, RTPROT_MIP,
0, IP6_RT_PRIO_MIP6_FWD,
NULL, 0, &p->ple_prefix, p->ple_plen, NULL) < 0)
return -1;
+ /* MCoA
+ * Add the MNP fwmark rule
+ */
+ if(table != RT6_TABLE_MIP6
+ && rule_add(NULL, table, IP6_RULE_PRIO_MIP6_FWD_FWM,
+ table, RTN_UNICAST, &in6addr_any, 0,
+ &p->ple_prefix, p->ple_plen, 0) < 0)
+ return -1;
}
return 0;
}
+static int mcoa_ha_init_rt_table(struct bcentry *bce)
+{
+ /* MCoA TODO2
+ * At the moment, the routing table number is the BID number.
+ * BID thus must be between BCE_TABLE_MIN and BCE_TABLE_MAX
+ */
+ assert(bce);
+
+ /* If BID is not assigned, default table is taken */
+ if (!bce->bid)
+ return (bce->table = RT6_TABLE_MIP6);
+
+ if (bce->bid >= BCE_TABLE_MIN && bce->bid <= BCE_TABLE_MAX)
+ return (bce->table = bce->bid);
+
+ return -1;
+}
+
+static int mcoa_ha_del_dflt_rules(struct bcentry *bce)
+{
+ struct list_head *list;
+ struct prefix_list_entry *pfx;
+ struct bcentry *best_bce = bce;
+ const struct in6_addr *peer_addr = &bce->peer_addr;
+ int8_t priority = 0;
+
+ MDBG("Current BCE has the best priority (%d), "
+ "erasing default rules\n", best_bce->priority);
+
+ /* Erase the default HoA rule */
+ rule_del(NULL, 0, IP6_RULE_PRIO_MIP6_FWD_MCOA, 0,
+ RTN_UNICAST, &in6addr_any, 0, peer_addr, 128, 0);
+
+ /* Erase the default MNP rules */
+ list_for_each(list, &bce->mob_net_prefixes) {
+ pfx = list_entry(list, struct prefix_list_entry, list);
+ rule_del(NULL, 0, IP6_RULE_PRIO_MIP6_FWD_MCOA, 0,
+ RTN_UNICAST, &in6addr_any, 0,
+ &pfx->ple_prefix, pfx->ple_plen, 0);
+ }
+
+ /* Create new rule with next best bce available */
+ priority = bce->priority;
+ bce->priority = 0;
+ bcache_iterate_in(&bce->peer_addr, bce_highest_priority,
+ &best_bce);
+ bce->priority = priority;
+
+ if(best_bce != bce) {
+ MDBG("Rules replaced with BCE prio %d\n",
+ best_bce->priority);
+ rule_add(NULL, best_bce->table,
+ IP6_RULE_PRIO_MIP6_FWD_MCOA, 0, RTN_UNICAST,
+ &in6addr_any, 0, peer_addr, 128, 0);
+
+ /* Default prefix rules */
+ list_for_each(list, &bce->mob_net_prefixes) {
+ pfx = list_entry(list,
+ struct prefix_list_entry, list);
+ rule_add(NULL, best_bce->table,
+ IP6_RULE_PRIO_MIP6_FWD_MCOA, 0,
+ RTN_UNICAST, &in6addr_any, 0,
+ &pfx->ple_prefix, pfx->ple_plen, 0);
+ }
+ } else
+ MDBG("No other BCE available, no dflt rules added\n");
+
+ return 0;
+}
+
+static int mcoa_ha_add_dflt_rules(struct bcentry *bce)
+{
+ struct list_head *list;
+ const struct in6_addr *peer_addr = &bce->peer_addr;
+
+ MDBG("BCE has the best priority (%d), adding default HoA "
+ "and prefix rules\n", bce->priority);
+
+ /* Erase the default HoA rule */
+ rule_del(NULL, 0, IP6_RULE_PRIO_MIP6_FWD_MCOA, 0,
+ RTN_UNICAST, &in6addr_any, 0, peer_addr, 128, 0);
+
+ /* Add the default HoA rule */
+ if (rule_add(NULL, bce->table,
+ IP6_RULE_PRIO_MIP6_FWD_MCOA, 0, RTN_UNICAST,
+ &in6addr_any, 0, peer_addr, 128, 0) < 0)
+ return -1;
+
+ /* Delete and add the default prefix rules */
+ list_for_each(list, &bce->mob_net_prefixes) {
+ struct prefix_list_entry *pfx;
+ pfx = list_entry(list, struct prefix_list_entry, list);
+
+ rule_del(NULL, 0, IP6_RULE_PRIO_MIP6_FWD_MCOA,
+ 0, RTN_UNICAST, &in6addr_any, 0,
+ &pfx->ple_prefix, pfx->ple_plen, 0);
+
+ if (rule_add(NULL, bce->table,
+ IP6_RULE_PRIO_MIP6_FWD_MCOA, 0,
+ RTN_UNICAST, &in6addr_any, 0,
+ &pfx->ple_prefix, pfx->ple_plen, 0) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
struct home_tnl_ops_parm {
struct bcentry *bce;
int ba_status;
@@ -547,6 +678,7 @@
static int home_tnl_del(int old_if, int new_if, struct home_tnl_ops_parm *p)
{
const struct in6_addr *our_addr, *peer_addr, *coa, *old_coa;
+ struct bcentry *best_bce = NULL;
assert(old_if);
@@ -563,12 +695,33 @@
ha_ipsec_tnl_pol_del(our_addr, peer_addr, p->bce->tunnel);
}
/* delete HoA route */
+ /* MCoA: The route is deleted in the table given by p->bce->table */
+ /* RKRK: for the moment the route is installed in the MAIN table.
+ * See home_tnl_add */
+ //MDBG("Deleting old default route in table %d\n", p->bce->table);
+ MDBG("Deleting old default route in table %d\n", RT6_TABLE_MAIN);
+ //route_del(old_if, p->bce->table,
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);
+ &p->mob_net_prefixes, p->bce->table,
+ old_if, 1);
+ /* MCoA
+ * Delete the HoA and fwmark rules, and if needed replace
+ * the default HoA and MNP rules with the best available one
+ */
+ if(p->bce->table != RT6_TABLE_MIP6) {
+ rule_del(NULL, p->bce->table, IP6_RULE_PRIO_MIP6_FWD_FWM,
+ p->bce->table, RTN_UNICAST, &in6addr_any, 0,
+ peer_addr, 128, 0);
+ best_bce = p->bce;
+ bcache_iterate_in(&p->bce->peer_addr,
+ bce_highest_priority, &best_bce);
+ if(best_bce == p->bce)
+ mcoa_ha_del_dflt_rules(p->bce);
+ }
/* update tunnel interface */
p->bce->tunnel = new_if;
@@ -578,6 +731,7 @@
static int home_tnl_add(int old_if, int new_if, struct home_tnl_ops_parm *p)
{
const struct in6_addr *our_addr, *peer_addr, *coa, *old_coa;
+ struct bcentry *best_bce = NULL;
assert(new_if);
@@ -591,7 +745,8 @@
/* add MNP routes */
if (nemo_ha_add_mnp_routes(&p->bce->mob_net_prefixes,
- &p->mob_net_prefixes, new_if, 1) < 0) {
+ &p->mob_net_prefixes, p->bce->table,
+ new_if, 1) < 0) {
if (p->bce->nemo_type == BCE_NEMO_EXPLICIT)
p->ba_status = IP6_MH_BAS_INVAL_PRFX;
else
@@ -599,12 +754,39 @@
goto err;
}
/* add HoA route */
+ /* MCoA: The route is added in the table given by p->bce->table */
+ /* RKRK: does not work. Route has to be added in the MAIN table.
+ * Need to check why ! */
+ //MDBG("Adding route in table %d via iface %d\n", p->bce->table, new_if);
+ MDBG("Adding route in table %d via iface %d\n", RT6_TABLE_MAIN, new_if);
+ //if (route_add(new_if, p->bce->table,
if (route_add(new_if, RT6_TABLE_MAIN,
RTPROT_MIP, 0, IP6_RT_PRIO_MIP6_FWD,
NULL, 0, peer_addr, 128, NULL) < 0) {
p->ba_status = IP6_MH_BAS_INSUFFICIENT;
goto err;
}
+ /* MCoA
+ * Add the HoA and fwmark rules, and if needed replace
+ * the default HoA and MNP rules with the best available one
+ */
+ if (p->bce->table != RT6_TABLE_MIP6) {
+ if (rule_add(NULL, p->bce->table,
+ IP6_RULE_PRIO_MIP6_FWD_FWM,
+ p->bce->table, RTN_UNICAST,
+ &in6addr_any, 0, peer_addr, 128, 0) < 0) {
+ p->ba_status = IP6_MH_BAS_INSUFFICIENT;
+ goto err;
+ }
+ best_bce = p->bce;
+ bcache_iterate_in(&p->bce->peer_addr,
+ bce_highest_priority, &best_bce);
+ if(best_bce == p->bce
+ && mcoa_ha_add_dflt_rules(p->bce) < 0) {
+ p->ba_status = IP6_MH_BAS_INSUFFICIENT;
+ goto err;
+ }
+ }
/* add SP entry */
if (conf.UseMnHaIPsec) {
if (ha_ipsec_tnl_pol_add(our_addr, peer_addr,
@@ -641,11 +823,17 @@
MR's MNPs have changed */
if (prefix_list_cmp(&p->bce->mob_net_prefixes,
&p->mob_net_prefixes)) {
+ /* MCoA TODO1
+ * Default prefix rules may have changed
+ * this should be updated also here.
+ */
nemo_ha_del_mnp_routes(&p->bce->mob_net_prefixes,
&p->mob_net_prefixes,
+ p->bce->table,
old_if, 0);
if (nemo_ha_add_mnp_routes(&p->bce->mob_net_prefixes,
&p->mob_net_prefixes,
+ p->bce->table,
new_if, 0) < 0) {
if (p->bce->nemo_type == BCE_NEMO_EXPLICIT)
p->ba_status = IP6_MH_BAS_INVAL_PRFX;
@@ -685,10 +873,14 @@
static void home_cleanup(struct bcentry *bce)
{
+ /* MCoA TODO2
+ * MPA should be canceled only if last BCE entry
+ * ie if(mcoa_bce_count(&bce->peer_addr) == 1)
+ */
mpd_cancel_mpa(&bce->our_addr, &bce->peer_addr);
if (bce->link > 0) {
- route_del(bce->link, RT6_TABLE_MIP6, IP6_RT_PRIO_MIP6_OUT,
+ route_del(bce->link, bce->table, IP6_RT_PRIO_MIP6_OUT,
&bce->our_addr, 128, &bce->peer_addr, 128, NULL);
proxy_nd_stop(bce->link, &bce->peer_addr, bce->flags);
}
@@ -702,6 +894,9 @@
if (conf.UseMnHaIPsec) {
ha_mn_ipsec_pol_mod(&bce->our_addr, &bce->peer_addr);
}
+
+ /* MCoA: Freeing the BCE's MNPs list */
+ prefix_list_free(&bce->mob_net_prefixes);
}
@@ -778,19 +973,28 @@
{
struct ha_recv_bu_args *arg = varg;
struct in6_addr_bundle out;
- struct bcentry *bce;
+ struct bcentry *bce, *bce_exists;
struct timespec lft, tmp;
- int iif, status, new, home_ifindex;
- uint16_t bu_flags, seqno;
- uint8_t ba_flags;
+ int iif, status, status_bid, new, home_ifindex;
+ int update_dflt_table;
+ uint16_t bu_flags, seqno, bid;
+ uint8_t ba_flags, bid_priority, bid_flags;
struct home_tnl_ops_parm p;
+ struct ip6_mh_opt_bid *bid_opt;
pthread_dbg("thread started");
restart:
home_ifindex = 0;
new = 0;
+ bid = 0;
+ bid_priority = 0;
+ bid_flags = 0;
+ update_dflt_table = 0;
ba_flags = 0;
- lft = arg->lft;
+ status = IP6_MH_BAS_UNSPECIFIED;
+ status_bid = 0;
+ bce = NULL;
+ lft = arg->lft;
iif = arg->iif;
bu_flags = arg->bu->ip6mhbu_flags;
seqno = ntohs(arg->bu->ip6mhbu_seqno);
@@ -805,8 +1009,79 @@
else
out.bind_coa = NULL;
out.local_coa = NULL;
+ bid_opt = NULL;
- bce = bcache_get(out.src, out.dst);
+ /* MCoA
+ * We check if a BCE already exists for this HoA
+ * We take the first one available
+ */
+ bce_exists = bcache_get(out.src, out.dst, MCOA_NO_BID);
+ if(bce_exists)
+ bcache_release_entry(bce_exists);
+
+ /* MCoA
+ * we need the BID before looking at the BCE
+ */
+ bid_opt = mh_opt(&arg->bu->ip6mhbu_hdr,
+ &arg->mh_opts,
+ IP6_MHOPT_BID);
+
+ if (bid_opt && !default_mcoa_reg(out.dst)) {
+ /* MCoA: BAck without BID option will be sent */
+ MDBG("BUI option, but MCoA registration not allowed.\n");
+ } else if (bid_opt) {
+ MDBG("BUI option, and HA is configured for MCoA.\n");
+ bid = ntohs(bid_opt->ip6mobid_bid);
+ bid_priority = bid_opt->ip6mobid_priority;
+ bid_flags = ntohs(bid_opt->ip6mobid_reserved);
+
+ if (!bid) {
+ MDBG("BID invalid, BU discarded.\n");
+ goto out;
+ }
+
+ MDBG("BID = %d, Priority = %d\n", bid, bid_priority);
+ /* MCoA TODO1
+ * if B flag is set but no altcoa option:
+ * BAck status 145.
+ * To update according to latest draft.
+ */
+ if (bid_flags & IP6_OPT_BID_BULK) {
+ /* MCoA TODO1
+ * At the moment we do not check the AltCoA option,
+ * and just reject the BU if B flag is set
+ */
+ MDBG("BULK Reg., but not supported yet.\n");
+ status = IP6_MH_BAS_MCOA_BULK_FAILED;
+ goto send_nack;
+ }
+ if (bce_exists && !bce_exists->bid) {
+ /* MCoA
+ * The BCE has a BID = 0, this means no MCoA
+ * are registered. We delete the entry and set
+ * BA status to 144.
+ * New registratration is done later
+ */
+ MDBG("BID option but BCE has no BID\n");
+ MDBG("Delete BCE and register new one.\n");
+ bcache_delete(out.src, out.dst, MCOA_NO_BID);
+ status_bid = IP6_MH_BAS_CONFLICT_BINDING;
+ }
+ } else /* No BUI option in BU */ {
+ if(tsisset(lft) && bce_exists && bce_exists->bid) {
+ /* MCoA
+ * A BCE exists with a BID != 0 but no BUI
+ * sub-option are set in the BU: we delete
+ * all existing entries for this HoA. New
+ * registration is done later.
+ */
+ MDBG("No BID option but BCE has BID.\n");
+ MDBG("Delete all BCE and register new one.\n");
+ bcache_delete(out.src, out.dst, MCOA_NO_BID);
+ }
+ }
+
+ bce = bcache_get(out.src, out.dst, bid);
if (bce) {
if (bce->type != BCE_NONCE_BLOCK) {
/* H-bit or R-bit mismatch, flags changed */
@@ -851,7 +1126,7 @@
goto send_nack;
}
/* else get rid of it */
- bcache_delete(out.src, out.dst);
+ bcache_delete(out.src, out.dst, bid);
}
} else if (!tsisset(lft)) {
status = IP6_MH_BAS_NOT_HA;
@@ -859,9 +1134,21 @@
}
if ((status = mpd_prefix_check(out.src, out.dst,
&lft, &home_ifindex, new)) < 0) {
- if (!(bu_flags & IP6_MH_BU_MR) ||
- !prefix_list_find(&conf.nemo_ha_served_prefixes,
- out.dst, 0)) {
+ if ((bu_flags & IP6_MH_BU_MR) &&
+ prefix_list_find(&conf.nemo_ha_served_prefixes,
+ out.dst, 0)) {
+ struct ha_interface *i = ha_get_if_by_addr(out.src);
+ if (i != NULL) {
+ home_ifindex = i->ifindex;
+ /* set the prefix lifetime to the maximum */
+ tssetsec(lft, MAX_BINDING_LIFETIME);
+ } else {
+ /* not home agent for this subnet */
+ status = IP6_MH_BAS_NOT_HOME_SUBNET;
+ goto send_nack;
+ }
+ } else {
+
/* not home agent for this subnet */
status = IP6_MH_BAS_NOT_HOME_SUBNET;
goto send_nack;
@@ -872,6 +1159,10 @@
out.src, arg->bu, arg->len);
if (status >= IP6_MH_BAS_UNSPECIFIED)
goto send_nack;
+
+ if(status_bid)
+ status = status_bid;
+
/* lifetime may be further decreased by local policy */
if (conf.pmgr.max_binding_life(out.dst, out.bind_coa, out.src,
arg->bu, arg->len, &lft, &tmp)) {
@@ -893,24 +1184,38 @@
bce->type = BCE_DAD;
bce->cleanup = NULL;
bce->link = home_ifindex;
-
+ bce->bid = bid;
+ bce->priority = bid_priority;
+ if(bce_exists)
+ bce->xfrm_create = 0;
+ else
+ bce->xfrm_create = 1;
+
+ /* MCoA: Initialize the routing table used by the BCE */
+ if(mcoa_ha_init_rt_table(bce) < 0) {
+ free(bce);
+ bce = NULL;
+ status = IP6_MH_BAS_INSUFFICIENT;
+ goto send_nack;
+ }
if (bcache_add_homereg(bce) < 0) {
free(bce);
bce = NULL;
status = IP6_MH_BAS_INSUFFICIENT;
goto send_nack;
}
- if (!(arg->flags & HA_BU_F_SKIP_DAD)) {
+ /* MCoA: Do DAD only if no entries yet for this HoA */
+ if (!(arg->flags & HA_BU_F_SKIP_DAD) && !bce_exists) {
/* Do DAD for home address */
if (ndisc_do_dad(home_ifindex, out.dst,
bu_flags & IP6_MH_BU_LLOCAL) < 0) {
- bcache_delete(out.src, out.dst);
+ bcache_delete(out.src, out.dst, bid);
bce = NULL;
status = IP6_MH_BAS_DAD_FAILED;
goto send_nack;
}
}
- bce = bcache_get(out.src, out.dst);
+ bce = bcache_get(out.src, out.dst, bid);
if (!bce) {
BUG("BCE deleted before DAD completed!");
status = IP6_MH_BAS_UNSPECIFIED;
@@ -942,6 +1247,12 @@
bce->seqno = seqno;
bce->flags = bu_flags;
bce->lifetime = lft;
+ /* MCoA TODO2
+ * MNPs are added to the BCE.
+ * Need to maintain this list when deregistration
+ */
+ bce_add_mnps(bce, &p.mob_net_prefixes);
+
if (new) {
if (tunnel_add(out.src, out.bind_coa, 0,
home_tnl_ops, &p) < 0) {
@@ -953,7 +1264,8 @@
}
bce->cleanup = home_cleanup;
- if (route_add(bce->link, RT6_TABLE_MIP6,
+ /* MCoA: The route is added in the table given by the BCE */
+ if (route_add(bce->link, bce->table,
RTPROT_MIP, 0, IP6_RT_PRIO_MIP6_OUT,
&bce->our_addr, 128, &bce->peer_addr, 128,
NULL) < 0) {
@@ -961,16 +1273,23 @@
goto send_nack;
}
- if (proxy_nd_start(bce->link, out.dst, out.src,
- bu_flags) < 0) {
- status = IP6_MH_BAS_INSUFFICIENT;
- goto send_nack;
+ /* MCoA: Do Proxy ND only if no entries yet for this HoA */
+ if (!bce_exists) {
+ if (proxy_nd_start(bce->link, out.dst,
+ out.src, bu_flags) < 0) {
+ status = IP6_MH_BAS_INSUFFICIENT;
+ goto send_nack;
+ }
}
bce->type = BCE_HOMEREG;
bcache_complete_homereg(bce);
} else {
bce->old_coa = bce->coa;
bce->coa = *out.bind_coa;
+ if (tsisset(lft)) {
+ bce->bid = bid;
+ bce->priority = bid_priority;
+ }
if (tunnel_mod(bce->tunnel, out.src, out.bind_coa, 0,
home_tnl_ops, &p) < 0) {
if (p.ba_status >= IP6_MH_BAS_UNSPECIFIED)
@@ -984,7 +1303,10 @@
/* bce is always valid here */
bcache_release_entry(bce);
if (!tsisset(lft))
- bcache_delete(out.src, out.dst);
+ /* MCoA: We delete one specific entry (bid is set)
+ * or all entries for this HoA (if bid is set to 0)
+ */
+ bcache_delete(out.src, out.dst, bid);
if ((bu_flags & IP6_MH_BU_KEYM) &&
conf.pmgr.use_keymgm(out.dst, out.src))
@@ -1005,12 +1327,16 @@
* 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)
+ if ((status < IP6_MH_BAS_UNSPECIFIED
+ || status == IP6_MH_BAS_CONFLICT_BINDING)
+ && 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))
+ mh_send_ba(&out, status, ba_flags, seqno, &lft,
+ bid, bid_priority, NULL, iif);
+ /* MCoA: Start MPA only if no entries yet for this HoA */
+ if (!bce_exists && new && tsisset(lft))
mpd_start_mpa(&bce->our_addr, &bce->peer_addr);
out:
free(arg);
@@ -1030,10 +1356,12 @@
send_nack:
if (bce) {
bcache_release_entry(bce);
- bcache_delete(out.src, out.dst);
+ bcache_delete(out.src, out.dst, bid);
}
if (!(arg->flags & HA_BU_F_SKIP_BA))
- mh_send_ba_err(&out, status, 0, seqno, NULL, iif);
+ /* MCoA: Specify the BID and BID priority to the BAck */
+ mh_send_ba_err(&out, status, 0, seqno, bid,
+ bid_priority, NULL, iif);
goto out;
}
@@ -1059,12 +1387,13 @@
arg = malloc(sizeof(struct ha_recv_bu_args) + len);
if (!arg) {
- if (bce_exists(out.src, out.dst))
- bcache_delete(out.src, out.dst);
+ if (bce_exists(out.src, out.dst, MCOA_NO_BID))
+ bcache_delete(out.src, out.dst, MCOA_NO_BID);
if (!(arg->flags & HA_BU_F_SKIP_BA))
mh_send_ba_err(&out, IP6_MH_BAS_INSUFFICIENT, 0,
- ntohs(bu->ip6mhbu_seqno), NULL, iif);
+ ntohs(bu->ip6mhbu_seqno), 0, 0,
+ NULL, iif);
return -ENOMEM;
}
arg->src = *out.src;
@@ -1136,8 +1465,9 @@
return -1;
if (mpd_ha_init() < 0)
return -1;
+ /* MCoA: Rule to the default table (RT6_TABLE_MIP6) */
if (rule_add(NULL, RT6_TABLE_MIP6,
- IP6_RULE_PRIO_MIP6_FWD, RTN_UNICAST,
+ IP6_RULE_PRIO_MIP6_FWD, 0, RTN_UNICAST,
&in6addr_any, 0, &in6addr_any, 0, 0) < 0)
return -1;
icmp6_handler_reg(ND_ROUTER_ADVERT, &ha_ra_handler);
@@ -1155,7 +1485,7 @@
pthread_mutex_unlock(&bu_worker_mutex);
bcache_flush();
rule_del(NULL, RT6_TABLE_MIP6,
- IP6_RULE_PRIO_MIP6_FWD, RTN_UNICAST,
+ IP6_RULE_PRIO_MIP6_FWD, 0, RTN_UNICAST,
&in6addr_any, 0, &in6addr_any, 0, 0);
mpd_ha_cleanup();
dhaad_ha_cleanup();
diff -Nur mipv6-daemon-umip-0.3-nepl/src/hash.c mipv6-daemon-umip-0.3-nepl-mcoa/src/hash.c
--- mipv6-daemon-umip-0.3-nepl/src/hash.c 2007-06-13 10:36:09.000000000 +0200
+++ mipv6-daemon-umip-0.3-nepl-mcoa/src/hash.c 2007-06-13 16:11:09.000000000 +0200
@@ -47,6 +47,7 @@
struct hash_entry {
struct in6_addr *our_addr; /* pointer to our_addr in data */
struct in6_addr *peer_addr; /* pointer to peer_addr in data */
+ uint16_t *bid; /* pointer to bid in data, can be NULL */
struct hash_entry *next;
void *data;
};
@@ -78,7 +79,7 @@
}
static int match2(struct hash_entry *h, const struct in6_addr *our_addr,
- const struct in6_addr *peer_addr)
+ const struct in6_addr *peer_addr, uint16_t bid)
{
assert(h);
assert(our_addr && h->our_addr);
@@ -89,9 +90,15 @@
printf("h->peer %s\n", inet_ntop(AF_INET6, h->peer_addr, s, sizeof(s)));
printf("our_addr %s\n", inet_ntop(AF_INET6, our_addr, s, sizeof(s)));
printf("h->our_addr %s\n", inet_ntop(AF_INET6, h->our_addr, s, sizeof(s)));
+ printf("bid %d\n", bid);
+ if(h->bid != NULL)
+ printf("h->bid %d\n", *(h->bid));
+ else
+ printf("h->bid is NULL\n");
#endif
if (IN6_ARE_ADDR_EQUAL(h->peer_addr, peer_addr) &&
- IN6_ARE_ADDR_EQUAL(h->our_addr, our_addr)) {
+ IN6_ARE_ADDR_EQUAL(h->our_addr, our_addr) &&
+ (bid == 0 || (h->bid != NULL && bid == *(h->bid)))) {
return 1;
}
return 0;
@@ -99,7 +106,7 @@
}
static int match1(struct hash_entry *h, const struct in6_addr *dummy,
- const struct in6_addr *peer_addr)
+ const struct in6_addr *peer_addr, uint16_t bid)
{
assert(h);
assert(h->peer_addr && peer_addr);
@@ -107,8 +114,14 @@
char s[INET6_ADDRSTRLEN];
printf("match1: peer %s\n", inet_ntop(AF_INET6, peer_addr, s, sizeof(s)));
printf("h->peer %s\n", inet_ntop(AF_INET6, h->peer_addr, s, sizeof(s)));
+ printf("bid %d\n", bid);
+ if(h->bid != NULL)
+ printf("h->bid %d\n", *(h->bid));
+ else
+ printf("h->bid is NULL\n");
#endif
- if (!IN6_ARE_ADDR_EQUAL(h->peer_addr, peer_addr))
+ if (!IN6_ARE_ADDR_EQUAL(h->peer_addr, peer_addr) ||
+ (bid !=0 && h->bid != NULL && bid != *(h->bid)))
return 0;
return 1;
}
@@ -155,7 +168,8 @@
void *hash_get(const struct hash *h,
const struct in6_addr *our_addr,
- const struct in6_addr *peer_addr)
+ const struct in6_addr *peer_addr,
+ uint16_t bid)
{
struct hash_entry *hptr = NULL;
@@ -165,7 +179,7 @@
hptr = h->hash_buckets[h->calc_hash(h->buckets, our_addr , peer_addr)];
while(hptr) {
- if (h->match(hptr, our_addr, peer_addr))
+ if (h->match(hptr, our_addr, peer_addr, bid))
return hptr->data;
hptr = hptr->next;
}
@@ -173,7 +187,8 @@
}
int hash_add(const struct hash *h, void *data,
- struct in6_addr *our_addr, struct in6_addr *peer_addr)
+ struct in6_addr *our_addr, struct in6_addr *peer_addr,
+ uint16_t *bid)
{
struct hash_entry *hptr = NULL, *new;
uint32_t hash_ind;
@@ -185,17 +200,19 @@
assert(peer_addr);
if ((new = (struct hash_entry *)malloc(sizeof(struct hash_entry))) == NULL) {
- dbg("out of memeory\n");
+ dbg("out of memory\n");
return -ENOMEM;
}
new->our_addr = our_addr;
new->peer_addr = peer_addr;
new->data = data;
+ new->bid = bid;
hash_ind = h->calc_hash(h->buckets, our_addr, peer_addr);
hptr = h->hash_buckets[hash_ind];
if (hptr) {
while (hptr->next){
- if (h->match(hptr, our_addr, peer_addr)) {
+ if (h->match(hptr, our_addr, peer_addr,
+ (bid) ? (*bid) : 0)) {
free(new);
return -EEXIST;
}
@@ -231,9 +248,35 @@
return 0;
}
+int hash_iterate_in(const struct hash *h,
+ const struct in6_addr *peer_addr,
+ int (*func)(void *, void *),
+ void *arg)
+{
+ int err = 0;
+ int i;
+ struct hash_entry *hptr, *nptr;
+
+ assert(func);
+
+ for (i=0; i < h->buckets; i++) {
+ if((hptr = h->hash_buckets[i]) != NULL) {
+ while(hptr) {
+ nptr = hptr->next;
+ if (IN6_ARE_ADDR_EQUAL(hptr->peer_addr, peer_addr)
+ && (err = func(hptr->data, arg)))
+ return err;
+ hptr = nptr;
+ }
+ }
+ }
+ return 0;
+}
+
void hash_delete(const struct hash *h,
const struct in6_addr *our_addr,
- const struct in6_addr *peer_addr)
+ const struct in6_addr *peer_addr,
+ uint16_t bid)
{
struct hash_entry *hptr, *pptr, *head;
int hash_ind;
@@ -247,7 +290,7 @@
pptr = hptr = head;
while (hptr) {
- if (h->match(hptr, our_addr, peer_addr)){
+ if (h->match(hptr, our_addr, peer_addr, bid)){
if (hptr != head)
pptr->next = hptr->next;
else {
diff -Nur mipv6-daemon-umip-0.3-nepl/src/hash.h mipv6-daemon-umip-0.3-nepl-mcoa/src/hash.h
--- mipv6-daemon-umip-0.3-nepl/src/hash.h 2007-06-13 10:36:09.000000000 +0200
+++ mipv6-daemon-umip-0.3-nepl-mcoa/src/hash.h 2007-06-13 16:11:09.000000000 +0200
@@ -20,7 +20,9 @@
int buckets;
int type;
uint32_t (*calc_hash)(int, const struct in6_addr *, const struct in6_addr *);
- int (*match)(struct hash_entry *, const struct in6_addr *, const struct in6_addr *);
+ int (*match)(struct hash_entry *, const struct in6_addr *,
+ const struct in6_addr *, uint16_t);
+
struct hash_entry **hash_buckets;
};
@@ -37,19 +39,24 @@
*/
void hash_cleanup(struct hash *h);
/*
- * Get data stored in a hash entry based on one or two addresses, depending on type of hash
+ * Get data stored in a hash entry based on one or two addresses and the bid,
+ * depending on type of hash. bid=0 means we do not use bid as a search key.
*/
void *hash_get(const struct hash *h,
const struct in6_addr *our_addr,
- const struct in6_addr *peer_addr) ;
+ const struct in6_addr *peer_addr,
+ uint16_t bid);
/* Iterate through the hash and call func for every entry */
int hash_iterate(const struct hash *h, int (*func)(void *data, void *arg), void *arg);
+int hash_iterate_in(const struct hash *h, const struct in6_addr *peer_addr,
+ int (*func)(void *, void *), void *arg);
/* Add a hash entry to hash */
int hash_add(const struct hash *h, void *data,
- struct in6_addr *our_addr, struct in6_addr *peer_addr);
+ struct in6_addr *our_addr, struct in6_addr *peer_addr,
+ uint16_t *bid);
/*
*Delete entry from hash
@@ -57,6 +64,7 @@
void hash_delete(const struct hash *h,
const struct in6_addr *our_addr,
- const struct in6_addr *peer_addr);
+ const struct in6_addr *peer_addr,
+ uint16_t bid);
#endif /* _HASH_H */
diff -Nur mipv6-daemon-umip-0.3-nepl/src/mh.c mipv6-daemon-umip-0.3-nepl-mcoa/src/mh.c
--- mipv6-daemon-umip-0.3-nepl/src/mh.c 2007-06-13 10:36:38.000000000 +0200
+++ mipv6-daemon-umip-0.3-nepl-mcoa/src/mh.c 2007-06-13 16:11:09.000000000 +0200
@@ -77,6 +77,7 @@
0, /* Nonce Index */
0, /* Binding Auth Data */
1, /* Mobile Network Prefix */
+ 1 /* Binding Unique Identifier */
};
#define __MH_SENTINEL (IP6_MH_TYPE_MAX + 1)
@@ -443,6 +444,41 @@
return 0;
}
+/* MCoA
+ * mh_create_opt_bid - Create a Binding Unique Identifier Option
+ * MCoA TODO1: need to be adapted for BULK registration
+ */
+int mh_create_opt_bid(struct iovec *iov, uint16_t bid,
+ uint8_t priority, uint8_t bid_flags)
+{
+ int optlen = sizeof(struct ip6_mh_opt_bid);
+ struct ip6_mh_opt_bid *opt_bid;
+ 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;
+
+ opt_bid = (struct ip6_mh_opt_bid *)data;
+
+ opt_bid->ip6mobid_type = IP6_MHOPT_BID;
+ opt_bid->ip6mobid_len = 4;
+ opt_bid->ip6mobid_bid = htons(bid);
+ opt_bid->ip6mobid_priority = priority;
+ opt_bid->ip6mobid_reserved |= bid_flags;
+
+ data += sizeof(struct ip6_mh_opt_bid);
+ MDBG("BUI sub-option created with BID = %d and priority %d\n",
+ bid, priority);
+
+ return 0;
+}
+
static size_t mh_length(struct iovec *vec, int count)
{
size_t len = 0;
@@ -487,6 +523,9 @@
case IP6_MHOPT_MOB_NET_PRFX:
pad = optpad(8, 4, len); /* 8n+4 */
break;
+ case IP6_MHOPT_BID:
+ pad = optpad(2, 0, len); /* 2n */
+ break;
}
if (pad > 0) {
create_opt_pad(&out[n++], pad);
@@ -497,9 +536,10 @@
out[n].iov_base = in[m].iov_base;
n++;
}
- if (count == 1) {
+ if (count == 1 || len%8 != 0) {
pad = optpad(8, 0, len);
create_opt_pad(&out[n++], pad);
+ MDBG("Added %d bytes for padding\n", pad);
}
return n;
@@ -984,11 +1024,14 @@
void mh_send_ba(const struct in6_addr_bundle *addrs, uint8_t status,
uint8_t flags, uint16_t sequence,
- const struct timespec *lifetime, const uint8_t *key, int iif)
+ const struct timespec *lifetime,
+ const uint16_t bid,
+ const uint8_t priority,
+ const uint8_t *key, int iif)
{
int iovlen = 1;
struct ip6_mh_binding_ack *ba;
- struct iovec mh_vec[2];
+ struct iovec mh_vec[3];
MDBG("status %d\n", status);
@@ -1012,6 +1055,9 @@
}
if (key)
mh_create_opt_auth_data(&mh_vec[iovlen++]);
+ /* MCoA: Create Binding Unique Identifier Option if needed */
+ if (bid)
+ mh_create_opt_bid(&mh_vec[iovlen++], bid, priority, 0);
mh_send(addrs, mh_vec, iovlen, key, iif);
free_iov_data(mh_vec, iovlen);
}
@@ -1058,8 +1104,11 @@
return -1;
if (!IN6_ARE_ADDR_EQUAL(out_addrs->bind_coa, peer_addr)) {
/* check that there is no circular reference */
- if (bce_exists(our_addr, out_addrs->bind_coa))
+ if (bce_exists(our_addr, out_addrs->bind_coa,
+ MCOA_NO_BID)) {
+ MDBG("Circular reference found in BC\n");
return -1;
+ }
tssetsec(*lifetime, ntohs(bu->ip6mhbu_lifetime) << 2);
}
}
diff -Nur mipv6-daemon-umip-0.3-nepl/src/mh.h mipv6-daemon-umip-0.3-nepl-mcoa/src/mh.h
--- mipv6-daemon-umip-0.3-nepl/src/mh.h 2007-06-13 10:36:38.000000000 +0200
+++ mipv6-daemon-umip-0.3-nepl-mcoa/src/mh.h 2007-06-13 16:11:09.000000000 +0200
@@ -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_MOB_NET_PRFX
+#define IP6_MHOPT_MAX IP6_MHOPT_BID
struct in6_addr_bundle {
struct in6_addr *src;
@@ -43,14 +43,20 @@
void mh_send_ba(const struct in6_addr_bundle *addrs, uint8_t status,
uint8_t flags, uint16_t sequence,
const struct timespec *lifetime,
+ const uint16_t bid,
+ const uint8_t priority,
const uint8_t *key, int iif);
static inline void mh_send_ba_err(const struct in6_addr_bundle *addrs,
uint8_t status, uint8_t flags,
- uint16_t seqno, const uint8_t *key, int iif)
+ uint16_t seqno,
+ const uint16_t bid,
+ const uint8_t priority,
+ const uint8_t *key, int iif)
{
struct timespec zero = { 0, 0 };
- mh_send_ba(addrs, status, flags, seqno, &zero, key, iif);
+ mh_send_ba(addrs, status, flags, seqno, &zero,
+ bid, priority, key, iif);
}
void mh_send_be(struct in6_addr *dst,
@@ -79,6 +85,9 @@
int mh_create_opt_mob_net_prefix(struct iovec *iov, int mnp_count,
struct list_head *mnps);
+int mh_create_opt_bid(struct iovec *iov, uint16_t bid, uint8_t priority,
+ uint8_t bid_flags);
+
static inline void *mh_opt(const struct ip6_mh *mh,
const struct mh_options *mh_opts, uint8_t type)
{
diff -Nur mipv6-daemon-umip-0.3-nepl/src/mipv6.h mipv6-daemon-umip-0.3-nepl-mcoa/src/mipv6.h
--- mipv6-daemon-umip-0.3-nepl/src/mipv6.h 2007-06-13 10:36:09.000000000 +0200
+++ mipv6-daemon-umip-0.3-nepl-mcoa/src/mipv6.h 2007-06-13 16:11:09.000000000 +0200
@@ -23,6 +23,7 @@
/* Constants below have no explicit names in the spec. */
#define MAX_BINDING_LIFETIME (0xffff << 2) /* seconds */
+#define MCOA_NO_BID 0 /* BID is null */
/* Maximum time for a binding to be unused for CN to still send a BRR
* before the binding expires */
diff -Nur mipv6-daemon-umip-0.3-nepl/src/mn.c mipv6-daemon-umip-0.3-nepl-mcoa/src/mn.c
--- mipv6-daemon-umip-0.3-nepl/src/mn.c 2007-06-13 10:36:38.000000000 +0200
+++ mipv6-daemon-umip-0.3-nepl-mcoa/src/mn.c 2007-06-14 18:09:03.000000000 +0200
@@ -35,6 +35,8 @@
#include
#include
#include
+#include
+#include
#include
#include
@@ -94,10 +96,44 @@
const struct timespec min_valid_bu_lifetime_ts =
{ MIN_VALID_BU_LIFETIME, 0 };
+struct flag_hoa_args {
+ struct home_addr_info *target;
+ struct bulentry *bule;
+ int flag;
+};
+
static int pending_bas = 0;
static void mn_send_home_bu(struct home_addr_info *hai);
static int mn_ext_tunnel_ops(int request, int old_if, int new_if, void *data);
+static int flag_hoa(struct ifaddrmsg *ifa, struct rtattr *rta_tb[], void *arg);
+static int mcoa_iface_rules_add(int iif, struct home_addr_info *hai);
+static struct bulentry* mcoa_iface_rules_del(int iif,
+ struct home_addr_info *hai,
+ int replace);
+static void mcoa_mn_rules_del(struct home_addr_info *hinfo);
+static int nemo_mr_rules_add(struct home_addr_info *hinfo);
+static void nemo_mr_rules_del(struct home_addr_info *hinfo);
+
+static int mcoa_mn_init_rt_table(struct bulentry *bule)
+{
+ /* MCoA TODO2
+ * At the moment, the routing table number
+ * is the BID number. BID must be between
+ * BCE_TABLE_MIN and BCE_TABLE_MAX
+ */
+ assert(bule);
+
+ /* If BID is not assigned, default table is taken */
+ if (!bule->bid)
+ return (bule->table = RT6_TABLE_MIP6);
+
+ if (bule->bid >= BULE_TABLE_MIN && bule->bid <= BULE_TABLE_MAX)
+ return (bule->table = bule->bid);
+
+ MDBG("Routing Table index is out of range");
+ return -1;
+}
static int mn_block_rule_del(struct home_addr_info *hai)
{
@@ -108,9 +144,9 @@
return ret;
}
- if ((ret = rule_del(NULL, 0, IP6_RULE_PRIO_MIP6_BLOCK, RTN_BLACKHOLE,
- &hai->hoa.addr, 128, &in6addr_any, 0,
- FIB_RULE_FIND_SADDR)) < 0)
+ if ((ret = rule_del(NULL, 0, IP6_RULE_PRIO_MIP6_BLOCK, 0,
+ RTN_BLACKHOLE, &hai->hoa.addr, 128, &in6addr_any,
+ 0, FIB_RULE_FIND_SADDR)) < 0)
MDBG("failed to delete blackhole rule.\n");
else
hai->home_block &= ~HOME_ADDR_RULE_BLOCK;
@@ -126,9 +162,9 @@
MDBG("blackhole is already set.\n");
return ret;
}
- if ((ret = rule_add(NULL, 0, IP6_RULE_PRIO_MIP6_BLOCK, RTN_BLACKHOLE,
- &hai->hoa.addr, 128, &in6addr_any, 0,
- FIB_RULE_FIND_SADDR)) < 0)
+ if ((ret = rule_add(NULL, 0, IP6_RULE_PRIO_MIP6_BLOCK,
+ 0, RTN_BLACKHOLE, &hai->hoa.addr, 128,
+ &in6addr_any, 0, FIB_RULE_FIND_SADDR)) < 0)
MDBG("failed to add blackhole rule.\n");
else
hai->home_block |= HOME_ADDR_RULE_BLOCK;
@@ -156,7 +192,10 @@
struct home_addr_info *hai = e->home;
struct in6_addr hoa, peer_addr;
int type = e->type;
+ int rules = e->rules;
+ int if_coa = e->if_coa;
uint16_t flags = e->flags;
+ uint16_t bid = e->bid;
if (type != BUL_ENTRY)
return;
@@ -173,7 +212,7 @@
if (hai->at_home)
return;
- e = create_bule(&hoa, &peer_addr);
+ e = create_bule(&hoa, &peer_addr, hai->reg_mcoa?bid:0);
if (e == NULL)
return;
@@ -185,6 +224,19 @@
e->lifetime = NON_MIP_CN_LTIME_TS;
e->delay = NON_MIP_CN_LTIME_TS;
e->callback = bul_expire;
+ e->priority = get_prio_from_bid(e->bid);
+ e->mcoa_dereg = 0;
+ /* MCoA: No tunnels are linked to this BULE anymore */
+ e->if_tunnel = 0;
+ /* MCoA: We prevent MIPL to install rules for this entry */
+ e->rules = 1;
+ mcoa_mn_init_rt_table(e);
+
+ /* MCoA: Erase rules corresponding to this BULE */
+ /* TODO2: this should be done when bul is deleted */
+ if(hai->reg_mcoa && rules)
+ mcoa_iface_rules_del(if_coa, hai, 1);
+
if (bul_add(e) < 0)
bul_delete(e);
}
@@ -279,7 +331,10 @@
pthread_rwlock_wrlock(&mn_lock);
if (mn_rr_error_check(laddr, raddr, &addr))
laddr = &addr;
- e = bul_get(NULL, laddr, raddr);
+ /* MCoA TODO1
+ * All bule with same laddr, raddr should be invalidated
+ */
+ e = bul_get(NULL, laddr, raddr, get_bid_from_ifindex(iif));
if (e != NULL) {
if (e->flags & IP6_MH_BU_HOME) {
if (!conf.UseMnHaIPsec &&
@@ -328,6 +383,19 @@
}
if (bule->flags & IP6_MH_BU_HOME) {
struct home_addr_info *hai = bule->home;
+ /* MCoA TODO1: to update according to latest draft
+ * Binding Unique Identifier Option
+ * For deregistration, BUI option is sent only
+ * when some specific entry needs to be deleted.
+ * If all entries are deleted, no need to send BUI
+ */
+ if ((bu->ip6mhbu_lifetime || !bule->mcoa_dereg)
+ && hai->reg_mcoa && bule->bid
+ && mh_create_opt_bid(&iov[iov_ind++], bule->bid,
+ bule->priority, 0) < 0) {
+ free_iov_data(iov, iov_ind);
+ return -ENOMEM;
+ }
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++],
@@ -353,7 +421,29 @@
addrs.remote_coa = NULL;
addrs.bind_coa = &bule->coa;
+ /* MCoA
+ * before sending BU, if !bule->rules then
+ * add rule from HoA to HA in table bule->table
+ * This to be able to send a BU if no rules are in
+ * the RPDB (eg. because of the Reliability option)
+ */
+ if(bule->home->reg_mcoa && !bule->rules)
+ /* MCoA: Rule for HoA to HA from the MN */
+ rule_add(NULL, bule->table,
+ IP6_RULE_PRIO_MIP6_HOA_OUT_MCOA, 0, RTN_UNICAST,
+ &bule->home->hoa.addr, 128, &bule->peer_addr, 128,
+ FIB_RULE_FIND_SADDR);
+
ret = mh_send(&addrs, iov, iov_ind, bind_key, bule->if_coa);
+
+ /* MCoA
+ * Delete the previously installed rule
+ */
+ if(bule->home->reg_mcoa && !bule->rules)
+ rule_del(NULL, bule->table,
+ IP6_RULE_PRIO_MIP6_HOA_OUT_MCOA, 0, RTN_UNICAST,
+ &bule->home->hoa.addr, 128, &bule->peer_addr, 128,
+ FIB_RULE_FIND_SADDR);
if (ret <= 0)
MDBG("mh_send failed ret: %d\n", ret);
@@ -363,15 +453,35 @@
return ret;
}
+struct mn_addr *mcoa_get_current_coa(struct home_addr_info *hai, int iif)
+{
+ struct list_head *l;
+
+ if(!hai->reg_mcoa)
+ return hai->current_coa;
+
+ list_for_each(l, &hai->mcoa) {
+ struct mn_addr *coa_entry;
+ coa_entry = list_entry(l, struct mn_addr, list);
+ if (coa_entry->iif == iif)
+ return coa_entry;
+ }
+
+ return NULL;
+}
+
static int mn_get_home_lifetime(struct home_addr_info *hai,
- struct timespec *lifetime, int dereg)
+ struct timespec *lifetime,
+ int iif, int dereg)
{
if (!hai->at_home && !dereg) {
- struct mn_addr *coa = &hai->primary_coa;
+ /* MCoA: Pick up the CoA from the correct iface */
+ struct mn_addr *coa = mcoa_get_current_coa(hai, iif);
struct timespec now;
unsigned long coa_lft;
unsigned long hoa_lft;
+ assert(coa);
clock_gettime(CLOCK_REALTIME, &now);
coa_lft = mpd_curr_lft(&now, &coa->timestamp,
@@ -403,16 +513,20 @@
if (!hai->at_home && !dereg) {
struct bulentry *e;
- e = bul_get(hai, NULL, &hai->ha_addr);
+ e = bul_get(hai, NULL, &hai->ha_addr,
+ hai->reg_mcoa?
+ get_bid_from_ifindex(hai->current_coa->iif)
+ :MCOA_NO_BID);
if (e == NULL || !(e->flags & IP6_MH_BU_HOME)) {
MDBG("No valid home registration");
} else {
struct timespec now;
- struct mn_addr *coa = &hai->primary_coa;
+ struct mn_addr *coa = hai->current_coa;
unsigned long coa_lft;
unsigned long home_lft;
+ assert(coa);
clock_gettime(CLOCK_REALTIME, &now);
coa_lft = mpd_curr_lft(&now, &coa->timestamp,
@@ -432,6 +546,21 @@
return 1;
}
+/* MCoA
+ * Deregister a specific bule
+ */
+static int mn_dereg_bule(struct bulentry *bule)
+{
+ if (bule->type != NON_MIP_CN_ENTRY) {
+ bule->seq++;
+ bule->mcoa_dereg = 0;
+ tsclear(bule->lifetime);
+ mn_send_bu_msg(bule);
+ }
+ bul_delete(bule);
+ return 0;
+}
+
static int mn_dereg(void *vbule, void *arg)
{
struct bulentry *bule = vbule;
@@ -445,7 +574,20 @@
}
bule->seq++;
tsclear(bule->lifetime);
- mn_send_bu_msg(bule);
+ /* MCoA
+ * When a MN wants to deregister Multiple CoA,
+ * one BU is enough to deregister all the CoA
+ */
+ if(bule->home->reg_mcoa && bule->mcoa_dereg) {
+ mn_send_bu_msg(bule);
+ /* MCoA
+ * Flag the other entries that match the
+ * peer address (to avoid sending multiple
+ * BUs)
+ */
+ mcoa_bule_dereg(bule, 0);
+ } else if (!bule->home->reg_mcoa)
+ mn_send_bu_msg(bule);
}
bul_delete(bule);
return 0;
@@ -486,8 +628,9 @@
int dereg;
if (bule->flags & IP6_MH_BU_HOME)
- dereg = mn_get_home_lifetime(bule->home, &bule->lifetime, 0);
- else
+ dereg = mn_get_home_lifetime(bule->home, &bule->lifetime,
+ bule->if_coa, 0);
+ else
dereg = mn_get_ro_lifetime(bule->home, &bule->lifetime,
bule->dereg);
@@ -544,6 +687,7 @@
if (!task_interrupted()) {
struct bulentry *bule = tq_data(tqe, struct bulentry, tqe);
int expired;
+ int iif = bule->if_coa;
MDBG("Bul refresh type: %d\n", bule->type);
clock_gettime(CLOCK_REALTIME, &bule->lastsent);
@@ -554,6 +698,10 @@
bule->seq++;
bule->callback = bu_resend;
+ /* MCoA : Check for interface reliability */
+ if(bule->home->reg_mcoa
+ && get_reliable_from_ifindex(iif) == 0)
+ mcoa_iface_rules_del(iif, bule->home, 1);
pre_bu_bul_update(bule);
mn_send_bu_msg(bule);
@@ -626,14 +774,53 @@
return 0;
}
-int nemo_mr_tnl_routes_add(struct home_addr_info *hai, int ifindex)
+/*
+ * Copy home address between two interfaces
+ */
+static int cp_hoa(struct ifaddrmsg *ifa, struct rtattr *rta_tb[], void *arg)
+{
+ struct mv_hoa_args *mha = arg;
+ struct home_addr_info *hai = mha->target;
+ struct mn_addr *hoa = &hai->hoa;
+ int err;
+ struct timespec now;
+ uint32_t preferred = PREFIX_LIFETIME_INFINITE;
+ uint32_t valid = PREFIX_LIFETIME_INFINITE;
+ int plen = (mha->if_next == hai->if_tunnel ? 128 : hai->plen);
+
+ clock_gettime(CLOCK_REALTIME, &now);
+
+ if (hai->lladdr_comp && rta_tb[IFA_CACHEINFO] != NULL) {
+ struct ifa_cacheinfo *ci = RTA_DATA(rta_tb[IFA_CACHEINFO]);
+ mn_update_hoa_lifetime(hoa, &now,
+ ci->ifa_valid, ci->ifa_prefered);
+ valid = ci->ifa_valid;
+ preferred = ci->ifa_prefered;
+ }
+ if (mha->if_next == ifa->ifa_index)
+ return 0;
+
+ MDBG("Copy HoA %x:%x:%x:%x:%x:%x:%x:%x/%d from iface %d to %d\n",
+ NIP6ADDR(&hoa->addr), plen, ifa->ifa_index, mha->if_next);
+
+ err = addr_add(&hoa->addr, plen,
+ ifa->ifa_flags|IFA_F_HOMEADDRESS,
+ ifa->ifa_scope, mha->if_next, preferred, valid);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+int nemo_mr_tnl_routes_add(struct home_addr_info *hai,
+ int ifindex, int rtable)
{
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,
+ if (route_add(ifindex, rtable, RTPROT_MIP,
0, IP6_RT_PRIO_MIP6_FWD,
&p->ple_prefix, p->ple_plen,
&in6addr_any, 0, NULL) < 0) {
@@ -646,7 +833,7 @@
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,
+ route_del(ifindex, rtable, IP6_RT_PRIO_MIP6_FWD,
&p->ple_prefix, p->ple_plen, &in6addr_any, 0, NULL);
if (p == pe)
break;
@@ -654,44 +841,47 @@
return -1;
}
-static int mn_tnl_state_add(struct home_addr_info *hai, int ifindex, int all)
+static int mn_tnl_state_add(struct home_addr_info *hai,
+ int ifindex, int all, int rtable)
{
int err = 0;
if (hai->home_reg_status != HOME_REG_NONE) {
if ((err = mn_ro_pol_add(hai, ifindex, all)) < 0)
return err;
- if ((err = route_add(ifindex, RT6_TABLE_MIP6, RTPROT_MIP, 0,
+ if ((err = route_add(ifindex, rtable, RTPROT_MIP, 0,
IP6_RT_PRIO_MIP6_OUT, &in6addr_any, 0,
&in6addr_any, 0, NULL)) < 0) {
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,
+ (err = nemo_mr_tnl_routes_add(hai, ifindex, rtable)) < 0) {
+ route_del(ifindex, rtable, 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)
+static void nemo_mr_tnl_routes_del(struct home_addr_info *hai,
+ int ifindex, int rtable)
{
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,
+ route_del(ifindex, rtable, 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)
+static void mn_tnl_state_del(struct home_addr_info *hai, int ifindex,
+ int all, int rtable)
{
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,
+ nemo_mr_tnl_routes_del(hai, ifindex, rtable);
+ route_del(ifindex, rtable, IP6_RT_PRIO_MIP6_OUT,
&hai->hoa.addr, 128, &in6addr_any, 0, NULL);
mn_ro_pol_del(hai, ifindex, all);
}
@@ -715,8 +905,18 @@
static void mn_pol_ext_cleanup(struct bulentry *bule)
{
MDBG("\n");
- mpd_cancel_mps(&bule->hoa, &bule->peer_addr);
- mn_tnl_state_del(bule->home, bule->home->if_tunnel, 0);
+ /* MCoA
+ * MPS is canceled only if the BULE is the last entry
+ * for the HoA, or when at home
+ */
+ if (mcoa_bule_count(bule) == 0 || bule->home->at_home)
+ mpd_cancel_mps(&bule->hoa, &bule->peer_addr);
+ if (bule->home->reg_mcoa)
+ mn_tnl_state_del(bule->home, bule->if_tunnel, 0,
+ bule->table);
+ else
+ mn_tnl_state_del(bule->home, bule->home->if_tunnel,
+ 0, bule->table);
if (conf.UseMnHaIPsec) {
mn_ipsec_tnl_update(&bule->peer_addr, &bule->hoa, bule);
@@ -730,12 +930,13 @@
struct timespec *lifetime)
{
int err = 0;
+ assert(hai->current_coa);
bule->type = BUL_ENTRY;
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;
+ bule->coa = hai->current_coa->addr;
+ bule->if_coa = hai->current_coa->iif;
bule->lifetime = *lifetime;
bule->delay = conf.InitialBindackTimeoutFirstReg_ts;
bule->callback = bu_resend;
@@ -744,10 +945,47 @@
bule->ext_cleanup = mn_pol_ext_cleanup;
bule->home = hai;
bule->consecutive_resends = 0;
+ bule->priority = get_prio_from_bid(bule->bid);
hai->home_reg_status = HOME_REG_UNCERTAIN;
- if ((err = mn_tnl_state_add(hai, hai->if_tunnel, 0)) < 0)
+ /* MCoA: MCoA requires one tunnel per CoA. Need to create a new one */
+ if (bule->if_tunnel == 0
+ && hai->reg_mcoa
+ && get_bid_from_ifindex(hai->current_coa->iif)) {
+ MDBG("Creating new tunnel for iface %d (BID %d)\n",
+ hai->current_coa->iif,
+ get_bid_from_ifindex(hai->current_coa->iif));
+ bule->if_tunnel = tunnel_add(&hai->hoa.addr,
+ &hai->ha_addr,
+ hai->current_coa->iif,
+ NULL, NULL);
+ if (bule->if_tunnel <= 0) {
+ MDBG("Failed to create MN-HA tunnel\n");
+ return -1;
+ } else {
+ MDBG("MN-HA tunnel created (iface tnl = %d)\n",
+ bule->if_tunnel);
+ struct flag_hoa_args arg;
+ arg.target = hai;
+ arg.flag = 1;
+ arg.bule = bule;
+ if (addr_do(&hai->hoa.addr, 128,
+ bule->if_tunnel, &arg,
+ flag_hoa) < 0) {
+ MDBG("addr_do failed for tunnel %d\n",
+ bule->if_tunnel);
+ return -1;
+ }
+ }
+ } else if (bule->if_tunnel == 0)
+ /* MCoA
+ * If MCoA is not used, then initialise the tunnel
+ * number to the one in hai
+ */
+ bule->if_tunnel = hai->if_tunnel;
+
+ if ((err = mn_tnl_state_add(hai, bule->if_tunnel, 0, bule->table)) < 0)
MDBG("Failed to initialize new bule for HA\n");
else
MDBG("New bule for HA\n");
@@ -781,14 +1019,18 @@
movement_t type_movement = MIP6_TYPE_MOVEMENT_UNKNOWN;
TRACE;
+ assert(hai->current_coa);
if (IN6_IS_ADDR_UNSPECIFIED(&hai->ha_addr)) {
MDBG("HA not set for home link\n");
return;
}
- mn_get_home_lifetime(hai, &lifetime, 0);
+ mn_get_home_lifetime(hai, &lifetime, hai->current_coa->iif, 0);
- if ((bule = bul_get(hai, NULL, &hai->ha_addr)) == NULL) {
+ if ((bule = bul_get(hai, NULL, &hai->ha_addr,
+ hai->reg_mcoa?
+ get_bid_from_ifindex(hai->current_coa->iif)
+ :MCOA_NO_BID)) == NULL) {
assert(!hai->at_home);
/* Create new bul entry for HA */
if (!tsisset(lifetime)) {
@@ -807,14 +1049,22 @@
mn_change_ha(hai);
return;
}
- bule = create_bule(&hai->hoa.addr, &hai->ha_addr);
+ bule = create_bule(&hai->hoa.addr, &hai->ha_addr,
+ hai->reg_mcoa?
+ get_bid_from_ifindex(hai->current_coa->iif)
+ :MCOA_NO_BID);
if (bule == NULL)
return;
- if (process_first_home_bu(bule, hai, &lifetime) < 0 ||
+ if (mcoa_mn_init_rt_table(bule) < 0 ||
+ process_first_home_bu(bule, hai, &lifetime) < 0 ||
bul_add(bule) < 0) {
bul_delete(bule);
return;
}
+ /* MCoA: Check for interface reliability */
+ if(get_reliable_from_ifindex(bule->if_coa) > 0)
+ /* MCoA: Add the rules */
+ mcoa_iface_rules_add(hai->current_coa->iif, hai);
type_movement = MIP6_TYPE_MOVEMENT_HL2FL;
MDBG("New bule for HA\n");
} else if (bule->type == BUL_ENTRY) {
@@ -829,8 +1079,8 @@
}
type_movement = MIP6_TYPE_MOVEMENT_HL2FL;
} else {
- bule->coa = hai->primary_coa.addr;
- bule->if_coa = hai->primary_coa.iif;
+ bule->coa = hai->current_coa->addr;
+ bule->if_coa = hai->current_coa->iif;
/* Rate limiting home registration binding updates
is necessary for multihomed MNs */
@@ -850,6 +1100,10 @@
bule->callback = bu_resend;
}
bule->seq++;
+ /* MCoA: Check for interface reliability */
+ if(bule->home->reg_mcoa
+ && get_reliable_from_ifindex(bule->if_coa) == 0)
+ mcoa_iface_rules_del(bule->if_coa, bule->home, 1);
pre_bu_bul_update(bule);
MDBG("Bule for HA exists. Updating it.\n");
} else {
@@ -885,10 +1139,13 @@
&bule->hoa, bule);
}
}
+ /* MCoA: Update the current routing table */
+ hai->table = bule->table;
/* Before bul_iterate, tunnel modification should be done. */
- tunnel_mod(hai->if_tunnel, &hai->primary_coa.addr, &hai->ha_addr,
- hai->primary_coa.iif, mn_ext_tunnel_ops, hai);
-
+ bule->if_tunnel = tunnel_mod(bule->if_tunnel, &hai->current_coa->addr,
+ &hai->ha_addr, hai->current_coa->iif,
+ mn_ext_tunnel_ops, hai);
+ hai->if_tunnel = bule->if_tunnel;
bule->last_coa = bule->coa;
bule->coa_changed = 0;
@@ -1017,14 +1274,87 @@
return -1;
}
+static int mn_disable_mcoa(struct bulentry *bule)
+{
+/*
+ struct bulentry *bule_del;
+ struct home_addr_info *hai;
+ struct flag_hoa_args arg;
+ struct list_head *l, *tmp;
+ struct net_iface *best_iface = NULL;
+*/
+
+ /* MCoA TODO1: At the moment we simply exit */
+ MDBG("HA does not accept MCoA registration. Check "\
+ "your HA or change your MR configuration\n");
+ kill(0, SIGINT);
+ return 0;
+
+/*
+ assert(bule);
+ hai = bule->home;
+ mcoa_mn_rules_del(hai);
+ while((bule_del = bul_get(hai, NULL,
+ &bule->peer_addr, MCOA_NO_BID)))
+ bul_delete(bule_del);
+
+ hai->if_tunnel = tunnel_add(&hai->hoa.addr, &hai->ha_addr,
+ hai->if_home, NULL, NULL);
+ if (hai->if_tunnel <= 0) {
+ MDBG("failed to create MN-HA tunnel\n");
+ goto clean_err;
+ }
+
+ arg.target = hai;
+ arg.flag = 1;
+ if (addr_do(&hai->hoa.addr, 128, hai->if_tunnel,
+ &arg, flag_hoa) < 0)
+ goto clean_err;
+
+ nemo_mr_rules_del(hai);
+ hai->reg_mcoa = 0;
+ nemo_mr_rules_add(hai);
+ if (rule_add(NULL, RT6_TABLE_MIP6, IP6_RULE_PRIO_MIP6_HOA_OUT, 0,
+ RTN_UNICAST, &hai->hoa.addr,
+ 128, &in6addr_any, 0, FIB_RULE_FIND_SADDR) < 0)
+ goto clean_err;
+
+ list_for_each(l, &conf.net_ifaces) {
+ struct net_iface *iface = NULL;
+ iface = list_entry(l, struct net_iface, list);
+ if (!best_iface
+ || iface->mn_if_bidprio > best_iface->mn_if_bidprio)
+ best_iface = iface;
+ }
+ list_for_each_safe(l, tmp, &conf.net_ifaces) {
+ struct net_iface *iface = NULL;
+ iface = list_entry(l, struct net_iface, list);
+ if (iface != best_iface) {
+ MDBG("Deleting iface %d\n", iface->ifindex);
+ list_del(l);
+ }
+ }
+ return 1;
+
+clean_err:
+ rule_del(NULL, RT6_TABLE_MIP6,
+ IP6_RULE_PRIO_MIP6_HOA_OUT, 0, RTN_UNICAST,
+ &hai->hoa.addr, 128, &in6addr_any, 0, FIB_RULE_FIND_SADDR);
+ tunnel_del(hai->if_tunnel, NULL, NULL);
+
+ return 0;
+*/
+}
+
static void mn_recv_ba(const struct ip6_mh *mh, ssize_t len,
const struct in6_addr_bundle *in, int iif)
{
struct ip6_mh_binding_ack *ba;
+ struct ip6_mh_opt_bid *bui;
struct mh_options mh_opts;
struct bulentry *bule;
struct timespec now, ba_lifetime, br_adv;
- uint16_t seqno;
+ uint16_t seqno, bid;
TRACE;
@@ -1036,25 +1366,32 @@
ba = (struct ip6_mh_binding_ack *)mh;
pthread_rwlock_wrlock(&mn_lock);
- bule = bul_get(NULL, in->dst, in->src);
+
+ /* MCoA: Lookup in BA options for the BUI sub-option and the BID */
+ bui = mh_opt(&ba->ip6mhba_hdr, &mh_opts, IP6_MHOPT_BID);
+ bid = bui ? ntohs(bui->ip6mobid_bid) : MCOA_NO_BID;
+
+ bule = bul_get(NULL, in->dst, in->src, bid);
if (!bule || bule->type != BUL_ENTRY) {
MDBG("Got BA without corresponding BUL entry "
"from %x:%x:%x:%x:%x:%x:%x:%x "
"to home address %x:%x:%x:%x:%x:%x:%x:%x "
- "with coa %x:%x:%x:%x:%x:%x:%x:%x\n",
+ "with coa %x:%x:%x:%x:%x:%x:%x:%x"
+ "and bid %d\n",
NIP6ADDR(in->src),
NIP6ADDR(in->dst),
NIP6ADDR(in->local_coa != NULL ?
- in->local_coa : &in6addr_any));
+ in->local_coa : &in6addr_any),
+ bid);
pthread_rwlock_unlock(&mn_lock);
return;
}
dbg("Got BA from %x:%x:%x:%x:%x:%x:%x:%x "
"to home address %x:%x:%x:%x:%x:%x:%x:%x "
- "with coa %x:%x:%x:%x:%x:%x:%x:%x and status %d\n",
+ "with coa %x:%x:%x:%x:%x:%x:%x:%x, bid %d and status %d\n",
NIP6ADDR(in->src), NIP6ADDR(in->dst),
NIP6ADDR(in->local_coa != NULL ? in->local_coa : &in6addr_any),
- ba->ip6mhba_status);
+ bid, ba->ip6mhba_status);
dbg("Dumping corresponding BULE\n");
dbg_func(bule, dump_bule);
/* First check authenticator */
@@ -1076,6 +1413,17 @@
return;
}
}
+ /* MCoA: Check if BID matches */
+ if (bule->bid && !bui) {
+ /* The BACK did not have any BID suboption whereas
+ * we sent a BU with a BID option. MCoA is disabled
+ * on the node.
+ */
+ MDBG("Got BA with no BID option, disabling MCoA registration.\n");
+ mn_disable_mcoa(bule);
+ pthread_rwlock_unlock(&mn_lock);
+ return;
+ }
bule->do_send_bu = 0;
bule->consecutive_resends = 0;
clock_gettime(CLOCK_REALTIME, &now);
@@ -1086,11 +1434,18 @@
bule->seq = seqno + 1;
if (bule->flags & IP6_MH_BU_HOME)
mn_get_home_lifetime(bule->home,
- &bule->lifetime, 0);
+ &bule->lifetime,
+ bule->if_coa,
+ 0);
else
mn_get_ro_lifetime(bule->home,
&bule->lifetime, 0);
bule->callback = bu_resend;
+ /* MCoA: Check for interface reliability */
+ if(bule->home->reg_mcoa
+ && get_reliable_from_ifindex(bule->if_coa) == 0)
+ mcoa_iface_rules_del(bule->if_coa,
+ bule->home, 1);
pre_bu_bul_update(bule);
mn_send_bu_msg(bule);
bule->delay = conf.InitialBindackTimeoutReReg_ts;
@@ -1137,6 +1492,10 @@
tssetsec(ba_lifetime, ntohs(ba->ip6mhba_lifetime) << 2);
br_adv = ba_lifetime;
tsadd(bule->lastsent, ba_lifetime, bule->hard_expire);
+ /* MCoA: Check for interface reliability */
+ if(bule->home->reg_mcoa
+ && get_reliable_from_ifindex(bule->if_coa) == 0)
+ mcoa_iface_rules_add(bule->if_coa, bule->home);
if (!(bule->flags & IP6_MH_BU_HOME) || !conf.OptimisticHandoff)
post_ba_bul_update(bule);
if (bule->flags & IP6_MH_BU_HOME) {
@@ -1266,11 +1625,6 @@
return NULL;
}
-struct flag_hoa_args {
- struct home_addr_info *target;
- int flag;
-};
-
static int flag_hoa(struct ifaddrmsg *ifa, struct rtattr *rta_tb[], void *arg)
{
/*
@@ -1279,13 +1633,18 @@
struct flag_hoa_args *fhoa = arg;
struct home_addr_info *hai = fhoa->target;
+ struct bulentry *bule = fhoa->bule;
struct mn_addr *hoa = &hai->hoa;
struct in6_addr *addr = RTA_DATA(rta_tb[IFA_ADDRESS]);
struct timespec now;
uint32_t preferred;
uint32_t valid;
- int err;
- int plen = (ifa->ifa_index == hai->if_tunnel ? 128 : hai->plen);
+ int err, plen;
+
+ if (hai->reg_mcoa && bule != NULL)
+ plen = (ifa->ifa_index == bule->if_tunnel ? 128 : hai->plen);
+ else
+ plen = (ifa->ifa_index == hai->if_tunnel ? 128 : hai->plen);
clock_gettime(CLOCK_REALTIME, &now);
@@ -1321,6 +1680,220 @@
return 0;
}
+static int mcoa_iface_dflt_hoa_rule_del(struct bulentry *bule,
+ struct bulentry *best_bule,
+ struct home_addr_info *hai,
+ int replace)
+{
+ /* MCoA: Delete the default HoA rule */
+ rule_del(NULL, bule->bid, IP6_RULE_PRIO_MIP6_HOA_OUT,
+ 0, RTN_UNICAST, &hai->hoa.addr, 128,
+ &in6addr_any, 0, FIB_RULE_FIND_SADDR);
+
+ /* MCoA
+ * Do not replace the default rules
+ * if there are no other best bule
+ */
+ if(best_bule && best_bule != bule && replace) {
+ if (rule_add(NULL, best_bule->bid,
+ IP6_RULE_PRIO_MIP6_HOA_OUT, 0, RTN_UNICAST,
+ &hai->hoa.addr, 128, &in6addr_any, 0,
+ FIB_RULE_FIND_SADDR) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+static void mcoa_iface_dflt_mnp_rules_del(struct bulentry *bule,
+ struct bulentry *best_bule,
+ struct home_addr_info *hai,
+ struct prefix_list_entry *p,
+ int replace)
+{
+ /* MCoA: Delete the default MNP rule */
+ rule_del(NULL, bule->bid, IP6_RULE_PRIO_MIP6_FWD_MCOA,
+ 0, RTN_UNICAST, &p->ple_prefix, p->ple_plen,
+ &in6addr_any, 0, 0);
+
+ /* MCoA
+ * Do not replace the default rules
+ * if there are no other best bule
+ */
+ if(best_bule && best_bule != bule && replace) {
+ rule_add(NULL, best_bule->bid,
+ IP6_RULE_PRIO_MIP6_FWD_MCOA, 0, RTN_UNICAST,
+ &p->ple_prefix, p->ple_plen, &in6addr_any, 0, 0);
+ }
+}
+
+static struct bulentry* mcoa_iface_rules_del(int iif,
+ struct home_addr_info *hai,
+ int replace)
+{
+ uint16_t bid = hai->reg_mcoa?get_bid_from_ifindex(iif):MCOA_NO_BID;
+ uint8_t prio_tmp = 0;
+ struct bulentry *bule, *best_bule = NULL;
+ struct list_head *l;
+ int delete_dflt_mnp = 0;
+
+ bule = bul_get(hai, NULL, &hai->ha_addr, bid);
+ if (!hai->reg_mcoa || (bule && !bule->rules))
+ return NULL;
+
+ /* MCoA: Delete rule for HoA traffic from the MN */
+ rule_del(NULL, bid, IP6_RULE_PRIO_MIP6_HOA_OUT_MCOA,
+ /* fwmark */ bid, RTN_UNICAST,
+ &hai->hoa.addr, 128, &in6addr_any, 0,
+ FIB_RULE_FIND_SADDR);
+
+ bul_iterate_in(&hai->ha_addr, bul_highest_priority,
+ &best_bule);
+ if(bule && best_bule == bule) {
+ delete_dflt_mnp = 1;
+ /* MCoA: search for the next best BULE */
+ prio_tmp = bule->priority;
+ bule->priority = 0;
+ bul_iterate_in(&hai->ha_addr,
+ bul_highest_priority, &best_bule);
+ bule->priority = prio_tmp;
+ /* MCoA: delete the default HoA rule */
+ mcoa_iface_dflt_hoa_rule_del(bule, best_bule, hai, replace);
+ }
+
+ list_for_each(l, &hai->mob_net_prefixes) {
+ struct prefix_list_entry *p = NULL;
+ p = list_entry(l, struct prefix_list_entry, list);
+ /* MCoA: Delete MNP rule */
+ rule_del(NULL, bid, IP6_RULE_PRIO_MIP6_FWD_FWM,
+ /*fwmark*/ bid, RTN_UNICAST, &p->ple_prefix,
+ p->ple_plen, &in6addr_any, 0, 0);
+ if(delete_dflt_mnp) {
+ /* MCoA: Delete default MNP rule */
+ mcoa_iface_dflt_mnp_rules_del(bule, best_bule,
+ hai, p, replace);
+ }
+ }
+
+ if (bule) {
+ bule->rules = 0;
+ MDBG("MNP and HoA rules deleted for iface %d bid %d\n",
+ iif, bule->bid);
+ }
+
+ return bule;
+}
+
+static void mcoa_mn_rules_del(struct home_addr_info *hinfo)
+{
+ struct list_head *l;
+
+ list_for_each(l, &hinfo->mcoa) {
+ struct mn_addr *iface = NULL;
+ iface = list_entry(l, struct mn_addr, list);
+ mcoa_iface_rules_del(iface->iif, hinfo, 0);
+ }
+ rule_del(NULL, 0, IP6_RULE_PRIO_MIP6_HOA_OUT,
+ 0, RTN_UNICAST, &hinfo->hoa.addr, 128,
+ &in6addr_any, 0, FIB_RULE_FIND_SADDR);
+ if (hinfo->at_home && hinfo->reg_mcoa) {
+ 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, 0,
+ RTN_UNICAST, &p->ple_prefix,
+ p->ple_plen, &in6addr_any, 0, 0);
+ }
+ }
+}
+
+static int mcoa_iface_rules_add(int iif, struct home_addr_info *hai)
+{
+ uint16_t bid = hai->reg_mcoa?get_bid_from_ifindex(iif):MCOA_NO_BID;
+ struct bulentry *bule, *best_bule = NULL;
+ struct prefix_list_entry *pe = NULL;
+ struct list_head *l;
+ uint8_t prio;
+
+ bule = bul_get(hai, NULL, &hai->ha_addr, bid);
+ if (!bid || !hai->reg_mcoa || !bule || (bule && bule->rules))
+ return 0;
+
+ prio = get_prio_from_bid(bid);
+
+ /* MCoA: Rule for HoA traffic from the MN */
+ if (rule_add(NULL, bid, IP6_RULE_PRIO_MIP6_HOA_OUT_MCOA,
+ /* fwmark */ bid, RTN_UNICAST,
+ &hai->hoa.addr, 128, &in6addr_any, 0,
+ FIB_RULE_FIND_SADDR) < 0)
+ goto undo;
+
+ bul_iterate_in(&hai->ha_addr, bul_highest_priority,
+ &best_bule);
+
+ if (!best_bule || prio >= best_bule->priority) {
+ rule_del(NULL, 0, IP6_RULE_PRIO_MIP6_HOA_OUT,
+ 0, RTN_UNICAST, &hai->hoa.addr, 128,
+ &in6addr_any, 0, FIB_RULE_FIND_SADDR);
+ if (rule_add(NULL, bid, IP6_RULE_PRIO_MIP6_HOA_OUT,
+ 0, RTN_UNICAST, &hai->hoa.addr, 128,
+ &in6addr_any, 0, FIB_RULE_FIND_SADDR) < 0)
+ goto undo;
+ }
+
+ /* MCoA: Rule for forwarded traffic from the NEMO */
+ list_for_each(l, &hai->mob_net_prefixes) {
+ struct prefix_list_entry *p = NULL;
+ p = list_entry(l, struct prefix_list_entry, list);
+ if (rule_add(NULL, bid, IP6_RULE_PRIO_MIP6_FWD_FWM,
+ /*fwmark*/ bid, RTN_UNICAST,
+ &p->ple_prefix, p->ple_plen,
+ &in6addr_any, 0, 0) < 0) {
+ pe = p;
+ goto undo;
+ }
+ /* MCoA
+ * Add default rules if the bule has the highest
+ * priority
+ */
+ if (!best_bule || prio >= best_bule->priority) {
+ rule_del(NULL, 0, IP6_RULE_PRIO_MIP6_FWD_MCOA,
+ 0, RTN_UNICAST, &p->ple_prefix, p->ple_plen,
+ &in6addr_any, 0, 0);
+ if (rule_add(NULL, bid, IP6_RULE_PRIO_MIP6_FWD_MCOA,
+ 0, RTN_UNICAST, &p->ple_prefix, p->ple_plen,
+ &in6addr_any, 0, 0) < 0)
+ goto undo;
+ }
+ }
+
+ bule->rules = 1;
+ MDBG("MNP and HoA Rules added for interface %d.\n", iif);
+ return 0;
+
+undo:
+ rule_del(NULL, bid, IP6_RULE_PRIO_MIP6_HOA_OUT_MCOA,
+ /* fwmark */ bid, RTN_UNICAST,
+ &hai->hoa.addr, 128, &in6addr_any, 0,
+ FIB_RULE_FIND_SADDR);
+
+ rule_del(NULL, bid, IP6_RULE_PRIO_MIP6_HOA_OUT,
+ 0, RTN_UNICAST, &hai->hoa.addr, 128,
+ &in6addr_any, 0, FIB_RULE_FIND_SADDR);
+
+ list_for_each(l, &hai->mob_net_prefixes) {
+ struct prefix_list_entry *p = NULL;
+ p = list_entry(l, struct prefix_list_entry, list);
+ rule_del(NULL, bid, IP6_RULE_PRIO_MIP6_FWD_FWM,
+ /*fwmark*/ bid, RTN_UNICAST, &p->ple_prefix,
+ p->ple_plen, &in6addr_any, 0, 0);
+ if (p == pe)
+ break;
+ }
+ return -1;
+}
+
static void nemo_mr_rules_del(struct home_addr_info *hinfo)
{
struct list_head *l;
@@ -1328,11 +1901,17 @@
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);
+ if (hinfo->reg_mcoa) {
+ rule_del(NULL, 0, IP6_RULE_PRIO_MIP6_FWD_MCOA, 0,
+ RTN_UNICAST, &p->ple_prefix, p->ple_plen,
+ &in6addr_any, 0, 0);
+ } else
+ rule_del(NULL, RT6_TABLE_MIP6,
+ IP6_RULE_PRIO_MIP6_FWD, 0, 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,
+ IP6_RULE_PRIO_MIP6_MNP_IN, 0, RTN_UNICAST,
&in6addr_any, 0, &p->ple_prefix, p->ple_plen, 0);
}
}
@@ -1346,19 +1925,21 @@
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,
+ IP6_RULE_PRIO_MIP6_MNP_IN, 0, 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) {
+ if (!hinfo->reg_mcoa
+ && rule_add(NULL, RT6_TABLE_MIP6,
+ IP6_RULE_PRIO_MIP6_FWD, 0, 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);
+ IP6_RULE_PRIO_MIP6_MNP_IN, 0,
+ RTN_UNICAST, &in6addr_any, 0,
+ &p->ple_prefix, p->ple_plen, 0);
pe = p;
goto undo;
}
@@ -1368,11 +1949,14 @@
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);
+ if (!hinfo->reg_mcoa) {
+ rule_del(NULL, RT6_TABLE_MIP6,
+ IP6_RULE_PRIO_MIP6_FWD, 0, 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,
+ IP6_RULE_PRIO_MIP6_MNP_IN, 0, RTN_UNICAST,
&in6addr_any, 0, &p->ple_prefix, p->ple_plen, 0);
if (p == pe)
break;
@@ -1380,6 +1964,11 @@
return -1;
}
+struct mcoa_tnl_id {
+ struct list_head list;
+ int tnl_id;
+};
+
static void clean_home_addr_info(struct home_addr_info *hai)
{
struct flag_hoa_args arg;
@@ -1390,17 +1979,24 @@
nemo_mr_rules_del(hai);
arg.target = hai;
arg.flag = 0;
- addr_do(&hai->hoa.addr, plen,
- hai->hoa.iif, &arg, flag_hoa);
+ /* MCoA: Flag HoA on the tunnel iface is not necessary here */
+ if (!hai->reg_mcoa)
+ addr_do(&hai->hoa.addr, plen,
+ hai->hoa.iif, &arg, flag_hoa);
bul_iterate(&hai->bul, mn_dereg, NULL);
- bul_home_cleanup(&hai->bul);
-
+ /* MCoA: Delete all mn rules */
+ if (hai->reg_mcoa)
+ mcoa_mn_rules_del(hai);
mn_block_rule_del(hai);
- rule_del(NULL, RT6_TABLE_MIP6,
- IP6_RULE_PRIO_MIP6_HOA_OUT, RTN_UNICAST,
- &hai->hoa.addr, 128, &in6addr_any, 0, FIB_RULE_FIND_SADDR);
- tunnel_del(hai->if_tunnel, NULL, NULL);
+ if (!hai->reg_mcoa) {
+ rule_del(NULL, RT6_TABLE_MIP6,
+ IP6_RULE_PRIO_MIP6_HOA_OUT, 0, RTN_UNICAST,
+ &hai->hoa.addr, 128, &in6addr_any, 0,
+ FIB_RULE_FIND_SADDR);
+ tunnel_del(hai->if_tunnel, NULL, NULL);
+ }
+ bul_home_cleanup(&hai->bul);
dhaad_stop(hai);
free(hai);
}
@@ -1448,6 +2044,11 @@
&hai->mob_net_prefixes) < 0)
goto mutex_undo;
+ INIT_LIST_HEAD(&hai->mcoa);
+ if (hai->reg_mcoa &&
+ prefix_list_copy(&conf_hai->mcoa, &hai->mcoa) < 0)
+ goto mutex_undo;
+
INIT_LIST_HEAD(&hai->ro_policies);
if (rpl_copy(&conf_hai->ro_policies, &hai->ro_policies) < 0)
goto mnp_undo;
@@ -1493,17 +2094,22 @@
MDBG("HA address %x:%x:%x:%x:%x:%x:%x:%x\n",
NIP6ADDR(&hai->ha_addr));
}
- hai->if_tunnel = tunnel_add(&hai->hoa.addr, &hai->ha_addr,
- hai->if_home, NULL, NULL);
-
- if (hai->if_tunnel <= 0) {
- MDBG("failed to create MN-HA tunnel\n");
- goto clean_err;
- }
- if (rule_add(NULL, RT6_TABLE_MIP6,
- IP6_RULE_PRIO_MIP6_HOA_OUT, RTN_UNICAST,
- &hai->hoa.addr, 128, &in6addr_any, 0, FIB_RULE_FIND_SADDR) < 0) {
- goto clean_err;
+ /* MCoA: tunnel is created only if MCoA registration is not used */
+ if(!hai->reg_mcoa) {
+ hai->if_tunnel = tunnel_add(&hai->hoa.addr,
+ &hai->ha_addr,
+ hai->if_home, NULL, NULL);
+
+ if (hai->if_tunnel <= 0) {
+ MDBG("failed to create MN-HA tunnel\n");
+ goto clean_err;
+ }
+ if (rule_add(NULL, RT6_TABLE_MIP6,
+ IP6_RULE_PRIO_MIP6_HOA_OUT, 0, RTN_UNICAST,
+ &hai->hoa.addr, 128, &in6addr_any, 0,
+ FIB_RULE_FIND_SADDR) < 0) {
+ goto clean_err;
+ }
}
if (mn_block_rule_add(hai) < 0)
@@ -1524,16 +2130,25 @@
PREFIX_LIFETIME_INFINITE,
PREFIX_LIFETIME_INFINITE);
- arg.target = hai;
- arg.flag = 1;
-
- if (addr_do(&hai->hoa.addr, 128,
- hai->if_tunnel, &arg, flag_hoa) < 0) {
- goto clean_err;
+ /* MCoA */
+ if(!hai->reg_mcoa) {
+ arg.target = hai;
+ arg.flag = 1;
+
+ if (addr_do(&hai->hoa.addr, 128,
+ hai->if_tunnel, &arg, flag_hoa) < 0) {
+ goto clean_err;
+ }
}
if (hai->mob_rtr && nemo_mr_rules_add(hai) < 0) {
goto clean_err;
}
+ /* MCoA TODO1
+ * For Home-CoA support, hai->at_home must be initialized to 0
+ * if(hai->reg_mcoa) hai->at_home = 0;
+ * BUT Home-CoA solution seems to be deprecated by the no-NDP
+ * solution
+ */
hai->at_home = hai->hoa.iif == hai->if_home;
pthread_rwlock_wrlock(&mn_lock);
list_add(&hai->list, &home_addr_list);
@@ -1635,7 +2250,11 @@
if (!hai->at_home) {
struct bulentry *e;
- e = bul_get(hai, NULL, &hai->ha_addr);
+ /* MCoA TODO1
+ * Do the same for all entries that match &hai->ha_addr
+ */
+ e = bul_get(hai, NULL, &hai->ha_addr, MCOA_NO_BID);
+
if (e == NULL || !(e->flags & IP6_MH_BU_HOME))
return -ENOENT;
@@ -1668,8 +2287,9 @@
return ret;
hai = mn_get_home_addr(hoa);
if (hai) {
- *coa = hai->primary_coa.addr;
- ret = hai->primary_coa.iif;
+ assert(hai->current_coa);
+ *coa = hai->current_coa->addr;
+ ret = hai->current_coa->iif;
} else {
MDBG("Failed to find a home address info\n");
ret = -1;
@@ -1683,14 +2303,14 @@
static inline void linklocal_rt_rules_del(void)
{
rule_del(NULL, RT6_TABLE_MAIN,
- IP6_RULE_PRIO_MIP6_COA_OUT, RTN_UNICAST,
+ IP6_RULE_PRIO_MIP6_COA_OUT, 0, RTN_UNICAST,
&linklocal_prefix, 64, &in6addr_any, 0, 0);
}
static inline int linklocal_rt_rules_add(void)
{
return rule_add(NULL, RT6_TABLE_MAIN,
- IP6_RULE_PRIO_MIP6_COA_OUT, RTN_UNICAST,
+ IP6_RULE_PRIO_MIP6_COA_OUT, 0, RTN_UNICAST,
&linklocal_prefix, 64, &in6addr_any, 0, 0);
}
@@ -1705,12 +2325,13 @@
mha.if_next = new_if;
mha.target = hai;
+ /* MCoA: Update state for the correct table (hai->table) */
if (hai->hoa.iif == old_if &&
- (mn_tnl_state_add(hai, new_if, 1) ||
+ (mn_tnl_state_add(hai, new_if, 1, hai->table) ||
addr_do(&hai->hoa.addr, 128, old_if, &mha, mv_hoa) < 0))
goto undo;
- mn_tnl_state_del(hai, old_if, 1);
+ mn_tnl_state_del(hai, old_if, 1, hai->table);
hai->if_tunnel = new_if;
return 0;
undo:
@@ -1718,28 +2339,52 @@
if (hai->hoa.iif == new_if)
addr_do(&hai->hoa.addr, 128, new_if, &mha, mv_hoa);
- mn_tnl_state_del(hai, new_if, 1);
+ mn_tnl_state_del(hai, new_if, 1, hai->table);
return -1;
}
static int mn_move(struct home_addr_info *hai)
{
struct mv_hoa_args mha;
+ struct list_head *l;
mha.target = hai;
TRACE;
+ assert(hai->current_coa);
if (hai->at_home) {
int plen = (hai->hoa.iif == hai->if_tunnel ? 128 : hai->plen);
struct bulentry *e;
MDBG("in home net\n");
+ /* MCoA
+ * If we are in the home network, add a rule to
+ * RT6_TABLE_MIP6 to allow routing of the packets from
+ * the MNNs (routes in RT6_TABLE_MIP6 are
+ * added/deleted in movement.c/md_update_router_stats,
+ * __md_free_router) and the MR.
+ */
+ if (hai->reg_mcoa) {
+ list_for_each(l, &hai->mob_net_prefixes) {
+ struct prefix_list_entry *p = NULL;
+ p = list_entry(l, struct prefix_list_entry,
+ list);
+ rule_add(NULL, RT6_TABLE_MIP6,
+ IP6_RULE_PRIO_MIP6_FWD, 0,
+ RTN_UNICAST, &p->ple_prefix,
+ p->ple_plen, &in6addr_any, 0, 0);
+ }
+ }
if (hai->home_reg_status == HOME_REG_NONE &&
- (e = bul_get(hai, NULL, &hai->ha_addr)) != NULL &&
+ (e = bul_get(hai, NULL, &hai->ha_addr,
+ hai->reg_mcoa?
+ get_bid_from_ifindex(hai->current_coa->iif)
+ :MCOA_NO_BID))
+ != NULL &&
e->flags & IP6_MH_BU_HOME && e->type != BUL_ENTRY)
bul_delete(e);
- if (hai->hoa.iif != hai->primary_coa.iif) {
- mha.if_next = hai->primary_coa.iif;
+ if (hai->hoa.iif != hai->current_coa->iif) {
+ mha.if_next = hai->current_coa->iif;
addr_do(&hai->hoa.addr, plen,
hai->hoa.iif, &mha, mv_hoa);
if (hai->home_reg_status == HOME_REG_NONE) {
@@ -1760,10 +2405,33 @@
hai->pend_ba = 0;
pending_bas--;
}
+ /* MCoA
+ * When in a foreign network, delete the
+ * rules to RT6_TABLE_MIP6
+ */
+ if (hai->reg_mcoa) {
+ list_for_each(l, &hai->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, 0,
+ RTN_UNICAST, &p->ple_prefix,
+ p->ple_plen, &in6addr_any, 0, 0);
+ }
+ }
if (hai->hoa.iif != hai->if_tunnel) {
mha.if_next = hai->if_tunnel;
- addr_do(&hai->hoa.addr, hai->plen,
- hai->hoa.iif, &mha, mv_hoa);
+ /* MCoA
+ * HoA is moved if we do not use MCoA,
+ * HoA is copied if we use MCoA
+ */
+ if (hai->reg_mcoa)
+ addr_do(&hai->hoa.addr, hai->plen,
+ hai->hoa.iif, &mha, cp_hoa);
+ else
+ addr_do(&hai->hoa.addr, hai->plen,
+ hai->hoa.iif, &mha, mv_hoa);
}
do_handoff(hai);
}
@@ -1951,6 +2619,7 @@
struct in6_addr solicit;
int type = FLUSH_ALL;
+ assert(hai->current_coa);
if ((sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0)
return ret;
@@ -1963,22 +2632,22 @@
sizeof(struct icmp6_filter));
ipv6_addr_solict_mult(&hai->hoa.addr, &solicit);
- if_mc_group(sock, hai->primary_coa.iif, &in6addr_all_nodes_mc,
+ if_mc_group(sock, hai->current_coa->iif, &in6addr_all_nodes_mc,
IPV6_JOIN_GROUP);
- if_mc_group(sock, hai->primary_coa.iif, &solicit, IPV6_JOIN_GROUP);
+ if_mc_group(sock, hai->current_coa->iif, &solicit, IPV6_JOIN_GROUP);
if (hai->home_reg_status == HOME_REG_NONE) {
if (hai->lladdr_comp) {
struct in6_addr lladdr;
ipv6_addr_llocal(&hai->hoa.addr, &lladdr);
if (mn_addr_do_dad(sock, NULL, &lladdr, 64,
- hai->primary_coa.iif, 0) < 0) {
+ hai->current_coa->iif, 0) < 0) {
MDBG("Link-local DAD failed!\n");
goto err;
}
}
if (mn_addr_do_dad(sock, hai, &hai->hoa.addr, hai->plen,
- hai->primary_coa.iif, 0) < 0) {
+ hai->current_coa->iif, 0) < 0) {
MDBG("HoA DAD failed!\n");
goto err;
}
@@ -1986,7 +2655,7 @@
mn_send_home_na(hai);
ret = mn_move(hai);
} else if (!mn_addr_do_dad(sock, hai, &hai->hoa.addr,
- hai->plen, hai->primary_coa.iif, 1)) {
+ hai->plen, hai->current_coa->iif, 1)) {
ret = mn_move(hai);
}
out:
@@ -2009,15 +2678,19 @@
static void mn_coa_updated(struct home_addr_info *hai)
{
+ assert(hai->current_coa);
if (!hai->at_home) {
struct bulentry *e;
struct mn_addr *coa;
- e = bul_get(hai, NULL, &hai->ha_addr);
+ e = bul_get(hai, NULL, &hai->ha_addr,
+ hai->reg_mcoa?
+ get_bid_from_ifindex(hai->current_coa->iif)
+ :MCOA_NO_BID);
if (e == NULL || !(e->flags & IP6_MH_BU_HOME))
return;
- coa = &hai->primary_coa;
+ coa = hai->current_coa;
MDBG2("preferred_time %u valid_life %u\n",
coa->preferred_time.tv_sec,
@@ -2075,6 +2748,10 @@
list_for_each(l, iface_list) {
struct md_inet6_iface *iface;
iface = list_entry(l, struct md_inet6_iface, list);
+ /* MCoA TODO1
+ * If MCoA is used, MCoA preference must be used instead
+ * of interfaces preference
+ */
if (mn_verify_iface(iface) &&
(best_iface == NULL ||
(best_iface)->preference > iface->preference ||
@@ -2119,6 +2796,106 @@
return best_coa;
}
+static int mcoa_mn_make_ho_verdict(const struct movement_event *me,
+ const struct home_addr_info *hai,
+ struct md_router **next_rtr,
+ struct md_coa **next_coa)
+{
+ /* MCoA
+ * The handoff algorithm is different from
+ * mn_make_ho_verdict because we do not perform vertical
+ * handover, but only horizontal handovers.
+ */
+ struct md_router *rtr;
+ struct md_coa *coa = NULL;
+ int force = 0;
+
+ /* MCoA TODO1
+ * For Home-CoA support, remove this if(){}
+ * BUT Home-CoA seems to be deprecated
+ */
+ if (me->iface != NULL &&
+ (rtr = md_get_first_router(&me->iface->default_rtr)) != NULL &&
+ mn_is_at_home(&rtr->prefixes, &hai->home_prefix, hai->home_plen)) {
+ *next_rtr = rtr;
+ *next_coa = NULL;
+ return MN_HO_RETURN_HOME;
+ }
+ switch (me->event_type) {
+ case ME_DHAAD:
+ force = 1;
+ break;
+ case ME_IFACE_DOWN:
+ case ME_LINK_DOWN:
+ case ME_RTR_EXPIRED:
+ break;
+ case ME_RTR_NEW:
+ assert(!list_empty(&me->iface->default_rtr));
+ case ME_LINK_UP:
+ assert(me->iface != NULL);
+ break;
+ case ME_RTR_BACK:
+ case ME_RTR_UPDATED:
+ assert(me->iface != NULL);
+ assert(!list_empty(&me->iface->default_rtr));
+
+ *next_coa = md_get_coa(&me->iface->coas,
+ &hai->current_coa->addr);
+ if (*next_coa == NULL)
+ break;
+ *next_rtr = md_get_first_router(&me->iface->default_rtr);
+ return MN_HO_REESTABLISH;
+ case ME_COA_NEW:
+ assert(me->iface != NULL);
+ assert(me->coa != NULL);
+ assert(me->iface->ifindex == me->coa->ifindex);
+ break;
+ case ME_COA_EXPIRED:
+ assert(me->iface != NULL);
+ assert(me->coa != NULL);
+ assert(me->iface->ifindex == me->coa->ifindex);
+
+ if (IN6_ARE_ADDR_EQUAL(&hai->current_coa->addr,
+ &me->coa->addr))
+ break;
+ return MN_HO_IGNORE;
+ case ME_COA_LFT_DEC:
+ case ME_COA_LFT_INC:
+ assert(me->iface != NULL);
+ assert(me->coa != NULL);
+ assert(me->iface->ifindex == me->coa->ifindex);
+
+ if (!IN6_ARE_ADDR_EQUAL(&hai->current_coa->addr,
+ &me->coa->addr)) {
+ return MN_HO_IGNORE;
+ }
+
+ *next_coa = me->coa;
+ return MN_HO_CHECK_LIFETIME;
+ default:
+ return MN_HO_IGNORE;
+ }
+ if (!mn_verify_iface(me->iface))
+ return MN_HO_INVALIDATE;
+
+ coa = mn_get_coa(hai, me->iface->ifindex,
+ &hai->current_coa->addr, &me->iface->coas);
+
+ if (coa == NULL)
+ return MN_HO_INVALIDATE;
+
+ if (!force &&
+ IN6_ARE_ADDR_EQUAL(&coa->addr, &hai->current_coa->addr))
+ return MN_HO_IGNORE;
+
+ if (list_empty(&me->iface->default_rtr))
+ return MN_HO_IGNORE;
+
+ *next_rtr = md_get_first_router(&me->iface->default_rtr);
+ *next_coa = coa;
+ return MN_HO_PROCEED;
+}
+
static int mn_make_ho_verdict(const struct movement_event *me,
const struct home_addr_info *hai,
struct md_router **next_rtr,
@@ -2127,9 +2904,11 @@
struct md_inet6_iface *old_iface = NULL, *new_iface = NULL;
struct md_router *rtr;
struct md_coa *coa = NULL;
- int pref_iif = hai->primary_coa.iif; /* prefer current CoA interface */
+ int pref_iif;
int force = 0;
+ assert(hai->current_coa);
+ pref_iif = hai->current_coa->iif; /* prefer current CoA interface */
if (me->iface != NULL &&
(rtr = md_get_first_router(&me->iface->default_rtr)) != NULL &&
mn_is_at_home(&rtr->prefixes, &hai->home_prefix, hai->home_plen)) {
@@ -2170,7 +2949,7 @@
return MN_HO_IGNORE;
*next_coa = md_get_coa(&old_iface->coas,
- &hai->primary_coa.addr);
+ &hai->current_coa->addr);
if (*next_coa == NULL)
break;
*next_rtr = md_get_first_router(&old_iface->default_rtr);
@@ -2187,7 +2966,7 @@
if (old_iface == NULL ||
(old_iface == me->iface &&
- IN6_ARE_ADDR_EQUAL(&hai->primary_coa.addr,
+ IN6_ARE_ADDR_EQUAL(&hai->current_coa->addr,
&me->coa->addr)))
break;
return MN_HO_IGNORE;
@@ -2201,7 +2980,7 @@
break;
if (old_iface != me->iface ||
- !IN6_ARE_ADDR_EQUAL(&hai->primary_coa.addr,
+ !IN6_ARE_ADDR_EQUAL(&hai->current_coa->addr,
&me->coa->addr))
return MN_HO_IGNORE;
@@ -2216,13 +2995,13 @@
return MN_HO_INVALIDATE;
coa = mn_get_coa(hai, new_iface->ifindex,
- &hai->primary_coa.addr, &new_iface->coas);
+ &hai->current_coa->addr, &new_iface->coas);
if (coa == NULL)
return MN_HO_INVALIDATE;
if (!force && new_iface == old_iface &&
- IN6_ARE_ADDR_EQUAL(&coa->addr, &hai->primary_coa.addr))
+ IN6_ARE_ADDR_EQUAL(&coa->addr, &hai->current_coa->addr))
return MN_HO_IGNORE;
if (list_empty(&new_iface->default_rtr))
@@ -2233,6 +3012,100 @@
return MN_HO_PROCEED;
}
+static void mcoa_mn_chk_ho_verdict(struct home_addr_info *hai,
+ const struct movement_event *event)
+{
+ struct md_router *rtr = NULL;
+ struct md_coa *coa = NULL;
+ struct bulentry *bule;
+ int move_home = 0;
+ int active_coa = 0;
+
+ if ((bule = bul_get(hai, NULL, &hai->ha_addr,
+ hai->reg_mcoa?
+ get_bid_from_ifindex(event->iface->ifindex)
+ :MCOA_NO_BID)))
+ active_coa = mcoa_bule_count(bule);
+
+ if (event->event_type == ME_COA_EXPIRED &&
+ IN6_ARE_ADDR_EQUAL(&event->coa->addr, &hai->hoa.addr))
+ return;
+
+ hai->current_coa = mcoa_get_current_coa(hai, event->iface->ifindex);
+ if (hai->current_coa == NULL)
+ return;
+
+ hai->verdict = mcoa_mn_make_ho_verdict(event, hai, &rtr, &coa);
+ MDBG2("Verdict %d for iface %d\n",
+ hai->verdict, hai->current_coa->iif);
+
+ if (hai->verdict == MN_HO_IGNORE)
+ return;
+
+ if (hai->verdict == MN_HO_INVALIDATE) {
+ /* MCoA
+ * Unless this is the last available interface
+ * Rules related to this iface are deleted,
+ * BULE is deleted, and deregistration BU is sent
+ */
+ if (active_coa > 1
+ && (bule = mcoa_iface_rules_del(hai->current_coa->iif,
+ hai, 1)))
+ /* MCoA TODO2
+ * Send a deregistration BU
+ * Is it the correct place to do that?
+ * because when BACK is received, BULE has
+ * already been deleted
+ * (actually BAck cannot be received at the BULE's CoA
+ * because the iface is down...)
+ */
+ mn_dereg_bule(bule);
+ hai->current_coa = NULL;
+ return;
+ }
+ if (rtr != NULL)
+ move_home = mn_home_rtr_chk(hai, rtr);
+
+ if (hai->verdict == MN_HO_CHECK_LIFETIME) {
+ mn_update_coa_lifetime(hai->current_coa, coa);
+ mn_coa_updated(hai);
+ } else if (hai->verdict == MN_HO_REESTABLISH) {
+ mn_update_coa_lifetime(hai->current_coa, coa);
+ mn_coa_updated(hai);
+ } else {
+ switch (hai->verdict) {
+ case MN_HO_PROCEED:
+ hai->current_coa->addr = coa->addr;
+ mn_update_coa_lifetime(hai->current_coa, coa);
+ /* MCoA
+ * Rules related to this iface are added if needed
+ */
+ mcoa_iface_rules_add(hai->current_coa->iif, hai);
+ break;
+ case MN_HO_RETURN_HOME:
+ hai->current_coa->addr = hai->hoa.addr;
+ mcoa_iface_rules_del(hai->current_coa->iif, hai, 1);
+ break;
+ default:
+ return;
+ }
+ if (hai->at_home && !hai->pend_ba) {
+ /* check if router is HA */
+ if (hai->home_reg_status != HOME_REG_NONE &&
+ rtr_addr_chk(rtr, &hai->ha_addr)) {
+ mn_move(hai);
+ } else if (hai->home_reg_status != HOME_REG_NONE ||
+ move_home) {
+ int type = FLUSH_FAILED;
+ mn_do_dad(hai, 0);
+ if (hai->home_reg_status == HOME_REG_NONE)
+ bul_iterate(&hai->bul,
+ _bul_flush, &type);
+ }
+ }
+ }
+}
+
static void mn_chk_ho_verdict(struct home_addr_info *hai,
const struct movement_event *event)
{
@@ -2244,35 +3117,36 @@
IN6_ARE_ADDR_EQUAL(&event->coa->addr, &hai->hoa.addr))
return;
+ assert(hai->current_coa);
hai->verdict = mn_make_ho_verdict(event, hai, &rtr, &coa);
if (hai->verdict == MN_HO_IGNORE)
return;
if (hai->verdict == MN_HO_INVALIDATE) {
- hai->primary_coa.iif = 0;
+ hai->current_coa->iif = 0;
return;
}
if (rtr != NULL)
move_home = mn_home_rtr_chk(hai, rtr);
if (hai->verdict == MN_HO_CHECK_LIFETIME) {
- mn_update_coa_lifetime(&hai->primary_coa, coa);
+ mn_update_coa_lifetime(hai->current_coa, coa);
mn_coa_updated(hai);
} else if (hai->verdict == MN_HO_REESTABLISH) {
- hai->primary_coa.iif = coa->ifindex;
- mn_update_coa_lifetime(&hai->primary_coa, coa);
+ hai->current_coa->iif = coa->ifindex;
+ mn_update_coa_lifetime(hai->current_coa, coa);
mn_coa_updated(hai);
} else {
switch (hai->verdict) {
case MN_HO_PROCEED:
- hai->primary_coa.iif = coa->ifindex;
- hai->primary_coa.addr = coa->addr;
- mn_update_coa_lifetime(&hai->primary_coa, coa);
+ hai->current_coa->iif = coa->ifindex;
+ hai->current_coa->addr = coa->addr;
+ mn_update_coa_lifetime(hai->current_coa, coa);
break;
case MN_HO_RETURN_HOME:
- hai->primary_coa.iif = rtr->ifindex;
- hai->primary_coa.addr = hai->hoa.addr;
+ hai->current_coa->iif = rtr->ifindex;
+ hai->current_coa->addr = hai->hoa.addr;
break;
default:
return;
@@ -2311,14 +3185,20 @@
return 0;
}
dhaad_stop(hai);
- mn_chk_ho_verdict(hai, event);
+ if (hai->reg_mcoa)
+ mcoa_mn_chk_ho_verdict(hai, event);
+ else
+ mn_chk_ho_verdict(hai, event);
} else {
if (event->event_type == ME_COA_EXPIRED)
mn_rr_delete_co(&event->coa->addr);
list_for_each(lh, &home_addr_list) {
hai = list_entry(lh,
struct home_addr_info, list);
- mn_chk_ho_verdict(hai, event);
+ if (hai->reg_mcoa)
+ mcoa_mn_chk_ho_verdict(hai, event);
+ else
+ mn_chk_ho_verdict(hai, event);
}
}
}
@@ -2397,7 +3277,9 @@
"from %x:%x:%x:%x:%x:%x:%x:%x\n",
NIP6ADDR(cn), NIP6ADDR(hoa));
- bule = bul_get(NULL, hoa, cn);
+ bule = bul_get(NULL, hoa, cn,
+ hai->reg_mcoa?
+ get_bid_from_ifindex(iif):MCOA_NO_BID);
if (bule) {
/* If BUL entry exists, RR is done or in progress */
@@ -2405,7 +3287,9 @@
return;
}
- bule = create_bule(hoa, cn);
+ bule = create_bule(hoa, cn,
+ hai->reg_mcoa?
+ get_bid_from_ifindex(iif):MCOA_NO_BID);
if (!bule) {
MDBG("Malloc failed at starting of RO\n");
pthread_rwlock_unlock(&mn_lock);
@@ -2419,6 +3303,18 @@
bule->coa_changed = -1;
bule->home = hai;
bule->rr.state = RR_NOT_STARTED;
+ bule->priority = get_prio_from_bid(bule->bid);
+ /* MCoA TODO2
+ * At the moment we prevent MIPL from installing rules for
+ * this entry
+ */
+ bule->rules = 1;
+ /* MCoA TODO2
+ * Support for CN
+ * The table index must be filled with
+ * mcoa_mn_init_rt_table(bule)
+ */
+ bule->table = RT6_TABLE_MIP6;
mn_reset_ro_bule(bule);
@@ -2451,7 +3347,10 @@
hoa = in->dst;
pthread_rwlock_wrlock(&mn_lock);
/* Do we have BUL entry for cn? If not, drop. */
- if ((e = bul_get(NULL, hoa, cn)) == NULL) {
+ /* MCoA TODO2
+ * get BID from BRR BUI option
+ */
+ if ((e = bul_get(NULL, hoa, cn, get_bid_from_ifindex(iif))) == NULL) {
pthread_rwlock_unlock(&mn_lock);
return;
}
@@ -2499,7 +3398,11 @@
hoa = in->dst;
/* Do we have BUL entry for cn? If not, drop. */
- if ((e = bul_get(NULL, hoa, cn)) == NULL || e->type != BUL_ENTRY)
+ /* MCoA TODO2
+ * get BID from BUI option in BERROR
+ */
+ if ((e = bul_get(NULL, hoa, cn, get_bid_from_ifindex(iif))) == NULL
+ || e->type != BUL_ENTRY)
goto out;
clock_gettime(CLOCK_REALTIME, &now);
diff -Nur mipv6-daemon-umip-0.3-nepl/src/mn.h mipv6-daemon-umip-0.3-nepl-mcoa/src/mn.h
--- mipv6-daemon-umip-0.3-nepl/src/mn.h 2007-06-13 10:36:38.000000000 +0200
+++ mipv6-daemon-umip-0.3-nepl-mcoa/src/mn.h 2007-06-13 16:11:09.000000000 +0200
@@ -52,6 +52,7 @@
#define NEMO_FWD_BLOCK 0x10
struct mn_addr {
+ struct list_head list;
struct in6_addr addr;
int iif;
struct timespec timestamp;
@@ -75,7 +76,8 @@
uint8_t home_plen;
struct in6_addr home_prefix;
struct hash bul; /* Binding Update List */
- struct mn_addr primary_coa;
+ struct mn_addr *current_coa; /* MCoA: pointer to a member of mcoa */
+ struct list_head mcoa; /* MCoA: list of all active CoAs */
struct list_head ro_policies;
struct ha_candidate_list ha_list;
struct in6_addr ha_addr;
@@ -84,9 +86,11 @@
int if_tunnel;
int if_home;
int if_block;
+ int table; /* MCoA: routing table number where routes are stored */
short hwalen;
uint8_t altcoa;
uint8_t mob_rtr;
+ uint8_t reg_mcoa;
char name[IF_NAMESIZE];
int mnp_count;
struct list_head mob_net_prefixes;
diff -Nur mipv6-daemon-umip-0.3-nepl/src/movement.c mipv6-daemon-umip-0.3-nepl-mcoa/src/movement.c
--- mipv6-daemon-umip-0.3-nepl/src/movement.c 2007-06-13 10:44:56.000000000 +0200
+++ mipv6-daemon-umip-0.3-nepl-mcoa/src/movement.c 2007-06-13 16:11:09.000000000 +0200
@@ -169,7 +169,7 @@
struct in6_addr prefix;
ipv6_addr_prefix(&prefix, &p->ple_prefix, p->ple_plen);
rule_del(NULL, RT6_TABLE_MAIN, IP6_RULE_PRIO_MIP6_COA_OUT,
- RTN_UNICAST, &prefix, p->ple_plen,
+ 0, RTN_UNICAST, &prefix, p->ple_plen,
&in6addr_any, 0, 0);
}
@@ -316,10 +316,10 @@
static void md_block_rule_del(struct md_inet6_iface *iface)
{
- rule_del(NULL, 0, IP6_RULE_PRIO_MIP6_BLOCK_HOA, RTN_BLACKHOLE,
+ rule_del(NULL, 0, IP6_RULE_PRIO_MIP6_BLOCK_HOA, 0, RTN_BLACKHOLE,
&in6addr_any, 0, &in6addr_any, 0, 0);
- rule_del(NULL, RT6_TABLE_MAIN, IP6_RULE_PRIO_MIP6_COA_OUT, RTN_UNICAST,
- &in6addr_any, 128, &in6addr_any, 0, 0);
+ rule_del(NULL, RT6_TABLE_MAIN, IP6_RULE_PRIO_MIP6_COA_OUT, 0,
+ RTN_UNICAST, &in6addr_any, 128, &in6addr_any, 0, 0);
iface->iface_flags &= ~MD_BLOCK_TRAFFIC;
}
@@ -1294,7 +1294,7 @@
struct in6_addr prefix;
ipv6_addr_prefix(&prefix, &p->ple_prefix, p->ple_plen);
rule_add(NULL, RT6_TABLE_MAIN, IP6_RULE_PRIO_MIP6_COA_OUT,
- RTN_UNICAST, &prefix, p->ple_plen,
+ 0, RTN_UNICAST, &prefix, p->ple_plen,
&in6addr_any, 0, 0);
}
@@ -1365,13 +1365,13 @@
iface->iface_flags |= MD_BLOCK_TRAFFIC;
/* Allow DAD probes and RS messages */
rule_add(NULL, RT6_TABLE_MAIN,
- IP6_RULE_PRIO_MIP6_COA_OUT, RTN_UNICAST,
+ IP6_RULE_PRIO_MIP6_COA_OUT, 0, RTN_UNICAST,
&in6addr_any, 128, &in6addr_any, 0, 0);
/* drop outgoing global traffic until DAD has been performed
on CoA to make routing and tunnel end-point updates atomic
during handoff */
return rule_add(NULL, 0,
- IP6_RULE_PRIO_MIP6_BLOCK_HOA, RTN_BLACKHOLE,
+ IP6_RULE_PRIO_MIP6_BLOCK_HOA, 0, RTN_BLACKHOLE,
&in6addr_any, 0, &in6addr_any, 0, 0);
}
diff -Nur mipv6-daemon-umip-0.3-nepl/src/mpdisc_ha.c mipv6-daemon-umip-0.3-nepl-mcoa/src/mpdisc_ha.c
--- mipv6-daemon-umip-0.3-nepl/src/mpdisc_ha.c 2007-06-13 10:36:09.000000000 +0200
+++ mipv6-daemon-umip-0.3-nepl-mcoa/src/mpdisc_ha.c 2007-06-13 16:11:09.000000000 +0200
@@ -68,7 +68,7 @@
const struct in6_addr *hoa)
{
- return hash_get(&mpa_hash, ha, hoa);
+ return hash_get(&mpa_hash, ha, hoa, 0);
}
/* HA functions */
@@ -214,7 +214,7 @@
pthread_mutex_lock(&mpa_lock);
e = mpa_get(ha, hoa);
if (e != NULL) {
- hash_delete(&mpa_hash, &e->ha, &e->hoa);
+ hash_delete(&mpa_hash, &e->ha, &e->hoa, 0);
if (tsisset(e->delay))
del_task(&e->tqe);
free(e);
@@ -239,7 +239,7 @@
memset(e, 0, sizeof(struct mpa_entry));
e->ha = *ha;
e->hoa = *hoa;
- if (hash_add(&mpa_hash, e, &e->ha, &e->hoa)) {
+ if (hash_add(&mpa_hash, e, &e->ha, &e->hoa, NULL)) {
free(e);
goto out;
}
diff -Nur mipv6-daemon-umip-0.3-nepl/src/mpdisc_mn.c mipv6-daemon-umip-0.3-nepl-mcoa/src/mpdisc_mn.c
--- mipv6-daemon-umip-0.3-nepl/src/mpdisc_mn.c 2007-06-13 10:36:09.000000000 +0200
+++ mipv6-daemon-umip-0.3-nepl-mcoa/src/mpdisc_mn.c 2007-06-13 16:11:09.000000000 +0200
@@ -65,7 +65,7 @@
static inline struct mps_entry *mps_get(const struct in6_addr *hoa,
const struct in6_addr *ha)
{
- return hash_get(&mps_hash, hoa, ha);
+ return hash_get(&mps_hash, hoa, ha, 0);
}
#ifdef ENABLE_VT
@@ -116,7 +116,7 @@
e = mps_get(hoa, ha);
if (e != NULL) {
dbg("canceling MPS\n");
- hash_delete(&mps_hash, &e->hoa, &e->ha);
+ hash_delete(&mps_hash, &e->hoa, &e->ha, 0);
if (tsisset(e->delay))
del_task(&e->tqe);
free(e);
@@ -175,7 +175,7 @@
memset(e, 0, sizeof(struct mps_entry));
e->hoa = *hoa;
e->ha = *ha;
- if (hash_add(&mps_hash, e, &e->hoa, &e->ha)) {
+ if (hash_add(&mps_hash, e, &e->hoa, &e->ha, NULL)) {
free(e);
goto out;
}
diff -Nur mipv6-daemon-umip-0.3-nepl/src/ndisc.h mipv6-daemon-umip-0.3-nepl-mcoa/src/ndisc.h
--- mipv6-daemon-umip-0.3-nepl/src/ndisc.h 2007-06-13 10:36:09.000000000 +0200
+++ mipv6-daemon-umip-0.3-nepl-mcoa/src/ndisc.h 2007-06-13 16:11:09.000000000 +0200
@@ -21,6 +21,7 @@
return 1;
/* supported virtual devices */
case ARPHRD_SIT:
+ return 4;
case ARPHRD_TUNNEL6:
case ARPHRD_PPP:
case ARPHRD_IPGRE:
diff -Nur mipv6-daemon-umip-0.3-nepl/src/policy.c mipv6-daemon-umip-0.3-nepl-mcoa/src/policy.c
--- mipv6-daemon-umip-0.3-nepl/src/policy.c 2007-06-13 10:36:38.000000000 +0200
+++ mipv6-daemon-umip-0.3-nepl-mcoa/src/policy.c 2007-06-13 16:11:09.000000000 +0200
@@ -49,6 +49,25 @@
int def_bind_policy = IP6_MH_BAS_PROHIBIT;
/**
+ * default_mcoa_reg - Check if MCoA reg is allowed
+ * @remote_hoa: remote MN's home address
+ *
+ * Returns 0 if not allowed, 1 if allowed.
+ **/
+int default_mcoa_reg(const struct in6_addr *remote_hoa)
+{
+ struct policy_bind_acl_entry *acl;
+ int ret = 1;
+
+ pthread_rwlock_rdlock(&policy_lock);
+ acl = hash_get(&policy_bind_acl_hash, NULL, remote_hoa, 0);
+ if (!conf.HaAcceptMCoAReg || (acl && !acl->mcoa_reg))
+ ret = 0;
+ pthread_rwlock_unlock(&policy_lock);
+ return ret;
+}
+
+/**
* default_best_iface - select best interface during handoff
* @hoa: MN's home address
* @ha: HA's address
@@ -148,7 +167,7 @@
return IP6_MH_BAS_MR_OP_NOT_PERMITTED;
pthread_rwlock_rdlock(&policy_lock);
- acl = hash_get(&policy_bind_acl_hash, NULL, remote_hoa);
+ acl = hash_get(&policy_bind_acl_hash, NULL, remote_hoa, 0);
if (acl != NULL) {
ret = acl->bind_policy;
if (ret < IP6_MH_BAS_UNSPECIFIED &&
@@ -213,8 +232,16 @@
struct net_iface *nif;
nif = list_entry(list, struct net_iface, list);
if (nif->ifindex == iif) {
- if (is_if_mn(nif))
- return nif->mn_if_preference;
+ if (is_if_mn(nif)) {
+ /* MCoA
+ * Return the BID Priority if the
+ * interface preference is 0
+ */
+ if(nif->mn_if_preference)
+ return nif->mn_if_preference;
+ else
+ return nif->mn_if_bidprio;
+ }
return 0;
}
}
@@ -259,7 +286,7 @@
int ret = 0;
struct policy_bind_acl_entry *acl;
pthread_rwlock_rdlock(&policy_lock);
- acl = hash_get(&policy_bind_acl_hash, NULL, hoa);
+ acl = hash_get(&policy_bind_acl_hash, NULL, hoa, 0);
if (acl != NULL)
ret = acl->mnp_count;
pthread_rwlock_unlock(&policy_lock);
@@ -275,7 +302,7 @@
struct policy_bind_acl_entry *acl;
pthread_rwlock_rdlock(&policy_lock);
- acl = hash_get(&policy_bind_acl_hash, NULL, hoa);
+ acl = hash_get(&policy_bind_acl_hash, NULL, hoa, 0);
if (acl != NULL) {
struct list_head *l;
list_for_each(l, &acl->mob_net_prefixes) {
@@ -314,7 +341,7 @@
static int policy_bind_acl_add(struct policy_bind_acl_entry *acl)
{
int err;
- err = hash_add(&policy_bind_acl_hash, acl, NULL, &acl->hoa);
+ err = hash_add(&policy_bind_acl_hash, acl, NULL, &acl->hoa, NULL);
if (!err) {
list_del(&acl->list);
}
diff -Nur mipv6-daemon-umip-0.3-nepl/src/policy.h mipv6-daemon-umip-0.3-nepl-mcoa/src/policy.h
--- mipv6-daemon-umip-0.3-nepl/src/policy.h 2007-06-13 10:36:38.000000000 +0200
+++ mipv6-daemon-umip-0.3-nepl-mcoa/src/policy.h 2007-06-13 16:11:09.000000000 +0200
@@ -6,7 +6,13 @@
#include
#include "list.h"
-#define POL_MN_IF_DEF_PREFERENCE 5
+/* MCoA
+ * Changed POL_MN_IF_DEF_PREFERENCE from 5 to 0
+ */
+#define POL_MN_IF_DEF_PREFERENCE 0
+#define POL_MN_IF_DEF_BID 0
+#define POL_MN_IF_DEF_BID_PRIORITY 0
+#define POL_MN_IF_DEF_RELIABLE 1
struct ip6_mh_binding_update;
struct nd_router_advert;
@@ -17,11 +23,20 @@
struct in6_addr hoa;
int plen;
int bind_policy;
+ int mcoa_reg;
int mnp_count;
struct list_head mob_net_prefixes;
};
/**
+ * default_mcoa_reg - Check if MCoA registration is allowed
+ * @remote_hoa: remote MN's home address
+ *
+ * Returns 0 if not allowed, 1 if allowed.
+ **/
+int default_mcoa_reg(const struct in6_addr *remote_hoa);
+
+/**
* default_best_iface - select best interface during handoff
* @hoa: MN's home address
* @ha: HA's address
diff -Nur mipv6-daemon-umip-0.3-nepl/src/retrout.c mipv6-daemon-umip-0.3-nepl-mcoa/src/retrout.c
--- mipv6-daemon-umip-0.3-nepl/src/retrout.c 2007-06-13 10:36:09.000000000 +0200
+++ mipv6-daemon-umip-0.3-nepl-mcoa/src/retrout.c 2007-06-13 16:11:09.000000000 +0200
@@ -151,7 +151,7 @@
rre->own2 = *own2;
rre->iif = iif;
- if (hash_add(&rrl_hash, rre, &rre->own1, &rre->peer) < 0) {
+ if (hash_add(&rrl_hash, rre, &rre->own1, &rre->peer, NULL) < 0) {
rrl_delete(rre);
return NULL;
}
@@ -168,7 +168,7 @@
assert(our_addr);
- rre = (struct rrlentry *)hash_get(&rrl_hash, our_addr, peer_addr);
+ rre = (struct rrlentry *)hash_get(&rrl_hash, our_addr, peer_addr, 0);
if (rre != NULL && rre->type != type)
return NULL;
@@ -188,7 +188,7 @@
TRACE;
del_task(&rre->tqe);
- hash_delete(&rrl_hash, &rre->own1, &rre->peer);
+ hash_delete(&rrl_hash, &rre->own1, &rre->peer, 0);
if (rre->type == COT_ENTRY) {
struct list_head *list, *n;
@@ -629,7 +629,7 @@
const struct in6_addr *peer,
struct in6_addr *hoa)
{
- struct rrlentry *rre = hash_get(&rrl_hash, own, peer);
+ struct rrlentry *rre = hash_get(&rrl_hash, own, peer, 0);
if (rre == NULL || !rre->wait)
return 0;
@@ -694,7 +694,11 @@
struct addr_holder *ah;
ah = list_entry(list, struct addr_holder, list);
- bule = bul_get(NULL, &ah->addr, cn_addr);
+ /* MCoA TODO2
+ * MCoA does not work with RR
+ * At the moment the first entry that match is chosen
+ */
+ bule = bul_get(NULL, &ah->addr, cn_addr, MCOA_NO_BID);
if (bule == NULL || bule->type != BUL_ENTRY ||
!IN6_ARE_ADDR_EQUAL(&rre_co->own1, &bule->coa)) {
@@ -773,7 +777,11 @@
pthread_rwlock_unlock(&mn_lock);
return;
}
- bule = bul_get(NULL, home_addr, cn_addr);
+ /* MCoA TODO2
+ * MCoA does not work with RR
+ * At the moment the first entry that match is chosen
+ */
+ bule = bul_get(NULL, home_addr, cn_addr, MCOA_NO_BID);
if (bule == NULL || bule->type != BUL_ENTRY) {
rrl_delete(rre_ho);
diff -Nur mipv6-daemon-umip-0.3-nepl/src/rtnl.c mipv6-daemon-umip-0.3-nepl-mcoa/src/rtnl.c
--- mipv6-daemon-umip-0.3-nepl/src/rtnl.c 2007-06-13 10:36:09.000000000 +0200
+++ mipv6-daemon-umip-0.3-nepl-mcoa/src/rtnl.c 2007-06-13 16:11:09.000000000 +0200
@@ -299,7 +299,7 @@
}
static int rule_mod(const char *iface, int cmd, uint8_t table,
- uint32_t priority, uint8_t action,
+ uint32_t priority, uint32_t fwmark, uint8_t action,
const struct in6_addr *src, int src_plen,
const struct in6_addr *dst, int dst_plen, int flags)
{
@@ -331,6 +331,8 @@
addattr_l(n, sizeof(buf), RTA_SRC, src, sizeof(*src));
if (priority)
addattr32(n, sizeof(buf), RTA_PRIORITY, priority);
+ if (fwmark)
+ addattr32(n, sizeof(buf), RTA_PROTOINFO, fwmark);
if (iface)
addattr_l(n, sizeof(buf), RTA_IIF, iface, strlen(iface) + 1);
@@ -349,12 +351,12 @@
* negative otherwise.
**/
int rule_add(const char *iface, uint8_t table,
- uint32_t priority, uint8_t action,
+ uint32_t priority, uint32_t fwmark, uint8_t action,
const struct in6_addr *src, int src_plen,
const struct in6_addr *dst, int dst_plen, int flags)
{
return rule_mod(iface, RTM_NEWRULE, table,
- priority, action,
+ priority, fwmark, action,
src, src_plen, dst, dst_plen, flags);
}
@@ -370,12 +372,12 @@
* otherwise.
**/
int rule_del(const char *iface, uint8_t table,
- uint32_t priority, uint8_t action,
+ uint32_t priority, uint32_t fwmark, uint8_t action,
const struct in6_addr *src, int src_plen,
const struct in6_addr *dst, int dst_plen, int flags)
{
return rule_mod(iface, RTM_DELRULE, table,
- priority, action,
+ priority, fwmark, action,
src, src_plen, dst, dst_plen, flags);
}
diff -Nur mipv6-daemon-umip-0.3-nepl/src/rtnl.h mipv6-daemon-umip-0.3-nepl-mcoa/src/rtnl.h
--- mipv6-daemon-umip-0.3-nepl/src/rtnl.h 2007-06-13 10:36:38.000000000 +0200
+++ mipv6-daemon-umip-0.3-nepl-mcoa/src/rtnl.h 2007-06-13 16:11:09.000000000 +0200
@@ -17,11 +17,14 @@
#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
-#define IP6_RULE_PRIO_MIP6_BLOCK_HOA 1004
-#define IP6_RULE_PRIO_MIP6_FWD 1005
+#define IP6_RULE_PRIO_MIP6_HOA_OUT_MCOA 1001
+#define IP6_RULE_PRIO_MIP6_HOA_OUT 1002
+#define IP6_RULE_PRIO_MIP6_COA_OUT 1003
+#define IP6_RULE_PRIO_MIP6_BLOCK 1004
+#define IP6_RULE_PRIO_MIP6_BLOCK_HOA 1005
+#define IP6_RULE_PRIO_MIP6_FWD_FWM 1006
+#define IP6_RULE_PRIO_MIP6_FWD_MCOA 1007
+#define IP6_RULE_PRIO_MIP6_FWD 1008
static inline int rtnl_route_open(struct rtnl_handle *rth,
unsigned subscriptions)
@@ -74,12 +77,12 @@
const struct in6_addr *gateway);
int rule_add(const char *iface, uint8_t table,
- uint32_t priority, uint8_t action,
+ uint32_t priority, uint32_t fwmark, uint8_t action,
const struct in6_addr *src, int src_plen,
const struct in6_addr *dst, int dst_plen, int flags);
int rule_del(const char *iface, uint8_t table,
- uint32_t priority, uint8_t action,
+ uint32_t priority, uint32_t fwmark, uint8_t action,
const struct in6_addr *src, int src_plen,
const struct in6_addr *dst, int dst_plen,int flags);
diff -Nur mipv6-daemon-umip-0.3-nepl/src/scan.l mipv6-daemon-umip-0.3-nepl-mcoa/src/scan.l
--- mipv6-daemon-umip-0.3-nepl/src/scan.l 2007-06-13 10:36:38.000000000 +0200
+++ mipv6-daemon-umip-0.3-nepl-mcoa/src/scan.l 2007-06-13 16:11:09.000000000 +0200
@@ -137,7 +137,15 @@
MnDiscardHaParamProb { return MNDISCARDHAPARAMPROB; }
OptimisticHandoff { return OPTIMISTICHANDOFF; }
HaAcceptMobRtr { return HAACCEPTMOBRTR; }
+HaAcceptMCoAReg { return HAACCEPTMCOAREG; }
+MCoAReg { return MCOAREG; }
+NoMCoAReg { return NOMCOAREG; }
IsMobRtr { return ISMOBRTR; }
+Bid { return BID; }
+BidPriority { return BIDPRIORITY; }
+Reliable { return RELIABLE; }
+RegMultipleCoA { return REGMULTIPLECOA; }
+IfMultipleCoA { return IFMULTIPLECOA; }
HaServedPrefix { return HASERVEDPREFIX; }
HomePrefix { return HOMEPREFIX; }
MobRtrUseExplicitMode { return MOBRTRUSEEXPLICITMODE; }
diff -Nur mipv6-daemon-umip-0.3-nepl/src/tunnelctl.c mipv6-daemon-umip-0.3-nepl-mcoa/src/tunnelctl.c
--- mipv6-daemon-umip-0.3-nepl/src/tunnelctl.c 2007-06-13 10:36:09.000000000 +0200
+++ mipv6-daemon-umip-0.3-nepl-mcoa/src/tunnelctl.c 2007-06-13 16:11:09.000000000 +0200
@@ -157,7 +157,7 @@
if (tnl->users == 0) {
struct ifreq ifr;
list_del(&tnl->list);
- hash_delete(&tnl_hash, &tnl->parm.laddr, &tnl->parm.raddr);
+ hash_delete(&tnl_hash, &tnl->parm.laddr, &tnl->parm.raddr, 0);
strcpy(ifr.ifr_name, tnl->parm.name);
if ((res = ioctl(tnl_fd, SIOCDELTUNNEL, &ifr)) < 0) {
TDBG("SIOCDELTUNNEL failed status %d %s\n",
@@ -249,7 +249,7 @@
TDBG("no device called %s\n", tnl->parm.name);
goto err;
}
- if (hash_add(&tnl_hash, tnl, &tnl->parm.laddr, &tnl->parm.raddr) < 0)
+ if (hash_add(&tnl_hash, tnl, &tnl->parm.laddr, &tnl->parm.raddr, NULL) < 0)
goto err;
list_add_tail(&tnl->list, &tnl_list);
@@ -287,7 +287,7 @@
int res;
pthread_mutex_lock(&tnl_lock);
- if ((tnl = hash_get(&tnl_hash, local, remote)) != NULL) {
+ if ((tnl = hash_get(&tnl_hash, local, remote, 0)) != NULL) {
tnl->users++;
TDBG("tunnel %s (%d) from %x:%x:%x:%x:%x:%x:%x:%x "
"to %x:%x:%x:%x:%x:%x:%x:%x user count increased to %d\n",
@@ -339,9 +339,10 @@
errno, strerror(errno));
return -1;
}
- hash_delete(&tnl_hash, &tnl->parm.laddr, &tnl->parm.raddr);
+ hash_delete(&tnl_hash, &tnl->parm.laddr, &tnl->parm.raddr, 0);
memcpy(&tnl->parm, &parm, sizeof(struct ip6_tnl_parm));
- if (hash_add(&tnl_hash, tnl, &tnl->parm.laddr, &tnl->parm.raddr) < 0) {
+ if (hash_add(&tnl_hash, tnl, &tnl->parm.laddr,
+ &tnl->parm.raddr, NULL) < 0) {
free(tnl);
return -1;
}
@@ -387,7 +388,7 @@
old = get_tnl(ifindex);
assert(old != NULL);
- if ((new = hash_get(&tnl_hash, local, remote)) != NULL) {
+ if ((new = hash_get(&tnl_hash, local, remote, 0)) != NULL) {
if (new != old) {
new->users++;
TDBG("tunnel %s (%d) from %x:%x:%x:%x:%x:%x:%x:%x "
@@ -448,7 +449,7 @@
{
struct mip6_tnl *tnl = (struct mip6_tnl *) data;
list_del(&tnl->list);
- hash_delete(&tnl_hash, &tnl->parm.laddr, &tnl->parm.raddr);
+ hash_delete(&tnl_hash, &tnl->parm.laddr, &tnl->parm.raddr, 0);
free(tnl);
return 0;
}
diff -Nur mipv6-daemon-umip-0.3-nepl/src/vt.c mipv6-daemon-umip-0.3-nepl-mcoa/src/vt.c
--- mipv6-daemon-umip-0.3-nepl/src/vt.c 2007-06-13 10:36:09.000000000 +0200
+++ mipv6-daemon-umip-0.3-nepl-mcoa/src/vt.c 2007-06-13 16:11:09.000000000 +0200
@@ -428,6 +428,12 @@
fprintf(vh->vh_stream, " last_coa %x:%x:%x:%x:%x:%x:%x:%x",
NIP6ADDR(&bule->last_coa));
+ if (bule->bid) {
+ fprintf(vh->vh_stream, " BID %d", bule->bid);
+ fprintf(vh->vh_stream, " BidPriority %d",
+ bule->priority);
+ }
+
fprintf(vh->vh_stream, "\n");
if (!(bule->flags & IP6_MH_BU_HOME)) {
@@ -580,6 +586,11 @@
fprintf(vh->vh_stream, " coa %x:%x:%x:%x:%x:%x:%x:%x",
NIP6ADDR(&bce->coa));
+ if (bce->bid) {
+ fprintf(vh->vh_stream, " BID %d", bce->bid);
+ fprintf(vh->vh_stream, " BidPriority %d", bce->priority);
+ }
+
if (vh->vh_opt.verbose == VT_BOOL_TRUE)
fprintf(vh->vh_stream, " nonce %u", bce->nonce_coa);
diff -Nur mipv6-daemon-umip-0.3-nepl/src/xfrm.c mipv6-daemon-umip-0.3-nepl-mcoa/src/xfrm.c
--- mipv6-daemon-umip-0.3-nepl/src/xfrm.c 2007-06-13 10:36:38.000000000 +0200
+++ mipv6-daemon-umip-0.3-nepl-mcoa/src/xfrm.c 2007-06-15 10:11:25.000000000 +0200
@@ -56,7 +56,7 @@
#include "conf.h"
#include "ipsec.h"
-#define XFRM_DEBUG_LEVEL 1
+#define XFRM_DEBUG_LEVEL 2
#if XFRM_DEBUG_LEVEL >= 1
#define XDBG dbg
@@ -1425,7 +1425,7 @@
int res = -1;
pthread_rwlock_rdlock(&mn_lock);
if ((hai = mn_get_home_addr(our_addr)) != NULL) {
- if ((e = bul_get(hai, NULL, peer_addr)) != NULL) {
+ if ((e = bul_get(hai, NULL, peer_addr, MCOA_NO_BID)) != NULL) {
if (e->type == BUL_ENTRY &&
!_xfrm_add_bule_bce(our_addr, peer_addr, replace))
res = 0;
@@ -1452,17 +1452,20 @@
int xfrm_add_bce(const struct in6_addr *our_addr,
const struct in6_addr *peer_addr,
const struct in6_addr *coa,
- int replace)
+ int replace,
+ int create)
{
struct xfrm_selector sel;
/* Create policy for outbound RO data traffic */
- set_selector(peer_addr, our_addr, 0, 0, 0, 0, &sel);
- if (xfrm_state_add(&sel, IPPROTO_ROUTING, coa, replace, 0))
- return -1;
- set_selector(our_addr, peer_addr, 0, 0, 0, 0, &sel);
- if (xfrm_state_add(&sel, IPPROTO_DSTOPTS, coa, replace, 0))
- return -1;
+ if (create || replace) {
+ set_selector(peer_addr, our_addr, 0, 0, 0, 0, &sel);
+ if (xfrm_state_add(&sel, IPPROTO_ROUTING, coa, replace, 0))
+ return -1;
+ set_selector(our_addr, peer_addr, 0, 0, 0, 0, &sel);
+ if (xfrm_state_add(&sel, IPPROTO_DSTOPTS, coa, replace, 0))
+ return -1;
+ }
if (is_mn() && !xfrm_bule_bce_update(our_addr, peer_addr, replace))
return 0;
if (is_ha() && conf.UseMnHaIPsec) {
@@ -1470,7 +1473,8 @@
_ha_mn_ipsec_pol_mod, NULL) < 0)
return -1;
}
- _xfrm_add_bce(our_addr, peer_addr, replace);
+ if (create || replace)
+ _xfrm_add_bce(our_addr, peer_addr, replace);
return 0;
}
@@ -1578,7 +1582,7 @@
static int _xfrm_bce_reset(struct bulentry *bule)
{
/* for MN - MN communication */
- struct bcentry *bce = bcache_get(&bule->hoa, &bule->peer_addr);
+ struct bcentry *bce = bcache_get(&bule->hoa, &bule->peer_addr, MCOA_NO_BID);
int res = 0;
if (!bce)
return 0;
@@ -1596,21 +1600,34 @@
static int _xfrm_del_bule_data(struct bulentry *bule)
{
struct xfrm_selector sel;
+ int bule_exists = mcoa_bule_count(bule);
int prio;
- set_selector(&bule->peer_addr, &bule->hoa, 0, 0, 0, 0, &sel);
- xfrm_state_del(IPPROTO_DSTOPTS, &sel);
+ /* MCoA
+ * XFRM states are deleted only when the last BULE for
+ * the same peer is deleted, or when returning home
+ */
+ if (!bule_exists || !bule->home->reg_mcoa || bule->home->at_home) {
+ XDBG2("Last entry for the peer, deleting XFRM states\n");
+ set_selector(&bule->peer_addr, &bule->hoa, 0, 0, 0, 0, &sel);
+ xfrm_state_del(IPPROTO_DSTOPTS, &sel);
+ }
if (bule->home->home_reg_status != HOME_REG_NONE &&
mn_has_cn_ro_pol(bule)) {
struct xfrm_user_tmpl tmpl;
create_trig_dstopt_tmpl(&tmpl, &bule->peer_addr, &bule->hoa);
+ /* MCoA: replaced bule->home->if_tunnel with bule->if_tunnel */
set_selector(&bule->peer_addr, &bule->hoa,
- 0, 0, 0, bule->home->if_tunnel, &sel);
+ 0, 0, 0, bule->if_tunnel, &sel);
xfrm_mip_policy_add(&sel, 1, XFRM_POLICY_OUT,
XFRM_POLICY_ALLOW, MIP6_PRIO_RO_TRIG, &tmpl, 1);
- } else
- _mn_bule_ro_pol_del(bule, bule->home->if_tunnel);
+ } else if(!bule_exists || !bule->home->reg_mcoa || bule->home->at_home) {
+ /* MCoA: policies deleted only if this is the last BULE
+ * for the same peer, or when returning home */
+ /* MCoA: replaced bule->home->if_tunnel with bule->if_tunnel */
+ _mn_bule_ro_pol_del(bule, bule->if_tunnel);
+ }
if (!(bule->flags & IP6_MH_BU_HOME))
_xfrm_bce_reset(bule);
@@ -1621,20 +1638,25 @@
/* MN - CN/HA case, BU out */
prio = (bule->flags & IP6_MH_BU_HOME ?
MIP6_PRIO_HOME_SIG : MIP6_PRIO_RO_SIG);
- if (bule->flags & IP6_MH_BU_ACK) {
+ if ((bule->flags & IP6_MH_BU_ACK)
+ && (!bule_exists || !bule->home->reg_mcoa
+ || bule->home->at_home)) {
set_selector(&bule->hoa, &bule->peer_addr, IPPROTO_MH,
IP6_MH_TYPE_BACK, 0, 0, &sel);
if (xfrm_mip_policy_add(&sel, 1, XFRM_POLICY_IN,
XFRM_POLICY_ALLOW, prio, NULL, 0))
return -1;
}
- set_selector(&bule->peer_addr, &bule->hoa, IPPROTO_MH,
- IP6_MH_TYPE_BU, 0, 0, &sel);
- if (xfrm_mip_policy_add(&sel, 1, XFRM_POLICY_OUT,
- XFRM_POLICY_ALLOW, prio, NULL, 0))
- return -1;
+ if (!bule_exists || !bule->home->reg_mcoa
+ || bule->home->at_home) {
+ set_selector(&bule->peer_addr, &bule->hoa, IPPROTO_MH,
+ IP6_MH_TYPE_BU, 0, 0, &sel);
+ if (xfrm_mip_policy_add(&sel, 1, XFRM_POLICY_OUT,
+ XFRM_POLICY_ALLOW, prio, NULL, 0))
+ return -1;
+ bule->xfrm_state &= ~BUL_XFRM_STATE_DATA;
+ }
- bule->xfrm_state &= ~BUL_XFRM_STATE_DATA;
return 0;
}
@@ -1659,7 +1681,14 @@
{
if (bule->xfrm_state & BUL_XFRM_STATE_DATA)
_xfrm_del_bule_data(bule);
- _xfrm_del_bule_sig(bule);
+ /* MCoA
+ * XFRM policies are deleted only when the last BULE for the
+ * same peer is deleted, or when returning home
+ */
+ if (mcoa_bule_count(bule) == 0 || bule->home->at_home) {
+ XDBG2("Last entry for the peer, deleting XFRM policies\n");
+ _xfrm_del_bule_sig(bule);
+ }
}
/* before sending BU, MN should insert policy/state only for BU/BA */
@@ -1675,9 +1704,20 @@
struct home_addr_info *hai = bule->home;
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 (bule->home_block & HOME_LINK_BLOCK)
+ xfrm_unblock_bule_link(bule);
+ if (!hai->reg_mcoa)
+ xfrm_block_link(hai);
+ else
+ xfrm_block_bule_link(bule);
+ if (hai->mob_rtr) {
+ if (!hai->reg_mcoa &&
+ !(hai->home_block & NEMO_FWD_BLOCK))
+ xfrm_block_fwd(hai);
+ else if (hai->reg_mcoa &&
+ !(bule->home_block & NEMO_FWD_BLOCK))
+ bule_block_fwd(bule);
+ }
}
if (IN6_ARE_ADDR_EQUAL(&bule->hoa, &bule->coa)) {
if (rdata)
@@ -1691,25 +1731,32 @@
return -1;
}
/* MN - CN/HA case, BU out */
- prio = (bule->flags & IP6_MH_BU_HOME ?
- MIP6_PRIO_HOME_SIG : MIP6_PRIO_RO_SIG);
- if (bule->flags & IP6_MH_BU_ACK) {
- create_rh_tmpl(&tmpl);
- set_selector(&bule->hoa, &bule->peer_addr, IPPROTO_MH,
- IP6_MH_TYPE_BACK, 0, 0, &sel);
- if (xfrm_mip_policy_add(&sel, rsig, XFRM_POLICY_IN,
+ if (mcoa_bule_count(bule) == 1) {
+ /* MCoA
+ * If another BULE already exists for this HoA/HA addr
+ * we do not need to install the policies once again
+ */
+ prio = (bule->flags & IP6_MH_BU_HOME ?
+ MIP6_PRIO_HOME_SIG : MIP6_PRIO_RO_SIG);
+ if (bule->flags & IP6_MH_BU_ACK) {
+ create_rh_tmpl(&tmpl);
+ set_selector(&bule->hoa, &bule->peer_addr, IPPROTO_MH,
+ IP6_MH_TYPE_BACK, 0, 0, &sel);
+ if (xfrm_mip_policy_add(&sel, rsig, XFRM_POLICY_IN,
+ XFRM_POLICY_ALLOW, prio, &tmpl, 1))
+ return -1;
+ }
+ create_dstopt_tmpl(&tmpl, &bule->peer_addr, &bule->hoa);
+ set_selector(&bule->peer_addr, &bule->hoa, IPPROTO_MH,
+ IP6_MH_TYPE_BU, 0, 0, &sel);
+ if (xfrm_mip_policy_add(&sel, rsig, XFRM_POLICY_OUT,
XFRM_POLICY_ALLOW, prio, &tmpl, 1))
return -1;
}
- create_dstopt_tmpl(&tmpl, &bule->peer_addr, &bule->hoa);
- set_selector(&bule->peer_addr, &bule->hoa, IPPROTO_MH,
- IP6_MH_TYPE_BU, 0, 0, &sel);
- if (xfrm_mip_policy_add(&sel, rsig, XFRM_POLICY_OUT,
- XFRM_POLICY_ALLOW, prio, &tmpl, 1))
- return -1;
if (!(bule->flags & IP6_MH_BU_HOME)) {
- struct bcentry *bce = bcache_get(&bule->hoa, &bule->peer_addr);
+ struct bcentry *bce = bcache_get(&bule->hoa, &bule->peer_addr,
+ MCOA_NO_BID);
if (bce) {
if (bce->type > BCE_NONCE_BLOCK &&
_xfrm_add_bce(&bule->hoa, &bule->peer_addr, 1)) {
@@ -1719,11 +1766,19 @@
bcache_release_entry(bce);
}
}
- if (_mn_bule_ro_pol_add(bule, bule->home->if_tunnel, rdata))
- return -1;
+ /* MCoA: Add the policy only if it's an update, or if there is
+ * is only 1 BCE for the peer */
+ if (rdata || mcoa_bule_count(bule) == 1) {
+ /* MCoA: Replaced bule->home->if_tunnel with bule->if_tunnel */
+ if (_mn_bule_ro_pol_add(bule, bule->if_tunnel, rdata))
+ return -1;
+ }
set_selector(&bule->peer_addr, &bule->hoa, 0, 0, 0, 0, &sel);
/* XXX: acquired state is already inserted */
- if (!(bule->flags & IP6_MH_BU_HOME)) {
+ /* MCoA: Add the states if there is only 1 BCE for the peer,
+ * otherwise just update the CoA
+ */
+ if (!(bule->flags & IP6_MH_BU_HOME) || mcoa_bule_count(bule) > 1) {
XDBG2("%s: original rdata = %d\n", __FUNCTION__, rdata);
rdata = 1;
}
@@ -1742,15 +1797,20 @@
struct home_addr_info *hai = bule->home;
if (hai->home_block & HOME_LINK_BLOCK)
xfrm_unblock_link(hai);
+ if (bule->home_block & HOME_LINK_BLOCK)
+ xfrm_unblock_bule_link(bule);
if (hai->home_block & NEMO_FWD_BLOCK)
xfrm_unblock_fwd(hai);
+ if (bule->home_block & NEMO_FWD_BLOCK)
+ bule_unblock_fwd(bule);
}
/* check if XFRM policies and states have already been cleaned up */
if (IN6_ARE_ADDR_EQUAL(&bule->hoa, &bule->coa))
return 0;
if (!(bule->flags & IP6_MH_BU_HOME)) {
- struct bcentry *bce = bcache_get(&bule->hoa, &bule->peer_addr);
+ struct bcentry *bce = bcache_get(&bule->hoa, &bule->peer_addr,
+ MCOA_NO_BID);
if (bce) {
if (bce->type > BCE_NONCE_BLOCK &&
_xfrm_add_bule_bce(&bule->hoa,
@@ -1763,11 +1823,27 @@
}
prio = (bule->flags & IP6_MH_BU_HOME ?
MIP6_PRIO_HOME_DATA : MIP6_PRIO_RO_BULE_DATA);
- set_selector(&bule->peer_addr, &bule->hoa, 0, 0, 0,
- bule->home->if_tunnel, &sel);
- create_dstopt_tmpl(&tmpls[0], &bule->peer_addr, &bule->hoa);
- ret = xfrm_mip_policy_add(&sel, 1, XFRM_POLICY_OUT,
- XFRM_POLICY_ALLOW, prio, tmpls, 1);
+
+ /* MCoA: Replaced bule->home->if_tunnel with bule->if_tunnel */
+ set_selector(&bule->peer_addr, &bule->hoa, 0, 0, 0,
+ bule->if_tunnel, &sel);
+
+ /* MCoA TODO1: to update according to the latest draft.
+ * When MCoA is used, do not use HAO dest. option
+ * for traffic from the MN/MR to the HA. Tunnel packets
+ * instead.
+ */
+ if(bule->home->reg_mcoa) {
+ ret = xfrm_mip_policy_add(&sel, 1, XFRM_POLICY_OUT,
+ XFRM_POLICY_ALLOW, prio,
+ NULL, 0);
+ } else {
+ create_dstopt_tmpl(&tmpls[0], &bule->peer_addr, &bule->hoa);
+ ret = xfrm_mip_policy_add(&sel, 1, XFRM_POLICY_OUT,
+ XFRM_POLICY_ALLOW, prio,
+ tmpls, 1);
+ }
+
if (ret)
XDBG("failed to insert outbound policy\n");
@@ -1964,6 +2040,31 @@
xfrm_cn_cleanup();
}
+/* blocking all payload packets from MN via a specific interface */
+int xfrm_block_bule_link(struct bulentry *bule)
+{
+ int ret = 0;
+ struct xfrm_selector sel;
+ bule->home_block |= HOME_LINK_BLOCK;
+ /* allow MN to send NA messages */
+ /* RK: such policy is already installed in xfrm_cn_init at startup,
+ * so we update it (update field to 1) */
+ set_selector(&in6addr_any, &in6addr_any, IPPROTO_ICMPV6,
+ ND_NEIGHBOR_ADVERT, 0, bule->if_coa, &sel);
+ if ((ret = xfrm_mip_policy_add(&sel, 1 /* update */, XFRM_POLICY_OUT,
+ XFRM_POLICY_ALLOW,
+ MIP6_PRIO_HOME_SIG_ANY, NULL, 0)))
+ return ret;
+
+ /* block any packets from HoA to the CN */
+ set_selector(&in6addr_any, &in6addr_any, 0, 0, 0, bule->if_coa, &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;
+}
+
/* blocking all payload packets from MN */
int xfrm_block_link(struct home_addr_info *hai)
{
@@ -1988,6 +2089,21 @@
return ret;
}
+void xfrm_unblock_bule_link(struct bulentry *bule)
+{
+ struct xfrm_selector sel;
+ set_selector(&in6addr_any, &in6addr_any, 0, 0, 0, bule->if_coa, &sel);
+ xfrm_mip_policy_del(&sel, XFRM_POLICY_OUT);
+ /* RK: instead of deleting the policy, update it to its previous state
+ * (the one installed in xfrm_cn_init) */
+ set_selector(&in6addr_any, &in6addr_any, IPPROTO_ICMPV6,
+ ND_NEIGHBOR_ADVERT, 0, 0, &sel);
+ if (xfrm_mip_policy_add(&sel, 1 /* update */, XFRM_POLICY_OUT, XFRM_POLICY_ALLOW,
+ MIP6_PRIO_NO_RO_SIG_ANY, NULL, 0) < 0)
+ XDBG("Could not update NA policy\n");
+ bule->home_block &= ~HOME_LINK_BLOCK;
+}
+
void xfrm_unblock_link(struct home_addr_info *hai)
{
struct xfrm_selector sel;
diff -Nur mipv6-daemon-umip-0.3-nepl/src/xfrm.h mipv6-daemon-umip-0.3-nepl-mcoa/src/xfrm.h
--- mipv6-daemon-umip-0.3-nepl/src/xfrm.h 2007-06-13 10:36:38.000000000 +0200
+++ mipv6-daemon-umip-0.3-nepl-mcoa/src/xfrm.h 2007-06-13 16:11:09.000000000 +0200
@@ -50,7 +50,8 @@
int xfrm_add_bce(const struct in6_addr *our_addr,
const struct in6_addr *peer_addr,
const struct in6_addr *coa,
- int replace);
+ int replace,
+ int create);
void xfrm_del_bce(const struct in6_addr *our_addr,
const struct in6_addr *peer_addr);
@@ -81,7 +82,9 @@
int cn_wildrecv_bu_pol_add(void);
void cn_wildrecv_bu_pol_del(void);
+int xfrm_block_bule_link(struct bulentry *bule);
int xfrm_block_link(struct home_addr_info *hai);
+void xfrm_unblock_bule_link(struct bulentry *bule);
void xfrm_unblock_link(struct home_addr_info *hai);
int xfrm_block_hoa(struct home_addr_info *hai);