diff --git a/openair3/NEMO_SHO/COPYING b/openair3/NEMO_SHO/COPYING
deleted file mode 100644
index 94a9ed024d3859793618152ea559a168bbcbb5e2..0000000000000000000000000000000000000000
--- a/openair3/NEMO_SHO/COPYING
+++ /dev/null
@@ -1,674 +0,0 @@
-                    GNU GENERAL PUBLIC LICENSE
-                       Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-                            Preamble
-
-  The GNU General Public License is a free, copyleft license for
-software and other kinds of works.
-
-  The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works.  By contrast,
-the GNU General Public License is intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users.  We, the Free Software Foundation, use the
-GNU General Public License for most of our software; it applies also to
-any other work released this way by its authors.  You can apply it to
-your programs, too.
-
-  When we speak of free software, we are referring to freedom, not
-price.  Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-them if you wish), that you receive source code or can get it if you
-want it, that you can change the software or use pieces of it in new
-free programs, and that you know you can do these things.
-
-  To protect your rights, we need to prevent others from denying you
-these rights or asking you to surrender the rights.  Therefore, you have
-certain responsibilities if you distribute copies of the software, or if
-you modify it: responsibilities to respect the freedom of others.
-
-  For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must pass on to the recipients the same
-freedoms that you received.  You must make sure that they, too, receive
-or can get the source code.  And you must show them these terms so they
-know their rights.
-
-  Developers that use the GNU GPL protect your rights with two steps:
-(1) assert copyright on the software, and (2) offer you this License
-giving you legal permission to copy, distribute and/or modify it.
-
-  For the developers' and authors' protection, the GPL clearly explains
-that there is no warranty for this free software.  For both users' and
-authors' sake, the GPL requires that modified versions be marked as
-changed, so that their problems will not be attributed erroneously to
-authors of previous versions.
-
-  Some devices are designed to deny users access to install or run
-modified versions of the software inside them, although the manufacturer
-can do so.  This is fundamentally incompatible with the aim of
-protecting users' freedom to change the software.  The systematic
-pattern of such abuse occurs in the area of products for individuals to
-use, which is precisely where it is most unacceptable.  Therefore, we
-have designed this version of the GPL to prohibit the practice for those
-products.  If such problems arise substantially in other domains, we
-stand ready to extend this provision to those domains in future versions
-of the GPL, as needed to protect the freedom of users.
-
-  Finally, every program is threatened constantly by software patents.
-States should not allow patents to restrict development and use of
-software on general-purpose computers, but in those that do, we wish to
-avoid the special danger that patents applied to a free program could
-make it effectively proprietary.  To prevent this, the GPL assures that
-patents cannot be used to render the program non-free.
-
-  The precise terms and conditions for copying, distribution and
-modification follow.
-
-                       TERMS AND CONDITIONS
-
-  0. Definitions.
-
-  "This License" refers to version 3 of the GNU General Public License.
-
-  "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
-
-  "The Program" refers to any copyrightable work licensed under this
-License.  Each licensee is addressed as "you".  "Licensees" and
-"recipients" may be individuals or organizations.
-
-  To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy.  The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
-  A "covered work" means either the unmodified Program or a work based
-on the Program.
-
-  To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy.  Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
-  To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies.  Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
-  An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License.  If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
-  1. Source Code.
-
-  The "source code" for a work means the preferred form of the work
-for making modifications to it.  "Object code" means any non-source
-form of a work.
-
-  A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
-  The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form.  A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
-  The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities.  However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work.  For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
-  The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
-  The Corresponding Source for a work in source code form is that
-same work.
-
-  2. Basic Permissions.
-
-  All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met.  This License explicitly affirms your unlimited
-permission to run the unmodified Program.  The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work.  This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
-  You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force.  You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright.  Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
-  Conveying under any other circumstances is permitted solely under
-the conditions stated below.  Sublicensing is not allowed; section 10
-makes it unnecessary.
-
-  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
-  No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
-  When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
-  4. Conveying Verbatim Copies.
-
-  You may convey verbatim copies of the Program's source code as you
-receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
-  You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
-  5. Conveying Modified Source Versions.
-
-  You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
-    a) The work must carry prominent notices stating that you modified
-    it, and giving a relevant date.
-
-    b) The work must carry prominent notices stating that it is
-    released under this License and any conditions added under section
-    7.  This requirement modifies the requirement in section 4 to
-    "keep intact all notices".
-
-    c) You must license the entire work, as a whole, under this
-    License to anyone who comes into possession of a copy.  This
-    License will therefore apply, along with any applicable section 7
-    additional terms, to the whole of the work, and all its parts,
-    regardless of how they are packaged.  This License gives no
-    permission to license the work in any other way, but it does not
-    invalidate such permission if you have separately received it.
-
-    d) If the work has interactive user interfaces, each must display
-    Appropriate Legal Notices; however, if the Program has interactive
-    interfaces that do not display Appropriate Legal Notices, your
-    work need not make them do so.
-
-  A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit.  Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
-  6. Conveying Non-Source Forms.
-
-  You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
-    a) Convey the object code in, or embodied in, a physical product
-    (including a physical distribution medium), accompanied by the
-    Corresponding Source fixed on a durable physical medium
-    customarily used for software interchange.
-
-    b) Convey the object code in, or embodied in, a physical product
-    (including a physical distribution medium), accompanied by a
-    written offer, valid for at least three years and valid for as
-    long as you offer spare parts or customer support for that product
-    model, to give anyone who possesses the object code either (1) a
-    copy of the Corresponding Source for all the software in the
-    product that is covered by this License, on a durable physical
-    medium customarily used for software interchange, for a price no
-    more than your reasonable cost of physically performing this
-    conveying of source, or (2) access to copy the
-    Corresponding Source from a network server at no charge.
-
-    c) Convey individual copies of the object code with a copy of the
-    written offer to provide the Corresponding Source.  This
-    alternative is allowed only occasionally and noncommercially, and
-    only if you received the object code with such an offer, in accord
-    with subsection 6b.
-
-    d) Convey the object code by offering access from a designated
-    place (gratis or for a charge), and offer equivalent access to the
-    Corresponding Source in the same way through the same place at no
-    further charge.  You need not require recipients to copy the
-    Corresponding Source along with the object code.  If the place to
-    copy the object code is a network server, the Corresponding Source
-    may be on a different server (operated by you or a third party)
-    that supports equivalent copying facilities, provided you maintain
-    clear directions next to the object code saying where to find the
-    Corresponding Source.  Regardless of what server hosts the
-    Corresponding Source, you remain obligated to ensure that it is
-    available for as long as needed to satisfy these requirements.
-
-    e) Convey the object code using peer-to-peer transmission, provided
-    you inform other peers where the object code and Corresponding
-    Source of the work are being offered to the general public at no
-    charge under subsection 6d.
-
-  A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
-  A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling.  In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage.  For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product.  A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
-  "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source.  The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
-  If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information.  But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
-  The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed.  Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
-  Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
-  7. Additional Terms.
-
-  "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law.  If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
-  When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it.  (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.)  You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
-  Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
-    a) Disclaiming warranty or limiting liability differently from the
-    terms of sections 15 and 16 of this License; or
-
-    b) Requiring preservation of specified reasonable legal notices or
-    author attributions in that material or in the Appropriate Legal
-    Notices displayed by works containing it; or
-
-    c) Prohibiting misrepresentation of the origin of that material, or
-    requiring that modified versions of such material be marked in
-    reasonable ways as different from the original version; or
-
-    d) Limiting the use for publicity purposes of names of licensors or
-    authors of the material; or
-
-    e) Declining to grant rights under trademark law for use of some
-    trade names, trademarks, or service marks; or
-
-    f) Requiring indemnification of licensors and authors of that
-    material by anyone who conveys the material (or modified versions of
-    it) with contractual assumptions of liability to the recipient, for
-    any liability that these contractual assumptions directly impose on
-    those licensors and authors.
-
-  All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10.  If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term.  If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
-  If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
-  Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
-  8. Termination.
-
-  You may not propagate or modify a covered work except as expressly
-provided under this License.  Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
-  However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
-  Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
-  Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License.  If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
-  9. Acceptance Not Required for Having Copies.
-
-  You are not required to accept this License in order to receive or
-run a copy of the Program.  Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance.  However,
-nothing other than this License grants you permission to propagate or
-modify any covered work.  These actions infringe copyright if you do
-not accept this License.  Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
-  10. Automatic Licensing of Downstream Recipients.
-
-  Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License.  You are not responsible
-for enforcing compliance by third parties with this License.
-
-  An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations.  If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
-  You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License.  For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
-  11. Patents.
-
-  A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based.  The
-work thus licensed is called the contributor's "contributor version".
-
-  A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version.  For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
-  Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
-  In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement).  To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
-  If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients.  "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-
-  If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
-  A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License.  You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
-  Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
-  12. No Surrender of Others' Freedom.
-
-  If conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License.  If you cannot convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all.  For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
-  13. Use with the GNU Affero General Public License.
-
-  Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU Affero General Public License into a single
-combined work, and to convey the resulting work.  The terms of this
-License will continue to apply to the part which is the covered work,
-but the special requirements of the GNU Affero General Public License,
-section 13, concerning interaction through a network will apply to the
-combination as such.
-
-  14. Revised Versions of this License.
-
-  The Free Software Foundation may publish revised and/or new versions of
-the GNU General Public License from time to time.  Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-  Each version is given a distinguishing version number.  If the
-Program specifies that a certain numbered version of the GNU General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation.  If the Program does not specify a version number of the
-GNU General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
-  If the Program specifies that a proxy can decide which future
-versions of the GNU General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
-  Later license versions may give you additional or different
-permissions.  However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
-  15. Disclaimer of Warranty.
-
-  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
-APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
-IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
-  16. Limitation of Liability.
-
-  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGES.
-
-  17. Interpretation of Sections 15 and 16.
-
-  If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
-                     END OF TERMS AND CONDITIONS
-
-            How to Apply These Terms to Your New Programs
-
-  If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
-  To do so, attach the following notices to the program.  It is safest
-to attach them to the start of each source file to most effectively
-state the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-    <one line to give the program's name and a brief idea of what it does.>
-    Copyright (C) <year>  <name of author>
-
-    This program is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-Also add information on how to contact you by electronic and paper mail.
-
-  If the program does terminal interaction, make it output a short
-notice like this when it starts in an interactive mode:
-
-    <program>  Copyright (C) <year>  <name of author>
-    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
-    This is free software, and you are welcome to redistribute it
-    under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License.  Of course, your program's commands
-might be different; for a GUI interface, you would use an "about box".
-
-  You should also get your employer (if you work as a programmer) or school,
-if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU GPL, see
-<http://www.gnu.org/licenses/>.
-
-  The GNU General Public License does not permit incorporating your program
-into proprietary programs.  If your program is a subroutine library, you
-may consider it more useful to permit linking proprietary applications with
-the library.  If this is what you want to do, use the GNU Lesser General
-Public License instead of this License.  But first, please read
-<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/openair3/NEMO_SHO/README b/openair3/NEMO_SHO/README
deleted file mode 100644
index 8753e997a98a334cb74ef025e4577a5713b26c8f..0000000000000000000000000000000000000000
--- a/openair3/NEMO_SHO/README
+++ /dev/null
@@ -1,6 +0,0 @@
-THE APPLY ORDER MUST BE THE FOLLOWING:
-mmipv6-daemon-umip-0.4-nepl-20080108.patch
-mmipv6-daemon-umip-0.4-nepl-mcoa-20080108.patch
-mmipv6-daemon-umip-0.4-sho-20080331.patch
-mmipv6-daemon-umip-0.4-nasmesh-2009-may-12.patch
-
diff --git a/openair3/NEMO_SHO/mipv6-daemon-umip-0.4-nasmesh-2009-may-12.patch b/openair3/NEMO_SHO/mipv6-daemon-umip-0.4-nasmesh-2009-may-12.patch
deleted file mode 100644
index abb8f76f8a31340ec3209cf2e699b38e6bcdd3b1..0000000000000000000000000000000000000000
--- a/openair3/NEMO_SHO/mipv6-daemon-umip-0.4-nasmesh-2009-may-12.patch
+++ /dev/null
@@ -1,301 +0,0 @@
-Only in mipv6-daemon-umip-0.4_patch_nepl_mcoa_sho: config.h
-Only in mipv6-daemon-umip-0.4_patch_nepl_mcoa_sho: config.log
-Only in mipv6-daemon-umip-0.4_patch_nepl_mcoa_sho: config.status
-Only in mipv6-daemon-umip-0.4_patch_nepl_mcoa_sho/libmissing: .deps
-Only in mipv6-daemon-umip-0.4_patch_nepl_mcoa_sho/libmissing: Makefile
-Only in mipv6-daemon-umip-0.4_patch_nepl_mcoa_sho/libnetlink: .deps
-Only in mipv6-daemon-umip-0.4_patch_nepl_mcoa_sho/libnetlink: Makefile
-Only in mipv6-daemon-umip-0.4_patch_nepl_mcoa_sho: Makefile
-Only in mipv6-daemon-umip-0.4_patch_nepl_mcoa_sho/man: Makefile
-Only in mipv6-daemon-umip-0.4_patch_nepl_mcoa_sho/src: .deps
-Only in mipv6-daemon-umip-0.4_patch_nepl_mcoa_sho/src: gram.c
-Only in mipv6-daemon-umip-0.4_patch_nepl_mcoa_sho/src: gram.h
-Only in mipv6-daemon-umip-0.4_patch_nepl_mcoa_sho/src: Makefile
-diff -ur mipv6-daemon-umip-0.4.all.paches.original/src/mh.c mipv6-daemon-umip-0.4_patch_nepl_mcoa_sho/src/mh.c
---- mipv6-daemon-umip-0.4.all.paches.original/src/mh.c	2009-05-12 14:38:53.000000000 +0200
-+++ mipv6-daemon-umip-0.4_patch_nepl_mcoa_sho/src/mh.c	2009-05-12 14:33:25.000000000 +0200
-@@ -816,8 +816,11 @@
- 	}
- 
- 	pthread_mutex_lock(&mh_sock.send_mutex);
--	setsockopt(mh_sock.fd, IPPROTO_IPV6, IPV6_PKTINFO,
-+	ret = setsockopt(mh_sock.fd, IPPROTO_IPV6, IPV6_PKTINFO,
- 		   &on, sizeof(int));
-+	if (ret < 0)
-+		dbg("setsockopt: %s\n", strerror(errno));
-+
- 	ret = sendmsg(mh_sock.fd, &msg, 0);
- 	if (ret < 0)
- 		dbg("sendmsg: %s\n", strerror(errno));
-Only in mipv6-daemon-umip-0.4_patch_nepl_mcoa_sho/src: mh.c~
-diff -ur mipv6-daemon-umip-0.4.all.paches.original/src/mn.c mipv6-daemon-umip-0.4_patch_nepl_mcoa_sho/src/mn.c
---- mipv6-daemon-umip-0.4.all.paches.original/src/mn.c	2009-05-12 14:38:53.000000000 +0200
-+++ mipv6-daemon-umip-0.4_patch_nepl_mcoa_sho/src/mn.c	2009-05-12 14:33:25.000000000 +0200
-@@ -130,6 +130,8 @@
- 	 * is the BID number. BID must be between 
- 	 * BCE_TABLE_MIN and BCE_TABLE_MAX
- 	 */
-+        MDBG("--------------------------------------\n");
-+        MDBG("mcoa_mn_init_rt_table()\n");
- 	assert(bule);
- 
- 	/* If BID is not assigned, default table is taken */
-@@ -147,6 +149,8 @@
- {
- 	int ret = -1;
- 
-+        MDBG("--------------------------------------\n");
-+        MDBG("mn_block_rule_del()\n");
- 	if (!(hai->home_block & HOME_ADDR_RULE_BLOCK)) {
- 		MDBG("blackhole is not set.\n");
- 		return ret;
-@@ -166,6 +170,8 @@
- {
- 	int ret = -1;
- 
-+        MDBG("--------------------------------------\n");
-+        MDBG("mn_block_rule_add()\n");
- 	if (hai->home_block & HOME_ADDR_RULE_BLOCK) {
- 		MDBG("blackhole is already set.\n");
- 		return ret;
-@@ -182,6 +188,8 @@
- 
- static void bul_expire(struct tq_elem *tqe)
- {
-+        MDBG("--------------------------------------\n");
-+        MDBG("bul_expire()\n");
- 	pthread_rwlock_wrlock(&mn_lock);
- 	if (!task_interrupted()) {
- 		struct bulentry *bule = tq_data(tqe, struct bulentry, tqe);
-@@ -205,6 +213,8 @@
- 	uint16_t flags = e->flags;
- 	uint16_t bid = e->bid;
- 
-+        MDBG("--------------------------------------\n");
-+        MDBG("bule_invalidate()\n");
- 	if (type != BUL_ENTRY) 
- 		return;
- 
-@@ -307,6 +317,8 @@
- 	struct in6_addr *raddr = &ip6h->ip6_dst;
- 	struct in6_addr addr;
- 
-+        MDBG("--------------------------------------\n");
-+        MDBG("mn_recv_param_prob()\n");
- 	/* We only handle code 1 & 2 messages. */
- 	if (ih->icmp6_code != ICMP6_PARAMPROB_NEXTHEADER &&
- 	    ih->icmp6_code != ICMP6_PARAMPROB_OPTION)
-@@ -623,6 +635,8 @@
-  */
- static int mn_dereg_bule(struct bulentry *bule)
- {
-+        MDBG("--------------------------------------\n");
-+        MDBG("mn_dereg_bule()\n");
- 	if (bule->type != NON_MIP_CN_ENTRY) {
- 		bule->seq++;
- 		bule->mcoa_dereg = 0;
-@@ -637,6 +651,8 @@
- {
- 	struct bulentry *bule = vbule;
- 
-+        MDBG("--------------------------------------\n");
-+        MDBG("mn_dereg()\n");
- 	if (bule->type == BUL_ENTRY) {
- 		if (!(bule->flags & IP6_MH_BU_HOME)) {
- 			bule->dereg = 1;
-@@ -684,6 +700,8 @@
- {
- 	int dhaad = dhaad_home_reg_failed(hai);
- 	int type = FLUSH_VALID;
-+        MDBG("--------------------------------------\n");
-+        MDBG("mn_change_ha()\n");
- 	if (hai->home_reg_status != HOME_REG_NONE)
- 		bul_iterate(&hai->bul, _bul_flush, &type);
- 	syslog(LOG_ERR,
-@@ -820,6 +838,8 @@
- 	uint32_t valid = PREFIX_LIFETIME_INFINITE;
- 	int plen = (mha->if_next == hai->if_tunnel ? 128 : hai->plen);
- 
-+        MDBG("--------------------------------------\n");
-+        MDBG("mv_hoa\n");
- 	clock_gettime(CLOCK_REALTIME, &now);
- 
- 	if (hai->lladdr_comp && rta_tb[IFA_CACHEINFO] != NULL) {
-@@ -889,6 +909,8 @@
- {
- 	struct list_head *l;
- 	struct prefix_list_entry *pe;
-+        MDBG("--------------------------------------\n");
-+        MDBG("nemo_mr_tnl_routes_add\n");
- 	list_for_each(l, &hai->mob_net_prefixes) {
- 		struct prefix_list_entry *p;
- 		p = list_entry(l, struct prefix_list_entry, list);
-@@ -917,6 +939,8 @@
- 			    int ifindex, int all, int rtable)
- {
- 	int err = 0;
-+        MDBG("--------------------------------------\n");
-+        MDBG("mn_tnl_state_add\n");
- 	if (hai->home_reg_status != HOME_REG_NONE) {
- 		if ((err = mn_ro_pol_add(hai, ifindex, all)) < 0)
- 			return err;
-@@ -939,6 +963,8 @@
- 				   int ifindex, int rtable)
- {
- 	struct list_head *l;
-+        MDBG("--------------------------------------\n");
-+        MDBG("nemo_mr_tnl_routes_del\n");
- 	list_for_each(l, &hai->mob_net_prefixes) {
- 		struct prefix_list_entry *p;
- 		p = list_entry(l, struct prefix_list_entry, list);
-@@ -1001,6 +1027,8 @@
- 				 struct home_addr_info *hai,
- 				 struct timespec *lifetime)
- {
-+        MDBG("--------------------------------------\n");
-+        MDBG("process_first_home_bu\n");
- 	int err = 0;
- 	assert(hai->current_coa);
- 	bule->type = BUL_ENTRY;
-@@ -1090,6 +1118,8 @@
- 	int homereg_expired = 0;
- 	movement_t type_movement = MIP6_TYPE_MOVEMENT_UNKNOWN;
- 
-+        MDBG("--------------------------------------\n");
-+        MDBG("mn_send_home_bu\n");
- 	TRACE;
- 	assert(hai->current_coa);
- 
-@@ -1285,6 +1315,8 @@
- 
- void mn_send_cn_bu(struct bulentry *bule)
- {
-+        MDBG("--------------------------------------\n");
-+        MDBG("mn_send_cn_bu\n");
- 	/* Rate limiting CN registration binding updates
- 	   is necessary for multihomed MNs */
- 	if (mn_bu_ratelimit(bule))
-@@ -1487,6 +1519,8 @@
- 	struct timespec now, ba_lifetime, br_adv;
- 	uint16_t seqno, bid;
- 
-+        MDBG("--------------------------------------\n");
-+        MDBG("mn_recv_ba\n");
- 	TRACE;
- 
- 	if (len < sizeof(struct ip6_mh_binding_ack) ||
-@@ -1875,6 +1909,8 @@
- 					struct home_addr_info *hai,
- 					int replace)
- {
-+        MDBG("--------------------------------------\n");
-+        MDBG("mcoa_iface_dflt_hoa_rule_del\n");
- 	/* MCoA: Delete the default HoA rule */
- 	rule_del(NULL, bule->bid, IP6_RULE_PRIO_MIP6_HOA_OUT, 
- 		0, RTN_UNICAST, &hai->hoa.addr, 128,
-@@ -1900,6 +1936,8 @@
- 					  struct prefix_list_entry *p,
- 					  int replace)
- {
-+        MDBG("--------------------------------------\n");
-+        MDBG("mcoa_iface_dflt_mnp_rules_del\n");
- 	/* 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, 
-@@ -1926,6 +1964,8 @@
- 	struct list_head *l;
- 	int delete_dflt_mnp = 0;
- 
-+        MDBG("--------------------------------------\n");
-+        MDBG("mcoa_iface_rules_del\n");
- 	bule = bul_get(hai,  NULL, &hai->ha_addr, bid);
- 	if (!hai->reg_mcoa || (bule && !bule->rules))
- 		return NULL;
-@@ -1977,6 +2017,8 @@
- {
- 	struct list_head *l;
-  
-+        MDBG("--------------------------------------\n");
-+        MDBG("mcoa_mn_rules_del\n");
- 	list_for_each(l, &hinfo->mcoa) {
- 		struct mn_addr *iface = NULL;
- 		iface = list_entry(l, struct mn_addr, list);
-@@ -2006,6 +2048,8 @@
- 	struct list_head *l;
- 	uint8_t prio;
-  
-+        MDBG("--------------------------------------\n");
-+        MDBG("mcoa_iface_rules_add\n");
- 	bule = bul_get(hai, NULL, &hai->ha_addr, bid);
- 	if (!bid || !hai->reg_mcoa || !bule || (bule && bule->rules))
- 		return 0;
-@@ -2088,6 +2132,8 @@
- {
- 	struct list_head *l;
- 
-+        MDBG("--------------------------------------\n");
-+        MDBG("nemo_mr_rules_del\n");
- 	list_for_each(l, &hinfo->mob_net_prefixes) {
- 		struct prefix_list_entry *p = NULL;
- 		p = list_entry(l, struct prefix_list_entry, list);
-@@ -2111,6 +2157,8 @@
- 	struct prefix_list_entry *pe = NULL;
- 	struct list_head *l;
- 
-+        MDBG("--------------------------------------\n");
-+        MDBG("nemo_mr_rules_add\n");
- 	list_for_each(l, &hinfo->mob_net_prefixes) {
- 		struct prefix_list_entry *p = NULL;
- 		p = list_entry(l, struct prefix_list_entry, list);
-@@ -2164,6 +2212,8 @@
- 	struct flag_hoa_args arg;
- 	int plen = (hai->hoa.iif == hai->if_tunnel ? 128 : hai->plen);
- 
-+        MDBG("--------------------------------------\n");
-+        MDBG("clean_home_addr_info\n");
- 	list_del(&hai->list);
- 	if (hai->mob_rtr)
- 		nemo_mr_rules_del(hai);
-@@ -2538,6 +2588,8 @@
- 	struct mv_hoa_args mha;
- 	struct list_head *l;
- 
-+        MDBG("--------------------------------------\n");
-+        MDBG("mn_move\n");
- 	mha.target = hai;
- 
- 	TRACE;
-Only in mipv6-daemon-umip-0.4_patch_nepl_mcoa_sho/src: mn.c~
-diff -ur mipv6-daemon-umip-0.4.all.paches.original/src/movement.c mipv6-daemon-umip-0.4_patch_nepl_mcoa_sho/src/movement.c
---- mipv6-daemon-umip-0.4.all.paches.original/src/movement.c	2009-05-12 14:38:53.000000000 +0200
-+++ mipv6-daemon-umip-0.4_patch_nepl_mcoa_sho/src/movement.c	2009-05-12 14:33:25.000000000 +0200
-@@ -611,7 +611,9 @@
- 	memset(lladdr, 0, sizeof(struct in6_addr));
- 	uint8_t *eui = lladdr->s6_addr + 8;
- 	switch (iface_type) {
--	case ARPHRD_ETHER:
-+	case ARPHRD_EUROPENAIRMESH:
-+		memcpy(eui, hwa, 8);
-+		break;
- 	case ARPHRD_IEEE802:
- 	case ARPHRD_IEEE802_TR:
- 	case ARPHRD_IEEE80211:
-Only in mipv6-daemon-umip-0.4_patch_nepl_mcoa_sho/src: movement.c~
-diff -ur mipv6-daemon-umip-0.4.all.paches.original/src/ndisc.h mipv6-daemon-umip-0.4_patch_nepl_mcoa_sho/src/ndisc.h
---- mipv6-daemon-umip-0.4.all.paches.original/src/ndisc.h	2009-05-12 14:38:38.000000000 +0200
-+++ mipv6-daemon-umip-0.4_patch_nepl_mcoa_sho/src/ndisc.h	2009-05-12 14:33:25.000000000 +0200
-@@ -11,6 +11,8 @@
- {
- 	switch (iface_type) {
- 		/* supported physical devices */
-+	case ARPHRD_EUROPENAIRMESH:
-+		return 8;
- 	case ARPHRD_ETHER:
- 	case ARPHRD_IEEE802:
- 	case ARPHRD_IEEE802_TR:
-Only in mipv6-daemon-umip-0.4_patch_nepl_mcoa_sho/src: ndisc.h~
-Only in mipv6-daemon-umip-0.4_patch_nepl_mcoa_sho/src: pmgr.c
-Only in mipv6-daemon-umip-0.4_patch_nepl_mcoa_sho/src: pmgr.h
-Only in mipv6-daemon-umip-0.4_patch_nepl_mcoa_sho/src: scan.c
-Only in mipv6-daemon-umip-0.4_patch_nepl_mcoa_sho: stamp-h1
-Only in mipv6-daemon-umip-0.4.all.paches.original: ZE_PATCH.patch
diff --git a/openair3/NEMO_SHO/mipv6-daemon-umip-0.4-nepl-20080108.patch b/openair3/NEMO_SHO/mipv6-daemon-umip-0.4-nepl-20080108.patch
deleted file mode 100755
index 7d70c0d531afe6c1b3c27f979942812262204c4d..0000000000000000000000000000000000000000
--- a/openair3/NEMO_SHO/mipv6-daemon-umip-0.4-nepl-20080108.patch
+++ /dev/null
@@ -1,2862 +0,0 @@
-diff -r a7e20b0b5c43 AUTHORS
---- a/AUTHORS	Wed Nov 28 16:43:32 2007 +0100
-+++ b/AUTHORS	Tue Jan 08 11:28:48 2008 +0100
-@@ -5,3 +5,14 @@ Petander.  Code has been contributed by 
- Petander.  Code has been contributed by several individuals.  See
- THANKS for listing.  See libnetlink/README for information regarding
- libnetlink.
-+
-+The NEMO Basic support code is developed by Ville Nuorvala
-+<vnuorval@tcs.hut.fi> in co-operation with the Nautilus6/WIDE
-+project (http://www.nautilus6.org).
-+
-+The NEMO Basic Support code has been ported to UMIP by Romain KUNTZ
-+<kuntz@lsiit.u-strasbg.fr> and received contributions from the
-+following people:
-+- Sebastien DECUGIS (Nautilus6): IPsec support for NEMO
-+- Arnaud EBALARD (EADS): fixes for Big Endian architectures and
-+  improvements of the NEMO debug messages.
-diff -r a7e20b0b5c43 BUGS
---- a/BUGS	Wed Nov 28 16:43:32 2007 +0100
-+++ b/BUGS	Tue Jan 08 11:28:48 2008 +0100
-@@ -17,3 +17,11 @@ Mobile Node issues
- * Multihoming support hasn't been very thoroughly tested and should
-   therefore be considered developmental code.  However, it is a lot
-   more stable than in the Release Candidates.
-+
-+NEMO issues
-+-----------
-+
-+* The Mobile Router's home address may only be on the egress interface.
-+
-+* Dynamic routing protocols between the Home Agent and Mobile Router
-+  are not yet supported.
-diff -r a7e20b0b5c43 COPYING.NEMO
---- /dev/null	Thu Jan 01 00:00:00 1970 +0000
-+++ b/COPYING.NEMO	Tue Jan 08 11:28:48 2008 +0100
-@@ -0,0 +1,13 @@
-+Cisco and Nokia have both published IPR notices regarding RFC 3963
-+"Network Mobility (NEMO) Basic Support Protocol."
-+
-+Cisco has agreed not to assert its patents against any party agreeing with the
-+terms in its IPR notice.
-+
-+Likewise, Nokia has agreed not to assert its patents against Open Source
-+implementations of the specification.
-+
-+For further information, please read
-+licenses/cisco-ipr-draft-ietf-nemo-basic-support-03.txt and 
-+licenses/nokia-ipr-draft-ietf-nemo-basic-support.txt.
-+
-diff -r a7e20b0b5c43 INSTALL
---- a/INSTALL	Wed Nov 28 16:43:32 2007 +0100
-+++ b/INSTALL	Tue Jan 08 11:28:48 2008 +0100
-@@ -45,6 +45,8 @@ 4. Run 'make install'.  Executables shou
-    further information on how to configure your node.  Also take a
-    look at the example configuration files in the extras directory.
- 
-+   For comments about NEMO check README.NEMO.
-+
-    For comments about IPsec support check README.IPsec.
- 
- 5. A startup script 
-diff -r a7e20b0b5c43 README
---- a/README	Wed Nov 28 16:43:32 2007 +0100
-+++ b/README	Tue Jan 08 11:28:48 2008 +0100
-@@ -2,6 +2,9 @@ MIPL Mobile IPv6 for Linux
- 
-   MIPL Mobile IPv6 for Linux is an implementation of the Mobility
-   Support in IP version 6 (RFC 3775).
-+
-+  It also supports Network Mobility with the NEMO Basic Support
-+  implementation (RFC 3963).
-   
-   This user space part works together with Mobile IPv6 enabled Linux
-   kernels.  See INSTALL and any other documents referred there for
-diff -r a7e20b0b5c43 README.NEMO
---- /dev/null	Thu Jan 01 00:00:00 1970 +0000
-+++ b/README.NEMO	Tue Jan 08 11:28:48 2008 +0100
-@@ -0,0 +1,18 @@
-+README for NEMO Basic Support 
-+-----------------------------
-+
-+Here are a few things you need to keep in mind when setting up Network
-+Mobility:
-+
-+The MR is a router so you need to set
-+/proc/sys/net/ipv6/conf/all/forwarding to 1 to make sure it will forward
-+packets between its ingress and egress interfaces.
-+
-+With static routing the HA and other routers on the home link might need some
-+additional boot-strapping.  If the MR has a physical home link that it may be
-+attached to, the other routers must be pre-configured with routes to the MR's
-+Mobile Network Prefixes via the MR's home address.  This ensures packets will
-+be forwarded correctly also when the MR is at home.
-+
-+To be able to support NEMO DHAAD the HA needs to have AdvHomeAgentInfo and
-+AdvMobRtrSupportFlag turned on in radvd.conf.
-diff -r a7e20b0b5c43 include/netinet/icmp6.h
---- a/include/netinet/icmp6.h	Wed Nov 28 16:43:32 2007 +0100
-+++ b/include/netinet/icmp6.h	Tue Jan 08 11:28:48 2008 +0100
-@@ -27,7 +27,13 @@ struct mip_dhaad_req {		/* Dynamic HA Ad
- #define mip_dhreq_code			mip_dhreq_hdr.icmp6_code
- #define mip_dhreq_cksum			mip_dhreq_hdr.icmp6_cksum
- #define mip_dhreq_id			mip_dhreq_hdr.icmp6_data16[0]
--#define mip_dhreq_reserved		mip_dhreq_hdr.icmp6_data16[1]
-+#define mip_dhreq_flags_reserved	mip_dhreq_hdr.icmp6_data16[1]
-+
-+#if BYTE_ORDER == BIG_ENDIAN
-+#define MIP_DHREQ_FLAG_SUPPORT_MR	0x8000
-+#else				/* BYTE_ORDER == LITTLE_ENDIAN */
-+#define MIP_DHREQ_FLAG_SUPPORT_MR	0x0080
-+#endif
- #endif
- 
- #ifndef HAVE_STRUCT_MIP_DHAAD_REP
-@@ -40,7 +46,13 @@ struct mip_dhaad_rep {		/* HA Address Di
- #define mip_dhrep_code			mip_dhrep_hdr.icmp6_code
- #define mip_dhrep_cksum			mip_dhrep_hdr.icmp6_cksum
- #define mip_dhrep_id			mip_dhrep_hdr.icmp6_data16[0]
--#define mip_dhrep_reserved		mip_dhrep_hdr.icmp6_data16[1]
-+#define mip_dhrep_flags_reserved	mip_dhrep_hdr.icmp6_data16[1]
-+
-+#if BYTE_ORDER == BIG_ENDIAN
-+#define MIP_DHREP_FLAG_SUPPORT_MR	0x8000
-+#else				/* BYTE_ORDER == LITTLE_ENDIAN */
-+#define MIP_DHREP_FLAG_SUPPORT_MR	0x0080
-+#endif
- #endif
- 
- #ifndef HAVE_STRUCT_MIP_PREFIX_SOLICIT
-@@ -89,10 +101,20 @@ struct nd_opt_homeagent_info {	/* Home A
- struct nd_opt_homeagent_info {	/* Home Agent information */
- 	uint8_t		nd_opt_hai_type;
- 	uint8_t		nd_opt_hai_len;
--	uint16_t	nd_opt_hai_reserved;
-+	uint16_t	nd_opt_hai_flags_reserved;
- 	uint16_t	nd_opt_hai_preference;
- 	uint16_t	nd_opt_hai_lifetime;
- };
- #endif
- 
-+#define nd_opt_hai_reserved     nd_opt_hai_flags_reserved
-+
-+#ifndef ND_OPT_HAI_FLAG_SUPPORT_MR
-+#if BYTE_ORDER == BIG_ENDIAN
-+#define ND_OPT_HAI_FLAG_SUPPORT_MR	0x8000
-+#else				/* BYTE_ORDER == LITTLE_ENDIAN */
-+#define ND_OPT_HAI_FLAG_SUPPORT_MR	0x0080
-+#endif
-+#endif
-+
- #endif	/* netinet/icmp6.h */
-diff -r a7e20b0b5c43 licenses/cisco-ipr-draft-ietf-nemo-basic-support-03.txt
---- /dev/null	Thu Jan 01 00:00:00 1970 +0000
-+++ b/licenses/cisco-ipr-draft-ietf-nemo-basic-support-03.txt	Tue Jan 08 11:28:48 2008 +0100
-@@ -0,0 +1,41 @@
-+Title: Cisco Systems' Updated Statement about IPR claimed in
-+       draft-ietf-nemo-basic-support-03.txt
-+Received 25 October 2004
-+From: Robert Barr <rbarr@cisco.com>
-+
-+This statement updates the IPR statement filed by Cisco on June 20, 2003 for
-+draft-ietf-nemo-basic-support-00.txt.
-+
-+Cisco is the owner of US Patent No. 6,636,498 and at least one pending
-+patent application
-+relating to the subject matter of draft-ietf-nemo-basic-support-03.txt
-+"Network Mobility (NEMO) Basic Support Protocol" .
-+If a standard relating to this subject matter is adopted by IETF and any
-+claims
-+of any issued Cisco patents are necessary for practicing this standard, any
-+party will be able to obtain a license from Cisco to use any such patent
-+claims under openly specified, reasonable, non-discriminatory terms, with
-+reciprocity, to implement and fully comply with the standard.
-+
-+The reasonable non-discriminatory terms are:
-+
-+If this standard is adopted, Cisco will not assert any patents owned or
-+controlled by Cisco against any party for making, using, selling, importing
-+or offering for sale a product that implements the standard, provided,
-+however that Cisco retains the right to assert its patents (including the
-+right to claim past royalties) against any party that asserts a patent it
-+owns or controls (either directly or indirectly) against Cisco or any of
-+Cisco's affiliates or successors in title; and Cisco retains the right to
-+assert its patents against any product or portion thereof that is not
-+necessary for compliance with the standard.
-+
-+Royalty-bearing licenses will be available to anyone who prefers that
-+option.
-+
-+For information contact:
-+
-+Robert Barr
-+Worldwide Patent Counsel
-+Cisco Systems
-+408-525-9706
-+rbarr@cisco.com
-diff -r a7e20b0b5c43 licenses/nokia-ipr-draft-ietf-nemo-basic-support.txt
---- /dev/null	Thu Jan 01 00:00:00 1970 +0000
-+++ b/licenses/nokia-ipr-draft-ietf-nemo-basic-support.txt	Tue Jan 08 11:28:48 2008 +0100
-@@ -0,0 +1,26 @@
-+Title: Nokia Corporation's statement about IPR claimed in draft-ietf-nemo-basic-support
-+Received: July 1, 2003
-+From: Heikki Huttunen <heikki.a.huttunen@nokia.com>
-+
-+This is to advise the IETF that Nokia believes the Nokia patent application "Mobile Router 
-+Support for IPv6", US10/295014, WO03/043226 may be relevant to Nemo Basic Support Protocol 
-+<draft-ietf-nemo-basic-support>.
-+
-+Regarding internet draft "draft-ietf-nemo-basic-support", to the extent this draft is 
-+included into final IETF standard specification, Nokia agrees not to assert those claims 
-+in Nokia patents that apply to this draft and that are technically necessary to implement 
-+the IETF standard specification against any other party in respect of its implementation of 
-+the specification, if only practiced under any software distributed under the present terms 
-+of GNU GENERAL PUBLIC LICENSE (http://www.fsf.org/copyleft/gpl.html) or under license terms 
-+that conform to the present open source definition (http://www.opensource.org/osd.html) and 
-+provided that the party relying on this commitment does not assert its patents against Nokia.
-+
-+Otherwise general Nokia Statement on Patent Licensing (http://www.ietf.org/ietf/IPR/NOKIA) 
-+applies to this submission. 
-+
-+
-+Heikki Huttunen
-+Director, Licensing
-+Nokia Corporation
-+P.O Box 86, FIN-24101 Salo, Finland
-+Phone: +358 (0) 7180 41202, Fax: +358 (0) 7180 44275
-diff -r a7e20b0b5c43 man/mip6d.conf.tmpl
---- a/man/mip6d.conf.tmpl	Wed Nov 28 16:43:32 2007 +0100
-+++ b/man/mip6d.conf.tmpl	Tue Jan 08 11:28:48 2008 +0100
-@@ -1,12 +1,12 @@
- .\" $Id: mip6d.conf.tmpl 1.33 06/05/12 11:48:36+03:00 vnuorval@tcs.hut.fi $
--.TH mip6d.conf 5 "January 31, 2006" "" "Mobile IPv6 Daemon Configuration"
-+.TH mip6d.conf 5 "January 31, 2006" "" "Mobile IPv6 and NEMO Daemon Configuration"
- .SH NAME
--mip6d.conf \- MIPL Mobile IPv6 Configuration file
-+mip6d.conf \- MIPL Mobile IPv6 and NEMO Configuration file
- .SH SYNOPSIS
- .B %etc%/mip6d.conf
- .sp
- .SH DESCRIPTION
--MIPL Mobile IPv6 daemon's configuration file
-+MIPL Mobile IPv6 and NEMO daemon's configuration file
- .P
- Below is a list of currently supported configuration options. All
- configuration lines are terminated with a semicolon.  Sub-sections are
-@@ -184,10 +184,29 @@ Default: 86400
- Default: 86400
- 
- .TP
--.BR "BindingAclPolicy " "address " "allow | deny"
-+.BR "HaAcceptMobRtr enabled | disabled"
- 
--Defines if a MN is allowed to register with the HA or not. The MN home address
--of the MN is given in the address field."
-+Indicates if the HA accepts Mobile Router bindings.
-+
-+Default: disabled;
-+
-+.TP
-+.BR "HaServedPrefix " "prefix/length" ";"
-+
-+Prefix is an IPv6 prefix and length is the prefix length. Defines the whole
-+aggregated or extended prefix the HA serves. This option is only used for MR
-+bindings and is only needed if the MRs derive their Home Addresses from their
-+Mobile Network Prefixes, instead of one of the home link prefixes.
-+
-+.TP
-+.BR "BindingAclPolicy " "address MNP list " "allow | deny"
-+
-+Defines if a MN is allowed to register with the HA or not. The home address
-+of the MN is given in the address field.  The mobile network prefixes
-+belonging a NEMO Mobile Router are listed in the MNP list. The list can either
-+be an empty string or a comma separated list of network prefixes
-+enclosed in braces, for example:
-+.B "(3ffe:2620:6:3::/64, 3ffe:2620:6:4::/64)"
- 
- .TP
- .BR "DefaultBindingAclPolicy allow | deny"
-@@ -254,6 +273,13 @@ Default: disabled
- Default: disabled
- 
- .TP
-+.BR "MobRtrUseExplicitMode enabled | disabled"
-+
-+Toggles between explicit or implicit mode home registrations in the MR.
-+
-+Default: enabled
-+
-+.TP
- .BR "UseCnBuAck " "boolean" ";"
- 
- Indicates if the Acknowledge bit should be set in Binding Updates sent to
-@@ -299,7 +325,7 @@ Default: disabled;
- .TP
- .nf
- .BR "MnHomeLink " "name " "{"
--.BR "	HomeAddress " "address/length" ";"
-+.BR "	HomeAddress " "address/length MNP list" ";"
- .BR "	HomeAgentAddress " "address" ";"
- .BR "	MnRoPolicy ..."
- .BR "	..."
-@@ -317,11 +343,14 @@ definitions.  All the home link specific
- definitions.  All the home link specific definitions are detailed below: 
- 
- .TP
--.BR "HomeAddress " "address/length" ";"
-+.BR "HomeAddress " "address/length MNP list" ";"
- 
- Address is an IPv6 address, and length the prefix length of the
--address, usually 64.  This option must be included in a home link
--definition.
-+address, usually 64.  The MNP list contains the mobile network prefixes
-+belonging to that particular NEMO Mobile Router. The MNP list is of the
-+same format as in
-+.B "BindingAclPolicy."
-+This option must be included in a home link definition.
- 
- .TP
- .BR "HomeAgentAddress " "address" ";"
-@@ -330,6 +359,13 @@ if it is the unspecified address ::.
- if it is the unspecified address ::.
- 
- Default: ::
-+
-+.TP
-+.BR "IsMobRtr enabled | disabled"
-+
-+Defines if the MN is a NEMO MR.
-+
-+Default: disabled
- 
- .TP
- The route optimization policies are of the form:
-@@ -351,6 +387,49 @@ matching this entry.
- matching this entry.
- 
- .SH EXAMPLES
-+
-+.TP
-+.BR "A NEMO Home Agent example:"
-+
-+.nf
-+NodeConfig HA;
-+
-+Interface "eth0";
-+
-+HaAcceptMobRtr enabled;
-+
-+HaServedPrefix 3ffe:2620:6::/48;
-+
-+DefaultBindingAclPolicy deny;
-+BindingAclPolicy 3ffe:2620:6:1::1234 (3ffe:2620:6:2::/64, 3ffe:2620:6:3::/64) allow;
-+BindingAclPolicy 3ffe:2620:6:1::1235 allow;
-+
-+UseMnHaIPsec disabled;
-+.fi
-+
-+.TP
-+.BR "A NEMO Mobile Router example:"
-+
-+.nf
-+NodeConfig MN;
-+
-+DoRouteOptimizationCN disabled;
-+DoRouteOptimizationMN disabled;
-+
-+Interface "eth0";
-+
-+MnRouterProbes 1;
-+
-+MobRtrUseExplicitMode enabled;
-+
-+MnHomeLink "eth0" {
-+        IsMobRtr enabled;
-+        HomeAgentAddress 3ffe:2620:6:1::1;
-+        HomeAddress 3ffe:2620:6:1::1234/64 (3ffe:2620:6:2::/64, 3ffe:2620:6:3::/64);
-+}
-+
-+UseMnHaIPsec disabled;
-+.fi
- 
- .TP
- .BR "A Correspondent Node example:"
-diff -r a7e20b0b5c43 man/mip6d.tmpl
---- a/man/mip6d.tmpl	Wed Nov 28 16:43:32 2007 +0100
-+++ b/man/mip6d.tmpl	Tue Jan 08 11:28:48 2008 +0100
-@@ -1,13 +1,13 @@
- .\" $Id: mip6d.tmpl 1.4 05/05/16 13:13:41+03:00 anttit@tcs.hut.fi $
--.TH mip6d 1 "May 16, 2005" "" "Mobile IPv6 Daemon"
-+.TH mip6d 1 "May 16, 2005" "" "Mobile IPv6 and NEMO Daemon"
- .SH NAME
--mip6d \- MIPL Mobile IPv6 protocol implementation
-+mip6d \- MIPL Mobile IPv6 and NEMO Basic Support protocol implementation
- .SH SYNOPSIS
- .B mip6d [options]
- .sp
- .SH DESCRIPTION
- 
--Mobile IPv6 implementation
-+Mobile IPv6 and NEMO Basic Support implementation
- 
- .SH OPTIONS
- .IP "\fB\-V, \-\-version\fP"
-@@ -41,3 +41,5 @@ RFC3775: Mobility Support in IPv6,
- .PP
- RFC3776: Using IPsec to Protect Mobile IPv6 Signaling Between Mobile
- Nodes and Home Agents
-+.PP
-+RFC3963: Network Mobility (NEMO) Basic Support Protocol
-diff -r a7e20b0b5c43 src/bcache.c
---- a/src/bcache.c	Wed Nov 28 16:43:32 2007 +0100
-+++ b/src/bcache.c	Tue Jan 08 11:28:48 2008 +0100
-@@ -39,6 +39,7 @@
- #include "mh.h"
- #include "cn.h"
- #include "vt.h"
-+#include "prefix.h"
- 
- #define BCACHE_BUCKETS 32
- 
-@@ -63,6 +64,7 @@ void dump_bce(void *bce, void *os)
- {
- 	struct bcentry *e = (struct bcentry *)bce;
- 	FILE *out = (FILE *)os;
-+	int mnpcount = 0;
- 
- 	fprintf(out, " == Binding Cache entry ");
- 
-@@ -87,6 +89,37 @@ void dump_bce(void *bce, void *os)
- 		NIP6ADDR(&e->our_addr));
- 	fprintf(out, " lifetime %ld\n ", e->lifetime.tv_sec);
- 	fprintf(out, " seqno %d\n", e->seqno);
-+
-+	if (e->flags & IP6_MH_BA_MR) {
-+		struct list_head *list;
-+
-+		/* MR registration type */
-+		fprintf(out, "MR Registration type: ");
-+		switch(e->nemo_type) {
-+		case BCE_NEMO_EXPLICIT:
-+			fprintf(out, "explicit.\n");
-+			break;
-+		case BCE_NEMO_IMPLICIT:
-+			fprintf(out, "implicit.\n");
-+			break;
-+		default:
-+			fprintf(out, "unknown.\n");
-+		}
-+
-+		/* Mobile Network prefixes */
-+		fprintf(out, "MR Mobile network prefixes: ");
-+		list_for_each(list, &e->mob_net_prefixes) {
-+			struct prefix_list_entry *p;
-+			p = list_entry(list, struct prefix_list_entry, list);
-+			if (mnpcount)
-+				fprintf(out, "                            ");
-+			fprintf(out, "%x:%x:%x:%x:%x:%x:%x:%x/%d\n",
-+				NIP6ADDR(&p->ple_prefix), p->ple_plen);
-+			mnpcount++;
-+		}
-+		if (!mnpcount)
-+			fprintf(out, " none registered.\n");
-+	}
- 
- 	fflush(out);
- }
-@@ -144,6 +177,7 @@ struct bcentry *bcache_alloc(int type)
- 	}
- 	memset(tmp, 0, sizeof(*tmp));
- 	INIT_LIST_HEAD(&tmp->tqe.list);
-+	INIT_LIST_HEAD(&tmp->mob_net_prefixes);
- 	return tmp;
- }
- 
-@@ -158,6 +192,7 @@ void bcache_free(struct bcentry *bce)
- 	/* This function should really return allocated space to free
- 	 * pool. */
- 	pthread_rwlock_destroy(&bce->lock);
-+	prefix_list_free(&bce->mob_net_prefixes);
- 	free(bce);
- }
- 
-diff -r a7e20b0b5c43 src/bcache.h
---- a/src/bcache.h	Wed Nov 28 16:43:32 2007 +0100
-+++ b/src/bcache.h	Tue Jan 08 11:28:48 2008 +0100
-@@ -18,7 +18,8 @@ struct bcentry {
- 
- 	uint16_t nonce_coa;
- 	uint16_t nonce_hoa;
--	int type;			/* Entry type */
-+	uint16_t type;     		/* Entry type */
-+	uint16_t nemo_type;    		/* NEMO registration type */
- 	int unreach;			/* ICMP dest unreach count */
- 	int tunnel;			/* Tunnel interface index */
- 	int link;			/* Home link interface index */
-@@ -33,6 +34,8 @@ struct bcentry {
- 	struct tq_elem tqe;		/* Timer queue entry for expire */
- 
- 	void (*cleanup)(struct bcentry *bce); /* Clean up bce data */
-+
-+	struct list_head mob_net_prefixes;
- };
- 
- #define BCE_NONCE_BLOCK 0
-@@ -40,6 +43,10 @@ struct bcentry {
- #define BCE_CACHED  2
- #define BCE_CACHE_DYING 3
- #define BCE_DAD 4
-+
-+#define BCE_NEMO_EXPLICIT 1
-+#define BCE_NEMO_IMPLICIT 2
-+#define BCE_NEMO_DYNAMIC 3
- 
- struct bcentry *bcache_alloc(int type);
- 
-diff -r a7e20b0b5c43 src/bul.c
---- a/src/bul.c	Wed Nov 28 16:43:32 2007 +0100
-+++ b/src/bul.c	Tue Jan 08 11:28:48 2008 +0100
-@@ -103,9 +103,11 @@ void dump_bule(void *bule, void *os)
- 	if (e->flags & IP6_MH_BU_ACK)
- 		fprintf(out, "IP6_MH_BU_ACK ");
- 	if (e->flags & IP6_MH_BU_LLOCAL)
--		fprintf(out, "IP6_MH_BU_LLOCAL");
-+		fprintf(out, "IP6_MH_BU_LLOCAL ");
- 	if (e->flags & IP6_MH_BU_KEYM)
--		fprintf(out, "IP6_MH_BU_KEYM");
-+		fprintf(out, "IP6_MH_BU_KEYM ");
-+	if (e->flags & IP6_MH_BU_MR)
-+		fprintf(out, "IP6_MH_BU_MR");
- 
- 	fprintf(out, "\n");
- 	fflush(out);
-@@ -184,7 +186,8 @@ int bul_add(struct bulentry *bule)
- 			goto home_bul_free;
- 	} else if (bule->type == NON_MIP_CN_ENTRY) {
- 		if (bule->flags & IP6_MH_BU_HOME) {
--			if (xfrm_block_hoa(hai) < 0)
-+			if (xfrm_block_hoa(hai) < 0 ||
-+			    (hai->mob_rtr && xfrm_block_ra(hai) < 0))
- 				goto home_bul_free;
- 		}
- 	}
-@@ -231,6 +234,10 @@ void bul_delete(struct bulentry *bule)
- 				xfrm_unblock_link(hai);
- 			if (hai->home_block & HOME_ADDR_BLOCK)
- 				xfrm_unblock_hoa(hai);
-+			if (hai->home_block & NEMO_RA_BLOCK)
-+				xfrm_unblock_ra(hai);
-+			if (hai->home_block & NEMO_FWD_BLOCK)
-+				xfrm_unblock_fwd(hai);
- 		}
- 	}
- 	while (bule->ext_cleanup)
-diff -r a7e20b0b5c43 src/cn.c
---- a/src/cn.c	Wed Nov 28 16:43:32 2007 +0100
-+++ b/src/cn.c	Tue Jan 08 11:28:48 2008 +0100
-@@ -177,8 +177,8 @@ void cn_recv_bu(const struct ip6_mh *mh,
- 	non_ind = mh_opt(&bu->ip6mhbu_hdr, &mh_opts, IP6_MHOPT_NONCEID);
- 	bce = bcache_get(out.src, out.dst);
- 	if (bce) {
--		if ((bce->flags^bu_flags) & IP6_MH_BU_HOME) {
--			/* H-bit mismatch, flags changed */
-+		if ((bce->flags^bu_flags) & (IP6_MH_BU_HOME|IP6_MH_BU_MR)) {
-+			/* H-bit or R-bit mismatch, flags changed */
- 			bcache_release_entry(bce);
- 			bce = NULL;
- 			status = IP6_MH_BAS_REG_NOT_ALLOWED;
-@@ -221,9 +221,15 @@ void cn_recv_bu(const struct ip6_mh *mh,
- 			/* else get rid of it */
- 			bcache_delete(out.src, out.dst);
- 		}
--	} else if (bu_flags & IP6_MH_BU_HOME) {
--		status = IP6_MH_BAS_HA_NOT_SUPPORTED;
--		goto send_nack;
-+	} else {
-+		if (bu_flags & IP6_MH_BU_HOME) {
-+			status = IP6_MH_BAS_HA_NOT_SUPPORTED;
-+			goto send_nack;
-+		}
-+		if (bu_flags & IP6_MH_BU_MR) {
-+			status = IP6_MH_BAS_MR_OP_NOT_PERMITTED;
-+			goto send_nack;
-+		}
- 	}
- 	status = conf.pmgr.discard_binding(out.dst, out.bind_coa,
- 					   out.src, bu, len);
-diff -r a7e20b0b5c43 src/conf.c
---- a/src/conf.c	Wed Nov 28 16:43:32 2007 +0100
-+++ b/src/conf.c	Tue Jan 08 11:28:48 2008 +0100
-@@ -212,6 +212,7 @@ static void conf_default(struct mip6_con
- 	INIT_LIST_HEAD(&c->home_addrs);
- 	c->MoveModulePath = NULL; /* internal */
- 	c->DoRouteOptimizationMN = 1;
-+	c->MobRtrUseExplicitMode = 1;
- 	c->SendMobPfxSols = 1;
- 	c->OptimisticHandoff = 0;
- 
-@@ -221,6 +222,7 @@ static void conf_default(struct mip6_con
- 	c->MaxMobPfxAdvInterval = 86400; /* seconds */
- 	c->MinMobPfxAdvInterval = 600; /* seconds */
- 	c->HaMaxBindingLife = MAX_BINDING_LIFETIME;
-+	INIT_LIST_HEAD(&c->nemo_ha_served_prefixes);
- 
- 	/* CN bindings */
- 	c->DoRouteOptimizationCN = 1;
-@@ -304,6 +306,8 @@ void conf_show(struct mip6_config *c)
- 	    CONF_BOOL_STR(c->MnDiscardHaParamProb));
- 	dbg("SendMobPfxSols = %s\n", CONF_BOOL_STR(c->SendMobPfxSols));
- 	dbg("OptimisticHandoff = %s\n", CONF_BOOL_STR(c->OptimisticHandoff));
-+	dbg("MobRtrUseExplicitMode = %s\n",
-+	    CONF_BOOL_STR(c->MobRtrUseExplicitMode));
- 
- 	/* HA options */
- 	dbg("SendMobPfxAdvs = %s\n", CONF_BOOL_STR(c->SendMobPfxAdvs));
-@@ -312,7 +316,8 @@ void conf_show(struct mip6_config *c)
- 	dbg("MaxMobPfxAdvInterval = %u\n", c->MaxMobPfxAdvInterval);
- 	dbg("MinMobPfxAdvInterval = %u\n", c->MinMobPfxAdvInterval);
- 	dbg("HaMaxBindingLife = %u\n", c->HaMaxBindingLife);
--	
-+	dbg("HaAcceptMobRtr = %s\n", CONF_BOOL_STR(c->HaAcceptMobRtr));
-+
- 	/* CN options */
- 	dbg("DoRouteOptimizationCN = %s\n",
- 	    CONF_BOOL_STR(c->DoRouteOptimizationCN));
-diff -r a7e20b0b5c43 src/conf.h
---- a/src/conf.h	Wed Nov 28 16:43:32 2007 +0100
-+++ b/src/conf.h	Tue Jan 08 11:28:48 2008 +0100
-@@ -39,6 +39,7 @@ struct mip6_config {
- 	struct list_head home_addrs;
- 	char *MoveModulePath;
- 	uint16_t CnBuAck;
-+	char MobRtrUseExplicitMode;
- 	char DoRouteOptimizationMN;
- 	char MnUseAllInterfaces;
- 	char MnDiscardHaParamProb;
-@@ -46,15 +47,16 @@ struct mip6_config {
- 	char OptimisticHandoff;
- 
- 	/* HA options */
-+	char HaAcceptMobRtr;
- 	char SendMobPfxAdvs;
- 	char SendUnsolMobPfxAdvs;
- 	unsigned int MaxMobPfxAdvInterval;
- 	unsigned int MinMobPfxAdvInterval;
- 	unsigned int HaMaxBindingLife;
-+	struct list_head nemo_ha_served_prefixes;
- 
- 	/* CN options */
- 	char DoRouteOptimizationCN;
--
- };
- 
- struct net_iface {
-diff -r a7e20b0b5c43 src/dhaad_ha.c
---- a/src/dhaad_ha.c	Wed Nov 28 16:43:32 2007 +0100
-+++ b/src/dhaad_ha.c	Tue Jan 08 11:28:48 2008 +0100
-@@ -83,8 +83,8 @@ static void dhaad_expire_halist(struct t
- 	pthread_rwlock_unlock(&ha_lock);
- }
- 
--void dhaad_insert_halist(struct ha_interface *i, 
--			 uint16_t key, uint16_t life_sec,
-+void dhaad_insert_halist(struct ha_interface *i, uint16_t key,
-+			 uint16_t life_sec, uint16_t flags,
- 			 struct nd_opt_prefix_info *pinfo,
- 			 const struct in6_addr *lladdr)
- {
-@@ -110,6 +110,7 @@ void dhaad_insert_halist(struct ha_inter
- 			return;
- 		}
- 		memset(ha, 0, sizeof(*ha));
-+		ha->flags = flags;
- 		ha->iface = i;
- 		ha->addr = *addr;
- 		INIT_LIST_HEAD(&ha->tqe.list);
-@@ -136,18 +137,22 @@ void dhaad_insert_halist(struct ha_inter
- 	return;
- }
- 
--static int dhaad_get_halist(struct ha_interface *i, int max, struct iovec *iov)
-+static int dhaad_get_halist(struct ha_interface *i, uint16_t flags,
-+			    int max, struct iovec *iov)
- {
- 	struct list_head *lp;
- 	int n = 0;
- 	list_for_each(lp, &i->ha_list) {
- 		struct home_agent *h;
- 		h = list_entry(lp, struct home_agent, list);
--		n++;
--		iov[n].iov_len = sizeof(struct in6_addr);
--		iov[n].iov_base = &h->addr;
--		if (n >= max)
--			break;
-+		if (!(flags & MIP_DHREQ_FLAG_SUPPORT_MR) ||
-+		    h->flags & ND_OPT_HAI_FLAG_SUPPORT_MR) {
-+			n++;
-+			iov[n].iov_len = sizeof(struct in6_addr);
-+			iov[n].iov_base = &h->addr;
-+			if (n >= max)
-+				break;
-+		}
- 	}
- 	return n;
- }
-@@ -177,8 +182,12 @@ static void dhaad_recv_req(const struct 
- 
- 	rph->mip_dhrep_id = rqh->mip_dhreq_id;
- 
-+	if (rqh->mip_dhreq_flags_reserved & MIP_DHREQ_FLAG_SUPPORT_MR)
-+		rph->mip_dhrep_flags_reserved = MIP_DHREP_FLAG_SUPPORT_MR;
-+
- 	pthread_rwlock_rdlock(&ha_lock);
--	iovlen = dhaad_get_halist(i, MAX_HOME_AGENTS, iov);
-+	iovlen = dhaad_get_halist(i, rqh->mip_dhreq_flags_reserved,
-+				  MAX_HOME_AGENTS, iov);
- 	icmp6_send(i->ifindex, 64, ha_addr, src, iov, iovlen + 1);
- 	pthread_rwlock_unlock(&ha_lock);
- 	free_iov_data(&iov[0], 1);
-diff -r a7e20b0b5c43 src/dhaad_ha.h
---- a/src/dhaad_ha.h	Wed Nov 28 16:43:32 2007 +0100
-+++ b/src/dhaad_ha.h	Tue Jan 08 11:28:48 2008 +0100
-@@ -17,8 +17,8 @@ void dhaad_halist_iterate(struct ha_inte
- 			  int (* func)(int, void *, void *), void *arg);
- #endif
- 
--void dhaad_insert_halist(struct ha_interface *i, 
--			 uint16_t key, uint16_t life_sec,
-+void dhaad_insert_halist(struct ha_interface *i, uint16_t key,
-+			 uint16_t life_sec, uint16_t flags,
- 			 struct nd_opt_prefix_info *pinfo,
- 			 const struct in6_addr *lladdr);
- 
-diff -r a7e20b0b5c43 src/dhaad_mn.c
---- a/src/dhaad_mn.c	Wed Nov 28 16:43:32 2007 +0100
-+++ b/src/dhaad_mn.c	Tue Jan 08 11:28:48 2008 +0100
-@@ -86,7 +86,8 @@ static int dhaad_append_candidate(struct
- }
- 
- static int dhaad_send_request(int oif, struct in6_addr *src, 
--			      struct in6_addr *pfx, int plen)
-+			      struct in6_addr *pfx, int plen,
-+			      uint16_t flags)
- {
- 	struct mip_dhaad_req *ih;
- 	struct iovec iov;
-@@ -98,6 +99,7 @@ static int dhaad_send_request(int oif, s
- 	    return -1;
- 	id = dhaad_id++;
- 	ih->mip_dhreq_id = htons(id);
-+	ih->mip_dhreq_flags_reserved = flags;
- 	dhaad_gen_ha_anycast(&dst, pfx, plen);
- 	icmp6_send(oif, 0, src, &dst, &iov, 1);
- 	free_iov_data(&iov, 1);
-@@ -121,7 +123,9 @@ static void dhaad_resend(struct tq_elem 
- 		t->dhaad_id = dhaad_send_request(hai->primary_coa.iif,
- 						 &hai->primary_coa.addr,
- 						 &hai->home_prefix,
--						 hai->home_plen);
-+						 hai->home_plen,
-+						 hai->mob_rtr?
-+						 MIP_DHREQ_FLAG_SUPPORT_MR:0);
- 		t->dhaad_resends++;
- 		tsadd(t->dhaad_delay, t->dhaad_delay, t->dhaad_delay);
- 		add_task_rel(&t->dhaad_delay, &t->tqe, dhaad_resend);
-@@ -139,11 +143,15 @@ static void _dhaad_start(struct home_add
- 	      t->dhaad_resends == DHAAD_RETRIES))) {
- 		if (!(hai->home_block & HOME_ADDR_BLOCK))
- 			xfrm_block_hoa(hai);
-+		if (hai->mob_rtr && !(hai->home_block & NEMO_RA_BLOCK))
-+			xfrm_block_ra(hai);
- 		t->dhaad_resends = 0;
- 		t->dhaad_id = dhaad_send_request(hai->primary_coa.iif,
- 						 &hai->primary_coa.addr,
- 						 &hai->home_prefix,
--						 hai->home_plen);
-+						 hai->home_plen,
-+						 hai->mob_rtr?
-+						 MIP_DHREQ_FLAG_SUPPORT_MR:0);
- 		t->dhaad_delay = INITIAL_DHAAD_TIMEOUT_TS;
- 		add_task_rel(&t->dhaad_delay, &t->tqe, dhaad_resend);
- 	}
-@@ -165,6 +173,8 @@ static void _dhaad_stop(struct home_addr
- 	tsclear(t->dhaad_delay);
- 	if (hai->home_block & HOME_ADDR_BLOCK)
- 		xfrm_unblock_hoa(hai);
-+	if (hai->home_block & NEMO_RA_BLOCK)
-+		xfrm_unblock_ra(hai);
- }
- 
- void dhaad_stop(struct home_addr_info *hai)
-@@ -245,6 +255,12 @@ static void dhaad_recv_rep(const struct 
- 		pthread_rwlock_unlock(&mn_lock);
- 		return;
- 	}
-+	if (hai->mob_rtr &&
-+	    !(rph->mip_dhrep_flags_reserved & MIP_DHREP_FLAG_SUPPORT_MR)) {
-+		dbg("HA doesn't support MR\n");
-+		pthread_rwlock_unlock(&mn_lock);
-+		return;
-+	}
- 	ha = (struct in6_addr *)(ih + 1);
- 
- 	dhaad_flush_candidates(&hai->ha_list);
-diff -r a7e20b0b5c43 src/gram.y
---- a/src/gram.y	Wed Nov 28 16:43:32 2007 +0100
-+++ b/src/gram.y	Tue Jan 08 11:28:48 2008 +0100
-@@ -30,10 +30,10 @@
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
-+#include <stdio.h>
- #include <pthread.h>
- #include <netinet/in.h>
- #include <net/if.h>
--#include <stdio.h>
- #include <string.h>
- #include <stdarg.h>
- #include <netinet/ip6mh.h>
-@@ -54,8 +54,23 @@ struct net_iface ni = {
- };
- 	
- struct home_addr_info hai = {
--	.ro_policies = LIST_HEAD_INIT(hai.ro_policies)
-+	.ro_policies = LIST_HEAD_INIT(hai.ro_policies),
-+	.mob_net_prefixes = LIST_HEAD_INIT(hai.mob_net_prefixes)
- };
-+
-+LIST_HEAD(prefixes);
-+
-+int mv_prefixes(struct list_head *list)
-+{
-+	struct list_head *l, *n;
-+	int res = 0;
-+	list_for_each_safe(l, n, &prefixes) {
-+		list_del(l);
-+		list_add_tail(l, list);
-+		res++;
-+	}
-+	return res;
-+}
- 
- struct policy_bind_acl_entry *bae = NULL;
- 
-@@ -165,6 +180,11 @@ static void uerror(const char *fmt, ...)
- %token		MNROUTERPROBETIMEOUT
- %token		MNDISCARDHAPARAMPROB
- %token		OPTIMISTICHANDOFF
-+%token		HOMEPREFIX
-+%token		HAACCEPTMOBRTR
-+%token		ISMOBRTR
-+%token		HASERVEDPREFIX
-+%token		MOBRTRUSEEXPLICITMODE
- 
- %token		INV_TOKEN
- 
-@@ -282,6 +302,19 @@ topdef		: MIP6ENTITY mip6entity ';'
- 		{
- 			conf.DefaultBindingAclPolicy = $2;
- 		}
-+		| HAACCEPTMOBRTR BOOL ';'
-+		{
-+			conf.HaAcceptMobRtr = $2;
-+		}
-+		| HASERVEDPREFIX prefixlistentry ';'
-+		{
-+			list_splice(&prefixes,
-+				    conf.nemo_ha_served_prefixes.prev);
-+		}
-+		| MOBRTRUSEEXPLICITMODE BOOL ';'
-+		{
-+			conf.MobRtrUseExplicitMode = $2;
-+		}
- 		| BINDINGACLPOLICY bindaclpolicy ';' 
- 		{
- 			bae = NULL;
-@@ -398,12 +431,16 @@ linksub		: QSTRING '{' linkdefs '}'
- 			memcpy(nhai, &hai, sizeof(struct home_addr_info));
- 			INIT_LIST_HEAD(&nhai->ro_policies);
- 			INIT_LIST_HEAD(&nhai->ha_list.home_agents);
-+			INIT_LIST_HEAD(&nhai->mob_net_prefixes);
- 			nhai->ha_list.dhaad_id = -1;
- 			list_splice(&hai.ro_policies, &nhai->ro_policies);
-+			list_splice(&hai.mob_net_prefixes,
-+				    &nhai->mob_net_prefixes);
- 			list_add_tail(&nhai->list, &conf.home_addrs);
- 
- 			memset(&hai, 0, sizeof(struct home_addr_info));
- 			INIT_LIST_HEAD(&hai.ro_policies);
-+			INIT_LIST_HEAD(&hai.mob_net_prefixes);
- 		}
- 		;
- 
-@@ -415,16 +452,35 @@ linkdef		: HOMEAGENTADDRESS ADDR ';'
- 		{
- 			memcpy(&hai.ha_addr, &$2, sizeof(struct in6_addr));
- 		}
--		| HOMEADDRESS ADDR '/' prefixlen ';'
--		{
--			hai.hoa.addr = $2;
--			hai.plen = $4;
--		}
-+		| HOMEADDRESS homeaddress ';'
- 		| USEALTCOA BOOL ';'
-                 {
- 		        hai.altcoa = $2;
- 		}	  
- 		| MNROPOLICY mnropolicy ';'
-+		| ISMOBRTR BOOL ';'
-+                {
-+			if ($2)
-+				hai.mob_rtr = IP6_MH_BU_MR;
-+		}
-+		|  HOMEPREFIX ADDR '/' prefixlen ';'
-+                {
-+			ipv6_addr_prefix(&hai.home_prefix, &$2, $4);
-+			hai.home_plen = $4;
-+		}
-+		;
-+
-+homeaddress	: homeaddrdef prefixlistsub
-+		{
-+			hai.mnp_count = mv_prefixes(&hai.mob_net_prefixes);
-+		}
-+		;
-+
-+homeaddrdef	: ADDR '/' prefixlen
-+		{
-+			hai.hoa.addr = $1;
-+			hai.plen = $3;
-+		}
- 		;
- 
- ipsecpolicyset	: ipsechaaddrdef ipsecmnaddrdefs ipsecpolicydefs
-@@ -639,7 +695,7 @@ bindaclpolval	: BOOL
- 		| NUMBER { $$ = $1; }
- 		;
- 
--bindaclpolicy	: ADDR bindaclpolval
-+bindaclpolicy	: ADDR prefixlistsub bindaclpolval
- 		{
- 			bae = malloc(sizeof(struct policy_bind_acl_entry));
- 			if (bae == NULL) {
-@@ -649,7 +705,9 @@ bindaclpolicy	: ADDR bindaclpolval
- 			memset(bae, 0, sizeof(struct policy_bind_acl_entry)); 
- 			bae->hoa = $1;
- 			bae->plen = 128;
--			bae->bind_policy = $2;
-+			INIT_LIST_HEAD(&bae->mob_net_prefixes);
-+			bae->mnp_count = mv_prefixes(&bae->mob_net_prefixes);
-+			bae->bind_policy = $3;
- 			list_add_tail(&bae->list, &conf.bind_acl);
- 		}
- 		;
-@@ -664,4 +722,27 @@ prefixlen	: NUMBER
- 		}
- 		;
- 
-+prefixlistsub	:
-+		| '(' prefixlist ')'
-+		;
-+
-+prefixlist	: prefixlistentry
-+		| prefixlist ',' prefixlistentry
-+		;
-+
-+prefixlistentry	: ADDR '/' prefixlen
-+		{
-+			struct prefix_list_entry *p;
-+			p = malloc(sizeof(struct prefix_list_entry));
-+			if (p == NULL) {
-+				fprintf(stderr,
-+					"%s: out of memory\n", __FUNCTION__);
-+				return -1;
-+			}
-+			memset(p, 0, sizeof(struct prefix_list_entry));
-+			p->ple_prefix = $1;
-+			p->ple_plen = $3;
-+			list_add_tail(&p->list, &prefixes);
-+		}
-+		;
- %%
-diff -r a7e20b0b5c43 src/ha.c
---- a/src/ha.c	Wed Nov 28 16:43:32 2007 +0100
-+++ b/src/ha.c	Tue Jan 08 11:28:48 2008 +0100
-@@ -79,6 +79,7 @@ static void ha_recv_ra(const struct icmp
- 	struct ha_interface *iface;
- 	uint16_t pref = 0;
- 	uint16_t life = 0;
-+	uint16_t flags = 0;
- 
- 	/* validity checks */
- 	if (hoplimit < 255 || !IN6_IS_ADDR_LINKLOCAL(src) ||
-@@ -120,6 +121,7 @@ static void ha_recv_ra(const struct icmp
- 			hainfo = (struct nd_opt_homeagent_info *)opt;
- 			pref = ntohs(hainfo->nd_opt_hai_preference);
- 			life = ntohs(hainfo->nd_opt_hai_lifetime);
-+			flags = hainfo->nd_opt_hai_flags_reserved;
- 		}
- 		optlen -= olen;
- 		opt += olen;
-@@ -129,7 +131,7 @@ static void ha_recv_ra(const struct icmp
- 		if (pinfo[i]->nd_opt_pi_flags_reserved & 
- 		    ND_OPT_PI_FLAG_RADDR) {
- 			dhaad_insert_halist(iface, pref, life,
--					    pinfo[i], src);
-+					    flags, pinfo[i], src);
- 		}
- 	}
- 	mpd_del_expired_pinfos(iface);
-@@ -499,14 +501,53 @@ static int ha_vt_init(void)
- }
- #endif
- 
-+
-+static void nemo_ha_del_mnp_routes(struct list_head *old_mnps,
-+				   struct list_head *new_mnps,
-+				   int ifindex, int all)
-+{
-+	struct list_head *list;
-+	list_for_each(list, old_mnps) {
-+		struct prefix_list_entry *p;
-+		p = list_entry(list, struct prefix_list_entry, list);
-+		if (!all &&
-+		    prefix_list_find(new_mnps, &p->ple_prefix, p->ple_plen))
-+			continue;
-+
-+		route_del(ifindex, RT6_TABLE_MIP6, IP6_RT_PRIO_MIP6_FWD,
-+			  NULL, 0, &p->ple_prefix, p->ple_plen, NULL);
-+	}
-+}
-+
-+static int nemo_ha_add_mnp_routes(struct list_head *old_mnps,
-+				  struct list_head *new_mnps,
-+				  int ifindex, int all)
-+{
-+	struct list_head *list;
-+	list_for_each(list, new_mnps) {
-+		struct prefix_list_entry *p;
-+		p = list_entry(list, struct prefix_list_entry, list);
-+		if (!all &&
-+		    prefix_list_find(old_mnps, &p->ple_prefix, p->ple_plen))
-+			continue;
-+		if (route_add(ifindex, RT6_TABLE_MIP6, RTPROT_MIP,
-+			      0, IP6_RT_PRIO_MIP6_FWD,
-+			      NULL, 0, &p->ple_prefix, p->ple_plen, NULL) < 0)
-+			return -1;
-+	}
-+	return 0;
-+}
-+
- struct home_tnl_ops_parm {
- 	struct bcentry *bce;
- 	int ba_status;
-+	struct list_head mob_net_prefixes;
- };
- 
- static int home_tnl_del(int old_if, int new_if, struct home_tnl_ops_parm *p)
- {
- 	const struct in6_addr *our_addr, *peer_addr, *coa, *old_coa;
-+	struct list_head *mnp;
- 
- 	assert(old_if);
- 
-@@ -514,17 +555,22 @@ static int home_tnl_del(int old_if, int 
- 	peer_addr = &p->bce->peer_addr;
- 	coa = &p->bce->peer_addr;
- 	old_coa = &p->bce->coa;
-+	mnp = &p->bce->mob_net_prefixes;
- 
- 	if (conf.UseMnHaIPsec) {
- 		/* migrate */ 
- 		ha_ipsec_tnl_update(our_addr, peer_addr,
--				    coa, old_coa, p->bce->tunnel);
-+				    coa, old_coa, p->bce->tunnel, mnp);
- 		/* delete SP entry */ 
--		ha_ipsec_tnl_pol_del(our_addr, peer_addr, p->bce->tunnel);
-+		ha_ipsec_tnl_pol_del(our_addr, peer_addr, p->bce->tunnel, mnp);
- 	}
- 	/* delete HoA route */
- 	route_del(old_if, RT6_TABLE_MAIN,
- 		  IP6_RT_PRIO_MIP6_FWD, NULL, 0, peer_addr, 128, NULL);
-+
-+	/* delete MNP routes */
-+	nemo_ha_del_mnp_routes(&p->bce->mob_net_prefixes,
-+			       &p->mob_net_prefixes, old_if, 1);
- 	/* update tunnel interface */
- 	p->bce->tunnel = new_if;
- 
-@@ -534,17 +580,29 @@ static int home_tnl_add(int old_if, int 
- static int home_tnl_add(int old_if, int new_if, struct home_tnl_ops_parm *p)
- {
- 	const struct in6_addr *our_addr, *peer_addr, *coa, *old_coa;
-+	struct list_head *mnp;
- 
- 	assert(new_if);
- 
- 	our_addr = &p->bce->our_addr;
- 	peer_addr = &p->bce->peer_addr;
- 	coa = &p->bce->coa;
--	old_coa = &p->bce->peer_addr;
-+	old_coa = IN6_ARE_ADDR_EQUAL(&p->bce->old_coa, &in6addr_any) ?
-+		&p->bce->peer_addr : &p->bce->old_coa;
-+	mnp = &p->mob_net_prefixes;
- 
- 	/* update tunnel interface */
- 	p->bce->tunnel = new_if;
- 
-+	/* add MNP routes */
-+	if (nemo_ha_add_mnp_routes(&p->bce->mob_net_prefixes,
-+				   &p->mob_net_prefixes, new_if, 1) < 0) {
-+		if (p->bce->nemo_type == BCE_NEMO_EXPLICIT)
-+			p->ba_status = IP6_MH_BAS_INVAL_PRFX;
-+		else
-+			p->ba_status = IP6_MH_BAS_FWDING_FAILED;
-+		goto err;
-+	}
- 	/* add HoA route */
- 	if (route_add(new_if, RT6_TABLE_MAIN,
- 		      RTPROT_MIP, 0, IP6_RT_PRIO_MIP6_FWD,
-@@ -555,13 +613,13 @@ static int home_tnl_add(int old_if, int 
- 	/* add SP entry */	
- 	if (conf.UseMnHaIPsec) {
- 		if (ha_ipsec_tnl_pol_add(our_addr, peer_addr,
--					 p->bce->tunnel) < 0) {
-+					 p->bce->tunnel, mnp) < 0) {
- 			p->ba_status = IP6_MH_BAS_INSUFFICIENT;
- 			goto err;
- 		}
- 		/* migrate */ 
- 		if (ha_ipsec_tnl_update(our_addr, peer_addr, coa, old_coa,
--					p->bce->tunnel) < 0) {
-+					p->bce->tunnel, mnp) < 0) {
- 			p->ba_status = IP6_MH_BAS_INSUFFICIENT;
- 			goto err;
- 		}
-@@ -578,17 +636,51 @@ static int home_tnl_chg(int old_if, int 
- 
- 	if (old_if == new_if) {
- 		const struct in6_addr *our_addr, *peer_addr, *coa, *old_coa;
-+		struct list_head *mnp;
- 
- 		our_addr = &p->bce->our_addr;
- 		peer_addr = &p->bce->peer_addr;
- 		coa = &p->bce->coa;
- 		old_coa = &p->bce->old_coa;
-+		mnp = &p->mob_net_prefixes;
-+
-+		/* if interface hasn't changed, at least check if the
-+		   MR's MNPs have changed */
-+		if (!prefix_list_cmp(&p->bce->mob_net_prefixes,
-+				     &p->mob_net_prefixes)) {
-+
-+			/* Remove old policies and install new ones */
-+			if (conf.UseMnHaIPsec) {
-+				ha_ipsec_mnp_pol_del(our_addr, peer_addr,
-+						     &p->bce->mob_net_prefixes,
-+						     &p->mob_net_prefixes,
-+						     p->bce->tunnel);
-+				ha_ipsec_mnp_pol_add(our_addr, peer_addr,
-+						     &p->bce->mob_net_prefixes,
-+						     &p->mob_net_prefixes,
-+						     p->bce->tunnel);
-+			}
-+
-+			/* Do the same for routes */
-+			nemo_ha_del_mnp_routes(&p->bce->mob_net_prefixes,
-+					       &p->mob_net_prefixes,
-+					       old_if, 0);
-+			if (nemo_ha_add_mnp_routes(&p->bce->mob_net_prefixes,
-+						   &p->mob_net_prefixes,
-+						   new_if, 0) < 0) {
-+				if (p->bce->nemo_type == BCE_NEMO_EXPLICIT)
-+					p->ba_status = IP6_MH_BAS_INVAL_PRFX;
-+				else
-+					p->ba_status = IP6_MH_BAS_FWDING_FAILED;
-+				return -1;
-+			}
-+		}
- 
- 		/* migrate */ 
- 		if (conf.UseMnHaIPsec &&
- 		    !IN6_ARE_ADDR_EQUAL(old_coa, coa) &&
- 		    ha_ipsec_tnl_update(our_addr, peer_addr, coa, old_coa,
--					p->bce->tunnel) < 0) {
-+					p->bce->tunnel, mnp) < 0) {
- 			return -1;
- 		}
- 	} else { 
-@@ -632,6 +724,61 @@ static void home_cleanup(struct bcentry 
- 	if (conf.UseMnHaIPsec) {
- 		ha_mn_ipsec_pol_mod(&bce->our_addr, &bce->peer_addr);
- 	}
-+}
-+
-+
-+static int ha_extract_mnps(const struct ip6_mh_binding_update *bu,
-+			   const struct mh_options *opts,
-+			   struct list_head *mob_net_prefixes)
-+{
-+	struct ip6_mh_opt_mob_net_prefix *op;
-+	int prefix_count = 0;
-+	for (op = mh_opt(&bu->ip6mhbu_hdr, opts, IP6_MHOPT_MOB_NET_PRFX);
-+	     op != NULL;
-+	     op = mh_opt_next(&bu->ip6mhbu_hdr, opts, op)) {
-+		struct prefix_list_entry *p;
-+		p = malloc(sizeof(struct prefix_list_entry));
-+		if (p == NULL) {
-+			prefix_list_free(mob_net_prefixes);
-+			return -1;
-+		}
-+		memset(p, 0, sizeof(struct prefix_list_entry));
-+		p->ple_plen = op->ip6mnp_prefix_len;
-+		p->ple_prefix = op->ip6mnp_prefix;
-+		list_add_tail(&p->list, mob_net_prefixes);
-+		prefix_count++;
-+	}
-+	return prefix_count;
-+}
-+
-+static int ha_get_mnps(const struct in6_addr *hoa,
-+		       struct list_head *mob_net_prefixes)
-+{
-+	struct nd_opt_prefix_info *mnps;
-+	int mnp_count = conf.pmgr.get_mnp_count(hoa);
-+	int i;
-+
-+	if (mnp_count <= 0)
-+		return mnp_count;
-+
-+	mnps = calloc(mnp_count, sizeof(struct nd_opt_prefix_info));
-+	if (mnps == NULL)
-+		return -1;
-+
-+	mnp_count = conf.pmgr.get_mnps(hoa, mnp_count, mnps);
-+	for (i = 0; i < mnp_count; i++) {
-+		struct prefix_list_entry *p;
-+		p = malloc(sizeof(struct prefix_list_entry));
-+		if (p == NULL) {
-+			prefix_list_free(mob_net_prefixes);
-+			free(mnps);
-+			return -1;
-+		}
-+		p->pinfo = *(mnps + i);
-+		list_add_tail(&p->list, mob_net_prefixes);
-+	}
-+	free(mnps);
-+	return mnp_count;
- }
- 
- struct ha_recv_bu_args {
-@@ -684,8 +831,9 @@ restart:
- 	bce = bcache_get(out.src, out.dst);
- 	if (bce) {
- 		if (bce->type != BCE_NONCE_BLOCK) {
--			if (!(bce->flags & IP6_MH_BU_HOME)) {
--				/* H-bit mismatch, flags changed */
-+			/* H-bit or R-bit mismatch, flags changed */
-+			if ((bce->flags ^ bu_flags) &
-+			    (IP6_MH_BU_HOME | IP6_MH_BU_MR)) {
- 				bcache_release_entry(bce);
- 				bce = NULL;
- 				status = IP6_MH_BAS_REG_NOT_ALLOWED;
-@@ -733,9 +881,15 @@ restart:
- 	}
- 	if ((status = mpd_prefix_check(out.src, out.dst,
- 				       &lft, &home_ifindex, new)) < 0) {
--		/* not home agent for this subnet */
--		status = IP6_MH_BAS_NOT_HOME_SUBNET;
--		goto send_nack;
-+		if (!(bu_flags & IP6_MH_BU_MR) ||
-+		    home_ifindex == 0 ||
-+		    !prefix_list_find(&conf.nemo_ha_served_prefixes,
-+		     		      out.dst, 0)) {
-+			/* not home agent for this subnet */
-+			status = IP6_MH_BAS_NOT_HOME_SUBNET;
-+			goto send_nack;
-+		}
-+		status = IP6_MH_BAS_ACCEPTED;
- 	}
- 	status = conf.pmgr.discard_binding(out.dst, out.bind_coa,
- 					   out.src, arg->bu, arg->len);
-@@ -787,6 +941,25 @@ restart:
- 		}
- 		new = 1;
- 	}
-+	INIT_LIST_HEAD(&p.mob_net_prefixes);
-+	if (bu_flags & IP6_MH_BU_MR && tsisset(lft)) {
-+		if (mh_opt(&arg->bu->ip6mhbu_hdr,
-+			   &arg->mh_opts, IP6_MHOPT_MOB_NET_PRFX) != NULL) {
-+			if (ha_extract_mnps(arg->bu,
-+					    &arg->mh_opts,
-+					    &p.mob_net_prefixes) < 0) {
-+				status = IP6_MH_BAS_INVAL_PRFX;
-+				goto send_nack;
-+			}
-+			bce->nemo_type = BCE_NEMO_EXPLICIT;
-+		} else if (ha_get_mnps(out.dst, &p.mob_net_prefixes) > 0) {
-+			bce->nemo_type = BCE_NEMO_IMPLICIT;
-+		} else {
-+			/* Todo: dynamic routing */
-+			status = IP6_MH_BAS_FWDING_FAILED;
-+			goto send_nack;
-+		}
-+	}
- 	p.bce = bce;
- 	p.ba_status = status;
- 	bce->seqno = seqno;
-@@ -801,6 +974,9 @@ restart:
- 				status = IP6_MH_BAS_INSUFFICIENT;
- 			goto send_nack;
- 		}
-+		/* Now save the MNP list in the BCE */
-+		list_splice(&p.mob_net_prefixes, &bce->mob_net_prefixes);
-+
- 		bce->cleanup = home_cleanup;
- 
- 		if (route_add(bce->link, RT6_TABLE_MIP6,
-@@ -829,6 +1005,10 @@ restart:
- 				status = IP6_MH_BAS_INSUFFICIENT;
- 			goto send_nack;
- 		}
-+		/* Now update the MNP list in the BCE */
-+		prefix_list_free(&bce->mob_net_prefixes);
-+		list_splice(&p.mob_net_prefixes, &bce->mob_net_prefixes);
-+
- 		bcache_update_expire(bce);
- 	}
- 	/* bce is always valid here */
-@@ -855,6 +1035,9 @@ restart:
- 		 * have a binding before sending this Binding Update,
- 		 * discard the connections to the home address. */
- 	}
-+ 	if (status < IP6_MH_BAS_UNSPECIFIED && bu_flags & IP6_MH_BU_MR)
-+ 		ba_flags |= IP6_MH_BA_MR;
-+
- 	if (!(arg->flags & HA_BU_F_SKIP_BA))
- 		mh_send_ba(&out, status, ba_flags, seqno, &lft, NULL, iif);
- 	if (new && tsisset(lft))
-diff -r a7e20b0b5c43 src/ha.h
---- a/src/ha.h	Wed Nov 28 16:43:32 2007 +0100
-+++ b/src/ha.h	Tue Jan 08 11:28:48 2008 +0100
-@@ -23,6 +23,7 @@ struct home_agent {
- 	struct list_head list;
- 	struct in6_addr addr;
- 	uint16_t preference;
-+	uint16_t flags;
- 	struct timespec lifetime;
- 	struct ha_interface *iface;
- 	struct tq_elem tqe;
-diff -r a7e20b0b5c43 src/ipsec.c
---- a/src/ipsec.c	Wed Nov 28 16:43:32 2007 +0100
-+++ b/src/ipsec.c	Tue Jan 08 11:28:48 2008 +0100
-@@ -81,7 +81,9 @@ static void _set_sp(struct xfrm_userpoli
- 		    struct ipsec_policy_entry *e,
- 		    int dir,
- 		    const struct in6_addr *in6_dst,
-+		    int  dst_len,
- 		    const struct in6_addr *in6_src,
-+		    int src_len,
- 		    int ifindex,
- 		    int nodetype)
- {
-@@ -97,10 +99,13 @@ static void _set_sp(struct xfrm_userpoli
- 	sp->action = e->action;
- 	memcpy(&sp->sel.saddr.a6, in6_src, sizeof(sp->sel.saddr.a6));
- 	memcpy(&sp->sel.daddr.a6, in6_dst, sizeof(sp->sel.daddr.a6));
--	sp->sel.prefixlen_s = IN6_ARE_ADDR_EQUAL(in6_src, &in6addr_any) ?
--				0 : 128;
--	sp->sel.prefixlen_d = IN6_ARE_ADDR_EQUAL(in6_dst, &in6addr_any) ?
--				0 : 128;
-+	sp->sel.prefixlen_s = src_len;
-+	if (!src_len && (!IN6_ARE_ADDR_EQUAL(in6_src, &in6addr_any)))
-+		sp->sel.prefixlen_s = 128;
-+	sp->sel.prefixlen_d = dst_len;
-+	if (!dst_len && (!IN6_ARE_ADDR_EQUAL(in6_dst, &in6addr_any)))
-+		sp->sel.prefixlen_d = 128;
-+
- 	sp->sel.ifindex = 0;
- 
- 	switch (e->type) {
-@@ -347,6 +352,7 @@ struct ha_ipsec_tnl_update {
- 	int tunnel;
- 	struct in6_addr coa;
- 	struct in6_addr old_coa;
-+	struct list_head *mnp;
- };
- 
- /*
-@@ -365,6 +371,7 @@ static int _ha_tnl_update(const struct i
- 	int ifindex;
- 	const struct in6_addr *oldcoa, *newcoa;
- 	const struct in6_addr *peer_addr = hoa;
-+	struct list_head *mnp;
- 	u_int8_t ipsec_proto;
- 	struct xfrm_user_tmpl tmpl;
- 	struct xfrm_userpolicy_info sp;
-@@ -399,13 +406,14 @@ static int _ha_tnl_update(const struct i
- 	oldcoa = IN6_ARE_ADDR_EQUAL(&info->old_coa, &in6addr_any) ?
- 		peer_addr : &info->old_coa;
- 	newcoa = &info->coa;
-+	mnp = info->mnp;
- 
- 	dump_migrate(ifindex, ipsec_proto, hoa, haaddr, oldcoa, newcoa);
- 
- 	/* inbound */
- 	_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
- 		  haaddr, oldcoa, e->reqid_toha);
--	_set_sp(&sp, e, XFRM_POLICY_IN, &in6addr_any, hoa,
-+	_set_sp(&sp, e, XFRM_POLICY_IN, &in6addr_any, 0, hoa, 0,
- 		ifindex, MIP6_ENTITY_HA);
- 	if ((err = xfrm_sendmigrate(&sp, &tmpl, haaddr, newcoa)) < 0) {
- 		dbg("migrate for INBOUND policy failed\n");
-@@ -415,7 +423,7 @@ static int _ha_tnl_update(const struct i
- 	/* forward */
- 	_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
- 		  haaddr, oldcoa, e->reqid_toha);
--	_set_sp(&sp, e, XFRM_POLICY_FWD, &in6addr_any, hoa,
-+	_set_sp(&sp, e, XFRM_POLICY_FWD, &in6addr_any, 0, hoa, 0,
- 		ifindex, MIP6_ENTITY_HA);
- 	if ((err = xfrm_sendmigrate(&sp, &tmpl, haaddr, newcoa)) < 0) {
- 		dbg("migrate for FORWARD policy failed\n");
-@@ -425,11 +433,54 @@ static int _ha_tnl_update(const struct i
- 	/* outbound */
- 	_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
- 		  oldcoa, haaddr, e->reqid_tomn);
--	_set_sp(&sp, e, XFRM_POLICY_OUT, hoa, &in6addr_any,
-+	_set_sp(&sp, e, XFRM_POLICY_OUT, hoa, 0, &in6addr_any, 0,
- 		ifindex, MIP6_ENTITY_HA);
- 	if ((err = xfrm_sendmigrate(&sp, &tmpl, newcoa, haaddr)) < 0) {
- 		dbg("migrate for OUTBOUND policy failed\n");
-         	goto end;
-+	}
-+
-+	/* Mobile router case */
-+	if ( (e->type == IPSEC_POLICY_TYPE_TUNNELPAYLOAD) && mnp)
-+	{
-+		struct list_head *list;
-+
-+		/* We have to modify rules to protect traffic to and from MNP's, the same way as HoA */
-+		list_for_each(list, mnp)
-+		{
-+			struct prefix_list_entry *p;
-+			p = list_entry(list, struct prefix_list_entry, list);
-+
-+			/* inbound */
-+			_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
-+				  haaddr, oldcoa, e->reqid_toha);
-+			_set_sp(&sp, e, XFRM_POLICY_IN, &in6addr_any, 0, &p->ple_prefix, p->ple_plen,
-+				ifindex, MIP6_ENTITY_HA);
-+			if ((err = xfrm_sendmigrate(&sp, &tmpl, haaddr, newcoa)) < 0) {
-+				dbg("migrate for INBOUND policy failed\n");
-+        			goto end;
-+			}
-+
-+			/* forward */
-+			_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
-+				  haaddr, oldcoa, e->reqid_toha);
-+			_set_sp(&sp, e, XFRM_POLICY_FWD, &in6addr_any, 0, &p->ple_prefix, p->ple_plen,
-+				ifindex, MIP6_ENTITY_HA);
-+			if ((err = xfrm_sendmigrate(&sp, &tmpl, haaddr, newcoa)) < 0) {
-+				dbg("migrate for FORWARD policy failed\n");
-+				goto end;
-+			}
-+
-+			/* outbound */
-+			_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
-+				  oldcoa, haaddr, e->reqid_tomn);
-+			_set_sp(&sp, e, XFRM_POLICY_OUT, &p->ple_prefix, p->ple_plen, &in6addr_any, 0,
-+				ifindex, MIP6_ENTITY_HA);
-+			if ((err = xfrm_sendmigrate(&sp, &tmpl, newcoa, haaddr)) < 0) {
-+				dbg("migrate for OUTBOUND policy failed\n");
-+        			goto end;
-+			}
-+		}
- 	}
- 
-  end:
-@@ -440,13 +491,176 @@ int ha_ipsec_tnl_update(const struct in6
- 			const struct in6_addr *hoa,
- 			const struct in6_addr *coa,
- 			const struct in6_addr *old_coa,
--			int tunnel)
-+			int tunnel,
-+			struct list_head *mnp)
- {
- 	struct ha_ipsec_tnl_update b;
- 	b.coa = *coa;
- 	b.old_coa = *old_coa;
- 	b.tunnel = tunnel;
-+	b.mnp = mnp;
- 	return ipsec_policy_apply(haaddr, hoa, _ha_tnl_update, &b);
-+}
-+
-+struct ha_ipsec_mnp_update {
-+	int tunnel;
-+	struct list_head *old_mnps;
-+	struct list_head *new_mnps;
-+};
-+
-+/*
-+ *   Add/Delete MNP IPsec Security Policy
-+ */
-+static int _ha_mnp_pol_mod(const struct in6_addr *haaddr,
-+			   const struct in6_addr *hoa,
-+			   struct ipsec_policy_entry *e,
-+			   void *arg,
-+			   int add)
-+{
-+	int err = 0;
-+	struct ha_ipsec_mnp_update *parms = (struct ha_ipsec_mnp_update *)arg;
-+	struct xfrm_userpolicy_info sp;
-+	struct xfrm_user_tmpl tmpl;
-+	u_int16_t ipsec_proto;
-+	struct list_head *list, *old_mnps, *new_mnps, *main_mnps, *ref_mnps;
-+	int ifindex;
-+
-+	assert(haaddr);
-+	assert(hoa);
-+	assert(e);
-+	assert(arg);
-+
-+	ifindex = parms->tunnel;
-+	old_mnps = parms->old_mnps;
-+	new_mnps = parms->new_mnps;
-+
-+	if (e->type != IPSEC_POLICY_TYPE_TUNNELPAYLOAD)
-+		goto end;
-+
-+	/* XXX Limitation: Single IPsec proto can only be applied */
-+	if (ipsec_use_esp(e))
-+		ipsec_proto = IPPROTO_ESP;
-+	else if (ipsec_use_ah(e))
-+		ipsec_proto = IPPROTO_AH;
-+	else if (ipsec_use_ipcomp(e))
-+		ipsec_proto = IPPROTO_COMP;
-+	else {
-+		dbg("invalid ipsec proto\n");
-+		goto end;
-+	}
-+
-+	/* Reverse the search logic on lists based on expected
-+	 * action (add/del) */
-+	main_mnps = add ? new_mnps : old_mnps;
-+	ref_mnps = add ? old_mnps : new_mnps;
-+
-+	if (main_mnps == NULL)
-+		goto end;
-+
-+	/* We have to add/delete rules to protect traffic to
-+	   and from MNP's, the same way as HoA */
-+	list_for_each(list, main_mnps) {
-+		struct prefix_list_entry *p;
-+		p = list_entry(list, struct prefix_list_entry, list);
-+
-+		if (ref_mnps &&
-+		    prefix_list_find(ref_mnps, &p->ple_prefix, p->ple_plen))
-+			continue;
-+
-+		/* inbound */
-+		_set_sp(&sp, e, XFRM_POLICY_IN, &in6addr_any, 0, &p->ple_prefix, p->ple_plen,
-+			ifindex, MIP6_ENTITY_HA);
-+		_set_tmpl(&tmpl, AF_INET6, ipsec_proto, XFRM_MODE_TUNNEL,
-+			  haaddr, hoa, e->reqid_toha);
-+		if (xfrm_ipsec_policy_mod(&sp, &tmpl, 1, add) < 0) {
-+			dbg("modifying INBOUND policy failed\n");
-+			err = -1;
-+			goto end;
-+		}
-+
-+		/* forward */
-+		_set_sp(&sp, e, XFRM_POLICY_FWD, &in6addr_any, 0, &p->ple_prefix, p->ple_plen,
-+			ifindex, MIP6_ENTITY_HA);
-+		_set_tmpl(&tmpl, AF_INET6, ipsec_proto, XFRM_MODE_TUNNEL,
-+			  haaddr, hoa, e->reqid_toha);
-+		if (xfrm_ipsec_policy_mod(&sp, &tmpl, 1, add) < 0) {
-+			dbg("modifying FORWARD policy failed\n");
-+			err = -1;
-+			goto end;
-+		}
-+
-+		/* outbound */
-+		_set_sp(&sp, e, XFRM_POLICY_OUT, &p->ple_prefix, p->ple_plen, &in6addr_any, 0,
-+			ifindex, MIP6_ENTITY_HA);
-+		_set_tmpl(&tmpl, AF_INET6, ipsec_proto, XFRM_MODE_TUNNEL,
-+			  hoa, haaddr, e->reqid_tomn);
-+		if (xfrm_ipsec_policy_mod(&sp, &tmpl, 1, add) < 0) {
-+			dbg("modifying OUTBOUND policy failed\n");
-+			err = -1;
-+			goto end;
-+		}
-+	}
-+
-+ end:
-+	return err;
-+}
-+
-+
-+/*
-+ *   Add SP entry (for MNP on HA)
-+ *
-+ *   NOTE:
-+ *   - This is a hook routine to ipsec_policy_apply()
-+ */
-+static int _ha_mnp_pol_add(const struct in6_addr *haaddr,
-+			   const struct in6_addr *hoa,
-+			   struct ipsec_policy_entry *e,
-+			   void *arg)
-+{
-+	return _ha_mnp_pol_mod(haaddr, hoa, e, arg, 1);
-+}
-+
-+int ha_ipsec_mnp_pol_add(const struct in6_addr *our_addr,
-+			 const struct in6_addr *peer_addr,
-+			 struct list_head *old_mnps,
-+			 struct list_head *new_mnps,
-+			 int tunnel)
-+{
-+	struct ha_ipsec_mnp_update b;
-+	b.tunnel = tunnel;
-+	b.old_mnps = old_mnps;
-+	b.new_mnps = new_mnps;
-+
-+	return ipsec_policy_apply(our_addr, peer_addr, _ha_mnp_pol_add, &b);
-+}
-+
-+/*
-+ *   Delete SP entry (for MNP on HA)
-+ *
-+ *   NOTE:
-+ *   - This is a hook routine to ipsec_policy_apply()
-+ */
-+static int _ha_mnp_pol_del(const struct in6_addr *haaddr,
-+			   const struct in6_addr *hoa,
-+			   struct ipsec_policy_entry *e,
-+			   void *arg)
-+{
-+	return _ha_mnp_pol_mod(haaddr, hoa, e, arg, 0);
-+}
-+
-+int ha_ipsec_mnp_pol_del(const struct in6_addr *our_addr,
-+			 const struct in6_addr *peer_addr,
-+			 struct list_head *old_mnps,
-+			 struct list_head *new_mnps,
-+			 int tunnel)
-+{
-+	struct ha_ipsec_mnp_update b;
-+	b.tunnel = tunnel;
-+	b.old_mnps = old_mnps;
-+	b.new_mnps = new_mnps;
-+
-+	return ipsec_policy_apply(our_addr, peer_addr,
-+				  _ha_mnp_pol_del, &b);
- }
- 
- /*
-@@ -459,7 +673,9 @@ static int _ha_tnl_pol_mod(const struct 
- 			   int add)
- {
- 	int err = 0;
--	int ifindex = *(int *)arg;
-+	struct ha_ipsec_tnl_update *parms = (struct ha_ipsec_tnl_update *)arg;
-+	int ifindex;
-+	struct list_head *mnp;
- 	struct xfrm_userpolicy_info sp;
- 	struct xfrm_user_tmpl tmpl;
- 	u_int16_t ipsec_proto;
-@@ -468,6 +684,9 @@ static int _ha_tnl_pol_mod(const struct 
- 	assert(hoa);
- 	assert(e);
- 	assert(arg);
-+
-+	ifindex = parms->tunnel;
-+	mnp = parms->mnp;
- 
- 	switch (e->type) {
- 	case IPSEC_POLICY_TYPE_TUNNELHOMETESTING:
-@@ -493,7 +712,7 @@ static int _ha_tnl_pol_mod(const struct 
- 	dump_migrate(ifindex, ipsec_proto, hoa, haaddr, NULL, NULL);
- 
- 	/* inbound */
--	_set_sp(&sp, e, XFRM_POLICY_IN, &in6addr_any, hoa,
-+	_set_sp(&sp, e, XFRM_POLICY_IN, &in6addr_any, 0, hoa, 0,
- 		ifindex, MIP6_ENTITY_HA);
- 	_set_tmpl(&tmpl, AF_INET6, ipsec_proto, XFRM_MODE_TUNNEL,
- 		  haaddr, hoa, e->reqid_toha);
-@@ -504,7 +723,7 @@ static int _ha_tnl_pol_mod(const struct 
- 	}
- 
- 	/* forward */
--	_set_sp(&sp, e, XFRM_POLICY_FWD, &in6addr_any, hoa,
-+	_set_sp(&sp, e, XFRM_POLICY_FWD, &in6addr_any, 0, hoa, 0,
- 		ifindex, MIP6_ENTITY_HA);
- 	_set_tmpl(&tmpl, AF_INET6, ipsec_proto, XFRM_MODE_TUNNEL,
- 		  haaddr, hoa, e->reqid_toha);
-@@ -515,7 +734,7 @@ static int _ha_tnl_pol_mod(const struct 
- 	}
- 
- 	/* outbound */
--	_set_sp(&sp, e, XFRM_POLICY_OUT, hoa, &in6addr_any,
-+	_set_sp(&sp, e, XFRM_POLICY_OUT, hoa, 0, &in6addr_any, 0,
- 		ifindex, MIP6_ENTITY_HA);
- 	_set_tmpl(&tmpl, AF_INET6, ipsec_proto, XFRM_MODE_TUNNEL,
- 		  hoa, haaddr, e->reqid_tomn);
-@@ -525,6 +744,16 @@ static int _ha_tnl_pol_mod(const struct 
- 		goto end;
- 	}
- 
-+	/* Mobile Router case */
-+	if ((e->type == IPSEC_POLICY_TYPE_TUNNELPAYLOAD) && mnp) {
-+		struct ha_ipsec_mnp_update b;
-+
-+		b.tunnel = ifindex;
-+		b.old_mnps = add ? NULL : mnp;
-+		b.new_mnps = add ? mnp : NULL;
-+
-+		err = _ha_mnp_pol_mod(haaddr, hoa, e, (void *)&b, add);
-+	}
-  end:
- 	return err;
- }
-@@ -545,11 +774,14 @@ static int _ha_tnl_pol_add(const struct 
- 
- int ha_ipsec_tnl_pol_add(const struct in6_addr *our_addr, 
- 			 const struct in6_addr *peer_addr,
--			 int tunnel)
-+			 int tunnel,
-+			 struct list_head *mnp)
- {
--	int t = tunnel;
-+	struct ha_ipsec_tnl_update b;
-+	b.tunnel = tunnel;
-+	b.mnp = mnp;
- 
--	return ipsec_policy_apply(our_addr, peer_addr, _ha_tnl_pol_add, &t);
-+	return ipsec_policy_apply(our_addr, peer_addr, _ha_tnl_pol_add, &b);
- }
- 
- /*
-@@ -568,12 +800,15 @@ static int _ha_tnl_pol_del(const struct 
- 
- int ha_ipsec_tnl_pol_del(const struct in6_addr *our_addr, 
- 			 const struct in6_addr *peer_addr,
--			 int tunnel)
-+			 int tunnel,
-+			 struct list_head *mnp)
- {
--	int t = tunnel;
-+	struct ha_ipsec_tnl_update b;
-+	b.tunnel = tunnel;
-+	b.mnp = mnp;
- 
- 	return ipsec_policy_apply(our_addr, peer_addr,
--				  _ha_tnl_pol_del, &t);
-+				  _ha_tnl_pol_del, &b);
- }
- 
- /*
-@@ -631,7 +866,7 @@ static int _mn_tnl_update(const struct i
- 	/* outbound */
- 	_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
- 		  haaddr, oldcoa, e->reqid_toha);
--	_set_sp(&sp, e, XFRM_POLICY_OUT, &in6addr_any, hoa,
-+	_set_sp(&sp, e, XFRM_POLICY_OUT, &in6addr_any, 0, hoa, 0,
- 		ifindex, MIP6_ENTITY_MN);
- 	if ((err = xfrm_sendmigrate(&sp, &tmpl, haaddr, newcoa)) < 0) {
- 		dbg("migrate for OUTBOUND policy failed\n");
-@@ -641,7 +876,7 @@ static int _mn_tnl_update(const struct i
- 	/* inbound */
- 	_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
- 		  oldcoa, haaddr, e->reqid_tomn);
--	_set_sp(&sp, e, XFRM_POLICY_IN, hoa, &in6addr_any,
-+	_set_sp(&sp, e, XFRM_POLICY_IN, hoa, 0, &in6addr_any, 0,
- 		ifindex, MIP6_ENTITY_MN);
- 	if ((err = xfrm_sendmigrate(&sp, &tmpl, newcoa, haaddr)) < 0) {
- 		dbg("migrate for INBOUND policy (1) failed\n");
-@@ -657,7 +892,7 @@ static int _mn_tnl_update(const struct i
- 		/* template */
- 		_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
- 			  oldcoa, haaddr, e->reqid_tomn);
--		_set_sp(&sp, e, XFRM_POLICY_IN, hoa, &in6addr_any,
-+		_set_sp(&sp, e, XFRM_POLICY_IN, hoa, 0, &in6addr_any, 0,
- 			ifindex, MIP6_ENTITY_MN);
- 		/* additional settings */
- 		sp.priority = MIP6_PRIO_RO_SIG_IPSEC;
-@@ -666,6 +901,52 @@ static int _mn_tnl_update(const struct i
- 		if ((err = xfrm_sendmigrate(&sp, &tmpl, newcoa, haaddr)) < 0) {
- 			dbg("migrate for INBOUND policy (2) failed\n");
- 			goto end;
-+		}
-+	}
-+
-+	/*
-+	 * If we are a Mobile Router, we also need to migrate IN/FWD/OUT rules
-+	 * for forwarded traffic in case we have TUNNELPAYLOAD protection.
-+	 */
-+	if ((e->type == IPSEC_POLICY_TYPE_TUNNELPAYLOAD) && (bule->home->mob_rtr))
-+	{
-+		struct list_head *mnp;
-+
-+		list_for_each(mnp, &bule->home->mob_net_prefixes)
-+		{
-+			struct prefix_list_entry *p;
-+			p = list_entry(mnp, struct prefix_list_entry, list);
-+
-+			/* outbound */
-+			_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
-+				  haaddr, oldcoa, e->reqid_toha);
-+			_set_sp(&sp, e, XFRM_POLICY_OUT, &in6addr_any, 0, &p->ple_prefix, p->ple_plen,
-+				ifindex, MIP6_ENTITY_MN);
-+			if ((err = xfrm_sendmigrate(&sp, &tmpl, haaddr, newcoa)) < 0) {
-+				dbg("migrate for OUTBOUND policy failed\n");
-+				goto end;
-+			}
-+
-+			/* forwarded */
-+			_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
-+				  oldcoa, haaddr, e->reqid_tomn);
-+			_set_sp(&sp, e, XFRM_POLICY_IN, &p->ple_prefix, p->ple_plen, &in6addr_any, 0,
-+				ifindex, MIP6_ENTITY_MN);
-+			if ((err = xfrm_sendmigrate(&sp, &tmpl, newcoa, haaddr)) < 0) {
-+				dbg("migrate for INBOUND policy (1) failed\n");
-+				goto end;
-+			}
-+
-+			/* inbound */
-+			_set_tmpl(&tmpl, 0, ipsec_proto, XFRM_MODE_TUNNEL,
-+				  oldcoa, haaddr, e->reqid_tomn);
-+			_set_sp(&sp, e, XFRM_POLICY_IN, &p->ple_prefix, p->ple_plen, &in6addr_any, 0,
-+				ifindex, MIP6_ENTITY_MN);
-+			if ((err = xfrm_sendmigrate(&sp, &tmpl, newcoa, haaddr)) < 0) {
-+				dbg("migrate for INBOUND policy (1) failed\n");
-+				goto end;
-+			}
-+
- 		}
- 	}
- 
-@@ -724,7 +1005,7 @@ static int _mn_tnl_pol_mod(const struct 
- 	dump_migrate(ifindex, ipsec_proto, hoa, haaddr, NULL, NULL);
- 
- 	/* inbound */
--	_set_sp(&sp, e, XFRM_POLICY_IN, hoa, &in6addr_any,
-+	_set_sp(&sp, e, XFRM_POLICY_IN, hoa, 0, &in6addr_any, 0,
- 		ifindex, MIP6_ENTITY_MN);
- 	_set_tmpl(&tmpl, AF_INET6, ipsec_proto, XFRM_MODE_TUNNEL,
- 		  hoa, haaddr, e->reqid_tomn);
-@@ -735,7 +1016,7 @@ static int _mn_tnl_pol_mod(const struct 
- 	}
- 		
- 	/* outbound */
--	_set_sp(&sp, e, XFRM_POLICY_OUT, &in6addr_any, hoa,
-+	_set_sp(&sp, e, XFRM_POLICY_OUT, &in6addr_any, 0, hoa, 0,
- 		ifindex, MIP6_ENTITY_MN);
- 	_set_tmpl(&tmpl, AF_INET6, ipsec_proto, XFRM_MODE_TUNNEL,
- 		  haaddr, hoa, e->reqid_toha);
-@@ -758,6 +1039,54 @@ static int _mn_tnl_pol_mod(const struct 
- 			mn_ipsec_recv_bu_tnl_pol_del(bule, ifindex, e);
- 			/* restore wildrecv SPD entry for processing BU */
- 			err = cn_wildrecv_bu_pol_add();
-+		}
-+	}
-+
-+	/*
-+	 * If we are a Mobile Router, we also need to create IN/FWD/OUT rules
-+	 * for forwarded traffic in case we have TUNNELPAYLOAD protection.
-+	 */
-+	if ((e->type == IPSEC_POLICY_TYPE_TUNNELPAYLOAD) && (bule->home->mob_rtr))
-+	{
-+		struct list_head *mnp;
-+
-+		list_for_each(mnp, &bule->home->mob_net_prefixes)
-+		{
-+			struct prefix_list_entry *p;
-+			p = list_entry(mnp, struct prefix_list_entry, list);
-+
-+			/* inbound */
-+			_set_sp(&sp, e, XFRM_POLICY_IN, &p->ple_prefix, p->ple_plen, &in6addr_any, 0,
-+				ifindex, MIP6_ENTITY_MN);
-+			_set_tmpl(&tmpl, AF_INET6, ipsec_proto, XFRM_MODE_TUNNEL,
-+				  hoa, haaddr, e->reqid_tomn);
-+			if (xfrm_ipsec_policy_mod(&sp, &tmpl, 1, add) < 0) {
-+				dbg("modifying INBOUND policy failed.\n");
-+				err = -1;
-+				goto end;
-+			}
-+
-+			/* forward */
-+			_set_sp(&sp, e, XFRM_POLICY_FWD, &p->ple_prefix, p->ple_plen, &in6addr_any, 0,
-+				ifindex, MIP6_ENTITY_MN);
-+			_set_tmpl(&tmpl, AF_INET6, ipsec_proto, XFRM_MODE_TUNNEL,
-+				  hoa, haaddr, e->reqid_tomn);
-+			if (xfrm_ipsec_policy_mod(&sp, &tmpl, 1, add) < 0) {
-+				dbg("modifying INBOUND policy failed.\n");
-+				err = -1;
-+				goto end;
-+			}
-+
-+			/* outbound */
-+			_set_sp(&sp, e, XFRM_POLICY_OUT, &in6addr_any, 0, &p->ple_prefix, p->ple_plen,
-+				ifindex, MIP6_ENTITY_MN);
-+			_set_tmpl(&tmpl, AF_INET6, ipsec_proto, XFRM_MODE_TUNNEL,
-+				  haaddr, hoa, e->reqid_toha);
-+			if (xfrm_ipsec_policy_mod(&sp, &tmpl, 1, add) < 0) {
-+				dbg("modifying OUTBOUND policy failed.\n");
-+				err = -1;
-+				goto end;
-+			}
- 		}
- 	}
- 
-diff -r a7e20b0b5c43 src/ipsec.h
---- a/src/ipsec.h	Wed Nov 28 16:43:32 2007 +0100
-+++ b/src/ipsec.h	Tue Jan 08 11:28:48 2008 +0100
-@@ -82,15 +82,30 @@ int ha_ipsec_tnl_update(const struct in6
- 			const struct in6_addr *hoa,
- 			const struct in6_addr *coa,
- 			const struct in6_addr *old_coa,
--			int tunnel);
-+			int tunnel,
-+			struct list_head *mnp);
-+
-+int ha_ipsec_mnp_pol_del(const struct in6_addr *our_addr,
-+			 const struct in6_addr *peer_addr,
-+			 struct list_head *old_mnps,
-+			 struct list_head *new_mnps,
-+			 int tunnel);
-+
-+int ha_ipsec_mnp_pol_add(const struct in6_addr *our_addr,
-+			 const struct in6_addr *peer_addr,
-+			 struct list_head *old_mnps,
-+			 struct list_head *new_mnps,
-+			 int tunnel);
- 
- int ha_ipsec_tnl_pol_add(const struct in6_addr *our_addr, 
- 			 const struct in6_addr *peer_addr,
--			 int tunnel);
-+			 int tunnel,
-+			 struct list_head *mnp);
- 
- int ha_ipsec_tnl_pol_del(const struct in6_addr *our_addr, 
- 			 const struct in6_addr *peer_addr,
--			 int tunnel);
-+			 int tunnel,
-+			 struct list_head *mnp);
- 
- int mn_ipsec_tnl_update(const struct in6_addr *haaddr,
- 			const struct in6_addr *hoa,
-diff -r a7e20b0b5c43 src/mh.c
---- a/src/mh.c	Wed Nov 28 16:43:32 2007 +0100
-+++ b/src/mh.c	Tue Jan 08 11:28:48 2008 +0100
-@@ -51,6 +51,7 @@
- #include "conf.h"
- #include "bcache.h"
- #include "keygen.h"
-+#include "prefix.h"
- 
- #define MH_DEBUG_LEVEL 1
- 
-@@ -75,6 +76,7 @@ int mh_opts_dup_ok[] = {
- 	0, /* Alternate CoA */
- 	0, /* Nonce Index */
- 	0, /* Binding Auth Data */
-+	1, /* Mobile Network Prefix */
- };
- 
- #define __MH_SENTINEL (IP6_MH_TYPE_MAX + 1)
-@@ -401,6 +403,46 @@ static int create_opt_pad(struct iovec *
- 	return 0;
- }
- 
-+int mh_create_opt_mob_net_prefix(struct iovec *iov, int mnp_count,
-+				 struct list_head *mnps)
-+{
-+	int optlen = (mnp_count * sizeof(struct ip6_mh_opt_mob_net_prefix) +
-+		      (mnp_count - 1) * sizeof(_pad4));
-+	struct list_head *l;
-+	int i = 0;
-+	uint8_t *data;
-+	iov->iov_base = malloc(optlen);
-+	iov->iov_len = optlen;
-+
-+	if (iov->iov_base == NULL)
-+		return -ENOMEM;
-+
-+	memset(iov->iov_base, 0, iov->iov_len);
-+	data = (uint8_t *)iov->iov_base;
-+
-+	list_for_each(l, mnps) {
-+		struct prefix_list_entry *p;
-+		struct ip6_mh_opt_mob_net_prefix *mnp;
-+
-+		p = list_entry(l, struct prefix_list_entry, list);
-+		mnp = (struct ip6_mh_opt_mob_net_prefix *)data;
-+
-+		mnp->ip6mnp_type = IP6_MHOPT_MOB_NET_PRFX;
-+		mnp->ip6mnp_len = 18;
-+		mnp->ip6mnp_prefix_len = p->ple_plen;
-+		mnp->ip6mnp_prefix = p->ple_prefix;
-+
-+		data += sizeof(struct ip6_mh_opt_mob_net_prefix);
-+
-+		/* do internal padding here, so one iovec for MNPs is enough */
-+		if (++i < mnp_count) {
-+		  memcpy(data, _pad4, sizeof(_pad4));
-+		  data += sizeof(_pad4);
-+		}
-+	}
-+	return 0;
-+}
-+
- static size_t mh_length(struct iovec *vec, int count)
- {
- 	size_t len = 0;
-@@ -441,6 +483,9 @@ static int mh_try_pad(const struct iovec
- 			break;
- 		case IP6_MHOPT_BAUTH:
- 			pad = optpad(8, 2, len); /* 8n+2 */
-+			break;
-+		case IP6_MHOPT_MOB_NET_PRFX:
-+			pad = optpad(8, 4, len); /* 8n+4 */
- 			break;
- 		}
- 		if (pad > 0) {
-@@ -694,6 +739,8 @@ static int mh_opt_len_chk(uint8_t type, 
- 		return len != sizeof(struct ip6_mh_opt_nonce_index);
- 	case IP6_MHOPT_BAUTH:
- 		return len != sizeof(struct ip6_mh_opt_auth_data);
-+	case IP6_MHOPT_MOB_NET_PRFX:
-+		return len != sizeof(struct ip6_mh_opt_mob_net_prefix);
- 	case IP6_MHOPT_PADN:
- 	default:
- 		return 0;
-diff -r a7e20b0b5c43 src/mh.h
---- a/src/mh.h	Wed Nov 28 16:43:32 2007 +0100
-+++ b/src/mh.h	Tue Jan 08 11:28:48 2008 +0100
-@@ -10,7 +10,7 @@
- 
- /* If new types or options appear, these should be updated. */
- #define IP6_MH_TYPE_MAX IP6_MH_TYPE_BERROR
--#define IP6_MHOPT_MAX IP6_MHOPT_BAUTH
-+#define IP6_MHOPT_MAX IP6_MHOPT_MOB_NET_PRFX
- 
- struct in6_addr_bundle {
- 	struct in6_addr *src;
-@@ -74,6 +74,11 @@ int mh_create_opt_nonce_index(struct iov
- 
- int mh_create_opt_auth_data(struct iovec *iov);
- 
-+struct list_head;
-+
-+int mh_create_opt_mob_net_prefix(struct iovec *iov, int mnp_count,
-+				 struct list_head *mnps);
-+
- static inline void *mh_opt(const struct ip6_mh *mh,
- 			   const struct mh_options *mh_opts, uint8_t type)
- {
-diff -r a7e20b0b5c43 src/mn.c
---- a/src/mn.c	Wed Nov 28 16:43:32 2007 +0100
-+++ b/src/mn.c	Tue Jan 08 11:28:48 2008 +0100
-@@ -326,7 +326,17 @@ static int mn_send_bu_msg(struct bulentr
- 		free_iov_data(iov, iov_ind);
- 		return -ENOMEM;
- 	}
--	if (!(bule->flags & IP6_MH_BU_HOME)) {
-+	if (bule->flags & IP6_MH_BU_HOME) {
-+		struct home_addr_info *hai = bule->home;
-+		if (bule->flags & IP6_MH_BU_MR && bu->ip6mhbu_lifetime &&
-+		    bule->home->mnp_count > 0 && conf.MobRtrUseExplicitMode &&
-+		    mh_create_opt_mob_net_prefix(&iov[iov_ind++],
-+						 hai->mnp_count,
-+						 &hai->mob_net_prefixes) < 0) {
-+			free_iov_data(iov, iov_ind);
-+			return -ENOMEM;
-+		}
-+	} else {
- 		if (mh_create_opt_nonce_index(&iov[iov_ind++], bule->rr.ho_ni,
- 					      bule->rr.co_ni) ||
- 		    mh_create_opt_auth_data(&iov[iov_ind++])) {
-@@ -616,6 +626,34 @@ static int mv_hoa(struct ifaddrmsg *ifa,
- 	return 0;
- }
- 
-+int nemo_mr_tnl_routes_add(struct home_addr_info *hai, int ifindex)
-+{
-+	struct list_head *l;
-+	struct prefix_list_entry *pe;
-+	list_for_each(l, &hai->mob_net_prefixes) {
-+		struct prefix_list_entry *p;
-+		p = list_entry(l, struct prefix_list_entry, list);
-+		if (route_add(ifindex, RT6_TABLE_MIP6, RTPROT_MIP,
-+			      0, IP6_RT_PRIO_MIP6_FWD,
-+			      &p->ple_prefix, p->ple_plen,
-+			      &in6addr_any, 0, NULL) < 0) {
-+			pe = p;
-+			goto undo;
-+		}
-+	}
-+	return 0;
-+undo:
-+	list_for_each(l, &hai->mob_net_prefixes) {
-+		struct prefix_list_entry *p;
-+		p = list_entry(l, struct prefix_list_entry, list);
-+		route_del(ifindex, RT6_TABLE_MIP6, IP6_RT_PRIO_MIP6_FWD,
-+			  &p->ple_prefix, p->ple_plen, &in6addr_any, 0, NULL);
-+		if (p == pe)
-+			break;
-+	}
-+	return -1;
-+}
-+
- static int mn_tnl_state_add(struct home_addr_info *hai, int ifindex, int all)
- {
- 	int err = 0;
-@@ -628,12 +666,31 @@ static int mn_tnl_state_add(struct home_
- 			mn_ro_pol_del(hai, ifindex, all);
- 		}
- 	}
-+	if (hai->mob_rtr &&
-+	    (err = nemo_mr_tnl_routes_add(hai, ifindex)) < 0) {
-+		route_del(ifindex, RT6_TABLE_MIP6, IP6_RT_PRIO_MIP6_OUT,
-+			  &hai->hoa.addr, 128, &in6addr_any, 0, NULL);
-+		mn_ro_pol_del(hai, ifindex, all);
-+	}
- 	return err;
-+}
-+
-+static void nemo_mr_tnl_routes_del(struct home_addr_info *hai, int ifindex)
-+{
-+	struct list_head *l;
-+	list_for_each(l, &hai->mob_net_prefixes) {
-+		struct prefix_list_entry *p;
-+		p = list_entry(l, struct prefix_list_entry, list);
-+		route_del(ifindex, RT6_TABLE_MIP6, IP6_RT_PRIO_MIP6_FWD,
-+			  &p->ple_prefix, p->ple_plen, &in6addr_any, 0, NULL);
-+	}
- }
- 
- static void mn_tnl_state_del(struct home_addr_info *hai, int ifindex, int all)
- {
- 	if (hai->home_reg_status != HOME_REG_NONE) {
-+		if (hai->mob_rtr)
-+			nemo_mr_tnl_routes_del(hai, ifindex);
- 		route_del(ifindex, RT6_TABLE_MIP6, IP6_RT_PRIO_MIP6_OUT, 
- 			  &hai->hoa.addr, 128, &in6addr_any, 0, NULL);
- 		mn_ro_pol_del(hai, ifindex, all);
-@@ -674,7 +731,8 @@ static int process_first_home_bu(struct 
- {
- 	int err = 0;
- 	bule->type = BUL_ENTRY;
--	bule->flags = IP6_MH_BU_HOME | IP6_MH_BU_ACK | hai->lladdr_comp;
-+	bule->flags = (IP6_MH_BU_HOME | IP6_MH_BU_ACK |
-+		       hai->lladdr_comp | hai->mob_rtr);
- 	bule->coa_changed = -1;
- 	bule->coa = hai->primary_coa.addr;
- 	bule->if_coa = hai->primary_coa.iif;
-@@ -1084,6 +1142,18 @@ static void mn_recv_ba(const struct ip6_
- 	if (bule->flags & IP6_MH_BU_HOME) {
- 		struct home_addr_info *hai = bule->home;
- 		struct ip6_mh_opt_refresh_advice *bra;
-+
-+		if (bule->flags & IP6_MH_BU_MR &&
-+		    !(ba->ip6mhba_flags & IP6_MH_BA_MR)) {
-+			if (hai->use_dhaad) {
-+				mn_change_ha(hai);
-+			} else {
-+				int one = 1;
-+				bul_iterate(&hai->bul, mn_dereg, &one);
-+			}
-+			pthread_rwlock_unlock(&mn_lock);
-+			return;
-+		}
- 		if (!tsisset(ba_lifetime)) {
- 			int type = FLUSH_FAILED;
- 			mn_dereg_home(hai);
-@@ -1251,12 +1321,73 @@ static int flag_hoa(struct ifaddrmsg *if
- 	return 0;
- }
- 
-+static void nemo_mr_rules_del(struct home_addr_info *hinfo)
-+{
-+	struct list_head *l;
-+
-+	list_for_each(l, &hinfo->mob_net_prefixes) {
-+		struct prefix_list_entry *p = NULL;
-+		p = list_entry(l, struct prefix_list_entry, list);
-+		rule_del(NULL, RT6_TABLE_MIP6,
-+			 IP6_RULE_PRIO_MIP6_FWD, RTN_UNICAST,
-+			 &p->ple_prefix, p->ple_plen, &in6addr_any, 0, 0);
-+		rule_del(NULL, RT6_TABLE_MAIN,
-+			 IP6_RULE_PRIO_MIP6_MNP_IN, RTN_UNICAST,
-+			 &in6addr_any, 0, &p->ple_prefix, p->ple_plen, 0);
-+	}
-+}
-+
-+static int nemo_mr_rules_add(struct home_addr_info *hinfo)
-+{
-+	struct prefix_list_entry *pe = NULL;
-+	struct list_head *l;
-+
-+	list_for_each(l, &hinfo->mob_net_prefixes) {
-+		struct prefix_list_entry *p = NULL;
-+		p = list_entry(l, struct prefix_list_entry, list);
-+		if (rule_add(NULL, RT6_TABLE_MAIN,
-+			     IP6_RULE_PRIO_MIP6_MNP_IN, RTN_UNICAST,
-+			     &in6addr_any, 0,
-+			     &p->ple_prefix, p->ple_plen, 0) < 0) {
-+			pe = p;
-+			goto undo;
-+		}
-+		if (rule_add(NULL, RT6_TABLE_MIP6,
-+			     IP6_RULE_PRIO_MIP6_FWD, RTN_UNICAST,
-+			     &p->ple_prefix, p->ple_plen,
-+			     &in6addr_any, 0, 0) < 0) {
-+			rule_del(NULL, RT6_TABLE_MAIN,
-+				 IP6_RULE_PRIO_MIP6_MNP_IN, RTN_UNICAST,
-+				 &in6addr_any, 0, &p->ple_prefix, p->ple_plen, 0);
-+			pe = p;
-+			goto undo;
-+		}
-+	}
-+	return 0;
-+undo:
-+	list_for_each(l, &hinfo->mob_net_prefixes) {
-+		struct prefix_list_entry *p = NULL;
-+		p = list_entry(l, struct prefix_list_entry, list);
-+		rule_del(NULL, RT6_TABLE_MIP6,
-+			 IP6_RULE_PRIO_MIP6_FWD,  RTN_UNICAST,
-+			 &p->ple_prefix, p->ple_plen, &in6addr_any, 0, 0);
-+		rule_del(NULL, RT6_TABLE_MAIN,
-+			 IP6_RULE_PRIO_MIP6_MNP_IN, RTN_UNICAST,
-+			 &in6addr_any, 0, &p->ple_prefix, p->ple_plen, 0);
-+		if (p == pe)
-+			break;
-+	}
-+	return -1;
-+}
-+
- static void clean_home_addr_info(struct home_addr_info *hai)
- {
- 	struct flag_hoa_args arg;
- 	int plen = (hai->hoa.iif == hai->if_tunnel ? 128 : hai->plen);
- 
- 	list_del(&hai->list);
-+	if (hai->mob_rtr)
-+		nemo_mr_rules_del(hai);
- 	arg.target = hai;
- 	arg.flag = 0;
- 	addr_do(&hai->hoa.addr, plen,
-@@ -1310,13 +1441,23 @@ static struct home_addr_info *hai_copy(s
- 
- 		if (pthread_mutex_init(&hai->ha_list.c_lock, NULL))
- 			goto undo;
-+
-+		INIT_LIST_HEAD(&hai->mob_net_prefixes);
-+		if (hai->mob_rtr &&
-+		    prefix_list_copy(&conf_hai->mob_net_prefixes,
-+				     &hai->mob_net_prefixes) < 0)
-+			goto mutex_undo;
-+
- 		INIT_LIST_HEAD(&hai->ro_policies);
- 		if (rpl_copy(&conf_hai->ro_policies, &hai->ro_policies) < 0)
--			goto mutex_undo;
-+			goto mnp_undo;
-+
- 		INIT_LIST_HEAD(&hai->ha_list.tqe.list);
- 		INIT_LIST_HEAD(&hai->ha_list.home_agents);
- 	}
- 	return hai;
-+mnp_undo:
-+	prefix_list_free(&hai->mob_net_prefixes);
- mutex_undo:
- 	pthread_mutex_destroy(&hai->ha_list.c_lock);
- undo:
-@@ -1337,6 +1478,15 @@ static int conf_home_addr_info(struct ho
- 	if  ((hai = hai_copy(conf_hai)) == NULL)
- 		goto err;
- 
-+	if (hai->mob_rtr) {
-+		MDBG("is Mobile Router\n");
-+		list_for_each(list, &hai->mob_net_prefixes) {
-+			struct prefix_list_entry *p;
-+			p = list_entry(list, struct prefix_list_entry, list);
-+			MDBG("Mobile Network Prefix %x:%x:%x:%x:%x:%x:%x:%x/%d\n",
-+			     NIP6ADDR(&p->ple_prefix), p->ple_plen);
-+		}
-+	}
- 	if (IN6_IS_ADDR_UNSPECIFIED(&hai->ha_addr)) {
- 		hai->use_dhaad = 1;
- 	} else {
-@@ -1379,6 +1529,9 @@ static int conf_home_addr_info(struct ho
- 
- 	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;
- 	}
- 	hai->at_home = hai->hoa.iif == hai->if_home;
-diff -r a7e20b0b5c43 src/mn.h
---- a/src/mn.h	Wed Nov 28 16:43:32 2007 +0100
-+++ b/src/mn.h	Tue Jan 08 11:28:48 2008 +0100
-@@ -45,9 +45,11 @@ struct ha_candidate_list {
- 	pthread_mutex_t c_lock;
- };
- 
--#define	HOME_LINK_BLOCK	0x1
--#define	HOME_ADDR_BLOCK	0x2
--#define	HOME_ADDR_RULE_BLOCK	0x4
-+#define	HOME_LINK_BLOCK	0x01
-+#define	HOME_ADDR_BLOCK	0x02
-+#define	HOME_ADDR_RULE_BLOCK	0x04
-+#define	NEMO_RA_BLOCK	0x08
-+#define	NEMO_FWD_BLOCK	0x10
- 
- struct mn_addr {
- 	struct in6_addr addr;
-@@ -84,7 +86,10 @@ struct home_addr_info {
- 	int if_block;
- 	short hwalen;
- 	uint8_t altcoa;
-+	uint16_t mob_rtr;
- 	char name[IF_NAMESIZE];
-+	int mnp_count;
-+	struct list_head mob_net_prefixes;
- };
- 
- enum {
-diff -r a7e20b0b5c43 src/movement.c
---- a/src/movement.c	Wed Nov 28 16:43:32 2007 +0100
-+++ b/src/movement.c	Tue Jan 08 11:28:48 2008 +0100
-@@ -78,6 +78,7 @@ static int conf_default_rs = 3;
- static int conf_default_rs = 3;
- static int conf_default_rs_ival = 4;
- 
-+static int conf_forwarding = 0;
- static int conf_autoconf = 1;
- static int conf_ra_defrtr = 0;
- static int conf_rs = 0;
-@@ -177,6 +178,12 @@ static void __md_free_router(struct md_r
- 
- 		route_del(rtr->ifindex, RT_TABLE_MAIN, 0,
- 			  &in6addr_any, 0, &in6addr_any, 0, &rtr->lladdr);
-+
-+		/* delete default route for the packets coming from the
-+		 * Mobile Network
-+		 */
-+		route_del(rtr->ifindex, RT6_TABLE_MIP6, 0,
-+			  &in6addr_any, 0, &in6addr_any, 0, &rtr->lladdr);
- 	}
- 	list_for_each_safe(l, n, &rtr->prefixes) {
- 		struct prefix_list_entry *p;
-@@ -231,8 +238,31 @@ static void md_expire_coa(struct md_inet
- 	list_add_tail(&coa->list, &iface->expired_coas);
- }
- 
-+static void md_reset_egress_forward(void)
-+{
-+	struct list_head *l;
-+	int forward = 0;;
-+
-+	if (list_empty(&ifaces))
-+		return;
-+
-+	list_for_each(l, &ifaces) {
-+		struct md_inet6_iface *i;
-+		i = list_entry(l, struct md_inet6_iface, list);
-+		forward |= i->home_link;
-+	}
-+	list_for_each(l, &ifaces) {
-+		struct md_inet6_iface *i;
-+		i = list_entry(l, struct md_inet6_iface, list);
-+		set_iface_proc_entry(PROC_SYS_IP6_FORWARDING,
-+				     i->name, forward);
-+	}
-+}
-+
- static void md_reset_home_link(struct md_inet6_iface *i)
- {
-+	if (i->home_link)
-+		md_reset_egress_forward();
- 	i->home_link = 0;
- 	i->ll_dad_unsafe = 0;
- }
-@@ -648,6 +678,8 @@ md_create_inet6_iface(struct ifinfomsg *
- 
- static void iface_proc_entries_init(struct md_inet6_iface *iface)
- {
-+	set_iface_proc_entry(PROC_SYS_IP6_FORWARDING, iface->name,
-+			     conf_forwarding);
- 	set_iface_proc_entry(PROC_SYS_IP6_AUTOCONF, iface->name,
- 			     conf_autoconf);
- 	set_iface_proc_entry(PROC_SYS_IP6_ACCEPT_RA_DEFRTR, iface->name, conf_ra_defrtr);
-@@ -878,6 +910,8 @@ static void md_check_home_link(struct md
- 			ll_dad_unsafe |= hai->lladdr_comp;
- 		}
- 	}
-+	if (i->home_link != home_link)
-+		md_reset_egress_forward();
- 	i->home_link = home_link;
- 	i->ll_dad_unsafe = ll_dad_unsafe;
- }
-@@ -1189,6 +1223,11 @@ static void md_update_router_stats(struc
- 		  RTF_DEFAULT|RTF_ADDRCONF, 1024,
- 		  &in6addr_any, 0, &in6addr_any, 0, &rtr->lladdr);
- 	
-+	/* default route for the packet coming from the Mobile Network */
-+	route_add(rtr->ifindex, RT6_TABLE_MIP6, RTPROT_MIP,
-+		  0, IP6_RT_PRIO_MIP6_FWD,
-+		  &in6addr_any, 0, &in6addr_any, 0, &rtr->lladdr);
-+
- 	list_for_each(list, &rtr->prefixes) {
- 		struct prefix_list_entry *p;
- 		p = list_entry(list, struct prefix_list_entry, list);
-@@ -1737,6 +1776,8 @@ static void iface_default_proc_entries_c
- 
- static void iface_proc_entries_cleanup(struct md_inet6_iface *iface)
- {
-+	set_iface_proc_entry(PROC_SYS_IP6_FORWARDING, iface->name,
-+			     iface->devconf[DEVCONF_FORWARDING]);
- 	set_iface_proc_entry(PROC_SYS_IP6_AUTOCONF, iface->name,
- 			     iface->devconf[DEVCONF_AUTOCONF]);
- 	set_iface_proc_entry(PROC_SYS_IP6_ACCEPT_RA_DEFRTR, iface->name,
-diff -r a7e20b0b5c43 src/ndisc.c
---- a/src/ndisc.c	Wed Nov 28 16:43:32 2007 +0100
-+++ b/src/ndisc.c	Tue Jan 08 11:28:48 2008 +0100
-@@ -106,7 +106,7 @@ int proxy_nd_start(int ifindex, struct i
- {
- 	struct in6_addr lladdr;
- 	int err;
--	int nd_flags = 0;
-+	int nd_flags = bu_flags&IP6_MH_BU_MR ? NTF_ROUTER : 0;
- 
- 	err = pneigh_add(ifindex, nd_flags, target);
- 
-@@ -117,7 +117,9 @@ int proxy_nd_start(int ifindex, struct i
- 			pneigh_del(ifindex, target);
- 	}
- 	if (!err) {
--		uint32_t na_flags = ND_NA_FLAG_OVERRIDE;
-+		uint32_t na_flags = (ND_NA_FLAG_OVERRIDE |
-+				     nd_flags ? ND_NA_FLAG_ROUTER : 0);
-+
- 		ndisc_send_na(ifindex, src, &in6addr_all_nodes_mc,
- 			      target, na_flags);
- 
-diff -r a7e20b0b5c43 src/policy.c
---- a/src/policy.c	Wed Nov 28 16:43:32 2007 +0100
-+++ b/src/policy.c	Tue Jan 08 11:28:48 2008 +0100
-@@ -107,6 +107,23 @@ int default_max_binding_life(const struc
- 	return 0;
- }
- 
-+static inline int
-+policy_check_mob_net_prefix(const struct policy_bind_acl_entry *acl,
-+			    const struct ip6_mh_binding_update *bu,
-+			    const struct mh_options *opts)
-+{
-+	struct ip6_mh_opt_mob_net_prefix *op;
-+	for (op = mh_opt(&bu->ip6mhbu_hdr, opts, IP6_MHOPT_MOB_NET_PRFX);
-+	     op != NULL;
-+	     op = mh_opt_next(&bu->ip6mhbu_hdr, opts, op)) {
-+		if (!prefix_list_get(&acl->mob_net_prefixes,
-+				     &op->ip6mnp_prefix,
-+				     op->ip6mnp_prefix_len))
-+			return IP6_MH_BAS_NOT_AUTH_FOR_PRFX;
-+	}
-+	return IP6_MH_BAS_ACCEPTED;
-+}
-+
- /**
-  * default_discard_binding - check for discard policy
-  * @remote_hoa: remote MN's home address
-@@ -127,10 +144,20 @@ int default_discard_binding(const struct
- 	int ret = def_bind_policy;
- 	struct policy_bind_acl_entry *acl;
- 
-+	if (bu->ip6mhbu_flags & IP6_MH_BU_MR && !conf.HaAcceptMobRtr)
-+		return IP6_MH_BAS_MR_OP_NOT_PERMITTED;
-+
- 	pthread_rwlock_rdlock(&policy_lock);
- 	acl = hash_get(&policy_bind_acl_hash, NULL, remote_hoa);
- 	if (acl != NULL) {
- 		ret = acl->bind_policy;
-+		if (ret < IP6_MH_BAS_UNSPECIFIED &&
-+		    bu->ip6mhbu_flags & IP6_MH_BU_MR) {
-+			struct mh_options opts;
-+			mh_opt_parse(&bu->ip6mhbu_hdr, len,
-+				     sizeof(*bu), &opts);
-+			ret = policy_check_mob_net_prefix(acl, bu, &opts);
-+		}
- 	}
- 	pthread_rwlock_unlock(&policy_lock);
- 	return ret;
-@@ -227,6 +254,42 @@ int default_best_ro_coa(const struct in6
- 	return 0;
- }
- 
-+int default_get_mnp_count(const struct in6_addr *hoa)
-+{
-+	int ret = 0;
-+	struct policy_bind_acl_entry *acl;
-+	pthread_rwlock_rdlock(&policy_lock);
-+	acl = hash_get(&policy_bind_acl_hash, NULL, hoa);
-+	if (acl != NULL)
-+		ret = acl->mnp_count;
-+	pthread_rwlock_unlock(&policy_lock);
-+	return ret;
-+
-+}
-+
-+int default_get_mnps(const struct in6_addr *hoa,
-+		     const int mnp_count,
-+		     struct nd_opt_prefix_info *mnps)
-+{
-+	int i = 0;
-+	struct policy_bind_acl_entry *acl;
-+
-+	pthread_rwlock_rdlock(&policy_lock);
-+	acl = hash_get(&policy_bind_acl_hash, NULL, hoa);
-+	if (acl != NULL) {
-+		struct list_head *l;
-+		list_for_each(l, &acl->mob_net_prefixes) {
-+			struct prefix_list_entry *e;
-+			if (i >= mnp_count)
-+				break;
-+			e = list_entry(l, struct prefix_list_entry, list);
-+			mnps[i++] = e->pinfo;
-+		}
-+	}
-+	pthread_rwlock_unlock(&policy_lock);
-+	return i;
-+}
-+
- static int policy_bind_acle_cleanup(void *data, void *arg)
- {
- 	struct policy_bind_acl_entry *acl = data;
-diff -r a7e20b0b5c43 src/policy.h
---- a/src/policy.h	Wed Nov 28 16:43:32 2007 +0100
-+++ b/src/policy.h	Tue Jan 08 11:28:48 2008 +0100
-@@ -10,12 +10,15 @@
- 
- struct ip6_mh_binding_update;
- struct nd_router_advert;
-+struct nd_opt_prefix_info;
- 
- struct policy_bind_acl_entry {
- 	struct list_head list;
- 	struct in6_addr hoa;
- 	int plen;
- 	int bind_policy;
-+	int mnp_count;
-+	struct list_head mob_net_prefixes;
- };
- 
- /**
-@@ -147,6 +150,12 @@ int default_best_ro_coa(const struct in6
- 			const struct in6_addr *cn,
- 			struct in6_addr *coa);
- 
-+int default_get_mnp_count(const struct in6_addr *hoa);
-+
-+int default_get_mnps(const struct in6_addr *hoa,
-+		     const int mnp_count,
-+		     struct nd_opt_prefix_info *mnps);
-+
- void policy_cleanup(void);
- 
- int policy_init(void);
-diff -r a7e20b0b5c43 src/proc_sys.h
---- a/src/proc_sys.h	Wed Nov 28 16:43:32 2007 +0100
-+++ b/src/proc_sys.h	Tue Jan 08 11:28:48 2008 +0100
-@@ -14,6 +14,7 @@
- #define PROC_SYS_IP6_APP_SOLICIT "/proc/sys/net/ipv6/neigh/%s/app_solicit"
- #define PROC_SYS_IP6_BASEREACHTIME_MS "/proc/sys/net/ipv6/neigh/%s/base_reachable_time_ms"
- #define PROC_SYS_IP6_RETRANSTIMER_MS "/proc/sys/net/ipv6/neigh/%s/retrans_time_ms"
-+#define PROC_SYS_IP6_FORWARDING "/proc/sys/net/ipv6/conf/%s/forwarding"
- 
- int set_iface_proc_entry(const char *tmpl, const char *if_name, int val);
- 
-diff -r a7e20b0b5c43 src/rtnl.h
---- a/src/rtnl.h	Wed Nov 28 16:43:32 2007 +0100
-+++ b/src/rtnl.h	Tue Jan 08 11:28:48 2008 +0100
-@@ -16,6 +16,7 @@
- #define IP6_RT_PRIO_MIP6_FWD 192
- #define IP6_RT_PRIO_ADDRCONF 256
- 
-+#define IP6_RULE_PRIO_MIP6_MNP_IN    1000
- #define IP6_RULE_PRIO_MIP6_HOA_OUT   1001
- #define IP6_RULE_PRIO_MIP6_COA_OUT   1002
- #define IP6_RULE_PRIO_MIP6_BLOCK     1003
-diff -r a7e20b0b5c43 src/scan.l
---- a/src/scan.l	Wed Nov 28 16:43:32 2007 +0100
-+++ b/src/scan.l	Tue Jan 08 11:28:48 2008 +0100
-@@ -136,6 +136,11 @@ MnRouterProbeTimeout		{ return MNROUTERP
- MnRouterProbeTimeout		{ return MNROUTERPROBETIMEOUT; }
- MnDiscardHaParamProb		{ return MNDISCARDHAPARAMPROB; }
- OptimisticHandoff		{ return OPTIMISTICHANDOFF; }
-+HaAcceptMobRtr   		{ return HAACCEPTMOBRTR; }
-+IsMobRtr       			{ return ISMOBRTR; }
-+HaServedPrefix       	       	{ return HASERVEDPREFIX; }
-+HomePrefix     			{ return HOMEPREFIX; }
-+MobRtrUseExplicitMode    	{ return MOBRTRUSEEXPLICITMODE; }
- internal			{ return INTERNAL; }
- 
- {addr}		{
-diff -r a7e20b0b5c43 src/vt.c
---- a/src/vt.c	Wed Nov 28 16:43:32 2007 +0100
-+++ b/src/vt.c	Tue Jan 08 11:28:48 2008 +0100
-@@ -677,6 +677,16 @@ static int bcache_vt_dump(void *data, vo
- 	}
- 
- 	fprintf(vh->vh_stream, "\n");
-+
-+	/* Dump the registered MNP */
-+	{
-+		struct list_head *l;
-+		list_for_each(l, &bce->mob_net_prefixes) {
-+			struct prefix_list_entry *p;
-+			p = list_entry(l, struct prefix_list_entry, list);
-+			fprintf(vh->vh_stream, " MNP: %x:%x:%x:%x:%x:%x:%x:%x/%d\n", NIP6ADDR(&p->ple_prefix), p->ple_plen);
-+		}
-+	}
- 
- 	return 0;
- }
-diff -r a7e20b0b5c43 src/xfrm.c
---- a/src/xfrm.c	Wed Nov 28 16:43:32 2007 +0100
-+++ b/src/xfrm.c	Tue Jan 08 11:28:48 2008 +0100
-@@ -679,12 +679,73 @@ static int _mn_ha_ipsec_bypass_init(cons
- 	return err;
- }
- 
-+static int mr_ipsec_bypass_init(void)
-+{
-+	struct list_head *home;
-+	struct list_head *mnps;
-+	int err=0;
-+
-+	/* Loop for each HomeAddress info */
-+	list_for_each(home, &conf.home_addrs)
-+	{
-+		struct home_addr_info *hai;
-+		hai = list_entry(home, struct home_addr_info, list);
-+
-+		/* If Mobile Router for this link, loop for each MNP */
-+		if (hai->mob_rtr)
-+		{
-+			/* Add bypass policies to and from the MNP link */
-+			list_for_each(mnps, &hai->mob_net_prefixes)
-+			{
-+				struct prefix_list_entry * mnp;
-+				struct xfrm_selector sel;
-+
-+				mnp = list_entry(mnps, struct prefix_list_entry, list);
-+
-+				memset(&sel, 0, sizeof(sel));
-+				sel.family = AF_INET6;
-+				sel.user = getuid();
-+
-+				/* IN, src = MNP , dst = any */
-+				memcpy(&sel.saddr.a6, &mnp->ple_prefix, sizeof(sel.saddr.a6));
-+				sel.prefixlen_s = mnp->ple_plen;
-+
-+				err = xfrm_ipsec_policy_add(&sel, 0, XFRM_POLICY_IN,
-+				        		    XFRM_POLICY_ALLOW, MIP6_PRIO_MR_LOCAL_DATA_BYPASS,
-+							    NULL, 0);
-+
-+				/* XXX: what should we do in case of error? */
-+
-+				/* FWD, src = MNP , dst = any */
-+				err = xfrm_ipsec_policy_add(&sel, 0, XFRM_POLICY_FWD,
-+				        		    XFRM_POLICY_ALLOW, MIP6_PRIO_MR_LOCAL_DATA_BYPASS,
-+							    NULL, 0);
-+
-+				/* OUT, src = any , dst = MNP */
-+				memset(&sel.saddr.a6, 0, sizeof(sel.saddr.a6));
-+				sel.prefixlen_s = 0;
-+				memcpy(&sel.daddr.a6, &mnp->ple_prefix, sizeof(sel.daddr.a6));
-+				sel.prefixlen_d = mnp->ple_plen;
-+
-+				err = xfrm_ipsec_policy_add(&sel, 0, XFRM_POLICY_OUT,
-+				        		    XFRM_POLICY_ALLOW, MIP6_PRIO_MR_LOCAL_DATA_BYPASS,
-+							    NULL, 0);
-+			}
-+		}
-+	}
-+
-+	return err;
-+}
-+
- static inline int mn_ha_ipsec_init(void)
- {
- 	int err;
- 
- 	/* insert bypass policy */
- 	err = ipsec_policy_walk(_mn_ha_ipsec_bypass_init, NULL);
-+
-+	/* insert NEMO-related bypass */
-+	err = mr_ipsec_bypass_init();
- 
- 	err = ipsec_policy_walk(_mn_ha_ipsec_init, NULL);
- 
-@@ -787,9 +848,64 @@ static int _mn_ha_ipsec_bypass_cleanup(c
- 	return err;
- }
- 
-+static int mr_ipsec_bypass_cleanup(void)
-+{
-+	struct list_head *home;
-+	struct list_head *mnps;
-+	int err=0;
-+
-+	/* Loop for each HomeAddress info */
-+	list_for_each(home, &conf.home_addrs)
-+	{
-+		struct home_addr_info *hai;
-+		hai = list_entry(home, struct home_addr_info, list);
-+
-+		/* If Mobile Router for this link, loop for each MNP */
-+		if (hai->mob_rtr)
-+		{
-+			/* Delete bypass policies to and from the MNP link */
-+			list_for_each(mnps, &hai->mob_net_prefixes)
-+			{
-+				struct prefix_list_entry * mnp;
-+				struct xfrm_selector sel;
-+
-+				mnp = list_entry(mnps, struct prefix_list_entry, list);
-+
-+				memset(&sel, 0, sizeof(sel));
-+				sel.family = AF_INET6;
-+				sel.user = getuid();
-+
-+				/* IN, src = MNP , dst = any */
-+				memcpy(&sel.saddr.a6, &mnp->ple_prefix, sizeof(sel.saddr.a6));
-+				sel.prefixlen_s = mnp->ple_plen;
-+
-+				err = xfrm_ipsec_policy_del(&sel, XFRM_POLICY_IN);
-+
-+				/* XXX: what should we do in case of error? */
-+
-+				/* FWD, src = MNP , dst = any */
-+				err = xfrm_ipsec_policy_del(&sel, XFRM_POLICY_FWD);
-+
-+				/* OUT, src = any , dst = MNP */
-+				memset(&sel.saddr.a6, 0, sizeof(sel.saddr.a6));
-+				sel.prefixlen_s = 0;
-+				memcpy(&sel.daddr.a6, &mnp->ple_prefix, sizeof(sel.daddr.a6));
-+				sel.prefixlen_d = mnp->ple_plen;
-+
-+				err = xfrm_ipsec_policy_del(&sel, XFRM_POLICY_OUT);
-+			}
-+		}
-+	}
-+
-+	return err;
-+}
-+
-+
- static inline void mn_ha_ipsec_cleanup(void)
- {
- 	ipsec_policy_walk(_mn_ha_ipsec_bypass_cleanup, NULL);
-+
-+	(void)mr_ipsec_bypass_cleanup();
- 
- 	ipsec_policy_walk(_mn_ha_ipsec_cleanup, NULL);
- }
-@@ -1719,6 +1835,8 @@ int xfrm_pre_bu_add_bule(struct bulentry
- 		if (hai->home_block & HOME_LINK_BLOCK)
- 			xfrm_unblock_link(hai);
- 		xfrm_block_link(hai);
-+		if (hai->mob_rtr && !(hai->home_block & NEMO_FWD_BLOCK))
-+			xfrm_block_fwd(hai);
- 	}
- 	if (IN6_ARE_ADDR_EQUAL(&bule->hoa, &bule->coa)) {
- 		if (rdata)
-@@ -1784,6 +1902,8 @@ int xfrm_post_ba_mod_bule(struct bulentr
- 		struct home_addr_info *hai = bule->home;
- 		if (hai->home_block & HOME_LINK_BLOCK)
- 			xfrm_unblock_link(hai);
-+		if (hai->home_block & NEMO_FWD_BLOCK)
-+			xfrm_unblock_fwd(hai);
- 	}
- 	/* check if XFRM policies and states have already been cleaned up */
- 	if (IN6_ARE_ADDR_EQUAL(&bule->hoa, &bule->coa))
-@@ -2058,6 +2178,50 @@ void xfrm_unblock_hoa(struct home_addr_i
- 	hai->home_block &= ~HOME_ADDR_BLOCK;
- }
- 
-+/* block all RA messages sent by MR */
-+int xfrm_block_ra(struct home_addr_info *hai)
-+{
-+	int ret = 0;
-+	struct xfrm_selector sel;
-+	hai->home_block |= NEMO_RA_BLOCK;
-+	set_selector(&in6addr_any, &in6addr_any, IPPROTO_ICMPV6,
-+		     ND_ROUTER_ADVERT, 0, 0, &sel);
-+	if ((ret = xfrm_mip_policy_add(&sel, 0, XFRM_POLICY_OUT, XFRM_POLICY_BLOCK,
-+				   MIP6_PRIO_HOME_BLOCK, NULL, 0)))
-+		return ret;
-+	return ret;
-+}
-+
-+void xfrm_unblock_ra(struct home_addr_info *hai)
-+{
-+	struct xfrm_selector sel;
-+	set_selector(&in6addr_any, &in6addr_any, IPPROTO_ICMPV6,
-+		     ND_ROUTER_ADVERT, 0, 0, &sel);
-+	xfrm_mip_policy_del(&sel, XFRM_POLICY_OUT);
-+	hai->home_block &= ~NEMO_RA_BLOCK;
-+}
-+
-+/* block all forwarded packets */
-+int xfrm_block_fwd(struct home_addr_info *hai)
-+{
-+	int ret = 0;
-+	struct xfrm_selector sel;
-+	hai->home_block |= NEMO_FWD_BLOCK;
-+	set_selector(&in6addr_any, &in6addr_any, 0, 0, 0, 0, &sel);
-+	if ((ret = xfrm_mip_policy_add(&sel, 0, XFRM_POLICY_FWD, XFRM_POLICY_BLOCK,
-+				   MIP6_PRIO_HOME_BLOCK, NULL, 0)))
-+		return ret;
-+	return ret;
-+}
-+
-+void xfrm_unblock_fwd(struct home_addr_info *hai)
-+{
-+	struct xfrm_selector sel;
-+	set_selector(&in6addr_any, &in6addr_any, 0, 0, 0, 0, &sel);
-+	xfrm_mip_policy_del(&sel, XFRM_POLICY_FWD);
-+	hai->home_block &= ~NEMO_FWD_BLOCK;
-+}
-+
- int mn_ipsec_recv_bu_tnl_pol_add(struct bulentry *bule, int ifindex, 
- 				 struct ipsec_policy_entry *e)
- {
-diff -r a7e20b0b5c43 src/xfrm.h
---- a/src/xfrm.h	Wed Nov 28 16:43:32 2007 +0100
-+++ b/src/xfrm.h	Tue Jan 08 11:28:48 2008 +0100
-@@ -15,6 +15,7 @@
- #define MIP6_PRIO_RO_SIG_IPSEC		7	/* XXX: BU between MN-MN with IPsec */
- #define MIP6_PRIO_RO_SIG		8	/* XXX: BU between MN-CN */
- #define MIP6_PRIO_RO_SIG_ANY		9
-+#define MIP6_PRIO_MR_LOCAL_DATA_BYPASS	9	/* Bypass rule for local traffic in mobile network */
- #define MIP6_PRIO_RO_SIG_RR		10	/* XXX: MH(or HoTI/HoT) between MN-CN */
- #define MIP6_PRIO_RO_BLOCK		11
- #define MIP6_PRIO_NO_RO_SIG_ANY		12
-@@ -87,6 +88,12 @@ int xfrm_block_hoa(struct home_addr_info
- int xfrm_block_hoa(struct home_addr_info *hai);
- void xfrm_unblock_hoa(struct home_addr_info *hai);
- 
-+int xfrm_block_ra(struct home_addr_info *hai);
-+void xfrm_unblock_ra(struct home_addr_info *hai);
-+
-+int xfrm_block_fwd(struct home_addr_info *hai);
-+void xfrm_unblock_fwd(struct home_addr_info *hai);
-+
- int ha_mn_ipsec_pol_mod(struct in6_addr *haaddr,
- 			struct in6_addr *hoa);
- 
diff --git a/openair3/NEMO_SHO/mipv6-daemon-umip-0.4-nepl-mcoa-20080108.patch b/openair3/NEMO_SHO/mipv6-daemon-umip-0.4-nepl-mcoa-20080108.patch
deleted file mode 100755
index 11217388cf4dfb57b61f20c87d40cb056d08dec7..0000000000000000000000000000000000000000
--- a/openair3/NEMO_SHO/mipv6-daemon-umip-0.4-nepl-mcoa-20080108.patch
+++ /dev/null
@@ -1,5535 +0,0 @@
-diff -r 82fcd4bea972 NEWS.MCOA
---- /dev/null	Thu Jan 01 00:00:00 1970 +0000
-+++ b/NEWS.MCOA	Fri Jan 11 17:02:25 2008 +0100
-@@ -0,0 +1,103 @@
-+mipv6-daemon-umip-0.4-nepl-mcoa-20080108.patch
-+News and Bugfixes list since mipv6-daemon-umip-0.3-nepl-mcoa-20071022.patch:
-+
-+* Updated code on top of the latest NEPL patch
-+* No new features
-+
-+-----------------------------------------------------------------------
-+mipv6-daemon-umip-0.4-nepl-mcoa-20071022.patch
-+News and Bugfixes list since mipv6-daemon-umip-0.3-nepl-mcoa-20070613.patch:
-+
-+* Ported the code to UMIP 0.4. MCoA now runs on a 2.6.23 kernel, 
-+  with an UMIP 0.4-based code for the userland.
-+* Merged a fix to the proxy ND code for the HA (provided by 
-+  Tobias HOF): the HA can now be used as legacy node on the 
-+  Home Link (whereas it only worked as a gateway before).
-+
-+-----------------------------------------------------------------------
-+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 -r 82fcd4bea972 README.MCOA
---- /dev/null	Thu Jan 01 00:00:00 1970 +0000
-+++ b/README.MCOA	Fri Jan 11 17:02:25 2008 +0100
-@@ -0,0 +1,154 @@
-+--------------------------------------------
-+Multiple CoA implementation on UMIP
-+<http://software.nautilus6.org/MCoA/>
-+ver. 20080108
-+--------------------------------------------
-+Romain KUNTZ <kuntz(at)sfc.wide.ad.jp>
-+Jean LORCHAT <lorchat(at)sfc.wide.ad.jp>
-+Nautilus6 Project <http://www.nautilus6.org>
-+--------------------------------------------
-+
-+
-+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 
-+<http://www.linux-ipv6.org/umip-0.3-ann.html.en>
-+
-+
-+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 <kuntz(at)sfc.wide.ad.jp>
-+Jean LORCHAT <lorchat(at)sfc.wide.ad.jp>
-+Nautilus6 Project <http://www.nautilus6.org>
-+--------------------------------------------
-diff -r 82fcd4bea972 include/netinet/ip6mh.h
---- a/include/netinet/ip6mh.h	Fri Jan 11 16:55:08 2008 +0100
-+++ b/include/netinet/ip6mh.h	Fri Jan 11 17:02:25 2008 +0100
-@@ -146,6 +146,25 @@ struct ip6_mh_opt_mob_net_prefix {
- } __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 @@ struct ip6_mh_opt_mob_net_prefix {
- #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 @@ struct ip6_mh_opt_mob_net_prefix {
- #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 -r 82fcd4bea972 man/mip6d.conf.tmpl
---- a/man/mip6d.conf.tmpl	Fri Jan 11 16:55:08 2008 +0100
-+++ b/man/mip6d.conf.tmpl	Fri Jan 11 17:02:25 2008 +0100
-@@ -57,6 +57,9 @@ These options are used both in the Home 
- .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 
- 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
- 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;
- 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 
- 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 
- 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
- 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 @@ matching this entry.
- .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";
- 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;
- DoRouteOptimizationCN disabled;
- DoRouteOptimizationMN disabled;
- 
--Interface "eth0";
-+Interface "eth0" {
-+        Bid 111;
-+        BidPriority 10;
-+};
-+
-+Interface "eth1" {
-+        Bid 222;
-+        BidPriority 5;
-+};
- 
- MnRouterProbes 1;
- 
-@@ -426,6 +514,8 @@ MnHomeLink "eth0" {
-         IsMobRtr enabled;
-         HomeAgentAddress 3ffe:2620:6:1::1;
-         HomeAddress 3ffe:2620:6:1::1234/64 (3ffe:2620:6:2::/64, 3ffe:2620:6:3::/64);
-+        RegMultipleCoA enabled;
-+        IfMultipleCoA "eth0", "eth1";
- }
- 
- UseMnHaIPsec disabled;
-diff -r 82fcd4bea972 src/bcache.c
---- a/src/bcache.c	Fri Jan 11 16:55:08 2008 +0100
-+++ b/src/bcache.c	Fri Jan 11 17:02:25 2008 +0100
-@@ -48,6 +48,7 @@ static int bcache_count = 0;
- static int bcache_count = 0;
- 
- 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
-@@ -90,6 +91,12 @@ void dump_bce(void *bce, void *os)
- 	fprintf(out, " lifetime %ld\n ", e->lifetime.tv_sec);
- 	fprintf(out, " seqno %d\n", e->seqno);
- 
-+ 	if (e->bid)
-+ 		fprintf(out, " BID = %d, Priority = %d\n", 
-+ 			e->bid, e->priority);
-+ 	else
-+ 		fprintf(out, " No BID assigned\n");
-+ 
- 	if (e->flags & IP6_MH_BA_MR) {
- 		struct list_head *list;
- 
-@@ -201,6 +208,7 @@ void bcache_free(struct bcentry *bce)
-  * @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
-@@ -208,7 +216,8 @@ void bcache_free(struct bcentry *bce)
-  * 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;
- 
-@@ -216,7 +225,7 @@ struct bcentry *bcache_get(const struct 
- 
- 	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);
-@@ -240,16 +249,19 @@ void bcache_release_entry(struct bcentry
-  * 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;
-@@ -264,7 +276,8 @@ static int __bcache_insert(struct bcentr
- {
- 	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;
- 
-@@ -282,7 +295,14 @@ static int __bcache_start(struct bcentry
- 	      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;
- }
- 
-@@ -350,22 +370,26 @@ int bcache_update_expire(struct bcentry 
- 	}
- 	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);
- }
- 
-@@ -398,8 +422,27 @@ static void bce_delete(struct bcentry *b
- 	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);
-@@ -414,7 +457,7 @@ static void bce_delete(struct bcentry *b
- 		}
- 	}
- 	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);
- }
-@@ -458,3 +501,71 @@ int bcache_iterate(int (* func)(void *, 
- 	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;
-+}
-+
-diff -r 82fcd4bea972 src/bcache.h
---- a/src/bcache.h	Fri Jan 11 16:55:08 2008 +0100
-+++ b/src/bcache.h	Fri Jan 11 17:02:25 2008 +0100
-@@ -20,6 +20,12 @@ struct bcentry {
- 	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 @@ struct bcentry {
- #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,37 @@ int bcache_update_expire(struct bcentry 
- 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_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 -r 82fcd4bea972 src/bul.c
---- a/src/bul.c	Fri Jan 11 16:55:08 2008 +0100
-+++ b/src/bul.c	Fri Jan 11 17:02:25 2008 +0100
-@@ -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;
- 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 @@ struct bulentry *create_bule(const struc
- 		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 @@ void dump_bule(void *bule, void *os)
- 		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 ");
-@@ -118,21 +131,23 @@ void dump_bule(void *bule, void *os)
-  * @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;
- }
- 
-@@ -175,9 +190,11 @@ int bul_add(struct bulentry *bule)
- 
- 	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);
-@@ -197,9 +214,9 @@ int bul_add(struct bulentry *bule)
- 	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; 
- }
- 
-@@ -209,8 +226,8 @@ void bul_delete(struct bulentry *bule)
- 	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;
-@@ -222,6 +239,7 @@ void bul_delete(struct bulentry *bule)
- 		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);
-@@ -232,16 +250,28 @@ void bul_delete(struct bulentry *bule)
- 		} 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);
-@@ -312,3 +342,129 @@ int bul_iterate(struct hash *h, int (* f
- 	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 -r 82fcd4bea972 src/bul.h
---- a/src/bul.h	Fri Jan 11 16:55:08 2008 +0100
-+++ b/src/bul.h	Fri Jan 11 17:02:25 2008 +0100
-@@ -9,6 +9,9 @@
- #include "tqueue.h"
- #include "hash.h"
- #include "list.h"
-+
-+#define BULE_TABLE_MIN 1
-+#define BULE_TABLE_MAX 251
- 
- struct home_addr_info;
- 
-@@ -31,10 +34,16 @@ struct bulentry {
- 	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 @@ struct bulentry {
- 	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 @@ enum {
- 
- 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 *
- 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 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 -r 82fcd4bea972 src/cn.c
---- a/src/cn.c	Fri Jan 11 16:55:08 2008 +0100
-+++ b/src/cn.c	Fri Jan 11 17:02:25 2008 +0100
-@@ -67,7 +67,11 @@ static void cn_recv_dst_unreach(const st
- 	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 @@ static void cn_recv_dst_unreach(const st
- 	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 @@ void cn_recv_bu(const struct ip6_mh *mh,
- 	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 @@ void cn_recv_bu(const struct ip6_mh *mh,
- 
- 	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 @@ void cn_recv_bu(const struct ip6_mh *mh,
- 				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 @@ void cn_recv_bu(const struct ip6_mh *mh,
- 		}
- 		/* 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 -r 82fcd4bea972 src/conf.c
---- a/src/conf.c	Fri Jan 11 16:55:08 2008 +0100
-+++ b/src/conf.c	Fri Jan 11 17:02:25 2008 +0100
-@@ -74,6 +74,7 @@ static void conf_version(void)
- {
- 	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 @@ static void conf_default(struct mip6_con
- 
- 	/* HA options */
- 	c->SendMobPfxAdvs = 1;
-+	c->HaAcceptMCoAReg = 0;
- 	c->SendUnsolMobPfxAdvs = 1;
- 	c->MaxMobPfxAdvInterval = 86400; /* seconds */
- 	c->MinMobPfxAdvInterval = 600; /* seconds */
-@@ -317,8 +319,89 @@ void conf_show(struct mip6_config *c)
- 	dbg("MinMobPfxAdvInterval = %u\n", c->MinMobPfxAdvInterval);
- 	dbg("HaMaxBindingLife = %u\n", c->HaMaxBindingLife);
- 	dbg("HaAcceptMobRtr = %s\n", CONF_BOOL_STR(c->HaAcceptMobRtr));
-+	dbg("HaAcceptMCoAReg = %s\n", CONF_BOOL_STR(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 -r 82fcd4bea972 src/conf.h
---- a/src/conf.h	Fri Jan 11 16:55:08 2008 +0100
-+++ b/src/conf.h	Fri Jan 11 17:02:25 2008 +0100
-@@ -48,6 +48,7 @@ struct mip6_config {
- 
- 	/* HA options */
- 	char HaAcceptMobRtr;
-+	char HaAcceptMCoAReg;
- 	char SendMobPfxAdvs;
- 	char SendUnsolMobPfxAdvs;
- 	unsigned int MaxMobPfxAdvInterval;
-@@ -66,6 +67,9 @@ struct net_iface {
- 	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 @@ int conf_parse(struct mip6_config *c, in
- 
- 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 -r 82fcd4bea972 src/dhaad_mn.c
---- a/src/dhaad_mn.c	Fri Jan 11 16:55:08 2008 +0100
-+++ b/src/dhaad_mn.c	Fri Jan 11 17:02:25 2008 +0100
-@@ -120,8 +120,9 @@ static void dhaad_resend(struct tq_elem 
- 			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 @@ static void _dhaad_start(struct home_add
- 		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 -r 82fcd4bea972 src/gram.y
---- a/src/gram.y	Fri Jan 11 16:55:08 2008 +0100
-+++ b/src/gram.y	Fri Jan 11 17:02:25 2008 +0100
-@@ -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 @@ static void uerror(const char *fmt, ...)
- %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 @@ static void uerror(const char *fmt, ...)
- %type <addr>	mnropolicyaddr
- %type <bool>	dorouteopt
- %type <num>	bindaclpolval
-+%type <num>	mcoapolval
- %type <num>	prefixlen
- %type <num>	mip6entity
- %type <bool>	xfrmaction
-@@ -306,6 +320,10 @@ topdef		: MIP6ENTITY mip6entity ';'
- 		{
- 			conf.HaAcceptMobRtr = $2;
- 		}
-+		| HAACCEPTMCOAREG BOOL ';' 
-+		{ 
-+			conf.HaAcceptMCoAReg = $2;
-+		}
- 		| HASERVEDPREFIX prefixlistentry ';'
- 		{
- 			list_splice(&prefixes,
-@@ -375,6 +393,9 @@ ifacedef	: QSTRING ifacesub
- 			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 @@ ifaceopt	: IFTYPE mip6entity ';'
- 		} 
- 		| 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 @@ linksub		: QSTRING '{' linkdefs '}'
- 			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 @@ linkdef		: HOMEAGENTADDRESS ADDR ';'
- 			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 @@ bindaclpolval	: BOOL
- 		| 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 @@ bindaclpolicy	: ADDR prefixlistsub binda
- 			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 @@ prefixlistentry	: ADDR '/' prefixlen
- 			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 -r 82fcd4bea972 src/ha.c
---- a/src/ha.c	Fri Jan 11 16:55:08 2008 +0100
-+++ b/src/ha.c	Fri Jan 11 17:02:25 2008 +0100
-@@ -59,6 +59,14 @@
- #include "xfrm.h"
- #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;
-@@ -504,7 +512,7 @@ static int ha_vt_init(void)
- 
- 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 @@ static void nemo_ha_del_mnp_routes(struc
- 		    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,11 +546,89 @@ static int nemo_ha_add_mnp_routes(struct
- 		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;
- }
- 
-@@ -544,10 +638,49 @@ struct home_tnl_ops_parm {
- 	struct list_head mob_net_prefixes;
- };
- 
-+static int mcoa_ha_add_dflt_rules(struct home_tnl_ops_parm *p)
-+{
-+	struct list_head *list;
-+	struct bcentry *bce = p->bce;
-+	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, &p->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;
-+}
-+
- static int home_tnl_del(int old_if, int new_if, struct home_tnl_ops_parm *p)
- {
- 	const struct in6_addr *our_addr, *peer_addr, *coa, *old_coa;
- 	struct list_head *mnp;
-+	struct bcentry *best_bce = NULL;
- 
- 	assert(old_if);
- 
-@@ -565,12 +698,33 @@ static int home_tnl_del(int old_if, int 
- 		ha_ipsec_tnl_pol_del(our_addr, peer_addr, p->bce->tunnel, mnp);
- 	}
- 	/* 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;
- 
-@@ -581,6 +735,7 @@ static int home_tnl_add(int old_if, int 
- {
- 	const struct in6_addr *our_addr, *peer_addr, *coa, *old_coa;
- 	struct list_head *mnp;
-+	struct bcentry *best_bce = NULL;
- 
- 	assert(new_if);
- 
-@@ -596,7 +751,8 @@ static int home_tnl_add(int old_if, int 
- 
- 	/* 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
-@@ -604,11 +760,38 @@ static int home_tnl_add(int old_if, int 
- 		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) < 0) {
-+			p->ba_status = IP6_MH_BAS_INSUFFICIENT;
-+			goto err;
-+		}
- 	}
- 	/* add SP entry */	
- 	if (conf.UseMnHaIPsec) {
-@@ -664,9 +847,11 @@ static int home_tnl_chg(int old_if, int 
- 			/* Do the same for routes */
- 			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;
-@@ -707,12 +892,22 @@ static int home_tnl_ops(int request, int
- 
- static void home_cleanup(struct bcentry *bce)
- {
--	mpd_cancel_mpa(&bce->our_addr, &bce->peer_addr);
-+	int nb_entry = mcoa_bce_count(&bce->peer_addr);
-+
-+	/* MCoA 
-+	 * MPA is canceled if this is the last BCE entry
-+	 */
-+	if (nb_entry == 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);
-+		/* MCoA
-+		 * Proxy ND is stopped if this is the last BCE entry
-+		 */
-+		if (nb_entry == 1)
-+			proxy_nd_stop(bce->link, &bce->peer_addr, bce->flags);
- 	}
- 	if (bce->tunnel > 0) {
- 		struct home_tnl_ops_parm p = {
-@@ -724,6 +919,9 @@ static void home_cleanup(struct bcentry 
- 	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);
- }
- 
- 
-@@ -800,19 +998,28 @@ static void *ha_recv_bu_worker(void *var
- {
- 	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);
-@@ -827,8 +1034,79 @@ restart:
- 	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 */
-@@ -873,7 +1151,7 @@ restart:
- 				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;
-@@ -895,6 +1173,10 @@ restart:
- 					   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)) {
-@@ -916,24 +1198,38 @@ restart:
- 		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;
-@@ -965,6 +1261,7 @@ restart:
- 	bce->seqno = seqno;
- 	bce->flags = bu_flags;
- 	bce->lifetime = lft;
-+
- 	if (new) {
- 		if (tunnel_add(out.src, out.bind_coa, 0, 
- 			       home_tnl_ops, &p) < 0) {
-@@ -979,7 +1276,8 @@ restart:
- 
- 		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) {
-@@ -987,16 +1285,23 @@ restart:
- 			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)
-@@ -1006,15 +1311,24 @@ restart:
- 			goto send_nack;
- 		}
- 		/* Now update the MNP list in the BCE */
--		prefix_list_free(&bce->mob_net_prefixes);
--		list_splice(&p.mob_net_prefixes, &bce->mob_net_prefixes);
--
-+		/* MCoA: the update is done only if this is not a 
-+		 * deregistration BU, otherwise MNPs are erased from the BCE
-+		 * (the dereg BU does not have any MNP option), thus there 
-+		 * is a problem to update the fwmark MNP rules
-+		 */
-+		if (tsisset(lft)) {
-+			prefix_list_free(&bce->mob_net_prefixes);
-+			list_splice(&p.mob_net_prefixes, &bce->mob_net_prefixes);
-+		}
- 		bcache_update_expire(bce);
- 	}
- 	/* bce is always valid here */
- 	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))
-@@ -1035,12 +1349,16 @@ restart:
- 		 * have a binding before sending this Binding Update,
- 		 * discard the connections to the home address. */
- 	}
-- 	if (status < IP6_MH_BAS_UNSPECIFIED && bu_flags & IP6_MH_BU_MR)
-+	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);
-@@ -1060,10 +1378,12 @@ send_nack:
- 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;
- }
- 
-@@ -1089,12 +1409,13 @@ int ha_recv_bu_main(const struct ip6_mh 
- 
- 	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;
-@@ -1166,8 +1487,9 @@ int ha_init(void)
- 		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);
-@@ -1185,7 +1507,7 @@ void ha_cleanup(void)
- 	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 -r 82fcd4bea972 src/hash.c
---- a/src/hash.c	Fri Jan 11 16:55:08 2008 +0100
-+++ b/src/hash.c	Fri Jan 11 17:02:25 2008 +0100
-@@ -47,6 +47,7 @@ struct hash_entry {
- 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 uint32_t calc_hash1(int s, const 
- }
- 
- 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 @@ static int match2(struct hash_entry *h, 
- 	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 match2(struct hash_entry *h, 
- }
- 
- 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 @@ static int match1(struct hash_entry *h, 
- 	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_cleanup(struct hash *h)
- 
- 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 @@ void *hash_get(const struct hash *h,
- 	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 @@ void *hash_get(const struct hash *h,
- }
- 
- 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 @@ int hash_add(const struct hash *h, void 
- 	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 @@ int hash_iterate(const struct hash *h, i
- 	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 @@ void hash_delete(const struct hash *h,
- 	
- 	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 -r 82fcd4bea972 src/hash.h
---- a/src/hash.h	Fri Jan 11 16:55:08 2008 +0100
-+++ b/src/hash.h	Fri Jan 11 17:02:25 2008 +0100
-@@ -20,7 +20,9 @@ struct hash {
- 	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 @@ int hash_init(struct hash *h, int type, 
-  */
- 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 @@ int hash_add(const struct hash *h, void 
- 
- 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 -r 82fcd4bea972 src/mh.c
---- a/src/mh.c	Fri Jan 11 16:55:08 2008 +0100
-+++ b/src/mh.c	Fri Jan 11 17:02:25 2008 +0100
-@@ -77,6 +77,7 @@ int mh_opts_dup_ok[] = {
- 	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 @@ int mh_create_opt_mob_net_prefix(struct 
- 	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 @@ static int mh_try_pad(const struct iovec
- 		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 @@ static int mh_try_pad(const struct iovec
- 		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_brr(struct in6_addr *mn_add
- 
- 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 @@ void mh_send_ba(const struct in6_addr_bu
- 	}
- 	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 @@ int mh_bu_parse(struct ip6_mh_binding_up
- 			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 -r 82fcd4bea972 src/mh.h
---- a/src/mh.h	Fri Jan 11 16:55:08 2008 +0100
-+++ b/src/mh.h	Fri Jan 11 17:02:25 2008 +0100
-@@ -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_bu
- 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,
-@@ -78,6 +84,9 @@ struct list_head;
- 
- 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 -r 82fcd4bea972 src/mipv6.h
---- a/src/mipv6.h	Fri Jan 11 16:55:08 2008 +0100
-+++ b/src/mipv6.h	Fri Jan 11 17:02:25 2008 +0100
-@@ -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 -r 82fcd4bea972 src/mn.c
---- a/src/mn.c	Fri Jan 11 16:55:08 2008 +0100
-+++ b/src/mn.c	Fri Jan 11 17:02:25 2008 +0100
-@@ -35,6 +35,8 @@
- #include <errno.h>
- #include <time.h>
- #include <unistd.h> 
-+#include <sys/types.h>
-+#include <signal.h>
- 
- #include <netinet/icmp6.h>
- #include <netinet/ip6mh.h>
-@@ -94,10 +96,44 @@ const struct timespec min_valid_bu_lifet
- 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 @@ static int mn_block_rule_del(struct home
- 		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 @@ static int mn_block_rule_add(struct home
- 		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 @@ static void bule_invalidate(struct bulen
- 	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 @@ static void bule_invalidate(struct bulen
- 	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 @@ static void bule_invalidate(struct bulen
- 	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 @@ static void mn_recv_param_prob(const str
- 	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 @@ static int mn_send_bu_msg(struct bulentr
- 	}
- 	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 @@ static int mn_send_bu_msg(struct bulentr
- 	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 @@ static int mn_send_bu_msg(struct bulentr
- 	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 @@ static int mn_get_ro_lifetime(struct hom
- 	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 @@ static int mn_get_ro_lifetime(struct hom
- 	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 @@ static int mn_dereg(void *vbule, void *a
- 		}
- 		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 @@ static int bu_lft_check(struct bulentry 
- 	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 @@ static void bu_refresh(struct tq_elem *t
- 	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 @@ static void bu_refresh(struct tq_elem *t
- 
- 		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 @@ static int mv_hoa(struct ifaddrmsg *ifa,
- 	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 @@ undo:
- 	list_for_each(l, &hai->mob_net_prefixes) {
- 		struct prefix_list_entry *p;
- 		p = list_entry(l, struct prefix_list_entry, list);
--		route_del(ifindex, RT6_TABLE_MIP6, IP6_RT_PRIO_MIP6_FWD,
-+ 		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 @@ undo:
- 	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 bu
- 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 @@ static int process_first_home_bu(struct 
- 				 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 @@ static int process_first_home_bu(struct 
- 	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 @@ static void mn_send_home_bu(struct home_
- 	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 @@ static void mn_send_home_bu(struct home_
- 				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 @@ static void mn_send_home_bu(struct home_
- 			}
- 			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 @@ static void mn_send_home_bu(struct home_
- 			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 @@ static void mn_send_home_bu(struct home_
- 					    &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 @@ static int mn_chk_bauth(struct ip6_mh_bi
- 	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 @@ static void mn_recv_ba(const struct ip6_
- 	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 @@ static void mn_recv_ba(const struct ip6_
- 			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 @@ static void mn_recv_ba(const struct ip6_
- 			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 @@ static void mn_recv_ba(const struct ip6_
- 	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 @@ struct home_addr_info *mn_get_home_addr_
- 	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 @@ static int flag_hoa(struct ifaddrmsg *if
- 
- 	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 @@ static int flag_hoa(struct ifaddrmsg *if
- 	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 @@ static void nemo_mr_rules_del(struct hom
- 	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 @@ static int nemo_mr_rules_add(struct home
- 		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,17 +1949,25 @@ undo:
- 	list_for_each(l, &hinfo->mob_net_prefixes) {
- 		struct prefix_list_entry *p = NULL;
- 		p = list_entry(l, struct prefix_list_entry, list);
--		rule_del(NULL, RT6_TABLE_MIP6,
--			 IP6_RULE_PRIO_MIP6_FWD,  RTN_UNICAST,
--			 &p->ple_prefix, p->ple_plen, &in6addr_any, 0, 0);
-+		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;
- 	}
- 	return -1;
- }
-+
-+struct mcoa_tnl_id {
-+	struct list_head list;
-+	int tnl_id;
-+};
- 
- static void clean_home_addr_info(struct home_addr_info *hai)
- {
-@@ -1390,17 +1979,24 @@ static void clean_home_addr_info(struct 
- 		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 @@ static struct home_addr_info *hai_copy(s
- 				     &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 @@ static int conf_home_addr_info(struct ho
- 		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);
-+	/* 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, RTN_UNICAST,
--		     &hai->hoa.addr, 128, &in6addr_any, 0, FIB_RULE_FIND_SADDR) < 0) {
--		goto clean_err;
-+		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 @@ static int conf_home_addr_info(struct ho
- 			       PREFIX_LIFETIME_INFINITE,
- 			       PREFIX_LIFETIME_INFINITE);
- 
--	arg.target = hai;
--	arg.flag = 1;
-+	/* 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 (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 @@ int mn_update_home_prefix(struct home_ad
- 	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 @@ static int mn_get_ro_coa(const struct in
- 		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_de
- 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 @@ static int mn_ext_tunnel_ops(int request
- 	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 @@ undo:
- 
- 	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 @@ static int mn_move(struct home_addr_info
- 			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 @@ static int mn_do_dad(struct home_addr_in
- 	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 @@ static int mn_do_dad(struct home_addr_in
- 		   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 @@ static int mn_do_dad(struct home_addr_in
- 			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 inline void mn_update_coa_lifetim
- 
- 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 @@ static struct md_inet6_iface *mn_get_ifa
- 	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 @@ static struct md_coa *mn_get_coa(const s
- 	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 @@ static int mn_make_ho_verdict(const stru
- 	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 @@ static int mn_make_ho_verdict(const stru
- 			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 @@ static int mn_make_ho_verdict(const stru
- 
- 		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 @@ static int mn_make_ho_verdict(const stru
- 			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 @@ static int mn_make_ho_verdict(const stru
- 		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))
-@@ -2231,6 +3010,100 @@ static int mn_make_ho_verdict(const stru
- 	*next_rtr = md_get_first_router(&new_iface->default_rtr);
- 	*next_coa = coa;
- 	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,
-@@ -2244,35 +3117,36 @@ static void mn_chk_ho_verdict(struct hom
- 	    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 @@ int mn_movement_event(struct movement_ev
- 				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 @@ void mn_start_ro(struct in6_addr *cn, st
- 		     "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 @@ void mn_start_ro(struct in6_addr *cn, st
- 			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 @@ void mn_start_ro(struct in6_addr *cn, st
- 		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 @@ static void mn_recv_brr(const struct ip6
- 	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 @@ static void mn_recv_be(const struct ip6_
- 		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 -r 82fcd4bea972 src/mn.h
---- a/src/mn.h	Fri Jan 11 16:55:08 2008 +0100
-+++ b/src/mn.h	Fri Jan 11 17:02:25 2008 +0100
-@@ -52,6 +52,7 @@ struct ha_candidate_list {
- #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 @@ struct home_addr_info {
- 	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 @@ struct home_addr_info {
- 	int if_tunnel;
- 	int if_home;
- 	int if_block;
-+	int table; /* MCoA: routing table number where routes are stored */
- 	short hwalen;
- 	uint8_t altcoa;
- 	uint16_t mob_rtr;
-+	uint8_t reg_mcoa;
- 	char name[IF_NAMESIZE];
- 	int mnp_count;
- 	struct list_head mob_net_prefixes;
-diff -r 82fcd4bea972 src/movement.c
---- a/src/movement.c	Fri Jan 11 16:55:08 2008 +0100
-+++ b/src/movement.c	Fri Jan 11 17:02:25 2008 +0100
-@@ -165,7 +165,7 @@ static void md_prefix_rule_del(struct pr
- 	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);
- }
- 
-@@ -312,10 +312,10 @@ static void md_expire_router(struct md_i
- 
- 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;
- }
- 
-@@ -1290,7 +1290,7 @@ static void md_prefix_rule_add(struct pr
- 	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);
- }
- 
-@@ -1361,13 +1361,13 @@ static int md_block_rule_add(struct md_i
- 	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 -r 82fcd4bea972 src/mpdisc_ha.c
---- a/src/mpdisc_ha.c	Fri Jan 11 16:55:08 2008 +0100
-+++ b/src/mpdisc_ha.c	Fri Jan 11 17:02:25 2008 +0100
-@@ -68,7 +68,7 @@ static inline struct mpa_entry *mpa_get(
- 					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 @@ void mpd_cancel_mpa(const struct in6_add
- 	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 @@ int mpd_start_mpa(const struct in6_addr 
- 		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 -r 82fcd4bea972 src/mpdisc_mn.c
---- a/src/mpdisc_mn.c	Fri Jan 11 16:55:08 2008 +0100
-+++ b/src/mpdisc_mn.c	Fri Jan 11 17:02:25 2008 +0100
-@@ -65,7 +65,7 @@ static inline struct mps_entry *mps_get(
- 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 @@ void mpd_cancel_mps(const struct in6_add
- 	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 @@ int mpd_schedule_first_mps(const struct 
- 		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 -r 82fcd4bea972 src/ndisc.h
---- a/src/ndisc.h	Fri Jan 11 16:55:08 2008 +0100
-+++ b/src/ndisc.h	Fri Jan 11 17:02:25 2008 +0100
-@@ -21,6 +21,7 @@ static inline short nd_get_l2addr_len(un
- 		return 1;
- 		/* supported virtual devices */
- 	case ARPHRD_SIT:
-+		return 4;
- 	case ARPHRD_TUNNEL6:
- 	case ARPHRD_PPP:
- 	case ARPHRD_IPGRE:
-diff -r 82fcd4bea972 src/policy.c
---- a/src/policy.c	Fri Jan 11 16:55:08 2008 +0100
-+++ b/src/policy.c	Fri Jan 11 17:02:25 2008 +0100
-@@ -47,6 +47,25 @@ pthread_rwlock_t policy_lock;
- pthread_rwlock_t policy_lock;
- struct hash policy_bind_acl_hash;
- 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
-@@ -148,7 +167,7 @@ int default_discard_binding(const struct
- 		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 @@ int default_accept_inet6_iface(int iif)
- 		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 default_get_mnp_count(const struct i
- 	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 @@ int default_get_mnps(const struct in6_ad
- 	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 po
- 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 -r 82fcd4bea972 src/policy.h
---- a/src/policy.h	Fri Jan 11 16:55:08 2008 +0100
-+++ b/src/policy.h	Fri Jan 11 17:02:25 2008 +0100
-@@ -6,7 +6,13 @@
- #include <netinet/in.h>
- #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,9 +23,18 @@ struct policy_bind_acl_entry {
- 	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
-diff -r 82fcd4bea972 src/retrout.c
---- a/src/retrout.c	Fri Jan 11 16:55:08 2008 +0100
-+++ b/src/retrout.c	Fri Jan 11 17:02:25 2008 +0100
-@@ -151,7 +151,7 @@ static struct rrlentry *rre_create(int t
- 	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 @@ static struct rrlentry *rrl_get(int type
- 
- 	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 @@ static void rrl_delete(struct rrlentry *
- 	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 @@ int mn_rr_error_check(const struct in6_a
- 		      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 @@ static void mn_recv_cot(const struct ip6
- 		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)) {
-@@ -774,7 +778,11 @@ static void mn_recv_hot(const struct ip6
- 		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 -r 82fcd4bea972 src/rtnl.c
---- a/src/rtnl.c	Fri Jan 11 16:55:08 2008 +0100
-+++ b/src/rtnl.c	Fri Jan 11 17:02:25 2008 +0100
-@@ -299,7 +299,7 @@ int route_del(int oif, uint8_t table, ui
- }
- 
- 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 @@ static int rule_mod(const char *iface, i
- 		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 @@ static int rule_mod(const char *iface, i
-  * 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 @@ int rule_add(const char *iface, uint8_t 
-  * 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 -r 82fcd4bea972 src/rtnl.h
---- a/src/rtnl.h	Fri Jan 11 16:55:08 2008 +0100
-+++ b/src/rtnl.h	Fri Jan 11 17:02:25 2008 +0100
-@@ -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 @@ int route_del(int oif, uint8_t table, ui
- 	      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 -r 82fcd4bea972 src/scan.l
---- a/src/scan.l	Fri Jan 11 16:55:08 2008 +0100
-+++ b/src/scan.l	Fri Jan 11 17:02:25 2008 +0100
-@@ -137,7 +137,15 @@ MnDiscardHaParamProb		{ return MNDISCARD
- 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 -r 82fcd4bea972 src/tunnelctl.c
---- a/src/tunnelctl.c	Fri Jan 11 16:55:08 2008 +0100
-+++ b/src/tunnelctl.c	Fri Jan 11 17:02:25 2008 +0100
-@@ -157,7 +157,7 @@ static int __tunnel_del(struct mip6_tnl 
- 	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 @@ static struct mip6_tnl *__tunnel_add(str
- 		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 tunnel_add(struct in6_addr *local,
- 	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 @@ static int __tunnel_mod(struct mip6_tnl 
- 		     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 @@ int tunnel_mod(int ifindex,
- 	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 @@ static int tnl_cleanup(void *data, void 
- {
- 	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 -r 82fcd4bea972 src/vt.c
---- a/src/vt.c	Fri Jan 11 16:55:08 2008 +0100
-+++ b/src/vt.c	Fri Jan 11 17:02:25 2008 +0100
-@@ -428,6 +428,12 @@ static int bul_vt_dump(void *data, void 
- 		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)) {
-@@ -579,6 +585,11 @@ static int bcache_vt_dump(void *data, vo
- 
- 	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 -r 82fcd4bea972 src/xfrm.c
---- a/src/xfrm.c	Fri Jan 11 16:55:08 2008 +0100
-+++ b/src/xfrm.c	Fri Jan 11 17:02:25 2008 +0100
-@@ -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
-@@ -1555,7 +1555,7 @@ static int xfrm_bule_bce_update(const st
- 	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;
-@@ -1582,30 +1582,34 @@ int xfrm_add_bce(const struct in6_addr *
- 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)){
--		/* 
--		 * WORKAROUND 
--		 * In some cases, MN fail to add it because of the state
--		 * inserted by kernel when notifying aquire. So,update it.
--		 */
--		if (xfrm_state_add(&sel, IPPROTO_ROUTING, coa, 1, 0))
--			return -1;
--	}
--	set_selector(our_addr, peer_addr, 0, 0, 0, 0, &sel);
--	if (xfrm_state_add(&sel, IPPROTO_DSTOPTS, coa, replace, 0)){
--		/* 
--		 * WORKAROUND 
--		 * In some cases, MN fail to add it because of the state
--		 * inserted by kernel when notifying aquire. So,update it.
--		 */
--		if (xfrm_state_add(&sel, IPPROTO_DSTOPTS, coa, 1, 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)){
-+			/* 
-+			 * WORKAROUND 
-+			 * In some cases, MN fail to add it because of the state
-+			 * inserted by kernel when notifying aquire. So,update it.
-+			 */
-+			if (xfrm_state_add(&sel, IPPROTO_ROUTING, coa, 1, 0))
-+				return -1;
-+		}
-+	
-+		set_selector(our_addr, peer_addr, 0, 0, 0, 0, &sel);
-+		if (xfrm_state_add(&sel, IPPROTO_DSTOPTS, coa, replace, 0)){
-+			/* 
-+			 * WORKAROUND 
-+			 * In some cases, MN fail to add it because of the state
-+			 * inserted by kernel when notifying aquire. So,update it.
-+			 */
-+			if (xfrm_state_add(&sel, IPPROTO_DSTOPTS, coa, 1, 0))
-+				return -1;
-+		}
- 	}
- 	if (is_mn() && !xfrm_bule_bce_update(our_addr, peer_addr, replace))
- 		return 0;
-@@ -1614,7 +1618,8 @@ int xfrm_add_bce(const struct in6_addr *
- 				       _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;
- }
- 
-@@ -1643,7 +1648,7 @@ void xfrm_del_bce(const struct in6_addr 
- 		/* for MN-MN communications, checking BUL to insert RO policy */
- 		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, 0);
- 			}
-@@ -1736,7 +1741,7 @@ static int _xfrm_bce_reset(struct bulent
- 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;
-@@ -1754,21 +1759,34 @@ static int _xfrm_del_bule_data(struct bu
- 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);
-@@ -1779,20 +1797,25 @@ static int _xfrm_del_bule_data(struct bu
- 	/* 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;
- }
- 
-@@ -1817,7 +1840,14 @@ void xfrm_del_bule(struct bulentry *bule
- {
- 	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 */
-@@ -1829,14 +1859,26 @@ int xfrm_pre_bu_add_bule(struct bulentry
- 	int rdata = bule->xfrm_state & BUL_XFRM_STATE_DATA;
- 	int prio;
- 	int exist = 0;
-+	int bule_count = mcoa_bule_count(bule);
- 
- 	if (bule->flags & IP6_MH_BU_HOME) {
- 		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)
-@@ -1850,25 +1892,32 @@ int xfrm_pre_bu_add_bule(struct bulentry
- 			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 (bule_count == 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)) {
-@@ -1879,11 +1928,16 @@ int xfrm_pre_bu_add_bule(struct bulentry
- 			exist = 1;
- 		}
- 	}
--	if(!exist &&_mn_bule_ro_pol_add(bule, bule->home->if_tunnel, rdata))
-+	/* MCoA: Replaced bule->home->if_tunnel with bule->if_tunnel */
-+	if(!exist && bule_count == 1
-+	   && _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;
- 	}
-@@ -1902,15 +1956,20 @@ int xfrm_post_ba_mod_bule(struct bulentr
- 		struct home_addr_info *hai = bule->home;
- 		if (hai->home_block & HOME_LINK_BLOCK)
- 			xfrm_unblock_link(hai);
-+		if (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,
-@@ -1925,11 +1984,27 @@ int xfrm_post_ba_mod_bule(struct bulentr
- 	}
- 	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");
- 
-@@ -2126,6 +2201,31 @@ void xfrm_cleanup(void)
- 	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)
- {
-@@ -2141,6 +2241,21 @@ int xfrm_block_link(struct home_addr_inf
- 				       MIP6_PRIO_HOME_BLOCK, NULL, 0)))
- 		return ret;
- 	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)
-diff -r 82fcd4bea972 src/xfrm.h
---- a/src/xfrm.h	Fri Jan 11 16:55:08 2008 +0100
-+++ b/src/xfrm.h	Fri Jan 11 17:02:25 2008 +0100
-@@ -51,7 +51,8 @@ int xfrm_add_bce(const struct in6_addr *
- 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);
-@@ -82,7 +83,9 @@ int cn_wildrecv_bu_pol_add(void);
- 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);
diff --git a/openair3/NEMO_SHO/mipv6-daemon-umip-0.4-sho-20080331.patch b/openair3/NEMO_SHO/mipv6-daemon-umip-0.4-sho-20080331.patch
deleted file mode 100755
index 50da24d540ffec86ccb927c89868829aefc29466..0000000000000000000000000000000000000000
--- a/openair3/NEMO_SHO/mipv6-daemon-umip-0.4-sho-20080331.patch
+++ /dev/null
@@ -1,978 +0,0 @@
-diff -Nru mipv6-daemon-umip-0.4-nepl-mcoa/extras/mr_mcoa_sho_UMIP.conf mipv6-daemon-umip-0.4-nepl-mcoa-sho/extras/mr_mcoa_sho_UMIP.conf
---- mipv6-daemon-umip-0.4-nepl-mcoa/extras/mr_mcoa_sho_UMIP.conf	1970-01-01 01:00:00.000000000 +0100
-+++ mipv6-daemon-umip-0.4-nepl-mcoa-sho/extras/mr_mcoa_sho_UMIP.conf	2008-03-31 17:06:27.000000000 +0200
-@@ -0,0 +1,67 @@
-+# This is an example of mip6d Mobile Node configuration file
-+
-+NodeConfig MN;
-+
-+## If set to > 0, will not detach from tty
-+DebugLevel 10;
-+
-+## Support route optimization with other MNs
-+DoRouteOptimizationCN disabled;
-+
-+## Use route optimization with CNs
-+DoRouteOptimizationMN disabled;
-+
-+UseCnBuAck disabled;
-+
-+Interface "eth0" { 
-+	Bid 100;
-+	BidPriority 1;
-+	Reliable false;
-+	DefaultDelay 5000;
-+}
-+
-+Interface "eth1" { 
-+	Bid 200;
-+	BidPriority 1;
-+	Reliable true;
-+	DefaultDelay 0;
-+}
-+
-+MnRouterProbes 1;
-+
-+MnHomeLink "eth0" {
-+	IsMobRtr enabled;
-+	MnUseSHO enabled;
-+#	MnUseSHO disabled;  
-+	MnUseAdaptiveCombining enabled;
-+#	MnUseAdaptiveCombining disabled;
-+	HomeAgentAddress 2001:4::1;
-+	HomeAddress 2001:4::4/64 (2001:4:0:2::/64);
-+	RegMultipleCoA enabled;
-+	IfMultipleCoA "eth0", "eth1";
-+
-+	#		proto	type	code	route opt.
-+#	MnRoPolicy 	ICMP	129	0	enabled;
-+#	MnRoPolicy 	ICMP	any	any	disabled;
-+	#		proto	dst	src	route opt.
-+#	MnRoPolicy 	TCP	80	any	enabled; 
-+#	MnRoPolicy 	TCP	any	any	disabled; 
-+}
-+
-+##
-+## IPsec configuration
-+##
-+
-+UseMnHaIPsec disabled;
-+
-+## Key Management Mobility Capability
-+KeyMngMobCapability disabled;
-+
-+IPsecPolicySet {
-+	HomeAgentAddress 3ffe:2620:6:1::1;
-+	HomeAddress 3ffe:2620:6:1::1234/64;
-+
-+	IPsecPolicy HomeRegBinding UseESP;
-+	IPsecPolicy MobPfxDisc UseESP;
-+	IPsecPolicy TunnelMh UseESP;
-+}
-diff -Nru mipv6-daemon-umip-0.4-nepl-mcoa/include/netinet/ip6mh.h mipv6-daemon-umip-0.4-nepl-mcoa-sho/include/netinet/ip6mh.h
---- mipv6-daemon-umip-0.4-nepl-mcoa/include/netinet/ip6mh.h	2008-03-21 16:40:07.000000000 +0100
-+++ mipv6-daemon-umip-0.4-nepl-mcoa-sho/include/netinet/ip6mh.h	2008-03-20 17:02:41.000000000 +0100
-@@ -157,6 +157,25 @@
- 	uint8_t ip6mobid_reserved;
- } __attribute__((packed));
- 
-+/* NEMO-SHO */
-+struct ip6_mh_opt_fid {
-+	uint8_t ip6fid_type;
-+	uint8_t ip6fid_len;
-+	uint8_t ip6fid_flags_high;
-+	uint8_t ip6fid_flags_low;
-+	uint8_t ip6fid_fid;
-+	uint8_t ip6fid_action;
-+	uint8_t ip6fid_status;
-+	uint8_t ip6fid_pro_cls;
-+} __attribute__((packed));
-+
-+struct ip6_mh_opt_fid_subopt{
-+	uint8_t ip6fid_subopt_type;
-+	uint8_t ip6fid_subopt_len;
-+	uint8_t ip6fid_subopt_bid;
-+} __attribute__((packed));	
-+/* NEMO-SHO */
-+
- /* Binding Unique Identifier sub-option flags */
- #if BYTE_ORDER == BIG_ENDIAN
- #define IP6_OPT_BID_BULK		0x80  /*  Bulk Registration */
-@@ -187,6 +206,7 @@
- #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 */
-+#define IP6_MHOPT_FID		0x08	/* Flow Identification */
- 
- /*
-  *    Status values accompanied with Mobility Binding Acknowledgement
-diff -Nru mipv6-daemon-umip-0.4-nepl-mcoa/src/bul.c mipv6-daemon-umip-0.4-nepl-mcoa-sho/src/bul.c
---- mipv6-daemon-umip-0.4-nepl-mcoa/src/bul.c	2008-03-21 16:40:07.000000000 +0100
-+++ mipv6-daemon-umip-0.4-nepl-mcoa-sho/src/bul.c	2008-03-20 16:55:16.000000000 +0100
-@@ -71,6 +71,7 @@
- 		bule->rules = 0;
- 		bule->home_block = 0;
- 		bule->mcoa_dereg = 1;
-+		bule->fid        = 0; /* NEMO-SHO */
- 		INIT_LIST_HEAD(&bule->tqe.list);
- 		bule->seq = random();
- 	}
-diff -Nru mipv6-daemon-umip-0.4-nepl-mcoa/src/bul.h mipv6-daemon-umip-0.4-nepl-mcoa-sho/src/bul.h
---- mipv6-daemon-umip-0.4-nepl-mcoa/src/bul.h	2008-03-21 16:40:07.000000000 +0100
-+++ mipv6-daemon-umip-0.4-nepl-mcoa-sho/src/bul.h	2008-03-20 16:54:49.000000000 +0100
-@@ -43,6 +43,7 @@
- 	uint16_t seq;			/* sequence number of the latest BU */
- 	uint16_t flags;			/* BU send flags */
- 	uint16_t bid;			/* MCoA: Binding Identifier */
-+	uint8_t  fid;                   /* NEMO-SHO: Associated FID */
- 	struct in6_addr last_coa;	/* Last good coa */      
- 	struct timespec lastsent;
- 	struct timespec lifetime;      	/* lifetime sent in this BU */
-diff -Nru mipv6-daemon-umip-0.4-nepl-mcoa/src/cn.c mipv6-daemon-umip-0.4-nepl-mcoa-sho/src/cn.c
---- mipv6-daemon-umip-0.4-nepl-mcoa/src/cn.c	2008-03-21 16:40:07.000000000 +0100
-+++ mipv6-daemon-umip-0.4-nepl-mcoa-sho/src/cn.c	2008-03-20 17:12:02.000000000 +0100
-@@ -301,7 +301,7 @@
- 		status = IP6_MH_BAS_ACCEPTED;
- 	}
- 	if (bu_flags & IP6_MH_BU_ACK)
--		mh_send_ba(&out, status, 0, seqno, &lft, 0, 0, key, iif);
-+		mh_send_ba(&out, status, 0, seqno, &lft, 0, 0, NULL, key, iif); /* NEMO-SHO */
- 	return;
- send_nack:
- 	if (bce) {
-diff -Nru mipv6-daemon-umip-0.4-nepl-mcoa/src/conf.c mipv6-daemon-umip-0.4-nepl-mcoa-sho/src/conf.c
---- mipv6-daemon-umip-0.4-nepl-mcoa/src/conf.c	2008-03-21 16:40:07.000000000 +0100
-+++ mipv6-daemon-umip-0.4-nepl-mcoa-sho/src/conf.c	2008-03-21 15:29:32.000000000 +0100
-@@ -404,4 +404,27 @@
- 	}
- 	return priority;
- }
-+#if 1
-+// NEMO-SHO
-+/* 
-+ * get_bid_from_ifindex - return the bid from the interface index
-+ * @iif: the interface index
-+ */ 
-+uint16_t get_delay_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_delay;
-+			return 0;
-+		}
-+	}
-+
-+	return 0;
-+}
-+#endif
- 
-diff -Nru mipv6-daemon-umip-0.4-nepl-mcoa/src/conf.h mipv6-daemon-umip-0.4-nepl-mcoa-sho/src/conf.h
---- mipv6-daemon-umip-0.4-nepl-mcoa/src/conf.h	2008-03-21 16:40:07.000000000 +0100
-+++ mipv6-daemon-umip-0.4-nepl-mcoa-sho/src/conf.h	2008-03-21 15:27:52.000000000 +0100
-@@ -45,6 +45,8 @@
- 	char MnDiscardHaParamProb;
- 	char SendMobPfxSols;
- 	char OptimisticHandoff;
-+	char MnUseSHO;
-+	char UseAdaptiveCombining;
- 
- 	/* HA options */
- 	char HaAcceptMobRtr;
-@@ -70,6 +72,7 @@
- 	uint16_t mn_if_bid;
- 	uint8_t mn_if_bidprio;
- 	int mn_if_reliable;
-+	uint16_t mn_if_delay; /* NEMO-SHO option */
- };
- 
- extern struct mip6_config conf;
-@@ -127,6 +130,7 @@
- uint16_t get_bid_from_ifindex(int iif);
- uint8_t get_prio_from_bid(uint16_t bid);
- uint8_t get_highest_prio();
-+uint16_t get_delay_from_bid(uint16_t bid);
- 
- int yyparse(void);
- 
-diff -Nru mipv6-daemon-umip-0.4-nepl-mcoa/src/gram.y mipv6-daemon-umip-0.4-nepl-mcoa-sho/src/gram.y
---- mipv6-daemon-umip-0.4-nepl-mcoa/src/gram.y	2008-03-21 16:40:07.000000000 +0100
-+++ mipv6-daemon-umip-0.4-nepl-mcoa-sho/src/gram.y	2008-03-21 15:49:44.000000000 +0100
-@@ -54,7 +54,8 @@
- 	.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
-+	.mn_if_reliable = POL_MN_IF_DEF_RELIABLE,
-+	.mn_if_delay = POL_MN_IF_DEF_DELAY
- };
- 	
- struct home_addr_info hai = {
-@@ -196,8 +197,11 @@
- %token		BID
- %token		BIDPRIORITY
- %token		RELIABLE
-+%token          DEFAULTDELAY
- %token		REGMULTIPLECOA
- %token		IFMULTIPLECOA
-+%token		MNUSESHO
-+%token		MNUSEAPC
- 
- %token		INV_TOKEN
- 
-@@ -448,6 +452,20 @@
- 			}
- 			ni.mn_if_bidprio = $2;
- 		}
-+		| DEFAULTDELAY NUMBER ';'
-+		{
-+			if (ni.mn_if_preference) {
-+				uerror("You cannot set Default Delay if "
-+				       "MnIfPreference is set.");
-+				return -1;
-+			}		
-+			if ($2 < 0 || $2 > 65535) {
-+				uerror("DefDelay error "
-+				       "(%d <= BidPriority <= %d)",0, 65535);
-+				return -1;
-+			}
-+			ni.mn_if_delay = $2;
-+		}
- 		| RELIABLE BOOL ';'
- 		{
- 			ni.mn_if_reliable = $2;
-@@ -543,6 +561,14 @@
- 		{
- 			hai.reg_mcoa = $2;
- 		}
-+		| MNUSESHO BOOL ';'
-+		{
-+			conf.MnUseSHO = $2;
-+		}
-+		| MNUSEAPC BOOL ';'
-+		{
-+			conf.UseAdaptiveCombining = $2;
-+		}
- 		| IFMULTIPLECOA iflist ';'
- 		;
- 
-diff -Nru mipv6-daemon-umip-0.4-nepl-mcoa/src/ha.c mipv6-daemon-umip-0.4-nepl-mcoa-sho/src/ha.c
---- mipv6-daemon-umip-0.4-nepl-mcoa/src/ha.c	2008-03-21 16:40:07.000000000 +0100
-+++ mipv6-daemon-umip-0.4-nepl-mcoa-sho/src/ha.c	2008-03-21 16:27:40.000000000 +0100
-@@ -60,6 +60,17 @@
- #include "ndisc.h"
- #include "prefix.h"
- 
-+/* NEMO-SHO CONFIG */
-+#define NEMO_SHO_LTOH // Enable in case of low speed to high speed 
-+#ifdef NEMO_SHO_LTOH
-+const static int NEMO_SHO_DEFAULT_DELAY1 = 0;    // msec
-+const static int NEMO_SHO_DEFAULT_DELAY2 = 1000; // msec
-+#else
-+const static int NEMO_SHO_DEFAULT_DELAY1 = 0;    // msec
-+const static int NEMO_SHO_DEFAULT_DELAY2 = 0;    // msec
-+#endif
-+/* NEMO-SHO CONFIG*/
-+
- #define HA_DEBUG_LEVEL 1
- 
- #if HA_DEBUG_LEVEL >= 1
-@@ -1007,6 +1018,12 @@
- 	struct home_tnl_ops_parm p;
- 	struct ip6_mh_opt_bid *bid_opt;	
- 
-+	/* NEMO-SHO */
-+	struct ip6_mh_opt_fid *fid_opt;
-+	struct ip6_mh_opt_fid_subopt *fid_opt_subopt;
-+	struct bcentry *bce_associated = NULL;
-+	/* NEMO-SHO */
-+
- 	pthread_dbg("thread started");
- restart:	
- 	home_ifindex = 0;
-@@ -1035,6 +1052,10 @@
- 		out.bind_coa = NULL;
- 	out.local_coa = NULL;
- 	bid_opt = NULL;
-+	/* NEMO-SHO */
-+	fid_opt = NULL;
-+	fid_opt_subopt = NULL;
-+	/* NEMO-SHO */
- 
- 	/* MCoA
- 	 * We check if a BCE already exists for this HoA 
-@@ -1322,6 +1343,85 @@
- 		}
- 		bcache_update_expire(bce);
- 	}
-+	/* NEMO-SHO */
-+	/* check if there is FID option */
-+	fid_opt = mh_opt(&arg->bu->ip6mhbu_hdr, 
-+			 &arg->mh_opts, 
-+			 IP6_MHOPT_FID);
-+	/* check if there is BID sub-option */
-+	if (fid_opt && (fid_opt->ip6fid_len > (sizeof(struct ip6_mh_opt_fid) - 2))){
-+		fid_opt_subopt = (struct ip6_mh_opt_fid_subopt*)(fid_opt+1);
-+		if (fid_opt_subopt->ip6fid_subopt_type == 1)
-+			MDBG("FID: BID Reference sub-option\n");
-+		else {
-+			MDBG("FID: Unknown sub-option. FID is not processed\n");
-+			fid_opt_subopt = NULL;
-+		}
-+	}
-+	
-+	if (fid_opt){
-+		MDBG("FID option (FID=%d) action=%d, status=%d, pro=%d, cls=%d\n",
-+		     fid_opt->ip6fid_fid, fid_opt->ip6fid_action, fid_opt->ip6fid_status,
-+		     (fid_opt->ip6fid_pro_cls & 0xF0) >> 4,
-+		     fid_opt->ip6fid_pro_cls & 0x0F);
-+		uint8_t action = fid_opt->ip6fid_action;
-+		switch ( fid_opt->ip6fid_pro_cls & 0xF0){
-+		case FBIND_ADD_FLOW:
-+			MDBG("FID: ADD FLOW\n");
-+			if ( (action == FBIND_ACTION_NCAST) ||
-+			     (action == FBIND_ACTION_NCAST_COMBINE )||
-+			     (action == FBIND_ACTION_NCAST_COMBINE_ADAP) ){
-+				int nemo_sho_flag = SHO_BICAST;
-+				if (conf.debug_level > 0)
-+					nemo_sho_flag |= SHO_DEBUG;
-+				if (action == FBIND_ACTION_NCAST_COMBINE)
-+					nemo_sho_flag |= SHO_COMBINING;
-+				else if (action == FBIND_ACTION_NCAST_COMBINE_ADAP)
-+					nemo_sho_flag |= (SHO_COMBINING|SHO_ADAPTIVE);
-+
-+				assert(fid_opt_subopt);
-+				MDBG("FID: ACTION NCAST (SHO_FLAG=%x)\n", nemo_sho_flag);
-+				// look up another bcache assigned to bid
-+				bce_associated = bcache_get(out.src, out.dst, 
-+							    fid_opt_subopt->ip6fid_subopt_bid);
-+				if (bce_associated){
-+					if (dtunnel_mod_type(bce->tunnel,
-+							     out.src, 
-+							     out.bind_coa, 
-+							     &bce_associated->coa,
-+							     0, // dummy
-+							     nemo_sho_flag,
-+							     1, /* HA to MN/MR */
-+							     NEMO_SHO_DEFAULT_DELAY1,
-+							     NEMO_SHO_DEFAULT_DELAY2
-+							     )< 0 ){
-+					}
-+					bcache_release_entry(bce_associated);
-+				}
-+				else 
-+					MDBG("FID: no other binding cache entry\n");
-+			}
-+			else 
-+				MDBG("FID: Unsupported Action\n");
-+			break;
-+		case FBIND_REMOVE_FLOW:
-+			MDBG("FID: REMOVE FLOW\n");
-+			dtunnel_mod_type(bce->tunnel,
-+					 out.src, 
-+					 out.bind_coa, 
-+					 0,
-+					 0, // dummy
-+					 0, // stop bicasting/combining
-+					 1  /* HA to MN/MR */,
-+					 0,
-+					 0);
-+			break;
-+		default:
-+			break;
-+		}
-+	}
-+	/* NEMO-SHO */
-+
- 	/* bce is always valid here */
- 	bcache_release_entry(bce);
- 	if (!tsisset(lft))
-@@ -1356,7 +1456,7 @@
- 
- 	if (!(arg->flags & HA_BU_F_SKIP_BA))
- 		mh_send_ba(&out, status, ba_flags, seqno, &lft,
--			   bid, bid_priority, NULL, iif);
-+			   bid, bid_priority, fid_opt, NULL, iif); /* NEMO-SHO */
- 	/* 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);
-diff -Nru mipv6-daemon-umip-0.4-nepl-mcoa/src/mh.c mipv6-daemon-umip-0.4-nepl-mcoa-sho/src/mh.c
---- mipv6-daemon-umip-0.4-nepl-mcoa/src/mh.c	2008-03-21 16:40:07.000000000 +0100
-+++ mipv6-daemon-umip-0.4-nepl-mcoa-sho/src/mh.c	2008-03-20 17:11:24.000000000 +0100
-@@ -479,6 +479,62 @@
- 	return 0;
- }
- 
-+/* NEMO-SHO
-+ * mh_create_opt_fid - Create a Flow Identifier Option
-+ * TODO1: (TBA)
-+ */
-+int mh_create_opt_fid(struct iovec *iov, 
-+		      uint8_t fid, uint8_t action, uint8_t status,
-+		      uint8_t priority,
-+		      uint8_t pro,
-+		      int fid_subopt,
-+		      uint8_t bid)
-+{
-+	int optlen = sizeof(struct ip6_mh_opt_fid) + 
-+		(fid_subopt?sizeof(struct ip6_mh_opt_fid_subopt):0);
-+	struct ip6_mh_opt_fid *opt_fid;
-+	struct ip6_mh_opt_fid_subopt *opt_fid_subopt;
-+	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_fid = (struct ip6_mh_opt_fid *)data;
-+
-+#define IP6_OPT_FID_R 0x80
-+#define IP6_OPT_FID_H 0x40
-+
-+	opt_fid->ip6fid_type = IP6_MHOPT_FID;
-+	opt_fid->ip6fid_len = fid_subopt?9:6; // NEMO-SHO TODO: hard-coded
-+	opt_fid->ip6fid_flags_high = 0;
-+	opt_fid->ip6fid_flags_low = IP6_OPT_FID_H|priority; // TODO: priority should be masked
-+	opt_fid->ip6fid_fid = fid;
-+	opt_fid->ip6fid_action = action;
-+	opt_fid->ip6fid_status = status;
-+	opt_fid->ip6fid_pro_cls = (pro << 4) | 0x00;
-+	data += sizeof(struct ip6_mh_opt_fid);
-+
-+	if (fid_subopt){
-+		opt_fid_subopt = (struct ip6_mh_opt_fid_subopt *)data;
-+		opt_fid_subopt->ip6fid_subopt_type = 1;
-+		opt_fid_subopt->ip6fid_subopt_len  = 3;
-+		opt_fid_subopt->ip6fid_subopt_bid  = bid;
-+		data += sizeof(struct ip6_mh_opt_fid_subopt);
-+	}
-+
-+	MDBG("FID sub-option created with FID = %d and action %d\n", 
-+		fid, action);
-+	
-+	return 0;
-+}
-+/* NEMO-SHO */
-+
- static size_t mh_length(struct iovec *vec, int count)
- {
- 	size_t len = 0;
-@@ -526,6 +582,11 @@
- 		case IP6_MHOPT_BID:
- 			pad = optpad(2, 0, len); /* 2n */
- 			break;
-+			/* NEMO-SHO */
-+		case IP6_MHOPT_FID:
-+			pad = optpad(2, 0, len); /* 2n */
-+			break;
-+			/* NEMO-SHO */
- 		}
- 		if (pad > 0) {
- 			create_opt_pad(&out[n++], pad);
-@@ -1027,6 +1088,7 @@
- 		const struct timespec *lifetime, 
- 		const uint16_t bid,
- 		const uint8_t priority,
-+		const struct ip6_mh_opt_fid *opt_fid, /* NEMO-SHO */
- 		const uint8_t *key, int iif)
- {
- 	int iovlen = 1;
-@@ -1058,6 +1120,18 @@
- 	/* MCoA: Create Binding Unique Identifier Option if needed */
- 	if (bid) 
- 		mh_create_opt_bid(&mh_vec[iovlen++], bid, priority, 0);
-+
-+	/* NEMO-SHO: FID option if needed & BA is accepted */
-+	if (opt_fid && (status == IP6_MH_BAS_ACCEPTED))
-+		mh_create_opt_fid(&mh_vec[iovlen++],
-+				  opt_fid->ip6fid_fid, //fid
-+				  opt_fid->ip6fid_action,  //action (n-casting)
-+				  0,  //status
-+				  0,  //priority
-+				  opt_fid->ip6fid_pro_cls,  //process
-+				  0,0);  //subopt is not present
-+	/* NEMO-SHO */
-+
- 	mh_send(addrs, mh_vec, iovlen, key, iif);
- 	free_iov_data(mh_vec, iovlen);
- }
-diff -Nru mipv6-daemon-umip-0.4-nepl-mcoa/src/mh.h mipv6-daemon-umip-0.4-nepl-mcoa-sho/src/mh.h
---- mipv6-daemon-umip-0.4-nepl-mcoa/src/mh.h	2008-03-21 16:40:07.000000000 +0100
-+++ mipv6-daemon-umip-0.4-nepl-mcoa-sho/src/mh.h	2008-03-21 16:27:24.000000000 +0100
-@@ -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_BID
-+#define IP6_MHOPT_MAX	IP6_MHOPT_FID /* NEMO-SHO */
- 
- struct in6_addr_bundle {
- 	struct in6_addr *src;
-@@ -45,6 +45,7 @@
- 		const struct timespec *lifetime,
- 		const uint16_t bid,
- 		const uint8_t priority,
-+		const struct ip6_mh_opt_fid *opt_fid, /* NEMO-SHO */
- 		const uint8_t *key, int iif);
- 
- static inline void mh_send_ba_err(const struct in6_addr_bundle *addrs,
-@@ -56,7 +57,7 @@
- {
- 	struct timespec zero = { 0, 0 };
- 	mh_send_ba(addrs, status, flags, seqno, &zero, 
--		   bid, priority, key, iif);
-+		   bid, priority, NULL, key, iif); /* NEMO-SHO */
- }
- 
- void mh_send_be(struct in6_addr *dst,
-@@ -87,6 +88,14 @@
- 
- int mh_create_opt_bid(struct iovec *iov, uint16_t bid, uint8_t priority, 
- 		      uint8_t bid_flags);
-+/* NEMO-SHO */
-+int mh_create_opt_fid(struct iovec *iov, 
-+		      uint8_t fid, uint8_t action, uint8_t status,
-+		      uint8_t priority,
-+		      uint8_t pro,
-+		      int fid_subopt,
-+		      uint8_t bid);
-+/* NEMO-SHO */
- 
- static inline void *mh_opt(const struct ip6_mh *mh,
- 			   const struct mh_options *mh_opts, uint8_t type)
-@@ -138,4 +147,13 @@
- void mh_handler_reg(uint8_t type, struct mh_handler *handler);
- void mh_handler_dereg(uint8_t type, struct mh_handler *handler);
- 
-+/* NEMO-SHO FlowBinding */
-+#define FBIND_ADD_FLOW    0x00
-+#define FBIND_REMOVE_FLOW 0xF0
-+#define FBIND_ACTION_NCAST              0x03
-+#define FBIND_ACTION_NCAST_COMBINE      0x04
-+#define FBIND_ACTION_NCAST_COMBINE_ADAP 0x05
-+#define FBIND_FID_SHO 0x08
-+/* NEMO-SHO */
-+
- #endif
-diff -Nru mipv6-daemon-umip-0.4-nepl-mcoa/src/mn.c mipv6-daemon-umip-0.4-nepl-mcoa-sho/src/mn.c
---- mipv6-daemon-umip-0.4-nepl-mcoa/src/mn.c	2008-03-21 16:40:07.000000000 +0100
-+++ mipv6-daemon-umip-0.4-nepl-mcoa-sho/src/mn.c	2008-03-31 16:15:06.000000000 +0200
-@@ -67,6 +67,14 @@
- #include "dhaad_mn.h"
- #include "ipsec.h"
- 
-+/* NEMO-SHO CONFIG */
-+uint16_t mcoa_get_previous_bid(struct home_addr_info *hai);
-+enum {
-+	TYPE_HO_DOWNWARD,
-+	TYPE_HO_UPWARD
-+};
-+/* NEMO-SHO CONFIG*/
-+
- #define MN_DEBUG_LEVEL 1
- 
- #if MN_DEBUG_LEVEL >= 1
-@@ -396,6 +404,49 @@
- 			free_iov_data(iov, iov_ind);
- 			return -ENOMEM;				
- 		}
-+		/* NEMO-SHO */
-+		if (hai->reg_mcoa && bule->bid && bule->fid){
-+			uint16_t prev_bid = 
-+				mcoa_get_previous_bid(hai); 
-+			uint8_t action;
-+			if (conf.MnUseSHO){
-+				if (conf.UseAdaptiveCombining)
-+					action = FBIND_ACTION_NCAST_COMBINE_ADAP;
-+				else
-+					action = FBIND_ACTION_NCAST_COMBINE;
-+			}
-+			else
-+				action = FBIND_ACTION_NCAST;
-+			// Start N-casting
-+			if ( bu->ip6mhbu_lifetime &&
-+			     mh_create_opt_fid(&iov[iov_ind++],
-+					       bule->fid, //fid
-+					       action,
-+					       0, //status
-+					       0, //priority
-+					       FBIND_ADD_FLOW, //process (adding)
-+					       1, //subopt is present
-+					       prev_bid //bid
-+				     ) < 0 ){
-+				free_iov_data(iov, iov_ind);
-+				return -ENOMEM; 
-+			}
-+			// Stop N-casting
-+			else if (!bule->mcoa_dereg &&
-+				 mh_create_opt_fid(&iov[iov_ind++],
-+						   bule->fid, //fid
-+						   action,
-+						   0,  //status
-+						   0,  //priority
-+						   0xF,//process (removing)
-+						   0,  //subopt is not present
-+						   0   //bid
-+					 ) < 0){
-+				free_iov_data(iov, iov_ind);
-+				return -ENOMEM; 
-+			}
-+		}
-+		/* NEMO-SHO */
- 		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++],
-@@ -452,6 +503,27 @@
- 	
- 	return ret;
- }
-+/* NEMO-SHO */
-+uint16_t mcoa_get_previous_bid(struct home_addr_info *hai)
-+{
-+	struct list_head *l;
-+	int iif = hai->current_coa->iif;
-+
-+	if(!hai->reg_mcoa){
-+		MDBG("================================= reg_mcoa is 0\n");
-+		return 0;
-+	}
-+	
-+	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 get_bid_from_ifindex(coa_entry->iif);
-+	}
-+	MDBG("================================= cannot find entry\n");
-+	return 0;
-+}
-+/* NEMO-SHO */
- 
- struct mn_addr *mcoa_get_current_coa(struct home_addr_info *hai, int iif)
- {
-@@ -1121,6 +1193,24 @@
- 	}
- 	if (!homereg_expired) {
- 		bule->do_send_bu = 1;
-+		/* NEMO-SHO */
-+		if (conf.MnUseSHO){
-+			struct bulentry *bul_prev = NULL;
-+			uint16_t prev_bid = 
-+				mcoa_get_previous_bid(hai); 
-+			if (prev_bid)
-+				bul_prev = bul_get(hai, NULL, 
-+						   &hai->ha_addr,
-+						   prev_bid);
-+			
-+			if (hai->reg_mcoa && bul_prev) {
-+				MDBG("=====previous_bid %d=====\n", prev_bid);
-+				bule->fid = FBIND_FID_SHO;
-+			}
-+			else 
-+				bule->fid = 0;
-+		}
-+		/* NEMO-SHO */
- 		mn_send_bu_msg(bule);
- 		bul_update_timer(bule);		
- 		if (conf.OptimisticHandoff)
-@@ -1145,6 +1235,44 @@
- 	bule->if_tunnel = tunnel_mod(bule->if_tunnel, &hai->current_coa->addr, 
- 				     &hai->ha_addr, hai->current_coa->iif, 
- 				     mn_ext_tunnel_ops, hai);
-+	/* NEMO-SHO */
-+	if (bule->fid){
-+		int HOtype;
-+		// only Packet Combining is enabled for this moement
-+		int nemo_sho_flag = SHO_COMBINING;
-+		if (conf.UseAdaptiveCombining)
-+			nemo_sho_flag |=SHO_ADAPTIVE;
-+		if (conf.debug_level > 0)
-+			nemo_sho_flag |=SHO_DEBUG;
-+
-+		uint16_t prev_bid = 
-+			mcoa_get_previous_bid(hai); 
-+		struct bulentry *bul_prev = bul_get(hai, NULL, &hai->ha_addr,
-+						    prev_bid);
-+		// share the same fid with another bul
-+		bul_prev->fid = bule->fid;
-+
-+		if (get_delay_from_bid(prev_bid) > 
-+		    get_delay_from_bid(bule->bid) )
-+			HOtype = TYPE_HO_DOWNWARD;
-+		else 
-+			HOtype = TYPE_HO_UPWARD;
-+
-+		dtunnel_mod_type(bule->if_tunnel, 
-+				 &bule->coa,
-+				 &bule->peer_addr,
-+				 &bul_prev->coa,
-+				 bule->if_coa,
-+				 nemo_sho_flag,
-+				 0,
-+				 (HOtype==TYPE_HO_DOWNWARD)?
-+				 get_delay_from_bid(bule->bid):0,
-+				 (HOtype==TYPE_HO_DOWNWARD)?
-+				 get_delay_from_bid(prev_bid):0
-+				 ); /* from MR to HA */
-+	}
-+	/* NEMO-SHO */
-+
- 	hai->if_tunnel = bule->if_tunnel;		
- 	bule->last_coa = bule->coa;
- 	bule->coa_changed = 0;
-@@ -1351,6 +1479,9 @@
- {
- 	struct ip6_mh_binding_ack *ba;
- 	struct ip6_mh_opt_bid *bui;
-+	// NEMO-SHO
-+	struct ip6_mh_opt_fid *fid_opt = NULL;
-+	// NEMO-SHO
- 	struct mh_options mh_opts;
- 	struct bulentry *bule;
- 	struct timespec now, ba_lifetime, br_adv;
-@@ -1370,6 +1501,7 @@
- 	/* 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;
-+	fid_opt = mh_opt(&ba->ip6mhba_hdr, &mh_opts, IP6_MHOPT_FID);
- 	
- 	bule = bul_get(NULL, in->dst, in->src, bid);
- 	if (!bule || bule->type != BUL_ENTRY) {
-@@ -1383,6 +1515,26 @@
- 		     NIP6ADDR(in->local_coa != NULL ? 
- 			      in->local_coa : &in6addr_any),
- 		     bid);
-+		if (fid_opt){
-+			struct home_addr_info *hai = mn_get_home_addr(in->dst);
-+			if (hai){
-+				MDBG("FID option (FID=%d) is attached. releasing Bicasting/Combining info\n", fid_opt->ip6fid_fid);
-+				bule = bul_get(hai, NULL, in->src, 
-+						get_bid_from_ifindex(iif));
-+				if (bule->fid == fid_opt->ip6fid_fid){
-+					dtunnel_mod_type(bule->if_tunnel, 
-+							 &bule->coa,
-+							 &bule->peer_addr,
-+							 0,
-+							 0,
-+							 0,
-+							 0,
-+							 0,
-+							 0); /* from MR to HA */
-+				}
-+			}
-+			hai = NULL;
-+		}
- 		pthread_rwlock_unlock(&mn_lock);
- 		return;
- 	}
-@@ -1554,6 +1706,44 @@
- 		dbg("Deleting bul entry\n");
- 		bul_delete(bule);
- 	}  else {
-+		/* NEMO-SHO */
-+		if (bule->fid){
-+			int nemo_sho_flag = SHO_BICAST|SHO_COMBINING;
-+			dbg("DTUNNEL from %x:%x:%x:%x:%x:%x:%x:%x "
-+			    "with coa %x:%x:%x:%x:%x:%x:%x:%x\n",
-+			    NIP6ADDR(in->src), NIP6ADDR(in->local_coa));
-+
-+			if (conf.UseAdaptiveCombining)
-+				nemo_sho_flag |=SHO_ADAPTIVE;
-+			if (conf.debug_level > 0)
-+				nemo_sho_flag |=SHO_DEBUG;
-+
-+			struct home_addr_info *hai = bule->home;
-+			uint16_t prev_bid = 
-+				mcoa_get_previous_bid(hai); 
-+			struct bulentry *bul_prev = bul_get(hai, NULL, 
-+							    &hai->ha_addr,
-+							    prev_bid);
-+			int HOtype;
-+			if (get_delay_from_bid(prev_bid) > 
-+			    get_delay_from_bid(bule->bid) )
-+				HOtype = TYPE_HO_DOWNWARD;
-+			else 
-+				HOtype = TYPE_HO_UPWARD;
-+			dtunnel_mod_type(bule->if_tunnel, 
-+					 &bule->coa,
-+					 &bule->peer_addr,
-+					 &bul_prev->coa,
-+					 bule->if_coa,
-+					 nemo_sho_flag,
-+					 0,
-+					 (HOtype==TYPE_HO_DOWNWARD)?
-+					 get_delay_from_bid(bule->bid):0,
-+					 (HOtype==TYPE_HO_DOWNWARD)?
-+					 get_delay_from_bid(prev_bid):0
-+				); /* from MR to HA */
-+		}
-+		/* NEMO-SHO */
- 		set_bule_lifetime(bule, &ba_lifetime, &br_adv);
- 		if (bule->flags & IP6_MH_BU_HOME) {
- 			dbg("Callback to bu_refresh after %d seconds\n",
-diff -Nru mipv6-daemon-umip-0.4-nepl-mcoa/src/movement.c mipv6-daemon-umip-0.4-nepl-mcoa-sho/src/movement.c
---- mipv6-daemon-umip-0.4-nepl-mcoa/src/movement.c	2008-03-21 16:40:07.000000000 +0100
-+++ mipv6-daemon-umip-0.4-nepl-mcoa-sho/src/movement.c	2008-03-31 14:43:09.000000000 +0200
-@@ -48,7 +48,7 @@
- #include "prefix.h"
- #include "conf.h"
- 
--#define MD_DEBUG_LEVEL 1
-+#define MD_DEBUG_LEVEL 0
- 
- #if MD_DEBUG_LEVEL >= 1
- #define MDBG dbg
-@@ -1411,10 +1411,13 @@
- 	if (old)
- 		md_expire_router(iface, old, new);
- 
-+	//NEMO-SHO avoid blocking outbound traffic here
-+#if 0
- 	if (list_empty(&iface->coas) &&
- 	    !(iface->iface_flags & MD_BLOCK_TRAFFIC)) {
- 		md_block_rule_add(iface);
- 	}
-+#endif
- 	new->used = 1;
- 	md_add_default_router(iface, new);
- 	__md_new_link(iface, link_changed);
-diff -Nru mipv6-daemon-umip-0.4-nepl-mcoa/src/policy.h mipv6-daemon-umip-0.4-nepl-mcoa-sho/src/policy.h
---- mipv6-daemon-umip-0.4-nepl-mcoa/src/policy.h	2008-03-21 16:40:07.000000000 +0100
-+++ mipv6-daemon-umip-0.4-nepl-mcoa-sho/src/policy.h	2008-03-21 15:43:20.000000000 +0100
-@@ -13,6 +13,7 @@
- #define POL_MN_IF_DEF_BID 0
- #define POL_MN_IF_DEF_BID_PRIORITY 0
- #define POL_MN_IF_DEF_RELIABLE 1
-+#define POL_MN_IF_DEF_DELAY 0
- 
- struct ip6_mh_binding_update;
- struct nd_router_advert;
-diff -Nru mipv6-daemon-umip-0.4-nepl-mcoa/src/scan.l mipv6-daemon-umip-0.4-nepl-mcoa-sho/src/scan.l
---- mipv6-daemon-umip-0.4-nepl-mcoa/src/scan.l	2008-03-21 16:40:07.000000000 +0100
-+++ mipv6-daemon-umip-0.4-nepl-mcoa-sho/src/scan.l	2008-03-21 15:34:55.000000000 +0100
-@@ -139,11 +139,14 @@
- HaAcceptMobRtr   		{ return HAACCEPTMOBRTR; }
- HaAcceptMCoAReg			{ return HAACCEPTMCOAREG; }
- MCoAReg				{ return MCOAREG; }
-+MnUseSHO			{ return MNUSESHO; }
-+MnUseAdaptiveCombining		{ return MNUSEAPC; }
- NoMCoAReg			{ return NOMCOAREG; }
- IsMobRtr       			{ return ISMOBRTR; }
- Bid				{ return BID; }
- BidPriority			{ return BIDPRIORITY; }
- Reliable			{ return RELIABLE; }
-+DefaultDelay			{ return DEFAULTDELAY; }
- RegMultipleCoA			{ return REGMULTIPLECOA; }
- IfMultipleCoA			{ return IFMULTIPLECOA; }
- HaServedPrefix       	       	{ return HASERVEDPREFIX; }
-diff -Nru mipv6-daemon-umip-0.4-nepl-mcoa/src/tunnelctl.c mipv6-daemon-umip-0.4-nepl-mcoa-sho/src/tunnelctl.c
---- mipv6-daemon-umip-0.4-nepl-mcoa/src/tunnelctl.c	2008-03-21 16:40:07.000000000 +0100
-+++ mipv6-daemon-umip-0.4-nepl-mcoa-sho/src/tunnelctl.c	2008-03-20 16:51:35.000000000 +0100
-@@ -315,6 +315,73 @@
- 	return res;
- }
- 
-+// ---------------- rueegg -------------------------
-+int dtunnel_mod_type(int ifindex,
-+		     struct in6_addr *local,
-+		     struct in6_addr *remote,
-+		     struct in6_addr *addr2,
-+		     int link,
-+		     int do_bicasting,
-+		     int tnl_type,
-+		     unsigned short defaultDeltaT1,
-+		     unsigned short defaultDeltaT2)
-+{
-+	struct mip6_tnl *tnl;
-+	struct ip6_tnl_parm parm;
-+	struct ifreq ifr;
-+		
-+	int res = -1;
-+
-+	pthread_mutex_lock(&tnl_lock);
-+
-+	TDBG("modifying mode of tunnel %d end points with "
-+	     "from %x:%x:%x:%x:%x:%x:%x:%x "
-+	     "to %x:%x:%x:%x:%x:%x:%x:%x\n",
-+	     ifindex, NIP6ADDR(local), NIP6ADDR(remote));
-+
-+	tnl = get_tnl(ifindex);
-+	assert(tnl != NULL);
-+
-+	if (tnl->users == 1){
-+		memset(&parm, 0, sizeof(struct ip6_tnl_parm));
-+		parm.proto = IPPROTO_IPV6;
-+		parm.flags = IP6_TNL_F_MIP6_DEV|IP6_TNL_F_IGN_ENCAP_LIMIT;
-+		parm.hop_limit = 64;
-+		parm.laddr = *local;
-+		parm.raddr = *remote;
-+		parm.link  = link;
-+		parm.dparms.dtnl_flag = do_bicasting;  //rueegg
-+		if (do_bicasting) {
-+			parm.dparms.dtnl_type = tnl_type; //rueegg
-+			parm.dparms.addr2 = *addr2; //rueegg
-+		}
-+		parm.dparms.defaultDeltaT[0]=defaultDeltaT1;
-+		parm.dparms.defaultDeltaT[1]=defaultDeltaT2;
-+		
-+		strcpy(ifr.ifr_name, tnl->parm.name);
-+		ifr.ifr_ifru.ifru_data = (void *)&parm;
-+		
-+		if(ioctl(tnl_fd, SIOCCHGTUNNEL, &ifr) < 0) {
-+			TDBG("SIOCCHGTUNNEL failed status %d %s\n", 
-+			     errno, strerror(errno));
-+			pthread_mutex_unlock(&tnl_lock);
-+			return -1;
-+		}
-+		memcpy(&tnl->parm, &parm, sizeof(struct ip6_tnl_parm));
-+		TDBG("modified tunnel iface %s (%d)"
-+		     "from %x:%x:%x:%x:%x:%x:%x:%x "
-+		     "to %x:%x:%x:%x:%x:%x:%x:%x\n",
-+		     tnl->parm.name, tnl->ifindex, NIP6ADDR(&tnl->parm.laddr),
-+		     NIP6ADDR(&tnl->parm.raddr));
-+		res = tnl->ifindex;
-+	}
-+		
-+	pthread_mutex_unlock(&tnl_lock);
-+	return res;
-+}
-+
-+// ---------- rueegg end -------------------
-+
- static int __tunnel_mod(struct mip6_tnl *tnl,
- 			struct in6_addr *local,
- 			struct in6_addr *remote,
-diff -Nru mipv6-daemon-umip-0.4-nepl-mcoa/src/tunnelctl.h mipv6-daemon-umip-0.4-nepl-mcoa-sho/src/tunnelctl.h
---- mipv6-daemon-umip-0.4-nepl-mcoa/src/tunnelctl.h	2007-09-13 11:42:42.000000000 +0200
-+++ mipv6-daemon-umip-0.4-nepl-mcoa-sho/src/tunnelctl.h	2008-03-20 16:51:13.000000000 +0100
-@@ -28,6 +28,21 @@
- 				     void *data),
- 	       void *data);
- 
-+/* NEMO-SHO by hirokazu */ 
-+#define SHO_BICAST    0x1
-+#define SHO_COMBINING 0x2
-+#define SHO_ADAPTIVE  0x4
-+#define SHO_DEBUG     0x8
-+int dtunnel_mod_type(int ifindex,
-+		     struct in6_addr *local,
-+		     struct in6_addr *remote, 
-+		     struct in6_addr *addr2, 
-+		     int link,
-+		     int do_bicasting,
-+		     int tnl_type,
-+		     unsigned short defaultDeltaT1,
-+		     unsigned short defaultDeltaT2);
-+/* NEMO-SHO by hirokazu */
- 
- int tunnelctl_init(void);
- 
diff --git a/openair3/NEMO_SHO/mipv6-daemon-umip-0.4.tar.gz b/openair3/NEMO_SHO/mipv6-daemon-umip-0.4.tar.gz
deleted file mode 100755
index 940362a1b530c14ae9105ecac74edb387ab8c724..0000000000000000000000000000000000000000
Binary files a/openair3/NEMO_SHO/mipv6-daemon-umip-0.4.tar.gz and /dev/null differ