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