3 # Patch managed by http://www.holgerschurig.de/patcher.html
6 --- linux-2.4.27/Documentation/Configure.help~mipv6-1.1-v2.4.26
7 +++ linux-2.4.27/Documentation/Configure.help
10 It is safe to say N here for now.
12 +IPv6: IPv6 over IPv6 Tunneling (EXPERIMENTAL)
14 + Experimental IP6-IP6 tunneling. You must select this, if you want
15 + to use CONFIG_IPV6_MOBILITY. More information in MIPL Mobile IPv6
18 + If you don't want IP6-IP6 tunnels and Mobile IPv6, say N.
20 +IPv6: Mobility Support (EXPERIMENTAL)
22 + This is experimental support for the upcoming specification of
23 + Mobile IPv6. Mobile IPv6 allows nodes to seamlessly move between
24 + networks without changing their IP addresses, thus allowing them to
25 + maintain upper layer connections (e.g. TCP). Selecting this option
26 + allows your computer to act as a Correspondent Node (CN). A MIPv6
27 + Mobile Node will be able to communicate with the CN and use route
30 + For more information and configuration details, see
31 + http://www.mipl.mediapoli.com/.
35 +MIPv6: Mobile Node Support
36 +CONFIG_IPV6_MOBILITY_MN
37 + If you want your computer to be a MIPv6 Mobile Node (MN), select
38 + this option. You must configure MN using the userspace tools
39 + available at http://www.mipl.mediapoli.com/download/mipv6-tools/.
41 + If your computer is stationary, or you are unsure if you need this,
42 + say N. Note that you will need a properly configured MIPv6 Home
43 + Agent to use any Mobile Nodes.
45 +MIPv6: Home Agent Support
46 +CONFIG_IPV6_MOBILITY_HA
47 + If you want your router to serve as a MIPv6 Home Agent (HA), select
48 + this option. You must configure HA using the userspace tools
49 + available at http://www.mipl.mediapoli.com/download/mipv6-tools/.
51 + If your computer is not a router, or you are unsure if you need
54 +MIPv6: Debug messages
55 +CONFIG_IPV6_MOBILITY_DEBUG
56 + MIPL Mobile IPv6 can produce a lot of debugging messages. There are
57 + eight debug levels (0 through 7) and the level is controlled via
58 + /proc/sys/net/ipv6/mobility/debuglevel. Since MIPL is still
59 + experimental, you might want to say Y here.
61 + Be sure to say Y and record debug messages when submitting a bug
63 The SCTP Protocol (EXPERIMENTAL)
65 Stream Control Transmission Protocol
66 --- linux-2.4.27/Documentation/DocBook/Makefile~mipv6-1.1-v2.4.26
67 +++ linux-2.4.27/Documentation/DocBook/Makefile
69 kernel-api.sgml parportbook.sgml kernel-hacking.sgml \
70 kernel-locking.sgml via-audio.sgml mousedrivers.sgml sis900.sgml \
71 deviceiobook.sgml procfs-guide.sgml tulip-user.sgml \
72 - journal-api.sgml libata.sgml
73 + journal-api.sgml libata.sgml mip6-func.sgml
75 PS := $(patsubst %.sgml, %.ps, $(BOOKS))
76 PDF := $(patsubst %.sgml, %.pdf, $(BOOKS))
78 procfs-guide.sgml: procfs-guide.tmpl procfs_example.sgml
79 $(TOPDIR)/scripts/docgen < procfs-guide.tmpl >$@
81 +mip6-func.sgml: mip6-func.tmpl
82 + $(TOPDIR)/scripts/docgen <$< >$@
84 APISOURCES := $(TOPDIR)/drivers/media/video/videodev.c \
85 $(TOPDIR)/arch/i386/kernel/irq.c \
86 $(TOPDIR)/arch/i386/kernel/mca.c \
88 +++ linux-2.4.27/Documentation/DocBook/mip6-func.tmpl
90 +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
91 +<book id="LinuxMobileIPv6">
93 + <title>MIPL Mobile IPv6 Function Reference Guide</title>
97 + <othername>MIPL Mobile IPv6 for Linux Team</othername>
99 + <orgname>Helsinki University of Technology</orgname>
100 + <orgdiv>Telecommunications Software and Multimedia Lab</orgdiv>
102 + <pob>PO BOX 9201</pob>
103 + <postcode>FIN-02015 HUT</postcode>
104 + <country>Finland</country>
105 + <email>mipl@list.mipl.mediapoli.com</email>
112 + <year>2000-2001</year>
113 + <holder>Helsinki University of Technology</holder>
118 + Copyright (c) 2001, 2002 MIPL Mobile IPv6 for Linux Team.
121 + Permission is granted to copy, distribute and/or modify this
122 + document under the terms of the GNU Free Documentation License,
123 + Version 1.1 published by the Free Software Foundation; with the
124 + Invariant Sections being "Introduction", with the Front-Cover
125 + Texts being "MIPL Mobile IPv6 Function Reference Guide", "MIPL
126 + Mobile IPv6 for Linux Team" and "Helsinki University of
127 + Technology". A copy of the license is included in <xref
136 + <preface id="intro">
137 + <title>Introduction</title>
140 + MIPL Mobile IPv6 for Linux is an implementation of Mobility
141 + Support in IPv6 IETF mobile-ip working groups Internet-Draft
142 + (draft-ietf-mobileip-ipv6). This implementation has been
143 + developed in the Telecommunications Software and Multimedia
144 + Laboratory at Helsinki University of Technology.
148 + MIPL is fully open source, licensed under the GNU General
149 + Public License. Latest source for MIPL can be downloaded from
150 + the MIPL website at:
153 + http://www.mipl.mediapoli.com/.
156 + Developers and users interested in MIPL can subscribe to the
157 + MIPL mailing list by sending e-mail to
158 + <email>majordomo@list.mipl.mediapoli.com</email> with
164 + in the body of the message.
168 + This document is a reference guide to MIPL functions. Intended
169 + audience is developers wishing to contribute to the project.
170 + Hopefully this document will make it easier and quicker to
171 + understand and adopt the inner workings of MIPL Mobile IPv6.
175 + MIPL Mobile IPv6 for Linux Team members (past and present):
180 + Sami Kivisaari <email>Sami.Kivisaari@hut.fi</email>
185 + Niklas Kampe <email>Niklas.Kampe@hut.fi</email>
190 + Juha Mynttinen <email>Juha.Mynttinen@hut.fi</email>
195 + Toni Nykanen <email>Toni.Nykanen@iki.fi</email>
200 + Henrik Petander <email>Henrik.Petander@hut.fi</email>
205 + Antti Tuominen <email>ajtuomin@tml.hut.fi</email>
218 + Ville Nuorvala <email>vnuorval@tcs.hut.fi</email>
223 + Jaakko Laine <email>Jaakko.Laine@hut.fi</email>
231 + <chapter id="common">
232 + <title>Common functions for all entities</title>
234 + <sect1><title>Low-level functions</title>
236 + These functions implement memory allocation used by others.
237 + Hashlist functions implement a linked list with hash lookup,
238 + which is used with Binding Update List, Binding Cache, Home
241 +!Inet/ipv6/mobile_ip6/mempool.h
242 +!Inet/ipv6/mobile_ip6/hashlist.h
245 + <sect1><title>Debug functions</title>
247 + Debug and utility functions. These functions are available if
248 + <constant>CONFIG_IPV6_MOBILITY_DEBUG</constant> is set.
249 + Otherwise macros expand to no operation.
251 +!Inet/ipv6/mobile_ip6/debug.h
252 +!Inet/ipv6/mobile_ip6/mipv6.c
255 + <sect1><title>Extension Header functions</title>
257 + These functions create and handle extension headers that are
260 +!Inet/ipv6/mobile_ip6/exthdrs.c
263 + <sect1><title>Mobility Header functions</title>
265 + MIPv6 specifies a new protocol called Mobility Header.
266 + Mobility Header has several message types. Messages may also
267 + carry Mobility Options. These functions are used to create and
268 + handle Mobility Headers and Mobility Options.
270 +!Inet/ipv6/mobile_ip6/sendopts.c
271 +!Inet/ipv6/mobile_ip6/mh_recv.c
272 +!Inet/ipv6/mobile_ip6/auth_subopt.c
275 + <sect1><title>Binding Cache</title>
277 + All Mobile IPv6 entities have a binding cache. These functions
278 + provide easy manipulation of the binding cache.
280 +!Inet/ipv6/mobile_ip6/bcache.c
283 + <sect1><title>Security</title>
286 + These functions are common authentication functions and
287 + implement Draft 13 style IPSec AH support for Binding Updates.
289 +!Inet/ipv6/mobile_ip6/ah_algo.c
290 +!Inet/ipv6/mobile_ip6/sadb.c
291 +!Inet/ipv6/mobile_ip6/ah.c
294 + <sect1><title>Utility functions</title>
297 + These functions are general utility functions commonly used by
300 +!Inet/ipv6/mobile_ip6/util.c
306 + <title>Mobile Node functions</title>
307 + <sect1><title>General functions</title>
310 +!Inet/ipv6/mobile_ip6/mn.c
313 + <sect1><title>Binding Update List</title>
315 + Mobile Node keeps track of sent binding updates in Binding
318 +!Inet/ipv6/mobile_ip6/bul.c
321 + <sect1><title>Movement detection</title>
324 + These functions are used by the mobile node for movement
327 +!Inet/ipv6/mobile_ip6/mdetect.c
332 + <title>Home Agent functions</title>
333 + <sect1><title>General functions</title>
336 +!Inet/ipv6/mobile_ip6/ha.c
339 + <sect1><title>Duplicate Address Detection functions</title>
341 + Home Agent does Duplicate Address Detection for Mobile Nodes'
342 + addresses. These functions implement MIPv6 specific DAD
345 +!Inet/ipv6/mobile_ip6/dad.c
349 + <appendix id="gfdl">
350 + <title>GNU Free Documentation License</title>
353 + Version 1.1, March 2000
357 + Copyright (C) 2000 Free Software Foundation, Inc.
358 + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
359 + Everyone is permitted to copy and distribute verbatim copies
360 + of this license document, but changing it is not allowed.
363 + <sect1><title>0. PREAMBLE</title>
366 + The purpose of this License is to make a manual, textbook, or
367 + other written document "free" in the sense of freedom: to
368 + assure everyone the effective freedom to copy and redistribute
369 + it, with or without modifying it, either commercially or
370 + noncommercially. Secondarily, this License preserves for the
371 + author and publisher a way to get credit for their work, while
372 + not being considered responsible for modifications made by
377 + This License is a kind of "copyleft", which means that
378 + derivative works of the document must themselves be free in the
379 + same sense. It complements the GNU General Public License,
380 + which is a copyleft license designed for free software.
384 + We have designed this License in order to use it for manuals
385 + for free software, because free software needs free
386 + documentation: a free program should come with manuals
387 + providing the same freedoms that the software does. But this
388 + License is not limited to software manuals; it can be used for
389 + any textual work, regardless of subject matter or whether it is
390 + published as a printed book. We recommend this License
391 + principally for works whose purpose is instruction or
396 + <sect1><title>1. APPLICABILITY AND DEFINITIONS</title>
399 + This License applies to any manual or other work that contains
400 + a notice placed by the copyright holder saying it can be
401 + distributed under the terms of this License. The "Document",
402 + below, refers to any such manual or work. Any member of the
403 + public is a licensee, and is addressed as "you".
407 + A "Modified Version" of the Document means any work containing
408 + the Document or a portion of it, either copied verbatim, or
409 + with modifications and/or translated into another language.
413 + A "Secondary Section" is a named appendix or a front-matter
414 + section of the Document that deals exclusively with the
415 + relationship of the publishers or authors of the Document to
416 + the Document's overall subject (or to related matters) and
417 + contains nothing that could fall directly within that overall
418 + subject. (For example, if the Document is in part a textbook of
419 + mathematics, a Secondary Section may not explain any
420 + mathematics.) The relationship could be a matter of historical
421 + connection with the subject or with related matters, or of
422 + legal, commercial, philosophical, ethical or political position
427 + The "Invariant Sections" are certain Secondary Sections whose
428 + titles are designated, as being those of Invariant Sections, in
429 + the notice that says that the Document is released under this
434 + The "Cover Texts" are certain short passages of text that are
435 + listed, as Front-Cover Texts or Back-Cover Texts, in the notice
436 + that says that the Document is released under this License.
440 + A "Transparent" copy of the Document means a machine-readable
441 + copy, represented in a format whose specification is available
442 + to the general public, whose contents can be viewed and edited
443 + directly and straightforwardly with generic text editors or
444 + (for images composed of pixels) generic paint programs or (for
445 + drawings) some widely available drawing editor, and that is
446 + suitable for input to text formatters or for automatic
447 + translation to a variety of formats suitable for input to text
448 + formatters. A copy made in an otherwise Transparent file format
449 + whose markup has been designed to thwart or discourage
450 + subsequent modification by readers is not Transparent. A copy
451 + that is not "Transparent" is called "Opaque".
455 + Examples of suitable formats for Transparent copies include
456 + plain ASCII without markup, Texinfo input format, LaTeX input
457 + format, SGML or XML using a publicly available DTD, and
458 + standard-conforming simple HTML designed for human
459 + modification. Opaque formats include PostScript, PDF,
460 + proprietary formats that can be read and edited only by
461 + proprietary word processors, SGML or XML for which the DTD
462 + and/or processing tools are not generally available, and the
463 + machine-generated HTML produced by some word processors for
464 + output purposes only.
468 + The "Title Page" means, for a printed book, the title page
469 + itself, plus such following pages as are needed to hold,
470 + legibly, the material this License requires to appear in the
471 + title page. For works in formats which do not have any title
472 + page as such, "Title Page" means the text near the most
473 + prominent appearance of the work's title, preceding the
474 + beginning of the body of the text.
478 + <sect1><title>2. VERBATIM COPYING</title>
481 + You may copy and distribute the Document in any medium, either
482 + commercially or noncommercially, provided that this License,
483 + the copyright notices, and the license notice saying this
484 + License applies to the Document are reproduced in all copies,
485 + and that you add no other conditions whatsoever to those of
486 + this License. You may not use technical measures to obstruct or
487 + control the reading or further copying of the copies you make
488 + or distribute. However, you may accept compensation in exchange
489 + for copies. If you distribute a large enough number of copies
490 + you must also follow the conditions in section 3.
494 + You may also lend copies, under the same conditions stated
495 + above, and you may publicly display copies.
499 + <sect1><title>3. COPYING IN QUANTITY</title>
502 + If you publish printed copies of the Document numbering more
503 + than 100, and the Document's license notice requires Cover
504 + Texts, you must enclose the copies in covers that carry,
505 + clearly and legibly, all these Cover Texts: Front-Cover Texts
506 + on the front cover, and Back-Cover Texts on the back
507 + cover. Both covers must also clearly and legibly identify you
508 + as the publisher of these copies. The front cover must present
509 + the full title with all words of the title equally prominent
510 + and visible. You may add other material on the covers in
511 + addition. Copying with changes limited to the covers, as long
512 + as they preserve the title of the Document and satisfy these
513 + conditions, can be treated as verbatim copying in other
518 + If the required texts for either cover are too voluminous to
519 + fit legibly, you should put the first ones listed (as many as
520 + fit reasonably) on the actual cover, and continue the rest onto
525 + If you publish or distribute Opaque copies of the Document
526 + numbering more than 100, you must either include a
527 + machine-readable Transparent copy along with each Opaque copy,
528 + or state in or with each Opaque copy a publicly-accessible
529 + computer-network location containing a complete Transparent
530 + copy of the Document, free of added material, which the general
531 + network-using public has access to download anonymously at no
532 + charge using public-standard network protocols. If you use the
533 + latter option, you must take reasonably prudent steps, when you
534 + begin distribution of Opaque copies in quantity, to ensure that
535 + this Transparent copy will remain thus accessible at the stated
536 + location until at least one year after the last time you
537 + distribute an Opaque copy (directly or through your agents or
538 + retailers) of that edition to the public.
542 + It is requested, but not required, that you contact the authors
543 + of the Document well before redistributing any large number of
544 + copies, to give them a chance to provide you with an updated
545 + version of the Document.
549 + <sect1><title>4. MODIFICATIONS</title>
552 + You may copy and distribute a Modified Version of the Document
553 + under the conditions of sections 2 and 3 above, provided that
554 + you release the Modified Version under precisely this License,
555 + with the Modified Version filling the role of the Document,
556 + thus licensing distribution and modification of the Modified
557 + Version to whoever possesses a copy of it. In addition, you
558 + must do these things in the Modified Version:
562 + <itemizedlist spacing=compact>
565 + A. Use in the Title Page (and on the covers, if any) a title
566 + distinct from that of the Document, and from those of previous
567 + versions (which should, if there were any, be listed in the
568 + History section of the Document). You may use the same title
569 + as a previous version if the original publisher of that
570 + version gives permission.
575 + B. List on the Title Page, as authors, one or more persons
576 + or entities responsible for authorship of the modifications in
577 + the Modified Version, together with at least five of the
578 + principal authors of the Document (all of its principal
579 + authors, if it has less than five).
584 + C. State on the Title page the name of the publisher of the
585 + Modified Version, as the publisher.
590 + D. Preserve all the copyright notices of the Document.
595 + E. Add an appropriate copyright notice for your
596 + modifications adjacent to the other copyright notices.
601 + F. Include, immediately after the copyright notices, a
602 + license notice giving the public permission to use the
603 + Modified Version under the terms of this License, in the form
604 + shown in the Addendum below.
609 + G. Preserve in that license notice the full lists of
610 + Invariant Sections and required Cover Texts given in the
611 + Document's license notice.
616 + H. Include an unaltered copy of this License.
621 + I. Preserve the section entitled "History", and its title,
622 + and add to it an item stating at least the title, year, new
623 + authors, and publisher of the Modified Version as given on the
624 + Title Page. If there is no section entitled "History" in the
625 + Document, create one stating the title, year, authors, and
626 + publisher of the Document as given on its Title Page, then add
627 + an item describing the Modified Version as stated in the
633 + J. Preserve the network location, if any, given in the
634 + Document for public access to a Transparent copy of the
635 + Document, and likewise the network locations given in the
636 + Document for previous versions it was based on. These may be
637 + placed in the "History" section. You may omit a network
638 + location for a work that was published at least four years
639 + before the Document itself, or if the original publisher of
640 + the version it refers to gives permission.
645 + K. In any section entitled "Acknowledgements" or
646 + "Dedications", preserve the section's title, and preserve in
647 + the section all the substance and tone of each of the
648 + contributor acknowledgements and/or dedications given therein.
653 + L. Preserve all the Invariant Sections of the Document,
654 + unaltered in their text and in their titles. Section numbers
655 + or the equivalent are not considered part of the section
661 + M. Delete any section entitled "Endorsements". Such a
662 + section may not be included in the Modified Version.
667 + N. Do not retitle any existing section as "Endorsements" or
668 + to conflict in title with any Invariant Section.
675 + If the Modified Version includes new front-matter sections or
676 + appendices that qualify as Secondary Sections and contain no
677 + material copied from the Document, you may at your option
678 + designate some or all of these sections as invariant. To do
679 + this, add their titles to the list of Invariant Sections in the
680 + Modified Version's license notice. These titles must be
681 + distinct from any other section titles.
685 + You may add a section entitled "Endorsements", provided it
686 + contains nothing but endorsements of your Modified Version by
687 + various parties--for example, statements of peer review or that
688 + the text has been approved by an organization as the
689 + authoritative definition of a standard.
693 + You may add a passage of up to five words as a Front-Cover
694 + Text, and a passage of up to 25 words as a Back-Cover Text, to
695 + the end of the list of Cover Texts in the Modified
696 + Version. Only one passage of Front-Cover Text and one of
697 + Back-Cover Text may be added by (or through arrangements made
698 + by) any one entity. If the Document already includes a cover
699 + text for the same cover, previously added by you or by
700 + arrangement made by the same entity you are acting on behalf
701 + of, you may not add another; but you may replace the old one,
702 + on explicit permission from the previous publisher that added
707 + The author(s) and publisher(s) of the Document do not by this
708 + License give permission to use their names for publicity for or
709 + to assert or imply endorsement of any Modified Version.
713 + <sect1><title>5. COMBINING DOCUMENTS</title>
716 + You may combine the Document with other documents released
717 + under this License, under the terms defined in section 4 above
718 + for modified versions, provided that you include in the
719 + combination all of the Invariant Sections of all of the
720 + original documents, unmodified, and list them all as Invariant
721 + Sections of your combined work in its license notice.
725 + The combined work need only contain one copy of this License,
726 + and multiple identical Invariant Sections may be replaced with
727 + a single copy. If there are multiple Invariant Sections with
728 + the same name but different contents, make the title of each
729 + such section unique by adding at the end of it, in parentheses,
730 + the name of the original author or publisher of that section if
731 + known, or else a unique number. Make the same adjustment to the
732 + section titles in the list of Invariant Sections in the license
733 + notice of the combined work.
737 + In the combination, you must combine any sections entitled
738 + "History" in the various original documents, forming one
739 + section entitled "History"; likewise combine any sections
740 + entitled "Acknowledgements", and any sections entitled
741 + "Dedications". You must delete all sections entitled
746 + <sect1><title>6. COLLECTIONS OF DOCUMENTS</title>
749 + You may make a collection consisting of the Document and other
750 + documents released under this License, and replace the
751 + individual copies of this License in the various documents with
752 + a single copy that is included in the collection, provided that
753 + you follow the rules of this License for verbatim copying of
754 + each of the documents in all other respects.
758 + You may extract a single document from such a collection, and
759 + distribute it individually under this License, provided you
760 + insert a copy of this License into the extracted document, and
761 + follow this License in all other respects regarding verbatim
762 + copying of that document.
766 + <sect1><title>7. AGGREGATION WITH INDEPENDENT WORKS</title>
769 + A compilation of the Document or its derivatives with other
770 + separate and independent documents or works, in or on a volume
771 + of a storage or distribution medium, does not as a whole count
772 + as a Modified Version of the Document, provided no compilation
773 + copyright is claimed for the compilation. Such a compilation is
774 + called an "aggregate", and this License does not apply to the
775 + other self-contained works thus compiled with the Document, on
776 + account of their being thus compiled, if they are not
777 + themselves derivative works of the Document.
781 + If the Cover Text requirement of section 3 is applicable to
782 + these copies of the Document, then if the Document is less than
783 + one quarter of the entire aggregate, the Document's Cover Texts
784 + may be placed on covers that surround only the Document within
785 + the aggregate. Otherwise they must appear on covers around the
790 + <sect1><title>8. TRANSLATION</title>
793 + Translation is considered a kind of modification, so you may
794 + distribute translations of the Document under the terms of
795 + section 4. Replacing Invariant Sections with translations
796 + requires special permission from their copyright holders, but
797 + you may include translations of some or all Invariant Sections
798 + in addition to the original versions of these Invariant
799 + Sections. You may include a translation of this License
800 + provided that you also include the original English version of
801 + this License. In case of a disagreement between the translation
802 + and the original English version of this License, the original
803 + English version will prevail.
807 + <sect1><title>9. TERMINATION</title>
810 + You may not copy, modify, sublicense, or distribute the
811 + Document except as expressly provided for under this
812 + License. Any other attempt to copy, modify, sublicense or
813 + distribute the Document is void, and will automatically
814 + terminate your rights under this License. However, parties who
815 + have received copies, or rights, from you under this License
816 + will not have their licenses terminated so long as such parties
817 + remain in full compliance.
821 + <sect1><title>10. FUTURE REVISIONS OF THIS LICENSE</title>
824 + The Free Software Foundation may publish new, revised versions
825 + of the GNU Free Documentation License from time to time. Such
826 + new versions will be similar in spirit to the present version,
827 + but may differ in detail to address new problems or
828 + concerns. See http://www.gnu.org/copyleft/.
832 + Each version of the License is given a distinguishing version
833 + number. If the Document specifies that a particular numbered
834 + version of this License "or any later version" applies to it,
835 + you have the option of following the terms and conditions
836 + either of that specified version or of any later version that
837 + has been published (not as a draft) by the Free Software
838 + Foundation. If the Document does not specify a version number
839 + of this License, you may choose any version ever published (not
840 + as a draft) by the Free Software Foundation.
846 --- linux-2.4.27/include/linux/icmpv6.h~mipv6-1.1-v2.4.26
847 +++ linux-2.4.27/include/linux/icmpv6.h
849 struct icmpv6_nd_ra {
851 #if defined(__LITTLE_ENDIAN_BITFIELD)
858 #elif defined(__BIG_ENDIAN_BITFIELD)
865 #error "Please fix <asm/byteorder.h>"
868 #define icmp6_addrconf_managed icmp6_dataun.u_nd_ra.managed
869 #define icmp6_addrconf_other icmp6_dataun.u_nd_ra.other
870 #define icmp6_rt_lifetime icmp6_dataun.u_nd_ra.rt_lifetime
871 +#define icmp6_home_agent icmp6_dataun.u_nd_ra.home_agent
875 --- linux-2.4.27/include/linux/if_arp.h~mipv6-1.1-v2.4.26
876 +++ linux-2.4.27/include/linux/if_arp.h
878 #define ARPHRD_RAWHDLC 518 /* Raw HDLC */
880 #define ARPHRD_TUNNEL 768 /* IPIP tunnel */
881 -#define ARPHRD_TUNNEL6 769 /* IPIP6 tunnel */
882 +#define ARPHRD_TUNNEL6 769 /* IP6IP6 tunnel */
883 #define ARPHRD_FRAD 770 /* Frame Relay Access Device */
884 #define ARPHRD_SKIP 771 /* SKIP vif */
885 #define ARPHRD_LOOPBACK 772 /* Loopback device */
886 --- linux-2.4.27/include/linux/in6.h~mipv6-1.1-v2.4.26
887 +++ linux-2.4.27/include/linux/in6.h
889 #define IPV6_TLV_JUMBO 194
892 + * Mobile IPv6 TLV options.
894 +#define MIPV6_TLV_HOMEADDR 201
897 * IPV6 socket options
900 --- linux-2.4.27/include/linux/ipv6.h~mipv6-1.1-v2.4.26
901 +++ linux-2.4.27/include/linux/ipv6.h
904 #define IPV6_SRCRT_STRICT 0x01 /* this hop must be a neighbor */
905 #define IPV6_SRCRT_TYPE_0 0 /* IPv6 type 0 Routing Header */
906 +#define IPV6_SRCRT_TYPE_2 2 /* type 2 for Mobile IPv6 */
911 struct in6_addr addr[0];
913 #define rt0_type rt_hdr.type
918 + * routing header type 2
922 + struct ipv6_rt_hdr rt_hdr;
924 + struct in6_addr addr;
926 +#define rt2_type rt_hdr.type;
930 @@ -156,12 +170,16 @@
931 struct inet6_skb_parm
943 + struct in6_addr hoa;
947 --- linux-2.4.27/include/linux/ipv6_route.h~mipv6-1.1-v2.4.26
948 +++ linux-2.4.27/include/linux/ipv6_route.h
950 #define RTF_CACHE 0x01000000 /* cache entry */
951 #define RTF_FLOW 0x02000000 /* flow significant route */
952 #define RTF_POLICY 0x04000000 /* policy route */
953 +#define RTF_MOBILENODE 0x10000000 /* for routing to Mobile Node */
955 #define RTF_LOCAL 0x80000000
958 +++ linux-2.4.27/include/linux/ipv6_tunnel.h
964 +#ifndef _IPV6_TUNNEL_H
965 +#define _IPV6_TUNNEL_H
967 +#define IPV6_TLV_TNL_ENCAP_LIMIT 4
968 +#define IPV6_DEFAULT_TNL_ENCAP_LIMIT 4
970 +/* don't add encapsulation limit if one isn't present in inner packet */
971 +#define IP6_TNL_F_IGN_ENCAP_LIMIT 0x1
972 +/* copy the traffic class field from the inner packet */
973 +#define IP6_TNL_F_USE_ORIG_TCLASS 0x2
974 +/* copy the flowlabel from the inner packet */
975 +#define IP6_TNL_F_USE_ORIG_FLOWLABEL 0x4
976 +/* created and maintained from within the kernel */
977 +#define IP6_TNL_F_KERNEL_DEV 0x8
978 +/* being used for Mobile IPv6 */
979 +#define IP6_TNL_F_MIP6_DEV 0x10
981 +struct ip6_tnl_parm {
982 + char name[IFNAMSIZ]; /* name of tunnel device */
983 + int link; /* ifindex of underlying L2 interface */
984 + __u8 proto; /* tunnel protocol */
985 + __u8 encap_limit; /* encapsulation limit for tunnel */
986 + __u8 hop_limit; /* hop limit for tunnel */
987 + __u32 flowinfo; /* traffic class and flowlabel for tunnel */
988 + __u32 flags; /* tunnel flags */
989 + struct in6_addr laddr; /* local tunnel end-point address */
990 + struct in6_addr raddr; /* remote tunnel end-point address */
994 --- linux-2.4.27/include/linux/rtnetlink.h~mipv6-1.1-v2.4.26
995 +++ linux-2.4.27/include/linux/rtnetlink.h
1006 #define IFA_F_SECONDARY 0x01
1008 +#define IFA_F_HOMEADDR 0x10
1009 #define IFA_F_DEPRECATED 0x20
1010 #define IFA_F_TENTATIVE 0x40
1011 #define IFA_F_PERMANENT 0x80
1012 --- linux-2.4.27/include/linux/skbuff.h~mipv6-1.1-v2.4.26
1013 +++ linux-2.4.27/include/linux/skbuff.h
1015 * want to keep them across layers you have to do a skb_clone()
1016 * first. This is owned by whoever has the skb queued ATM.
1021 unsigned int len; /* Length of actual data */
1022 unsigned int data_len;
1023 --- linux-2.4.27/include/linux/sysctl.h~mipv6-1.1-v2.4.26
1024 +++ linux-2.4.27/include/linux/sysctl.h
1025 @@ -404,6 +404,23 @@
1027 NET_IPV6_BINDV6ONLY=20,
1028 NET_IPV6_MLD_MAX_MSF=25,
1029 + NET_IPV6_MOBILITY=26
1032 +/* /proc/sys/net/ipv6/mobility */
1034 + NET_IPV6_MOBILITY_DEBUG=1,
1035 + NET_IPV6_MOBILITY_TUNNEL_SITELOCAL=2,
1036 + NET_IPV6_MOBILITY_ROUTER_SOLICITATION_MAX_SENDTIME=3,
1037 + NET_IPV6_MOBILITY_ROUTER_REACH=4,
1038 + NET_IPV6_MOBILITY_MDETECT_MECHANISM=5,
1039 + NET_IPV6_MOBILITY_RETROUT=6,
1040 + NET_IPV6_MOBILITY_MAX_TNLS=7,
1041 + NET_IPV6_MOBILITY_MIN_TNLS=8,
1042 + NET_IPV6_MOBILITY_BINDING_REFRESH=9,
1043 + NET_IPV6_MOBILITY_BU_F_LLADDR=10,
1044 + NET_IPV6_MOBILITY_BU_F_KEYMGM=11,
1045 + NET_IPV6_MOBILITY_BU_F_CN_ACK=12
1049 --- linux-2.4.27/include/net/addrconf.h~mipv6-1.1-v2.4.26
1050 +++ linux-2.4.27/include/net/addrconf.h
1052 #if defined(__BIG_ENDIAN_BITFIELD)
1056 + router_address : 1,
1058 #elif defined(__LITTLE_ENDIAN_BITFIELD)
1059 - __u8 reserved : 6,
1060 + __u8 reserved : 5,
1061 + router_address : 1,
1066 struct net_device *dev);
1067 extern struct inet6_ifaddr * ipv6_get_ifaddr(struct in6_addr *addr,
1068 struct net_device *dev);
1069 +extern void ipv6_del_addr(struct inet6_ifaddr *ifp);
1070 extern int ipv6_get_saddr(struct dst_entry *dst,
1071 struct in6_addr *daddr,
1072 struct in6_addr *saddr);
1074 extern void ipv6_mc_down(struct inet6_dev *idev);
1075 extern void ipv6_mc_init_dev(struct inet6_dev *idev);
1076 extern void ipv6_mc_destroy_dev(struct inet6_dev *idev);
1077 +extern void addrconf_dad_start(struct inet6_ifaddr *ifp, int flags);
1078 extern void addrconf_dad_failure(struct inet6_ifaddr *ifp);
1079 +extern void addrconf_dad_completed(struct inet6_ifaddr *ifp);
1081 extern int ipv6_chk_mcast_addr(struct net_device *dev, struct in6_addr *group,
1082 struct in6_addr *src_addr);
1084 extern int register_inet6addr_notifier(struct notifier_block *nb);
1085 extern int unregister_inet6addr_notifier(struct notifier_block *nb);
1087 +extern int ipv6_generate_eui64(u8 *eui, struct net_device *dev);
1088 +extern int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev);
1090 static inline struct inet6_dev *
1091 __in6_dev_get(struct net_device *dev)
1093 --- linux-2.4.27/include/net/ip6_route.h~mipv6-1.1-v2.4.26
1094 +++ linux-2.4.27/include/net/ip6_route.h
1096 #define _NET_IP6_ROUTE_H
1098 #define IP6_RT_PRIO_FW 16
1099 +#define IP6_RT_PRIO_MIPV6 64
1100 #define IP6_RT_PRIO_USER 1024
1101 #define IP6_RT_PRIO_ADDRCONF 256
1102 #define IP6_RT_PRIO_KERN 512
1105 extern int ip6_route_add(struct in6_rtmsg *rtmsg,
1108 +extern int ip6_route_del(struct in6_rtmsg *rtmsg,
1109 + struct nlmsghdr *);
1110 extern int ip6_del_rt(struct rt6_info *,
1116 static inline void ip6_dst_store(struct sock *sk, struct dst_entry *dst,
1117 - struct in6_addr *daddr)
1118 + struct in6_addr *daddr,
1119 + struct in6_addr *saddr)
1121 struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
1122 struct rt6_info *rt = (struct rt6_info *) dst;
1124 write_lock(&sk->dst_lock);
1125 __sk_dst_set(sk, dst);
1126 np->daddr_cache = daddr;
1127 +#ifdef CONFIG_IPV6_SUBTREES
1128 + np->saddr_cache = saddr;
1130 np->dst_cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0;
1131 write_unlock(&sk->dst_lock);
1133 --- linux-2.4.27/include/net/ipv6.h~mipv6-1.1-v2.4.26
1134 +++ linux-2.4.27/include/net/ipv6.h
1136 #define NEXTHDR_ICMP 58 /* ICMP for IPv6. */
1137 #define NEXTHDR_NONE 59 /* No next header */
1138 #define NEXTHDR_DEST 60 /* Destination options header. */
1139 +#define NEXTHDR_MH 135 /* Mobility header, RFC 3775 */
1141 #define NEXTHDR_MAX 255
1143 @@ -146,9 +147,12 @@
1144 __u16 opt_flen; /* after fragment hdr */
1145 __u16 opt_nflen; /* before fragment hdr */
1147 + __u8 mipv6_flags; /* flags set by MIPv6 */
1149 struct ipv6_opt_hdr *hopopt;
1150 struct ipv6_opt_hdr *dst0opt;
1151 - struct ipv6_rt_hdr *srcrt; /* Routing Header */
1152 + struct ipv6_rt_hdr *srcrt; /* Routing Header Type 0 */
1153 + struct ipv6_rt_hdr *srcrt2; /* Routing Header Type 2 */
1154 struct ipv6_opt_hdr *auth;
1155 struct ipv6_opt_hdr *dst1opt;
1157 @@ -257,6 +261,38 @@
1158 a->s6_addr32[2] | a->s6_addr32[3] ) == 0);
1161 +static inline void ipv6_addr_prefix(struct in6_addr *pfx,
1162 + const struct in6_addr *addr, int plen)
1164 + /* caller must guarantee 0 <= plen <= 128 */
1165 + int o = plen >> 3,
1168 + memcpy(pfx->s6_addr, addr, o);
1170 + pfx->s6_addr[o] = addr->s6_addr[o] & (0xff00 >> b);
1174 + memset(pfx->s6_addr + o, 0, 16 - o);
1177 +static inline int ipv6_prefix_cmp(const struct in6_addr *p1,
1178 + const struct in6_addr *p2, int plen)
1185 + res = memcmp(&p1->s6_addr[0], &p2->s6_addr[0], o);
1186 + if (res == 0 && b > 0) {
1187 + __u8 m = (0xff00 >> b) & 0xff;
1188 + res = (p1->s6_addr[o] & m) - (p2->s6_addr[o] & m);
1194 * Prototypes exported by ipv6
1197 +++ linux-2.4.27/include/net/ipv6_tunnel.h
1203 +#ifndef _NET_IPV6_TUNNEL_H
1204 +#define _NET_IPV6_TUNNEL_H
1206 +#include <linux/ipv6.h>
1207 +#include <linux/netdevice.h>
1208 +#include <linux/ipv6_tunnel.h>
1209 +#include <linux/skbuff.h>
1210 +#include <asm/atomic.h>
1212 +/* capable of sending packets */
1213 +#define IP6_TNL_F_CAP_XMIT 0x10000
1214 +/* capable of receiving packets */
1215 +#define IP6_TNL_F_CAP_RCV 0x20000
1217 +#define IP6_TNL_MAX 128
1222 + struct ip6_tnl *next; /* next tunnel in list */
1223 + struct net_device *dev; /* virtual device associated with tunnel */
1224 + struct net_device_stats stat; /* statistics for tunnel device */
1225 + int recursion; /* depth of hard_start_xmit recursion */
1226 + struct ip6_tnl_parm parms; /* tunnel configuration paramters */
1227 + struct flowi fl; /* flowi template for xmit */
1228 + atomic_t refcnt; /* nr of identical tunnels used by kernel */
1229 + struct socket *sock;
1232 +#define IP6_TNL_PRE_ENCAP 0
1233 +#define IP6_TNL_PRE_DECAP 1
1234 +#define IP6_TNL_MAXHOOKS 2
1236 +#define IP6_TNL_DROP 0
1237 +#define IP6_TNL_ACCEPT 1
1239 +typedef int ip6_tnl_hookfn(struct ip6_tnl *t, struct sk_buff *skb);
1241 +struct ip6_tnl_hook_ops {
1242 + struct list_head list;
1243 + unsigned int hooknum;
1245 + ip6_tnl_hookfn *hook;
1248 +enum ip6_tnl_hook_priorities {
1249 + IP6_TNL_PRI_FIRST = INT_MIN,
1250 + IP6_TNL_PRI_LAST = INT_MAX
1253 +/* Tunnel encapsulation limit destination sub-option */
1255 +struct ipv6_tlv_tnl_enc_lim {
1256 + __u8 type; /* type-code for option */
1257 + __u8 length; /* option length */
1258 + __u8 encap_limit; /* tunnel encapsulation limit */
1259 +} __attribute__ ((packed));
1262 +extern int ip6ip6_tnl_create(struct ip6_tnl_parm *p, struct ip6_tnl **pt);
1264 +extern struct ip6_tnl *ip6ip6_tnl_lookup(struct in6_addr *remote,
1265 + struct in6_addr *local);
1267 +void ip6ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p);
1269 +extern int ip6ip6_kernel_tnl_add(struct ip6_tnl_parm *p);
1271 +extern int ip6ip6_kernel_tnl_del(struct ip6_tnl *t);
1273 +extern unsigned int ip6ip6_tnl_inc_max_kdev_count(unsigned int n);
1275 +extern unsigned int ip6ip6_tnl_dec_max_kdev_count(unsigned int n);
1277 +extern unsigned int ip6ip6_tnl_inc_min_kdev_count(unsigned int n);
1279 +extern unsigned int ip6ip6_tnl_dec_min_kdev_count(unsigned int n);
1281 +extern void ip6ip6_tnl_register_hook(struct ip6_tnl_hook_ops *reg);
1283 +extern void ip6ip6_tnl_unregister_hook(struct ip6_tnl_hook_ops *reg);
1285 +#ifdef CONFIG_IPV6_TUNNEL
1286 +extern int __init ip6_tunnel_init(void);
1287 +extern void ip6_tunnel_cleanup(void);
1292 +++ linux-2.4.27/include/net/mipglue.h
1295 + * Glue for Mobility support integration to IPv6
1298 + * Antti Tuominen <ajtuomin@cc.hut.fi>
1302 + * This program is free software; you can redistribute it and/or
1303 + * modify it under the terms of the GNU General Public License
1304 + * as published by the Free Software Foundation; either version
1305 + * 2 of the License, or (at your option) any later version.
1309 +#ifndef _NET_MIPGLUE_H
1310 +#define _NET_MIPGLUE_H
1312 +#ifndef USE_IPV6_MOBILITY
1313 +#if defined(CONFIG_IPV6_MOBILITY) || defined(CONFIG_IPV6_MOBILITY_MODULE)
1314 +#define USE_IPV6_MOBILITY
1318 +/* symbols to indicate whether destination options received should take
1319 + * effect or not (see exthdrs.c, procrcv.c)
1321 +#define MIPV6_DSTOPTS_ACCEPT 1
1322 +#define MIPV6_DSTOPTS_DISCARD 0
1324 +#define MIPV6_IGN_RTR 0
1325 +#define MIPV6_ADD_RTR 1
1326 +#define MIPV6_CHG_RTR 2
1328 +/* MIPV6: Approximate maximum for mobile IPv6 options and headers */
1329 +#define MIPV6_HEADERS 48
1332 +#include <net/mipv6.h>
1333 +#include <linux/slab.h>
1334 +#include <net/ipv6.h>
1337 +struct ndisc_options;
1339 +struct ipv6_txoptions;
1343 +struct inet6_ifaddr;
1345 +#ifdef USE_IPV6_MOBILITY
1347 +/* calls a procedure from mipv6-module */
1348 +#define MIPV6_CALLPROC(X) if(mipv6_functions.X) mipv6_functions.X
1350 +/* calls a function from mipv6-module, default-value if function not defined
1352 +#define MIPV6_CALLFUNC(X,Y) (!mipv6_functions.X)?(Y):mipv6_functions.X
1354 +/* sets a handler-function to process a call */
1355 +#define MIPV6_SETCALL(X,Y) if(mipv6_functions.X) printk("mipv6: Warning, function assigned twice!\n"); \
1356 + mipv6_functions.X = Y
1357 +#define MIPV6_RESETCALL(X) mipv6_functions.X = NULL
1359 +/* pointers to mipv6 callable functions */
1360 +struct mipv6_callable_functions {
1361 + void (*mipv6_initialize_dstopt_rcv) (struct sk_buff *skb);
1362 + int (*mipv6_finalize_dstopt_rcv) (int process);
1363 + int (*mipv6_handle_homeaddr) (struct sk_buff *skb, int optoff);
1364 + int (*mipv6_ra_rcv) (struct sk_buff *skb,
1365 + struct ndisc_options *ndopts);
1366 + void (*mipv6_icmp_rcv) (struct sk_buff *skb);
1367 + struct ipv6_txoptions * (*mipv6_modify_txoptions) (
1369 + struct sk_buff *skb,
1370 + struct ipv6_txoptions *opt,
1372 + struct dst_entry **dst);
1373 + void (*mipv6_set_home) (int ifindex, struct in6_addr *homeaddr,
1374 + int plen, struct in6_addr *homeagent,
1376 + void (*mipv6_get_home_address) (struct in6_addr *home_addr);
1377 + void (*mipv6_get_care_of_address)(struct in6_addr *homeaddr,
1378 + struct in6_addr *coa);
1379 + int (*mipv6_is_home_addr)(struct in6_addr *addr);
1380 + void (*mipv6_change_router)(void);
1381 + void (*mipv6_check_dad)(struct in6_addr *home_addr);
1382 + void (*mipv6_icmp_swap_addrs)(struct sk_buff *skb);
1383 + int (*mipv6_forward)(struct sk_buff *skb);
1384 + int (*mipv6_mn_ha_probe)(struct inet6_ifaddr *ifp, u8 *lladdr);
1387 +extern struct mipv6_callable_functions mipv6_functions;
1389 +extern void mipv6_invalidate_calls(void);
1391 +extern int mipv6_handle_dstopt(struct sk_buff *skb, int optoff);
1394 +ndisc_mip_mn_ha_probe(struct inet6_ifaddr *ifp, u8 *lladdr)
1396 + return MIPV6_CALLFUNC(mipv6_mn_ha_probe, 0)(ifp, lladdr);
1399 +/* Must only be called for HA, no checks here */
1400 +static inline int ip6_mipv6_forward(struct sk_buff *skb)
1402 + return MIPV6_CALLFUNC(mipv6_forward, 0)(skb);
1406 + * Avoid adding new default routers if the old one is still in use
1409 +static inline int ndisc_mipv6_ra_rcv(struct sk_buff *skb,
1410 + struct ndisc_options *ndopts)
1412 + return MIPV6_CALLFUNC(mipv6_ra_rcv, MIPV6_ADD_RTR)(skb, ndopts);
1415 +static inline int ipv6_chk_mip_home_addr(struct in6_addr *addr)
1417 + return MIPV6_CALLFUNC(mipv6_is_home_addr, 0)(addr);
1420 +static inline void ndisc_mipv6_change_router(int change_rtr)
1422 + if (change_rtr == MIPV6_CHG_RTR)
1423 + MIPV6_CALLPROC(mipv6_change_router)();
1426 +static inline void ndisc_check_mipv6_dad(struct in6_addr *target)
1428 + MIPV6_CALLPROC(mipv6_check_dad)(target);
1431 +static inline void icmpv6_swap_mipv6_addrs(struct sk_buff *skb)
1433 + MIPV6_CALLPROC(mipv6_icmp_swap_addrs)(skb);
1436 +static inline void mipv6_icmp_rcv(struct sk_buff *skb)
1438 + MIPV6_CALLPROC(mipv6_icmp_rcv)(skb);
1441 +static inline int tcp_v6_get_mipv6_header_len(void)
1443 + return MIPV6_HEADERS;
1446 +static inline struct in6_addr *
1447 +mipv6_get_fake_hdr_daddr(struct in6_addr *hdaddr, struct in6_addr *daddr)
1453 +addrconf_set_mipv6_mn_home(int ifindex, struct in6_addr *homeaddr, int plen,
1454 + struct in6_addr *homeagent, int plen2)
1456 + MIPV6_CALLPROC(mipv6_set_home)(ifindex, homeaddr, plen, homeagent, plen2);
1459 +static inline void addrconf_get_mipv6_home_address(struct in6_addr *saddr)
1461 + MIPV6_CALLPROC(mipv6_get_home_address)(saddr);
1464 +static inline struct ipv6_txoptions *
1465 +ip6_add_mipv6_txoptions(struct sock *sk, struct sk_buff *skb,
1466 + struct ipv6_txoptions *opt, struct flowi *fl,
1467 + struct dst_entry **dst)
1469 + return MIPV6_CALLFUNC(mipv6_modify_txoptions, opt)(sk, skb, opt, fl, dst);
1474 +ip6_mark_mipv6_packet(struct ipv6_txoptions *txopt, struct sk_buff *skb)
1476 + struct inet6_skb_parm *opt;
1478 + opt = (struct inet6_skb_parm *)skb->cb;
1479 + opt->mipv6_flags = txopt->mipv6_flags;
1484 +ip6_free_mipv6_txoptions(struct ipv6_txoptions *opt,
1485 + struct ipv6_txoptions *orig_opt)
1487 + if (opt && opt != orig_opt)
1491 +#else /* USE_IPV6_MOBILITY */
1493 +#define mipv6_handle_dstopt ip6_tlvopt_unknown
1496 +ndisc_mip_mn_ha_probe(struct inet6_ifaddr *ifp, u8 *lladdr)
1501 +static inline int ip6_mipv6_forward(struct sk_buff *skb)
1506 +static inline int ndisc_mipv6_ra_rcv(struct sk_buff *skb,
1507 + struct ndisc_options *ndopts)
1509 + return MIPV6_ADD_RTR;
1512 +static inline int ipv6_chk_mip_home_addr(struct in6_addr *addr)
1517 +static inline void ndisc_mipv6_change_router(int change_rtr) {}
1519 +static inline void ndisc_check_mipv6_dad(struct in6_addr *target) {}
1521 +static inline void icmpv6_swap_mipv6_addrs(struct sk_buff *skb) {}
1523 +static inline void mipv6_icmp_rcv(struct sk_buff *skb) {}
1525 +static inline int tcp_v6_get_mipv6_header_len(void)
1530 +static inline struct in6_addr *
1531 +mipv6_get_fake_hdr_daddr(struct in6_addr *hdaddr, struct in6_addr *daddr)
1537 +addrconf_set_mipv6_mn_home(int ifindex, struct in6_addr *homeaddr, int plen,
1538 + struct in6_addr *homeagent, int plen2) {}
1540 +static inline void addrconf_get_mipv6_home_address(struct in6_addr *saddr) {}
1542 +static inline struct ipv6_txoptions *
1543 +ip6_add_mipv6_txoptions(struct sock *sk, struct sk_buff *skb,
1544 + struct ipv6_txoptions *opt, struct flowi *fl,
1545 + struct dst_entry **dst)
1551 +ip6_mark_mipv6_packet(struct ipv6_txoptions *txopt, struct sk_buff *skb) {}
1554 +ip6_free_mipv6_txoptions(struct ipv6_txoptions *opt,
1555 + struct ipv6_txoptions *orig_opt) {}
1557 +#endif /* USE_IPV6_MOBILITY */
1558 +#endif /* __KERNEL__ */
1559 +#endif /* _NET_MIPGLUE_H */
1561 +++ linux-2.4.27/include/net/mipv6.h
1564 + * Mobile IPv6 header-file
1567 + * Sami Kivisaari <skivisaa@cc.hut.fi>
1571 + * This program is free software; you can redistribute it and/or
1572 + * modify it under the terms of the GNU General Public License
1573 + * as published by the Free Software Foundation; either version
1574 + * 2 of the License, or (at your option) any later version.
1578 +#ifndef _NET_MIPV6_H
1579 +#define _NET_MIPV6_H
1581 +#include <linux/types.h>
1582 +#include <asm/byteorder.h>
1583 +#include <linux/in6.h>
1587 + * Mobile IPv6 Protocol constants
1590 +#define DHAAD_RETRIES 4 /* transmissions */
1591 +#define INITIAL_BINDACK_TIMEOUT 1 /* seconds */
1592 +#define INITIAL_DHAAD_TIMEOUT 3 /* seconds */
1593 +#define INITIAL_SOLICIT_TIMER 3 /* seconds */
1594 +#define MAX_BINDACK_TIMEOUT 32 /* seconds */
1595 +#define MAX_NONCE_LIFE 240 /* seconds */
1596 +#define MAX_TOKEN_LIFE 210 /* seconds */
1597 +#define MAX_RR_BINDING_LIFE 420 /* seconds */
1598 +#define MAX_UPDATE_RATE 3 /* 1/s (min delay=1s) */
1599 +#define PREFIX_ADV_RETRIES 3 /* transmissions */
1600 +#define PREFIX_ADV_TIMEOUT 3 /* seconds */
1602 +#define MAX_FAST_UPDATES 5 /* transmissions */
1603 +#define MAX_PFX_ADV_DELAY 1000 /* seconds */
1604 +#define SLOW_UPDATE_RATE 10 /* 1/10s (max delay=10s)*/
1605 +#define INITIAL_BINDACK_DAD_TIMEOUT 2 /* seconds */
1609 + * Mobile IPv6 (RFC 3775) Protocol configuration variable defaults
1612 +#define DefHomeRtrAdvInterval 1000 /* seconds */
1613 +#define DefMaxMobPfxAdvInterval 86400 /* seconds */
1614 +#define DefMinDelayBetweenRAs 3 /* seconds (min 0.03) */
1615 +#define DefMinMobPfxAdvInterval 600 /* seconds */
1616 +#define DefInitialBindackTimeoutFirstReg 1.5 /* seconds */
1618 +/* This is not actually specified in the draft, but is needed to avoid
1619 + * prefix solicitation storm when valid lifetime of a prefix is smaller
1620 + * than MAX_PFX_ADV_DELAY
1622 +#define MIN_PFX_SOL_DELAY 5 /* seconds */
1624 +/* Mobile IPv6 ICMP types */
1626 + * Official numbers from RFC 3775
1628 +#define MIPV6_DHAAD_REQUEST 144
1629 +#define MIPV6_DHAAD_REPLY 145
1630 +#define MIPV6_PREFIX_SOLICIT 146
1631 +#define MIPV6_PREFIX_ADV 147
1633 +/* Binding update flag codes */
1634 +#define MIPV6_BU_F_ACK 0x80
1635 +#define MIPV6_BU_F_HOME 0x40
1636 +#define MIPV6_BU_F_LLADDR 0x20
1637 +#define MIPV6_BU_F_KEYMGM 0x10
1639 +/* Binding ackknowledgment flag codes */
1640 +#define MIPV6_BA_F_KEYMGM 0x80
1642 +/* Binding error status */
1643 +#define MIPV6_BE_HAO_WO_BINDING 1
1644 +#define MIPV6_BE_UNKNOWN_MH_TYPE 2
1646 +/* Mobility Header */
1649 + __u8 payload; /* Payload Protocol */
1650 + __u8 length; /* MH Length */
1651 + __u8 type; /* MH Type */
1652 + __u8 reserved; /* Reserved */
1653 + __u16 checksum; /* Checksum */
1654 + __u8 data[0]; /* Message specific data */
1655 +} __attribute__ ((packed));
1657 +/* Mobility Header type */
1658 +#define IPPROTO_MOBILITY 135 /* RFC 3775*/
1659 +/* Mobility Header Message Types */
1661 +#define MIPV6_MH_BRR 0
1662 +#define MIPV6_MH_HOTI 1
1663 +#define MIPV6_MH_COTI 2
1664 +#define MIPV6_MH_HOT 3
1665 +#define MIPV6_MH_COT 4
1666 +#define MIPV6_MH_BU 5
1667 +#define MIPV6_MH_BA 6
1668 +#define MIPV6_MH_BE 7
1671 + * Status codes for Binding Acknowledgements
1674 +#define REASON_UNSPECIFIED 128
1675 +#define ADMINISTRATIVELY_PROHIBITED 129
1676 +#define INSUFFICIENT_RESOURCES 130
1677 +#define HOME_REGISTRATION_NOT_SUPPORTED 131
1678 +#define NOT_HOME_SUBNET 132
1679 +#define NOT_HA_FOR_MN 133
1680 +#define DUPLICATE_ADDR_DETECT_FAIL 134
1681 +#define SEQUENCE_NUMBER_OUT_OF_WINDOW 135
1682 +#define EXPIRED_HOME_NONCE_INDEX 136
1683 +#define EXPIRED_CAREOF_NONCE_INDEX 137
1684 +#define EXPIRED_NONCES 138
1685 +#define REG_TYPE_CHANGE_FORBIDDEN 139
1687 + * Values for mipv6_flags in struct inet6_skb_parm
1690 +#define MIPV6_RCV_TUNNEL 0x1
1691 +#define MIPV6_SND_HAO 0x2
1692 +#define MIPV6_SND_BU 0x4
1695 + * Mobility Header Message structures
1698 +struct mipv6_mh_brr
1701 + /* Mobility options */
1702 +} __attribute__ ((packed));
1706 + __u16 sequence; /* sequence number of BU */
1707 + __u8 flags; /* flags */
1708 + __u8 reserved; /* reserved bits */
1709 + __u16 lifetime; /* lifetime of BU */
1710 + /* Mobility options */
1711 +} __attribute__ ((packed));
1715 + __u8 status; /* statuscode */
1716 + __u8 reserved; /* reserved bits */
1717 + __u16 sequence; /* sequence number of BA */
1718 + __u16 lifetime; /* lifetime in CN's bcache */
1719 + /* Mobility options */
1720 +} __attribute__ ((packed));
1726 + struct in6_addr home_addr;
1727 + /* Mobility options */
1728 +} __attribute__ ((packed));
1730 +struct mipv6_mh_addr_ti
1732 + __u16 reserved; /* Reserved */
1733 + u_int8_t init_cookie[8]; /* HoT/CoT Init Cookie */
1734 + /* Mobility options */
1735 +} __attribute__ ((packed));
1737 +struct mipv6_mh_addr_test
1739 + __u16 nonce_index; /* Home/Care-of Nonce Index */
1740 + u_int8_t init_cookie[8]; /* HoT/CoT Init Cookie */
1741 + u_int8_t kgen_token[8]; /* Home/Care-of key generation token */
1742 + /* Mobility options */
1743 +} __attribute__ ((packed));
1746 + * Mobility Options for various MH types.
1748 +#define MIPV6_OPT_PAD1 0x00
1749 +#define MIPV6_OPT_PADN 0x01
1750 +#define MIPV6_OPT_BIND_REFRESH_ADVICE 0x02
1751 +#define MIPV6_OPT_ALTERNATE_COA 0x03
1752 +#define MIPV6_OPT_NONCE_INDICES 0x04
1753 +#define MIPV6_OPT_AUTH_DATA 0x05
1755 +#define MIPV6_SEQ_GT(x,y) \
1756 + ((short int)(((__u16)(x)) - ((__u16)(y))) > 0)
1759 + * Mobility Option structures
1766 + __u8 value[0]; /* type specific data */
1767 +} __attribute__ ((packed));
1769 +struct mipv6_mo_pad1
1772 +} __attribute__ ((packed));
1774 +struct mipv6_mo_padn
1779 +} __attribute__ ((packed));
1781 +struct mipv6_mo_alt_coa
1785 + struct in6_addr addr; /* alternate care-of-address */
1786 +} __attribute__ ((packed));
1788 +struct mipv6_mo_nonce_indices
1792 + __u16 home_nonce_i; /* Home Nonce Index */
1793 + __u16 careof_nonce_i; /* Careof Nonce Index */
1794 +} __attribute__ ((packed));
1796 +struct mipv6_mo_bauth_data
1801 +} __attribute__ ((packed));
1803 +struct mipv6_mo_br_advice
1807 + __u16 refresh_interval; /* Refresh Interval */
1808 +} __attribute__ ((packed));
1811 + * Home Address Destination Option structure
1813 +struct mipv6_dstopt_homeaddr
1815 + __u8 type; /* type-code for option */
1816 + __u8 length; /* option length */
1817 + struct in6_addr addr; /* home address */
1818 +} __attribute__ ((packed));
1820 +#endif /* _NET_MIPV6_H */
1821 --- linux-2.4.27/include/net/ndisc.h~mipv6-1.1-v2.4.26
1822 +++ linux-2.4.27/include/net/ndisc.h
1824 #define ND_OPT_REDIRECT_HDR 4
1825 #define ND_OPT_MTU 5
1827 +/* Mobile IPv6 specific ndisc options */
1828 +#define ND_OPT_RTR_ADV_INTERVAL 7
1829 +#define ND_OPT_HOME_AGENT_INFO 8
1831 #define MAX_RTR_SOLICITATION_DELAY HZ
1833 #define ND_REACHABLE_TIME (30*HZ)
1835 } __attribute__((__packed__));
1837 struct ndisc_options {
1838 - struct nd_opt_hdr *nd_opt_array[7];
1839 + struct nd_opt_hdr *nd_opt_array[10];
1840 struct nd_opt_hdr *nd_opt_piend;
1844 #define nd_opts_pi_end nd_opt_piend
1845 #define nd_opts_rh nd_opt_array[ND_OPT_REDIRECT_HDR]
1846 #define nd_opts_mtu nd_opt_array[ND_OPT_MTU]
1847 +#define nd_opts_rai nd_opt_array[ND_OPT_RTR_ADV_INTERVAL]
1848 +#define nd_opts_hai nd_opt_array[ND_OPT_HOME_AGENT_INFO]
1850 extern struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur, struct nd_opt_hdr *end);
1851 extern struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len, struct ndisc_options *ndopts);
1853 struct in6_addr *daddr,
1854 struct in6_addr *saddr);
1856 +extern void ndisc_send_na(struct net_device *dev,
1857 + struct neighbour *neigh,
1858 + struct in6_addr *daddr,
1859 + struct in6_addr *solicited_addr,
1865 extern void ndisc_send_rs(struct net_device *dev,
1866 struct in6_addr *saddr,
1867 struct in6_addr *daddr);
1868 --- linux-2.4.27/include/net/sock.h~mipv6-1.1-v2.4.26
1869 +++ linux-2.4.27/include/net/sock.h
1871 struct in6_addr rcv_saddr;
1872 struct in6_addr daddr;
1873 struct in6_addr *daddr_cache;
1875 +#if defined(CONFIG_IPV6_SUBTREES)
1876 + struct in6_addr *saddr_cache;
1881 --- linux-2.4.27/net/Makefile~mipv6-1.1-v2.4.26
1882 +++ linux-2.4.27/net/Makefile
1885 O_TARGET := network.o
1887 -mod-subdirs := ipv4/netfilter ipv6/netfilter ipx irda bluetooth atm netlink sched core sctp 802
1888 +mod-subdirs := ipv4/netfilter ipv6/netfilter ipx irda bluetooth atm netlink sched core sctp 802 ipv6
1889 export-objs := netsyms.o
1891 subdir-y := core ethernet
1893 ifneq ($(CONFIG_IPV6),n)
1894 ifneq ($(CONFIG_IPV6),)
1895 subdir-$(CONFIG_NETFILTER) += ipv6/netfilter
1896 +subdir-$(CONFIG_IPV6_MOBILITY) += ipv6/mobile_ip6
1900 --- linux-2.4.27/net/core/neighbour.c~mipv6-1.1-v2.4.26
1901 +++ linux-2.4.27/net/core/neighbour.c
1906 - n = kmalloc(sizeof(*n) + key_len, GFP_KERNEL);
1907 + n = kmalloc(sizeof(*n) + key_len, GFP_ATOMIC);
1911 --- linux-2.4.27/net/ipv6/Config.in~mipv6-1.1-v2.4.26
1912 +++ linux-2.4.27/net/ipv6/Config.in
1915 # IPv6 configuration
1918 +bool ' IPv6: routing by source address (EXPERIMENTAL)' CONFIG_IPV6_SUBTREES
1919 #bool ' IPv6: flow policy support' CONFIG_RT6_POLICY
1920 #bool ' IPv6: firewall support' CONFIG_IPV6_FIREWALL
1922 +if [ "$CONFIG_IPV6" != "n" ]; then
1923 + dep_tristate ' IPv6: IPv6 over IPv6 Tunneling (EXPERIMENTAL)' CONFIG_IPV6_TUNNEL $CONFIG_IPV6
1926 +source net/ipv6/mobile_ip6/Config.in
1928 if [ "$CONFIG_NETFILTER" != "n" ]; then
1929 source net/ipv6/netfilter/Config.in
1931 --- linux-2.4.27/net/ipv6/Makefile~mipv6-1.1-v2.4.26
1932 +++ linux-2.4.27/net/ipv6/Makefile
1934 # unless it's something special (ie not a .c file).
1937 +export-objs := ipv6_syms.o ipv6_tunnel.o
1940 +#list-multi := ipv6.o ipv6_tunnel.o
1942 -obj-y := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o sit.o \
1943 - route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o raw.o \
1944 - protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \
1945 - exthdrs.o sysctl_net_ipv6.o datagram.o proc.o \
1946 - ip6_flowlabel.o ipv6_syms.o
1947 +ipv6-objs := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o \
1948 + sit.o route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o \
1949 + raw.o protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \
1950 + exthdrs.o sysctl_net_ipv6.o datagram.o proc.o \
1951 + ip6_flowlabel.o ipv6_syms.o
1953 -export-objs := ipv6_syms.o
1954 +ifneq ($(CONFIG_IPV6_MOBILITY),n)
1955 +ifneq ($(CONFIG_IPV6_MOBILITY),)
1956 +ipv6-objs += mipglue.o
1960 +obj-$(CONFIG_IPV6) += ipv6.o
1961 +obj-$(CONFIG_IPV6_TUNNEL) += ipv6_tunnel.o
1963 +ipv6.o: $(ipv6-objs)
1964 + $(LD) -r -o $@ $(ipv6-objs)
1966 -obj-m := $(O_TARGET)
1968 #obj-$(CONFIG_IPV6_FIREWALL) += ip6_fw.o
1970 --- linux-2.4.27/net/ipv6/addrconf.c~mipv6-1.1-v2.4.26
1971 +++ linux-2.4.27/net/ipv6/addrconf.c
1974 #include <asm/uaccess.h>
1976 +#include <net/mipglue.h>
1978 #define IPV6_MAX_ADDRESSES 16
1980 /* Set to 3 to get tracing... */
1983 static int addrconf_ifdown(struct net_device *dev, int how);
1985 -static void addrconf_dad_start(struct inet6_ifaddr *ifp, int flags);
1986 +void addrconf_dad_start(struct inet6_ifaddr *ifp, int flags);
1987 static void addrconf_dad_timer(unsigned long data);
1988 -static void addrconf_dad_completed(struct inet6_ifaddr *ifp);
1989 +void addrconf_dad_completed(struct inet6_ifaddr *ifp);
1990 static void addrconf_rs_timer(unsigned long data);
1991 static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa);
1993 @@ -330,38 +332,6 @@
1997 -void ipv6_addr_prefix(struct in6_addr *prefix,
1998 - struct in6_addr *addr, int prefix_len)
2000 - unsigned long mask;
2003 - memset(prefix, 0, sizeof(*prefix));
2005 - if (prefix_len <= 0)
2007 - if (prefix_len > 128)
2010 - ncopy = prefix_len / 32;
2012 - case 4: prefix->s6_addr32[3] = addr->s6_addr32[3];
2013 - case 3: prefix->s6_addr32[2] = addr->s6_addr32[2];
2014 - case 2: prefix->s6_addr32[1] = addr->s6_addr32[1];
2015 - case 1: prefix->s6_addr32[0] = addr->s6_addr32[0];
2018 - nbits = prefix_len % 32;
2022 - mask = ~((1 << (32 - nbits)) - 1);
2023 - mask = htonl(mask);
2025 - prefix->s6_addr32[ncopy] = addr->s6_addr32[ncopy] & mask;
2029 static void dev_forward_change(struct inet6_dev *idev)
2031 struct net_device *dev;
2034 /* This function wants to get referenced ifp and releases it before return */
2036 -static void ipv6_del_addr(struct inet6_ifaddr *ifp)
2037 +void ipv6_del_addr(struct inet6_ifaddr *ifp)
2039 struct inet6_ifaddr *ifa, **ifap;
2040 struct inet6_dev *idev = ifp->idev;
2041 @@ -662,6 +632,12 @@
2045 + /* The home address is always used as source address in
2046 + * MIPL mobile IPv6
2048 + if (scope != IFA_HOST && scope != IFA_LINK)
2049 + addrconf_get_mipv6_home_address(saddr);
2058 -static int ipv6_generate_eui64(u8 *eui, struct net_device *dev)
2059 +int ipv6_generate_eui64(u8 *eui, struct net_device *dev)
2061 switch (dev->type) {
2067 -static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev)
2068 +int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev)
2071 struct inet6_ifaddr *ifp;
2072 @@ -1407,6 +1383,24 @@
2077 + * addrconf_ipv6_tunnel_config - configure IPv6 tunnel device
2078 + * @dev: tunnel device
2081 +static void addrconf_ipv6_tunnel_config(struct net_device *dev)
2083 + struct inet6_dev *idev;
2087 + /* Assign inet6_dev structure to tunnel device */
2088 + if ((idev = ipv6_find_idev(dev)) == NULL) {
2089 + printk(KERN_DEBUG "init ipv6 tunnel: add_dev failed\n");
2095 int addrconf_notify(struct notifier_block *this, unsigned long event,
2097 @@ -1421,6 +1415,10 @@
2098 addrconf_sit_config(dev);
2101 + case ARPHRD_TUNNEL6:
2102 + addrconf_ipv6_tunnel_config(dev);
2105 case ARPHRD_LOOPBACK:
2108 @@ -1602,7 +1600,7 @@
2110 * Duplicate Address Detection
2112 -static void addrconf_dad_start(struct inet6_ifaddr *ifp, int flags)
2113 +void addrconf_dad_start(struct inet6_ifaddr *ifp, int flags)
2115 struct net_device *dev;
2116 unsigned long rand_num;
2117 @@ -1667,7 +1665,7 @@
2121 -static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
2122 +void addrconf_dad_completed(struct inet6_ifaddr *ifp)
2124 struct net_device * dev = ifp->idev->dev;
2126 @@ -1676,7 +1674,7 @@
2129 ipv6_ifa_notify(RTM_NEWADDR, ifp);
2131 + notifier_call_chain(&inet6addr_chain,NETDEV_UP,ifp);
2132 /* If added prefix is link local and forwarding is off,
2133 start sending router solicitations.
2135 @@ -1877,8 +1875,20 @@
2136 if (rta[IFA_LOCAL-1]) {
2137 if (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx)))
2139 + if (ifm->ifa_flags & IFA_F_HOMEADDR && !rta[IFA_HOMEAGENT-1])
2141 pfx = RTA_DATA(rta[IFA_LOCAL-1]);
2143 + if (rta[IFA_HOMEAGENT-1]) {
2144 + struct in6_addr *ha;
2145 + if (pfx == NULL || !(ifm->ifa_flags & IFA_F_HOMEADDR))
2147 + if (RTA_PAYLOAD(rta[IFA_HOMEAGENT-1]) < sizeof(*ha))
2149 + ha = RTA_DATA(rta[IFA_HOMEAGENT-1]);
2150 + addrconf_set_mipv6_mn_home(ifm->ifa_index, pfx, ifm->ifa_prefixlen,
2151 + ha, ifm->ifa_prefixlen);
2156 --- linux-2.4.27/net/ipv6/af_inet6.c~mipv6-1.1-v2.4.26
2157 +++ linux-2.4.27/net/ipv6/af_inet6.c
2159 #include <net/transp_v6.h>
2160 #include <net/ip6_route.h>
2161 #include <net/addrconf.h>
2162 +#ifdef CONFIG_IPV6_TUNNEL
2163 +#include <net/ipv6_tunnel.h>
2166 #include <asm/uaccess.h>
2167 #include <asm/system.h>
2168 @@ -646,6 +649,11 @@
2169 err = ndisc_init(&inet6_family_ops);
2172 +#ifdef CONFIG_IPV6_TUNNEL
2173 + err = ip6_tunnel_init();
2175 + goto ip6_tunnel_fail;
2177 err = igmp6_init(&inet6_family_ops);
2180 @@ -698,6 +706,10 @@
2184 +#ifdef CONFIG_IPV6_TUNNEL
2185 + ip6_tunnel_cleanup();
2192 ip6_route_cleanup();
2193 ipv6_packet_cleanup();
2195 +#ifdef CONFIG_IPV6_TUNNEL
2196 + ip6_tunnel_cleanup();
2200 #ifdef CONFIG_SYSCTL
2201 --- linux-2.4.27/net/ipv6/exthdrs.c~mipv6-1.1-v2.4.26
2202 +++ linux-2.4.27/net/ipv6/exthdrs.c
2204 #include <net/ip6_route.h>
2205 #include <net/addrconf.h>
2207 +#include <net/mipglue.h>
2208 +#include <net/mipv6.h>
2210 #include <asm/uaccess.h>
2214 *****************************/
2216 struct tlvtype_proc tlvprocdestopt_lst[] = {
2217 - /* No destination options are defined now */
2218 + /* Mobility Support destination options */
2219 + {MIPV6_TLV_HOMEADDR, mipv6_handle_dstopt},
2225 struct ipv6_rt_hdr *hdr;
2226 struct rt0_hdr *rthdr;
2227 + struct rt2_hdr *rt2hdr;
2229 if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
2230 !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
2231 @@ -225,17 +230,25 @@
2236 + /* Silently discard invalid packets containing RTH type 2 */
2237 + if (hdr->type == IPV6_SRCRT_TYPE_2 &&
2238 + (hdr->hdrlen != 2 || hdr->segments_left != 1)) {
2243 if (hdr->segments_left == 0) {
2244 - opt->srcrt = skb->h.raw - skb->nh.raw;
2245 + if (hdr->type == IPV6_SRCRT_TYPE_0)
2246 + opt->srcrt = skb->h.raw - skb->nh.raw;
2247 + else if (hdr->type == IPV6_SRCRT_TYPE_2)
2248 + opt->srcrt2 = skb->h.raw - skb->nh.raw;
2249 skb->h.raw += (hdr->hdrlen + 1) << 3;
2250 opt->dst0 = opt->dst1;
2252 return (&hdr->nexthdr) - skb->nh.raw;
2255 - if (hdr->type != IPV6_SRCRT_TYPE_0) {
2256 + if (hdr->type != IPV6_SRCRT_TYPE_0 && hdr->type != IPV6_SRCRT_TYPE_2) {
2257 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw);
2260 @@ -275,9 +288,20 @@
2262 i = n - --hdr->segments_left;
2264 - rthdr = (struct rt0_hdr *) hdr;
2265 - addr = rthdr->addr;
2267 + if (hdr->type == IPV6_SRCRT_TYPE_0) {
2268 + rthdr = (struct rt0_hdr *) hdr;
2269 + addr = rthdr->addr;
2272 + /* check that address is this node's home address */
2273 + rt2hdr = (struct rt2_hdr *) hdr;
2274 + addr = &rt2hdr->addr;
2275 + if (!ipv6_chk_addr(addr, NULL) ||
2276 + !ipv6_chk_mip_home_addr(addr)) {
2282 addr_type = ipv6_addr_type(addr);
2284 @@ -330,6 +354,10 @@
2285 temporary (or permanent) backdoor.
2286 If listening socket set IPV6_RTHDR to 2, then we invert header.
2289 + By the Mobile IPv6 specification Type 2 routing header MUST NOT be
2294 struct ipv6_txoptions *
2295 @@ -352,6 +380,18 @@
2296 struct ipv6_txoptions *opt;
2297 int hdrlen = ipv6_optlen(hdr);
2299 + if (hdr->type == IPV6_SRCRT_TYPE_2) {
2300 + opt = sock_kmalloc(sk, sizeof(*opt) + hdrlen, GFP_ATOMIC);
2303 + memset(opt, 0, sizeof(*opt));
2304 + opt->tot_len = sizeof(*opt) + hdrlen;
2305 + opt->srcrt = (void*)(opt+1);
2306 + opt->opt_nflen = hdrlen;
2307 + memcpy(opt->srcrt, hdr, sizeof(struct rt2_hdr));
2311 if (hdr->segments_left ||
2312 hdr->type != IPV6_SRCRT_TYPE_0 ||
2314 @@ -622,8 +662,18 @@
2317 prev_hdr = ipv6_build_exthdr(skb, prev_hdr, NEXTHDR_DEST, opt->dst0opt);
2319 - prev_hdr = ipv6_build_rthdr(skb, prev_hdr, opt->srcrt, daddr);
2321 + if (opt->srcrt2) {
2322 + struct in6_addr *rt2_hop = &((struct rt2_hdr *)opt->srcrt2)->addr;
2323 + prev_hdr = ipv6_build_rthdr(skb, prev_hdr, opt->srcrt, rt2_hop);
2325 + prev_hdr = ipv6_build_rthdr(skb, prev_hdr, opt->srcrt, daddr);
2327 + if (opt->srcrt2) {
2328 + struct inet6_skb_parm *parm = (struct inet6_skb_parm *)skb->cb;
2329 + ipv6_addr_copy(&parm->hoa, daddr);
2330 + prev_hdr = ipv6_build_rthdr(skb, prev_hdr, opt->srcrt2, daddr);
2335 @@ -684,6 +734,11 @@
2337 struct in6_addr **daddr)
2339 + if (opt->srcrt2) {
2340 + struct inet6_skb_parm *parm = (struct inet6_skb_parm *)skb->cb;
2341 + ipv6_addr_copy(&parm->hoa, *daddr);
2342 + ipv6_push_rthdr(skb, proto, opt->srcrt2, daddr);
2345 ipv6_push_rthdr(skb, proto, opt->srcrt, daddr);
2348 *((char**)&opt2->auth) += dif;
2350 *((char**)&opt2->srcrt) += dif;
2352 + *((char**)&opt2->srcrt2) += dif;
2356 --- linux-2.4.27/net/ipv6/icmp.c~mipv6-1.1-v2.4.26
2357 +++ linux-2.4.27/net/ipv6/icmp.c
2359 #include <net/addrconf.h>
2360 #include <net/icmp.h>
2362 +#include <net/mipglue.h>
2364 #include <asm/uaccess.h>
2365 #include <asm/system.h>
2371 + icmpv6_swap_mipv6_addrs(skb);
2373 ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, len, NULL, -1,
2375 if (type >= ICMPV6_DEST_UNREACH && type <= ICMPV6_PARAMPROB)
2376 @@ -562,13 +566,13 @@
2377 rt6_pmtu_discovery(&orig_hdr->daddr, &orig_hdr->saddr, dev,
2378 ntohl(hdr->icmp6_mtu));
2381 - * Drop through to notify
2383 + icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
2386 case ICMPV6_DEST_UNREACH:
2387 - case ICMPV6_TIME_EXCEED:
2388 case ICMPV6_PARAMPROB:
2389 + mipv6_icmp_rcv(skb);
2390 + case ICMPV6_TIME_EXCEED:
2391 icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
2394 @@ -598,6 +602,13 @@
2395 case ICMPV6_MLD2_REPORT:
2398 + case MIPV6_DHAAD_REQUEST:
2399 + case MIPV6_DHAAD_REPLY:
2400 + case MIPV6_PREFIX_SOLICIT:
2401 + case MIPV6_PREFIX_ADV:
2402 + mipv6_icmp_rcv(skb);
2406 if (net_ratelimit())
2407 printk(KERN_DEBUG "icmpv6: msg of unkown type\n");
2408 --- linux-2.4.27/net/ipv6/ip6_fib.c~mipv6-1.1-v2.4.26
2409 +++ linux-2.4.27/net/ipv6/ip6_fib.c
2411 * Yuji SEKIYA @USAGI: Support default route on router node;
2412 * remove ip6_null_entry from the top of
2414 + * Ville Nuorvala: Fixes to source address based routing
2416 #include <linux/config.h>
2417 #include <linux/errno.h>
2419 #include <net/ip6_route.h>
2422 -#undef CONFIG_IPV6_SUBTREES
2425 #define RT6_TRACE(x...) printk(KERN_DEBUG x)
2427 mod_timer(&ip6_fib_timer, jiffies + ip6_rt_gc_interval);
2430 +static struct rt6_info * fib6_find_prefix(struct fib6_node *fn);
2433 * Add routing information to the routing tree.
2434 * <destination addr>/<source addr>
2435 @@ -508,17 +510,19 @@
2437 int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nlmsghdr *nlh)
2439 - struct fib6_node *fn;
2440 + struct fib6_node *fn = root;
2443 - fn = fib6_add_1(root, &rt->rt6i_dst.addr, sizeof(struct in6_addr),
2444 - rt->rt6i_dst.plen, (u8*) &rt->rt6i_dst - (u8*) rt);
2445 +#ifdef CONFIG_IPV6_SUBTREES
2446 + struct fib6_node *pn = NULL;
2448 + fn = fib6_add_1(root, &rt->rt6i_src.addr, sizeof(struct in6_addr),
2449 + rt->rt6i_src.plen, (u8*) &rt->rt6i_src - (u8*) rt);
2454 -#ifdef CONFIG_IPV6_SUBTREES
2455 - if (rt->rt6i_src.plen) {
2456 + if (rt->rt6i_dst.plen) {
2457 struct fib6_node *sn;
2459 if (fn->subtree == NULL) {
2462 /* Now add the first leaf node to new subtree */
2464 - sn = fib6_add_1(sfn, &rt->rt6i_src.addr,
2465 - sizeof(struct in6_addr), rt->rt6i_src.plen,
2466 - (u8*) &rt->rt6i_src - (u8*) rt);
2467 + sn = fib6_add_1(sfn, &rt->rt6i_dst.addr,
2468 + sizeof(struct in6_addr), rt->rt6i_dst.plen,
2469 + (u8*) &rt->rt6i_dst - (u8*) rt);
2472 /* If it is failed, discard just allocated
2473 @@ -562,21 +566,30 @@
2474 /* Now link new subtree to main tree */
2477 - if (fn->leaf == NULL) {
2479 - atomic_inc(&rt->rt6i_ref);
2482 - sn = fib6_add_1(fn->subtree, &rt->rt6i_src.addr,
2483 - sizeof(struct in6_addr), rt->rt6i_src.plen,
2484 - (u8*) &rt->rt6i_src - (u8*) rt);
2485 + sn = fib6_add_1(fn->subtree, &rt->rt6i_dst.addr,
2486 + sizeof(struct in6_addr), rt->rt6i_dst.plen,
2487 + (u8*) &rt->rt6i_dst - (u8*) rt);
2493 + /* fib6_add_1 might have cleared the old leaf pointer */
2494 + if (fn->leaf == NULL) {
2496 + atomic_inc(&rt->rt6i_ref);
2503 + fn = fib6_add_1(root, &rt->rt6i_dst.addr, sizeof(struct in6_addr),
2504 + rt->rt6i_dst.plen, (u8*) &rt->rt6i_dst - (u8*) rt);
2510 err = fib6_add_rt2node(fn, rt, nlh);
2511 @@ -588,8 +601,30 @@
2517 +#ifdef CONFIG_IPV6_SUBTREES
2519 + /* If fib6_add_1 has cleared the old leaf pointer in the
2520 + super-tree leaf node, we have to find a new one for it.
2522 + This situation will never arise in the sub-tree since
2523 + the node will at least have the route that caused
2524 + fib6_add_rt2node to fail.
2527 + if (pn && !(pn->fn_flags & RTN_RTINFO)) {
2528 + pn->leaf = fib6_find_prefix(pn);
2531 + BUG_TRAP(pn->leaf);
2532 + pn->leaf = &ip6_null_entry;
2535 + atomic_inc(&pn->leaf->rt6i_ref);
2538 dst_free(&rt->u.dst);
2542 #ifdef CONFIG_IPV6_SUBTREES
2544 is orphan. If it is, shoot it.
2547 - if (fn && !(fn->fn_flags&RTN_RTINFO|RTN_ROOT))
2548 - fib_repair_tree(fn);
2549 + if (fn && !(fn->fn_flags & (RTN_RTINFO | RTN_ROOT)))
2550 + fib6_repair_tree(fn);
2551 dst_free(&rt->u.dst);
2554 @@ -641,22 +676,28 @@
2558 - while ((fn->fn_flags & RTN_ROOT) == 0) {
2560 #ifdef CONFIG_IPV6_SUBTREES
2562 - struct fib6_node *st;
2563 - struct lookup_args *narg;
2568 - st = fib6_lookup_1(fn->subtree, narg);
2569 + struct rt6key *key;
2571 - if (st && !(st->fn_flags & RTN_ROOT))
2573 + key = (struct rt6key *) ((u8 *) fn->leaf +
2576 + if (addr_match(&key->addr, args->addr, key->plen)) {
2577 + struct fib6_node *st;
2578 + struct lookup_args *narg = args + 1;
2579 + if (!ipv6_addr_any(narg->addr)) {
2580 + st = fib6_lookup_1(fn->subtree, narg);
2582 + if (st && !(st->fn_flags & RTN_ROOT))
2588 + if (fn->fn_flags & RTN_ROOT)
2591 if (fn->fn_flags & RTN_RTINFO) {
2593 @@ -680,13 +721,22 @@
2594 struct lookup_args args[2];
2595 struct rt6_info *rt = NULL;
2596 struct fib6_node *fn;
2597 +#ifdef CONFIG_IPV6_SUBTREES
2598 + struct in6_addr saddr_buf;
2601 +#ifdef CONFIG_IPV6_SUBTREES
2602 + if (saddr == NULL) {
2603 + memset(&saddr_buf, 0, sizeof(struct in6_addr));
2604 + saddr = &saddr_buf;
2606 + args[0].offset = (u8*) &rt->rt6i_src - (u8*) rt;
2607 + args[0].addr = saddr;
2608 + args[1].offset = (u8*) &rt->rt6i_dst - (u8*) rt;
2609 + args[1].addr = daddr;
2611 args[0].offset = (u8*) &rt->rt6i_dst - (u8*) rt;
2612 args[0].addr = daddr;
2614 -#ifdef CONFIG_IPV6_SUBTREES
2615 - args[1].offset = (u8*) &rt->rt6i_src - (u8*) rt;
2616 - args[1].addr = saddr;
2619 fn = fib6_lookup_1(root, args);
2620 @@ -739,19 +789,25 @@
2622 struct rt6_info *rt = NULL;
2623 struct fib6_node *fn;
2625 - fn = fib6_locate_1(root, daddr, dst_len,
2626 - (u8*) &rt->rt6i_dst - (u8*) rt);
2628 #ifdef CONFIG_IPV6_SUBTREES
2630 - BUG_TRAP(saddr!=NULL);
2633 + struct in6_addr saddr_buf;
2635 + if (saddr == NULL) {
2636 + memset(&saddr_buf, 0, sizeof(struct in6_addr));
2637 + saddr = &saddr_buf;
2639 + fn = fib6_locate_1(root, saddr, src_len,
2640 + (u8*) &rt->rt6i_src - (u8*) rt);
2643 - fn = fib6_locate_1(fn, saddr, src_len,
2644 - (u8*) &rt->rt6i_src - (u8*) rt);
2645 + fn = fib6_locate_1(fn->subtree, daddr, dst_len,
2646 + (u8*) &rt->rt6i_dst - (u8*) rt);
2651 + fn = fib6_locate_1(root, daddr, dst_len,
2652 + (u8*) &rt->rt6i_dst - (u8*) rt);
2655 if (fn && fn->fn_flags&RTN_RTINFO)
2660 - /* No more references are possiible at this point. */
2661 + /* No more references are possible at this point. */
2662 if (atomic_read(&rt->rt6i_ref) != 1) BUG();
2665 --- linux-2.4.27/net/ipv6/ip6_input.c~mipv6-1.1-v2.4.26
2666 +++ linux-2.4.27/net/ipv6/ip6_input.c
2668 #include <net/ip6_route.h>
2669 #include <net/addrconf.h>
2671 +static inline int ip6_proxy_chk(struct sk_buff *skb)
2673 + struct ipv6hdr *hdr = skb->nh.ipv6h;
2675 + if (ipv6_addr_type(&hdr->daddr)&IPV6_ADDR_UNICAST &&
2676 + pneigh_lookup(&nd_tbl, &hdr->daddr, skb->dev, 0)) {
2677 + u8 nexthdr = hdr->nexthdr;
2679 + struct icmp6hdr msg;
2681 + if (ipv6_ext_hdr(nexthdr)) {
2682 + offset = ipv6_skip_exthdr(skb, sizeof(*hdr), &nexthdr,
2683 + skb->len - sizeof(*hdr));
2687 + offset = sizeof(*hdr);
2689 + /* capture unicast NUD probes on behalf of the proxied node */
2691 + if (nexthdr == IPPROTO_ICMPV6 &&
2692 + !skb_copy_bits(skb, offset, &msg, sizeof(msg)) &&
2693 + msg.icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) {
2700 static inline int ip6_rcv_finish( struct sk_buff *skb)
2702 - if (skb->dst == NULL)
2703 - ip6_route_input(skb);
2705 + if (skb->dst == NULL) {
2706 + if (ip6_proxy_chk(skb))
2707 + return ip6_input(skb);
2708 + ip6_route_input(skb);
2710 return skb->dst->input(skb);
2713 --- linux-2.4.27/net/ipv6/ip6_output.c~mipv6-1.1-v2.4.26
2714 +++ linux-2.4.27/net/ipv6/ip6_output.c
2716 #include <net/rawv6.h>
2717 #include <net/icmp.h>
2719 +#include <net/mipglue.h>
2721 static __inline__ void ipv6_select_ident(struct sk_buff *skb, struct frag_hdr *fhdr)
2723 static u32 ipv6_fragmentation_id = 1;
2724 @@ -194,7 +196,14 @@
2725 u8 proto = fl->proto;
2726 int seg_len = skb->len;
2729 + struct ipv6_txoptions *orig_opt = opt;
2731 + opt = ip6_add_mipv6_txoptions(sk, skb, orig_opt, fl, &dst);
2733 + if(orig_opt && !opt)
2739 @@ -209,8 +218,11 @@
2740 struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room);
2744 + if (skb == NULL) {
2745 + ip6_free_mipv6_txoptions(opt, orig_opt);
2750 skb_set_owner_w(skb, sk);
2752 @@ -242,7 +254,10 @@
2754 if (skb->len <= dst->pmtu) {
2755 IP6_INC_STATS(Ip6OutRequests);
2756 - return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_maybe_reroute);
2757 + ip6_mark_mipv6_packet(opt, skb);
2758 + retval = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_maybe_reroute);
2759 + ip6_free_mipv6_txoptions(opt, orig_opt);
2763 if (net_ratelimit())
2765 skb->dev = dst->dev;
2766 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst->pmtu, skb->dev);
2769 + ip6_free_mipv6_txoptions(opt, orig_opt);
2776 IP6_INC_STATS(Ip6FragCreates);
2777 IP6_INC_STATS(Ip6OutRequests);
2778 + ip6_mark_mipv6_packet(opt, skb);
2779 err = NF_HOOK(PF_INET6,NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_maybe_reroute);
2781 kfree_skb(last_skb);
2783 IP6_INC_STATS(Ip6FragCreates);
2784 IP6_INC_STATS(Ip6FragOKs);
2785 IP6_INC_STATS(Ip6OutRequests);
2786 + ip6_mark_mipv6_packet(opt, last_skb);
2787 return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, last_skb, NULL,dst->dev, ip6_maybe_reroute);
2790 @@ -509,26 +529,43 @@
2791 struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
2792 struct in6_addr *final_dst = NULL;
2793 struct dst_entry *dst;
2794 + struct rt6_info *rt;
2796 unsigned int pktlength, jumbolen, mtu;
2797 struct in6_addr saddr;
2798 + struct ipv6_txoptions *orig_opt = opt;
2799 +#ifdef CONFIG_IPV6_SUBTREES
2800 + struct dst_entry *org_dst;
2803 + opt = ip6_add_mipv6_txoptions(sk, NULL, orig_opt, fl, NULL);
2805 + if(orig_opt && !opt)
2808 if (opt && opt->srcrt) {
2809 struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
2810 final_dst = fl->fl6_dst;
2811 fl->fl6_dst = rt0->addr;
2813 + } else if (opt && opt->srcrt2) {
2814 + struct rt2_hdr *rt2 = (struct rt2_hdr *) opt->srcrt2;
2815 + final_dst = fl->fl6_dst;
2816 + fl->fl6_dst = &rt2->addr;
2819 if (!fl->oif && ipv6_addr_is_multicast(fl->nl_u.ip6_u.daddr))
2820 fl->oif = np->mcast_oif;
2822 dst = __sk_dst_check(sk, np->dst_cookie);
2823 +#ifdef CONFIG_IPV6_SUBTREES
2827 - struct rt6_info *rt = (struct rt6_info*)dst;
2828 + rt = (struct rt6_info*)dst;
2830 /* Yes, checking route validity in not connected
2831 case is not very simple. Take into account,
2832 - that we do not support routing by source, TOS,
2833 + that we do not support routing by TOS,
2834 and MSG_DONTROUTE --ANK (980726)
2836 1. If route was host route, check that
2837 @@ -548,6 +585,13 @@
2838 ipv6_addr_cmp(fl->fl6_dst, &rt->rt6i_dst.addr))
2839 && (np->daddr_cache == NULL ||
2840 ipv6_addr_cmp(fl->fl6_dst, np->daddr_cache)))
2841 +#ifdef CONFIG_IPV6_SUBTREES
2842 + || (fl->fl6_src != NULL
2843 + && (rt->rt6i_src.plen != 128 ||
2844 + ipv6_addr_cmp(fl->fl6_src, &rt->rt6i_src.addr))
2845 + && (np->saddr_cache == NULL ||
2846 + ipv6_addr_cmp(fl->fl6_src, np->saddr_cache)))
2848 || (fl->oif && fl->oif != dst->dev->ifindex)) {
2851 @@ -560,21 +604,42 @@
2853 IP6_INC_STATS(Ip6OutNoRoutes);
2855 + ip6_free_mipv6_txoptions(opt, orig_opt);
2856 return -ENETUNREACH;
2859 if (fl->fl6_src == NULL) {
2860 err = ipv6_get_saddr(dst, fl->fl6_dst, &saddr);
2864 printk(KERN_DEBUG "ip6_build_xmit: "
2865 "no available source address\n");
2868 +#ifdef CONFIG_IPV6_SUBTREES
2869 + if (dst != org_dst) {
2876 fl->fl6_src = &saddr;
2878 +#ifdef CONFIG_IPV6_SUBTREES
2879 + rt = (struct rt6_info*)dst;
2880 + if (dst != org_dst || rt->rt6i_src.plen != 128 ||
2881 + ipv6_addr_cmp(fl->fl6_src, &rt->rt6i_src.addr)) {
2883 + dst = ip6_route_output(sk, fl);
2885 + IP6_INC_STATS(Ip6OutNoRoutes);
2887 + ip6_free_mipv6_txoptions(opt, orig_opt);
2888 + return -ENETUNREACH;
2898 IP6_INC_STATS(Ip6OutRequests);
2899 + ip6_mark_mipv6_packet(opt, skb);
2900 err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_maybe_reroute);
2903 @@ -688,9 +754,14 @@
2907 - ip6_dst_store(sk, dst, fl->nl_u.ip6_u.daddr == &np->daddr ? &np->daddr : NULL);
2908 + ip6_dst_store(sk, dst,
2909 + fl->nl_u.ip6_u.daddr == &np->daddr ? &np->daddr : NULL,
2910 + fl->nl_u.ip6_u.saddr == &np->saddr ? &np->saddr : NULL);
2912 err = np->recverr ? net_xmit_errno(err) : 0;
2914 + ip6_free_mipv6_txoptions(opt, orig_opt);
2919 @@ -769,6 +840,15 @@
2923 + /* The proxying router can't forward traffic sent to a link-local
2924 + address, so signal the sender and discard the packet. This
2925 + behavior is required by the MIPv6 specification. */
2927 + if (ipv6_addr_type(&hdr->daddr) & IPV6_ADDR_LINKLOCAL &&
2928 + skb->dev && pneigh_lookup(&nd_tbl, &hdr->daddr, skb->dev, 0)) {
2929 + dst_link_failure(skb);
2932 /* IPv6 specs say nothing about it, but it is clear that we cannot
2933 send redirects to source routed frames.
2935 --- linux-2.4.27/net/ipv6/ipv6_syms.c~mipv6-1.1-v2.4.26
2936 +++ linux-2.4.27/net/ipv6/ipv6_syms.c
2938 #include <net/ipv6.h>
2939 #include <net/addrconf.h>
2940 #include <net/ip6_route.h>
2941 +#include <net/ndisc.h>
2942 +#include <net/mipglue.h>
2944 EXPORT_SYMBOL(ipv6_addr_type);
2945 EXPORT_SYMBOL(icmpv6_send);
2947 EXPORT_SYMBOL(in6_dev_finish_destroy);
2948 EXPORT_SYMBOL(ipv6_skip_exthdr);
2950 +#if defined(CONFIG_IPV6_TUNNEL_MODULE) || defined(CONFIG_IPV6_MOBILITY_MODULE)
2951 +EXPORT_SYMBOL(ip6_build_xmit);
2952 +EXPORT_SYMBOL(rt6_lookup);
2953 +EXPORT_SYMBOL(ipv6_ext_hdr);
2955 +#ifdef CONFIG_IPV6_MOBILITY_MODULE
2956 +EXPORT_SYMBOL(mipv6_functions);
2957 +EXPORT_SYMBOL(mipv6_invalidate_calls);
2958 +#if defined(CONFIG_IPV6_MOBILITY_HA_MODULE) || defined(CONFIG_IPV6_MOBILITY_MN_MODULE)
2959 +EXPORT_SYMBOL(ip6_route_add);
2960 +EXPORT_SYMBOL(ip6_route_del);
2961 +EXPORT_SYMBOL(ipv6_get_lladdr);
2962 +EXPORT_SYMBOL(ipv6_get_ifaddr);
2963 +EXPORT_SYMBOL(nd_tbl);
2964 +EXPORT_SYMBOL(ndisc_send_ns);
2965 +EXPORT_SYMBOL(ndisc_send_na);
2966 +EXPORT_SYMBOL(ndisc_next_option);
2967 +EXPORT_SYMBOL(inet6_ifa_finish_destroy);
2969 +#ifdef CONFIG_IPV6_MOBILITY_HA_MODULE
2970 +EXPORT_SYMBOL(ipv6_dev_ac_dec);
2971 +EXPORT_SYMBOL(ipv6_dev_ac_inc);
2972 +EXPORT_SYMBOL(ipv6_dev_mc_dec);
2973 +EXPORT_SYMBOL(ipv6_dev_mc_inc);
2974 +EXPORT_SYMBOL(ip6_forward);
2975 +EXPORT_SYMBOL(ip6_input);
2976 +EXPORT_SYMBOL(ipv6_chk_acast_addr);
2978 +#ifdef CONFIG_IPV6_MOBILITY_MN_MODULE
2980 +EXPORT_SYMBOL(addrconf_add_ifaddr);
2981 +EXPORT_SYMBOL(addrconf_del_ifaddr);
2982 +EXPORT_SYMBOL(addrconf_dad_start);
2983 +EXPORT_SYMBOL(ip6_del_rt);
2984 +EXPORT_SYMBOL(ip6_routing_table);
2985 +EXPORT_SYMBOL(rt6_get_dflt_router);
2986 +EXPORT_SYMBOL(rt6_purge_dflt_routers);
2987 +EXPORT_SYMBOL(rt6_lock);
2988 +EXPORT_SYMBOL(ndisc_send_rs);
2989 +EXPORT_SYMBOL(fib6_clean_tree);
2990 +EXPORT_SYMBOL(ipv6_del_addr);
2991 +EXPORT_SYMBOL(ipv6_generate_eui64);
2992 +EXPORT_SYMBOL(ipv6_inherit_eui64);
2995 +++ linux-2.4.27/net/ipv6/ipv6_tunnel.c
2998 + * IPv6 over IPv6 tunnel device
2999 + * Linux INET6 implementation
3002 + * Ville Nuorvala <vnuorval@tcs.hut.fi>
3007 + * linux/net/ipv6/sit.c
3011 + * This program is free software; you can redistribute it and/or
3012 + * modify it under the terms of the GNU General Public License
3013 + * as published by the Free Software Foundation; either version
3014 + * 2 of the License, or (at your option) any later version.
3018 +#include <linux/config.h>
3019 +#include <linux/module.h>
3020 +#include <linux/errno.h>
3021 +#include <linux/types.h>
3022 +#include <linux/socket.h>
3023 +#include <linux/sockios.h>
3024 +#include <linux/if.h>
3025 +#include <linux/in.h>
3026 +#include <linux/ip.h>
3027 +#include <linux/if_tunnel.h>
3028 +#include <linux/net.h>
3029 +#include <linux/in6.h>
3030 +#include <linux/netdevice.h>
3031 +#include <linux/if_arp.h>
3032 +#include <linux/icmpv6.h>
3033 +#include <linux/init.h>
3034 +#include <linux/route.h>
3035 +#include <linux/rtnetlink.h>
3036 +#include <linux/tqueue.h>
3038 +#include <asm/uaccess.h>
3039 +#include <asm/atomic.h>
3041 +#include <net/sock.h>
3042 +#include <net/ipv6.h>
3043 +#include <net/protocol.h>
3044 +#include <net/ip6_route.h>
3045 +#include <net/addrconf.h>
3046 +#include <net/ipv6_tunnel.h>
3048 +MODULE_AUTHOR("Ville Nuorvala");
3049 +MODULE_DESCRIPTION("IPv6-in-IPv6 tunnel");
3050 +MODULE_LICENSE("GPL");
3052 +#define IPV6_TLV_TEL_DST_SIZE 8
3054 +#ifdef IP6_TNL_DEBUG
3055 +#define IP6_TNL_TRACE(x...) printk(KERN_DEBUG "%s:" x "\n", __FUNCTION__)
3057 +#define IP6_TNL_TRACE(x...) do {;} while(0)
3060 +#define IPV6_TCLASS_MASK (IPV6_FLOWINFO_MASK & ~IPV6_FLOWLABEL_MASK)
3062 +#define HASH_SIZE 32
3064 +#define HASH(addr) (((addr)->s6_addr32[0] ^ (addr)->s6_addr32[1] ^ \
3065 + (addr)->s6_addr32[2] ^ (addr)->s6_addr32[3]) & \
3068 +static int ip6ip6_fb_tnl_dev_init(struct net_device *dev);
3069 +static int ip6ip6_tnl_dev_init(struct net_device *dev);
3071 +/* the IPv6 IPv6 tunnel fallback device */
3072 +static struct net_device ip6ip6_fb_tnl_dev = {
3074 + init: ip6ip6_fb_tnl_dev_init
3077 +/* the IPv6 IPv6 fallback tunnel */
3078 +static struct ip6_tnl ip6ip6_fb_tnl = {
3079 + dev: &ip6ip6_fb_tnl_dev,
3080 + parms:{name: "ip6tnl0", proto: IPPROTO_IPV6}
3083 +/* lists for storing tunnels in use */
3084 +static struct ip6_tnl *tnls_r_l[HASH_SIZE];
3085 +static struct ip6_tnl *tnls_wc[1];
3086 +static struct ip6_tnl **tnls[2] = { tnls_wc, tnls_r_l };
3088 +/* list for unused cached kernel tunnels */
3089 +static struct ip6_tnl *tnls_kernel[1];
3090 +/* maximum number of cached kernel tunnels */
3091 +static unsigned int max_kdev_count = 0;
3092 +/* minimum number of cached kernel tunnels */
3093 +static unsigned int min_kdev_count = 0;
3094 +/* current number of cached kernel tunnels */
3095 +static unsigned int kdev_count = 0;
3097 +/* lists for tunnel hook functions */
3098 +static struct list_head hooks[IP6_TNL_MAXHOOKS];
3100 +/* locks for the different lists */
3101 +static rwlock_t ip6ip6_lock = RW_LOCK_UNLOCKED;
3102 +static rwlock_t ip6ip6_kernel_lock = RW_LOCK_UNLOCKED;
3103 +static rwlock_t ip6ip6_hook_lock = RW_LOCK_UNLOCKED;
3105 +/* flag indicating if the module is being removed */
3106 +static int shutdown = 0;
3109 + * ip6ip6_tnl_lookup - fetch tunnel matching the end-point addresses
3110 + * @remote: the address of the tunnel exit-point
3111 + * @local: the address of the tunnel entry-point
3114 + * tunnel matching given end-points if found,
3115 + * else fallback tunnel if its device is up,
3120 +ip6ip6_tnl_lookup(struct in6_addr *remote, struct in6_addr *local)
3122 + unsigned h0 = HASH(remote);
3123 + unsigned h1 = HASH(local);
3124 + struct ip6_tnl *t;
3126 + for (t = tnls_r_l[h0 ^ h1]; t; t = t->next) {
3127 + if (!ipv6_addr_cmp(local, &t->parms.laddr) &&
3128 + !ipv6_addr_cmp(remote, &t->parms.raddr) &&
3129 + (t->dev->flags & IFF_UP))
3132 + if ((t = tnls_wc[0]) != NULL && (t->dev->flags & IFF_UP))
3139 + * ip6ip6_bucket - get head of list matching given tunnel parameters
3140 + * @p: parameters containing tunnel end-points
3143 + * ip6ip6_bucket() returns the head of the list matching the
3144 + * &struct in6_addr entries laddr and raddr in @p.
3146 + * Return: head of IPv6 tunnel list
3149 +static struct ip6_tnl **
3150 +ip6ip6_bucket(struct ip6_tnl_parm *p)
3152 + struct in6_addr *remote = &p->raddr;
3153 + struct in6_addr *local = &p->laddr;
3157 + if (!ipv6_addr_any(remote) || !ipv6_addr_any(local)) {
3159 + h = HASH(remote) ^ HASH(local);
3161 + return &tnls[prio][h];
3165 + * ip6ip6_kernel_tnl_link - add new kernel tunnel to cache
3166 + * @t: kernel tunnel
3169 + * %IP6_TNL_F_KERNEL_DEV is assumed to be raised in t->parms.flags.
3170 + * See the comments on ip6ip6_kernel_tnl_add() for more information.
3174 +ip6ip6_kernel_tnl_link(struct ip6_tnl *t)
3176 + write_lock_bh(&ip6ip6_kernel_lock);
3177 + t->next = tnls_kernel[0];
3178 + tnls_kernel[0] = t;
3180 + write_unlock_bh(&ip6ip6_kernel_lock);
3184 + * ip6ip6_kernel_tnl_unlink - remove first kernel tunnel from cache
3186 + * Return: first free kernel tunnel
3189 + * See the comments on ip6ip6_kernel_tnl_add() for more information.
3192 +static inline struct ip6_tnl *
3193 +ip6ip6_kernel_tnl_unlink(void)
3195 + struct ip6_tnl *t;
3197 + write_lock_bh(&ip6ip6_kernel_lock);
3198 + if ((t = tnls_kernel[0]) != NULL) {
3199 + tnls_kernel[0] = t->next;
3202 + write_unlock_bh(&ip6ip6_kernel_lock);
3207 + * ip6ip6_tnl_link - add tunnel to hash table
3208 + * @t: tunnel to be added
3212 +ip6ip6_tnl_link(struct ip6_tnl *t)
3214 + struct ip6_tnl **tp = ip6ip6_bucket(&t->parms);
3216 + write_lock_bh(&ip6ip6_lock);
3219 + write_unlock_bh(&ip6ip6_lock);
3223 + * ip6ip6_tnl_unlink - remove tunnel from hash table
3224 + * @t: tunnel to be removed
3228 +ip6ip6_tnl_unlink(struct ip6_tnl *t)
3230 + struct ip6_tnl **tp;
3232 + write_lock_bh(&ip6ip6_lock);
3233 + for (tp = ip6ip6_bucket(&t->parms); *tp; tp = &(*tp)->next) {
3239 + write_unlock_bh(&ip6ip6_lock);
3243 + * ip6ip6_tnl_create() - create a new tunnel
3244 + * @p: tunnel parameters
3245 + * @pt: pointer to new tunnel
3248 + * Create tunnel matching given parameters. New kernel managed devices are
3249 + * not put in the normal hash structure, but are instead cached for later
3257 +static int __ip6ip6_tnl_create(struct ip6_tnl_parm *p,
3258 + struct ip6_tnl **pt,
3261 + struct net_device *dev;
3262 + int err = -ENOBUFS;
3263 + struct ip6_tnl *t;
3265 + MOD_INC_USE_COUNT;
3266 + dev = kmalloc(sizeof (*dev) + sizeof (*t), GFP_KERNEL);
3268 + MOD_DEC_USE_COUNT;
3271 + memset(dev, 0, sizeof (*dev) + sizeof (*t));
3272 + dev->priv = (void *) (dev + 1);
3273 + t = (struct ip6_tnl *) dev->priv;
3275 + dev->init = ip6ip6_tnl_dev_init;
3276 + dev->features |= NETIF_F_DYNALLOC;
3277 + if (kernel_list) {
3278 + memcpy(t->parms.name, p->name, IFNAMSIZ - 1);
3279 + t->parms.proto = IPPROTO_IPV6;
3280 + t->parms.flags = IP6_TNL_F_KERNEL_DEV;
3282 + memcpy(&t->parms, p, sizeof (*p));
3284 + t->parms.name[IFNAMSIZ - 1] = '\0';
3285 + strcpy(dev->name, t->parms.name);
3286 + if (!dev->name[0]) {
3288 + for (i = 0; i < IP6_TNL_MAX; i++) {
3289 + sprintf(dev->name, "ip6tnl%d", i);
3290 + if (__dev_get_by_name(dev->name) == NULL)
3294 + if (i == IP6_TNL_MAX) {
3297 + memcpy(t->parms.name, dev->name, IFNAMSIZ);
3299 + if ((err = register_netdevice(dev)) < 0) {
3303 + if (kernel_list) {
3304 + ip6ip6_kernel_tnl_link(t);
3306 + ip6ip6_tnl_link(t);
3312 + MOD_DEC_USE_COUNT;
3317 +int ip6ip6_tnl_create(struct ip6_tnl_parm *p, struct ip6_tnl **pt)
3319 + return __ip6ip6_tnl_create(p, pt, 0);
3323 +static void manage_kernel_tnls(void *foo);
3325 +static struct tq_struct manager_task = {
3326 + routine:manage_kernel_tnls,
3331 + * manage_kernel_tnls() - create and destroy kernel tunnels
3334 + * manage_kernel_tnls() creates new kernel devices if there
3335 + * are less than $min_kdev_count of them and deletes old ones if
3336 + * there are less than $max_kdev_count of them in the cache
3339 + * Schedules itself to be run later in process context if called from
3340 + * interrupt. Therefore only works synchronously when called from process
3345 +manage_kernel_tnls(void *foo)
3347 + struct ip6_tnl *t = NULL;
3348 + struct ip6_tnl_parm parm;
3350 + /* We can't do this processing in interrupt
3351 + context so schedule it for later */
3352 + if (in_interrupt()) {
3353 + read_lock(&ip6ip6_kernel_lock);
3355 + (kdev_count < min_kdev_count ||
3356 + kdev_count > max_kdev_count)) {
3357 + schedule_task(&manager_task);
3359 + read_unlock(&ip6ip6_kernel_lock);
3364 + read_lock_bh(&ip6ip6_kernel_lock);
3365 + memset(&parm, 0, sizeof (parm));
3366 + parm.flags = IP6_TNL_F_KERNEL_DEV;
3367 + /* Create tunnels until there are at least min_kdev_count */
3368 + while (kdev_count < min_kdev_count) {
3369 + read_unlock_bh(&ip6ip6_kernel_lock);
3370 + if (!__ip6ip6_tnl_create(&parm, &t, 1)) {
3375 + read_lock_bh(&ip6ip6_kernel_lock);
3378 + /* Destroy tunnels until there are at most max_kdev_count */
3379 + while (kdev_count > max_kdev_count) {
3380 + read_unlock_bh(&ip6ip6_kernel_lock);
3381 + if ((t = ip6ip6_kernel_tnl_unlink()) != NULL) {
3382 + unregister_netdevice(t->dev);
3386 + read_lock_bh(&ip6ip6_kernel_lock);
3388 + read_unlock_bh(&ip6ip6_kernel_lock);
3394 + * ip6ip6_tnl_inc_max_kdev_count() - increase max kernel dev cache size
3395 + * @n: size increase
3397 + * Increase the upper limit for the number of kernel devices allowed in the
3398 + * cache at any on time.
3402 +ip6ip6_tnl_inc_max_kdev_count(unsigned int n)
3404 + write_lock_bh(&ip6ip6_kernel_lock);
3405 + max_kdev_count += n;
3406 + write_unlock_bh(&ip6ip6_kernel_lock);
3407 + manage_kernel_tnls(NULL);
3408 + return max_kdev_count;
3412 + * ip6ip6_tnl_dec_max_kdev_count() - decrease max kernel dev cache size
3413 + * @n: size decrement
3415 + * Decrease the upper limit for the number of kernel devices allowed in the
3416 + * cache at any on time.
3420 +ip6ip6_tnl_dec_max_kdev_count(unsigned int n)
3422 + write_lock_bh(&ip6ip6_kernel_lock);
3423 + max_kdev_count -= min(max_kdev_count, n);
3424 + if (max_kdev_count < min_kdev_count)
3425 + min_kdev_count = max_kdev_count;
3426 + write_unlock_bh(&ip6ip6_kernel_lock);
3427 + manage_kernel_tnls(NULL);
3428 + return max_kdev_count;
3432 + * ip6ip6_tnl_inc_min_kdev_count() - increase min kernel dev cache size
3433 + * @n: size increase
3435 + * Increase the lower limit for the number of kernel devices allowed in the
3436 + * cache at any on time.
3440 +ip6ip6_tnl_inc_min_kdev_count(unsigned int n)
3442 + write_lock_bh(&ip6ip6_kernel_lock);
3443 + min_kdev_count += n;
3444 + if (min_kdev_count > max_kdev_count)
3445 + max_kdev_count = min_kdev_count;
3446 + write_unlock_bh(&ip6ip6_kernel_lock);
3447 + manage_kernel_tnls(NULL);
3448 + return min_kdev_count;
3452 + * ip6ip6_tnl_dec_min_kdev_count() - decrease min kernel dev cache size
3453 + * @n: size decrement
3455 + * Decrease the lower limit for the number of kernel devices allowed in the
3456 + * cache at any on time.
3460 +ip6ip6_tnl_dec_min_kdev_count(unsigned int n)
3462 + write_lock_bh(&ip6ip6_kernel_lock);
3463 + min_kdev_count -= min(min_kdev_count, n);
3464 + write_unlock_bh(&ip6ip6_kernel_lock);
3465 + manage_kernel_tnls(NULL);
3466 + return min_kdev_count;
3470 + * ip6ip6_tnl_locate - find or create tunnel matching given parameters
3471 + * @p: tunnel parameters
3472 + * @create: != 0 if allowed to create new tunnel if no match found
3475 + * ip6ip6_tnl_locate() first tries to locate an existing tunnel
3476 + * based on @parms. If this is unsuccessful, but @create is set a new
3477 + * tunnel device is created and registered for use.
3480 + * 0 if tunnel located or created,
3481 + * -EINVAL if parameters incorrect,
3482 + * -ENODEV if no matching tunnel available
3485 +int ip6ip6_tnl_locate(struct ip6_tnl_parm *p, struct ip6_tnl **pt, int create)
3487 + struct in6_addr *remote = &p->raddr;
3488 + struct in6_addr *local = &p->laddr;
3489 + struct ip6_tnl *t;
3491 + if (p->proto != IPPROTO_IPV6)
3494 + for (t = *ip6ip6_bucket(p); t; t = t->next) {
3495 + if (!ipv6_addr_cmp(local, &t->parms.laddr) &&
3496 + !ipv6_addr_cmp(remote, &t->parms.raddr)) {
3498 + return (create ? -EEXIST : 0);
3501 + return ip6ip6_tnl_create(p, pt);
3505 + * ip6ip6_tnl_dev_destructor - tunnel device destructor
3506 + * @dev: the device to be destroyed
3510 +ip6ip6_tnl_dev_destructor(struct net_device *dev)
3512 + if (dev != &ip6ip6_fb_tnl_dev) {
3513 + MOD_DEC_USE_COUNT;
3518 + * ip6ip6_tnl_dev_uninit - tunnel device uninitializer
3519 + * @dev: the device to be destroyed
3522 + * ip6ip6_tnl_dev_uninit() removes tunnel from its list
3526 +ip6ip6_tnl_dev_uninit(struct net_device *dev)
3528 + struct ip6_tnl *t = (struct ip6_tnl *) dev->priv;
3530 + if (dev == &ip6ip6_fb_tnl_dev) {
3531 + write_lock_bh(&ip6ip6_lock);
3532 + tnls_wc[0] = NULL;
3533 + write_unlock_bh(&ip6ip6_lock);
3535 + ip6ip6_tnl_unlink(t);
3537 + sock_release(t->sock);
3542 + * parse_tvl_tnl_enc_lim - handle encapsulation limit option
3543 + * @skb: received socket buffer
3546 + * 0 if none was found,
3547 + * else index to encapsulation limit
3551 +parse_tlv_tnl_enc_lim(struct sk_buff *skb, __u8 * raw)
3553 + struct ipv6hdr *ipv6h = (struct ipv6hdr *) raw;
3554 + __u8 nexthdr = ipv6h->nexthdr;
3555 + __u16 off = sizeof (*ipv6h);
3557 + while (ipv6_ext_hdr(nexthdr) && nexthdr != NEXTHDR_NONE) {
3559 + struct ipv6_opt_hdr *hdr;
3560 + if (raw + off + sizeof (*hdr) > skb->data &&
3561 + !pskb_may_pull(skb, raw - skb->data + off + sizeof (*hdr)))
3564 + hdr = (struct ipv6_opt_hdr *) (raw + off);
3565 + if (nexthdr == NEXTHDR_FRAGMENT) {
3566 + struct frag_hdr *frag_hdr = (struct frag_hdr *) hdr;
3567 + if (frag_hdr->frag_off)
3570 + } else if (nexthdr == NEXTHDR_AUTH) {
3571 + optlen = (hdr->hdrlen + 2) << 2;
3573 + optlen = ipv6_optlen(hdr);
3575 + if (nexthdr == NEXTHDR_DEST) {
3576 + __u16 i = off + 2;
3578 + struct ipv6_tlv_tnl_enc_lim *tel;
3580 + /* No more room for encapsulation limit */
3581 + if (i + sizeof (*tel) > off + optlen)
3584 + tel = (struct ipv6_tlv_tnl_enc_lim *) &raw[i];
3585 + /* return index of option if found and valid */
3586 + if (tel->type == IPV6_TLV_TNL_ENCAP_LIMIT &&
3589 + /* else jump to next option */
3591 + i += tel->length + 2;
3596 + nexthdr = hdr->nexthdr;
3603 + * ip6ip6_err - tunnel error handler
3606 + * ip6ip6_err() should handle errors in the tunnel according
3607 + * to the specifications in RFC 2473.
3610 +void ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
3611 + int type, int code, int offset, __u32 info)
3613 + struct ipv6hdr *ipv6h = (struct ipv6hdr *) skb->data;
3614 + struct ip6_tnl *t;
3616 + int rel_type = ICMPV6_DEST_UNREACH;
3617 + int rel_code = ICMPV6_ADDR_UNREACH;
3618 + __u32 rel_info = 0;
3621 + /* If the packet doesn't contain the original IPv6 header we are
3622 + in trouble since we might need the source address for furter
3623 + processing of the error. */
3625 + read_lock(&ip6ip6_lock);
3626 + if ((t = ip6ip6_tnl_lookup(&ipv6h->daddr, &ipv6h->saddr)) == NULL)
3631 + struct ipv6_tlv_tnl_enc_lim *tel;
3633 + case ICMPV6_DEST_UNREACH:
3634 + if (net_ratelimit())
3635 + printk(KERN_WARNING
3636 + "%s: Path to destination invalid "
3637 + "or inactive!\n", t->parms.name);
3640 + case ICMPV6_TIME_EXCEED:
3641 + if (code == ICMPV6_EXC_HOPLIMIT) {
3642 + if (net_ratelimit())
3643 + printk(KERN_WARNING
3644 + "%s: Too small hop limit or "
3645 + "routing loop in tunnel!\n",
3650 + case ICMPV6_PARAMPROB:
3651 + /* ignore if parameter problem not caused by a tunnel
3652 + encapsulation limit sub-option */
3653 + if (code != ICMPV6_HDR_FIELD) {
3656 + teli = parse_tlv_tnl_enc_lim(skb, skb->data);
3658 + if (teli && teli == ntohl(info) - 2) {
3659 + tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->data[teli];
3660 + if (tel->encap_limit == 0) {
3661 + if (net_ratelimit())
3662 + printk(KERN_WARNING
3663 + "%s: Too small encapsulation "
3664 + "limit or routing loop in "
3665 + "tunnel!\n", t->parms.name);
3670 + case ICMPV6_PKT_TOOBIG:
3671 + mtu = ntohl(info) - offset;
3672 + if (mtu < IPV6_MIN_MTU)
3673 + mtu = IPV6_MIN_MTU;
3674 + t->dev->mtu = mtu;
3676 + if ((len = sizeof (*ipv6h) + ipv6h->payload_len) > mtu) {
3677 + rel_type = ICMPV6_PKT_TOOBIG;
3684 + if (rel_msg && pskb_may_pull(skb, offset + sizeof (*ipv6h))) {
3685 + struct rt6_info *rt;
3686 + struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
3690 + dst_release(skb2->dst);
3692 + skb_pull(skb2, offset);
3693 + skb2->nh.raw = skb2->data;
3695 + /* Try to guess incoming interface */
3696 + rt = rt6_lookup(&skb2->nh.ipv6h->saddr, NULL, 0, 0);
3698 + if (rt && rt->rt6i_dev)
3699 + skb2->dev = rt->rt6i_dev;
3701 + icmpv6_send(skb2, rel_type, rel_code, rel_info, skb2->dev);
3704 + dst_release(&rt->u.dst);
3709 + read_unlock(&ip6ip6_lock);
3713 + * call_hooks - call ipv6 tunnel hooks
3714 + * @hooknum: hook number, either %IP6_TNL_PRE_ENCAP, or
3715 + * %IP6_TNL_PRE_DECAP
3716 + * @t: the current tunnel
3717 + * @skb: the tunneled packet
3720 + * Pass packet to all the hook functions until %IP6_TNL_DROP
3723 + * %IP6_TNL_ACCEPT or %IP6_TNL_DROP
3727 +call_hooks(unsigned int hooknum, struct ip6_tnl *t, struct sk_buff *skb)
3729 + struct ip6_tnl_hook_ops *h;
3730 + int accept = IP6_TNL_ACCEPT;
3732 + if (hooknum < IP6_TNL_MAXHOOKS) {
3733 + struct list_head *i;
3734 + read_lock(&ip6ip6_hook_lock);
3735 + for (i = hooks[hooknum].next; i != &hooks[hooknum]; i = i->next) {
3736 + h = (struct ip6_tnl_hook_ops *) i;
3739 + accept = h->hook(t, skb);
3741 + if (accept != IP6_TNL_ACCEPT)
3745 + read_unlock(&ip6ip6_hook_lock);
3751 + * ip6ip6_rcv - decapsulate IPv6 packet and retransmit it locally
3752 + * @skb: received socket buffer
3757 +int ip6ip6_rcv(struct sk_buff *skb)
3759 + struct ipv6hdr *ipv6h;
3760 + struct ip6_tnl *t;
3762 + if (!pskb_may_pull(skb, sizeof (*ipv6h)))
3765 + ipv6h = skb->nh.ipv6h;
3767 + read_lock(&ip6ip6_lock);
3769 + if ((t = ip6ip6_tnl_lookup(&ipv6h->saddr, &ipv6h->daddr)) != NULL) {
3770 + if (!(t->parms.flags & IP6_TNL_F_CAP_RCV) ||
3771 + call_hooks(IP6_TNL_PRE_DECAP, t, skb) != IP6_TNL_ACCEPT) {
3772 + t->stat.rx_dropped++;
3773 + read_unlock(&ip6ip6_lock);
3776 + skb->mac.raw = skb->nh.raw;
3777 + skb->nh.raw = skb->data;
3778 + skb->protocol = htons(ETH_P_IPV6);
3779 + skb->pkt_type = PACKET_HOST;
3780 + memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
3781 + skb->dev = t->dev;
3782 + dst_release(skb->dst);
3784 + t->stat.rx_packets++;
3785 + t->stat.rx_bytes += skb->len;
3787 + read_unlock(&ip6ip6_lock);
3790 + read_unlock(&ip6ip6_lock);
3791 + icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, skb->dev);
3797 +static inline struct ipv6_txoptions *create_tel(__u8 encap_limit)
3799 + struct ipv6_tlv_tnl_enc_lim *tel;
3800 + struct ipv6_txoptions *opt;
3803 + int opt_len = sizeof(*opt) + IPV6_TLV_TEL_DST_SIZE;
3805 + if (!(opt = kmalloc(opt_len, GFP_ATOMIC))) {
3808 + memset(opt, 0, opt_len);
3809 + opt->tot_len = opt_len;
3810 + opt->dst0opt = (struct ipv6_opt_hdr *) (opt + 1);
3811 + opt->opt_nflen = 8;
3813 + tel = (struct ipv6_tlv_tnl_enc_lim *) (opt->dst0opt + 1);
3814 + tel->type = IPV6_TLV_TNL_ENCAP_LIMIT;
3816 + tel->encap_limit = encap_limit;
3818 + raw = (__u8 *) opt->dst0opt;
3819 + raw[5] = IPV6_TLV_PADN;
3826 +ip6ip6_getfrag(const void *data, struct in6_addr *addr,
3827 + char *buff, unsigned int offset, unsigned int len)
3829 + memcpy(buff, data + offset, len);
3834 + * ip6ip6_tnl_addr_conflict - compare packet addresses to tunnel's own
3835 + * @t: the outgoing tunnel device
3836 + * @hdr: IPv6 header from the incoming packet
3839 + * Avoid trivial tunneling loop by checking that tunnel exit-point
3840 + * doesn't match source of incoming packet.
3848 +ip6ip6_tnl_addr_conflict(struct ip6_tnl *t, struct ipv6hdr *hdr)
3850 + return !ipv6_addr_cmp(&t->parms.raddr, &hdr->saddr);
3854 + * ip6ip6_tnl_xmit - encapsulate packet and send
3855 + * @skb: the outgoing socket buffer
3856 + * @dev: the outgoing tunnel device
3859 + * Build new header and do some sanity checks on the packet before sending
3860 + * it to ip6_build_xmit().
3866 +int ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
3868 + struct ip6_tnl *t = (struct ip6_tnl *) dev->priv;
3869 + struct net_device_stats *stats = &t->stat;
3870 + struct ipv6hdr *ipv6h = skb->nh.ipv6h;
3871 + struct ipv6_txoptions *opt = NULL;
3872 + int encap_limit = -1;
3876 + struct dst_entry *dst;
3877 + struct sock *sk = t->sock->sk;
3878 + struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
3881 + if (t->recursion++) {
3882 + stats->collisions++;
3885 + if (skb->protocol != htons(ETH_P_IPV6) ||
3886 + !(t->parms.flags & IP6_TNL_F_CAP_XMIT) ||
3887 + ip6ip6_tnl_addr_conflict(t, ipv6h)) {
3890 + if ((offset = parse_tlv_tnl_enc_lim(skb, skb->nh.raw)) > 0) {
3891 + struct ipv6_tlv_tnl_enc_lim *tel;
3892 + tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->nh.raw[offset];
3893 + if (tel->encap_limit == 0) {
3894 + icmpv6_send(skb, ICMPV6_PARAMPROB,
3895 + ICMPV6_HDR_FIELD, offset + 2, skb->dev);
3898 + encap_limit = tel->encap_limit - 1;
3899 + } else if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) {
3900 + encap_limit = t->parms.encap_limit;
3902 + if (call_hooks(IP6_TNL_PRE_ENCAP, t, skb) != IP6_TNL_ACCEPT)
3904 + memcpy(&fl, &t->fl, sizeof (fl));
3906 + if ((t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS))
3907 + fl.fl6_flowlabel |= (*(__u32 *) ipv6h & IPV6_TCLASS_MASK);
3908 + if ((t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL))
3909 + fl.fl6_flowlabel |= (*(__u32 *) ipv6h & IPV6_FLOWLABEL_MASK);
3911 + if (encap_limit >= 0 && (opt = create_tel(encap_limit)) == NULL)
3914 + dst = __sk_dst_check(sk, np->dst_cookie);
3917 + if (np->daddr_cache == NULL ||
3918 + ipv6_addr_cmp(fl.fl6_dst, np->daddr_cache) ||
3919 +#ifdef CONFIG_IPV6_SUBTREES
3920 + np->saddr_cache == NULL ||
3921 + ipv6_addr_cmp(fl.fl6_src, np->saddr_cache) ||
3923 + (fl.oif && fl.oif != dst->dev->ifindex)) {
3929 + if (dst == NULL) {
3930 + dst = ip6_route_output(sk, &fl);
3932 + stats->tx_carrier_errors++;
3933 + dst_link_failure(skb);
3934 + goto tx_err_dst_release;
3936 + /* local routing loop */
3937 + if (dst->dev == dev) {
3938 + stats->collisions++;
3939 + if (net_ratelimit())
3940 + printk(KERN_WARNING
3941 + "%s: Local routing loop detected!\n",
3943 + goto tx_err_dst_release;
3946 + mtu = dst->pmtu - sizeof (*ipv6h);
3948 + mtu -= (opt->opt_nflen + opt->opt_flen);
3950 + if (mtu < IPV6_MIN_MTU)
3951 + mtu = IPV6_MIN_MTU;
3952 + if (skb->dst && mtu < skb->dst->pmtu) {
3953 + struct rt6_info *rt = (struct rt6_info *) skb->dst;
3954 + rt->rt6i_flags |= RTF_MODIFIED;
3955 + rt->u.dst.pmtu = mtu;
3957 + if (skb->len > mtu) {
3958 + icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev);
3959 + goto tx_err_dst_release;
3961 + ip6_dst_store(sk, dst, &np->daddr, &np->saddr);
3962 + err = ip6_build_xmit(sk, ip6ip6_getfrag, (void *) skb->nh.raw,
3963 + &fl, skb->len, opt, t->parms.hop_limit,
3966 + if (err == NET_XMIT_SUCCESS || err == NET_XMIT_CN) {
3967 + stats->tx_bytes += skb->len;
3968 + stats->tx_packets++;
3970 + stats->tx_errors++;
3971 + stats->tx_aborted_errors++;
3978 +tx_err_dst_release:
3983 + stats->tx_errors++;
3985 + stats->tx_dropped++;
3991 +static void ip6_tnl_set_cap(struct ip6_tnl *t)
3993 + struct ip6_tnl_parm *p = &t->parms;
3994 + struct in6_addr *laddr = &p->laddr;
3995 + struct in6_addr *raddr = &p->raddr;
3996 + int ltype = ipv6_addr_type(laddr);
3997 + int rtype = ipv6_addr_type(raddr);
3999 + p->flags &= ~(IP6_TNL_F_CAP_XMIT|IP6_TNL_F_CAP_RCV);
4001 + if (ltype != IPV6_ADDR_ANY && rtype != IPV6_ADDR_ANY &&
4003 + (IPV6_ADDR_UNICAST|
4004 + IPV6_ADDR_LOOPBACK|IPV6_ADDR_LINKLOCAL|
4005 + IPV6_ADDR_MAPPED|IPV6_ADDR_RESERVED)) == IPV6_ADDR_UNICAST) {
4006 + struct net_device *ldev = NULL;
4011 + ldev = dev_get_by_index(p->link);
4013 + if ((ltype&IPV6_ADDR_UNICAST) && !ipv6_chk_addr(laddr, ldev))
4016 + if ((rtype&IPV6_ADDR_UNICAST) && ipv6_chk_addr(raddr, NULL))
4019 + if (l_ok && r_ok) {
4020 + if (ltype&IPV6_ADDR_UNICAST)
4021 + p->flags |= IP6_TNL_F_CAP_XMIT;
4022 + if (rtype&IPV6_ADDR_UNICAST)
4023 + p->flags |= IP6_TNL_F_CAP_RCV;
4030 +static void ip6ip6_tnl_link_config(struct ip6_tnl *t)
4032 + struct net_device *dev = t->dev;
4033 + struct ip6_tnl_parm *p = &t->parms;
4034 + struct flowi *fl = &t->fl;
4036 + /* Set up flowi template */
4037 + fl->fl6_src = &p->laddr;
4038 + fl->fl6_dst = &p->raddr;
4039 + fl->oif = p->link;
4040 + fl->fl6_flowlabel = 0;
4042 + if (!(p->flags&IP6_TNL_F_USE_ORIG_TCLASS))
4043 + fl->fl6_flowlabel |= IPV6_TCLASS_MASK & htonl(p->flowinfo);
4044 + if (!(p->flags&IP6_TNL_F_USE_ORIG_FLOWLABEL))
4045 + fl->fl6_flowlabel |= IPV6_FLOWLABEL_MASK & htonl(p->flowinfo);
4047 + ip6_tnl_set_cap(t);
4049 + if (p->flags&IP6_TNL_F_CAP_XMIT && p->flags&IP6_TNL_F_CAP_RCV)
4050 + dev->flags |= IFF_POINTOPOINT;
4052 + dev->flags &= ~IFF_POINTOPOINT;
4054 + if (p->flags & IP6_TNL_F_CAP_XMIT) {
4055 + struct rt6_info *rt = rt6_lookup(&p->raddr, &p->laddr,
4061 + if (rt->rt6i_dev) {
4062 + dev->iflink = rt->rt6i_dev->ifindex;
4064 + dev->hard_header_len = rt->rt6i_dev->hard_header_len +
4065 + sizeof (struct ipv6hdr);
4067 + dev->mtu = rt->rt6i_dev->mtu - sizeof (struct ipv6hdr);
4069 + if (dev->mtu < IPV6_MIN_MTU)
4070 + dev->mtu = IPV6_MIN_MTU;
4072 + dst_release(&rt->u.dst);
4077 + * __ip6ip6_tnl_change - update the tunnel parameters
4078 + * @t: tunnel to be changed
4079 + * @p: tunnel configuration parameters
4082 + * __ip6ip6_tnl_change() updates the tunnel parameters
4086 +__ip6ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p)
4088 + ipv6_addr_copy(&t->parms.laddr, &p->laddr);
4089 + ipv6_addr_copy(&t->parms.raddr, &p->raddr);
4090 + t->parms.flags = p->flags;
4091 + t->parms.hop_limit = p->hop_limit;
4092 + t->parms.encap_limit = p->encap_limit;
4093 + t->parms.flowinfo = p->flowinfo;
4094 + ip6ip6_tnl_link_config(t);
4097 +void ip6ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p)
4099 + ip6ip6_tnl_unlink(t);
4100 + __ip6ip6_tnl_change(t, p);
4101 + ip6ip6_tnl_link(t);
4105 + * ip6ip6_kernel_tnl_add - configure and add kernel tunnel to hash
4106 + * @p: kernel tunnel configuration parameters
4109 + * ip6ip6_kernel_tnl_add() fetches an unused kernel tunnel configures
4110 + * it according to @p and places it among the active tunnels.
4113 + * number of references to tunnel on success,
4114 + * %-EEXIST if there is already a device matching description
4115 + * %-EINVAL if p->flags doesn't have %IP6_TNL_F_KERNEL_DEV raised,
4116 + * %-ENODEV if there are no unused kernel tunnels available
4119 + * The code for creating, opening, closing and destroying network devices
4120 + * must be called from process context, while the Mobile IP code, which
4121 + * needs the tunnel devices, unfortunately runs in interrupt context.
4123 + * The devices must be created and opened in advance, then placed in a
4124 + * list where the kernel can fetch and ready them for use at a later time.
4129 +ip6ip6_kernel_tnl_add(struct ip6_tnl_parm *p)
4131 + struct ip6_tnl *t;
4133 + if (!(p->flags & IP6_TNL_F_KERNEL_DEV))
4135 + if ((t = ip6ip6_tnl_lookup(&p->raddr, &p->laddr)) != NULL &&
4136 + t != &ip6ip6_fb_tnl) {
4137 + /* Handle duplicate tunnels by incrementing
4138 + reference count */
4139 + atomic_inc(&t->refcnt);
4142 + if ((t = ip6ip6_kernel_tnl_unlink()) == NULL)
4144 + __ip6ip6_tnl_change(t, p);
4146 + atomic_inc(&t->refcnt);
4148 + ip6ip6_tnl_link(t);
4150 + manage_kernel_tnls(NULL);
4152 + return atomic_read(&t->refcnt);
4156 + * ip6ip6_kernel_tnl_del - delete no longer needed kernel tunnel
4157 + * @t: kernel tunnel to be removed from hash
4160 + * ip6ip6_kernel_tnl_del() removes and deconfigures the tunnel @t
4161 + * and places it among the unused kernel devices.
4164 + * number of references on success,
4165 + * %-EINVAL if p->flags doesn't have %IP6_TNL_F_KERNEL_DEV raised,
4168 + * See the comments on ip6ip6_kernel_tnl_add() for more information.
4172 +ip6ip6_kernel_tnl_del(struct ip6_tnl *t)
4177 + if (!(t->parms.flags & IP6_TNL_F_KERNEL_DEV))
4180 + if (atomic_dec_and_test(&t->refcnt)) {
4181 + struct ip6_tnl_parm p;
4182 + ip6ip6_tnl_unlink(t);
4183 + memset(&p, 0, sizeof (p));
4184 + p.flags = IP6_TNL_F_KERNEL_DEV;
4186 + __ip6ip6_tnl_change(t, &p);
4188 + ip6ip6_kernel_tnl_link(t);
4190 + manage_kernel_tnls(NULL);
4192 + return atomic_read(&t->refcnt);
4196 + * ip6ip6_tnl_ioctl - configure ipv6 tunnels from userspace
4197 + * @dev: virtual device associated with tunnel
4198 + * @ifr: parameters passed from userspace
4199 + * @cmd: command to be performed
4202 + * ip6ip6_tnl_ioctl() is used for managing IPv6 tunnels
4205 + * The possible commands are the following:
4206 + * %SIOCGETTUNNEL: get tunnel parameters for device
4207 + * %SIOCADDTUNNEL: add tunnel matching given tunnel parameters
4208 + * %SIOCCHGTUNNEL: change tunnel parameters to those given
4209 + * %SIOCDELTUNNEL: delete tunnel
4211 + * The fallback device "ip6tnl0", created during module
4212 + * initialization, can be used for creating other tunnel devices.
4216 + * %-EFAULT if unable to copy data to or from userspace,
4217 + * %-EPERM if current process hasn't %CAP_NET_ADMIN set or attempting
4218 + * to configure kernel devices from userspace,
4219 + * %-EINVAL if passed tunnel parameters are invalid,
4220 + * %-EEXIST if changing a tunnel's parameters would cause a conflict
4221 + * %-ENODEV if attempting to change or delete a nonexisting device
4224 + * See the comments on ip6ip6_kernel_tnl_add() for more information
4225 + * about kernel tunnels.
4229 +ip6ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
4233 + struct ip6_tnl_parm p;
4234 + struct ip6_tnl *t = NULL;
4236 + MOD_INC_USE_COUNT;
4239 + case SIOCGETTUNNEL:
4240 + if (dev == &ip6ip6_fb_tnl_dev) {
4241 + if (copy_from_user(&p,
4242 + ifr->ifr_ifru.ifru_data,
4247 + if ((err = ip6ip6_tnl_locate(&p, &t, 0)) == -ENODEV)
4248 + t = (struct ip6_tnl *) dev->priv;
4252 + t = (struct ip6_tnl *) dev->priv;
4254 + memcpy(&p, &t->parms, sizeof (p));
4255 + if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof (p))) {
4259 + case SIOCADDTUNNEL:
4260 + case SIOCCHGTUNNEL:
4262 + create = (cmd == SIOCADDTUNNEL);
4263 + if (!capable(CAP_NET_ADMIN))
4265 + if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p))) {
4269 + if (p.flags & IP6_TNL_F_KERNEL_DEV) {
4272 + if (!create && dev != &ip6ip6_fb_tnl_dev) {
4273 + t = (struct ip6_tnl *) dev->priv;
4275 + if (!t && (err = ip6ip6_tnl_locate(&p, &t, create))) {
4278 + if (cmd == SIOCCHGTUNNEL) {
4279 + if (t->dev != dev) {
4283 + if (t->parms.flags & IP6_TNL_F_KERNEL_DEV) {
4287 + ip6ip6_tnl_change(t, &p);
4288 + netdev_state_change(dev);
4290 + if (copy_to_user(ifr->ifr_ifru.ifru_data,
4291 + &t->parms, sizeof (p))) {
4297 + case SIOCDELTUNNEL:
4299 + if (!capable(CAP_NET_ADMIN))
4302 + if (dev == &ip6ip6_fb_tnl_dev) {
4303 + if (copy_from_user(&p, ifr->ifr_ifru.ifru_data,
4308 + err = ip6ip6_tnl_locate(&p, &t, 0);
4311 + if (t == &ip6ip6_fb_tnl) {
4316 + t = (struct ip6_tnl *) dev->priv;
4318 + if (t->parms.flags & IP6_TNL_F_KERNEL_DEV)
4321 + err = unregister_netdevice(t->dev);
4326 + MOD_DEC_USE_COUNT;
4331 + * ip6ip6_tnl_get_stats - return the stats for tunnel device
4332 + * @dev: virtual device associated with tunnel
4334 + * Return: stats for device
4337 +static struct net_device_stats *
4338 +ip6ip6_tnl_get_stats(struct net_device *dev)
4340 + return &(((struct ip6_tnl *) dev->priv)->stat);
4344 + * ip6ip6_tnl_change_mtu - change mtu manually for tunnel device
4345 + * @dev: virtual device associated with tunnel
4346 + * @new_mtu: the new mtu
4350 + * %-EINVAL if mtu too small
4354 +ip6ip6_tnl_change_mtu(struct net_device *dev, int new_mtu)
4356 + if (new_mtu < IPV6_MIN_MTU) {
4359 + dev->mtu = new_mtu;
4364 + * ip6ip6_tnl_dev_init_gen - general initializer for all tunnel devices
4365 + * @dev: virtual device associated with tunnel
4368 + * Set function pointers and initialize the &struct flowi template used
4373 +ip6ip6_tnl_dev_init_gen(struct net_device *dev)
4375 + struct ip6_tnl *t = (struct ip6_tnl *) dev->priv;
4376 + struct flowi *fl = &t->fl;
4380 + if ((err = sock_create(PF_INET6, SOCK_RAW, IPPROTO_IPV6, &t->sock))) {
4382 + "Failed to create IPv6 tunnel socket (err %d).\n", err);
4385 + t->sock->inode->i_uid = 0;
4386 + t->sock->inode->i_gid = 0;
4389 + sk->allocation = GFP_ATOMIC;
4390 + sk->net_pinfo.af_inet6.hop_limit = 254;
4391 + sk->net_pinfo.af_inet6.mc_loop = 0;
4392 + sk->prot->unhash(sk);
4394 + memset(fl, 0, sizeof (*fl));
4395 + fl->proto = IPPROTO_IPV6;
4397 + dev->destructor = ip6ip6_tnl_dev_destructor;
4398 + dev->uninit = ip6ip6_tnl_dev_uninit;
4399 + dev->hard_start_xmit = ip6ip6_tnl_xmit;
4400 + dev->get_stats = ip6ip6_tnl_get_stats;
4401 + dev->do_ioctl = ip6ip6_tnl_ioctl;
4402 + dev->change_mtu = ip6ip6_tnl_change_mtu;
4404 + dev->type = ARPHRD_TUNNEL6;
4405 + dev->hard_header_len = LL_MAX_HEADER + sizeof (struct ipv6hdr);
4406 + dev->mtu = ETH_DATA_LEN - sizeof (struct ipv6hdr);
4407 + dev->flags |= IFF_NOARP;
4409 + /* Hmm... MAX_ADDR_LEN is 8, so the ipv6 addresses can't be
4410 + copied to dev->dev_addr and dev->broadcast, like the ipv4
4411 + addresses were in ipip.c, ip_gre.c and sit.c. */
4412 + dev->addr_len = 0;
4417 + * ip6ip6_tnl_dev_init - initializer for all non fallback tunnel devices
4418 + * @dev: virtual device associated with tunnel
4422 +ip6ip6_tnl_dev_init(struct net_device *dev)
4424 + struct ip6_tnl *t = (struct ip6_tnl *) dev->priv;
4425 + ip6ip6_tnl_dev_init_gen(dev);
4426 + ip6ip6_tnl_link_config(t);
4433 + * ip6ip6_fb_tnl_open - function called when fallback device opened
4434 + * @dev: fallback device
4440 +ip6ip6_fb_tnl_open(struct net_device *dev)
4442 + MOD_INC_USE_COUNT;
4447 + * ip6ip6_fb_tnl_close - function called when fallback device closed
4448 + * @dev: fallback device
4454 +ip6ip6_fb_tnl_close(struct net_device *dev)
4456 + MOD_DEC_USE_COUNT;
4462 + * ip6ip6_fb_tnl_dev_init - initializer for fallback tunnel device
4463 + * @dev: fallback device
4469 +ip6ip6_fb_tnl_dev_init(struct net_device *dev)
4471 + ip6ip6_tnl_dev_init_gen(dev);
4473 + dev->open = ip6ip6_fb_tnl_open;
4474 + dev->stop = ip6ip6_fb_tnl_close;
4477 + tnls_wc[0] = &ip6ip6_fb_tnl;
4482 + * ip6ip6_tnl_register_hook - add hook for processing of tunneled packets
4483 + * @reg: hook function and its parameters
4486 + * Add a netfilter like hook function for special handling of tunneled
4487 + * packets. The hook functions are called before encapsulation
4488 + * (%IP6_TNL_PRE_ENCAP) and before decapsulation
4489 + * (%IP6_TNL_PRE_DECAP). The possible return values by the hook
4490 + * functions are %IP6_TNL_DROP, %IP6_TNL_ACCEPT and
4491 + * %IP6_TNL_STOLEN (in case the hook function took care of the packet
4492 + * and it doesn't have to be processed any further).
4496 +ip6ip6_tnl_register_hook(struct ip6_tnl_hook_ops *reg)
4498 + if (reg->hooknum < IP6_TNL_MAXHOOKS) {
4499 + struct list_head *i;
4501 + write_lock_bh(&ip6ip6_hook_lock);
4502 + for (i = hooks[reg->hooknum].next;
4503 + i != &hooks[reg->hooknum]; i = i->next) {
4504 + if (reg->priority <
4505 + ((struct ip6_tnl_hook_ops *) i)->priority) {
4509 + list_add(®->list, i->prev);
4510 + write_unlock_bh(&ip6ip6_hook_lock);
4515 + * ip6ip6_tnl_unregister_hook - remove tunnel hook
4516 + * @reg: hook function and its parameters
4520 +ip6ip6_tnl_unregister_hook(struct ip6_tnl_hook_ops *reg)
4522 + if (reg->hooknum < IP6_TNL_MAXHOOKS) {
4523 + write_lock_bh(&ip6ip6_hook_lock);
4524 + list_del(®->list);
4525 + write_unlock_bh(&ip6ip6_hook_lock);
4530 +/* the IPv6 over IPv6 protocol structure */
4531 +static struct inet6_protocol ip6ip6_protocol = {
4532 + ip6ip6_rcv, /* IPv6 handler */
4533 + ip6ip6_err, /* IPv6 error control */
4535 + IPPROTO_IPV6, /* protocol ID */
4538 + "IPv6 over IPv6" /* name */
4542 + * ip6_tunnel_init - register protocol and reserve needed resources
4544 + * Return: 0 on success
4547 +int __init ip6_tunnel_init(void)
4551 + ip6ip6_fb_tnl_dev.priv = (void *) &ip6ip6_fb_tnl;
4553 + for (i = 0; i < IP6_TNL_MAXHOOKS; i++) {
4554 + INIT_LIST_HEAD(&hooks[i]);
4556 + if ((err = register_netdev(&ip6ip6_fb_tnl_dev)))
4559 + inet6_add_protocol(&ip6ip6_protocol);
4564 + * ip6_tunnel_cleanup - free resources and unregister protocol
4567 +void ip6_tunnel_cleanup(void)
4569 + write_lock_bh(&ip6ip6_kernel_lock);
4571 + write_unlock_bh(&ip6ip6_kernel_lock);
4572 + flush_scheduled_tasks();
4573 + manage_kernel_tnls(NULL);
4574 + inet6_del_protocol(&ip6ip6_protocol);
4575 + unregister_netdev(&ip6ip6_fb_tnl_dev);
4579 +module_init(ip6_tunnel_init);
4580 +module_exit(ip6_tunnel_cleanup);
4583 +#if defined(CONFIG_IPV6_MOBILITY_HA_MODULE) || defined(CONFIG_IPV6_MOBILITY_MN_MODULE)
4584 +EXPORT_SYMBOL(ip6ip6_tnl_register_hook);
4585 +EXPORT_SYMBOL(ip6ip6_tnl_unregister_hook);
4587 +#ifdef CONFIG_IPV6_MOBILITY_HA_MODULE
4588 +EXPORT_SYMBOL(ip6ip6_tnl_dec_max_kdev_count);
4589 +EXPORT_SYMBOL(ip6ip6_tnl_inc_max_kdev_count);
4590 +EXPORT_SYMBOL(ip6ip6_tnl_dec_min_kdev_count);
4591 +EXPORT_SYMBOL(ip6ip6_tnl_inc_min_kdev_count);
4592 +EXPORT_SYMBOL(ip6ip6_kernel_tnl_add);
4593 +EXPORT_SYMBOL(ip6ip6_kernel_tnl_del);
4594 +EXPORT_SYMBOL(ip6ip6_tnl_lookup);
4596 +#ifdef CONFIG_IPV6_MOBILITY_MN_MODULE
4597 +EXPORT_SYMBOL(ip6ip6_tnl_create);
4598 +EXPORT_SYMBOL(ip6ip6_tnl_change);
4602 +++ linux-2.4.27/net/ipv6/mipglue.c
4605 + * Glue for Mobility support integration to IPv6
4608 + * Antti Tuominen <ajtuomin@cc.hut.fi>
4612 + * This program is free software; you can redistribute it and/or
4613 + * modify it under the terms of the GNU General Public License
4614 + * as published by the Free Software Foundation; either version
4615 + * 2 of the License, or (at your option) any later version.
4619 +#include <linux/sched.h>
4621 +#include <net/ipv6.h>
4622 +#include <net/addrconf.h>
4623 +#include <net/neighbour.h>
4624 +#include <net/mipglue.h>
4626 +extern int ip6_tlvopt_unknown(struct sk_buff *skb, int optoff);
4628 +/* Initialize all zero */
4629 +struct mipv6_callable_functions mipv6_functions = { NULL };
4631 +/* Sets mipv6_functions struct to zero to invalidate all successive
4632 + * calls to mipv6 functions. Used on module unload. */
4634 +void mipv6_invalidate_calls(void)
4636 + memset(&mipv6_functions, 0, sizeof(mipv6_functions));
4640 +/* Selects correct handler for tlv encoded destination option. Called
4641 + * by ip6_parse_tlv. Checks if mipv6 calls are valid before calling. */
4643 +int mipv6_handle_dstopt(struct sk_buff *skb, int optoff)
4647 + switch (skb->nh.raw[optoff]) {
4648 + case MIPV6_TLV_HOMEADDR:
4649 + ret = MIPV6_CALLFUNC(mipv6_handle_homeaddr, 0)(skb, optoff);
4652 + /* Should never happen */
4653 + printk(KERN_ERR __FILE__ ": Invalid destination option code (%d)\n",
4654 + skb->nh.raw[optoff]);
4659 + /* If mipv6 handlers are not valid, pass the packet to
4660 + * ip6_tlvopt_unknown() for correct handling. */
4662 + return ip6_tlvopt_unknown(skb, optoff);
4668 +++ linux-2.4.27/net/ipv6/mobile_ip6/Config.in
4671 +# Mobile IPv6 Configuration
4673 +dep_tristate ' IPv6: Mobility Support (Correspondent Node)' CONFIG_IPV6_MOBILITY $CONFIG_IPV6
4674 +if [ "$CONFIG_IPV6_IPV6_TUNNEL" != "n" ]; then
4675 + dep_tristate ' MIPv6: Mobile Node Support' CONFIG_IPV6_MOBILITY_MN $CONFIG_IPV6_MOBILITY
4677 + dep_tristate ' MIPv6: Home Agent Support' CONFIG_IPV6_MOBILITY_HA $CONFIG_IPV6_MOBILITY
4679 +if [ "$CONFIG_IPV6_MOBILITY" != "n" ]; then
4680 + bool ' MIPv6: Debug messages' CONFIG_IPV6_MOBILITY_DEBUG
4683 +++ linux-2.4.27/net/ipv6/mobile_ip6/Makefile
4686 +# Makefile for the MIPL Mobile IPv6 for Linux.
4688 +# Note! Dependencies are done automagically by 'make dep', which also
4689 +# removes any old dependencies. DON'T put your own dependencies here
4690 +# unless it's something special (ie not a .c file).
4694 +O_TARGET := mip6_base.o
4696 +list-multi := mip6_ha.o mip6_mn.o
4698 +obj-y := hashlist.o bcache.o mobhdr_common.o stats.o exthdrs.o \
4699 + rr_crypto.o hmac.o auth_opt.o mipv6_icmp.o module_cn.o
4701 +obj-m := $(O_TARGET)
4703 +mip6_ha-objs := halist.o mipv6_icmp_ha.o tunnel_ha.o \
4704 + ndisc_ha.o ha.o module_ha.o
4706 +mip6_mn-objs := mipv6_icmp_mn.o ioctl_mn.o tunnel_mn.o \
4707 + mdetect.o bul.o multiaccess_ctl.o mobhdr_mn.o mn.o \
4710 +obj-$(CONFIG_IPV6_MOBILITY_HA) += mip6_ha.o
4711 +obj-$(CONFIG_IPV6_MOBILITY_MN) += mip6_mn.o
4713 +include $(TOPDIR)/Rules.make
4715 +mip6_ha.o: $(mip6_ha-objs)
4716 + $(LD) -r -o $@ $(mip6_ha-objs)
4718 +mip6_mn.o: $(mip6_mn-objs)
4719 + $(LD) -r -o $@ $(mip6_mn-objs)
4721 +++ linux-2.4.27/net/ipv6/mobile_ip6/README
4723 +MIPL Mobile IPv6 for Linux
4725 +More information at http://www.mipl.mediapoli.com/.
4727 +To join MIPL Mobile IPv6 for Linux mailing lists go to:
4729 + http://www.mipl.mediapoli.com/cgi-bin/mailman/listinfo
4731 +Or send mail with subject "subscribe" for the general list to:
4733 + mipl-request@list.mipl.mediapoli.com
4735 +or for the developer list to:
4737 + mipl-devel-request@list.mail.mediapoli.com
4739 +++ linux-2.4.27/net/ipv6/mobile_ip6/auth_opt.c
4742 + * MIPv6 Binding Authentication Data Option functions
4745 + * Henrik Petander <lpetande@tml.hut.fi>
4749 + * This program is free software; you can redistribute it and/or
4750 + * modify it under the terms of the GNU General Public License
4751 + * as published by the Free Software Foundation; either version
4752 + * 2 of the License, or (at your option) any later version.
4755 +#include <linux/autoconf.h>
4756 +#include <linux/icmpv6.h>
4757 +#include <net/mipv6.h>
4761 +#include "mobhdr.h"
4765 +int mipv6_auth_build(struct in6_addr *cn_addr, struct in6_addr *coa,
4766 + __u8 *mh, __u8 *aud_data, __u8 *k_bu)
4768 + /* First look up the peer from sadb based on his address */
4769 + struct ah_processing ahp;
4771 + /* Don't add any other options or this system is screwed */
4773 + __u8 buf[MAX_HASH_LENGTH];
4777 + DEBUG(DBG_ERROR, "k_bu missing, aborting");
4780 + DEBUG(DBG_KEY, "Key for building authenticator:");
4781 + debug_print_buffer(DBG_KEY, k_bu, HMAC_SHA1_KEY_SIZE);
4783 + if (ah_hmac_sha1_init(&ahp, k_bu, HMAC_SHA1_KEY_SIZE) < 0) {
4784 + DEBUG(DBG_ERROR, "Failed to initialize hmac sha1");
4788 + DEBUG(DBG_KEY, "coa: ");
4789 + debug_print_buffer(DBG_KEY, coa, 16);
4790 + DEBUG(DBG_KEY, "cn_addr: ");
4791 + debug_print_buffer(DBG_KEY, cn_addr, 16);
4792 + DEBUG(DBG_KEY, "MH contents: ");
4793 + debug_print_buffer(DBG_KEY, mh, aud_data - mh);
4795 + /* First the common part */
4796 + ah_hmac_sha1_loop(&ahp, coa, sizeof(struct in6_addr));
4797 + ah_hmac_sha1_loop(&ahp, cn_addr, sizeof(struct in6_addr));
4798 + ah_hmac_sha1_loop(&ahp, mh, aud_data - mh);
4799 + ah_hmac_sha1_result(&ahp, buf);
4801 + memcpy(aud_data, buf, MIPV6_RR_MAC_LENGTH);
4806 +int mipv6_auth_check(struct in6_addr *cn_addr, struct in6_addr *coa,
4807 + __u8 *opt, __u8 optlen,
4808 + struct mipv6_mo_bauth_data *aud, __u8 *k_bu)
4811 + struct ah_processing ahp;
4812 + __u8 htarget[MAX_HASH_LENGTH];
4814 + /* Look up peer by home address */
4816 + DEBUG(DBG_ERROR, "k_bu missing, aborting");
4820 + DEBUG(DBG_KEY, "Key for checking authenticator:");
4821 + debug_print_buffer(DBG_KEY, k_bu, HMAC_SHA1_KEY_SIZE);
4823 + if (!aud || !coa) {
4824 + DEBUG(DBG_INFO, "%s is NULL", aud ? "coa" : "aud");
4828 + if (aud->length != MIPV6_RR_MAC_LENGTH) {
4830 + ": Incorrect authentication option length %d", aud->length);
4834 + if (ah_hmac_sha1_init(&ahp, k_bu, HMAC_SHA1_KEY_SIZE) < 0) {
4836 + "internal error in initialization of authentication algorithm");
4839 + DEBUG(DBG_KEY, "coa: ");
4840 + debug_print_buffer(DBG_KEY, coa, 16);
4841 + DEBUG(DBG_KEY, "cn_addr: ");
4842 + debug_print_buffer(DBG_KEY, cn_addr, 16);
4843 + DEBUG(DBG_KEY, "MH contents: ");
4844 + debug_print_buffer(DBG_KEY, opt, (u8*) aud->data - opt);
4846 + ah_hmac_sha1_loop(&ahp, coa, sizeof(struct in6_addr));
4847 + ah_hmac_sha1_loop(&ahp, cn_addr, sizeof(struct in6_addr));
4850 + * Process MH + options till the start of the authenticator in
4851 + * Auth. data option
4853 + ah_hmac_sha1_loop(&ahp, opt, (u8 *)aud->data - opt);
4854 + ah_hmac_sha1_result(&ahp, htarget);
4855 + if (memcmp(htarget, aud->data, MIPV6_RR_MAC_LENGTH) == 0)
4858 + DEBUG(DBG_ERROR, "returning %d", ret);
4863 +++ linux-2.4.27/net/ipv6/mobile_ip6/bcache.c
4869 + * Juha Mynttinen <jmynttin@cc.hut.fi>
4873 + * This program is free software; you can redistribute it and/or
4874 + * modify it under the terms of the GNU General Public License
4875 + * as published by the Free Software Foundation; either version
4876 + * 2 of the License, or (at your option) any later version.
4882 + * Nanno Langstraat : Timer code cleaned up, active socket
4886 +#include <linux/autoconf.h>
4887 +#include <linux/sched.h>
4888 +#include <linux/timer.h>
4889 +#include <linux/in6.h>
4890 +#include <linux/init.h>
4891 +#include <linux/spinlock.h>
4892 +#include <linux/proc_fs.h>
4893 +#include <linux/ipv6_route.h>
4894 +#include <net/ipv6.h>
4895 +#include <net/addrconf.h>
4896 +#include <net/tcp.h>
4897 +#include <net/udp.h>
4898 +#include <net/ip6_route.h>
4899 +#include <net/mipv6.h>
4901 +#include "bcache.h"
4902 +#include "hashlist.h"
4904 +#include "mobhdr.h"
4905 +#include "tunnel.h"
4906 +#include "config.h"
4908 +#define TIMERDELAY HZ/10
4910 +struct mipv6_bcache {
4911 + struct hashlist *entries;
4913 + struct timer_list callback_timer;
4916 +struct in6_addr_pair {
4917 + struct in6_addr *a1;
4918 + struct in6_addr *a2;
4921 +static rwlock_t bcache_lock = RW_LOCK_UNLOCKED;
4923 +static struct mipv6_bcache bcache;
4925 +static int bcache_proc_info(char *buffer, char **start, off_t offset,
4928 +#define MIPV6_BCACHE_HASHSIZE 32
4930 +/* Moment of transmission of a BR, in seconds before bcache entry expiry */
4931 +#define BCACHE_BR_SEND_LEAD 3
4933 +#define MIPV6_MAX_BRR 3 /* Send 3 BRRs before deleting BC entry */
4934 +#define MIPV6_BRR_RATE HZ /* Send BRRs once per second */
4937 + * Internal functions.
4940 +struct cache_entry_iterator_args {
4941 + struct mipv6_bce **entry;
4944 +static int find_first_cache_entry_iterator(void *data, void *args,
4945 + unsigned long *lifetime)
4947 + struct mipv6_bce *entry =
4948 + (struct mipv6_bce *) data;
4949 + struct cache_entry_iterator_args *state =
4950 + (struct cache_entry_iterator_args *) args;
4952 + ASSERT(entry != NULL);
4954 + if (entry->type == CACHE_ENTRY) {
4955 + *(state->entry) = entry;
4956 + return ITERATOR_STOP; /* stop iteration */
4958 + return ITERATOR_CONT; /* continue iteration */
4964 + * Get memory for a new bcache entry. If bcache is full, a cache
4965 + * entry may be deleted to get space for a home registration, but not
4968 +static struct mipv6_bce *mipv6_bce_alloc(__u8 type)
4970 + struct mipv6_bce *entry;
4971 + struct cache_entry_iterator_args args;
4975 + entry = (struct mipv6_bce *)
4976 + hashlist_alloc(bcache.entries, SLAB_ATOMIC);
4978 + /* Cache replacement policy: always replace the CACHE_ENTRY
4979 + closest to expiration. Type HOME_REGISTRATION entry may
4980 + never be deleted before expiration. */
4981 + if (entry == NULL) {
4982 + /* cache full, try to delete a CACHE_ENTRY */
4983 + args.entry = &entry;
4984 + hashlist_iterate(bcache.entries, &args,
4985 + find_first_cache_entry_iterator);
4986 + if (entry == NULL)
4988 + hashlist_delete(bcache.entries,
4989 + (struct hashlist_entry *)entry);
4990 + entry = (struct mipv6_bce *)
4991 + hashlist_alloc(bcache.entries, SLAB_ATOMIC);
4997 + * Frees entry's memory allocated with mipv6_bce_alloc
4999 +static void mipv6_bce_free(struct mipv6_bce *entry)
5001 + hashlist_free(bcache.entries, (void *) entry);
5005 + * Removes all expired entries
5007 +static void expire(void)
5009 + struct mipv6_bce *entry;
5011 + struct in6_addr daddr;
5012 + struct in6_addr saddr;
5013 + struct br_addrs *next;
5015 + struct br_addrs *br_info = NULL;
5019 + write_lock(&bcache_lock);
5021 + while ((entry = (struct mipv6_bce *)
5022 + hashlist_get_first(bcache.entries)) != NULL) {
5023 + struct rt6_info *rt;
5024 + if (time_after_eq(jiffies, entry->callback_time)) {
5026 + DEBUG(DBG_INFO, "an entry expired");
5028 + if (entry->type & HOME_REGISTRATION) {
5029 + mip6_fn.proxy_del(&entry->home_addr, entry);
5031 + hashlist_delete(bcache.entries, (void *)entry);
5032 + mipv6_bce_free(entry);
5034 + } else if (entry->br_callback_time != 0 &&
5035 + time_after_eq(jiffies, entry->br_callback_time) &&
5036 + entry->br_count < MIPV6_MAX_BRR &&
5037 + (rt = rt6_lookup(&entry->home_addr, &entry->our_addr, 0, 0)) != NULL){
5038 + /* Do we have a destination cache entry for the home address */
5039 + if (rt->rt6i_flags & RTF_CACHE) {
5040 + struct br_addrs *tmp;
5043 + "bcache entry recently used. Sending BR.");
5044 + /* queue for sending */
5045 + br_info = kmalloc(sizeof(struct br_addrs),
5048 + ipv6_addr_copy(&br_info->saddr,
5049 + &entry->our_addr);
5050 + ipv6_addr_copy(&br_info->daddr,
5051 + &entry->home_addr);
5052 + br_info->next = tmp;
5053 + entry->last_br = jiffies;
5054 + entry->br_callback_time = jiffies + MIPV6_BRR_RATE;
5055 + entry->br_count++;
5058 + DEBUG(DBG_ERROR, "Out of memory");
5062 + entry->br_callback_time = 0;
5063 + dst_release(&rt->u.dst);
5065 + entry->br_callback_time = 0;
5069 + write_unlock(&bcache_lock);
5072 + struct br_addrs *tmp = br_info->next;
5073 + if (mipv6_send_brr(&br_info->saddr, &br_info->daddr, NULL) < 0)
5074 + DEBUG(DBG_WARNING,
5075 + "BR send for %x:%x:%x:%x:%x:%x:%x:%x failed",
5076 + NIPV6ADDR(&br_info->daddr));
5082 +static void set_timer(void)
5084 + struct mipv6_bce *entry;
5085 + unsigned long callback_time;
5089 + entry = (struct mipv6_bce *)
5090 + hashlist_get_first(bcache.entries);
5091 + if (entry != NULL) {
5092 + if (entry->br_callback_time > 0 &&
5093 + time_after(entry->br_callback_time, jiffies))
5094 + callback_time = entry->br_callback_time;
5095 + else if (time_after(entry->callback_time, jiffies))
5096 + callback_time = entry->callback_time;
5098 + DEBUG(DBG_WARNING,
5099 + "bcache timer attempted to schedule"
5100 + " for a historical jiffies count!");
5101 + callback_time = jiffies + TIMERDELAY;
5104 + DEBUG(DBG_INFO, "setting timer to now");
5105 + mod_timer(&bcache.callback_timer, callback_time);
5107 + del_timer(&bcache.callback_timer);
5108 + DEBUG(DBG_INFO, "BC empty, not setting a new timer");
5113 + * The function that is scheduled to do the callback functions. May be
5114 + * modified e.g to allow Binding Requests, now only calls expire() and
5115 + * schedules a new timer.
5117 +static void timer_handler(unsigned long dummy)
5120 + write_lock(&bcache_lock);
5122 + write_unlock(&bcache_lock);
5126 + * Interface functions visible to other modules
5130 + * mipv6_bcache_add - add Binding Cache entry
5131 + * @ifindex: interface index
5132 + * @our_addr: own address
5133 + * @home_addr_org: MN's home address
5134 + * @coa: MN's care-of address
5135 + * @lifetime: lifetime for this binding
5136 + * @prefix: prefix length
5137 + * @seq: sequence number
5138 + * @flags: flags received in BU
5139 + * @type: type of entry
5141 + * Adds an entry for this @home_addr_org in the Binding Cache. If entry
5142 + * already exists, old entry is updated. @type may be %CACHE_ENTRY or
5143 + * %HOME_REGISTRATION.
5145 +int mipv6_bcache_add(int ifindex,
5146 + struct in6_addr *our_addr,
5147 + struct in6_addr *home_addr,
5148 + struct in6_addr *coa,
5149 + __u32 lifetime, __u16 seq, __u8 flags, __u8 type)
5151 + struct mipv6_bce *entry;
5153 + int create_tunnel = 0;
5154 + unsigned long now = jiffies;
5155 + struct in6_addr_pair hashkey;
5160 + hashkey.a1 = home_addr;
5161 + hashkey.a2 = our_addr;
5163 + write_lock(&bcache_lock);
5165 + if (type == HOME_REGISTRATION && !(mip6node_cnf.capabilities&CAP_HA))
5168 + if (unlikely(bcache.entries == NULL)) {
5173 + if ((entry = (struct mipv6_bce *)
5174 + hashlist_get(bcache.entries, &hashkey)) != NULL) {
5175 + /* if an entry for this home_addr exists (with smaller
5176 + * seq than the new seq), update it by removing it
5179 + if (!MIPV6_SEQ_GT(seq, entry->seq)) {
5180 + DEBUG(DBG_INFO, "smaller seq than existing, not updating");
5183 + DEBUG(DBG_INFO, "updating an existing entry");
5186 + /* H-flag is already checked in BU handler. */
5187 + /* XXX: Should we care about the other flags?*/
5188 + if (flags != entry->flags) {
5189 + DEBUG(DBG_INFO, "entry/BU flag mismatch");
5192 + if (type == HOME_REGISTRATION) {
5193 + create_tunnel = (ipv6_addr_cmp(&entry->coa, coa) ||
5194 + entry->ifindex != ifindex);
5197 + /* no entry for this home_addr, try to create a new entry */
5198 + DEBUG(DBG_INFO, "creating a new entry");
5201 + entry = mipv6_bce_alloc(type);
5202 + if (entry == NULL) {
5203 + DEBUG(DBG_INFO, "cache full, entry not added");
5207 + create_tunnel = (type == HOME_REGISTRATION);
5210 + if (create_tunnel) {
5212 + mip6_fn.proxy_del(&entry->home_addr, entry);
5213 + if (mip6_fn.proxy_create(flags, ifindex, coa, our_addr, home_addr) < 0) {
5218 + ipv6_addr_copy(&(entry->our_addr), our_addr);
5219 + ipv6_addr_copy(&(entry->home_addr), home_addr);
5220 + ipv6_addr_copy(&(entry->coa), coa);
5221 + entry->ifindex = ifindex;
5223 + entry->type = type;
5224 + entry->flags = flags;
5226 + entry->last_br = 0;
5227 + entry->destunr_count = 0;
5228 + entry->callback_time = now + lifetime * HZ;
5229 + if (entry->type & HOME_REGISTRATION)
5230 + entry->br_callback_time = 0;
5232 + entry->br_callback_time = now +
5233 + (lifetime - BCACHE_BR_SEND_LEAD) * HZ;
5236 + DEBUG(DBG_INFO, "updating entry : %x", entry);
5237 + hashlist_reposition(bcache.entries, (void *)entry,
5238 + entry->callback_time);
5240 + DEBUG(DBG_INFO, "adding entry: %x", entry);
5241 + if ((hashlist_add(bcache.entries,
5243 + entry->callback_time, entry)) < 0) {
5245 + DEBUG(DBG_ERROR, "Hash add failed");
5246 + goto err_hashlist;
5253 + write_unlock(&bcache_lock);
5257 + if (create_tunnel) {
5258 + mip6_fn.proxy_del(home_addr, entry);
5262 + hashlist_delete(bcache.entries, (void *)entry);
5264 + mipv6_bce_free(entry);
5266 + write_unlock(&bcache_lock);
5270 +int mipv6_bcache_icmp_err(struct in6_addr *home_addr,
5271 + struct in6_addr *our_addr,
5272 + int destunr_count)
5274 + struct mipv6_bce *entry;
5275 + struct in6_addr_pair hashkey;
5277 + int ret = -ENOENT;
5281 + hashkey.a1 = home_addr;
5282 + hashkey.a2 = our_addr;
5284 + write_lock(&bcache_lock);
5285 + if (unlikely(bcache.entries == NULL)) {
5290 + if ((entry = (struct mipv6_bce *)
5291 + hashlist_get(bcache.entries, &hashkey)) != NULL) {
5292 + entry->last_destunr = jiffies;
5293 + entry->destunr_count = destunr_count;
5297 + write_unlock(&bcache_lock);
5303 + * mipv6_bcache_delete - delete Binding Cache entry
5304 + * @home_addr: MN's home address
5305 + * @our_addr: our address
5306 + * @type: type of entry
5308 + * Deletes an entry associated with @home_addr from Binding Cache.
5309 + * Valid values for @type are %CACHE_ENTRY, %HOME_REGISTRATION and
5310 + * %ANY_ENTRY. %ANY_ENTRY deletes any type of entry.
5312 +int mipv6_bcache_delete(struct in6_addr *home_addr,
5313 + struct in6_addr *our_addr, __u8 type)
5315 + struct mipv6_bce *entry;
5316 + struct in6_addr_pair hashkey;
5321 + if (home_addr == NULL || our_addr == NULL) {
5322 + DEBUG(DBG_INFO, "error in arguments");
5326 + hashkey.a1 = home_addr;
5327 + hashkey.a2 = our_addr;
5329 + write_lock(&bcache_lock);
5331 + if (unlikely(bcache.entries == NULL) ||
5332 + (entry = (struct mipv6_bce *)
5333 + hashlist_get(bcache.entries, &hashkey)) == NULL ||
5334 + !(entry->type & type)) {
5335 + DEBUG(DBG_INFO, "No matching entry found");
5340 + hashlist_delete(bcache.entries, (void *) entry);
5341 + mipv6_bce_free(entry);
5345 + write_unlock(&bcache_lock);
5350 + * mipv6_bcache_exists - check if entry exists
5351 + * @home_addr: home address to check
5352 + * @our_addr: our address
5354 + * Determines if a binding exists for @home_addr. Returns type of the
5355 + * entry or negative if entry does not exist.
5357 +int mipv6_bcache_exists(struct in6_addr *home_addr,
5358 + struct in6_addr *our_addr)
5360 + struct mipv6_bce *entry;
5361 + struct in6_addr_pair hashkey;
5362 + int type = -ENOENT;
5366 + if (home_addr == NULL || our_addr == NULL)
5369 + hashkey.a1 = home_addr;
5370 + hashkey.a2 = our_addr;
5372 + read_lock(&bcache_lock);
5373 + if (likely(bcache.entries != NULL) &&
5374 + (entry = (struct mipv6_bce *)
5375 + hashlist_get(bcache.entries, &hashkey)) != NULL) {
5376 + type = entry->type;
5378 + read_unlock(&bcache_lock);
5384 + * mipv6_bcache_get - get entry from Binding Cache
5385 + * @home_addr: home address to search
5386 + * @our_addr: our address
5387 + * @entry: pointer to buffer
5389 + * Gets a copy of Binding Cache entry for @home_addr. If entry
5390 + * exists entry is copied to @entry and zero is returned.
5391 + * Otherwise returns negative.
5393 +int mipv6_bcache_get(struct in6_addr *home_addr,
5394 + struct in6_addr *our_addr,
5395 + struct mipv6_bce *entry)
5397 + struct mipv6_bce *entry2;
5398 + struct in6_addr_pair hashkey;
5399 + int ret = -ENOENT;
5403 + if (home_addr == NULL || our_addr == NULL || entry == NULL)
5406 + hashkey.a1 = home_addr;
5407 + hashkey.a2 = our_addr;
5409 + read_lock_bh(&bcache_lock);
5411 + entry2 = (struct mipv6_bce *)
5412 + hashlist_get(bcache.entries, &hashkey);
5413 + if (entry2 != NULL) {
5414 + memcpy(entry, entry2, sizeof(struct mipv6_bce));
5417 + read_unlock_bh(&bcache_lock);
5421 +int mipv6_bcache_iterate(hashlist_iterator_t func, void *args)
5425 + read_lock_bh(&bcache_lock);
5426 + ret = hashlist_iterate(bcache.entries, args, func);
5427 + read_unlock_bh(&bcache_lock);
5433 + * Proc-filesystem functions
5436 +#define BC_INFO_LEN 80
5438 +struct procinfo_iterator_args {
5446 +static int procinfo_iterator(void *data, void *args, unsigned long *pref)
5448 + struct procinfo_iterator_args *arg =
5449 + (struct procinfo_iterator_args *) args;
5450 + struct mipv6_bce *entry =
5451 + (struct mipv6_bce *) data;
5453 + ASSERT(entry != NULL);
5455 + if (arg->skip < arg->offset / BC_INFO_LEN) {
5457 + return ITERATOR_CONT;
5460 + if (arg->len >= arg->length)
5461 + return ITERATOR_CONT;
5463 + /* HoA CoA CallbackInSecs Type */
5464 + arg->len += sprintf(arg->buffer + arg->len,
5465 + "%08x%08x%08x%08x %08x%08x%08x%08x %010lu %02d\n",
5466 + ntohl(entry->home_addr.s6_addr32[0]),
5467 + ntohl(entry->home_addr.s6_addr32[1]),
5468 + ntohl(entry->home_addr.s6_addr32[2]),
5469 + ntohl(entry->home_addr.s6_addr32[3]),
5470 + ntohl(entry->coa.s6_addr32[0]),
5471 + ntohl(entry->coa.s6_addr32[1]),
5472 + ntohl(entry->coa.s6_addr32[2]),
5473 + ntohl(entry->coa.s6_addr32[3]),
5474 + ((entry->callback_time) - jiffies) / HZ,
5475 + (int) entry->type);
5477 + return ITERATOR_CONT;
5481 + * Callback function for proc filesystem.
5483 +static int bcache_proc_info(char *buffer, char **start, off_t offset,
5486 + struct procinfo_iterator_args args;
5490 + args.buffer = buffer;
5491 + args.offset = offset;
5492 + args.length = length;
5496 + read_lock_bh(&bcache_lock);
5497 + hashlist_iterate(bcache.entries, &args, procinfo_iterator);
5498 + read_unlock_bh(&bcache_lock);
5502 + *start += offset % BC_INFO_LEN;
5504 + args.len -= offset % BC_INFO_LEN;
5506 + if (args.len > length)
5507 + args.len = length;
5514 +static int bcache_compare(void *data, void *hashkey)
5516 + struct in6_addr_pair *p = (struct in6_addr_pair *) hashkey;
5517 + struct mipv6_bce *e = (struct mipv6_bce *) data;
5519 + if (ipv6_addr_cmp(&e->home_addr, p->a1) == 0
5520 + && ipv6_addr_cmp(&e->our_addr, p->a2) == 0)
5526 +static __u32 bcache_hash(void *hashkey)
5528 + struct in6_addr_pair *p = (struct in6_addr_pair *) hashkey;
5530 + return p->a1->s6_addr32[0] ^ p->a1->s6_addr32[1] ^
5531 + p->a2->s6_addr32[2] ^ p->a2->s6_addr32[3];
5535 + * Initialization and shutdown functions
5538 +int __init mipv6_bcache_init(__u32 size)
5541 + DEBUG(DBG_ERROR, "Binding cache size must be at least 1");
5544 + bcache.entries = hashlist_create(MIPV6_BCACHE_HASHSIZE, size,
5545 + sizeof(struct mipv6_bce),
5546 + "mip6_bcache", NULL, NULL,
5547 + bcache_compare, bcache_hash);
5549 + if (bcache.entries == NULL) {
5550 + DEBUG(DBG_ERROR, "Failed to initialize hashlist");
5554 + init_timer(&bcache.callback_timer);
5555 + bcache.callback_timer.data = 0;
5556 + bcache.callback_timer.function = timer_handler;
5557 + bcache.size = size;
5559 + proc_net_create("mip6_bcache", 0, bcache_proc_info);
5561 + DEBUG(DBG_INFO, "Binding cache initialized");
5566 +bce_cleanup_iterator(void *rawentry, void *args, unsigned long *sortkey)
5568 + int type = (int) args;
5569 + struct mipv6_bce *entry = (struct mipv6_bce *) rawentry;
5570 + if (entry->type == type) {
5571 + if (entry->type & HOME_REGISTRATION) {
5572 + if (unlikely(mip6_fn.proxy_del == NULL))
5573 + DEBUG(DBG_ERROR, "proxy_del unitialized");
5575 + mip6_fn.proxy_del(&entry->home_addr, entry);
5577 + return ITERATOR_DELETE_ENTRY;
5579 + return ITERATOR_CONT;
5583 +void mipv6_bcache_cleanup(int type)
5585 + write_lock_bh(&bcache_lock);
5586 + hashlist_iterate(bcache.entries,(void *) type, bce_cleanup_iterator);
5587 + write_unlock_bh(&bcache_lock);
5590 +int __exit mipv6_bcache_exit(void)
5592 + struct hashlist *entries;
5596 + proc_net_remove("mip6_bcache");
5598 + write_lock_bh(&bcache_lock);
5599 + DEBUG(DBG_INFO, "Stopping the bcache timer");
5600 + del_timer(&bcache.callback_timer);
5601 + hashlist_iterate(bcache.entries,(void *)CACHE_ENTRY,
5602 + bce_cleanup_iterator);
5604 + entries = bcache.entries;
5605 + bcache.entries = NULL;
5606 + write_unlock_bh(&bcache_lock);
5608 + hashlist_destroy(entries);
5612 +++ linux-2.4.27/net/ipv6/mobile_ip6/bcache.h
5615 + * MIPL Mobile IPv6 Binding Cache header file
5619 + * This program is free software; you can redistribute it and/or
5620 + * modify it under the terms of the GNU General Public License
5621 + * as published by the Free Software Foundation; either version
5622 + * 2 of the License, or (at your option) any later version.
5628 +#include <linux/in6.h>
5629 +#include <linux/timer.h>
5630 +#include "hashlist.h"
5632 +#define CACHE_ENTRY 1 /* this and HOME_REGISTRATION are the entry types */
5633 +#define HOME_REGISTRATION 2
5634 +#define ANY_ENTRY 3
5636 +#define MIPV6_MAX_DESTUNREACH 5 /* Delete CN BCEs after 5 destination unreachables */
5637 +#define MIPV6_DEST_UNR_IVAL 10 /* What is the max interval of destination
5638 + unreacahable error messages for them to be persistent*/
5641 + struct hashlist_entry e;
5642 + int ifindex; /* Interface identifier */
5643 + struct in6_addr our_addr; /* our address (as seen by the MN) */
5644 + struct in6_addr home_addr; /* MN home address */
5645 + struct in6_addr coa; /* MN care-of address */
5646 + unsigned long callback_time; /* time of expiration (in jiffies) */
5647 + unsigned long br_callback_time; /* time for sending a BR (in jiffies) */
5648 + int (*callback_function)(struct mipv6_bce *entry);
5649 + __u8 type; /* home registration */
5650 + __u8 router; /* mn is router */
5651 + __u8 flags; /* flags received in BU */
5652 + __u16 seq; /* sequence number */
5653 + unsigned long last_br; /* time when last BR sent */
5654 + unsigned long last_destunr; /* time when last ICMP destination unreachable received */
5655 + int br_count; /* How many BRRs have sent */
5656 + int destunr_count; /* Number of destination unreachables received */
5659 +int mipv6_bcache_add(int ifindex, struct in6_addr *our_addr,
5660 + struct in6_addr *home_addr, struct in6_addr *coa,
5661 + __u32 lifetime, __u16 seq, __u8 flags, __u8 type);
5663 +int mipv6_bcache_icmp_err(struct in6_addr *home_addr,
5664 + struct in6_addr *our_addr,
5665 + int destunr_count);
5667 +int mipv6_bcache_delete(struct in6_addr *home_addr, struct in6_addr *our_addr,
5670 +int mipv6_bcache_exists(struct in6_addr *home_addr,
5671 + struct in6_addr *our_addr);
5673 +int mipv6_bcache_get(struct in6_addr *home_addr,
5674 + struct in6_addr *our_addr,
5675 + struct mipv6_bce *entry);
5677 +int mipv6_bcache_iterate(int (*func)(void *, void *, unsigned long *), void *args);
5679 +void mipv6_bcache_cleanup(int type);
5681 +int mipv6_bcache_init(__u32 size);
5683 +int mipv6_bcache_exit(void);
5685 +#endif /* _BCACHE_H */
5687 +++ linux-2.4.27/net/ipv6/mobile_ip6/bul.c
5690 + * Binding update list
5693 + * Juha Mynttinen <jmynttin@cc.hut.fi>
5697 + * This program is free software; you can redistribute it and/or
5698 + * modify it under the terms of the GNU General Public License
5699 + * as published by the Free Software Foundation; either version
5700 + * 2 of the License, or (at your option) any later version.
5706 + * Nanno Langstraat : Timer code cleaned up
5709 +#include <linux/autoconf.h>
5710 +#include <linux/sched.h>
5711 +#include <linux/timer.h>
5712 +#include <linux/in6.h>
5713 +#include <linux/init.h>
5714 +#include <linux/spinlock.h>
5715 +#include <net/ipv6.h>
5716 +#include <net/mipv6.h>
5717 +#include <linux/proc_fs.h>
5721 +#include "hashlist.h"
5722 +#include "tunnel_mn.h"
5723 +#include "mobhdr.h"
5725 +#define MIPV6_BUL_HASHSIZE 32
5727 +rwlock_t bul_lock = RW_LOCK_UNLOCKED;
5730 + struct hashlist *entries;
5731 + struct timer_list callback_timer;
5734 +static struct mipv6_bul bul;
5736 +struct in6_addr_pair {
5737 + struct in6_addr *a1;
5738 + struct in6_addr *a2;
5741 +/**********************************************************************
5743 + * Private functions
5745 + **********************************************************************/
5747 +static int bul_compare(void *data, void *hashkey)
5749 + struct in6_addr_pair *p = (struct in6_addr_pair *)hashkey;
5750 + struct mipv6_bul_entry *e = (struct mipv6_bul_entry *)data;
5752 + if (ipv6_addr_cmp(&e->cn_addr, p->a1) == 0
5753 + && ipv6_addr_cmp(&e->home_addr, p->a2) == 0)
5760 + struct in6_addr *addr;
5764 +static int bul_compare_cookie(void *data, void *keys)
5766 + struct test_keys *p = (struct test_keys *)keys;
5767 + struct mipv6_bul_entry *e = (struct mipv6_bul_entry *)data;
5769 + if (ipv6_addr_cmp(&e->cn_addr, p->addr) == 0 && e->rr
5770 + && memcmp(&e->rr->cot_cookie, p->cookie, 8) == 0)
5776 +static u32 bul_hash(void *hashkey)
5778 + struct in6_addr_pair *p = (struct in6_addr_pair *)hashkey;
5780 + return p->a1->s6_addr32[0] ^
5781 + p->a1->s6_addr32[1] ^
5782 + p->a1->s6_addr32[2] ^
5783 + p->a1->s6_addr32[3];
5786 +static int bul_proc_info(char *buffer, char **start, off_t offset,
5789 +static struct mipv6_bul_entry *mipv6_bul_get_entry(void)
5792 + return ((struct mipv6_bul_entry *)
5793 + hashlist_alloc(bul.entries, SLAB_ATOMIC));
5796 +static void mipv6_bul_entry_free(struct mipv6_bul_entry *entry)
5801 + if (entry->rr->kbu)
5802 + kfree(entry->rr->kbu);
5806 + kfree(entry->ops);
5807 + hashlist_free(bul.entries, (void *)entry);
5810 +static __inline__ int del_bul_entry_tnl(struct mipv6_bul_entry *entry)
5812 + if (entry->flags & MIPV6_BU_F_HOME) {
5813 + return mipv6_mv_tnl_to_ha(&entry->cn_addr,
5815 + &entry->home_addr);
5820 +static void timer_update(void)
5822 + struct mipv6_bul_entry *entry;
5826 + entry = hashlist_get_first(bul.entries);
5828 + while (entry && time_after_eq(jiffies, entry->callback_time)) {
5829 + if (time_after_eq(jiffies, entry->expire) ||
5830 + entry->callback(entry) != 0) {
5832 + * Either the entry has expired, or the callback
5833 + * indicated that it should be deleted.
5835 + hashlist_delete(bul.entries, (void *)entry);
5837 + del_bul_entry_tnl(entry);
5838 + mipv6_bul_entry_free(entry);
5839 + DEBUG(DBG_INFO, "Entry deleted (was expired) from "
5840 + "binding update list");
5842 + /* move entry to its right place in the hashlist */
5843 + DEBUG(DBG_INFO, "Rescheduling");
5844 + hashlist_reposition(bul.entries, (void *)entry,
5845 + entry->callback_time);
5847 + entry = (struct mipv6_bul_entry *)
5848 + hashlist_get_first(bul.entries);
5851 + if (entry == NULL) {
5852 + DEBUG(DBG_INFO, "bul empty, not setting a new timer");
5853 + del_timer(&bul.callback_timer);
5855 + mod_timer(&bul.callback_timer, entry->callback_time);
5859 +static void timer_handler(unsigned long dummy)
5863 + write_lock(&bul_lock);
5865 + write_unlock(&bul_lock);
5868 +/**********************************************************************
5870 + * Public interface functions
5872 + **********************************************************************/
5875 + * mipv6_bul_iterate - apply interator function to all entries
5876 + * @func: function to apply
5877 + * @args: extra arguments for iterator
5879 + * Applies @func for each entry in Binding Update List. Extra
5880 + * arguments given in @args are also passed to the iterator function.
5881 + * Caller must hold @bul_lock.
5883 +int mipv6_bul_iterate(hashlist_iterator_t func, void *args)
5887 + return hashlist_iterate(bul.entries, args, func);
5891 + * mipv6_bul_exists - check if Binding Update List entry exists
5892 + * @cn: address to check
5894 + * Checks if Binding Update List has an entry for @cn. Returns true
5895 + * if entry exists, false otherwise. Caller may not hold @bul_lock.
5897 +int mipv6_bul_exists(struct in6_addr *cn, struct in6_addr *haddr)
5900 + struct in6_addr_pair hashkey;
5905 + hashkey.a2 = haddr;
5907 + read_lock_bh(&bul_lock);
5909 + if (unlikely(bul.entries == NULL))
5912 + exists = (hashlist_get(bul.entries, &hashkey) != NULL);
5914 + read_unlock_bh(&bul_lock);
5919 + * mipv6_bul_get - get Binding Update List entry
5920 + * @cn_addr: CN address to search
5921 + * @home_addr: home address to search
5923 + * Returns Binding Update List entry for @cn_addr if it exists.
5924 + * Otherwise returns %NULL. Caller must hold @bul_lock.
5926 +struct mipv6_bul_entry *mipv6_bul_get(struct in6_addr *cn_addr,
5927 + struct in6_addr *home_addr)
5929 + struct mipv6_bul_entry *entry;
5930 + struct in6_addr_pair hashkey;
5934 + if (unlikely(bul.entries == NULL)) {
5937 + hashkey.a1 = cn_addr;
5938 + hashkey.a2 = home_addr;
5940 + entry = (struct mipv6_bul_entry *)
5941 + hashlist_get(bul.entries, &hashkey);
5946 +struct mipv6_bul_entry *mipv6_bul_get_by_ccookie(
5947 + struct in6_addr *cn_addr, u8 *cookie)
5949 + struct test_keys key;
5953 + if (unlikely(bul.entries == NULL))
5955 + key.addr = cn_addr;
5956 + key.cookie = cookie;
5958 + return (struct mipv6_bul_entry *)
5959 + hashlist_get_ex(bul.entries, &key,
5960 + bul_compare_cookie);
5964 + * mipv6_bul_reschedule - reschedule Binding Update List entry
5965 + * @entry: entry to reschedule
5967 + * Reschedules a Binding Update List entry. Must be called after
5968 + * modifying entry lifetime. Caller must hold @bul_lock (write).
5970 +void mipv6_bul_reschedule(struct mipv6_bul_entry *entry)
5974 + hashlist_reposition(bul.entries,
5976 + entry->callback_time);
5981 + * mipv6_bul_add - add binding update to Binding Update List
5982 + * @cn_addr: IPv6 address where BU was sent
5983 + * @home_addr: Home address for this binding
5984 + * @coa: Care-of address for this binding
5985 + * @lifetime: expiration time of the binding in seconds
5986 + * @seq: sequence number of the BU
5987 + * @flags: %MIPV6_BU_F_* flags
5988 + * @callback: callback function called on expiration
5989 + * @callback_time: expiration time for callback
5990 + * @state: binding send state
5991 + * @delay: retransmission delay
5992 + * @maxdelay: retransmission maximum delay
5993 + * @ops: Mobility header options for BU
5994 + * @rr: Return routability information
5996 + * Adds a binding update sent to @cn_addr for @home_addr to the
5997 + * Binding Update List. If entry already exists, it is updated.
5998 + * Entry is set to expire in @lifetime seconds. Entry has a callback
5999 + * function @callback that is called at @callback_time. Entry @state
6000 + * controls resending of this binding update and it can be set to
6001 + * %ACK_OK, %RESEND_EXP or %ACK_ERROR. Returns a pointer to the newly
6002 + * created or updated entry. Caller must hold @bul_lock (write).
6004 +struct mipv6_bul_entry *mipv6_bul_add(
6005 + struct in6_addr *cn_addr, struct in6_addr *home_addr,
6006 + struct in6_addr *coa,
6007 + __u32 lifetime, __u16 seq, __u8 flags,
6008 + int (*callback)(struct mipv6_bul_entry *entry),
6009 + __u32 callback_time,
6010 + __u8 state, __u32 delay, __u32 maxdelay,
6011 + struct mipv6_mh_opt *ops,
6012 + struct mipv6_rr_info *rr)
6014 + struct mipv6_bul_entry *entry;
6016 + struct in6_addr_pair hashkey;
6020 + if (unlikely(bul.entries == NULL))
6023 + if (cn_addr == NULL || home_addr == NULL || coa == NULL ||
6024 + lifetime < 0 || callback == NULL || callback_time < 0 ||
6025 + (state != ACK_OK && state != RESEND_EXP && state != ACK_ERROR) ||
6026 + delay < 0 || maxdelay < 0) {
6027 + DEBUG(DBG_ERROR, "invalid arguments");
6030 + DEBUG(DBG_INFO, "cn_addr: %x:%x:%x:%x:%x:%x:%x:%x, "
6031 + "home_addr: %x:%x:%x:%x:%x:%x:%x:%x"
6032 + "coaddr: %x:%x:%x:%x:%x:%x:%x:%x", NIPV6ADDR(cn_addr),
6033 + NIPV6ADDR(home_addr), NIPV6ADDR(coa));
6034 + hashkey.a1 = cn_addr;
6035 + hashkey.a2 = home_addr;
6038 + * decide whether to add a new entry or update existing, also
6039 + * check if there's room for a new entry when adding a new
6040 + * entry (latter is handled by mipv6_bul_get_entry()
6042 + if ((entry = (struct mipv6_bul_entry *)
6043 + hashlist_get(bul.entries, &hashkey)) != NULL) {
6044 + /* if an entry for this cn_addr exists (with smaller
6045 + * seq than the new entry's seq), update it */
6047 + if (MIPV6_SEQ_GT(seq, entry->seq)) {
6048 + DEBUG(DBG_INFO, "updating an existing entry");
6051 + DEBUG(DBG_INFO, "smaller seq than existing, not updating");
6055 + entry = mipv6_bul_get_entry();
6056 + if (entry == NULL) {
6057 + DEBUG(DBG_WARNING, "binding update list full, can't add!!!");
6060 + memset(entry, 0, sizeof(*entry));
6061 + /* First BU send happens here, save count in the entry */
6062 + entry->consecutive_sends = 1;
6066 + ipv6_addr_copy(&(entry->cn_addr), cn_addr);
6067 + ipv6_addr_copy(&(entry->home_addr), home_addr);
6070 + /* Add Return Routability info to bul entry */
6077 + ipv6_addr_copy(&(entry->coa), coa);
6078 + entry->lifetime = lifetime;
6080 + entry->expire = jiffies + lifetime * HZ;
6081 + else if (flags & MIPV6_BU_F_ACK)
6082 + entry->expire = jiffies + HOME_RESEND_EXPIRE * HZ;
6084 + entry->flags = flags;
6085 + entry->lastsend = jiffies; /* current time = last use of the entry */
6086 + entry->state = state;
6087 + entry->delay = delay;
6088 + entry->maxdelay = maxdelay;
6089 + entry->callback_time = jiffies + callback_time * HZ;
6090 + entry->callback = callback;
6092 + if (flags & MIPV6_BU_F_HOME &&
6093 + mipv6_mv_tnl_to_ha(cn_addr, coa, home_addr)) {
6094 + DEBUG(DBG_ERROR, "reconfiguration of the tunnel failed");
6097 + DEBUG(DBG_INFO, "updating entry: %x", entry);
6098 + hashlist_reposition(bul.entries, (void *)entry,
6099 + entry->callback_time);
6101 + DEBUG(DBG_INFO, "adding entry: %x", entry);
6103 + hashkey.a1 = &entry->cn_addr;
6104 + hashkey.a2 = &entry->home_addr;
6106 + if ((hashlist_add(bul.entries, &hashkey,
6107 + entry->callback_time,
6109 + DEBUG(DBG_ERROR, "Hash add failed");
6110 + mipv6_bul_entry_free(entry);
6120 + * mipv6_bul_delete - delete Binding Update List entry
6121 + * @cn_addr: address for entry to delete
6123 + * Deletes the entry for @cn_addr from the Binding Update List.
6124 + * Returns zero if entry was deleted succesfully, otherwise returns
6125 + * negative. Caller may not hold @bul_lock.
6127 +int mipv6_bul_delete(struct in6_addr *cn_addr, struct in6_addr *home_addr)
6129 + struct mipv6_bul_entry *entry;
6130 + struct in6_addr_pair hashkey;
6134 + hashkey.a1 = cn_addr;
6135 + hashkey.a2 = home_addr;
6137 + write_lock(&bul_lock);
6139 + if (unlikely(bul.entries == NULL) ||
6140 + (entry = (struct mipv6_bul_entry *)
6141 + hashlist_get(bul.entries, &hashkey)) == NULL) {
6142 + write_unlock(&bul_lock);
6143 + DEBUG(DBG_INFO, "No such entry");
6147 + hashlist_delete(bul.entries, (void *)entry);
6149 + del_bul_entry_tnl(entry);
6151 + mipv6_bul_entry_free(entry);
6153 + write_unlock(&bul_lock);
6155 + DEBUG(DBG_INFO, "Binding update list entry deleted");
6160 +/**********************************************************************
6162 + * Proc interface functions
6164 + **********************************************************************/
6166 +#define BUL_INFO_LEN 152
6168 +struct procinfo_iterator_args {
6176 +static int procinfo_iterator(void *data, void *args,
6177 + unsigned long *sortkey)
6179 + struct procinfo_iterator_args *arg =
6180 + (struct procinfo_iterator_args *)args;
6181 + struct mipv6_bul_entry *entry =
6182 + (struct mipv6_bul_entry *)data;
6183 + unsigned long callback_seconds;
6187 + if (entry == NULL) return ITERATOR_ERR;
6189 + if (time_after(jiffies, entry->callback_time))
6190 + callback_seconds = 0;
6192 + callback_seconds = (entry->callback_time - jiffies) / HZ;
6194 + if (arg->skip < arg->offset / BUL_INFO_LEN) {
6196 + return ITERATOR_CONT;
6199 + if (arg->len >= arg->length)
6200 + return ITERATOR_CONT;
6202 + /* CN HoA CoA ExpInSecs SeqNum State Delay MaxDelay CallbackInSecs */
6203 + arg->len += sprintf(arg->buffer + arg->len,
6204 + "%08x%08x%08x%08x %08x%08x%08x%08x %08x%08x%08x%08x\n"
6205 + "%010lu %05d %02d %010d %010d %010lu\n",
6206 + ntohl(entry->cn_addr.s6_addr32[0]),
6207 + ntohl(entry->cn_addr.s6_addr32[1]),
6208 + ntohl(entry->cn_addr.s6_addr32[2]),
6209 + ntohl(entry->cn_addr.s6_addr32[3]),
6210 + ntohl(entry->home_addr.s6_addr32[0]),
6211 + ntohl(entry->home_addr.s6_addr32[1]),
6212 + ntohl(entry->home_addr.s6_addr32[2]),
6213 + ntohl(entry->home_addr.s6_addr32[3]),
6214 + ntohl(entry->coa.s6_addr32[0]),
6215 + ntohl(entry->coa.s6_addr32[1]),
6216 + ntohl(entry->coa.s6_addr32[2]),
6217 + ntohl(entry->coa.s6_addr32[3]),
6218 + (entry->expire - jiffies) / HZ,
6219 + entry->seq, entry->state, entry->delay,
6220 + entry->maxdelay, callback_seconds);
6222 + return ITERATOR_CONT;
6227 + * Callback function for proc filesystem.
6229 +static int bul_proc_info(char *buffer, char **start, off_t offset,
6232 + struct procinfo_iterator_args args;
6236 + args.buffer = buffer;
6237 + args.offset = offset;
6238 + args.length = length;
6242 + read_lock_bh(&bul_lock);
6243 + hashlist_iterate(bul.entries, &args, procinfo_iterator);
6244 + read_unlock_bh(&bul_lock);
6248 + *start += offset % BUL_INFO_LEN;
6250 + args.len -= offset % BUL_INFO_LEN;
6252 + if (args.len > length)
6253 + args.len = length;
6260 +/**********************************************************************
6262 + * Code module init/fini functions
6264 + **********************************************************************/
6266 +int __init mipv6_bul_init(__u32 size)
6271 + DEBUG(DBG_CRITICAL,
6272 + "Binding update list size must be at least 1");
6275 + bul.entries = hashlist_create(MIPV6_BUL_HASHSIZE, size,
6276 + sizeof(struct mipv6_bul_entry),
6277 + "mip6_bul", NULL, NULL,
6278 + bul_compare, bul_hash);
6280 + if (bul.entries == NULL) {
6281 + DEBUG(DBG_CRITICAL, "Couldn't allocate memory for "
6282 + "hashlist when creating a binding update list");
6285 + init_timer(&bul.callback_timer);
6286 + bul.callback_timer.data = 0;
6287 + bul.callback_timer.function = timer_handler;
6288 + proc_net_create("mip6_bul", 0, bul_proc_info);
6289 + DEBUG(DBG_INFO, "Binding update list initialized");
6293 +void __exit mipv6_bul_exit()
6295 + struct mipv6_bul_entry *entry;
6296 + struct hashlist *entries;
6300 + proc_net_remove("mip6_bul");
6302 + write_lock_bh(&bul_lock);
6304 + DEBUG(DBG_INFO, "Stopping the bul timer");
6305 + del_timer(&bul.callback_timer);
6307 + while ((entry = (struct mipv6_bul_entry *)
6308 + hashlist_get_first(bul.entries)) != NULL) {
6309 + hashlist_delete(bul.entries, (void *)entry);
6311 + del_bul_entry_tnl(entry);
6313 + mipv6_bul_entry_free(entry);
6315 + entries = bul.entries;
6316 + bul.entries = NULL;
6317 + write_unlock_bh(&bul_lock);
6319 + hashlist_destroy(entries);
6321 + DEBUG(DBG_INFO, "binding update list destroyed");
6324 +++ linux-2.4.27/net/ipv6/mobile_ip6/bul.h
6327 + * MIPL Mobile IPv6 Binding Update List header file
6331 + * This program is free software; you can redistribute it and/or
6332 + * modify it under the terms of the GNU General Public License
6333 + * as published by the Free Software Foundation; either version
6334 + * 2 of the License, or (at your option) any later version.
6340 +#include "hashlist.h"
6342 +#define ACK_OK 0x01
6343 +#define RESEND_EXP 0x02
6344 +#define ACK_ERROR 0x04
6346 +#define HOME_RESEND_EXPIRE 3600
6347 +#define MIPV6_COOKIE_LEN 8
6348 +struct mipv6_rr_info {
6349 + /* RR information */
6350 + u16 rr_state; /* State of the RR */
6351 + u16 rr_flags; /* Flags for the RR */
6352 + u8 hot_cookie[MIPV6_COOKIE_LEN]; /* HoT Cookie */
6353 + u8 cot_cookie[MIPV6_COOKIE_LEN]; /* CoT Cookie */
6354 + u8 home_cookie[MIPV6_COOKIE_LEN]; /* Home Cookie */
6355 + u8 careof_cookie[MIPV6_COOKIE_LEN]; /* Careof Cookie */
6356 + u32 lastsend_hoti; /* When HoTI was last sent (jiffies) */
6357 + u32 lastsend_coti; /* When CoTI was last sent (jiffies) */
6358 + u32 home_time; /* when Care-of cookie was received */
6359 + u32 careof_time; /* when Home cookie was received */
6360 + int home_nonce_index; /* Home cookie nonce index */
6361 + int careof_nonce_index; /* Care-of cookie nonce index */
6362 + u8 *kbu; /* Binding authentication key */
6364 +struct mipv6_bul_entry {
6365 + struct hashlist_entry e;
6366 + struct in6_addr cn_addr; /* CN to which BU was sent */
6367 + struct in6_addr home_addr; /* home address of this binding */
6368 + struct in6_addr coa; /* care-of address of the sent BU */
6370 + unsigned long expire; /* entry's expiration time (jiffies) */
6371 + __u32 lifetime; /* lifetime sent in this BU */
6372 + __u32 lastsend; /* last time when BU sent (jiffies) */
6373 + __u32 consecutive_sends; /* Number of consecutive BU's sent */
6374 + __u16 seq; /* sequence number of the latest BU */
6375 + __u8 flags; /* BU send flags */
6376 + __u8 state; /* resend state */
6377 + __u32 initdelay; /* initial ack wait */
6378 + __u32 delay; /* current ack wait */
6379 + __u32 maxdelay; /* maximum ack wait */
6381 + struct mipv6_rr_info *rr;
6382 + struct mipv6_mh_opt *ops; /* saved option values */
6384 + unsigned long callback_time;
6385 + int (*callback)(struct mipv6_bul_entry *entry);
6388 +extern rwlock_t bul_lock;
6390 +int mipv6_bul_init(__u32 size);
6392 +void mipv6_bul_exit(void);
6394 +struct mipv6_bul_entry *mipv6_bul_add(
6395 + struct in6_addr *cn_addr, struct in6_addr *home_addr,
6396 + struct in6_addr *coa, __u32 lifetime, __u16 seq, __u8 flags,
6397 + int (*callback)(struct mipv6_bul_entry *entry), __u32 callback_time,
6398 + __u8 state, __u32 delay, __u32 maxdelay, struct mipv6_mh_opt *ops,
6399 + struct mipv6_rr_info *rr);
6401 +int mipv6_bul_delete(struct in6_addr *cn_addr, struct in6_addr *home_addr);
6403 +int mipv6_bul_exists(struct in6_addr *cnaddr, struct in6_addr *home_addr);
6405 +struct mipv6_bul_entry *mipv6_bul_get(struct in6_addr *cnaddr,
6406 + struct in6_addr *home_addr);
6407 +struct mipv6_bul_entry *mipv6_bul_get_by_ccookie(struct in6_addr *cn_addr,
6410 +int bul_entry_expired(struct mipv6_bul_entry *bulentry);
6412 +void mipv6_bul_reschedule(struct mipv6_bul_entry *entry);
6414 +int mipv6_bul_iterate(int (*func)(void *, void *, unsigned long *), void *args);
6418 +++ linux-2.4.27/net/ipv6/mobile_ip6/config.h
6421 + * Configuration parameters
6426 +#define MIPV6VERSION "D24"
6427 +#define MIPLVERSION "v1.0"
6429 +#define CAP_CN 0x01
6430 +#define CAP_HA 0x02
6431 +#define CAP_MN 0x04
6436 + int accept_ret_rout;
6437 + int max_rtr_reachable_time;
6438 + int eager_cell_switching;
6439 + int max_num_tunnels;
6440 + int min_num_tunnels;
6441 + int binding_refresh_advice;
6447 +extern struct mip6_conf mip6node_cnf;
6452 + void (*bce_home_add) (int ifindex, struct in6_addr *daddr,
6453 + struct in6_addr *haddr, struct in6_addr *coa,
6454 + struct in6_addr *rep_coa, __u32 lifetime,
6455 + __u16 sequence, __u8 flags, __u8 *k_bu);
6456 + void (*bce_cache_add) (int ifindex, struct in6_addr *daddr,
6457 + struct in6_addr *haddr, struct in6_addr *coa,
6458 + struct in6_addr *rep_coa, __u32 lifetime,
6459 + __u16 sequence, __u8 flags, __u8 *k_bu);
6460 + void (*bce_home_del) (struct in6_addr *daddr, struct in6_addr *haddr,
6461 + struct in6_addr *coa, struct in6_addr *rep_coa,
6462 + __u16 sequence, __u8 flags,
6464 + void (*bce_cache_del) (struct in6_addr *daddr, struct in6_addr *haddr,
6465 + struct in6_addr *coa, struct in6_addr *rep_coa,
6466 + __u16 sequence, __u8 flags,
6469 + int (*bce_tnl_rt_add) (struct in6_addr *coa,
6470 + struct in6_addr *ha_addr,
6471 + struct in6_addr *home_addr);
6473 + void (*bce_tnl_rt_del) (struct in6_addr *coa,
6474 + struct in6_addr *ha_addr,
6475 + struct in6_addr *home_addr);
6477 + void (*proxy_del) (struct in6_addr *home_addr, struct mipv6_bce *entry);
6478 + int (*proxy_create) (int flags, int ifindex, struct in6_addr *coa,
6479 + struct in6_addr *our_addr, struct in6_addr *home_addr);
6481 + int (*icmpv6_dhaad_rep_rcv) (struct sk_buff *skb);
6482 + int (*icmpv6_dhaad_req_rcv) (struct sk_buff *skb);
6483 + int (*icmpv6_pfxadv_rcv) (struct sk_buff *skb);
6484 + int (*icmpv6_pfxsol_rcv) (struct sk_buff *skb);
6485 + int (*icmpv6_paramprob_rcv) (struct sk_buff *skb);
6487 + int (*mn_use_hao) (struct in6_addr *daddr, struct in6_addr *saddr);
6488 + void (*mn_check_tunneled_packet) (struct sk_buff *skb);
6491 +extern struct mip6_func mip6_fn;
6493 +++ linux-2.4.27/net/ipv6/mobile_ip6/debug.h
6496 + * MIPL Mobile IPv6 Debugging macros and functions
6500 + * This program is free software; you can redistribute it and/or
6501 + * modify it under the terms of the GNU General Public License
6502 + * as published by the Free Software Foundation; either version
6503 + * 2 of the License, or (at your option) any later version.
6509 +#include <linux/autoconf.h>
6511 +/* priorities for different debug conditions */
6513 +#define DBG_CRITICAL 0 /* unrecoverable error */
6514 +#define DBG_ERROR 1 /* error (recoverable) */
6515 +#define DBG_WARNING 2 /* unusual situation but not a real error */
6516 +#define DBG_INFO 3 /* generally useful information */
6517 +#define DBG_EXTRA 4 /* extra information */
6518 +#define DBG_FUNC_ENTRY 6 /* use to indicate function entry and exit */
6519 +#define DBG_DATADUMP 7 /* packet dumps, etc. lots of flood */
6522 + * NIPV6ADDR - macro for IPv6 addresses
6523 + * @addr: Network byte order IPv6 address
6525 + * Macro for printing IPv6 addresses. Used in conjunction with
6526 + * printk() or derivatives (such as DEBUG macro).
6528 +#define NIPV6ADDR(addr) \
6529 + ntohs(((u16 *)addr)[0]), \
6530 + ntohs(((u16 *)addr)[1]), \
6531 + ntohs(((u16 *)addr)[2]), \
6532 + ntohs(((u16 *)addr)[3]), \
6533 + ntohs(((u16 *)addr)[4]), \
6534 + ntohs(((u16 *)addr)[5]), \
6535 + ntohs(((u16 *)addr)[6]), \
6536 + ntohs(((u16 *)addr)[7])
6538 +#ifdef CONFIG_IPV6_MOBILITY_DEBUG
6539 +extern int mipv6_debug;
6542 + * debug_print - print debug message
6543 + * @debug_level: message priority
6544 + * @fname: calling function's name
6545 + * @fmt: printf-style formatting string
6547 + * Prints a debug message to system log if @debug_level is less or
6548 + * equal to @mipv6_debug. Should always be called using DEBUG()
6549 + * macro, not directly.
6551 +static void debug_print(int debug_level, const char *fname, const char* fmt, ...)
6556 + if (mipv6_debug < debug_level)
6559 + va_start(args, fmt);
6560 + vsprintf(s, fmt, args);
6561 + printk("mip6[%s]: %s\n", fname, s);
6566 + * debug_print_buffer - print arbitrary buffer to system log
6567 + * @debug_level: message priority
6568 + * @data: pointer to buffer
6569 + * @len: number of bytes to print
6571 + * Prints @len bytes from buffer @data to system log. @debug_level
6572 + * tells on which debug level message gets printed. For
6573 + * debug_print_buffer() priority %DBG_DATADUMP should be used.
6575 +#define debug_print_buffer(debug_level,data,len) { \
6576 + if (mipv6_debug >= debug_level) { \
6578 + for (i=0; i<len; i++) { \
6579 + if (i%16 == 0) printk("\n%04x: ", i); \
6580 + printk("%02x ", ((unsigned char *)data)[i]); \
6586 +#define DEBUG(x,y,z...) debug_print(x,__FUNCTION__,y,##z)
6587 +#define DEBUG_FUNC() \
6588 +DEBUG(DBG_FUNC_ENTRY, "%s(%d)/%s: ", __FILE__,__LINE__,__FUNCTION__)
6591 +#define DEBUG(x,y,z...)
6592 +#define DEBUG_FUNC()
6593 +#define debug_print_buffer(x,y,z)
6597 +#define ASSERT(expression) { \
6598 + if (!(expression)) { \
6599 + (void)printk(KERN_ERR \
6600 + "Assertion \"%s\" failed: file \"%s\", function \"%s\", line %d\n", \
6601 + #expression, __FILE__, __FUNCTION__, __LINE__); \
6606 +#endif /* _DEBUG_H */
6608 +++ linux-2.4.27/net/ipv6/mobile_ip6/exthdrs.c
6611 + * Extension Header handling and adding code
6614 + * Sami Kivisaari <skivisaa@cc.hut.fi>
6618 + * This program is free software; you can redistribute it and/or
6619 + * modify it under the terms of the GNU General Public License
6620 + * as published by the Free Software Foundation; either version
6621 + * 2 of the License, or (at your option) any later version.
6624 +#include <linux/types.h>
6625 +#include <linux/slab.h>
6627 +#include <net/ipv6.h>
6628 +#include <net/ip6_route.h>
6629 +#include <net/addrconf.h>
6630 +#include <net/mipv6.h>
6634 +#include "mobhdr.h"
6635 +#include "bcache.h"
6636 +#include "config.h"
6639 + * mipv6_append_home_addr - Add Home Address Option
6640 + * @opt: buffer for Home Address Option
6641 + * @offset: offset from beginning of @opt
6642 + * @addr: address for HAO
6644 + * Adds a Home Address Option to a packet. Option is stored in
6645 + * @offset from beginning of @opt. The option is created but the
6646 + * original source address in IPv6 header is left intact. The source
6647 + * address will be changed from home address to CoA after the checksum
6648 + * has been calculated in getfrag. Padding is done automatically, and
6649 + * @opt must have allocated space for both actual option and pad.
6650 + * Returns offset from @opt to end of options.
6652 +int mipv6_append_home_addr(__u8 *opt, int offset, struct in6_addr *addr)
6655 + struct mipv6_dstopt_homeaddr *ho;
6657 + DEBUG(DBG_DATADUMP, "HAO: %x:%x:%x:%x:%x:%x:%x:%x",
6660 + pad = (6 - offset) & 7;
6661 + mipv6_add_pad(opt + offset, pad);
6663 + ho = (struct mipv6_dstopt_homeaddr *)(opt + offset + pad);
6664 + ho->type = MIPV6_TLV_HOMEADDR;
6665 + ho->length = sizeof(*ho) - 2;
6666 + ipv6_addr_copy(&ho->addr, addr);
6668 + return offset + pad + sizeof(*ho);
6670 +static inline int check_hao_validity(struct mipv6_dstopt_homeaddr *haopt,
6672 + struct in6_addr *saddr,
6673 + struct in6_addr *daddr)
6675 + int addr_type = ipv6_addr_type(&haopt->addr);
6676 + struct mipv6_bce bc_entry;
6678 + if (addr_type & IPV6_ADDR_LINKLOCAL ||
6679 + !(addr_type & IPV6_ADDR_UNICAST)) {
6680 + DEBUG(DBG_INFO, "HAO with link local or non-unicast HoA, "
6681 + "not sending BE to "
6683 + "%x:%x:%x:%x:%x:%x:%x:%x ",
6684 + "care-of address %x:%x:%x:%x:%x:%x:%x:%x",
6685 + NIPV6ADDR(&haopt->addr),
6686 + NIPV6ADDR(saddr));
6688 + } else if (dst1[0] != IPPROTO_MOBILITY &&
6689 + (mipv6_bcache_get(&haopt->addr,
6690 + daddr, &bc_entry) != 0 ||
6691 + ipv6_addr_cmp(saddr, &bc_entry.coa))) {
6692 + DEBUG(DBG_INFO, "HAO without binding or incorrect CoA, "
6693 + "sending BE code 1: "
6694 + "home address %x:%x:%x:%x:%x:%x:%x:%x",
6695 + "to care-of address %x:%x:%x:%x:%x:%x:%x:%x",
6696 + NIPV6ADDR(&haopt->addr),
6697 + NIPV6ADDR(saddr));
6703 + * mipv6_handle_homeaddr - Home Address Destination Option handler
6704 + * @skb: packet buffer
6705 + * @optoff: offset to where option begins
6707 + * Handles Home Address Option in IPv6 Destination Option header.
6708 + * Packet and offset to option are passed. If HAO is used without
6709 + * binding, sends a Binding Error code 1. When sending BE, notify bit
6710 + * is cleared to prevent IPv6 error handling from sending ICMP
6711 + * Parameter Problem. Returns 1 on success, otherwise zero.
6713 +int mipv6_handle_homeaddr(struct sk_buff *skb, int optoff)
6715 + struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
6716 + struct in6_addr coaddr;
6717 + struct inet6_skb_parm *opt = (struct inet6_skb_parm *) skb->cb;
6718 + struct mipv6_dstopt_homeaddr *haopt =
6719 + (struct mipv6_dstopt_homeaddr *) &skb->nh.raw[optoff];
6725 + if (haopt->length != sizeof(*haopt) - 2) {
6726 + DEBUG(DBG_WARNING, "HAO has invalid length");
6727 + MIPV6_INC_STATS(n_ha_drop.invalid);
6730 + dst1 = (u8 *)skb->h.raw;
6731 + err = check_hao_validity(haopt, dst1, saddr, &skb->nh.ipv6h->daddr);
6734 + haopt->type &= ~(0x80); /* clear notify bit */
6735 + if (err == -ENOENT)
6736 + mipv6_send_be(&skb->nh.ipv6h->daddr, saddr,
6737 + &haopt->addr, MIPV6_BE_HAO_WO_BINDING);
6738 + MIPV6_INC_STATS(n_ha_drop.misc);
6741 + ipv6_addr_copy(&coaddr, saddr);
6742 + ipv6_addr_copy(saddr, &haopt->addr);
6743 + ipv6_addr_copy(&haopt->addr, &coaddr);
6744 + opt->hao = optoff;
6745 + if (mip6_fn.mn_check_tunneled_packet != NULL)
6746 + mip6_fn.mn_check_tunneled_packet(skb);
6748 + MIPV6_INC_STATS(n_ha_rcvd);
6753 + * mipv6_icmp_swap_addrs - Switch HAO and src and RT2 and dest for ICMP errors
6754 + * @skb: packet buffer
6756 + * Reset the source address and the Home Address option in skb before
6757 + * appending it to an ICMP error message, so original packet appears
6758 + * in the error message rather than mangled.
6760 +void mipv6_icmp_swap_addrs(struct sk_buff *skb)
6762 + struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
6763 + struct in6_addr tmp;
6764 + struct in6_addr *hoa;
6766 + if (opt->srcrt2) {
6767 + struct rt2_hdr *rt2;
6768 + rt2 = (struct rt2_hdr *)(skb->nh.raw + opt->srcrt2);
6771 + ipv6_addr_copy(&tmp, hoa);
6772 + ipv6_addr_copy(hoa, &skb->nh.ipv6h->daddr);
6773 + ipv6_addr_copy(&skb->nh.ipv6h->daddr, &tmp);
6774 + rt2->rt_hdr.segments_left++;
6775 + skb->nh.ipv6h->hop_limit++;
6778 + struct mipv6_dstopt_homeaddr *hao;
6779 + hao = (struct mipv6_dstopt_homeaddr *)(skb->nh.raw + opt->hao);
6782 + ipv6_addr_copy(&tmp, hoa);
6783 + ipv6_addr_copy(hoa, &skb->nh.ipv6h->saddr);
6784 + ipv6_addr_copy(&skb->nh.ipv6h->saddr, &tmp);
6789 + * mipv6_append_rt2hdr - Add Type 2 Routing Header
6790 + * @rt: buffer for new routing header
6791 + * @addr: intermediate hop address
6793 + * Adds a Routing Header Type 2 in a packet. Stores newly created
6794 + * routing header in buffer @rt. Type 2 RT only carries one address,
6795 + * so there is no need to process old routing header. @rt must have
6796 + * allocated space for 24 bytes.
6798 +void mipv6_append_rt2hdr(struct ipv6_rt_hdr *rt, struct in6_addr *addr)
6800 + struct rt2_hdr *rt2 = (struct rt2_hdr *)rt;
6802 + DEBUG(DBG_DATADUMP, "RT2: %x:%x:%x:%x:%x:%x:%x:%x",
6805 + if (ipv6_addr_type(addr) == IPV6_ADDR_MULTICAST) {
6806 + DEBUG(DBG_ERROR, "destination address not unicast");
6810 + memset(rt2, 0, sizeof(*rt2));
6811 + rt2->rt_hdr.type = 2;
6812 + rt2->rt_hdr.hdrlen = 2;
6813 + rt2->rt_hdr.segments_left = 1;
6814 + ipv6_addr_copy(&rt2->addr, addr);
6818 + * mipv6_append_dst1opts - Add Destination Option (1) Headers
6819 + * @dst1opt: buffer for new destination options
6820 + * @saddr: address for Home Address Option
6821 + * @old_dst1opt: old destination options
6822 + * @len: length of options
6824 + * Adds Destination Option (1) Header to a packet. New options are
6825 + * stored in @dst1opt. If old destination options exist, they are
6826 + * copied from @old_dst1opt. Only Home Address Option is destination
6827 + * option. @dstopt must have allocated space for @len bytes. @len
6828 + * includes Destination Option Header (2 bytes), Home Address Option
6829 + * (18 bytes) and possible HAO pad (8n+6).
6832 + * ISSUE: Home Address Destination Option should really be added to a
6833 + * new destination option header specified in Mobile IPv6 spec which
6834 + * should be placed after routing header(s), but before fragmentation
6835 + * header. Putting HAO in DO1 works for now, but support for the new
6836 + * placement should be added to the IPv6 stack.
6839 +mipv6_append_dst1opts(struct ipv6_opt_hdr *dst1opt, struct in6_addr *saddr,
6840 + struct ipv6_opt_hdr *old_dst1opt, int len)
6844 + if (old_dst1opt) {
6845 + memcpy(dst1opt, old_dst1opt, ipv6_optlen(old_dst1opt));
6846 + offset = ipv6_optlen(old_dst1opt);
6848 + offset = sizeof (*dst1opt);
6850 + dst1opt->hdrlen = (len >> 3) - 1;
6851 + mipv6_append_home_addr((__u8 *) dst1opt, offset, saddr);
6855 + * mipv6_modify_txoptions - Modify outgoing packets
6857 + * @skb: packet buffer for outgoing packet
6858 + * @old_opt: transmit options
6859 + * @fl: packet flow structure
6860 + * @dst: pointer to destination cache entry
6862 + * Adds Home Address Option (for MN packets, when not at home) and
6863 + * Routing Header Type 2 (for CN packets when sending to an MN) to
6864 + * data packets. Old extension headers are copied from @old_opt (if
6865 + * any). Extension headers are _explicitly_ added for packets with
6866 + * Mobility Header. Returns the new header structure, or old if no
6869 +struct ipv6_txoptions *
6870 +mipv6_modify_txoptions(struct sock *sk, struct sk_buff *skb,
6871 + struct ipv6_txoptions *old_opt, struct flowi *fl,
6872 + struct dst_entry **dst)
6874 + struct ipv6_opt_hdr *old_hopopt = NULL;
6875 + struct ipv6_opt_hdr *old_dst1opt = NULL;
6876 + struct ipv6_rt_hdr *old_srcrt = NULL;
6878 + int srcrtlen = 0, dst1len = 0;
6879 + int tot_len, use_hao = 0;
6880 + struct ipv6_txoptions *opt;
6881 + struct mipv6_bce bc_entry;
6882 + struct in6_addr tmpaddr, *saddr, *daddr, coaddr;
6887 + if (fl->proto == IPPROTO_MOBILITY) return old_opt;
6889 + * we have to be prepared to the fact that saddr might not be present,
6890 + * if that is the case, we acquire saddr just as kernel does.
6892 + saddr = fl ? fl->fl6_src : NULL;
6893 + daddr = fl ? fl->fl6_dst : NULL;
6895 + if (daddr == NULL)
6897 + if (saddr == NULL) {
6898 + int err = ipv6_get_saddr(NULL, daddr, &tmpaddr);
6905 + DEBUG(DBG_DATADUMP,
6906 + "dest. address of packet: %x:%x:%x:%x:%x:%x:%x:%x",
6907 + NIPV6ADDR(daddr));
6908 + DEBUG(DBG_DATADUMP, " and src. address: %x:%x:%x:%x:%x:%x:%x:%x",
6909 + NIPV6ADDR(saddr));
6912 + old_hopopt = old_opt->hopopt;
6913 + old_dst1opt = old_opt->dst1opt;
6914 + old_srcrt = old_opt->srcrt;
6917 + if (mip6_fn.mn_use_hao != NULL)
6918 + use_hao = mip6_fn.mn_use_hao(daddr, saddr);
6922 + dst1len = ipv6_optlen(old_dst1opt);
6923 + dst1len += sizeof(struct mipv6_dstopt_homeaddr) +
6924 + ((6 - dst1len) & 7); /* padding */
6927 + if (mipv6_bcache_get(daddr, saddr, &bc_entry) == 0)
6928 + srcrtlen = sizeof(struct rt2_hdr);
6930 + if ((tot_len = srcrtlen + dst1len) == 0) {
6934 + tot_len += sizeof(*opt);
6936 + if (!(opt = kmalloc(tot_len, GFP_ATOMIC))) {
6939 + memset(opt, 0, tot_len);
6940 + opt->tot_len = tot_len;
6941 + opt_ptr = (__u8 *) (opt + 1);
6944 + opt->srcrt = old_srcrt;
6945 + opt->opt_nflen += ipv6_optlen(old_srcrt);
6949 + DEBUG(DBG_DATADUMP, "Binding exists. Adding routing header");
6951 + opt->srcrt2 = (struct ipv6_rt_hdr *) opt_ptr;
6952 + opt->opt_nflen += srcrtlen;
6953 + opt_ptr += srcrtlen;
6956 + * Append care-of-address to routing header (original
6957 + * destination address is home address, the first
6958 + * source route segment gets put to the destination
6959 + * address and the home address gets to the last
6960 + * segment of source route (just as it should))
6963 + ipv6_addr_copy(&coaddr, &bc_entry.coa);
6965 + mipv6_append_rt2hdr(opt->srcrt2, &coaddr);
6968 + * reroute output (we have to do this in case of TCP
6969 + * segment) unless a routing header of type 0 is also added
6971 + if (dst && !opt->srcrt) {
6972 + struct in6_addr *tmp = fl->fl6_dst;
6973 + fl->fl6_dst = &coaddr;
6975 + dst_release(*dst);
6976 + *dst = ip6_route_output(sk, fl);
6979 + fl->fl6_dst = tmp;
6981 + DEBUG(DBG_DATADUMP, "Rerouted outgoing packet");
6985 + /* Only home address option is inserted to first dst opt header */
6987 + opt->dst1opt = (struct ipv6_opt_hdr *) opt_ptr;
6988 + opt->opt_flen += dst1len;
6989 + opt_ptr += dst1len;
6990 + mipv6_append_dst1opts(opt->dst1opt, saddr,
6991 + old_dst1opt, dst1len);
6992 + opt->mipv6_flags = MIPV6_SND_HAO;
6993 + } else if (old_dst1opt) {
6994 + opt->dst1opt = old_dst1opt;
6995 + opt->opt_flen += ipv6_optlen(old_dst1opt);
6998 + opt->hopopt = old_hopopt;
6999 + opt->opt_nflen += ipv6_optlen(old_hopopt);
7005 +++ linux-2.4.27/net/ipv6/mobile_ip6/exthdrs.h
7008 + * MIPL Mobile IPv6 Extension Headers header file
7012 + * This program is free software; you can redistribute it and/or
7013 + * modify it under the terms of the GNU General Public License
7014 + * as published by the Free Software Foundation; either version
7015 + * 2 of the License, or (at your option) any later version.
7018 +#ifndef _MIPV6_EXTHDRS_H
7019 +#define _MIPV6_EXTHDRS_H
7023 +struct ipv6_rt_hdr;
7024 +struct ipv6_opt_hdr;
7025 +struct ipv6_txoptions;
7029 + * Home Address Destination Option function prototypes
7031 +int mipv6_append_home_addr(__u8 *opt, int offset, struct in6_addr *addr);
7033 +int mipv6_handle_homeaddr(struct sk_buff *skb, int optoff);
7035 +void mipv6_icmp_swap_addrs(struct sk_buff *skb);
7038 + * Creates a routing header of type 2.
7040 +void mipv6_append_rt2hdr(struct ipv6_rt_hdr *srcrt, struct in6_addr *addr);
7042 +/* Function to add the first destination option header, which may
7043 + * include a home address option.
7045 +void mipv6_append_dst1opts(struct ipv6_opt_hdr *dst1opt, struct in6_addr *saddr,
7046 + struct ipv6_opt_hdr *old_dst1opt, int len);
7048 +struct ipv6_txoptions *mipv6_modify_txoptions(
7049 + struct sock *sk, struct sk_buff *skb,
7050 + struct ipv6_txoptions *old_opt, struct flowi *fl,
7051 + struct dst_entry **dst);
7053 +#endif /* _MIPV6_EXTHDRS_H */
7055 +++ linux-2.4.27/net/ipv6/mobile_ip6/ha.c
7058 + * Home-agent functionality
7061 + * Sami Kivisaari <skivisaa@cc.hut.fi>
7062 + * Henrik Petander <lpetande@cc.hut.fi>
7066 + * This program is free software; you can redistribute it and/or
7067 + * modify it under the terms of the GNU General Public License
7068 + * as published by the Free Software Foundation; either version
7069 + * 2 of the License, or (at your option) any later version.
7071 + * Changes: Venkata Jagana,
7072 + * Krishna Kumar : Statistics fix
7073 + * Masahide Nakamura : Use of mipv6_forward
7077 +#include <linux/autoconf.h>
7078 +#include <linux/net.h>
7079 +#include <linux/skbuff.h>
7080 +#include <linux/if_ether.h>
7081 +#include <linux/netdevice.h>
7082 +#include <linux/in6.h>
7083 +#include <linux/init.h>
7084 +#include <linux/netfilter.h>
7085 +#include <linux/netfilter_ipv6.h>
7086 +#ifdef CONFIG_SYSCTL
7087 +#include <linux/sysctl.h>
7090 +#include <net/neighbour.h>
7091 +#include <net/ipv6.h>
7092 +#include <net/ip6_fib.h>
7093 +#include <net/ip6_route.h>
7094 +#include <net/ndisc.h>
7095 +#include <net/addrconf.h>
7096 +#include <net/neighbour.h>
7098 +#include "tunnel_ha.h"
7099 +#include "bcache.h"
7104 +#include "config.h"
7105 +#include "mobhdr.h"
7107 +static int mipv6_ha_tunnel_sitelocal = 0;
7109 +#ifdef CONFIG_SYSCTL
7111 +static struct ctl_table_header *mipv6_ha_sysctl_header;
7113 +static struct mipv6_ha_sysctl_table
7115 + struct ctl_table_header *sysctl_header;
7116 + ctl_table mipv6_vars[3];
7117 + ctl_table mipv6_mobility_table[2];
7118 + ctl_table mipv6_proto_table[2];
7119 + ctl_table mipv6_root_table[2];
7120 +} mipv6_ha_sysctl = {
7123 + {{NET_IPV6_MOBILITY_TUNNEL_SITELOCAL, "tunnel_sitelocal",
7124 + &mipv6_ha_tunnel_sitelocal, sizeof(int), 0644, NULL,
7128 + {{NET_IPV6_MOBILITY, "mobility", NULL, 0, 0555,
7129 + mipv6_ha_sysctl.mipv6_vars}, {0}},
7130 + {{NET_IPV6, "ipv6", NULL, 0, 0555,
7131 + mipv6_ha_sysctl.mipv6_mobility_table}, {0}},
7132 + {{CTL_NET, "net", NULL, 0, 0555,
7133 + mipv6_ha_sysctl.mipv6_proto_table}, {0}}
7136 +#endif /* CONFIG_SYSCTL */
7139 +/* this is defined in kernel IPv6 module (sockglue.c) */
7140 +extern struct packet_type ipv6_packet_type;
7142 +/* mipv6_forward: Intercept NS packets destined to home address of MN */
7143 +int mipv6_forward(struct sk_buff *skb)
7145 + struct ipv6hdr *ipv6h;
7146 + struct in6_addr *daddr, *saddr;
7150 + if (skb == NULL) return 0;
7152 + ipv6h = skb->nh.ipv6h;
7153 + daddr = &ipv6h->daddr;
7154 + saddr = &ipv6h->saddr;
7156 + nexthdr = ipv6h->nexthdr;
7157 + nhoff = sizeof(*ipv6h);
7159 + if (ipv6_ext_hdr(nexthdr))
7160 + nhoff = ipv6_skip_exthdr(skb, nhoff, &nexthdr,
7161 + skb->len - sizeof(*ipv6h));
7163 + /* Do not to forward Neighbor Solicitation to Home Address of MN */
7164 + if (nexthdr == IPPROTO_ICMPV6) {
7165 + struct icmp6hdr *icmp6h;
7168 + if (nhoff < 0 || !pskb_may_pull(skb, nhoff +
7169 + sizeof(struct icmp6hdr))) {
7174 + dest_type = ipv6_addr_type(daddr);
7175 + icmp6h = (struct icmp6hdr *)&skb->nh.raw[nhoff];
7177 + /* Intercepts NS to HoA of MN */
7179 + if ((icmp6h->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) ||
7180 + ((dest_type & IPV6_ADDR_MULTICAST) &&
7181 + (icmp6h->icmp6_type == NDISC_ROUTER_ADVERTISEMENT))) {
7194 + * mipv6_proxy_nd_rem - stop acting as a proxy for @home_address
7195 + * @home_addr: address to remove
7196 + * @ha_addr: home agent's address on home link
7197 + * @linklocal: link-local compatibility bit
7199 + * When Home Agent acts as a proxy for an address it must leave the
7200 + * solicited node multicast group for that address and stop responding
7201 + * to neighbour solicitations.
7203 +static int mipv6_proxy_nd_rem(struct in6_addr *home_addr,
7204 + int ifindex, int linklocal)
7206 + /* When MN returns home HA leaves the solicited mcast groups
7207 + * for MNs home addresses
7210 + struct net_device *dev;
7214 + if ((dev = dev_get_by_index(ifindex)) == NULL) {
7215 + DEBUG(DBG_ERROR, "couldn't get dev");
7219 + /* Remove link-local entry */
7221 + struct in6_addr ll_addr;
7222 + mipv6_generate_ll_addr(&ll_addr, home_addr);
7223 + if ((err = pneigh_delete(&nd_tbl, &ll_addr, dev)) < 0) {
7225 + "peigh_delete failed for "
7226 + "%x:%x:%x:%x:%x:%x:%x:%x",
7227 + NIPV6ADDR(&ll_addr));
7231 + /* Remove global (or site-local) entry */
7232 + if ((err = pneigh_delete(&nd_tbl, home_addr, dev)) < 0) {
7234 + "peigh_delete failed for "
7235 + "%x:%x:%x:%x:%x:%x:%x:%x",
7236 + NIPV6ADDR(home_addr));
7243 + * mipv6_proxy_nd - join multicast group for this address
7244 + * @home_addr: address to defend
7245 + * @ha_addr: home agent's address on home link
7246 + * @linklocal: link-local compatibility bit
7248 + * While Mobile Node is away from home, Home Agent acts as a proxy for
7249 + * @home_address. HA responds to neighbour solicitations for @home_address
7250 + * thus getting all packets destined to home address of MN.
7252 +static int mipv6_proxy_nd(struct in6_addr *home_addr,
7253 + int ifindex, int linklocal)
7255 + /* The HA sends a proxy ndisc_na message to all hosts on MN's
7256 + * home subnet by sending a neighbor advertisement with the
7257 + * home address or all addresses of the mobile node if the
7258 + * prefix is not 0. The addresses are formed by combining the
7259 + * suffix or the host part of the address with each subnet
7260 + * prefix that exists in the home subnet
7263 + /* Since no previous entry for MN exists a proxy_nd advertisement
7264 + * is sent to all nodes link local multicast address
7268 + struct net_device *dev;
7269 + struct in6_addr na_saddr;
7270 + struct in6_addr ll_addr;
7271 + struct pneigh_entry *ll_pneigh;
7272 + struct in6_addr mcdest;
7273 + int send_ll_na = 0;
7275 + int solicited = 0;
7280 + if ((dev = dev_get_by_index(ifindex)) == NULL) {
7281 + DEBUG(DBG_ERROR, "couldn't get dev");
7285 + if (!pneigh_lookup(&nd_tbl, home_addr, dev, 1)) {
7287 + "peigh_lookup failed for "
7288 + "%x:%x:%x:%x:%x:%x:%x:%x",
7289 + NIPV6ADDR(home_addr));
7294 + mipv6_generate_ll_addr(&ll_addr, home_addr);
7296 + if ((ll_pneigh = pneigh_lookup(&nd_tbl, &ll_addr,
7297 + dev, 1)) == NULL) {
7299 + "peigh_lookup failed for "
7300 + "%x:%x:%x:%x:%x:%x:%x:%x",
7301 + NIPV6ADDR(&ll_addr));
7302 + pneigh_delete(&nd_tbl, home_addr, dev);
7311 + /* Proxy neighbor advertisement of MN's home address
7312 + * to all nodes solicited multicast address
7314 + if (!ipv6_get_lladdr(dev, &na_saddr)) {
7315 + ipv6_addr_all_nodes(&mcdest);
7316 + ndisc_send_na(dev, NULL, &mcdest, home_addr, 0,
7317 + solicited, override, inc_opt);
7320 + ndisc_send_na(dev, NULL, &mcdest, &ll_addr,
7321 + 0, solicited, override, inc_opt);
7326 + DEBUG(DBG_ERROR, "failed to get link local address for sending proxy NA");
7334 +struct inet6_ifaddr *is_on_link_ipv6_address(struct in6_addr *mn_haddr,
7335 + struct in6_addr *ha_addr)
7337 + struct inet6_ifaddr *ifp;
7338 + struct inet6_dev *in6_dev;
7339 + struct inet6_ifaddr *oifp = NULL;
7341 + if ((ifp = ipv6_get_ifaddr(ha_addr, 0)) == NULL)
7344 + if ((in6_dev = ifp->idev) != NULL) {
7345 + in6_dev_hold(in6_dev);
7346 + oifp = in6_dev->addr_list;
7347 + while (oifp != NULL) {
7348 + spin_lock(&oifp->lock);
7349 + if (mipv6_prefix_compare(&oifp->addr, mn_haddr,
7350 + oifp->prefix_len) &&
7351 + !(oifp->flags & IFA_F_TENTATIVE)) {
7352 + spin_unlock(&oifp->lock);
7353 + DEBUG(DBG_INFO, "Home Addr Opt: on-link");
7354 + in6_ifa_hold(oifp);
7357 + spin_unlock(&oifp->lock);
7358 + oifp = oifp->if_next;
7360 + in6_dev_put(in6_dev);
7363 +/* DEBUG(DBG_WARNING, "Home Addr Opt NOT on-link"); */
7369 + * Lifetime checks. ifp->valid_lft >= ifp->prefered_lft always (see addrconf.c)
7370 + * Returned value is in seconds.
7373 +static __u32 get_min_lifetime(struct inet6_ifaddr *ifp, __u32 lifetime)
7375 + __u32 rem_lifetime = 0;
7376 + unsigned long now = jiffies;
7378 + if (ifp->valid_lft == 0) {
7379 + rem_lifetime = lifetime;
7381 + __u32 valid_lft_left =
7382 + ifp->valid_lft - ((now - ifp->tstamp) / HZ);
7384 + min_t(unsigned long, valid_lft_left, lifetime);
7387 + return rem_lifetime;
7390 +#define MAX_LIFETIME 1000
7393 + * mipv6_lifetime_check - check maximum lifetime is not exceeded
7394 + * @lifetime: lifetime to check
7396 + * Checks @lifetime does not exceed %MAX_LIFETIME. Returns @lifetime
7397 + * if not exceeded, otherwise returns %MAX_LIFETIME.
7399 +static int mipv6_lifetime_check(int lifetime)
7401 + return (lifetime > MAX_LIFETIME) ? MAX_LIFETIME : lifetime;
7404 +/* Generic routine handling finish of BU processing */
7405 +void mipv6_bu_finish(struct inet6_ifaddr *ifp, int ifindex, __u8 ba_status,
7406 + struct in6_addr *daddr, struct in6_addr *haddr,
7407 + struct in6_addr *coa, struct in6_addr *rep_coa,
7408 + __u32 ba_lifetime, __u16 sequence, __u8 flags, __u8 *k_bu)
7412 + if (ba_status >= REASON_UNSPECIFIED) {
7417 + ba_lifetime = get_min_lifetime(ifp, ba_lifetime);
7418 + ba_lifetime = mipv6_lifetime_check(ba_lifetime);
7420 + if ((err = mipv6_bcache_add(ifindex, daddr, haddr, coa,
7421 + ba_lifetime, sequence, flags,
7422 + HOME_REGISTRATION)) != 0 ) {
7423 + DEBUG(DBG_WARNING, "home reg failed.");
7425 + if (err == -ENOMEDIUM)
7428 + ba_status = INSUFFICIENT_RESOURCES;
7430 + DEBUG(DBG_INFO, "home reg succeeded.");
7433 + DEBUG(DBG_DATADUMP, "home_addr: %x:%x:%x:%x:%x:%x:%x:%x",
7434 + NIPV6ADDR(haddr));
7435 + DEBUG(DBG_DATADUMP, "coa: %x:%x:%x:%x:%x:%x:%x:%x",
7437 + DEBUG(DBG_DATADUMP, "lifet:%d, seq:%d", ba_lifetime, sequence);
7439 + mipv6_send_ba(daddr, haddr, coa, rep_coa, ba_status, sequence,
7440 + ba_lifetime, k_bu);
7443 +static int ha_proxy_create(int flags, int ifindex, struct in6_addr *coa,
7444 + struct in6_addr *our_addr, struct in6_addr *home_addr)
7448 + if ((ret = mipv6_add_tnl_to_mn(coa, our_addr, home_addr)) <= 0) {
7449 + if (ret != -ENOMEDIUM) {
7450 + DEBUG(DBG_ERROR, "unable to configure tunnel to MN!");
7454 + if (mipv6_proxy_nd(home_addr, ifindex,
7455 + flags & MIPV6_BU_F_LLADDR) != 0) {
7456 + DEBUG(DBG_ERROR, "mipv6_proxy_nd failed!");
7457 + mipv6_del_tnl_to_mn(coa, our_addr, home_addr);
7463 +static void ha_proxy_del(struct in6_addr *home_addr, struct mipv6_bce *entry)
7465 + if (mipv6_proxy_nd_rem(&entry->home_addr, entry->ifindex,
7466 + entry->flags & MIPV6_BU_F_LLADDR) == 0) {
7467 + DEBUG(DBG_INFO, "proxy_nd succ");
7469 + DEBUG(DBG_INFO, "proxy_nd fail");
7471 + mipv6_del_tnl_to_mn(&entry->coa, &entry->our_addr, home_addr);
7474 +static void bc_home_add(int ifindex,
7475 + struct in6_addr *daddr, struct in6_addr *haddr,
7476 + struct in6_addr *coa, struct in6_addr *rep_coa,
7477 + __u32 lifetime, __u16 sequence, __u8 flags,
7480 + struct inet6_ifaddr *ifp = NULL;
7481 + __u8 ba_status = SUCCESS;
7485 + ifp = is_on_link_ipv6_address(haddr, daddr);
7487 + if (ifp == NULL) {
7488 + ba_status = NOT_HOME_SUBNET;
7489 + } else if (((ipv6_addr_type(haddr) & IPV6_ADDR_SITELOCAL) ||
7490 + (ipv6_addr_type(coa) & IPV6_ADDR_SITELOCAL))
7491 + && !mipv6_ha_tunnel_sitelocal) {
7492 + /* Site-local home or care-of addresses are not
7493 + accepted by default */
7494 + ba_status = ADMINISTRATIVELY_PROHIBITED;
7498 + ifindex = ifp->idev->dev->ifindex;
7500 + if ((ret = mipv6_dad_start(ifp, ifindex, daddr,
7501 + haddr, coa, rep_coa, lifetime,
7502 + sequence, flags)) < 0) {
7503 + /* An error occurred */
7506 + /* DAD is needed to be performed. */
7512 + mipv6_bu_finish(ifp, ifindex, ba_status, daddr, haddr, coa,
7513 + rep_coa, lifetime, sequence, flags, k_bu);
7518 +static void bc_home_delete(struct in6_addr *daddr, struct in6_addr *haddr,
7519 + struct in6_addr *coa, struct in6_addr *rep_coa,
7520 + __u16 sequence, __u8 flags, __u8 *k_bu)
7522 + __u8 status = SUCCESS;
7523 + struct mipv6_bce bce;
7525 + /* Primary Care-of Address Deregistration */
7526 + if (mipv6_bcache_get(haddr, daddr, &bce) < 0) {
7527 + DEBUG(DBG_INFO, "entry is not in cache");
7528 + status = NOT_HA_FOR_MN;
7530 + ha_proxy_del(&bce.home_addr, &bce);
7531 + mipv6_bcache_delete(haddr, daddr, HOME_REGISTRATION);
7533 + mipv6_send_ba(daddr, haddr, coa, rep_coa, status, sequence, 0, k_bu);
7536 +extern int mipv6_ra_rcv_ptr(struct sk_buff *skb, struct icmp6hdr *msg);
7540 +mipv6_ha_tnl_xmit_stats_hook(struct ip6_tnl *t, struct sk_buff *skb)
7543 + if (is_mip6_tnl(t))
7544 + MIPV6_INC_STATS(n_encapsulations);
7545 + return IP6_TNL_ACCEPT;
7548 +static struct ip6_tnl_hook_ops mipv6_ha_tnl_xmit_stats_ops = {
7550 + IP6_TNL_PRE_ENCAP,
7552 + mipv6_ha_tnl_xmit_stats_hook
7556 +mipv6_ha_tnl_rcv_stats_hook(struct ip6_tnl *t, struct sk_buff *skb)
7559 + if (is_mip6_tnl(t))
7560 + MIPV6_INC_STATS(n_decapsulations);
7561 + return IP6_TNL_ACCEPT;
7564 +static struct ip6_tnl_hook_ops mipv6_ha_tnl_rcv_stats_ops = {
7566 + IP6_TNL_PRE_DECAP,
7568 + mipv6_ha_tnl_rcv_stats_hook
7571 +static struct mip6_func old;
7573 +int __init mipv6_ha_init(void)
7577 +#ifdef CONFIG_SYSCTL
7578 + if (!(mipv6_ha_sysctl_header =
7579 + register_sysctl_table(mipv6_ha_sysctl.mipv6_root_table, 0)))
7580 + printk(KERN_ERR "Failed to register sysctl handlers!");
7582 + memcpy(&old, &mip6_fn, sizeof(struct mip6_func));
7583 + mip6_fn.bce_home_add = bc_home_add;
7584 + mip6_fn.bce_home_del = bc_home_delete;
7585 + mip6_fn.proxy_del = ha_proxy_del;
7586 + mip6_fn.proxy_create = ha_proxy_create;
7587 + /* register packet interception hooks */
7588 + ip6ip6_tnl_register_hook(&mipv6_ha_tnl_xmit_stats_ops);
7589 + ip6ip6_tnl_register_hook(&mipv6_ha_tnl_rcv_stats_ops);
7593 +void __exit mipv6_ha_exit(void)
7597 +#ifdef CONFIG_SYSCTL
7598 + unregister_sysctl_table(mipv6_ha_sysctl_header);
7601 + /* remove packet interception hooks */
7602 + ip6ip6_tnl_unregister_hook(&mipv6_ha_tnl_rcv_stats_ops);
7603 + ip6ip6_tnl_unregister_hook(&mipv6_ha_tnl_xmit_stats_ops);
7605 + mip6_fn.bce_home_add = old.bce_home_add;
7606 + mip6_fn.bce_home_del = old.bce_home_del;
7607 + mip6_fn.proxy_del = old.proxy_del;
7608 + mip6_fn.proxy_create = old.proxy_create;
7611 +++ linux-2.4.27/net/ipv6/mobile_ip6/ha.h
7614 + * MIPL Mobile IPv6 Home Agent header file
7618 + * This program is free software; you can redistribute it and/or
7619 + * modify it under the terms of the GNU General Public License
7620 + * as published by the Free Software Foundation; either version
7621 + * 2 of the License, or (at your option) any later version.
7627 +int mipv6_ha_init(void);
7628 +void mipv6_ha_exit(void);
7630 +int mipv6_dad_start(struct inet6_ifaddr *ifp, int ifindex,
7631 + struct in6_addr *daddr, struct in6_addr *haddr,
7632 + struct in6_addr *coa, struct in6_addr *rep_coa,
7633 + __u32 ba_lifetime, __u16 sequence, __u8 flags);
7635 +void mipv6_bu_finish(struct inet6_ifaddr *ifp, int ifindex,
7636 + __u8 ba_status, struct in6_addr *daddr,
7637 + struct in6_addr *haddr, struct in6_addr *coa,
7638 + struct in6_addr *rep_coa, __u32 ba_lifetime,
7639 + __u16 sequence, __u8 flags, __u8 *k_bu);
7642 +static __inline__ void mipv6_generate_ll_addr(struct in6_addr *ll_addr,
7643 + struct in6_addr *addr)
7645 + ll_addr->s6_addr32[0] = htonl(0xfe800000);
7646 + ll_addr->s6_addr32[1] = 0;
7647 + ll_addr->s6_addr32[2] = addr->s6_addr32[2];
7648 + ll_addr->s6_addr32[3] = addr->s6_addr32[3];
7653 +++ linux-2.4.27/net/ipv6/mobile_ip6/halist.c
7656 + * Home Agents List
7659 + * Antti Tuominen <ajtuomin@tml.hut.fi>
7663 + * This program is free software; you can redistribute it and/or
7664 + * modify it under the terms of the GNU General Public License
7665 + * as published by the Free Software Foundation; either version
7666 + * 2 of the License, or (at your option) any later version.
7670 +#define PREF_BASE 0xffff /* MAX value for u16 field in RA */
7672 +#include <linux/autoconf.h>
7673 +#include <linux/sched.h>
7674 +#include <linux/timer.h>
7675 +#include <linux/proc_fs.h>
7676 +#include <linux/init.h>
7677 +#include <net/ipv6.h>
7678 +#include <net/addrconf.h>
7680 +#include "hashlist.h"
7684 +struct mipv6_halist {
7685 + struct hashlist *entries;
7686 + struct timer_list expire_timer;
7689 +static rwlock_t home_agents_lock = RW_LOCK_UNLOCKED;
7691 +static struct mipv6_halist home_agents;
7693 +struct mipv6_halist_entry {
7694 + struct hashlist_entry e;
7695 + int ifindex; /* Link identifier */
7696 + struct in6_addr link_local_addr; /* HA's link-local address */
7697 + struct in6_addr global_addr; /* HA's Global address */
7699 + long preference; /* The preference for this HA */
7700 + unsigned long expire; /* expiration time (jiffies) */
7703 +static inline void mipv6_ha_ac_add(struct in6_addr *ll_addr, int ifindex,
7704 + struct in6_addr *glob_addr, int plen)
7706 + struct net_device *dev;
7708 + if ((dev = __dev_get_by_index(ifindex)) && ipv6_chk_addr(ll_addr, dev)) {
7709 + struct in6_addr addr;
7710 + mipv6_ha_anycast(&addr, glob_addr, plen);
7711 + ipv6_dev_ac_inc(dev, &addr);
7715 +static inline void mipv6_ha_ac_del(struct in6_addr *ll_addr, int ifindex,
7716 + struct in6_addr *glob_addr, int plen)
7718 + struct net_device *dev;
7720 + if ((dev = __dev_get_by_index(ifindex)) && ipv6_chk_addr(ll_addr, dev)) {
7721 + struct in6_addr addr;
7722 + mipv6_ha_anycast(&addr, glob_addr, plen);
7723 + ipv6_dev_ac_dec(dev, &addr);
7727 +struct preflist_iterator_args {
7731 + struct in6_addr *list;
7734 +static int preflist_iterator(void *data, void *args,
7735 + unsigned long *pref)
7737 + struct preflist_iterator_args *state =
7738 + (struct preflist_iterator_args *)args;
7739 + struct mipv6_halist_entry *entry =
7740 + (struct mipv6_halist_entry *)data;
7741 + struct in6_addr *newaddr =
7742 + (struct in6_addr *)state->list + state->count;
7744 + if (state->count >= state->requested)
7745 + return ITERATOR_STOP;
7747 + if (time_after(jiffies, entry->expire)) {
7748 + if (!ipv6_addr_any(&entry->link_local_addr)) {
7749 + mipv6_ha_ac_del(&entry->link_local_addr,
7751 + &entry->global_addr, entry->plen);
7753 + DEBUG(DBG_INFO, "preflist_iterator: Deleting entry with address %x:%x:%x:%x:%x:%x:%x:%x to list", NIPV6ADDR(&entry->global_addr));
7754 + return ITERATOR_DELETE_ENTRY;
7756 + if (state->ifindex != entry->ifindex)
7757 + return ITERATOR_CONT;
7759 + ipv6_addr_copy(newaddr, &entry->global_addr);
7760 + DEBUG(DBG_INFO, "preflist_iterator: adding new entry with address %x:%x:%x:%x:%x:%x:%x:%x to list", NIPV6ADDR(&entry->global_addr));
7763 + return ITERATOR_CONT;
7766 +static int gc_iterator(void *data, void *args,
7767 + unsigned long *pref)
7769 + struct mipv6_halist_entry *entry =
7770 + (struct mipv6_halist_entry *)data;
7772 + int *type = (int *)args;
7774 + if (*type == 1 || time_after(jiffies, entry->expire)) {
7775 + if (!ipv6_addr_any(&entry->link_local_addr)) {
7776 + mipv6_ha_ac_del(&entry->link_local_addr,
7778 + &entry->global_addr, entry->plen);
7780 + return ITERATOR_DELETE_ENTRY;
7783 + return ITERATOR_CONT;
7786 +static int mipv6_halist_gc(int type)
7789 + hashlist_iterate(home_agents.entries, &type, gc_iterator);
7793 +static void mipv6_halist_expire(unsigned long dummy)
7797 + write_lock(&home_agents_lock);
7798 + mipv6_halist_gc(0);
7799 + write_unlock(&home_agents_lock);
7803 +static struct mipv6_halist_entry *mipv6_halist_new_entry(void)
7805 + struct mipv6_halist_entry *entry;
7809 + entry = hashlist_alloc(home_agents.entries, SLAB_ATOMIC);
7817 + * mipv6_halist_add - Add new home agent to the Home Agents List
7818 + * @ifindex: interface identifier
7819 + * @glob_addr: home agent's global address
7820 + * @ll_addr: home agent's link-local address
7821 + * @pref: relative preference for this home agent
7822 + * @lifetime: lifetime for the entry
7824 + * Adds new home agent to the Home Agents List. The list is interface
7825 + * specific and @ifindex tells through which interface the home agent
7826 + * was heard. Returns zero on success and negative on failure.
7829 +int mipv6_halist_add(int ifindex, struct in6_addr *glob_addr, int plen,
7830 + struct in6_addr *ll_addr, unsigned int pref, __u32 lifetime)
7832 + int update = 0, ret = 0;
7833 + unsigned int mpref;
7834 + struct mipv6_halist_entry *entry = NULL;
7838 + write_lock(&home_agents_lock);
7840 + if (glob_addr == NULL || lifetime <= 0) {
7841 + DEBUG(DBG_WARNING, "invalid arguments");
7845 + mpref = PREF_BASE - pref;
7846 + if ((entry = (struct mipv6_halist_entry *)
7847 + hashlist_get(home_agents.entries, glob_addr)) != NULL) {
7848 + if (entry->ifindex == ifindex) {
7849 + DEBUG(DBG_DATADUMP, "updating old entry with address %x:%x:%x:%x:%x:%x:%x:%x", NIPV6ADDR(glob_addr));
7852 + DEBUG(DBG_INFO, "halist_add : adding new entry with address %x:%x:%x:%x:%x:%x:%x:%x", NIPV6ADDR(glob_addr));
7857 + entry->expire = jiffies + lifetime * HZ;
7858 + if (entry->preference != mpref) {
7859 + entry->preference = mpref;
7860 + ret = hashlist_reposition(home_agents.entries,
7861 + (void *)entry, mpref);
7864 + entry = mipv6_halist_new_entry();
7865 + if (entry == NULL) {
7866 + DEBUG(DBG_INFO, "list full");
7870 + entry->ifindex = ifindex;
7872 + ipv6_addr_copy(&entry->link_local_addr, ll_addr);
7873 + mipv6_ha_ac_add(ll_addr, ifindex, glob_addr, plen);
7875 + ipv6_addr_set(&entry->link_local_addr, 0, 0, 0, 0);
7877 + ipv6_addr_copy(&entry->global_addr, glob_addr);
7878 + entry->plen = plen;
7879 + entry->preference = mpref;
7880 + entry->expire = jiffies + lifetime * HZ;
7881 + ret = hashlist_add(home_agents.entries, glob_addr, mpref,
7885 + write_unlock(&home_agents_lock);
7890 + * mipv6_halist_delete - delete home agent from Home Agents List
7891 + * @glob_addr: home agent's global address
7893 + * Deletes entry for home agent @glob_addr from the Home Agent List.
7895 +int mipv6_halist_delete(struct in6_addr *glob_addr)
7897 + struct hashlist_entry *e;
7898 + struct mipv6_halist_entry *entry;
7901 + if (glob_addr == NULL) {
7902 + DEBUG(DBG_WARNING, "invalid glob addr");
7905 + write_lock(&home_agents_lock);
7906 + if ((e = hashlist_get(home_agents.entries, glob_addr)) == NULL) {
7907 + write_unlock(&home_agents_lock);
7910 + hashlist_delete(home_agents.entries, e);
7911 + entry = (struct mipv6_halist_entry *)e;
7912 + if (!ipv6_addr_any(&entry->link_local_addr)) {
7913 + mipv6_ha_ac_del(&entry->link_local_addr, entry->ifindex,
7914 + &entry->global_addr, entry->plen);
7916 + hashlist_free(home_agents.entries, e);
7917 + write_unlock(&home_agents_lock);
7922 + * mipv6_ha_get_pref_list - Get list of preferred home agents
7923 + * @ifindex: interface identifier
7924 + * @addrs: pointer to a buffer to store the list
7925 + * @max: maximum number of home agents to return
7927 + * Creates a list of @max preferred (or all known if less than @max)
7928 + * home agents. Home Agents List is interface specific so you must
7929 + * supply @ifindex. Stores list in addrs and returns number of home
7930 + * agents stored. On failure, returns a negative value.
7932 +int mipv6_ha_get_pref_list(int ifindex, struct in6_addr **addrs, int max)
7934 + struct preflist_iterator_args args;
7943 + args.requested = max;
7944 + args.ifindex = ifindex;
7945 + args.list = kmalloc(max * sizeof(struct in6_addr), GFP_ATOMIC);
7947 + if (args.list == NULL) return -ENOMEM;
7949 + read_lock(&home_agents_lock);
7950 + hashlist_iterate(home_agents.entries, &args, preflist_iterator);
7951 + read_unlock(&home_agents_lock);
7953 + if (args.count >= 0) {
7954 + *addrs = args.list;
7960 + return args.count;
7963 +struct getaddr_iterator_args {
7964 + struct net_device *dev;
7965 + struct in6_addr *addr;
7968 +static int getaddr_iterator(void *data, void *args,
7969 + unsigned long *pref)
7971 + struct mipv6_halist_entry *entry =
7972 + (struct mipv6_halist_entry *)data;
7973 + struct getaddr_iterator_args *state =
7974 + (struct getaddr_iterator_args *)args;
7976 + if (entry->ifindex != state->dev->ifindex)
7977 + return ITERATOR_CONT;
7979 + if (ipv6_chk_addr(&entry->global_addr, state->dev)) {
7980 + ipv6_addr_copy(state->addr, &entry->global_addr);
7981 + return ITERATOR_STOP;
7983 + return ITERATOR_CONT;
7987 + * Get Home Agent Address for given interface. If node is not serving
7988 + * as a HA for this interface returns negative error value.
7990 +int mipv6_ha_get_addr(int ifindex, struct in6_addr *addr)
7992 + struct getaddr_iterator_args args;
7993 + struct net_device *dev;
7998 + if ((dev = dev_get_by_index(ifindex)) == NULL)
8001 + memset(addr, 0, sizeof(struct in6_addr));
8004 + read_lock(&home_agents_lock);
8005 + hashlist_iterate(home_agents.entries, &args, getaddr_iterator);
8006 + read_unlock(&home_agents_lock);
8009 + if (ipv6_addr_any(addr))
8015 +#define HALIST_INFO_LEN 81
8017 +struct procinfo_iterator_args {
8025 +static int procinfo_iterator(void *data, void *args,
8026 + unsigned long *pref)
8028 + struct procinfo_iterator_args *arg =
8029 + (struct procinfo_iterator_args *)args;
8030 + struct mipv6_halist_entry *entry =
8031 + (struct mipv6_halist_entry *)data;
8032 + unsigned long int expire;
8036 + if (entry == NULL) return ITERATOR_ERR;
8038 + if (time_after(jiffies, entry->expire)) {
8039 + if (!ipv6_addr_any(&entry->link_local_addr)) {
8040 + mipv6_ha_ac_del(&entry->link_local_addr,
8042 + &entry->global_addr, entry->plen);
8044 + return ITERATOR_DELETE_ENTRY;
8046 + if (arg->skip < arg->offset / HALIST_INFO_LEN) {
8048 + return ITERATOR_CONT;
8051 + if (arg->len >= arg->length)
8052 + return ITERATOR_CONT;
8054 + expire = (entry->expire - jiffies) / HZ;
8056 + arg->len += sprintf(arg->buffer + arg->len,
8057 + "%02d %08x%08x%08x%08x %08x%08x%08x%08x %05ld %05ld\n",
8059 + ntohl(entry->global_addr.s6_addr32[0]),
8060 + ntohl(entry->global_addr.s6_addr32[1]),
8061 + ntohl(entry->global_addr.s6_addr32[2]),
8062 + ntohl(entry->global_addr.s6_addr32[3]),
8063 + ntohl(entry->link_local_addr.s6_addr32[0]),
8064 + ntohl(entry->link_local_addr.s6_addr32[1]),
8065 + ntohl(entry->link_local_addr.s6_addr32[2]),
8066 + ntohl(entry->link_local_addr.s6_addr32[3]),
8067 + -(entry->preference - PREF_BASE), expire);
8069 + return ITERATOR_CONT;
8072 +static int halist_proc_info(char *buffer, char **start, off_t offset,
8075 + struct procinfo_iterator_args args;
8079 + args.buffer = buffer;
8080 + args.offset = offset;
8081 + args.length = length;
8085 + read_lock_bh(&home_agents_lock);
8086 + hashlist_iterate(home_agents.entries, &args, procinfo_iterator);
8087 + read_unlock_bh(&home_agents_lock);
8091 + *start += offset % HALIST_INFO_LEN;
8093 + args.len -= offset % HALIST_INFO_LEN;
8095 + if (args.len > length)
8096 + args.len = length;
8103 +static int halist_compare(void *data, void *hashkey)
8105 + struct mipv6_halist_entry *e = (struct mipv6_halist_entry *)data;
8106 + struct in6_addr *key = (struct in6_addr *)hashkey;
8108 + return ipv6_addr_cmp(&e->global_addr, key);
8111 +static __u32 halist_hash(void *hashkey)
8113 + struct in6_addr *key = (struct in6_addr *)hashkey;
8116 + hash = key->s6_addr32[0] ^
8117 + key->s6_addr32[1] ^
8118 + key->s6_addr32[2] ^
8119 + key->s6_addr32[3];
8124 +int __init mipv6_halist_init(__u32 size)
8129 + DEBUG(DBG_ERROR, "size must be at least 1");
8132 + init_timer(&home_agents.expire_timer);
8133 + home_agents.expire_timer.data = 0;
8134 + home_agents.expire_timer.function = mipv6_halist_expire;
8135 + home_agents_lock = RW_LOCK_UNLOCKED;
8137 + home_agents.entries = hashlist_create(16, size, sizeof(struct mipv6_halist_entry),
8138 + "mip6_halist", NULL, NULL,
8139 + halist_compare, halist_hash);
8141 + if (home_agents.entries == NULL) {
8142 + DEBUG(DBG_ERROR, "Failed to initialize hashlist");
8146 + proc_net_create("mip6_home_agents", 0, halist_proc_info);
8147 + DEBUG(DBG_INFO, "Home Agents List initialized");
8151 +void __exit mipv6_halist_exit(void)
8154 + proc_net_remove("mip6_home_agents");
8155 + write_lock_bh(&home_agents_lock);
8156 + DEBUG(DBG_INFO, "Stopping the halist timer");
8157 + del_timer(&home_agents.expire_timer);
8158 + mipv6_halist_gc(1);
8159 + write_unlock_bh(&home_agents_lock);
8160 + hashlist_destroy(home_agents.entries);
8163 +++ linux-2.4.27/net/ipv6/mobile_ip6/halist.h
8166 + * MIPL Mobile IPv6 Home Agents List header file
8170 + * This program is free software; you can redistribute it and/or
8171 + * modify it under the terms of the GNU General Public License
8172 + * as published by the Free Software Foundation; either version
8173 + * 2 of the License, or (at your option) any later version.
8179 +int mipv6_halist_init(__u32 size);
8181 +void mipv6_halist_exit(void);
8183 +int mipv6_halist_add(int ifindex, struct in6_addr *glob_addr, int plen,
8184 + struct in6_addr *ll_addr, unsigned int pref, __u32 lifetime);
8186 +int mipv6_halist_delete(struct in6_addr *glob_addr);
8188 +int mipv6_ha_get_pref_list(int ifindex, struct in6_addr **addrs, int max);
8190 +int mipv6_ha_get_addr(int ifindex, struct in6_addr *addr);
8192 +#endif /* _HALIST_H */
8194 +++ linux-2.4.27/net/ipv6/mobile_ip6/hashlist.c
8197 + * Generic hashtable with chaining. Supports secodary sort order
8198 + * with doubly linked-list.
8201 + * Sami Kivisaari <skivisaa@cc.hut.fi>
8202 + * Antti Tuominen <ajtuomin@tml.hut.fi>
8204 + * $Id: s.hashlist.c 1.21 02/10/07 19:31:52+03:00 antti@traci.mipl.mediapoli.com $
8206 + * This program is free software; you can redistribute it and/or
8207 + * modify it under the terms of the GNU General Public License as
8208 + * published by the Free Software Foundation; either version 2 of
8209 + * the License, or (at your option) any later version.
8212 +#include <linux/slab.h>
8213 +#include "hashlist.h"
8217 + int count; /* entry count */
8218 + int maxcount; /* max entries */
8219 + __u32 bucketnum; /* hash buckets */
8221 + kmem_cache_t *kmem;
8223 + struct list_head *hashtable;
8224 + struct list_head sortedlist;
8226 + int (*compare)(void *data, void *hashkey);
8227 + __u32 (*hash_function)(void *hashkey);
8231 + * hashlist_create - Create new hashlist
8232 + * @bucketnum: number of hash buckets
8233 + * @maxentries: maximum number of entries (0 = no limit)
8234 + * @size: entry size in bytes
8235 + * @name: name for kmem_cache_t
8236 + * @ctor: kmem_cache_t constructor
8237 + * @dtor: kmem_cache_t destructor
8238 + * @compare: compare function for key
8239 + * @hash_function: hash function
8241 + * Creates a hashlist structure with @max_entries entries of @size
8242 + * bytes. User must supply @hash_function and @compare function for
8243 + * the hashlist. User can also supply @ctor and @dtor for kmem_cache.
8245 +struct hashlist *hashlist_create(int bucketnum, int max_entries, size_t size,
8247 + void (*ctor)(void *, kmem_cache_t *, unsigned long),
8248 + void (*dtor)(void *, kmem_cache_t *, unsigned long),
8249 + int (*compare)(void *data, void *hashkey),
8250 + __u32 (*hash_function)(void *hashkey))
8253 + struct hashlist *hl;
8255 + if (!compare || !hash_function)
8258 + hl = kmalloc(sizeof(struct hashlist), GFP_ATOMIC);
8259 + if (!hl) goto hlfailed;
8261 + hl->kmem = kmem_cache_create(name, size, 0, 0, ctor, dtor);
8262 + if (!hl->kmem) goto poolfailed;
8264 + hl->hashtable = kmalloc(
8265 + sizeof(struct list_head) * bucketnum, GFP_ATOMIC);
8266 + if (!hl->hashtable) goto hashfailed;
8268 + for (i = 0; i < bucketnum; i++)
8269 + INIT_LIST_HEAD(&hl->hashtable[i]);
8271 + INIT_LIST_HEAD(&hl->sortedlist);
8273 + hl->maxcount = max_entries;
8275 + hl->bucketnum = bucketnum;
8276 + hl->compare = compare;
8277 + hl->hash_function = hash_function;
8282 + kmem_cache_destroy(hl->kmem);
8289 + DEBUG(DBG_ERROR, "could not create hashlist");
8295 + * hashlist_destroy - Destroy hashlist
8296 + * @hashlist: hashlist to destroy
8298 + * Frees all memory allocated for a hashlist.
8300 +void hashlist_destroy(struct hashlist *hashlist)
8304 + if (hashlist == NULL) return;
8306 + if (hashlist->hashtable) {
8307 + kfree(hashlist->hashtable);
8308 + hashlist->hashtable = NULL;
8311 + if (hashlist->kmem) {
8312 + kmem_cache_destroy(hashlist->kmem);
8313 + hashlist->kmem = NULL;
8322 + * Insert a chain of entries to hashlist into correct order. The
8323 + * entries are assumed to have valid hashkeys. We use time_after_eq
8324 + * for comparing, since it handles wrap-around correctly, and the
8325 + * sortkey is usually jiffies.
8327 +static void sorted_insert(struct list_head *lh, struct hashlist_entry *he)
8329 + struct list_head *p;
8330 + struct hashlist_entry *hlp = NULL;
8331 + unsigned long sortkey = he->sortkey;
8333 + if (list_empty(lh)) {
8334 + list_add(&he->sorted, lh);
8338 + list_for_each(p, lh) {
8339 + hlp = list_entry(p, typeof(*hlp), sorted);
8340 + if (time_after_eq(hlp->sortkey, sortkey)) {
8341 + list_add(&he->sorted, hlp->sorted.prev);
8345 + list_add(&he->sorted, &hlp->sorted);
8349 + * hashlist_iterate - Apply function for all elements in a hash list
8350 + * @hashlist: pointer to hashlist
8351 + * @args: data to pass to the function
8352 + * @func: pointer to a function
8354 + * Apply arbitrary function @func to all elements in a hash list.
8355 + * @func must be a pointer to a function with the following prototype:
8356 + * int func(void *entry, void *arg, struct in6_addr *hashkey, unsigned
8357 + * long *sortkey). Function must return %ITERATOR_STOP,
8358 + * %ITERATOR_CONT or %ITERATOR_DELETE_ENTRY. %ITERATOR_STOP stops
8359 + * iterator and returns last return value from the function.
8360 + * %ITERATOR_CONT continues with iteration. %ITERATOR_DELETE_ENTRY
8361 + * deletes current entry from the hashlist. If function changes
8362 + * hashlist element's sortkey, iterator automatically schedules
8363 + * element to be reinserted after all elements have been processed.
8365 +int hashlist_iterate(
8366 + struct hashlist *hashlist, void *args,
8367 + hashlist_iterator_t func)
8369 + int res = ITERATOR_CONT;
8370 + unsigned long skey;
8371 + struct list_head *p, *n, repos;
8372 + struct hashlist_entry *he;
8375 + INIT_LIST_HEAD(&repos);
8377 + list_for_each_safe(p, n, &hashlist->sortedlist) {
8378 + he = list_entry(p, typeof(*he), sorted);
8379 + if (res == ITERATOR_STOP)
8381 + skey = he->sortkey;
8382 + res = func(he, args, &he->sortkey);
8383 + if (res == ITERATOR_DELETE_ENTRY) {
8384 + hashlist_delete(hashlist, he);
8385 + hashlist_free(hashlist, he);
8386 + } else if (skey != he->sortkey) {
8387 + /* iterator changed the sortkey, schedule for
8388 + * repositioning */
8389 + list_move(&he->sorted, &repos);
8392 + list_for_each_safe(p, n, &repos) {
8393 + he = list_entry(p, typeof(*he), sorted);
8394 + sorted_insert(&hashlist->sortedlist, he);
8400 + * hashlist_alloc - Allocate memory for a hashlist entry
8401 + * @hashlist: hashlist for allocated entry
8402 + * @size: size of entry in bytes
8404 + * Allocates @size bytes memory from @hashlist->kmem.
8406 +void *hashlist_alloc(struct hashlist *hashlist, int type)
8408 + if (hashlist == NULL) return NULL;
8409 + return kmem_cache_alloc(hashlist->kmem, type);
8413 + * hashlist_free - Free hashlist entry
8414 + * @hashlist: hashlist where @he is
8415 + * @he: entry to free
8417 + * Frees an allocated hashlist entry.
8419 +void hashlist_free(struct hashlist *hashlist, struct hashlist_entry *he)
8421 + kmem_cache_free(hashlist->kmem, he);
8425 + * hashlist_add - Add element to hashlist
8426 + * @hashlist: pointer to hashlist
8427 + * @hashkey: hashkey for the element
8428 + * @sortkey: key for sorting
8429 + * @data: element data
8431 + * Add element to hashlist. Hashlist is also sorted in a linked list
8434 +int hashlist_add(struct hashlist *hashlist, void *hashkey,
8435 + unsigned long sortkey, void *entry)
8437 + struct hashlist_entry *he = (struct hashlist_entry *)entry;
8438 + unsigned int hash;
8440 + if (hashlist->count >= hashlist->maxcount)
8443 + hashlist->count++;
8445 + /* link the entry to sorted order */
8446 + he->sortkey = sortkey;
8447 + sorted_insert(&hashlist->sortedlist, he);
8449 + /* hash the entry */
8450 + hash = hashlist->hash_function(hashkey) % hashlist->bucketnum;
8451 + list_add(&he->hashlist, &hashlist->hashtable[hash]);
8457 + * hashlist_get_ex - Get element from hashlist
8458 + * @hashlist: hashlist
8459 + * @hashkey: hashkey of the desired entry
8461 + * Lookup entry with @hashkey from the hash table using @compare
8462 + * function for entry comparison. Returns entry on success, otherwise
8465 +struct hashlist_entry *hashlist_get_ex(
8466 + struct hashlist *hashlist, void *hashkey,
8467 + int (*compare)(void *data, void *hashkey))
8469 + struct list_head *p, *bkt;
8472 + hash = hashlist->hash_function(hashkey) % hashlist->bucketnum;
8473 + bkt = &hashlist->hashtable[hash];
8475 + /* scan the entries within the same hashbucket */
8476 + list_for_each(p, bkt) {
8477 + struct hashlist_entry *he = list_entry(p, typeof(*he),
8479 + if (compare(he, hashkey) == 0)
8487 + * hashlist_get - Get element from hashlist
8488 + * @hashlist: hashlist
8489 + * @hashkey: hashkey of the desired entry
8491 + * Lookup entry with @hashkey from the hash table. Returns entry on
8492 + * success, otherwise %NULL.
8494 +struct hashlist_entry *hashlist_get(struct hashlist *hashlist, void *hashkey)
8496 + return hashlist_get_ex(hashlist, hashkey, hashlist->compare);
8500 + * hashlist_reposition - set entry to new position in the list
8501 + * @hashlist: hashlist
8502 + * @he: entry to reposition
8503 + * @sortkey: new sortkey of the entry
8505 + * If secondary order sortkey changes, entry must be repositioned in
8506 + * the sorted list.
8508 +int hashlist_reposition(struct hashlist *hashlist, struct hashlist_entry *he,
8509 + unsigned long sortkey)
8511 + list_del(&he->sorted);
8512 + he->sortkey = sortkey;
8513 + sorted_insert(&hashlist->sortedlist, he);
8519 + * hashlist_delete - Delete entry from hashlist
8520 + * @hashlist: hashlist where entry is
8521 + * @he: entry to delete
8523 + * Deletes an entry from the hashlist and sorted list.
8525 +void hashlist_delete(struct hashlist *hashlist,
8526 + struct hashlist_entry *he)
8528 + list_del_init(&he->hashlist);
8529 + list_del_init(&he->sorted);
8531 + hashlist->count--;
8535 + * hashlist_get_first - Get first item from sorted list
8536 + * @hashlist: pointer to hashlist
8538 + * Returns first item in the secondary sort order.
8540 +void * hashlist_get_first(struct hashlist *hashlist)
8542 + if (list_empty(&hashlist->sortedlist))
8545 + return list_entry(hashlist->sortedlist.next, struct hashlist_entry, sorted);
8548 +++ linux-2.4.27/net/ipv6/mobile_ip6/hashlist.h
8551 + * MIPL Mobile IPv6 Hashlist header file
8555 + * This program is free software; you can redistribute it and/or
8556 + * modify it under the terms of the GNU General Public License
8557 + * as published by the Free Software Foundation; either version
8558 + * 2 of the License, or (at your option) any later version.
8561 +#ifndef _HASHLIST_H
8562 +#define _HASHLIST_H
8564 +#define ITERATOR_ERR -1
8565 +#define ITERATOR_CONT 0
8566 +#define ITERATOR_STOP 1
8567 +#define ITERATOR_DELETE_ENTRY 2
8569 +struct kmem_cache_t;
8571 +struct hashlist_entry {
8572 + unsigned long sortkey;
8573 + struct list_head sorted;
8574 + struct list_head hashlist;
8577 +struct hashlist * hashlist_create(
8578 + int bucketnum, int max_entries, size_t size, char *name,
8579 + void (*ctor)(void *, kmem_cache_t *, unsigned long),
8580 + void (*dtor)(void *, kmem_cache_t *, unsigned long),
8581 + int (*compare)(void *data, void *hashkey),
8582 + __u32 (*hash_function)(void *hashkey));
8584 +void hashlist_destroy(struct hashlist *hashlist);
8586 +void *hashlist_alloc(struct hashlist *hashlist, int type);
8588 +void hashlist_free(struct hashlist *hashlist, struct hashlist_entry *he);
8590 +struct hashlist_entry *hashlist_get(struct hashlist *hashlist, void *hashkey);
8592 +struct hashlist_entry *hashlist_get_ex(
8593 + struct hashlist *hashlist, void *hashkey,
8594 + int (*compare)(void *data, void *hashkey));
8596 +int hashlist_add(struct hashlist *hashlist, void *hashkey,
8597 + unsigned long sortkey, void *data);
8599 +void hashlist_delete(struct hashlist *hashlist, struct hashlist_entry *he);
8601 +/* iterator function */
8602 +typedef int (*hashlist_iterator_t)(void *, void *, unsigned long *);
8604 +int hashlist_iterate(struct hashlist *hashlist, void *args,
8605 + hashlist_iterator_t func);
8607 +void * hashlist_get_first(struct hashlist *hashlist);
8609 +int hashlist_reposition(struct hashlist *hashlist, struct hashlist_entry *he,
8610 + unsigned long sortkey);
8614 +++ linux-2.4.27/net/ipv6/mobile_ip6/hmac.c
8616 +/* Authentication algorithms
8619 + * Alexis Olivereau <Alexis.Olivereau@crm.mot.com>
8623 + * This program is free software; you can redistribute it and/or
8624 + * modify it under the terms of the GNU General Public License
8625 + * as published by the Free Software Foundation; either version
8626 + * 2 of the License, or (at your option) any later version.
8629 + * Henrik Petander : Cleaned up unused parts
8633 +#include <linux/sched.h>
8634 +#include <linux/tty.h>
8635 +#include <linux/types.h>
8636 +#include <linux/slab.h>
8637 +#include <linux/in6.h>
8640 +#define LROLL(x, s) (((x) << (s)) | ((x) >> (32 - (s))))
8643 +#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
8644 +#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
8645 +#define H(x, y, z) ((x) ^ (y) ^ (z))
8646 +#define I(x, y, z) ((y) ^ ((x) | ~(z)))
8648 +#define FF(a, b, c, d, m, s, t) { \
8649 + (a) += F ((b), (c), (d)) + (m) + (t); \
8650 + (a) = LROLL((a), (s)); \
8653 +#define GG(a, b, c, d, m, s, t) { \
8654 + (a) += G ((b), (c), (d)) + (m) + (t); \
8655 + (a) = LROLL((a), (s)); \
8658 +#define HH(a, b, c, d, m, s, t) { \
8659 + (a) += H ((b), (c), (d)) + (m) + (t); \
8660 + (a) = LROLL((a), (s)); \
8663 +#define II(a, b, c, d, m, s, t) { \
8664 + (a) += I ((b), (c), (d)) + (m) + (t); \
8665 + (a) = LROLL((a), (s)); \
8687 +#define f(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
8688 +#define g(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
8689 +#define h(x, y, z) ((x) ^ (y) ^ (z))
8691 +#define K1 0x5a827999
8692 +#define K2 0x6ed9eba1
8693 +#define K3 0x8f1bbcdc
8694 +#define K4 0xca62c1d6
8696 +int ah_hmac_md5_init(struct ah_processing *ahp, u_int8_t *key, u_int32_t key_len)
8700 + uint32_t ipad = 0x36363636;
8701 + uint8_t extkey[64];
8703 + ahp->key_auth = key;
8704 + ahp->key_auth_len = key_len;
8705 + ahp->context = (void *) kmalloc(sizeof(MD5_CTX), GFP_ATOMIC);
8706 + if (ahp->context == NULL)
8708 + md5_init((MD5_CTX *) ahp->context);
8709 + if ((64 * sizeof(uint8_t)) < ahp->key_auth_len) {
8710 + printk("buffer overflow!");
8713 + memcpy(extkey, ahp->key_auth, ahp->key_auth_len);
8714 + if (ahp->key_auth_len % 4) {
8715 + memset(extkey + ahp->key_auth_len, 0,
8716 + 4 - (ahp->key_auth_len % 4));
8718 + key_up4 = ((ahp->key_auth_len + 0x3) & 0xFFFFFFFC) / 4;
8720 + for (i = 0; i < key_up4; i++)
8721 + ((uint32_t *) extkey)[i] = ((uint32_t *) extkey)[i] ^ ipad;
8722 + for (i = key_up4; i < 16; i++)
8723 + ((uint32_t *) extkey)[i] = ipad;
8725 + md5_compute((MD5_CTX *) ahp->context, extkey, 64);
8729 +void ah_hmac_md5_loop(struct ah_processing *ahp, void *str, uint32_t len)
8731 + md5_compute((MD5_CTX *) ahp->context, str, len);
8734 +void ah_hmac_md5_result(struct ah_processing *ahp, char *digest)
8736 + uint8_t inner[HMAC_MD5_HASH_LEN];
8739 + uint32_t opad = 0x5c5c5c5c;
8740 + uint8_t extkey[64];
8742 + md5_final((MD5_CTX *) ahp->context, inner);
8743 + md5_init((MD5_CTX *) ahp->context);
8745 + memcpy(extkey, ahp->key_auth, ahp->key_auth_len);
8746 + if (ahp->key_auth_len % 4) {
8747 + memset(extkey + ahp->key_auth_len, 0,
8748 + 4 - (ahp->key_auth_len % 4));
8750 + key_up4 = ((ahp->key_auth_len + 0x3) & 0xFFFFFFFC) / 4;
8752 + for (i = 0; i < key_up4; i++)
8753 + ((uint32_t *) extkey)[i] = ((uint32_t *) extkey)[i] ^ opad;
8754 + for (i = key_up4; i < 16; i++)
8755 + ((uint32_t *) extkey)[i] = opad;
8757 + md5_compute((MD5_CTX *) ahp->context, extkey, 64);
8758 + md5_compute((MD5_CTX *) ahp->context, inner, HMAC_MD5_HASH_LEN);
8760 + md5_final((MD5_CTX *) ahp->context, digest);
8762 + kfree(ahp->context);
8765 +int ah_hmac_sha1_init(struct ah_processing *ahp, u_int8_t *key, u_int32_t key_len)
8769 + uint32_t ipad = 0x36363636;
8770 + uint8_t extkey[64];
8772 + ahp->key_auth = key;
8773 + ahp->key_auth_len = key_len;
8775 + ahp->context = (void *) kmalloc(sizeof(SHA1_CTX), GFP_ATOMIC);
8776 + //if (ahp->context == NULL)
8779 + sha1_init((SHA1_CTX *) ahp->context);
8781 + memcpy(extkey, ahp->key_auth, ahp->key_auth_len);
8782 + if (ahp->key_auth_len % 4) {
8783 + memset(extkey + ahp->key_auth_len, 0,
8784 + 4 - (ahp->key_auth_len % 4));
8786 + key_up4 = ((ahp->key_auth_len + 0x3) & 0xFFFFFFFC) / 4;
8788 + for (i = 0; i < key_up4; i++)
8789 + ((uint32_t *) extkey)[i] = ((uint32_t *) extkey)[i] ^ ipad;
8790 + for (i = key_up4; i < 16; i++)
8791 + ((uint32_t *) extkey)[i] = ipad;
8793 + sha1_compute((SHA1_CTX *) ahp->context, extkey, 64);
8797 +void ah_hmac_sha1_loop(struct ah_processing *ahp, void *str, uint32_t len)
8801 + sha1_compute((SHA1_CTX *) ahp->context, str, len);
8804 +void ah_hmac_sha1_result(struct ah_processing *ahp, char *digest)
8806 + uint8_t inner[HMAC_SHA1_HASH_LEN];
8809 + uint32_t opad = 0x5c5c5c5c;
8810 + uint8_t extkey[64];
8814 + sha1_final((SHA1_CTX *) ahp->context, inner);
8815 + sha1_init((SHA1_CTX *) ahp->context);
8817 + memcpy(extkey, ahp->key_auth, ahp->key_auth_len);
8818 + if (ahp->key_auth_len % 4) {
8819 + memset(extkey + ahp->key_auth_len, 0,
8820 + 4 - (ahp->key_auth_len % 4));
8822 + key_up4 = ((ahp->key_auth_len + 0x3) & 0xFFFFFFFC) / 4;
8824 + for (i = 0; i < key_up4; i++)
8825 + ((uint32_t *) extkey)[i] = ((uint32_t *) extkey)[i] ^ opad;
8826 + for (i = key_up4; i < 16; i++)
8827 + ((uint32_t *) extkey)[i] = opad;
8829 + sha1_compute((SHA1_CTX *) ahp->context, extkey, 64);
8830 + sha1_compute((SHA1_CTX *) ahp->context, inner,
8831 + HMAC_SHA1_HASH_LEN);
8833 + sha1_final((SHA1_CTX *) ahp->context, digest);
8835 + kfree(ahp->context);
8838 +void md5_init(MD5_CTX * ctx)
8840 + ctx->A = 0x67452301;
8841 + ctx->B = 0xefcdab89;
8842 + ctx->C = 0x98badcfe;
8843 + ctx->D = 0x10325476;
8844 + ctx->buf_cur = ctx->buf;
8845 + ctx->bitlen[0] = ctx->bitlen[1] = 0;
8846 + memset(ctx->buf, 0, 64);
8849 +void md5_over_block(MD5_CTX * ctx, uint8_t * data)
8852 + uint32_t a = ctx->A;
8853 + uint32_t b = ctx->B;
8854 + uint32_t c = ctx->C;
8855 + uint32_t d = ctx->D;
8857 + create_M_blocks(M, data);
8860 + FF(a, b, c, d, M[0], s11, 0xd76aa478); /* 1 */
8861 + FF(d, a, b, c, M[1], s12, 0xe8c7b756); /* 2 */
8862 + FF(c, d, a, b, M[2], s13, 0x242070db); /* 3 */
8863 + FF(b, c, d, a, M[3], s14, 0xc1bdceee); /* 4 */
8864 + FF(a, b, c, d, M[4], s11, 0xf57c0faf); /* 5 */
8865 + FF(d, a, b, c, M[5], s12, 0x4787c62a); /* 6 */
8866 + FF(c, d, a, b, M[6], s13, 0xa8304613); /* 7 */
8867 + FF(b, c, d, a, M[7], s14, 0xfd469501); /* 8 */
8868 + FF(a, b, c, d, M[8], s11, 0x698098d8); /* 9 */
8869 + FF(d, a, b, c, M[9], s12, 0x8b44f7af); /* 10 */
8870 + FF(c, d, a, b, M[10], s13, 0xffff5bb1); /* 11 */
8871 + FF(b, c, d, a, M[11], s14, 0x895cd7be); /* 12 */
8872 + FF(a, b, c, d, M[12], s11, 0x6b901122); /* 13 */
8873 + FF(d, a, b, c, M[13], s12, 0xfd987193); /* 14 */
8874 + FF(c, d, a, b, M[14], s13, 0xa679438e); /* 15 */
8875 + FF(b, c, d, a, M[15], s14, 0x49b40821); /* 16 */
8878 + GG(a, b, c, d, M[1], s21, 0xf61e2562); /* 17 */
8879 + GG(d, a, b, c, M[6], s22, 0xc040b340); /* 18 */
8880 + GG(c, d, a, b, M[11], s23, 0x265e5a51); /* 19 */
8881 + GG(b, c, d, a, M[0], s24, 0xe9b6c7aa); /* 20 */
8882 + GG(a, b, c, d, M[5], s21, 0xd62f105d); /* 21 */
8883 + GG(d, a, b, c, M[10], s22, 0x02441453); /* 22 */
8884 + GG(c, d, a, b, M[15], s23, 0xd8a1e681); /* 23 */
8885 + GG(b, c, d, a, M[4], s24, 0xe7d3fbc8); /* 24 */
8886 + GG(a, b, c, d, M[9], s21, 0x21e1cde6); /* 25 */
8887 + GG(d, a, b, c, M[14], s22, 0xc33707d6); /* 26 */
8888 + GG(c, d, a, b, M[3], s23, 0xf4d50d87); /* 27 */
8889 + GG(b, c, d, a, M[8], s24, 0x455a14ed); /* 28 */
8890 + GG(a, b, c, d, M[13], s21, 0xa9e3e905); /* 29 */
8891 + GG(d, a, b, c, M[2], s22, 0xfcefa3f8); /* 30 */
8892 + GG(c, d, a, b, M[7], s23, 0x676f02d9); /* 31 */
8893 + GG(b, c, d, a, M[12], s24, 0x8d2a4c8a); /* 32 */
8896 + HH(a, b, c, d, M[5], s31, 0xfffa3942); /* 33 */
8897 + HH(d, a, b, c, M[8], s32, 0x8771f681); /* 34 */
8898 + HH(c, d, a, b, M[11], s33, 0x6d9d6122); /* 35 */
8899 + HH(b, c, d, a, M[14], s34, 0xfde5380c); /* 36 */
8900 + HH(a, b, c, d, M[1], s31, 0xa4beea44); /* 37 */
8901 + HH(d, a, b, c, M[4], s32, 0x4bdecfa9); /* 38 */
8902 + HH(c, d, a, b, M[7], s33, 0xf6bb4b60); /* 39 */
8903 + HH(b, c, d, a, M[10], s34, 0xbebfbc70); /* 40 */
8904 + HH(a, b, c, d, M[13], s31, 0x289b7ec6); /* 41 */
8905 + HH(d, a, b, c, M[0], s32, 0xeaa127fa); /* 42 */
8906 + HH(c, d, a, b, M[3], s33, 0xd4ef3085); /* 43 */
8907 + HH(b, c, d, a, M[6], s34, 0x4881d05); /* 44 */
8908 + HH(a, b, c, d, M[9], s31, 0xd9d4d039); /* 45 */
8909 + HH(d, a, b, c, M[12], s32, 0xe6db99e5); /* 46 */
8910 + HH(c, d, a, b, M[15], s33, 0x1fa27cf8); /* 47 */
8911 + HH(b, c, d, a, M[2], s34, 0xc4ac5665); /* 48 */
8914 + II(a, b, c, d, M[0], s41, 0xf4292244); /* 49 */
8915 + II(d, a, b, c, M[7], s42, 0x432aff97); /* 50 */
8916 + II(c, d, a, b, M[14], s43, 0xab9423a7); /* 51 */
8917 + II(b, c, d, a, M[5], s44, 0xfc93a039); /* 52 */
8918 + II(a, b, c, d, M[12], s41, 0x655b59c3); /* 53 */
8919 + II(d, a, b, c, M[3], s42, 0x8f0ccc92); /* 54 */
8920 + II(c, d, a, b, M[10], s43, 0xffeff47d); /* 55 */
8921 + II(b, c, d, a, M[1], s44, 0x85845dd1); /* 56 */
8922 + II(a, b, c, d, M[8], s41, 0x6fa87e4f); /* 57 */
8923 + II(d, a, b, c, M[15], s42, 0xfe2ce6e0); /* 58 */
8924 + II(c, d, a, b, M[6], s43, 0xa3014314); /* 59 */
8925 + II(b, c, d, a, M[13], s44, 0x4e0811a1); /* 60 */
8926 + II(a, b, c, d, M[4], s41, 0xf7537e82); /* 61 */
8927 + II(d, a, b, c, M[11], s42, 0xbd3af235); /* 62 */
8928 + II(c, d, a, b, M[2], s43, 0x2ad7d2bb); /* 63 */
8929 + II(b, c, d, a, M[9], s44, 0xeb86d391); /* 64 */
8937 +void create_M_blocks(uint32_t * M, uint8_t * data)
8939 +#ifdef HAVE_LITTLE_ENDIAN
8940 + memcpy((uint8_t *) M, data, 64);
8941 +#endif /* HAVE_LITTLE_ENDIAN */
8943 +#ifdef HAVE_BIG_ENDIAN
8945 + for (i = 0; i < 16; i++, data += 4) {
8946 + ((uint8_t *) (&M[i]))[0] = data[3];
8947 + ((uint8_t *) (&M[i]))[1] = data[2];
8948 + ((uint8_t *) (&M[i]))[2] = data[1];
8949 + ((uint8_t *) (&M[i]))[3] = data[0];
8951 +#endif /* HAVE_BIG_ENDIAN */
8954 +void md5_compute(MD5_CTX * ctx, uint8_t * data, uint32_t len)
8956 + uint8_t pos = ((ctx->bitlen[0] >> 3) & 0x3f);
8958 + /* First we update the bit length */
8959 + if ((ctx->bitlen[0] += (len << 3)) < (len << 3))
8961 + ctx->bitlen[1] += (len >> 29); /* len is expressed in bytes */
8964 + /* Buffer is not empty */
8965 + if (64 - pos >= len) {
8966 + memcpy(ctx->buf_cur, data, len);
8967 + ctx->buf_cur += len;
8970 + /* The current block is over */
8971 + md5_over_block(ctx, ctx->buf);
8972 + ctx->buf_cur = ctx->buf;
8976 + memcpy(ctx->buf_cur, data, 64 - pos);
8977 + md5_over_block(ctx, ctx->buf);
8978 + len -= (64 - pos);
8979 + data += (64 - pos);
8980 + ctx->buf_cur = ctx->buf;
8983 + while (len >= 64) {
8984 + md5_over_block(ctx, data);
8989 + memcpy(ctx->buf_cur, data, len);
8990 + ctx->buf_cur += len;
8994 +void md5_final(MD5_CTX * ctx, uint8_t * digest)
8996 + uint32_t rem_size;
8997 + uint8_t *buf_cur = ctx->buf_cur;
9000 + rem_size = 64 - ((ctx->bitlen[0] >> 3) & 0x3f);
9001 + *(buf_cur++) = 0x80;
9003 + if (rem_size > 8 + 1) {
9004 + /* We have enough room in the current block */
9005 + for (i = 0; i < rem_size - 8 - 1; i++) {
9009 + /* We do not have enough room and need therefore to add a new
9011 + for (i = 0; i < rem_size - 1; i++) {
9014 + md5_over_block(ctx, ctx->buf);
9016 + buf_cur = ctx->buf;
9017 + for (i = 0; i < 64 - 8; i++) {
9021 +#ifdef HAVE_LITTLE_ENDIAN
9022 + memcpy(buf_cur, (uint8_t *) ctx->bitlen, 8);
9023 +#endif /* HAVE_LITTLE_ENDIAN */
9025 +#ifdef HAVE_BIG_ENDIAN
9026 + *(buf_cur++) = (ctx->bitlen[0] >> 24) & 0xff;
9027 + *(buf_cur++) = (ctx->bitlen[0] >> 16) & 0xff;
9028 + *(buf_cur++) = (ctx->bitlen[0] >> 8) & 0xff;
9029 + *(buf_cur++) = (ctx->bitlen[0] >> 0) & 0xff;
9030 + *(buf_cur++) = (ctx->bitlen[1] >> 24) & 0xff;
9031 + *(buf_cur++) = (ctx->bitlen[1] >> 16) & 0xff;
9032 + *(buf_cur++) = (ctx->bitlen[1] >> 8) & 0xff;
9033 + *(buf_cur++) = (ctx->bitlen[1] >> 0) & 0xff;
9034 +#endif /* HAVE_BIG_ENDIAN */
9036 + md5_over_block(ctx, ctx->buf);
9038 +#ifdef HAVE_LITTLE_ENDIAN
9039 + memcpy(digest + 0, (uint8_t *) (&(ctx->A)), sizeof(uint32_t));
9040 + memcpy(digest + 4, (uint8_t *) (&(ctx->B)), sizeof(uint32_t));
9041 + memcpy(digest + 8, (uint8_t *) (&(ctx->C)), sizeof(uint32_t));
9042 + memcpy(digest + 12, (uint8_t *) (&(ctx->D)), sizeof(uint32_t));
9043 +#endif /* HAVE_LITTLE_ENDIAN */
9045 +#ifdef HAVE_BIG_ENDIAN
9046 + digest[0] = ((ctx->A) >> 24) & 0xff;
9047 + digest[1] = ((ctx->A) >> 16) & 0xff;
9048 + digest[2] = ((ctx->A) >> 8) & 0xff;
9049 + digest[3] = ((ctx->A) >> 0) & 0xff;
9050 + digest[4] = ((ctx->B) >> 24) & 0xff;
9051 + digest[5] = ((ctx->B) >> 16) & 0xff;
9052 + digest[6] = ((ctx->B) >> 8) & 0xff;
9053 + digest[7] = ((ctx->B) >> 0) & 0xff;
9054 + digest[8] = ((ctx->C) >> 24) & 0xff;
9055 + digest[9] = ((ctx->C) >> 16) & 0xff;
9056 + digest[10] = ((ctx->C) >> 8) & 0xff;
9057 + digest[11] = ((ctx->C) >> 0) & 0xff;
9058 + digest[12] = ((ctx->D) >> 24) & 0xff;
9059 + digest[13] = ((ctx->D) >> 16) & 0xff;
9060 + digest[14] = ((ctx->D) >> 8) & 0xff;
9061 + digest[15] = ((ctx->D) >> 0) & 0xff;
9062 +#endif /* HAVE_BIG_ENDIAN */
9065 +void sha1_init(SHA1_CTX * ctx)
9067 + ctx->A = 0x67452301;
9068 + ctx->B = 0xefcdab89;
9069 + ctx->C = 0x98badcfe;
9070 + ctx->D = 0x10325476;
9071 + ctx->E = 0xc3d2e1f0;
9072 + ctx->buf_cur = ctx->buf;
9073 + ctx->bitlen[0] = ctx->bitlen[1] = 0;
9074 + memset(ctx->buf, 0, 64);
9077 +void sha1_over_block(SHA1_CTX * ctx, uint8_t * data)
9081 + uint32_t a = ctx->A;
9082 + uint32_t b = ctx->B;
9083 + uint32_t c = ctx->C;
9084 + uint32_t d = ctx->D;
9085 + uint32_t e = ctx->E;
9088 + create_W_blocks(W, data);
9091 + for (i = 0; i < 20; i++) {
9092 + temp = LROLL(a, 5) + f(b, c, d) + e + W[i] + K1;
9101 + for (i = 20; i < 40; i++) {
9102 + temp = LROLL(a, 5) + h(b, c, d) + e + W[i] + K2;
9111 + for (i = 40; i < 60; i++) {
9112 + temp = LROLL(a, 5) + g(b, c, d) + e + W[i] + K3;
9121 + for (i = 60; i < 80; i++) {
9122 + temp = LROLL(a, 5) + h(b, c, d) + e + W[i] + K4;
9137 +void create_W_blocks(uint32_t * W, uint8_t * data)
9141 +#ifdef HAVE_BIG_ENDIAN
9142 + memcpy((uint8_t *) W, data, 64);
9143 +#endif /* HAVE_BIG_ENDIAN */
9145 +#ifdef HAVE_LITTLE_ENDIAN
9146 + for (i = 0; i < 16; i++, data += 4) {
9147 + ((uint8_t *) (&W[i]))[0] = data[3];
9148 + ((uint8_t *) (&W[i]))[1] = data[2];
9149 + ((uint8_t *) (&W[i]))[2] = data[1];
9150 + ((uint8_t *) (&W[i]))[3] = data[0];
9152 +#endif /* HAVE_LITTLE_ENDIAN */
9153 + for (i = 16; i < 80; i++) {
9154 + W[i] = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16];
9155 + W[i] = LROLL(W[i], 1);
9159 +void sha1_compute(SHA1_CTX * ctx, uint8_t * data, uint32_t len)
9161 + uint8_t pos = ((ctx->bitlen[0] >> 3) & 0x3f);
9163 + /* First we update the bit length */
9164 + if ((ctx->bitlen[0] += (len << 3)) < (len << 3))
9166 + ctx->bitlen[1] += (len >> 29); /* len is expressed in bytes */
9169 + /* Buffer is not empty */
9170 + if (64 - pos >= len) {
9171 + memcpy(ctx->buf_cur, data, len);
9172 + ctx->buf_cur += len;
9175 + /* The current block is over */
9176 + sha1_over_block(ctx, ctx->buf);
9177 + ctx->buf_cur = ctx->buf;
9181 + memcpy(ctx->buf_cur, data, 64 - pos);
9182 + sha1_over_block(ctx, ctx->buf);
9183 + len -= (64 - pos);
9184 + data += (64 - pos);
9185 + ctx->buf_cur = ctx->buf;
9188 + while (len >= 64) {
9189 + sha1_over_block(ctx, data);
9194 + memcpy(ctx->buf_cur, data, len);
9195 + ctx->buf_cur += len;
9199 +void sha1_final(SHA1_CTX * ctx, uint8_t * digest)
9201 + uint32_t rem_size;
9202 + uint8_t *buf_cur = ctx->buf_cur;
9205 + rem_size = 64 - ((ctx->bitlen[0] >> 3) & 0x3f);
9206 + *(buf_cur++) = 0x80;
9208 + if (rem_size > 8 + 1) {
9209 + /* We have enough room in the current block */
9210 + for (i = 0; i < rem_size - 8 - 1; i++) {
9214 + /* We do not have enough room and need therefore to add a new
9216 + for (i = 0; i < rem_size - 1; i++) {
9219 + sha1_over_block(ctx, ctx->buf);
9221 + buf_cur = ctx->buf;
9222 + for (i = 0; i < 64 - 8; i++) {
9226 +#ifdef HAVE_BIG_ENDIAN
9227 + memcpy(buf_cur, (uint8_t *) ctx->bitlen, 8);
9228 +#endif /* HAVE_BIG_ENDIAN */
9230 +#ifdef HAVE_LITTLE_ENDIAN
9231 + *(buf_cur++) = (ctx->bitlen[1] >> 24) & 0xff;
9232 + *(buf_cur++) = (ctx->bitlen[1] >> 16) & 0xff;
9233 + *(buf_cur++) = (ctx->bitlen[1] >> 8) & 0xff;
9234 + *(buf_cur++) = (ctx->bitlen[1] >> 0) & 0xff;
9235 + *(buf_cur++) = (ctx->bitlen[0] >> 24) & 0xff;
9236 + *(buf_cur++) = (ctx->bitlen[0] >> 16) & 0xff;
9237 + *(buf_cur++) = (ctx->bitlen[0] >> 8) & 0xff;
9238 + *(buf_cur++) = (ctx->bitlen[0] >> 0) & 0xff;
9239 +#endif /* HAVE_LITTLE_ENDIAN */
9241 + sha1_over_block(ctx, ctx->buf);
9243 +#ifdef HAVE_BIG_ENDIAN
9244 + memcpy(digest + 0, (uint8_t *) (&(ctx->A)), sizeof(uint32_t));
9245 + memcpy(digest + 4, (uint8_t *) (&(ctx->B)), sizeof(uint32_t));
9246 + memcpy(digest + 8, (uint8_t *) (&(ctx->C)), sizeof(uint32_t));
9247 + memcpy(digest + 12, (uint8_t *) (&(ctx->D)), sizeof(uint32_t));
9248 + memcpy(digest + 16, (uint8_t *) (&(ctx->E)), sizeof(uint32_t));
9249 +#endif /* HAVE_BIG_ENDIAN */
9251 +#ifdef HAVE_LITTLE_ENDIAN
9252 + digest[0] = ((ctx->A) >> 24) & 0xff;
9253 + digest[1] = ((ctx->A) >> 16) & 0xff;
9254 + digest[2] = ((ctx->A) >> 8) & 0xff;
9255 + digest[3] = ((ctx->A) >> 0) & 0xff;
9256 + digest[4] = ((ctx->B) >> 24) & 0xff;
9257 + digest[5] = ((ctx->B) >> 16) & 0xff;
9258 + digest[6] = ((ctx->B) >> 8) & 0xff;
9259 + digest[7] = ((ctx->B) >> 0) & 0xff;
9260 + digest[8] = ((ctx->C) >> 24) & 0xff;
9261 + digest[9] = ((ctx->C) >> 16) & 0xff;
9262 + digest[10] = ((ctx->C) >> 8) & 0xff;
9263 + digest[11] = ((ctx->C) >> 0) & 0xff;
9264 + digest[12] = ((ctx->D) >> 24) & 0xff;
9265 + digest[13] = ((ctx->D) >> 16) & 0xff;
9266 + digest[14] = ((ctx->D) >> 8) & 0xff;
9267 + digest[15] = ((ctx->D) >> 0) & 0xff;
9268 + digest[16] = ((ctx->E) >> 24) & 0xff;
9269 + digest[17] = ((ctx->E) >> 16) & 0xff;
9270 + digest[18] = ((ctx->E) >> 8) & 0xff;
9271 + digest[19] = ((ctx->E) >> 0) & 0xff;
9272 +#endif /* HAVE_LITTLE_ENDIAN */
9275 +++ linux-2.4.27/net/ipv6/mobile_ip6/hmac.h
9278 + * MIPL Mobile IPv6 Message authentication algorithms
9282 + * This program is free software; you can redistribute it and/or
9283 + * modify it under the terms of the GNU General Public License
9284 + * as published by the Free Software Foundation; either version
9285 + * 2 of the License, or (at your option) any later version.
9291 +#include <linux/types.h>
9292 +#include <linux/in6.h>
9294 +#define HAVE_LITTLE_ENDIAN
9296 +#define NO_EXPIRY 1 /* For sec_as */
9298 +#define ALG_AUTH_NONE 0
9299 +#define ALG_AUTH_HMAC_MD5 1
9300 +#define ALG_AUTH_HMAC_SHA1 2
9303 +struct ah_processing {
9305 + struct sec_as *sas;
9306 + u_int8_t *key_auth;
9307 + u_int32_t key_auth_len;
9310 +struct antireplay {
9316 + u_int32_t A, B, C, D;
9317 + u_int32_t bitlen[2];
9318 + u_int8_t* buf_cur;
9323 + u_int32_t A, B, C, D, E;
9324 + u_int32_t bitlen[2];
9325 + u_int8_t* buf_cur;
9331 +int ah_hmac_md5_init (struct ah_processing *ahp, u_int8_t *key, u_int32_t key_len);
9332 +void ah_hmac_md5_loop(struct ah_processing*, void*, u_int32_t);
9333 +void ah_hmac_md5_result(struct ah_processing*, char*);
9334 +int ah_hmac_sha1_init(struct ah_processing*, u_int8_t *key, u_int32_t key_len);
9335 +void ah_hmac_sha1_loop(struct ah_processing*, void*, u_int32_t);
9336 +void ah_hmac_sha1_result(struct ah_processing*, char*);
9339 +#define AH_HDR_LEN 12 /* # of bytes for Next Header, Payload Length,
9340 + RESERVED, Security Parameters Index and
9342 + Sequence Number Field */
9344 +void md5_init(MD5_CTX *ctx);
9345 +void md5_over_block(MD5_CTX *ctx, u_int8_t* data);
9346 +void create_M_blocks(u_int32_t* M, u_int8_t* data);
9347 +void md5_compute(MD5_CTX *ctx, u_int8_t* data, u_int32_t len);
9348 +void md5_final(MD5_CTX *ctx, u_int8_t* digest);
9350 +void sha1_init(SHA1_CTX *ctx);
9351 +void sha1_over_block(SHA1_CTX *ctx, u_int8_t* data);
9352 +void create_W_blocks(u_int32_t* W, u_int8_t* data);
9353 +void sha1_compute(SHA1_CTX *ctx, u_int8_t* data, u_int32_t len);
9354 +void sha1_final(SHA1_CTX *ctx, u_int8_t* digest);
9357 + struct in6_addr coa;
9358 + struct in6_addr haddr;
9359 + struct in6_addr peer;
9362 +#define MIPV6_MAX_AUTH_DATA 20
9364 +#define HMAC_MD5_HASH_LEN 16
9365 +#define HMAC_SHA1_HASH_LEN 20
9366 +#define HMAC_SHA1_KEY_SIZE 20
9367 +#define HMAC_MD5_ICV_LEN 12 /* RFC 2403 */
9368 +#define HMAC_SHA1_ICV_LEN 12 /* RFC 2404 */
9370 +#endif /* _HMAC_H */
9372 +++ linux-2.4.27/net/ipv6/mobile_ip6/ioctl_mn.c
9375 + * Mobile Node IOCTL Control device
9378 + * Henrik Petander <lpetande@tml.hut.fi>
9382 + * This program is free software; you can redistribute it and/or
9383 + * modify it under the terms of the GNU General Public License
9384 + * as published by the Free Software Foundation; either version
9385 + * 2 of the License, or (at your option) any later version.
9388 +#include <linux/config.h>
9389 +#include <linux/module.h>
9390 +#include <linux/fs.h>
9391 +#include <linux/poll.h>
9392 +#include <linux/ioctl.h>
9393 +#include <net/ipv6.h>
9394 +#include <asm/uaccess.h>
9397 +#include "mdetect.h"
9398 +#include "multiaccess_ctl.h"
9400 +/* Reserved for local / experimental use */
9401 +#define MAJOR_NUM 0xf9
9403 +/* Get Care-of address information for Mobile Node */
9404 +#define IOCTL_GET_CAREOFADDR _IOWR(MAJOR_NUM, 9, void *)
9406 +#define MA_IOCTL_SET_IFACE_PREFERENCE _IOR (MAJOR_NUM, 13, void *)
9408 +/* The name of the device file */
9409 +#define CTLFILE "mipv6_dev"
9411 +static int inuse = 0;
9413 +static int mipv6_open(struct inode *inode, struct file *file)
9415 + DEBUG(DBG_INFO, "(%p)\n", file);
9422 + MOD_INC_USE_COUNT;
9427 +static int mipv6_close(struct inode *inode, struct file *file)
9429 + DEBUG(DBG_INFO, "(%p,%p)\n", inode, file);
9432 + MOD_DEC_USE_COUNT;
9437 +int mipv6_ioctl(struct inode *inode, struct file *file,
9438 + unsigned int ioctl_num, /* The number of the ioctl */
9439 + unsigned long arg) /* The parameter to it */
9441 + struct in6_addr careofaddr;
9443 + /* Switch according to the ioctl called */
9444 + switch (ioctl_num) {
9445 + case IOCTL_GET_CAREOFADDR:
9446 + DEBUG(DBG_DATADUMP, "IOCTL_GET_CAREOFADDR");
9447 + /* First get home address from user and then look up
9448 + * the care-of address and return it
9450 + if (copy_from_user(&careofaddr, (struct in6_addr *)arg,
9451 + sizeof(struct in6_addr)) < 0) {
9452 + DEBUG(DBG_WARNING, "Copy from user failed");
9455 + mipv6_get_care_of_address(&careofaddr, &careofaddr);
9456 + if (copy_to_user((struct in6_addr *)arg, &careofaddr,
9457 + sizeof(struct in6_addr)) < 0) {
9458 + DEBUG(DBG_WARNING, "copy_to_user failed");
9462 + case MA_IOCTL_SET_IFACE_PREFERENCE:
9463 + DEBUG(DBG_INFO, "MA_IOCTL_SET_IFACE_PREFERENCE");
9464 + ma_ctl_set_preference(arg);
9468 + DEBUG(DBG_WARNING, "Unknown ioctl cmd (%d)", ioctl_num);
9474 +struct file_operations Fops = {
9475 + owner: THIS_MODULE,
9479 + ioctl: mipv6_ioctl,
9481 + release: mipv6_close
9485 +/* Initialize the module - Register the character device */
9486 +int mipv6_ioctl_mn_init(void)
9490 + /* Register the character device (atleast try) */
9491 + ret_val = register_chrdev(MAJOR_NUM, CTLFILE, &Fops);
9493 + /* Negative values signify an error */
9494 + if (ret_val < 0) {
9495 + DEBUG(DBG_ERROR, "failed registering char device (err=%d)",
9500 + DEBUG(DBG_INFO, "Device number %x, success", MAJOR_NUM);
9505 +/* Cleanup - unregister the appropriate file from /proc */
9506 +void mipv6_ioctl_mn_exit(void)
9509 + /* Unregister the device */
9510 + ret = unregister_chrdev(MAJOR_NUM, CTLFILE);
9512 + /* If there's an error, report it */
9514 + DEBUG(DBG_ERROR, "errorcode: %d\n", ret);
9517 +++ linux-2.4.27/net/ipv6/mobile_ip6/mdetect.c
9520 + * Movement Detection Module
9523 + * Henrik Petander <lpetande@cc.hut.fi>
9527 + * This program is free software; you can redistribute it and/or
9528 + * modify it under the terms of the GNU General Public License
9529 + * as published by the Free Software Foundation; either version
9530 + * 2 of the License, or (at your option) any later version.
9532 + * Handles the L3 movement detection of mobile node and also
9533 + * changing of its routes.
9540 + * Nanno Langstraat : Locking fixes
9541 + * Venkata Jagana : Locking fix
9544 +#include <linux/autoconf.h>
9545 +#include <linux/errno.h>
9546 +#include <linux/init.h>
9547 +#include <linux/if_arp.h>
9548 +#include <linux/route.h>
9549 +#include <net/ipv6.h>
9550 +#include <net/ip6_route.h>
9551 +#include <net/addrconf.h>
9552 +#include <net/mipglue.h>
9553 +#ifdef CONFIG_SYSCTL
9554 +#include <linux/sysctl.h>
9555 +#endif /* CONFIG_SYSCTL */
9558 +#include "mdetect.h"
9561 +#include "multiaccess_ctl.h"
9566 +#define DEBUG_MDETECT 7
9568 +#define DEF_RTR_POLL_IVAL 5 /* In seconds */
9571 +#define RTR_SUSPECT 1
9572 +#define CURR_RTR_OK 2
9578 +#define MIPV6_MDF_NONE 0x0
9579 +#define MIPV6_MDF_HAS_RTR_PREV 0x1
9581 +#define ROUTER_REACHABLE 1
9582 +#define RADV_MISSED 2
9583 +#define NOT_REACHABLE 3
9585 +/* R_TIME_OUT paramater is used to make the decision when to change the
9586 + * default router, if the current one is unreachable. 2s is pretty aggressive
9587 + * and may result in hopping between two routers. OTOH a small value enhances
9590 +#define R_TIME_OUT 30*HZ
9592 +/* maximum RA interval for router unreachability detection */
9593 +#define MAX_RADV_INTERVAL 6*HZ /* 6000 ms... */
9595 +/* Threshold for exponential resending of router solicitations */
9596 +#define RS_RESEND_LINEAR 10*HZ
9598 +#define EAGER_CELL_SWITCHING 1
9599 +#define LAZY_CELL_SWITCHING 0
9600 +#define RESPECT_DAD 1
9602 +#define ROUTER_ADDRESS 0x20
9605 +#define ND_RA_FLAG_MANAGED 0x80
9606 +#define ND_RA_FLAG_OTHER 0x40
9607 +#define ND_RA_FLAG_HA 0x20
9609 +/* DAD flags for global and link local addresses */
9611 +#define COA_TENTATIVE 0x10
9612 +#define LLADDR_TENTATIVE 0x01
9615 + struct list_head list;
9616 + struct in6_addr ll_addr;
9617 + struct in6_addr raddr; /* Also contains prefix */
9618 + __u8 link_addr[MAX_ADDR_LEN]; /* link layer address */
9619 + __u8 link_addr_len;
9624 + int pfix_len; /* Length of the network prefix */
9625 + unsigned long lifetime; /* from ra */
9626 + __u32 last_ns_sent;
9627 + __u32 last_ra_rcvd;
9628 + __u32 interval; /* ra interval in milliseconds, 0 if not set */
9629 + int glob_addr; /*Whether raddr contains also routers global address*/
9630 + __u8 flags; /* RA flags, for example ha */
9631 + struct in6_addr CoA; /* care-off address used with this router */
9632 + int extra_addr_route;
9635 +/* dad could also be RESPECT_DAD for duplicate address detection of
9636 + new care-of addresses */
9637 +static int dad = 0;
9639 +/* Only one choice, nothing else implemented */
9640 +int max_rtr_reach_time = DEF_RTR_POLL_IVAL;
9643 +int eager_cell_switching = EAGER_CELL_SWITCHING; /* Can be set to 0 via proc */
9644 +static spinlock_t router_lock;
9645 +static spinlock_t ho_lock;
9647 +static void coa_timer_handler(unsigned long arg);
9648 +static void timer_handler(unsigned long foo);
9649 +static struct router *curr_router = NULL, *next_router = NULL;
9650 +static struct timer_list r_timer = { function: timer_handler };
9651 +static struct timer_list coa_timer = { function: coa_timer_handler };
9652 +#define MAX_ROUTERS 1000
9653 +static LIST_HEAD(rtr_list);
9654 +static int num_routers = 0;
9655 +static struct handoff *_ho = NULL;
9657 + * Functions for handling the default router list, which movement
9658 + * detection uses for avoiding loops etc.
9661 +/* TODO: Send NS to router after MAX interval has passed from last RA */
9662 +static int mipv6_router_state(struct router *rtr) {
9663 + if (rtr->interval) {
9664 + if (time_before(jiffies, (rtr->last_ra_rcvd + (rtr->interval * HZ) / 1000)))
9665 + return ROUTER_REACHABLE;
9667 + return NOT_REACHABLE;
9670 + if (time_after(jiffies, rtr->last_ra_rcvd + (rtr->lifetime * HZ)))
9671 + return NOT_REACHABLE;
9672 + return ROUTER_REACHABLE;
9675 +/* searches for a specific router or any router that is reachable,
9676 + * if address is NULL. Also deletes obsolete routers.
9678 +static void mipv6_router_gc(void)
9680 + struct router *curr = NULL;
9681 + struct list_head *lh, *lh_tmp;
9685 + list_for_each_safe(lh, lh_tmp, &rtr_list) {
9686 + curr = list_entry(lh, struct router, list);
9687 + if (mipv6_router_state(curr) == NOT_REACHABLE && !curr->is_current) {
9689 + list_del_init(&curr->list);
9690 + DEBUG(DBG_DATADUMP, "Deleting unreachable router %x:%x:%x:%x:%x:%x:%x:%x",
9691 + NIPV6ADDR(&curr->raddr));
9695 + DEBUG(DBG_DATADUMP, "NOT Deleting router %x:%x:%x:%x:%x:%x:%x:%x",
9696 + NIPV6ADDR(&curr->raddr));
9701 +static struct router *mipv6_rtr_get(struct in6_addr *search_addr)
9703 + struct router *rtr = NULL;
9704 + struct list_head *lh;
9708 + if (search_addr == NULL)
9710 + list_for_each(lh, &rtr_list) {
9711 + rtr = list_entry(lh, struct router, list);
9712 + if(!ipv6_addr_cmp(search_addr, &rtr->raddr)) {
9720 + * Adds router to list
9722 +static struct router *mipv6_rtr_add(struct router *nrt)
9725 + struct router *rptr;
9729 + /* check if someone is trying DoS attack, or we just have some
9730 + memory leaks... */
9731 + if (num_routers > MAX_ROUTERS) {
9732 + DEBUG(DBG_CRITICAL,
9733 + "failed to add new router, MAX_ROUTERS exceeded");
9737 + rptr = kmalloc(sizeof(struct router), GFP_ATOMIC);
9739 + memcpy(rptr, nrt, sizeof(struct router));
9740 + list_add(&rptr->list, &rtr_list);
9743 + DEBUG(DBG_INFO, "Adding router: %x:%x:%x:%x:%x:%x:%x:%x, "
9744 + "lifetime : %d sec, adv.interval: %d millisec",
9745 + NIPV6ADDR(&rptr->raddr), rptr->lifetime, rptr->interval);
9747 + DEBUG(DBG_INFO, "num_routers after addition: %d", num_routers);
9751 +/* Cleans up the list */
9752 +static void list_free(struct router **curr_router_p)
9754 + struct router *tmp;
9755 + struct list_head *lh, *lh_tmp;
9759 + DEBUG(DBG_INFO, "Freeing the router list");
9760 + /* set curr_router->prev_router and curr_router NULL */
9761 + *curr_router_p = NULL;
9762 + list_for_each_safe(lh, lh_tmp, &rtr_list) {
9763 + tmp = list_entry(lh, struct router, list);
9764 + DEBUG(DBG_INFO, "%x:%x:%x:%x:%x:%x:%x:%x",
9765 + NIPV6ADDR(&tmp->ll_addr));
9766 + list_del(&tmp->list);
9772 +int rs_state = START;
9774 +/* Sends router solicitations to all valid devices
9775 + * source = link local address (of sending interface)
9776 + * dstaddr = all routers multicast address
9777 + * Solicitations are sent at an exponentially decreasing rate
9779 + * TODO: send solicitation first at a normal rate (from ipv6) and
9780 + * after that use the exponentially increasing intervals
9782 +static int rs_send(void)
9784 + struct net_device *dev;
9785 + struct in6_addr raddr, lladdr;
9786 + struct inet6_dev *in6_dev = NULL;
9787 + static int num_rs;
9789 + if (rs_state == START) {
9791 + rs_state = CONTINUE;
9792 + } else if (num_rs++ > MAX_RTR_SOLICITATIONS)
9795 + ipv6_addr_all_routers(&raddr);
9796 + read_lock(&dev_base_lock);
9798 + /* Send router solicitations to all interfaces */
9799 + for (dev = dev_base; dev; dev = dev->next) {
9800 + if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ETHER) {
9801 + DEBUG(DBG_DATADUMP, "Sending RS to device %s",
9803 + if (!ipv6_get_lladdr(dev, &lladdr)) {
9804 + ndisc_send_rs(dev, &lladdr, &raddr);
9805 + in6_dev = in6_dev_get(dev);
9806 + in6_dev->if_flags |= IF_RS_SENT;
9807 + in6_dev_put(in6_dev);
9809 + DEBUG(DBG_DATADUMP, "%s: device doesn't have link-local address!\n", dev->name);
9815 + read_unlock(&dev_base_lock);
9816 + return RTR_SOLICITATION_INTERVAL;
9819 +/* Create a new CoA for MN and also add a route to it if it is still tentative
9820 + to allow MN to get packets to the address immediately
9822 +static int form_coa(struct in6_addr *coa, struct in6_addr *pfix,
9823 + int plen, int ifindex)
9825 + struct net_device *dev;
9826 + struct inet6_dev *in6_dev;
9829 + if ((dev = dev_get_by_index(ifindex)) == NULL) {
9830 + DEBUG(DBG_WARNING, "Device is not present");
9833 + if ((in6_dev = in6_dev_get(dev)) == NULL) {
9834 + DEBUG(DBG_WARNING, "inet6_dev is not present");
9838 + coa->s6_addr32[0] = pfix->s6_addr32[0];
9839 + coa->s6_addr32[1] = pfix->s6_addr32[1];
9841 + if (ipv6_generate_eui64(coa->s6_addr + 8, dev) &&
9842 + ipv6_inherit_eui64(coa->s6_addr + 8, in6_dev)) {
9843 + in6_dev_put(in6_dev);
9847 + if (ipv6_chk_addr(coa, dev) == 0) {
9848 + DEBUG(DBG_WARNING, "care-of address still tentative");
9851 + DEBUG(DBG_INFO, "Formed new CoA: %x:%x:%x:%x:%x:%x:%x:%x",
9854 + in6_dev_put(in6_dev);
9859 +static inline int rtr_is_gw(struct router *rtr, struct rt6_info *rt)
9861 + return ((rt->rt6i_flags & RTF_GATEWAY) &&
9862 + !ipv6_addr_cmp(&rt->rt6i_gateway, &rtr->ll_addr));
9865 +static inline int is_prefix_route(struct router *rtr, struct rt6_info *rt)
9867 + return (!(rt->rt6i_flags & RTF_GATEWAY) &&
9868 + mipv6_prefix_compare(&rt->rt6i_dst.addr, &rtr->raddr,
9873 + * Function that determines whether given rt6_info should be destroyed
9874 + * (negative => destroy rt6_info, zero or positive => do nothing)
9876 +static int mn_route_cleaner(struct rt6_info *rt, void *arg)
9880 + struct router *rtr = (struct router *)arg;
9886 + if (!rt || !rtr) {
9887 + DEBUG(DBG_ERROR, "mn_route_cleaner: rt or rtr NULL");
9891 + /* Do not delete routes to local addresses or to multicast
9892 + * addresses, since we need them to get router advertisements
9893 + * etc. Multicast addresses are more tricky, but we don't
9894 + * delete them in any case. The routing mechanism is not optimal for
9897 + * Also keep all new prefix routes, gateway routes through rtr and
9898 + * all remaining default routes (including those used for reverse
9901 + type = ipv6_addr_type(&rt->rt6i_dst.addr);
9903 + if ((type & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL)) ||
9904 + rt->rt6i_dev == &loopback_dev || rtr_is_gw(rtr, rt) ||
9905 + is_prefix_route(rtr, rt) || (rt->rt6i_flags & RTF_DEFAULT))
9908 + /* delete all others */
9910 + if (rt->rt6i_dev != &loopback_dev) {
9911 + DEBUG(DEBUG_MDETECT,
9914 + "gw: %x:%x:%x:%x:%x:%x:%x:%x,\n"
9917 + "src: %x:%x:%x:%x:%x:%x:%x:%x,\n"
9918 + "dst: %x:%x:%x:%x:%x:%x:%x:%x,\n"
9920 + (ret ? "Deleting" : "Keeping"),
9921 + rt->rt6i_dev->name,
9922 + NIPV6ADDR(&rt->rt6i_gateway),
9925 + NIPV6ADDR(&rt->rt6i_src.addr),
9926 + NIPV6ADDR(&rt->rt6i_dst.addr),
9927 + rt->rt6i_dst.plen);
9933 + * Deletes old routes
9935 +static __inline__ void delete_routes(struct router *rtr)
9939 + /* Routing table is locked to ensure that nobody uses its */
9940 + write_lock_bh(&rt6_lock);
9941 + DEBUG(DBG_INFO, "mipv6: Purging routes");
9942 + /* TODO: Does not prune, should it? */
9943 + fib6_clean_tree(&ip6_routing_table,
9944 + mn_route_cleaner, 0, rtr);
9945 + write_unlock_bh(&rt6_lock);
9950 +static __inline__ void delete_coas(struct router *rtr)
9952 + struct net_device *dev;
9953 + struct inet6_dev *idev;
9954 + struct inet6_ifaddr *ifa;
9956 + dev = dev_get_by_index(rtr->ifindex);
9960 + idev = in6_dev_get(dev);
9963 + read_lock_bh(&idev->lock);
9964 + ifa = idev->addr_list;
9967 + spin_lock(&ifa->lock);
9969 + keep = (ifa->flags&(IFA_F_PERMANENT|IFA_F_HOMEADDR) ||
9970 + !ipv6_addr_cmp(&ifa->addr, &rtr->CoA));
9972 + spin_unlock(&ifa->lock);
9975 + ifa = ifa->if_next;
9977 + in6_ifa_hold(ifa);
9978 + read_unlock_bh(&idev->lock);
9980 + ipv6_del_addr(ifa);
9982 + read_lock_bh(&idev->lock);
9983 + ifa = idev->addr_list;
9986 + read_unlock_bh(&idev->lock);
9987 + in6_dev_put(idev);
9992 +int next_mdet_state[3][3] = {{CURR_RTR_OK, NO_RTR, NO_RTR},
9993 + {CURR_RTR_OK, CURR_RTR_OK, NO_RTR},
9994 + {CURR_RTR_OK, CURR_RTR_OK, RTR_SUSPECT}};
9996 +char *states[3] = {"NO_RTR", "RTR_SUSPECT", "CURR_RTR_OK"};
9997 +char *events[3] = {"RA_RCVD", "NA_RCVD", "TIMEOUT"};
9999 +/* State transitions
10000 + * NO_RTR, RA_RCVD -> CURR_RTR_OK
10001 + * NO_RTR, NA_RCVD -> NO_RTR
10002 + * NO_RTR, TIMEOUT -> NO_RTR
10004 + * RTR_SUSPECT, RA_RCVD -> CURR_RTR_OK
10005 + * RTR_SUSPECT, NA_RCVD -> CURR_RTR_OK
10006 + * RTR_SUSPECT, TIMEOUT -> NO_RTR
10008 + * CURR_RTR_OK, RA_RCVD -> CURR_RTR_OK
10009 + * CURR_RTR_OK, NA_RCVD -> CURR_RTR_OK
10010 + * CURR_RTR_OK, TIMEOUT -> RTR_SUSPECT
10012 +static int _curr_state = NO_RTR;
10015 +static int get_mdet_state(void){
10017 + spin_lock_bh(&router_lock);
10018 + state = _curr_state;
10019 + spin_unlock_bh(&router_lock);
10024 +/* Needs to be called with router_lock locked */
10025 +static int mdet_statemachine(int event)
10028 + if (event > 2 || _curr_state > 2) {
10029 + DEBUG(DBG_ERROR, "Got illegal event or curr_state");
10033 + DEBUG(DBG_DATADUMP, "Got event %s and curr_state is %s",
10034 + events[event], states[_curr_state]);
10036 + _curr_state = next_mdet_state[_curr_state][event];
10037 + DEBUG(DBG_DATADUMP, "Next state is %s", states[_curr_state]);
10038 + return _curr_state;
10041 +static void mipv6_do_ll_dad(int ifindex)
10043 + struct net_device *dev = dev_get_by_index(ifindex);
10045 + struct in6_addr lladdr;
10046 + struct inet6_ifaddr *ifa;
10047 + if (!ipv6_get_lladdr(dev, &lladdr) &&
10048 + (ifa = ipv6_get_ifaddr(&lladdr, dev)) != NULL) {
10049 + spin_lock_bh(&ifa->lock);
10050 + if (!(ifa->flags & IFA_F_TENTATIVE)) {
10051 + ifa->flags |= IFA_F_TENTATIVE;
10052 + spin_unlock_bh(&ifa->lock);
10053 + addrconf_dad_start(ifa, 0);
10055 + spin_unlock_bh(&ifa->lock);
10062 + * Changes the router, called from ndisc.c if mipv6_router_event
10066 +static void mipv6_change_router(void)
10068 + struct in6_addr coa;
10069 + int ret, ifindex;
10074 + if (next_router == NULL)
10077 + spin_lock(&router_lock);
10080 + if (curr_router != NULL &&
10081 + !ipv6_addr_cmp(&curr_router->ll_addr, &next_router->ll_addr)) {
10082 + DEBUG(DBG_INFO,"Trying to handoff from: "
10083 + "%x:%x:%x:%x:%x:%x:%x:%x",
10084 + NIPV6ADDR(&curr_router->ll_addr));
10085 + DEBUG(DBG_INFO,"Trying to handoff to: "
10086 + "%x:%x:%x:%x:%x:%x:%x:%x",
10087 + NIPV6ADDR(&next_router->ll_addr));
10088 + next_router = NULL; /* Let's not leave dangling pointers */
10089 + spin_unlock(&router_lock);
10092 + ret = form_coa(&next_router->CoA, &next_router->raddr,
10093 + next_router->pfix_len, next_router->ifindex);
10095 + DEBUG(DBG_ERROR, "handoff: Creation of coa failed");
10096 + spin_unlock(&router_lock);
10098 + } else if (ret > 0)
10099 + next_router->flags |= COA_TENTATIVE;
10101 + mdet_statemachine(RA_RCVD); /* TODO: What if DAD fails... */
10102 + if (next_router->interval)
10103 + mod_timer(&r_timer, jiffies +
10104 + (next_router->interval * HZ)/1000);
10106 + mod_timer(&r_timer, jiffies + max_rtr_reach_time * HZ);
10110 + ipv6_addr_copy(&coa, &next_router->CoA);
10111 + ifindex = next_router->ifindex;
10112 + spin_unlock(&router_lock);
10113 + mipv6_mdet_finalize_ho(&coa, ifindex);
10116 + spin_unlock(&router_lock);
10119 +static unsigned long ns_send(void)
10121 + struct neighbour *neigh;
10122 + struct net_device *dev;
10123 + struct in6_addr *raddr;
10125 + DEBUG(DBG_DATADUMP, "Sending Neighbour solicitation to default router to verify its reachability");
10126 + if (!curr_router)
10128 + if ((dev = dev_get_by_index(curr_router->ifindex)) == NULL)
10130 + if ((neigh = ndisc_get_neigh(dev, &curr_router->ll_addr)) == NULL) {
10134 + if (curr_router->glob_addr)
10135 + raddr = &curr_router->raddr;
10137 + raddr = &curr_router->ll_addr;
10139 + curr_router->last_ns_sent = jiffies;
10140 + ndisc_send_ns(dev, neigh, raddr, raddr, NULL);
10142 + neigh_release(neigh);
10144 + return HZ/5; /* Wait 200ms for a reply */
10147 +static int na_rcvd(void)
10149 + int neigh_ok = 0;
10150 + struct neighbour *neigh;
10151 + struct net_device *dev;
10153 + if (!curr_router)
10155 + if ((dev = dev_get_by_index(curr_router->ifindex)) == NULL)
10157 + if ((neigh = ndisc_get_neigh(dev, &curr_router->ll_addr)) == NULL) {
10161 + if (neigh->flags & NTF_ROUTER &&
10162 + (time_after(neigh->confirmed, curr_router->last_ns_sent) ||
10163 + neigh->confirmed == curr_router->last_ns_sent)) {
10165 + DEBUG(DBG_DATADUMP, "Mdetect event: NA rcvd from curr rtr");
10167 + DEBUG(DBG_DATADUMP, "Mdetect event: NA NOT rcvd from curr rtr within time limit");
10168 + neigh_release(neigh);
10173 +static void coa_timer_handler(unsigned long dummy)
10176 + spin_lock_bh(&ho_lock);
10178 + DEBUG(DBG_INFO, "Starting handoff after DAD");
10179 + mipv6_mobile_node_moved(_ho);
10183 + spin_unlock_bh(&ho_lock);
10185 +static void timer_handler(unsigned long foo)
10187 + unsigned long timeout;
10189 + spin_lock_bh(&router_lock);
10191 + if (_curr_state != NO_RTR)
10192 + rs_state = START;
10194 + if (_curr_state == RTR_SUSPECT && na_rcvd()) {
10195 + state = mdet_statemachine(NA_RCVD);
10196 + timeout = curr_router->interval ? curr_router->interval : max_rtr_reach_time * HZ;
10198 + state = mdet_statemachine(TIMEOUT);
10199 + if (state == NO_RTR)
10200 + timeout = rs_send();
10201 + else /* RTR_SUSPECT */
10202 + timeout = ns_send();
10207 + mipv6_router_gc();
10208 + mod_timer(&r_timer, jiffies + timeout);
10209 + spin_unlock_bh(&router_lock);
10213 + * mipv6_get_care_of_address - get node's care-of primary address
10214 + * @homeaddr: one of node's home addresses
10215 + * @coaddr: buffer to store care-of address
10217 + * Stores the current care-of address in the @coaddr, assumes
10218 + * addresses in EUI-64 format. Since node might have several home
10219 + * addresses caller MUST supply @homeaddr. If node is at home
10220 + * @homeaddr is stored in @coaddr. Returns 0 on success, otherwise a
10221 + * negative value.
10223 +int mipv6_get_care_of_address(
10224 + struct in6_addr *homeaddr, struct in6_addr *coaddr)
10229 + if (homeaddr == NULL)
10231 + spin_lock_bh(&router_lock);
10232 + if (curr_router == NULL || mipv6_mn_is_at_home(homeaddr) ||
10233 + mipv6_prefix_compare(homeaddr, &curr_router->raddr, 64) ||
10234 + curr_router->flags&COA_TENTATIVE) {
10236 + "mipv6_get_care_of_address: returning home address");
10237 + ipv6_addr_copy(coaddr, homeaddr);
10238 + spin_unlock_bh(&router_lock);
10243 + /* At home or address check failure probably due to dad wait */
10244 + if (mipv6_prefix_compare(&curr_router->raddr, homeaddr,
10245 + curr_router->pfix_len)
10246 + || (dad == RESPECT_DAD &&
10247 + (ipv6_chk_addr(coaddr, NULL) == 0))) {
10248 + ipv6_addr_copy(coaddr, homeaddr);
10250 + ipv6_addr_copy(coaddr, &curr_router->CoA);
10253 + spin_unlock_bh(&router_lock);
10257 +int mipv6_mdet_del_if(int ifindex)
10259 + struct router *curr = NULL;
10260 + struct list_head *lh, *lh_tmp;
10262 + spin_lock_bh(&router_lock);
10263 + list_for_each_safe(lh, lh_tmp, &rtr_list) {
10264 + curr = list_entry(lh, struct router, list);
10265 + if (curr->ifindex == ifindex) {
10267 + list_del_init(&curr->list);
10268 + DEBUG(DBG_DATADUMP, "Deleting router %x:%x:%x:%x:%x:%x:%x:%x on interface %d",
10269 + NIPV6ADDR(&curr->raddr), ifindex);
10270 + if (curr_router == curr)
10271 + curr_router = NULL;
10275 + spin_unlock_bh(&router_lock);
10279 +void mipv6_mdet_retrigger_ho(void)
10281 + struct handoff ho;
10283 + spin_lock_bh(&router_lock);
10284 + if (curr_router != NULL) {
10285 + ho.coa = &curr_router->CoA;
10286 + ho.plen = curr_router->pfix_len;
10287 + ho.ifindex = curr_router->ifindex;
10288 + ipv6_addr_copy(&ho.rtr_addr, &curr_router->raddr);
10289 + ho.home_address = (curr_router->glob_addr &&
10290 + curr_router->flags&ND_RA_FLAG_HA);
10292 + spin_unlock_bh(&router_lock);
10293 + mipv6_mobile_node_moved(&ho);
10296 +void mipv6_mdet_set_curr_rtr_reachable(int reachable)
10298 + spin_lock_bh(&router_lock);
10299 + if (curr_router != NULL) {
10300 + curr_router->reachable = reachable;
10302 + spin_unlock_bh(&router_lock);
10306 +int mipv6_mdet_finalize_ho(const struct in6_addr *coa, const int ifindex)
10309 + struct handoff ho;
10310 + struct router *tmp;
10311 + struct net_device *dev;
10312 + struct in6_addr ll_addr;
10314 + spin_lock_bh(&router_lock);
10316 + if (!next_router) {
10317 + spin_unlock_bh(&router_lock);
10321 + dev = dev_get_by_index(next_router->ifindex);
10323 + if (ipv6_get_lladdr(dev, &ll_addr) == 0) {
10324 + if (ipv6_addr_cmp(&ll_addr, coa) == 0)
10325 + DEBUG(DBG_INFO, "DAD for link local address completed");
10326 + next_router->flags &= ~LLADDR_TENTATIVE;
10331 + if (mipv6_prefix_compare(coa, &next_router->CoA,
10332 + next_router->pfix_len)) {
10333 + DEBUG(DBG_INFO, "DAD for Care-of address completed");
10334 + next_router->flags &= ~COA_TENTATIVE;
10336 + if (!(next_router->flags&LLADDR_TENTATIVE) && !(next_router->flags&COA_TENTATIVE)) {
10337 + DEBUG(DBG_INFO, "%s: Proceeding with handoff after DAD\n", __FUNCTION__);
10338 + tmp = curr_router;
10339 + curr_router = next_router;
10340 + curr_router->is_current = 1;
10341 + next_router = NULL;
10342 + curr_router->flags &= ~COA_TENTATIVE;
10343 + delete_routes(curr_router);
10344 + delete_coas(curr_router);
10346 + struct net_device *dev_old = dev_get_by_index(tmp->ifindex);
10347 + struct rt6_info *rt = NULL;
10349 + rt = rt6_get_dflt_router(&tmp->ll_addr, dev_old);
10350 + dev_put(dev_old);
10353 + ip6_del_rt(rt, NULL);
10354 + tmp->is_current = 0;
10357 + ma_ctl_upd_iface(curr_router->ifindex, MA_IFACE_CURRENT, &dummy);
10358 + ma_ctl_upd_iface(curr_router->ifindex, MA_IFACE_CURRENT, &dummy);
10361 + ho.coa = &curr_router->CoA;
10362 + ho.plen = curr_router->pfix_len;
10363 + ho.ifindex = curr_router->ifindex;
10364 + ipv6_addr_copy(&ho.rtr_addr, &curr_router->raddr);
10365 + ho.home_address = (curr_router->glob_addr &&
10366 + curr_router->flags&ND_RA_FLAG_HA);
10368 + spin_unlock_bh(&router_lock);
10369 + mipv6_mobile_node_moved(&ho);
10371 + spin_unlock_bh(&router_lock);
10374 +/* Decides whether router candidate is the same router as current rtr
10375 + * based on prefix / global addresses of the routers and their link local
10378 +static int is_current_rtr(struct router *nrt, struct router *crt)
10382 + DEBUG(DEBUG_MDETECT, "Current router: "
10383 + "%x:%x:%x:%x:%x:%x:%x:%x and", NIPV6ADDR(&crt->raddr));
10384 + DEBUG(DEBUG_MDETECT, "Candidate router: "
10385 + "%x:%x:%x:%x:%x:%x:%x:%x", NIPV6ADDR(&nrt->raddr));
10387 + return (!ipv6_addr_cmp(&nrt->raddr,&crt->raddr) &&
10388 + !ipv6_addr_cmp(&nrt->ll_addr, &crt->ll_addr));
10392 + * Change next router to nrtr
10393 + * Returns 1, if router has been changed.
10396 +static int change_next_rtr(struct router *nrtr, struct router *ortr)
10401 + if (!next_router || ipv6_addr_cmp(&nrtr->raddr, &next_router->raddr)) {
10404 + next_router = nrtr;
10407 +static int clean_ncache(struct router *nrt, struct router *ort, int same_if)
10409 + struct net_device *ortdev;
10412 + /* Always call ifdown after a handoff to ensure proper routing */
10416 + if ((ortdev = dev_get_by_index(ort->ifindex)) == NULL) {
10417 + DEBUG(DBG_WARNING, "Device is not present");
10420 + neigh_ifdown(&nd_tbl, ortdev);
10425 +static int mdet_get_if_preference(int ifi)
10431 + pref = ma_ctl_get_preference(ifi);
10433 + DEBUG(DEBUG_MDETECT, "ifi: %d preference %d", ifi, pref);
10439 + * Called from mipv6_mn_ra_rcv to determine whether to do a handoff.
10441 +static int mipv6_router_event(struct router *rptr)
10443 + struct router *nrt = NULL;
10444 + int new_router = 0, same_if = 1;
10445 + int oldstate = _curr_state;
10446 + int addrtype = ipv6_addr_type(&rptr->raddr);
10450 + if (rptr->lifetime == 0)
10451 + return MIPV6_IGN_RTR;
10452 + DEBUG(DEBUG_MDETECT, "Received a RA from router: "
10453 + "%x:%x:%x:%x:%x:%x:%x:%x", NIPV6ADDR(&rptr->raddr));
10454 + spin_lock(&router_lock);
10456 + /* Add or update router entry */
10457 + if ((nrt = mipv6_rtr_get(&rptr->raddr)) == NULL) {
10458 + if (addrtype == IPV6_ADDR_ANY || (nrt = mipv6_rtr_add(rptr)) == NULL) {
10459 + spin_unlock(&router_lock);
10460 + return MIPV6_IGN_RTR;
10462 + DEBUG(DBG_INFO, "Router not on list,adding it to the list");
10465 + nrt->last_ra_rcvd = jiffies;
10466 + nrt->state = ROUTER_REACHABLE;
10467 + nrt->interval = rptr->interval;
10468 + nrt->lifetime = rptr->lifetime;
10469 + nrt->ifindex = rptr->ifindex;
10470 + nrt->flags = rptr->flags;
10471 + nrt->glob_addr = rptr->glob_addr;
10473 + /* Whether from current router */
10474 + if (curr_router && curr_router->reachable &&
10475 + is_current_rtr(nrt, curr_router)) {
10476 + if (nrt->interval)
10477 + mod_timer(&r_timer, jiffies + (nrt->interval * HZ)/1000);
10479 + mod_timer(&r_timer, jiffies + max_rtr_reach_time * HZ);
10480 + mdet_statemachine(RA_RCVD);
10481 + spin_unlock(&router_lock);
10482 + return MIPV6_ADD_RTR;
10483 + } else if (oldstate == NO_RTR) {
10484 + rt6_purge_dflt_routers(0); /* For multiple interface case */
10485 + DEBUG(DBG_INFO, "No router or router not reachable, switching to new one");
10488 + if (!curr_router) {
10492 + /* Router behind same interface as current one ?*/
10493 + same_if = (nrt->ifindex == curr_router->ifindex);
10494 + /* Switch to new router behind same interface if eager cell
10495 + * switching is used or if the interface is preferred
10497 + if ((new_router && eager_cell_switching && same_if) ||
10498 + (mdet_get_if_preference(nrt->ifindex) >
10499 + mdet_get_if_preference(curr_router->ifindex))) {
10500 + DEBUG(DBG_INFO, "Switching to new router.");
10504 + /* No handoff, don't add default route */
10505 + DEBUG(DEBUG_MDETECT, "Ignoring RA");
10506 + spin_unlock(&router_lock);
10507 + return MIPV6_IGN_RTR;
10509 + clean_ncache(nrt, curr_router, same_if);
10510 + nrt->reachable = 1;
10511 + if (same_if && change_next_rtr(nrt, curr_router)) {
10512 + mipv6_do_ll_dad(nrt->ifindex);
10513 + nrt->flags |= LLADDR_TENTATIVE;
10515 + spin_unlock(&router_lock);
10517 + return MIPV6_CHG_RTR;
10521 + * Called from ndisc.c's router_discovery.
10524 +static inline int ret_to_ha(struct in6_addr *addr)
10527 + struct mn_info *minfo;
10528 + read_lock(&mn_info_lock);
10529 + minfo = mipv6_mninfo_get_by_ha(addr);
10530 + if (minfo != NULL) {
10531 + spin_lock(&minfo->lock);
10532 + if (minfo->has_home_reg) {
10535 + spin_unlock(&minfo->lock);
10537 + read_unlock(&mn_info_lock);
10541 +static int mipv6_mn_ra_rcv(struct sk_buff *skb, struct ndisc_options *ndopts)
10543 + int ifi = ((struct inet6_skb_parm *)skb->cb)->iif;
10544 + struct ra_msg *ra = (struct ra_msg *) skb->h.raw;
10545 + struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
10546 + struct router nrt;
10547 + struct in6_addr *ha = NULL;
10548 + u8 *lladdr = NULL;
10552 + memset(&nrt, 0, sizeof(struct router));
10554 + if (ra->icmph.icmp6_home_agent) {
10555 + nrt.flags |= ND_RA_FLAG_HA;
10556 + DEBUG(DBG_DATADUMP, "RA has ND_RA_FLAG_HA up");
10559 + if (ra->icmph.icmp6_addrconf_managed) {
10560 + nrt.flags |= ND_RA_FLAG_MANAGED;
10561 + DEBUG(DBG_DATADUMP, "RA has ND_RA_FLAG_MANAGED up");
10564 + if (ra->icmph.icmp6_addrconf_other) {
10565 + nrt.flags |= ND_RA_FLAG_OTHER;
10566 + DEBUG(DBG_DATADUMP, "RA has ND_RA_FLAG_OTHER up");
10569 + ipv6_addr_copy(&nrt.ll_addr, saddr);
10570 + nrt.ifindex = ifi;
10571 + nrt.lifetime = ntohs(ra->icmph.icmp6_rt_lifetime);
10573 + if (ndopts->nd_opts_src_lladdr) {
10574 + lladdr = (u8 *) ndopts->nd_opts_src_lladdr+2;
10575 + nrt.link_addr_len = skb->dev->addr_len;
10576 + memcpy(nrt.link_addr, lladdr, nrt.link_addr_len);
10578 + if (ndopts->nd_opts_pi) {
10579 + struct nd_opt_hdr *p;
10580 + for (p = ndopts->nd_opts_pi;
10582 + p = ndisc_next_option(p, ndopts->nd_opts_pi_end)) {
10583 + struct prefix_info *pinfo;
10586 + pinfo = (struct prefix_info *) p;
10588 + if (!pinfo->autoconf)
10591 + if ((pinfo->router_address &&
10592 + (update = ret_to_ha(&pinfo->prefix))) ||
10593 + ipv6_addr_type(&nrt.raddr) != IPV6_ADDR_UNICAST) {
10594 + ipv6_addr_copy(&nrt.raddr, &pinfo->prefix);
10595 + nrt.pfix_len = pinfo->prefix_len;
10596 + if (pinfo->router_address)
10597 + nrt.glob_addr = 1;
10599 + nrt.glob_addr = 0;
10601 + ha = &pinfo->prefix;
10602 + DEBUG(DBG_DATADUMP, "Address of the received "
10603 + "prefix info option: %x:%x:%x:%x:%x:%x:%x:%x",
10604 + NIPV6ADDR(&nrt.raddr));
10605 + DEBUG(DBG_DATADUMP, "the length of the prefix is %d",
10610 + if (ndopts->nd_opts_rai) {
10611 + nrt.interval = ntohl(*(__u32 *)(ndopts->nd_opts_rai+4));
10612 + DEBUG(DBG_DATADUMP,
10613 + "received router interval option with interval : %d ",
10614 + nrt.interval / HZ);
10616 + if (nrt.interval > MAX_RADV_INTERVAL) {
10617 + nrt.interval = 0;
10618 + DEBUG(DBG_DATADUMP, "but we are using: %d, "
10619 + "because interval>MAX_RADV_INTERVAL",
10620 + nrt.interval / HZ);
10624 + res = mipv6_router_event(&nrt);
10626 + if (ha && lladdr) {
10627 + mipv6_mn_ha_nd_update(__dev_get_by_index(ifi), ha, lladdr);
10632 +int __init mipv6_initialize_mdetect(void)
10637 + spin_lock_init(&router_lock);
10638 + spin_lock_init(&ho_lock);
10639 + init_timer(&coa_timer);
10640 + init_timer(&r_timer);
10641 + r_timer.expires = jiffies + HZ;
10642 + add_timer(&r_timer);
10644 + /* Actual HO, also deletes old routes after the addition of new ones
10646 + MIPV6_SETCALL(mipv6_change_router, mipv6_change_router);
10648 + MIPV6_SETCALL(mipv6_ra_rcv, mipv6_mn_ra_rcv);
10653 +int __exit mipv6_shutdown_mdetect()
10658 + MIPV6_RESETCALL(mipv6_ra_rcv);
10659 + MIPV6_RESETCALL(mipv6_change_router);
10660 + spin_lock_bh(&router_lock);
10661 + spin_lock(&ho_lock);
10662 + del_timer(&coa_timer);
10663 + del_timer(&r_timer);
10664 + /* Free the memory allocated by router list */
10665 + list_free(&curr_router);
10668 + spin_unlock(&ho_lock);
10669 + spin_unlock_bh(&router_lock);
10673 +++ linux-2.4.27/net/ipv6/mobile_ip6/mdetect.h
10676 + * MIPL Mobile IPv6 Movement detection module header file
10680 + * This program is free software; you can redistribute it and/or
10681 + * modify it under the terms of the GNU General Public License
10682 + * as published by the Free Software Foundation; either version
10683 + * 2 of the License, or (at your option) any later version.
10686 +#ifndef _MDETECT_H
10687 +#define _MDETECT_H
10690 + int home_address; /* Is the coa a home address */
10693 + struct in6_addr *coa;
10694 + struct in6_addr rtr_addr; /* Prefix or rtr address if coa is home address */
10697 +int mipv6_initialize_mdetect(void);
10699 +int mipv6_shutdown_mdetect(void);
10701 +int mipv6_get_care_of_address(struct in6_addr *homeaddr, struct in6_addr *coa);
10703 +int mipv6_mdet_del_if(int ifindex);
10705 +int mipv6_mdet_finalize_ho(const struct in6_addr *coa, const int ifindex);
10707 +void mipv6_mdet_retrigger_ho(void);
10709 +void mipv6_mdet_set_curr_rtr_reachable(int reachable);
10711 +#endif /* _MDETECT_H */
10713 +++ linux-2.4.27/net/ipv6/mobile_ip6/mipv6_icmp.c
10716 + * Generic icmp routines
10719 + * Jaakko Laine <medved@iki.fi>,
10720 + * Ville Nuorvala <vnuorval@tcs.hut.fi>
10724 + * This program is free software; you can redistribute it and/or
10725 + * modify it under the terms of the GNU General Public License
10726 + * as published by the Free Software Foundation; either version
10727 + * 2 of the License, or (at your option) any later version.
10730 +#include <linux/config.h>
10731 +#include <linux/icmpv6.h>
10732 +#include <net/checksum.h>
10733 +#include <net/ipv6.h>
10734 +#include <net/ip6_route.h>
10735 +#include <net/mipv6.h>
10736 +#include <net/mipglue.h>
10738 +#include "debug.h"
10739 +#include "bcache.h"
10740 +#include "mipv6_icmp.h"
10741 +#include "config.h"
10743 +struct mipv6_icmpv6_msg {
10744 + struct icmp6hdr icmph;
10746 + struct in6_addr *daddr;
10751 +#define MIPV6_ICMP_HOP_LIMIT 64
10753 +static struct socket *mipv6_icmpv6_socket = NULL;
10754 +static __u16 identifier = 0;
10756 +int mipv6_icmpv6_no_rcv(struct sk_buff *skb)
10761 +static int mipv6_icmpv6_xmit_holder = -1;
10763 +static int mipv6_icmpv6_xmit_lock_bh(void)
10765 + if (!spin_trylock(&mipv6_icmpv6_socket->sk->lock.slock)) {
10766 + if (mipv6_icmpv6_xmit_holder == smp_processor_id())
10768 + spin_lock(&mipv6_icmpv6_socket->sk->lock.slock);
10770 + mipv6_icmpv6_xmit_holder = smp_processor_id();
10774 +static __inline__ int mipv6_icmpv6_xmit_lock(void)
10777 + local_bh_disable();
10778 + ret = mipv6_icmpv6_xmit_lock_bh();
10780 + local_bh_enable();
10784 +static void mipv6_icmpv6_xmit_unlock_bh(void)
10786 + mipv6_icmpv6_xmit_holder = -1;
10787 + spin_unlock(&mipv6_icmpv6_socket->sk->lock.slock);
10790 +static __inline__ void mipv6_icmpv6_xmit_unlock(void)
10792 + mipv6_icmpv6_xmit_unlock_bh();
10793 + local_bh_enable();
10798 + * mipv6_icmpv6_dest_unreach - Destination Unreachable ICMP error message handler
10799 + * @skb: buffer containing ICMP error message
10801 + * Special Mobile IPv6 ICMP handling. If Correspondent Node receives
10802 + * persistent ICMP Destination Unreachable messages for a destination
10803 + * in its Binding Cache, the binding should be deleted. See draft
10806 +static int mipv6_icmpv6_rcv_dest_unreach(struct sk_buff *skb)
10808 + struct icmp6hdr *icmph = (struct icmp6hdr *) skb->h.raw;
10809 + struct ipv6hdr *ipv6h = (struct ipv6hdr *) (icmph + 1);
10810 + int left = (skb->tail - skb->h.raw) - sizeof(*icmph)- sizeof(ipv6h);
10811 + struct ipv6_opt_hdr *eh;
10812 + struct rt2_hdr *rt2h = NULL;
10813 + struct in6_addr *daddr = &ipv6h->daddr;
10814 + struct in6_addr *saddr = &ipv6h->saddr;
10815 + int hdrlen, nexthdr = ipv6h->nexthdr;
10816 + struct mipv6_bce bce;
10819 + eh = (struct ipv6_opt_hdr *) (ipv6h + 1);
10821 + while (left > 0) {
10822 + if (nexthdr != NEXTHDR_HOP && nexthdr != NEXTHDR_DEST &&
10823 + nexthdr != NEXTHDR_ROUTING)
10826 + hdrlen = ipv6_optlen(eh);
10827 + if (hdrlen > left)
10830 + if (nexthdr == NEXTHDR_ROUTING) {
10831 + struct ipv6_rt_hdr *rth = (struct ipv6_rt_hdr *) eh;
10833 + if (rth->type == IPV6_SRCRT_TYPE_2) {
10834 + if (hdrlen != sizeof(struct rt2_hdr))
10837 + rt2h = (struct rt2_hdr *) rth;
10839 + if (rt2h->rt_hdr.segments_left > 0)
10840 + daddr = &rt2h->addr;
10844 + /* check for home address option in case this node is a MN */
10845 + if (nexthdr == NEXTHDR_DEST) {
10846 + __u8 *raw = (__u8 *) eh;
10849 + struct mipv6_dstopt_homeaddr *hao;
10851 + if (i + sizeof (*hao) > hdrlen)
10854 + hao = (struct mipv6_dstopt_homeaddr *) &raw[i];
10856 + if (hao->type == MIPV6_TLV_HOMEADDR &&
10857 + hao->length == sizeof(struct in6_addr)) {
10858 + saddr = &hao->addr;
10862 + i += hao->length + 2;
10868 + nexthdr = eh->nexthdr;
10869 + eh = (struct ipv6_opt_hdr *) ((u8 *) eh + hdrlen);
10872 + if (rt2h == NULL) return 0;
10874 + if (mipv6_bcache_get(daddr, saddr, &bce) == 0 && !(bce.flags&HOME_REGISTRATION)) {
10875 + /* A primitive algorithm for detecting persistent ICMP destination unreachable messages */
10876 + if (bce.destunr_count &&
10877 + time_after(jiffies,
10878 + bce.last_destunr + MIPV6_DEST_UNR_IVAL*HZ))
10879 + bce.destunr_count = 0;
10881 + bce.destunr_count++;
10883 + mipv6_bcache_icmp_err(daddr, saddr, bce.destunr_count);
10885 + if (bce.destunr_count > MIPV6_MAX_DESTUNREACH && mipv6_bcache_delete(daddr, saddr, CACHE_ENTRY) == 0) {
10886 + DEBUG(DBG_INFO, "Deleted bcache entry "
10887 + "%x:%x:%x:%x:%x:%x:%x:%x "
10888 + "%x:%x:%x:%x:%x:%x:%x:%x (reason: "
10889 + "%d dest unreachables) ",
10890 + NIPV6ADDR(daddr), NIPV6ADDR(saddr), bce.destunr_count);
10896 +static int mipv6_icmpv6_getfrag(const void *data, struct in6_addr *saddr,
10897 + char *buff, unsigned int offset,
10898 + unsigned int len)
10900 + struct mipv6_icmpv6_msg *msg = (struct mipv6_icmpv6_msg *) data;
10901 + struct icmp6hdr *icmph;
10905 + msg->csum = csum_partial_copy_nocheck(msg->data + offset -
10906 + sizeof(*icmph), buff,
10911 + csum = csum_partial_copy_nocheck((__u8 *) &msg->icmph, buff,
10912 + sizeof(*icmph), msg->csum);
10914 + csum = csum_partial_copy_nocheck(msg->data, buff + sizeof(*icmph),
10915 + len - sizeof(*icmph), csum);
10917 + icmph = (struct icmp6hdr *) buff;
10919 + icmph->icmp6_cksum = csum_ipv6_magic(saddr, msg->daddr, msg->len,
10920 + IPPROTO_ICMPV6, csum);
10925 + * mipv6_icmpv6_send - generic icmpv6 message send
10926 + * @daddr: destination address
10927 + * @saddr: source address
10928 + * @type: icmp type
10929 + * @code: icmp code
10930 + * @id: packet identifier. If null, uses internal counter to get new id
10931 + * @data: packet data
10932 + * @datalen: length of data in bytes
10934 +void mipv6_icmpv6_send(struct in6_addr *daddr, struct in6_addr *saddr, int type,
10935 + int code, __u16 *id, __u16 flags, void *data, int datalen)
10937 + struct sock *sk = mipv6_icmpv6_socket->sk;
10939 + struct mipv6_icmpv6_msg msg;
10943 + fl.proto = IPPROTO_ICMPV6;
10944 + fl.fl6_dst = daddr;
10945 + fl.fl6_src = saddr;
10946 + fl.fl6_flowlabel = 0;
10947 + fl.uli_u.icmpt.type = type;
10948 + fl.uli_u.icmpt.code = code;
10950 + msg.icmph.icmp6_type = type;
10951 + msg.icmph.icmp6_code = code;
10952 + msg.icmph.icmp6_cksum = 0;
10955 + msg.icmph.icmp6_identifier = htons(*id);
10957 + msg.icmph.icmp6_identifier = htons(identifier++);
10959 + msg.icmph.icmp6_sequence = htons(flags);
10962 + msg.len = datalen + sizeof(struct icmp6hdr);
10963 + msg.daddr = daddr;
10965 + if (mipv6_icmpv6_xmit_lock())
10968 + ip6_build_xmit(sk, mipv6_icmpv6_getfrag, &msg, &fl, msg.len, NULL, -1,
10971 + ICMP6_INC_STATS_BH(Icmp6OutMsgs);
10972 + mipv6_icmpv6_xmit_unlock();
10976 + * icmp6_rcv - ICMPv6 receive and multiplex
10977 + * @skb: buffer containing ICMP message
10979 + * Generic ICMPv6 receive function to multiplex messages to approriate
10980 + * handlers. Only used for ICMP messages with special handling in
10983 +static void icmp6_rcv(struct sk_buff *skb)
10985 + struct icmp6hdr *hdr;
10987 + if (skb_is_nonlinear(skb) &&
10988 + skb_linearize(skb, GFP_ATOMIC) != 0) {
10992 + __skb_push(skb, skb->data-skb->h.raw);
10994 + hdr = (struct icmp6hdr *) skb->h.raw;
10996 + switch (hdr->icmp6_type) {
10997 + case ICMPV6_DEST_UNREACH:
10998 + mipv6_icmpv6_rcv_dest_unreach(skb);
11001 + case ICMPV6_PARAMPROB:
11002 + mip6_fn.icmpv6_paramprob_rcv(skb);
11005 + case MIPV6_DHAAD_REPLY:
11006 + mip6_fn.icmpv6_dhaad_rep_rcv(skb);
11009 + case MIPV6_PREFIX_ADV:
11010 + mip6_fn.icmpv6_pfxadv_rcv(skb);
11013 + case MIPV6_DHAAD_REQUEST:
11014 + mip6_fn.icmpv6_dhaad_req_rcv(skb);
11017 + case MIPV6_PREFIX_SOLICIT:
11018 + mip6_fn.icmpv6_pfxsol_rcv(skb);
11023 +int mipv6_icmpv6_init(void)
11028 + if ((mipv6_icmpv6_socket = sock_alloc()) == NULL) {
11029 + DEBUG(DBG_ERROR, "Cannot allocate mipv6_icmpv6_socket");
11032 + mipv6_icmpv6_socket->type = SOCK_RAW;
11034 + if ((err = sock_create(PF_INET6, SOCK_RAW, IPPROTO_ICMP,
11035 + &mipv6_icmpv6_socket)) < 0) {
11036 + DEBUG(DBG_ERROR, "Cannot initialize mipv6_icmpv6_socket");
11037 + sock_release(mipv6_icmpv6_socket);
11038 + mipv6_icmpv6_socket = NULL; /* For safety */
11041 + sk = mipv6_icmpv6_socket->sk;
11042 + sk->allocation = GFP_ATOMIC;
11043 + sk->prot->unhash(sk);
11045 + /* Register our ICMP handler */
11046 + MIPV6_SETCALL(mipv6_icmp_rcv, icmp6_rcv);
11050 +void mipv6_icmpv6_exit(void)
11052 + MIPV6_RESETCALL(mipv6_icmp_rcv);
11053 + if (mipv6_icmpv6_socket)
11054 + sock_release(mipv6_icmpv6_socket);
11055 + mipv6_icmpv6_socket = NULL; /* For safety */
11058 +++ linux-2.4.27/net/ipv6/mobile_ip6/mipv6_icmp.h
11061 + * MIPL Mobile IPv6 ICMP send and receive prototypes
11065 + * This program is free software; you can redistribute it and/or
11066 + * modify it under the terms of the GNU General Public License
11067 + * as published by the Free Software Foundation; either version
11068 + * 2 of the License, or (at your option) any later version.
11071 +#ifndef _MIPV6_ICMP
11072 +#define _MIPV6_ICMP
11074 +#include <linux/config.h>
11075 +#include <linux/in6.h>
11077 +void mipv6_icmpv6_send(struct in6_addr *daddr, struct in6_addr *saddr,
11078 + int type, int code, __u16 *id, __u16 flags,
11079 + void *data, int datalen);
11081 +void mipv6_icmpv6_send_dhaad_req(struct in6_addr *home_addr, int plen, __u16 dhaad_id);
11083 +void mipv6_icmpv6_send_dhaad_rep(int ifindex, __u16 id, struct in6_addr *daddr);
11085 +int mipv6_icmpv6_no_rcv(struct sk_buff *skb);
11087 +/* Receive DHAAD Reply message */
11088 +int mipv6_icmpv6_rcv_dhaad_rep(struct sk_buff *skb);
11089 +/* Receive Parameter Problem message */
11090 +int mipv6_icmpv6_rcv_paramprob(struct sk_buff *skb);
11091 +/* Receive prefix advertisements */
11092 +int mipv6_icmpv6_rcv_pfx_adv(struct sk_buff *skb);
11094 +/* Receive DHAAD Request message */
11095 +int mipv6_icmpv6_rcv_dhaad_req(struct sk_buff *skb);
11096 +/* Receive prefix solicitations */
11097 +int mipv6_icmpv6_rcv_pfx_sol(struct sk_buff *skb);
11099 +int mipv6_icmpv6_init(void);
11100 +void mipv6_icmpv6_exit(void);
11104 +++ linux-2.4.27/net/ipv6/mobile_ip6/mipv6_icmp_ha.c
11107 + * Home Agent specific ICMP routines
11110 + * Antti Tuominen <ajtuomin@tml.hut.fi>
11111 + * Jaakko Laine <medved@iki.fi>
11115 + * This program is free software; you can redistribute it and/or
11116 + * modify it under the terms of the GNU General Public License
11117 + * as published by the Free Software Foundation; either version
11118 + * 2 of the License, or (at your option) any later version.
11121 +#include <linux/autoconf.h>
11122 +#include <linux/sched.h>
11123 +#include <net/ipv6.h>
11124 +#include <net/addrconf.h>
11125 +#include <net/ip6_route.h>
11126 +#include <net/mipv6.h>
11128 +#include "halist.h"
11129 +#include "debug.h"
11130 +#include "mipv6_icmp.h"
11131 +//#include "prefix.h"
11133 +/* Is this the easiest way of checking on
11134 + * which interface an anycast address is ?
11136 +static int find_ac_dev(struct in6_addr *addr)
11139 + struct net_device *dev;
11140 + read_lock(&dev_base_lock);
11141 + for (dev=dev_base; dev; dev=dev->next) {
11142 + if (ipv6_chk_acast_addr(dev, addr)) {
11143 + ifindex = dev->ifindex;
11147 + read_unlock(&dev_base_lock);
11152 + * mipv6_icmpv6_send_dhaad_rep - Reply to DHAAD Request
11153 + * @ifindex: index of interface request was received from
11154 + * @id: request's identification number
11155 + * @daddr: requester's IPv6 address
11157 + * When Home Agent receives Dynamic Home Agent Address Discovery
11158 + * request, it replies with a list of home agents available on the
11161 +void mipv6_icmpv6_send_dhaad_rep(int ifindex, __u16 id, struct in6_addr *daddr)
11163 + __u8 *data = NULL;
11164 + struct in6_addr home, *ha_addrs = NULL;
11165 + int addr_count, max_addrs, size = 0;
11167 + if (daddr == NULL)
11170 + if (mipv6_ha_get_addr(ifindex, &home) < 0) {
11171 + DEBUG(DBG_INFO, "Not Home Agent in this interface");
11175 + /* We send all available HA addresses, not exceeding a maximum
11176 + * number we can fit in a packet with minimum IPv6 MTU (to
11177 + * avoid fragmentation).
11180 + addr_count = mipv6_ha_get_pref_list(ifindex, &ha_addrs, max_addrs);
11182 + if (addr_count < 0) return;
11184 + if (addr_count != 0 && ha_addrs == NULL) {
11185 + DEBUG(DBG_ERROR, "addr_count = %d but return no addresses",
11189 + data = (u8 *)ha_addrs;
11191 + size = addr_count * sizeof(struct in6_addr);
11193 + mipv6_icmpv6_send(daddr, &home, MIPV6_DHAAD_REPLY,
11194 + 0, &id, 0, data, size);
11202 + * mipv6_icmpv6_dhaad_req - Home Agent Address Discovery Request ICMP handler
11203 + * @skb: buffer containing ICMP information message
11205 + * Special Mobile IPv6 ICMP message. Handles Dynamic Home Agent
11206 + * Address Discovery Request messages.
11208 +int mipv6_icmpv6_rcv_dhaad_req(struct sk_buff *skb)
11210 + struct icmp6hdr *phdr = (struct icmp6hdr *) skb->h.raw;
11211 + struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
11212 + struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
11213 + __u16 identifier;
11218 + /* Invalid packet checks. */
11219 + if (phdr->icmp6_code != 0)
11222 + identifier = ntohs(phdr->icmp6_identifier);
11225 + * Make sure we have the right ifindex (if the
11226 + * req came through another interface.
11228 + ifindex = find_ac_dev(daddr);
11229 + if (ifindex == 0) {
11230 + DEBUG(DBG_WARNING, "received dhaad request to anycast address %x:%x:%x:%x:%x:%x:%x:%x"
11231 + " on which prefix we are not HA",
11232 + NIPV6ADDR(daddr));
11237 + * send reply with list
11239 + mipv6_icmpv6_send_dhaad_rep(ifindex, identifier, saddr);
11244 + * mipv6_icmpv6_handle_pfx_sol - handle prefix solicitations
11245 + * @skb: sk_buff including the icmp6 message
11247 +int mipv6_icmpv6_rcv_pfx_sol(struct sk_buff *skb)
11249 + struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
11250 + struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
11251 + struct inet6_ifaddr *ifp;
11255 + if (!(ifp = ipv6_get_ifaddr(daddr, NULL)))
11258 + in6_ifa_put(ifp);
11259 + mipv6_pfx_cancel_send(saddr, -1);
11265 +++ linux-2.4.27/net/ipv6/mobile_ip6/mipv6_icmp_mn.c
11268 + * Mobile Node specific ICMP routines
11271 + * Antti Tuominen <ajtuomin@tml.hut.fi>
11272 + * Jaakko Laine <medved@iki.fi>
11276 + * This program is free software; you can redistribute it and/or
11277 + * modify it under the terms of the GNU General Public License
11278 + * as published by the Free Software Foundation; either version
11279 + * 2 of the License, or (at your option) any later version.
11282 +#include <linux/sched.h>
11283 +#include <net/ipv6.h>
11284 +#include <net/ip6_route.h>
11285 +#include <net/addrconf.h>
11286 +#include <net/mipv6.h>
11290 +#include "mdetect.h"
11291 +#include "debug.h"
11292 +#include "mipv6_icmp.h"
11294 +//#include "prefix.h"
11296 +#define INFINITY 0xffffffff
11299 + * mipv6_icmpv6_paramprob - Parameter Problem ICMP error message handler
11300 + * @skb: buffer containing ICMP error message
11302 + * Special Mobile IPv6 ICMP handling. If Mobile Node receives ICMP
11303 + * Parameter Problem message when using a Home Address Option,
11304 + * offending node should be logged and error message dropped. If
11305 + * error is received because of a Binding Update, offending node
11306 + * should be recorded in Binding Update List and no more Binding
11307 + * Updates should be sent to this destination. See RFC 3775 section
11310 +int mipv6_icmpv6_rcv_paramprob(struct sk_buff *skb)
11312 + struct icmp6hdr *phdr = (struct icmp6hdr *) skb->h.raw;
11313 + struct in6_addr *saddr = skb ? &skb->nh.ipv6h->saddr : NULL;
11314 + struct in6_addr *daddr = skb ? &skb->nh.ipv6h->daddr : NULL;
11315 + struct ipv6hdr *hdr = (struct ipv6hdr *) (phdr + 1);
11316 + int ulen = (skb->tail - (unsigned char *) (phdr + 1));
11323 + /* We only handle code 1 & 2 messages. */
11324 + if (phdr->icmp6_code != ICMPV6_UNK_NEXTHDR &&
11325 + phdr->icmp6_code != ICMPV6_UNK_OPTION)
11328 + /* Find offending octet in the original packet. */
11329 + errptr = ntohl(phdr->icmp6_pointer);
11331 + /* There is not enough of the original packet left to figure
11332 + * out what went wrong. Bail out. */
11333 + if (ulen <= errptr)
11336 + off_octet = ((__u8 *) hdr + errptr);
11337 + DEBUG(DBG_INFO, "Parameter problem: offending octet %d [0x%2x]",
11338 + errptr, *off_octet);
11340 + /* If CN did not understand Mobility Header, set BUL entry to
11341 + * ACK_ERROR so no further BUs are sumbitted to this CN. */
11342 + if (phdr->icmp6_code == ICMPV6_UNK_NEXTHDR &&
11343 + *off_octet == IPPROTO_MOBILITY) {
11344 + struct bul_inval_args args;
11345 + args.all_rr_states = 1;
11348 + write_lock(&bul_lock);
11349 + mipv6_bul_iterate(mn_bul_invalidate, &args);
11350 + write_unlock(&bul_lock);
11353 + /* If CN did not understand Home Address Option, we log an
11354 + * error and discard the error message. */
11355 + if (phdr->icmp6_code == ICMPV6_UNK_OPTION &&
11356 + *off_octet == MIPV6_TLV_HOMEADDR) {
11357 + DEBUG(DBG_WARNING, "Correspondent node does not "
11358 + "implement Home Address Option receipt.");
11365 + * mipv6_mn_dhaad_send_req - Send DHAAD Request to home network
11366 + * @home_addr: address to do DHAAD for
11367 + * @plen: prefix length for @home_addr
11369 + * Send Dynamic Home Agent Address Discovery Request to the Home
11370 + * Agents anycast address in the nodes home network.
11373 +mipv6_icmpv6_send_dhaad_req(struct in6_addr *home_addr, int plen, __u16 dhaad_id)
11375 + struct in6_addr ha_anycast;
11376 + struct in6_addr careofaddr;
11378 + if (mipv6_get_care_of_address(home_addr, &careofaddr) < 0) {
11379 + DEBUG(DBG_WARNING, "Could not get node's Care-of Address");
11383 + if (mipv6_ha_anycast(&ha_anycast, home_addr, plen) < 0) {
11384 + DEBUG(DBG_WARNING,
11385 + "Could not get Home Agent Anycast address for home address %x:%x.%x:%x:%x:%x:%x:%x/%d",
11386 + NIPV6ADDR(home_addr), plen);
11390 + mipv6_icmpv6_send(&ha_anycast, &careofaddr, MIPV6_DHAAD_REQUEST, 0,
11391 + &dhaad_id, 0, NULL, 0);
11396 + * mipv6_icmpv6_dhaad_rep - Home Agent Address Discovery Reply ICMP handler
11397 + * @skb: buffer containing ICMP information message
11399 + * Special Mobile IPv6 ICMP message. Handles Dynamic Home Agent
11400 + * Address Discovery Reply messages.
11402 +int mipv6_icmpv6_rcv_dhaad_rep(struct sk_buff *skb)
11404 + struct icmp6hdr *phdr = (struct icmp6hdr *) skb->h.raw;
11405 + struct in6_addr *address;
11406 + struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
11407 + __u16 identifier;
11408 + int ulen = (skb->tail - (unsigned char *) ((__u32 *) phdr + 2));
11410 + struct in6_addr home_addr, coa;
11411 + struct in6_addr *first_ha = NULL;
11412 + struct mn_info *minfo;
11413 + int n_addr = ulen / sizeof(struct in6_addr);
11417 + /* Invalid packet checks. */
11418 + if (ulen % sizeof(struct in6_addr) != 0)
11421 + if (phdr->icmp6_code != 0)
11424 + identifier = ntohs(phdr->icmp6_identifier);
11426 + address = (struct in6_addr *) ((__u32 *) phdr + 2);
11432 + /* receive list of home agent addresses
11433 + * add to home agents list
11435 + DEBUG(DBG_INFO, "DHAAD: got %d home agents", n_addr);
11437 + first_ha = address;
11439 + /* lookup H@ with identifier */
11440 + read_lock(&mn_info_lock);
11441 + minfo = mipv6_mninfo_get_by_id(identifier);
11443 + read_unlock(&mn_info_lock);
11444 + DEBUG(DBG_INFO, "no mninfo with id %d",
11448 + spin_lock(&minfo->lock);
11451 + * 1. if old HA on list, prefer it
11452 + * 2. otherwise first HA on list prefered
11454 + for (i = 0; i < n_addr; i++) {
11455 + DEBUG(DBG_INFO, "HA[%d] %x:%x:%x:%x:%x:%x:%x:%x",
11456 + i, NIPV6ADDR(address));
11457 + if (ipv6_addr_cmp(&minfo->ha, address) == 0) {
11458 + spin_unlock(&minfo->lock);
11459 + read_unlock(&mn_info_lock);
11464 + ipv6_addr_copy(&minfo->ha, first_ha);
11465 + spin_unlock(&minfo->lock);
11466 + ipv6_addr_copy(&home_addr, &minfo->home_addr);
11467 + read_unlock(&mn_info_lock);
11469 + mipv6_get_care_of_address(&home_addr, &coa);
11470 + init_home_registration(&home_addr, &coa);
11476 + * mipv6_icmpv6_handle_pfx_adv - handle prefix advertisements
11477 + * @skb: sk_buff including the icmp6 message
11479 +int mipv6_icmpv6_rcv_pfx_adv(struct sk_buff *skb)
11481 + struct icmp6hdr *hdr = (struct icmp6hdr *) skb->h.raw;
11482 + struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
11483 + struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
11484 + __u8 *opt = (__u8 *) (hdr + 1);
11485 + int optlen = (skb->tail - opt);
11486 + unsigned long min_expire = INFINITY;
11487 + struct inet6_skb_parm *parm = (struct inet6_skb_parm *) skb->cb;
11491 + while (optlen > 0) {
11492 + int len = opt[1] << 3;
11496 + if (opt[0] == ND_OPT_PREFIX_INFO) {
11498 + unsigned long expire;
11499 + struct prefix_info *pinfo =
11500 + (struct prefix_info *) opt;
11501 + struct net_device *dev;
11502 + struct mn_info *mninfo;
11504 + read_lock(&mn_info_lock);
11505 + mninfo = mipv6_mninfo_get_by_ha(saddr);
11506 + if (mninfo == NULL) {
11509 + spin_lock(&mninfo->lock);
11510 + ifindex = mninfo->ifindex;
11511 + spin_unlock(&mninfo->lock);
11514 + read_unlock(&mn_info_lock);
11516 + if (!(dev = dev_get_by_index(ifindex))) {
11517 + DEBUG(DBG_WARNING, "Cannot find device by index %d", parm->iif);
11521 + expire = ntohl(pinfo->valid);
11522 + expire = expire == 0 ? INFINITY : expire;
11524 + min_expire = expire < min_expire ? expire : min_expire;
11536 + mipv6_pfx_add_home(parm->iif, saddr, daddr, min_expire);
11541 +++ linux-2.4.27/net/ipv6/mobile_ip6/mn.c
11544 + * Mobile-node functionality
11547 + * Sami Kivisaari <skivisaa@cc.hut.fi>
11551 + * This program is free software; you can redistribute it and/or
11552 + * modify it under the terms of the GNU General Public License
11553 + * as published by the Free Software Foundation; either version
11554 + * 2 of the License, or (at your option) any later version.
11558 +#include <linux/autoconf.h>
11559 +#include <linux/sched.h>
11560 +#include <linux/ipv6.h>
11561 +#include <linux/net.h>
11562 +#include <linux/init.h>
11563 +#include <linux/skbuff.h>
11564 +#include <linux/rtnetlink.h>
11565 +#include <linux/if_arp.h>
11566 +#include <linux/ipsec.h>
11567 +#include <linux/notifier.h>
11568 +#include <linux/list.h>
11569 +#include <linux/route.h>
11570 +#include <linux/netfilter.h>
11571 +#include <linux/netfilter_ipv6.h>
11572 +#include <linux/tqueue.h>
11573 +#include <linux/proc_fs.h>
11575 +#include <asm/uaccess.h>
11577 +#include <net/ipv6.h>
11578 +#include <net/addrconf.h>
11579 +#include <net/neighbour.h>
11580 +#include <net/ndisc.h>
11581 +#include <net/ip6_route.h>
11582 +#include <net/mipglue.h>
11585 +#include "mdetect.h"
11587 +#include "mobhdr.h"
11588 +#include "debug.h"
11590 +#include "mipv6_icmp.h"
11591 +#include "multiaccess_ctl.h"
11592 +//#include "prefix.h"
11593 +#include "tunnel_mn.h"
11594 +#include "stats.h"
11595 +#include "config.h"
11597 +#define MIPV6_BUL_SIZE 128
11599 +static LIST_HEAD(mn_info_list);
11601 +/* Lock for list of MN infos */
11602 +rwlock_t mn_info_lock = RW_LOCK_UNLOCKED;
11604 +static spinlock_t ifrh_lock = SPIN_LOCK_UNLOCKED;
11606 +struct ifr_holder {
11607 + struct list_head list;
11608 + struct in6_ifreq ifr;
11610 + struct handoff *ho;
11613 +LIST_HEAD(ifrh_list);
11615 +static struct tq_struct mv_home_addr_task;
11617 +/* Determines whether manually configured home addresses are preferred as
11618 + * source addresses over dynamically configured ones
11620 +int mipv6_use_preconfigured_hoaddr = 1;
11622 +/* Determines whether home addresses, which are at home are preferred as
11623 + * source addresses over other home addresses
11625 +int mipv6_use_topol_corr_hoaddr = 0;
11627 +static spinlock_t icmpv6_id_lock = SPIN_LOCK_UNLOCKED;
11628 +static __u16 icmpv6_id = 0;
11630 +static inline __u16 mipv6_get_dhaad_id(void)
11633 + spin_lock_bh(&icmpv6_id_lock);
11634 + ret = ++icmpv6_id;
11635 + spin_unlock_bh(&icmpv6_id_lock);
11640 + * mipv6_mninfo_get_by_home - Returns mn_info for a home address
11641 + * @haddr: home address of MN
11643 + * Returns mn_info on success %NULL otherwise. Caller MUST hold
11644 + * @mn_info_lock (read or write).
11646 +struct mn_info *mipv6_mninfo_get_by_home(struct in6_addr *haddr)
11648 + struct list_head *lh;
11649 + struct mn_info *minfo;
11656 + list_for_each(lh, &mn_info_list) {
11657 + minfo = list_entry(lh, struct mn_info, list);
11658 + spin_lock(&minfo->lock);
11659 + if (!ipv6_addr_cmp(&minfo->home_addr, haddr)) {
11660 + spin_unlock(&minfo->lock);
11663 + spin_unlock(&minfo->lock);
11669 + * mipv6_mninfo_get_by_ha - Lookup mn_info with Home Agent address
11670 + * @home_agent: Home Agent address
11672 + * Searches for a mn_info entry with @ha set to @home_agent. You MUST
11673 + * hold @mn_info_lock when calling this function. Returns pointer to
11674 + * mn_info entry or %NULL on failure.
11676 +struct mn_info *mipv6_mninfo_get_by_ha(struct in6_addr *home_agent)
11678 + struct list_head *lh;
11679 + struct mn_info *minfo;
11684 + list_for_each(lh, &mn_info_list) {
11685 + minfo = list_entry(lh, struct mn_info, list);
11686 + spin_lock(&minfo->lock);
11687 + if (!ipv6_addr_cmp(&minfo->ha, home_agent)) {
11688 + spin_unlock(&minfo->lock);
11691 + spin_unlock(&minfo->lock);
11697 + * mipv6_mninfo_get_by_id - Lookup mn_info with id
11698 + * @id: DHAAD identifier
11700 + * Searches for a mn_info entry with @dhaad_id set to @id. You MUST
11701 + * hold @mn_info_lock when calling this function. Returns pointer to
11702 + * mn_info entry or %NULL on failure.
11704 +struct mn_info *mipv6_mninfo_get_by_id(unsigned short id)
11706 + struct list_head *lh;
11707 + struct mn_info *minfo = 0;
11709 + list_for_each(lh, &mn_info_list) {
11710 + minfo = list_entry(lh, struct mn_info, list);
11711 + spin_lock(&minfo->lock);
11712 + if (minfo->dhaad_id == id) {
11713 + spin_unlock(&minfo->lock);
11716 + spin_unlock(&minfo->lock);
11722 + * mipv6_mninfo_add - Adds a new home info for MN
11723 + * @ifindex: Interface for home address
11724 + * @home_addr: Home address of MN, must be set
11725 + * @plen: prefix length of the home address, must be set
11726 + * @isathome : home address at home
11727 + * @lifetime: lifetime of the home address, 0 is infinite
11728 + * @ha: home agent for the home address
11729 + * @ha_plen: prefix length of home agent's address, can be zero
11730 + * @ha_lifetime: Lifetime of the home address, 0 is infinite
11732 + * The function adds a new home info entry for MN, allowing it to
11733 + * register the home address with the home agent. Starts home
11734 + * registration process. If @ha is %ADDRANY, DHAAD is performed to
11735 + * find a home agent. Returns 0 on success, a negative value
11736 + * otherwise. Caller MUST NOT hold @mn_info_lock or
11737 + * @addrconf_hash_lock.
11739 +void mipv6_mninfo_add(int ifindex, struct in6_addr *home_addr, int plen,
11740 + int isathome, unsigned long lifetime, struct in6_addr *ha,
11741 + int ha_plen, unsigned long ha_lifetime, int man_conf)
11743 + struct mn_info *minfo;
11744 + struct in6_addr coa;
11748 + write_lock_bh(&mn_info_lock);
11749 + if ((minfo = mipv6_mninfo_get_by_home(home_addr)) != NULL){
11750 + DEBUG(1, "MN info already exists");
11751 + write_unlock_bh(&mn_info_lock);
11754 + minfo = kmalloc(sizeof(struct mn_info), GFP_ATOMIC);
11756 + write_unlock_bh(&mn_info_lock);
11759 + memset(minfo, 0, sizeof(struct mn_info));
11760 + spin_lock_init(&minfo->lock);
11763 + ipv6_addr_copy(&minfo->home_addr, home_addr);
11766 + ipv6_addr_copy(&minfo->ha, ha);
11767 + if (ha_plen < 128 && ha_plen > 0)
11768 + minfo->home_plen = ha_plen;
11769 + else minfo->home_plen = 64;
11771 + minfo->ifindex_user = ifindex; /* Ifindex for tunnel interface */
11772 + minfo->ifindex = ifindex; /* Interface on which home address is currently conf'd */
11773 + /* TODO: we should get home address lifetime from somewhere */
11774 + /* minfo->home_addr_expires = jiffies + lifetime * HZ; */
11776 + /* manual configuration flag cannot be unset by dynamic updates
11777 + * from prefix advertisements
11779 + if (!minfo->man_conf) minfo->man_conf = man_conf;
11780 + minfo->is_at_home = isathome;
11782 + list_add(&minfo->list, &mn_info_list);
11783 + write_unlock_bh(&mn_info_lock);
11785 + if (mipv6_get_care_of_address(home_addr, &coa) == 0)
11786 + init_home_registration(home_addr, &coa);
11790 + * mipv6_mninfo_del - Delete home info for MN
11791 + * @home_addr : Home address or prefix
11792 + * @del_dyn_only : Delete only dynamically created home entries
11794 + * Deletes every mn_info entry that matches the first plen bits of
11795 + * @home_addr. Returns number of deleted entries on success and a
11796 + * negative value otherwise. Caller MUST NOT hold @mn_info_lock.
11798 +int mipv6_mninfo_del(struct in6_addr *home_addr, int del_dyn_only)
11800 + struct list_head *lh, *next;
11801 + struct mn_info *minfo;
11806 + write_lock(&mn_info_lock);
11808 + list_for_each_safe(lh, next, &mn_info_list) {
11809 + minfo = list_entry(lh, struct mn_info, list);
11810 + if (ipv6_addr_cmp(&minfo->home_addr, home_addr) == 0
11811 + && ((!minfo->man_conf && del_dyn_only) || !del_dyn_only)){
11812 + list_del(&minfo->list);
11817 + write_unlock(&mn_info_lock);
11821 +void mipv6_mn_set_home(int ifindex, struct in6_addr *homeaddr, int plen,
11822 + struct in6_addr *homeagent, int ha_plen)
11824 + mipv6_mninfo_add(ifindex, homeaddr, plen, 0, 0,
11825 + homeagent, ha_plen, 0, 1);
11828 +static int skip_dad(struct in6_addr *addr)
11830 + struct mn_info *minfo;
11833 + if (addr == NULL) {
11834 + DEBUG(DBG_CRITICAL, "Null argument");
11837 + read_lock_bh(&mn_info_lock);
11838 + if ((minfo = mipv6_mninfo_get_by_home(addr)) != NULL) {
11839 + if ((minfo->is_at_home != MN_NOT_AT_HOME) && (minfo->has_home_reg))
11841 + DEBUG(DBG_INFO, "minfo->is_at_home = %d, minfo->has_home_reg = %d",
11842 + minfo->is_at_home, minfo->has_home_reg);
11844 + read_unlock_bh(&mn_info_lock);
11849 + * mipv6_mn_is_home_addr - Determines if addr is node's home address
11850 + * @addr: IPv6 address
11852 + * Returns 1 if addr is node's home address. Otherwise returns zero.
11854 +int mipv6_mn_is_home_addr(struct in6_addr *addr)
11858 + if (addr == NULL) {
11859 + DEBUG(DBG_CRITICAL, "Null argument");
11862 + read_lock_bh(&mn_info_lock);
11863 + if (mipv6_mninfo_get_by_home(addr))
11865 + read_unlock_bh(&mn_info_lock);
11871 + * mipv6_mn_is_at_home - determine if node is home for a home address
11872 + * @home_addr : home address of MN
11874 + * Returns 1 if home address in question is in the home network, 0
11875 + * otherwise. Caller MUST NOT not hold @mn_info_lock.
11877 +int mipv6_mn_is_at_home(struct in6_addr *home_addr)
11879 + struct mn_info *minfo;
11881 + read_lock_bh(&mn_info_lock);
11882 + if ((minfo = mipv6_mninfo_get_by_home(home_addr)) != NULL) {
11883 + spin_lock(&minfo->lock);
11884 + ret = (minfo->is_at_home == MN_AT_HOME);
11885 + spin_unlock(&minfo->lock);
11887 + read_unlock_bh(&mn_info_lock);
11890 +void mipv6_mn_set_home_reg(struct in6_addr *home_addr, int has_home_reg)
11892 + struct mn_info *minfo;
11893 + read_lock_bh(&mn_info_lock);
11895 + if ((minfo = mipv6_mninfo_get_by_home(home_addr)) != NULL) {
11896 + spin_lock(&minfo->lock);
11897 + minfo->has_home_reg = has_home_reg;
11898 + spin_unlock(&minfo->lock);
11900 + read_unlock_bh(&mn_info_lock);
11903 +static int mn_inet6addr_event(
11904 + struct notifier_block *nb, unsigned long event, void *ptr)
11906 + struct inet6_ifaddr *ifp = (struct inet6_ifaddr *)ptr;
11910 + /* Is address a valid coa ?*/
11911 + if (!(ifp->flags & IFA_F_TENTATIVE))
11912 + mipv6_mdet_finalize_ho(&ifp->addr,
11913 + ifp->idev->dev->ifindex);
11914 + else if(skip_dad(&ifp->addr))
11915 + ifp->flags &= ~IFA_F_TENTATIVE;
11917 + case NETDEV_DOWN:
11919 + /* This is useless with manually configured home
11920 + addresses, which will not expire
11922 + mipv6_mninfo_del(&ifp->addr, 0);
11928 + return NOTIFY_DONE;
11931 +struct notifier_block mipv6_mn_inet6addr_notifier = {
11932 + mn_inet6addr_event,
11934 + 0 /* check if using zero is ok */
11937 +static void mipv6_get_saddr_hook(struct in6_addr *homeaddr)
11939 + int found = 0, reiter = 0;
11940 + struct list_head *lh;
11941 + struct mn_info *minfo = NULL;
11942 + struct in6_addr coa;
11944 + read_lock_bh(&mn_info_lock);
11946 + list_for_each(lh, &mn_info_list) {
11947 + minfo = list_entry(lh, struct mn_info, list);
11948 + if ((ipv6_addr_scope(homeaddr) != ipv6_addr_scope(&minfo->home_addr))
11949 + || ipv6_chk_addr(&minfo->home_addr, NULL) == 0)
11952 + spin_lock(&minfo->lock);
11953 + if (minfo->is_at_home == MN_AT_HOME || minfo->has_home_reg) {
11954 + if ((mipv6_use_topol_corr_hoaddr &&
11955 + minfo->is_at_home == MN_AT_HOME) ||
11956 + (mipv6_use_preconfigured_hoaddr &&
11957 + minfo->man_conf) ||
11958 + (!(mipv6_use_preconfigured_hoaddr ||
11959 + mipv6_use_topol_corr_hoaddr) || reiter)) {
11960 + spin_unlock(&minfo->lock);
11961 + ipv6_addr_copy(homeaddr, &minfo->home_addr);
11966 + spin_unlock(&minfo->lock);
11968 + if (!found && !reiter) {
11973 + if (!found && minfo &&
11974 + !mipv6_get_care_of_address(&minfo->home_addr, &coa)) {
11975 + ipv6_addr_copy(homeaddr, &coa);
11977 + read_unlock_bh(&mn_info_lock);
11979 + DEBUG(DBG_DATADUMP, "Source address selection: %x:%x:%x:%x:%x:%x:%x:%x",
11980 + NIPV6ADDR(homeaddr));
11984 +static void mv_home_addr(void *arg)
11986 + mm_segment_t oldfs;
11987 + int err = 0, new_if = 0;
11988 + struct list_head *lh, *next;
11989 + struct ifr_holder *ifrh;
11992 + DEBUG(DBG_INFO, "mipv6 move home address task");
11994 + spin_lock_bh(&ifrh_lock);
11995 + list_splice_init(&ifrh_list, &list);
11996 + spin_unlock_bh(&ifrh_lock);
11998 + oldfs = get_fs(); set_fs(KERNEL_DS);
11999 + list_for_each_safe(lh, next, &list) {
12000 + ifrh = list_entry(lh, struct ifr_holder, list);
12001 + if (ifrh->old_ifi) {
12002 + new_if = ifrh->ifr.ifr6_ifindex;
12003 + ifrh->ifr.ifr6_ifindex = ifrh->old_ifi;
12004 + err = addrconf_del_ifaddr(&ifrh->ifr);
12005 + ifrh->ifr.ifr6_ifindex = new_if;
12007 + DEBUG(DBG_WARNING, "removal of home address %x:%x:%x:%x:%x:%x:%x:%x from"
12008 + " old interface %d failed with status %d",
12009 + NIPV6ADDR(&ifrh->ifr.ifr6_addr), ifrh->old_ifi, err);
12012 + err = addrconf_add_ifaddr(&ifrh->ifr);
12015 + DEBUG(DBG_INFO, "Calling mobile_node moved after moving home address to new if");
12016 + mipv6_mobile_node_moved(ifrh->ho);
12018 + list_del(&ifrh->list);
12024 + DEBUG(DBG_WARNING, "adding of home address to a new interface %d failed %d", new_if, err);
12026 + DEBUG(DBG_WARNING, "adding of home address to a new interface OK");
12030 +struct dhaad_halist {
12031 + struct list_head list;
12032 + struct in6_addr addr;
12036 +/* clear all has from candidate list. do this when a new dhaad reply
12037 + * is received. */
12038 +int mipv6_mn_flush_ha_candidate(struct list_head *ha)
12040 + struct list_head *p, *tmp;
12041 + struct dhaad_halist *e;
12043 + list_for_each_safe(p, tmp, ha) {
12044 + e = list_entry(p, struct dhaad_halist, list);
12052 +/* add new ha to candidates. only done when dhaad reply is received. */
12053 +int mipv6_mn_add_ha_candidate(struct list_head *ha, struct in6_addr *addr)
12055 + struct dhaad_halist *e;
12057 + e = kmalloc(sizeof(*e), GFP_ATOMIC);
12058 + memset(e, 0, sizeof(*e));
12059 + ipv6_addr_copy(&e->addr, addr);
12061 + list_add_tail(&e->list, ha);
12065 +#define MAX_RETRIES_PER_HA 3
12067 +/* get next ha candidate. this is done when dhaad reply has been
12068 + * received and we want to register with the best available ha. */
12069 +int mipv6_mn_get_ha_candidate(struct list_head *ha, struct in6_addr *addr)
12071 + struct list_head *p;
12073 + list_for_each(p, ha) {
12074 + struct dhaad_halist *e;
12075 + e = list_entry(p, typeof(*e), list);
12076 + if (e->retry >= 0 && e->retry < MAX_RETRIES_PER_HA) {
12077 + ipv6_addr_copy(addr, &e->addr);
12084 +/* change candidate status. if registration with ha fails, we
12085 + * increase retry for ha candidate. if retry is >= 3 we set it to -1
12086 + * (failed), do get_ha_candidate() again */
12087 +int mipv6_mn_try_ha_candidate(struct list_head *ha, struct in6_addr *addr)
12089 + struct list_head *p;
12091 + list_for_each(p, ha) {
12092 + struct dhaad_halist *e;
12093 + e = list_entry(p, typeof(*e), list);
12094 + if (ipv6_addr_cmp(addr, &e->addr) == 0) {
12095 + if (e->retry >= MAX_RETRIES_PER_HA) e->retry = -1;
12096 + else if (e->retry >= 0) e->retry++;
12104 + * mipv6_mn_get_bulifetime - Get lifetime for a binding update
12105 + * @home_addr: home address for BU
12106 + * @coa: care-of address for BU
12107 + * @flags: flags used for BU
12109 + * Returns maximum lifetime for BUs determined by the lifetime of
12110 + * care-of address and the lifetime of home address.
12112 +__u32 mipv6_mn_get_bulifetime(struct in6_addr *home_addr, struct in6_addr *coa,
12115 + struct inet6_ifaddr *ifp_hoa, *ifp_coa;
12116 + __u32 lifetime = (flags & MIPV6_BU_F_HOME ?
12117 + HA_BU_DEF_LIFETIME : CN_BU_DEF_LIFETIME);
12119 + ifp_hoa = ipv6_get_ifaddr(home_addr, NULL);
12121 + DEBUG(DBG_INFO, "home address missing");
12124 + if (!(ifp_hoa->flags & IFA_F_PERMANENT)){
12125 + if (ifp_hoa->valid_lft)
12126 + lifetime = min_t(__u32, lifetime, ifp_hoa->valid_lft);
12128 + DEBUG(DBG_ERROR, "Zero lifetime for home address");
12130 + in6_ifa_put(ifp_hoa);
12132 + ifp_coa = ipv6_get_ifaddr(coa, NULL);
12134 + DEBUG(DBG_INFO, "care-of address missing");
12137 + if (!(ifp_coa->flags & IFA_F_PERMANENT)) {
12138 + if(ifp_coa->valid_lft)
12139 + lifetime = min_t(__u32, lifetime, ifp_coa->valid_lft);
12142 + "Zero lifetime for care-of address");
12144 + in6_ifa_put(ifp_coa);
12146 + DEBUG(DBG_INFO, "Lifetime for binding is %ld", lifetime);
12151 +mipv6_mn_tnl_rcv_send_bu_hook(struct ip6_tnl *t, struct sk_buff *skb)
12153 + struct ipv6hdr *inner;
12154 + struct ipv6hdr *outer = skb->nh.ipv6h;
12155 + struct mn_info *minfo = NULL;
12157 + __u8 user_flags = 0;
12161 + if (!is_mip6_tnl(t))
12162 + return IP6_TNL_ACCEPT;
12164 + if (!mip6node_cnf.accept_ret_rout) {
12165 + DEBUG(DBG_INFO, "Return routability administratively disabled"
12166 + " not doing route optimization");
12167 + return IP6_TNL_ACCEPT;
12169 + if (!pskb_may_pull(skb, skb->h.raw-skb->data+sizeof(*inner)))
12170 + return IP6_TNL_DROP;
12172 + inner = (struct ipv6hdr *)skb->h.raw;
12174 + read_lock(&mn_info_lock);
12175 + minfo = mipv6_mninfo_get_by_home(&inner->daddr);
12178 + DEBUG(DBG_WARNING, "MN info missing");
12179 + read_unlock(&mn_info_lock);
12180 + return IP6_TNL_ACCEPT;
12182 + DEBUG(DBG_DATADUMP, "MIPV6 MN: Received a tunneled IPv6 packet"
12183 + " to %x:%x:%x:%x:%x:%x:%x:%x,"
12184 + " from %x:%x:%x:%x:%x:%x:%x:%x with\n tunnel header"
12185 + "daddr: %x:%x:%x:%x:%x:%x:%x:%x,"
12186 + "saddr: %x:%x:%x:%x:%x:%x:%x:%x",
12187 + NIPV6ADDR(&inner->daddr), NIPV6ADDR(&inner->saddr),
12188 + NIPV6ADDR(&outer->daddr), NIPV6ADDR(&outer->saddr));
12190 + spin_lock(&minfo->lock);
12192 + /* We don't send bus in response to all tunneled packets */
12194 + if (!ipv6_addr_cmp(&minfo->ha, &inner->saddr)) {
12195 + spin_unlock(&minfo->lock);
12196 + read_unlock(&mn_info_lock);
12197 + DEBUG(DBG_ERROR, "HA BUG: Received a tunneled packet "
12198 + "originally sent by home agent, not sending BU");
12199 + return IP6_TNL_ACCEPT;
12201 + spin_unlock(&minfo->lock);
12202 + read_unlock(&mn_info_lock);
12204 + DEBUG(DBG_DATADUMP, "Sending BU to correspondent node");
12206 + user_flags |= mip6node_cnf.bu_cn_ack ? MIPV6_BU_F_ACK : 0;
12208 + if (inner->nexthdr != IPPROTO_DSTOPTS &&
12209 + inner->nexthdr != IPPROTO_MOBILITY) {
12210 + struct in6_addr coa;
12211 + /* Don't start RR when receiving ICMP error messages */
12212 + if (inner->nexthdr == IPPROTO_ICMPV6) {
12213 + int ptr = (u8*)(inner+1) - skb->data;
12216 + if (skb_copy_bits(skb,
12217 + ptr+offsetof(struct icmp6hdr,
12220 + || !(type & ICMPV6_INFOMSG_MASK)) {
12221 + return IP6_TNL_ACCEPT;
12224 + lifetime = mipv6_mn_get_bulifetime(&inner->daddr,
12225 + &outer->daddr, 0);
12227 + !mipv6_get_care_of_address(&inner->daddr, &coa)) {
12228 + write_lock(&bul_lock);
12229 + mipv6_send_bu(&inner->daddr, &inner->saddr, &coa,
12230 + INITIAL_BINDACK_TIMEOUT,
12231 + MAX_BINDACK_TIMEOUT, 1,
12234 + write_unlock(&bul_lock);
12237 + DEBUG(DBG_DATADUMP, "setting rcv_tunnel flag in skb");
12238 + skb->security |= MIPV6_RCV_TUNNEL;
12239 + return IP6_TNL_ACCEPT;
12242 +static struct ip6_tnl_hook_ops mipv6_mn_tnl_rcv_send_bu_ops = {
12244 + IP6_TNL_PRE_DECAP,
12245 + IP6_TNL_PRI_FIRST,
12246 + mipv6_mn_tnl_rcv_send_bu_hook
12250 +mipv6_mn_tnl_xmit_stats_hook(struct ip6_tnl *t, struct sk_buff *skb)
12253 + if (is_mip6_tnl(t))
12254 + MIPV6_INC_STATS(n_encapsulations);
12255 + return IP6_TNL_ACCEPT;
12258 +static struct ip6_tnl_hook_ops mipv6_mn_tnl_xmit_stats_ops = {
12260 + IP6_TNL_PRE_ENCAP,
12261 + IP6_TNL_PRI_LAST,
12262 + mipv6_mn_tnl_xmit_stats_hook
12266 +mipv6_mn_tnl_rcv_stats_hook(struct ip6_tnl *t, struct sk_buff *skb)
12269 + if (is_mip6_tnl(t))
12270 + MIPV6_INC_STATS(n_decapsulations);
12271 + return IP6_TNL_ACCEPT;
12274 +static struct ip6_tnl_hook_ops mipv6_mn_tnl_rcv_stats_ops = {
12276 + IP6_TNL_PRE_DECAP,
12277 + IP6_TNL_PRI_LAST,
12278 + mipv6_mn_tnl_rcv_stats_hook
12281 +static void mn_check_tunneled_packet(struct sk_buff *skb)
12284 + /* If tunnel flag was set */
12285 + if (skb->security & MIPV6_RCV_TUNNEL) {
12286 + struct in6_addr coa;
12288 + __u8 user_flags = 0;
12289 + int ptr = (u8*)(skb->nh.ipv6h+1) - skb->data;
12290 + int len = skb->len - ptr;
12291 + __u8 nexthdr = skb->nh.ipv6h->nexthdr;
12296 + ptr = ipv6_skip_exthdr(skb, ptr, &nexthdr, len);
12300 + if (!mip6node_cnf.accept_ret_rout) {
12301 + DEBUG(DBG_INFO, "Return routability administratively disabled");
12304 + if (nexthdr == IPPROTO_MOBILITY)
12307 + /* Don't start RR when receiving ICMP error messages */
12308 + if (nexthdr == IPPROTO_ICMPV6) {
12311 + if (skb_copy_bits(skb,
12312 + ptr+offsetof(struct icmp6hdr,
12315 + || !(type & ICMPV6_INFOMSG_MASK)) {
12319 + user_flags |= mip6node_cnf.bu_cn_ack ? MIPV6_BU_F_ACK : 0;
12320 + mipv6_get_care_of_address(&skb->nh.ipv6h->daddr, &coa);
12321 + lifetime = mipv6_mn_get_bulifetime(&skb->nh.ipv6h->daddr,
12324 + DEBUG(DBG_WARNING, "packet to address %x:%x:%x:%x:%x:%x:%x:%x"
12325 + "was tunneled. Sending BU to CN"
12326 + "%x:%x:%x:%x:%x:%x:%x:%x",
12327 + NIPV6ADDR(&skb->nh.ipv6h->daddr),
12328 + NIPV6ADDR(&skb->nh.ipv6h->saddr));
12329 + /* This should work also with home address option */
12331 + write_lock(&bul_lock);
12332 + mipv6_send_bu(&skb->nh.ipv6h->daddr, &skb->nh.ipv6h->saddr,
12333 + &coa, INITIAL_BINDACK_TIMEOUT,
12334 + MAX_BINDACK_TIMEOUT, 1, user_flags,
12336 + write_unlock(&bul_lock);
12340 +static int sched_mv_home_addr_task(struct in6_addr *haddr, int plen_new,
12341 + int newif, int oldif, struct handoff *ho)
12344 + struct ifr_holder *ifrh;
12346 + alloc_size = sizeof(*ifrh) + (ho ? sizeof(*ho): 0);
12347 + if ((ifrh = kmalloc(alloc_size, GFP_ATOMIC)) == NULL) {
12348 + DEBUG(DBG_ERROR, "Out of memory");
12352 + ifrh->ho = (struct handoff *)((struct ifr_holder *)(ifrh + 1));
12353 + memcpy(ifrh->ho, ho, sizeof(*ho));
12357 + /* must queue task to avoid deadlock with rtnl */
12358 + ifrh->ifr.ifr6_ifindex = newif;
12359 + ifrh->ifr.ifr6_prefixlen = plen_new;
12360 + ipv6_addr_copy(&ifrh->ifr.ifr6_addr, haddr);
12361 + ifrh->old_ifi = oldif;
12363 + spin_lock_bh(&ifrh_lock);
12364 + list_add_tail(&ifrh->list, &ifrh_list);
12365 + spin_unlock_bh(&ifrh_lock);
12367 + schedule_task(&mv_home_addr_task);
12372 +static void send_ret_home_ns(struct in6_addr *ha_addr,
12373 + struct in6_addr *home_addr,
12376 + struct in6_addr nil;
12377 + struct in6_addr mcaddr;
12378 + struct net_device *dev = dev_get_by_index(ifindex);
12381 + memset(&nil, 0, sizeof(nil));
12382 + addrconf_addr_solict_mult(home_addr, &mcaddr);
12383 + ndisc_send_ns(dev, NULL, home_addr, &mcaddr, &nil);
12387 +static inline int ha_is_reachable(int ifindex, struct in6_addr *ha)
12389 + struct net_device *dev;
12390 + int reachable = 0;
12392 + dev = dev_get_by_index(ifindex);
12394 + struct neighbour *neigh;
12395 + if ((neigh = ndisc_get_neigh(dev, ha)) != NULL) {
12396 + read_lock_bh(&neigh->lock);
12397 + if (neigh->nud_state&NUD_VALID)
12399 + read_unlock_bh(&neigh->lock);
12400 + neigh_release(neigh);
12404 + return reachable;
12407 +static int mn_ha_handoff(struct handoff *ho)
12409 + struct list_head *lh;
12410 + struct mn_info *minfo;
12411 + struct in6_addr *coa= ho->coa;
12412 + int wait_mv_home = 0;
12414 + read_lock_bh(&mn_info_lock);
12415 + list_for_each(lh, &mn_info_list) {
12416 + __u8 has_home_reg;
12418 + struct in6_addr ha;
12421 + struct mipv6_bul_entry *entry = NULL;
12423 + minfo = list_entry(lh, struct mn_info, list);
12424 + spin_lock(&minfo->lock);
12425 + has_home_reg = minfo->has_home_reg;
12426 + ifindex = minfo->ifindex;
12427 + ipv6_addr_copy(&ha, &minfo->ha);
12429 + if (mipv6_prefix_compare(&ho->rtr_addr, &minfo->home_addr,
12431 + if (minfo->has_home_reg)
12432 + athome = minfo->is_at_home = MN_RETURNING_HOME;
12434 + athome = minfo->is_at_home = MN_AT_HOME;
12435 + coa = &minfo->home_addr;
12437 + spin_unlock(&minfo->lock);
12439 + /* Cancel prefix solicitation, rtr is our HA */
12440 + mipv6_pfx_cancel_send(&ho->rtr_addr, ifindex);
12442 + minfo->ifindex = ho->ifindex;
12444 + if (minfo->has_home_reg &&
12445 + !ha_is_reachable(ho->ifindex, &minfo->ha)) {
12446 + send_ret_home_ns(&minfo->ha,
12447 + &minfo->home_addr,
12449 + mipv6_mdet_set_curr_rtr_reachable(0);
12452 + if (ifindex != ho->ifindex){
12455 + "Moving home address back to "
12456 + "the home interface");
12457 + sched_mv_home_addr_task(&minfo->home_addr,
12462 + if (!has_home_reg || wait_mv_home)
12468 + athome = minfo->is_at_home = MN_NOT_AT_HOME;
12469 + if (minfo->ifindex_user != minfo->ifindex) {
12470 + DEBUG(DBG_INFO, "Scheduling home address move to virtual interface");
12471 + sched_mv_home_addr_task(&minfo->home_addr,
12473 + minfo->ifindex_user,
12474 + minfo->ifindex, ho); /* Is minfo->ifindex correct */
12478 + minfo->ifindex = minfo->ifindex_user;
12479 + spin_unlock(&minfo->lock);
12480 + if (wait_mv_home)
12482 + if (!has_home_reg &&
12483 + init_home_registration(&minfo->home_addr,
12487 + lifetime = mipv6_mn_get_bulifetime(&minfo->home_addr,
12489 + MIPV6_BU_F_HOME);
12492 + write_lock(&bul_lock);
12493 + if (!(entry = mipv6_bul_get(&ha, &minfo->home_addr)) ||
12494 + !(entry->flags & MIPV6_BU_F_HOME)) {
12496 + "Unable to find home registration for "
12497 + "home address: %x:%x:%x:%x:%x:%x:%x:%x!\n",
12498 + NIPV6ADDR(&minfo->home_addr));
12499 + write_unlock(&bul_lock);
12502 + DEBUG(DBG_INFO, "Sending home de ? %d registration for "
12503 + "home address: %x:%x:%x:%x:%x:%x:%x:%x\n"
12504 + "to home agent %x:%x:%x:%x:%x:%x:%x:%x, "
12505 + "with lifetime %ld",
12506 + (athome != MN_NOT_AT_HOME),
12507 + NIPV6ADDR(&entry->home_addr),
12508 + NIPV6ADDR(&entry->cn_addr), lifetime);
12509 + mipv6_send_bu(&entry->home_addr, &entry->cn_addr,
12510 + coa, INITIAL_BINDACK_TIMEOUT,
12511 + MAX_BINDACK_TIMEOUT, 1, entry->flags,
12513 + write_unlock(&bul_lock);
12516 + read_unlock_bh(&mn_info_lock);
12517 + return wait_mv_home;
12520 + * mn_cn_handoff - called for every bul entry to send BU to CN
12521 + * @rawentry: bul entry
12522 + * @args: handoff event
12525 + * Since MN can have many home addresses and home networks, every BUL
12526 + * entry needs to be checked
12528 +int mn_cn_handoff(void *rawentry, void *args, unsigned long *sortkey)
12530 + struct mipv6_bul_entry *entry = (struct mipv6_bul_entry *)rawentry;
12531 + struct in6_addr *coa = (struct in6_addr *)args;
12535 + /* Home registrations already handled by mn_ha_handoff */
12536 + if (entry->flags & MIPV6_BU_F_HOME)
12537 + return ITERATOR_CONT;
12539 + /* BUL is locked by mipv6_mobile_node_moved which calls us
12540 + through mipv6_bul_iterate */
12542 + if (mipv6_prefix_compare(coa,
12543 + &entry->home_addr,
12545 + mipv6_send_bu(&entry->home_addr, &entry->cn_addr,
12546 + &entry->home_addr, INITIAL_BINDACK_TIMEOUT,
12547 + MAX_BINDACK_TIMEOUT, 1, entry->flags, 0,
12550 + u32 lifetime = mipv6_mn_get_bulifetime(&entry->home_addr,
12553 + mipv6_send_bu(&entry->home_addr, &entry->cn_addr,
12554 + coa, INITIAL_BINDACK_TIMEOUT,
12555 + MAX_BINDACK_TIMEOUT, 1, entry->flags,
12558 + return ITERATOR_CONT;
12562 +int mn_bul_invalidate(void *rawentry, void *args, unsigned long *sortkey)
12564 + struct mipv6_bul_entry *bul = (struct mipv6_bul_entry *)rawentry;
12565 + struct bul_inval_args *arg = (struct bul_inval_args *)args;
12569 + if (!ipv6_addr_cmp(arg->cn, &bul->cn_addr) &&
12570 + (!ipv6_addr_cmp(arg->mn, &bul->home_addr) ||
12571 + !ipv6_addr_cmp(arg->mn, &bul->coa))) {
12572 + if (arg->all_rr_states || !bul->rr ||
12573 + (bul->rr->rr_state != RR_INIT &&
12574 + bul->rr->rr_state != RR_DONE)) {
12575 + bul->state = ACK_ERROR;
12576 + bul->callback = bul_entry_expired;
12577 + bul->callback_time = jiffies +
12578 + DUMB_CN_BU_LIFETIME * HZ;
12579 + bul->expire = bul->callback_time;
12580 + DEBUG(DBG_INFO, "BUL entry set to ACK_ERROR");
12581 + mipv6_bul_reschedule(bul);
12584 + return ITERATOR_CONT;
12587 + * init_home_registration - start Home Registration process
12588 + * @home_addr: home address
12589 + * @coa: care-of address
12591 + * Checks whether we have a Home Agent address for this home address.
12592 + * If not starts Dynamic Home Agent Address Discovery. Otherwise
12593 + * tries to register with home agent if not already registered.
12594 + * Returns 1, if home registration process is started and 0 otherwise
12596 +int init_home_registration(struct in6_addr *home_addr, struct in6_addr *coa)
12598 + struct mn_info *hinfo;
12599 + struct in6_addr ha;
12603 + __u8 user_flags = 0, flags;
12607 + read_lock_bh(&mn_info_lock);
12608 + if ((hinfo = mipv6_mninfo_get_by_home(home_addr)) == NULL) {
12609 + DEBUG(DBG_ERROR, "No mn_info found for address: "
12610 + "%x:%x:%x:%x:%x:%x:%x:%x",
12611 + NIPV6ADDR(home_addr));
12612 + read_unlock_bh(&mn_info_lock);
12615 + spin_lock(&hinfo->lock);
12616 + if (mipv6_prefix_compare(&hinfo->home_addr, coa, hinfo->home_plen)) {
12617 + spin_unlock(&hinfo->lock);
12618 + read_unlock_bh(&mn_info_lock);
12619 + DEBUG(DBG_INFO, "Adding home address, MN at home");
12622 + if (ipv6_addr_any(&hinfo->ha)) {
12623 + int dhaad_id = mipv6_get_dhaad_id();
12624 + hinfo->dhaad_id = dhaad_id;
12625 + spin_unlock(&hinfo->lock);
12626 + mipv6_icmpv6_send_dhaad_req(home_addr, hinfo->home_plen, dhaad_id);
12627 + read_unlock_bh(&mn_info_lock);
12629 + "Home Agent address not set, initiating DHAAD");
12632 + ipv6_addr_copy(&ha, &hinfo->ha);
12633 + man_conf = hinfo->man_conf;
12634 + ifindex = hinfo->ifindex;
12635 + spin_unlock(&hinfo->lock);
12636 + read_unlock_bh(&mn_info_lock);
12639 + mipv6_pfx_add_ha(&ha, coa, ifindex);
12641 + if (mipv6_bul_exists(&ha, home_addr)) {
12642 + DEBUG(DBG_INFO, "BU already sent to HA");
12645 + /* user flags received through sysctl */
12646 + user_flags |= mip6node_cnf.bu_lladdr ? MIPV6_BU_F_LLADDR : 0;
12647 + user_flags |= mip6node_cnf.bu_keymgm ? MIPV6_BU_F_KEYMGM : 0;
12649 + flags = MIPV6_BU_F_HOME | MIPV6_BU_F_ACK | user_flags;
12651 + lifetime = mipv6_mn_get_bulifetime(home_addr, coa, flags);
12653 + DEBUG(DBG_INFO, "Sending initial home registration for "
12654 + "home address: %x:%x:%x:%x:%x:%x:%x:%x\n"
12655 + "to home agent %x:%x:%x:%x:%x:%x:%x:%x, "
12656 + "with lifetime %ld, prefixlength %d",
12657 + NIPV6ADDR(home_addr), NIPV6ADDR(&ha), lifetime, 0);
12659 + write_lock_bh(&bul_lock);
12660 + mipv6_send_bu(home_addr, &ha, coa, INITIAL_BINDACK_DAD_TIMEOUT,
12661 + MAX_BINDACK_TIMEOUT, 1, flags, lifetime, NULL);
12662 + write_unlock_bh(&bul_lock);
12668 + * mipv6_mobile_node_moved - Send BUs to all HAs and CNs
12669 + * @ho: handoff structure contains the new and previous routers
12671 + * Event for handoff. Sends BUs everyone on Binding Update List.
12673 +int mipv6_mobile_node_moved(struct handoff *ho)
12676 + int bu_to_prev_router = 1;
12682 + ma_ctl_upd_iface(ho->ifindex,
12683 + MA_IFACE_CURRENT | MA_IFACE_HAS_ROUTER, &dummy);
12685 + /* First send BU to HA, then to all other nodes that are on BU list */
12686 + if (mn_ha_handoff(ho) != 0)
12687 + return 0; /* Wait for move home address task */
12689 + /* Add current care-of address to mn_info list, if current router acts
12692 + if (ho->home_address && bu_to_prev_router)
12693 + mipv6_mninfo_add(ho->coa, ho->plen,
12694 + MN_AT_HOME, 0, &ho->rtr_addr,
12695 + ho->plen, ROUTER_BU_DEF_LIFETIME,
12703 + * mipv6_mn_send_home_na - send NA when returning home
12704 + * @haddr: home address to advertise
12706 + * After returning home, MN must advertise all its valid addresses in
12707 + * home link to all nodes.
12709 +void mipv6_mn_send_home_na(struct in6_addr *haddr)
12711 + struct net_device *dev = NULL;
12712 + struct in6_addr mc_allnodes;
12713 + struct mn_info *hinfo = NULL;
12715 + read_lock(&mn_info_lock);
12716 + hinfo = mipv6_mninfo_get_by_home(haddr);
12718 + read_unlock(&mn_info_lock);
12721 + spin_lock(&hinfo->lock);
12722 + hinfo->is_at_home = MN_AT_HOME;
12723 + dev = dev_get_by_index(hinfo->ifindex);
12724 + spin_unlock(&hinfo->lock);
12725 + read_unlock(&mn_info_lock);
12726 + if (dev == NULL) {
12727 + DEBUG(DBG_ERROR, "Send home_na: device not found.");
12731 + ipv6_addr_all_nodes(&mc_allnodes);
12732 + ndisc_send_na(dev, NULL, &mc_allnodes, haddr, 0, 0, 1, 1);
12736 +static int mn_use_hao(struct in6_addr *daddr, struct in6_addr *saddr)
12738 + struct mipv6_bul_entry *entry;
12739 + struct mn_info *minfo = NULL;
12742 + read_lock_bh(&mn_info_lock);
12743 + minfo = mipv6_mninfo_get_by_home(saddr);
12744 + if (minfo && minfo->is_at_home != MN_AT_HOME) {
12745 + read_lock_bh(&bul_lock);
12746 + if ((entry = mipv6_bul_get(daddr, saddr)) == NULL) {
12747 + read_unlock_bh(&bul_lock);
12748 + read_unlock_bh(&mn_info_lock);
12751 + add_ha = (entry->state != ACK_ERROR &&
12752 + (!entry->rr || entry->rr->rr_state == RR_DONE ||
12753 + entry->flags & MIPV6_BU_F_HOME));
12754 + read_unlock_bh(&bul_lock);
12756 + read_unlock_bh(&mn_info_lock);
12761 +mn_dev_event(struct notifier_block *nb, unsigned long event, void *ptr)
12763 + struct net_device *dev = ptr;
12764 + struct list_head *lh;
12765 + struct mn_info *minfo;
12768 + /* here are probably the events we need to worry about */
12771 + DEBUG(DBG_DATADUMP, "New netdevice %s registered.", dev->name);
12772 + if (dev->type != ARPHRD_LOOPBACK && !dev_is_mip6_tnl(dev))
12773 + ma_ctl_add_iface(dev->ifindex);
12776 + case NETDEV_GOING_DOWN:
12777 + DEBUG(DBG_DATADUMP, "Netdevice %s disappeared.", dev->name);
12779 + * Go through mn_info list and move all home addresses on the
12780 + * netdev going down to a new device. This will make it
12781 + * practically impossible for the home address to return home,
12782 + * but allow MN to retain its connections using the address.
12785 + read_lock_bh(&mn_info_lock);
12786 + list_for_each(lh, &mn_info_list) {
12787 + minfo = list_entry(lh, struct mn_info, list);
12788 + spin_lock(&minfo->lock);
12789 + if (minfo->ifindex == dev->ifindex) {
12790 + if (sched_mv_home_addr_task(&minfo->home_addr, 128,
12791 + minfo->ifindex_user,
12793 + minfo->ifindex = 0;
12794 + spin_unlock(&minfo->lock);
12795 + read_unlock_bh(&mn_info_lock);
12796 + return NOTIFY_DONE;
12798 + minfo->ifindex = minfo->ifindex_user;
12799 + if (minfo->is_at_home) {
12800 + minfo->is_at_home = 0;
12803 + newif = minfo->ifindex_user;
12806 + spin_unlock(&minfo->lock);
12809 + read_unlock_bh(&mn_info_lock);
12811 + ma_ctl_upd_iface(dev->ifindex, MA_IFACE_NOT_PRESENT, &newif);
12812 + mipv6_mdet_del_if(dev->ifindex);
12814 + return NOTIFY_DONE;
12817 +struct notifier_block mipv6_mn_dev_notifier = {
12820 + 0 /* check if using zero is ok */
12823 +static void deprecate_addr(struct mn_info *minfo)
12826 + * Lookup address from IPv6 address list and set deprecated flag
12832 + * Required because we can only modify addresses after the packet is
12833 + * constructed. We otherwise mess with higher level protocol
12834 + * pseudoheaders. With strict protocol layering life would be SO much
12837 +static unsigned int modify_xmit_addrs(unsigned int hooknum,
12838 + struct sk_buff **pskb,
12839 + const struct net_device *in,
12840 + const struct net_device *out,
12841 + int (*okfn) (struct sk_buff *))
12843 + struct sk_buff *skb = *pskb;
12848 + struct ipv6hdr *hdr = skb->nh.ipv6h;
12849 + struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
12850 + struct mipv6_bul_entry *bule;
12851 + struct in6_addr *daddr;
12853 + if (!ipv6_addr_any(&opt->hoa))
12854 + daddr = &opt->hoa;
12856 + daddr = &hdr->daddr;
12858 + /* We don't consult bul when sending a BU to avoid deadlock, since
12859 + * BUL is already locked.
12863 + if (opt->mipv6_flags & MIPV6_SND_HAO &&
12864 + !(opt->mipv6_flags & MIPV6_SND_BU)) {
12865 + write_lock(&bul_lock);
12866 + bule = mipv6_bul_get(daddr, &hdr->saddr);
12868 + write_unlock(&bul_lock);
12869 + return NF_ACCEPT;
12871 + if (!bule->rr || bule->rr->rr_state == RR_DONE ||
12872 + bule->flags & MIPV6_BU_F_HOME) {
12873 + DEBUG(DBG_DATADUMP,
12874 + "Replace source address with CoA and reroute");
12875 + ipv6_addr_copy(&hdr->saddr, &bule->coa);
12876 + skb->nfcache |= NFC_ALTERED;
12878 + write_unlock(&bul_lock);
12879 + } else if (opt->mipv6_flags & MIPV6_SND_HAO) {
12880 + mipv6_get_care_of_address(&hdr->saddr, &hdr->saddr);
12881 + skb->nfcache |= NFC_ALTERED;
12884 + return NF_ACCEPT;
12887 +/* We set a netfilter hook so that we can modify outgoing packet's
12888 + * source addresses
12890 +struct nf_hook_ops addr_modify_hook_ops = {
12891 + {NULL, NULL}, /* List head, no predecessor, no successor */
12892 + modify_xmit_addrs,
12894 + NF_IP6_LOCAL_OUT,
12895 + NF_IP6_PRI_FIRST /* Should be of EXTREMELY high priority since we
12896 + * do not want to mess with IPSec (possibly
12897 + * implemented as packet filter)
12901 +#define MN_INFO_LEN 77
12903 +static int mn_proc_info(char *buffer, char **start, off_t offset,
12906 + struct list_head *p;
12907 + struct mn_info *minfo;
12908 + int len = 0, skip = 0;
12912 + read_lock_bh(&mn_info_lock);
12913 + list_for_each(p, &mn_info_list) {
12914 + if (len < offset / MN_INFO_LEN) {
12918 + if (len >= length)
12920 + minfo = list_entry(p, struct mn_info, list);
12921 + spin_lock(&minfo->lock);
12922 + len += sprintf(buffer + len, "%02d %08x%08x%08x%08x %02x "
12923 + "%08x%08x%08x%08x %d %d\n",
12925 + ntohl(minfo->home_addr.s6_addr32[0]),
12926 + ntohl(minfo->home_addr.s6_addr32[1]),
12927 + ntohl(minfo->home_addr.s6_addr32[2]),
12928 + ntohl(minfo->home_addr.s6_addr32[3]),
12929 + minfo->home_plen,
12930 + ntohl(minfo->ha.s6_addr32[0]),
12931 + ntohl(minfo->ha.s6_addr32[1]),
12932 + ntohl(minfo->ha.s6_addr32[2]),
12933 + ntohl(minfo->ha.s6_addr32[3]),
12934 + minfo->is_at_home, minfo->has_home_reg);
12935 + spin_unlock(&minfo->lock);
12937 + read_unlock_bh(&mn_info_lock);
12941 + *start += offset % MN_INFO_LEN;
12943 + len -= offset % MN_INFO_LEN;
12945 + if (len > length)
12953 +int mipv6_mn_ha_nd_update(struct net_device *dev,
12954 + struct in6_addr *ha, u8 *lladdr)
12957 + struct neighbour *neigh;
12958 + if ((neigh = ndisc_get_neigh(dev, ha))) {
12959 + read_lock(&neigh->lock);
12960 + valid = neigh->nud_state & NUD_VALID;
12961 + read_unlock(&neigh->lock);
12962 + if (!valid && lladdr)
12963 + neigh_update(neigh, lladdr, NUD_REACHABLE, 0, 1);
12964 + neigh_release(neigh);
12969 +int mipv6_mn_ha_probe(struct inet6_ifaddr *ifp, u8 *lladdr)
12971 + struct mn_info *minfo;
12973 + if (!(minfo = mipv6_mninfo_get_by_home(&ifp->addr)) ||
12974 + ipv6_addr_any(&minfo->ha))
12977 + if (mipv6_mn_ha_nd_update(ifp->idev->dev, &minfo->ha, lladdr))
12978 + mipv6_mdet_retrigger_ho();
12982 +int __init mipv6_mn_init(void)
12984 + struct net_device *dev;
12988 + if (mipv6_add_tnl_to_ha())
12991 + mipv6_bul_init(MIPV6_BUL_SIZE);
12992 + mip6_fn.mn_use_hao = mn_use_hao;
12993 + mip6_fn.mn_check_tunneled_packet = mn_check_tunneled_packet;
12994 + INIT_TQUEUE(&mv_home_addr_task, mv_home_addr, NULL);
12997 + for (dev = dev_base; dev; dev = dev->next) {
12998 + if (dev->flags & IFF_UP &&
12999 + dev->type != ARPHRD_LOOPBACK && !dev_is_mip6_tnl(dev)) {
13000 + ma_ctl_add_iface(dev->ifindex);
13003 + DEBUG(DBG_INFO, "Multiaccess support initialized");
13005 + register_netdevice_notifier(&mipv6_mn_dev_notifier);
13006 + register_inet6addr_notifier(&mipv6_mn_inet6addr_notifier);
13008 + ip6ip6_tnl_register_hook(&mipv6_mn_tnl_rcv_send_bu_ops);
13009 + ip6ip6_tnl_register_hook(&mipv6_mn_tnl_xmit_stats_ops);
13010 + ip6ip6_tnl_register_hook(&mipv6_mn_tnl_rcv_stats_ops);
13012 + MIPV6_SETCALL(mipv6_set_home, mipv6_mn_set_home);
13014 + mipv6_initialize_mdetect();
13016 + /* COA to home transformation hook */
13017 + MIPV6_SETCALL(mipv6_get_home_address, mipv6_get_saddr_hook);
13018 + MIPV6_SETCALL(mipv6_mn_ha_probe, mipv6_mn_ha_probe);
13019 + MIPV6_SETCALL(mipv6_is_home_addr, mipv6_mn_is_home_addr);
13020 + proc_net_create("mip6_mninfo", 0, mn_proc_info);
13021 + /* Set packet modification hook (source addresses) */
13022 + nf_register_hook(&addr_modify_hook_ops);
13027 +void __exit mipv6_mn_exit(void)
13029 + struct list_head *lh, *tmp;
13030 + struct mn_info *minfo;
13033 + mip6_fn.mn_use_hao = NULL;
13034 + mip6_fn.mn_check_tunneled_packet = NULL;
13036 + MIPV6_RESETCALL(mipv6_set_home);
13037 + MIPV6_RESETCALL(mipv6_get_home_address);
13038 + MIPV6_RESETCALL(mipv6_mn_ha_probe);
13039 + MIPV6_RESETCALL(mipv6_is_home_addr);
13040 + nf_unregister_hook(&addr_modify_hook_ops);
13041 + proc_net_remove("mip6_mninfo");
13042 + mipv6_shutdown_mdetect();
13043 + ip6ip6_tnl_unregister_hook(&mipv6_mn_tnl_rcv_stats_ops);
13044 + ip6ip6_tnl_unregister_hook(&mipv6_mn_tnl_xmit_stats_ops);
13045 + ip6ip6_tnl_unregister_hook(&mipv6_mn_tnl_rcv_send_bu_ops);
13048 + unregister_inet6addr_notifier(&mipv6_mn_inet6addr_notifier);
13049 + unregister_netdevice_notifier(&mipv6_mn_dev_notifier);
13050 + write_lock_bh(&mn_info_lock);
13052 + list_for_each_safe(lh, tmp, &mn_info_list) {
13053 + minfo = list_entry(lh, struct mn_info, list);
13054 + if (minfo->is_at_home == MN_NOT_AT_HOME)
13055 + deprecate_addr(minfo);
13056 + list_del(&minfo->list);
13059 + write_unlock_bh(&mn_info_lock);
13060 + mipv6_bul_exit();
13061 + flush_scheduled_tasks();
13062 + mipv6_del_tnl_to_ha();
13065 +++ linux-2.4.27/net/ipv6/mobile_ip6/mn.h
13068 + * MIPL Mobile IPv6 Mobile Node header file
13072 + * This program is free software; you can redistribute it and/or
13073 + * modify it under the terms of the GNU General Public License
13074 + * as published by the Free Software Foundation; either version
13075 + * 2 of the License, or (at your option) any later version.
13081 +#include <linux/in6.h>
13083 +/* constants for sending of BUs*/
13084 +#define HA_BU_DEF_LIFETIME 10000
13085 +#define CN_BU_DEF_LIFETIME 420 /* Max lifetime for RR bindings from RFC 3775 */
13086 +#define DUMB_CN_BU_LIFETIME 600 /* BUL entry lifetime in case of dumb CN */
13087 +#define ROUTER_BU_DEF_LIFETIME 30 /* For packet forwarding from previous coa */
13088 +#define ERROR_DEF_LIFETIME DUMB_CN_BU_LIFETIME
13090 +extern rwlock_t mn_info_lock;
13092 +#define MN_NOT_AT_HOME 0
13093 +#define MN_RETURNING_HOME 1
13094 +#define MN_AT_HOME 2
13097 + * Mobile Node information record
13100 + struct in6_addr home_addr;
13101 + struct in6_addr ha;
13104 + __u8 has_home_reg;
13107 + int ifindex_user;
13108 + unsigned long home_addr_expires;
13109 + unsigned short dhaad_id;
13110 + struct list_head list;
13114 +/* prototypes for interface functions */
13115 +int mipv6_mn_init(void);
13116 +void mipv6_mn_exit(void);
13120 +/* Interface to movement detection */
13121 +int mipv6_mobile_node_moved(struct handoff *ho);
13123 +void mipv6_mn_send_home_na(struct in6_addr *haddr);
13124 +/* Init home reg. with coa */
13125 +int init_home_registration(struct in6_addr *home_addr, struct in6_addr *coa);
13127 +/* mn_info functions that require locking by caller */
13128 +struct mn_info *mipv6_mninfo_get_by_home(struct in6_addr *haddr);
13130 +struct mn_info *mipv6_mninfo_get_by_ha(struct in6_addr *home_agent);
13132 +struct mn_info *mipv6_mninfo_get_by_id(unsigned short id);
13134 +/* "safe" mn_info functions */
13135 +void mipv6_mninfo_add(int ifindex, struct in6_addr *home_addr, int plen,
13136 + int isathome, unsigned long lifetime, struct in6_addr *ha,
13137 + int ha_plen, unsigned long ha_lifetime, int man_conf);
13139 +int mipv6_mninfo_del(struct in6_addr *home_addr, int del_dyn_only);
13141 +void mipv6_mn_set_home_reg(struct in6_addr *home_addr, int has_home_reg);
13143 +int mipv6_mn_is_at_home(struct in6_addr *addr);
13145 +int mipv6_mn_is_home_addr(struct in6_addr *addr);
13147 +__u32 mipv6_mn_get_bulifetime(struct in6_addr *home_addr,
13148 + struct in6_addr *coa, __u8 flags);
13149 +int mn_cn_handoff(void *rawentry, void *args, unsigned long *sortkey);
13151 +int mipv6_mn_ha_nd_update(struct net_device *dev,
13152 + struct in6_addr *ha, u8 *lladdr);
13154 +struct bul_inval_args {
13155 + int all_rr_states;
13156 + struct in6_addr *cn;
13157 + struct in6_addr *mn;
13160 +int mn_bul_invalidate(void *rawentry, void *args, unsigned long *sortkey);
13162 +#endif /* _MN_H */
13164 +++ linux-2.4.27/net/ipv6/mobile_ip6/mobhdr.h
13167 + * MIPL Mobile IPv6 Mobility Header send and receive
13171 + * This program is free software; you can redistribute it and/or
13172 + * modify it under the terms of the GNU General Public License
13173 + * as published by the Free Software Foundation; either version
13174 + * 2 of the License, or (at your option) any later version.
13180 +#include <net/mipv6.h>
13182 +/* RR states for mipv6_send_bu() */
13183 +#define RR_INIT 0x00
13184 +#define RR_WAITH 0x01
13185 +#define RR_WAITC 0x02
13186 +#define RR_WAITHC 0x13
13187 +#define RR_DONE 0x10
13189 +#define MH_UNKNOWN_CN 1
13190 +#define MH_AUTH_FAILED 2
13191 +#define MH_SEQUENCE_MISMATCH 3
13193 +struct mipv6_bul_entry;
13196 +int mipv6_mh_common_init(void);
13197 +void mipv6_mh_common_exit(void);
13198 +int mipv6_mh_mn_init(void);
13199 +void mipv6_mh_mn_exit(void);
13201 +struct mipv6_mh_opt {
13202 + struct mipv6_mo_alt_coa *alt_coa;
13203 + struct mipv6_mo_nonce_indices *nonce_indices;
13204 + struct mipv6_mo_bauth_data *auth_data;
13205 + struct mipv6_mo_br_advice *br_advice;
13213 + struct mipv6_mo_alt_coa *alt_coa;
13214 + struct mipv6_mo_nonce_indices *nonce_indices;
13215 + struct mipv6_mo_bauth_data *auth_data;
13216 + struct mipv6_mo_br_advice *br_advice;
13219 +struct mipv6_mh_opt *alloc_mh_opts(int totlen);
13220 +int append_mh_opt(struct mipv6_mh_opt *ops, u8 type, u8 len, void *data);
13221 +int parse_mo_tlv(void *mos, int len, struct mobopt *opts);
13222 +int mipv6_add_pad(u8 *data, int n);
13224 +struct mipv6_auth_parm {
13225 + struct in6_addr *coa;
13226 + struct in6_addr *cn_addr;
13230 +int send_mh(struct in6_addr *daddr, struct in6_addr *saddr,
13231 + u8 msg_type, u8 msg_len, u8 *msg,
13232 + struct in6_addr *hao_addr, struct in6_addr *rth_addr,
13233 + struct mipv6_mh_opt *ops, struct mipv6_auth_parm *parm);
13235 +int mipv6_mh_register(int type, int (*func)(struct sk_buff *,
13236 + struct in6_addr *, struct in6_addr *,
13237 + struct in6_addr *, struct in6_addr *, struct mipv6_mh *));
13239 +void mipv6_mh_unregister(int type);
13241 +int mipv6_send_brr(struct in6_addr *saddr, struct in6_addr *daddr,
13242 + struct mipv6_mh_opt *ops);
13244 +int mipv6_send_bu(struct in6_addr *saddr, struct in6_addr *daddr,
13245 + struct in6_addr *coa, __u32 initdelay,
13246 + __u32 maxackdelay, __u8 exp, __u8 flags,
13247 + __u32 lifetime, struct mipv6_mh_opt *ops);
13249 +int mipv6_send_be(struct in6_addr *saddr, struct in6_addr *daddr,
13250 + struct in6_addr *home, __u8 status);
13252 +int mipv6_send_ba(struct in6_addr *saddr, struct in6_addr *daddr,
13253 + struct in6_addr *auth_coa, struct in6_addr *rep_coa,
13254 + u8 status, u16 sequence, u32 lifetime, u8 *k_bu);
13256 +/* Binding Authentication Data Option routines */
13257 +#define MAX_HASH_LENGTH 20
13258 +#define MIPV6_RR_MAC_LENGTH 12
13260 +int mipv6_auth_build(struct in6_addr *cn_addr, struct in6_addr *coa,
13261 + __u8 *opt, __u8 *aud_data, __u8 *k_bu);
13263 +int mipv6_auth_check(struct in6_addr *cn_addr, struct in6_addr *coa,
13264 + __u8 *opt, __u8 optlen, struct mipv6_mo_bauth_data *aud,
13266 +#endif /* _MOBHDR_H */
13268 +++ linux-2.4.27/net/ipv6/mobile_ip6/mobhdr_common.c
13271 + * Mobile IPv6 Mobility Header Common Functions
13274 + * Antti Tuominen <ajtuomin@tml.hut.fi>
13276 + * $Id: s.mh_recv.c 1.159 02/10/16 15:01:29+03:00 antti@traci.mipl.mediapoli.com $
13278 + * This program is free software; you can redistribute it and/or
13279 + * modify it under the terms of the GNU General Public License
13280 + * as published by the Free Software Foundation; either version
13281 + * 2 of the License, or (at your option) any later version.
13285 +#include <linux/autoconf.h>
13286 +#include <linux/types.h>
13287 +#include <linux/in6.h>
13288 +#include <linux/skbuff.h>
13289 +#include <linux/ipsec.h>
13290 +#include <linux/init.h>
13291 +#include <net/ipv6.h>
13292 +#include <net/ip6_route.h>
13293 +#include <net/addrconf.h>
13294 +#include <net/mipv6.h>
13295 +#include <net/checksum.h>
13296 +#include <net/protocol.h>
13298 +#include "stats.h"
13299 +#include "debug.h"
13300 +#include "mobhdr.h"
13301 +#include "bcache.h"
13303 +#include "rr_crypto.h"
13304 +#include "exthdrs.h"
13305 +#include "config.h"
13307 +#define MIPV6_MH_MAX MIPV6_MH_BE
13309 + int (*func) (struct sk_buff *,
13310 + struct in6_addr *, struct in6_addr *,
13311 + struct in6_addr *, struct in6_addr *,
13312 + struct mipv6_mh *);
13315 +static struct mh_proto mh_rcv[MIPV6_MH_MAX];
13317 +int mipv6_mh_register(int type, int (*func)(struct sk_buff *,
13318 + struct in6_addr *, struct in6_addr *,
13319 + struct in6_addr *, struct in6_addr *, struct mipv6_mh *))
13321 + if (mh_rcv[type].func != NULL)
13324 + mh_rcv[type].func = func;
13329 +void mipv6_mh_unregister(int type)
13331 + if (type < 0 || type > MIPV6_MH_MAX)
13334 + mh_rcv[type].func = NULL;
13337 +struct socket *mipv6_mh_socket = NULL;
13339 +/* TODO: Fix fragmentation */
13340 +static int dstopts_getfrag(
13341 + const void *data, struct in6_addr *addr,
13342 + char *buff, unsigned int offset, unsigned int len)
13344 + memcpy(buff, data + offset, len);
13348 +struct mipv6_mh_opt *alloc_mh_opts(int totlen)
13350 + struct mipv6_mh_opt *ops;
13352 + ops = kmalloc(sizeof(*ops) + totlen, GFP_ATOMIC);
13356 + memset(ops, 0, sizeof(*ops));
13357 + ops->next_free = ops->data;
13358 + ops->freelen = totlen;
13363 +int append_mh_opt(struct mipv6_mh_opt *ops, u8 type, u8 len, void *data)
13365 + struct mipv6_mo *mo;
13367 + if (ops->next_free == NULL) {
13368 + DEBUG(DBG_ERROR, "No free room for option");
13371 + if (ops->freelen < len + 2) {
13372 + DEBUG(DBG_ERROR, "No free room for option");
13376 + ops->freelen -= (len + 2);
13377 + ops->totlen += (len + 2);
13380 + mo = (struct mipv6_mo *)ops->next_free;
13382 + mo->length = len;
13385 + case MIPV6_OPT_ALTERNATE_COA:
13386 + ops->alt_coa = (struct mipv6_mo_alt_coa *)mo;
13387 + ipv6_addr_copy(&ops->alt_coa->addr, (struct in6_addr *)data);
13389 + case MIPV6_OPT_NONCE_INDICES:
13390 + DEBUG(DBG_INFO, "Added nonce indices pointer");
13391 + ops->nonce_indices = (struct mipv6_mo_nonce_indices *)mo;
13392 + ops->nonce_indices->home_nonce_i = *(__u16 *)data;
13393 + ops->nonce_indices->careof_nonce_i = *((__u16 *)data + 1);
13395 + case MIPV6_OPT_AUTH_DATA:
13396 + DEBUG(DBG_INFO, "Added opt auth_data pointer");
13397 + ops->auth_data = (struct mipv6_mo_bauth_data *)mo;
13399 + case MIPV6_OPT_BIND_REFRESH_ADVICE:
13400 + ops->br_advice = (struct mipv6_mo_br_advice *)mo;
13401 + ops->br_advice->refresh_interval = htons(*(u16 *)data);
13404 + DEBUG(DBG_ERROR, "Unknow option type");
13408 + if (ops->freelen == 0)
13409 + ops->next_free = NULL;
13411 + ops->next_free += (len + 2);
13417 + * Calculates required padding with xn + y requirement with offset
13419 +static inline int optpad(int xn, int y, int offset)
13421 + return ((y - offset) & (xn - 1));
13424 +static int option_pad(int type, int offset)
13426 + if (type == MIPV6_OPT_ALTERNATE_COA)
13427 + return optpad(8, 6, offset); /* 8n + 6 */
13428 + if (type == MIPV6_OPT_BIND_REFRESH_ADVICE ||
13429 + type == MIPV6_OPT_NONCE_INDICES)
13430 + return optpad(2, 0, offset); /* 2n */
13435 + * Add Pad1 or PadN option to data
13437 +int mipv6_add_pad(u8 *data, int n)
13439 + struct mipv6_mo_padn *padn;
13441 + if (n <= 0) return 0;
13443 + *data = MIPV6_OPT_PAD1;
13446 + padn = (struct mipv6_mo_padn *)data;
13447 + padn->type = MIPV6_OPT_PADN;
13448 + padn->length = n - 2;
13449 + memset(padn->data, 0, n - 2);
13454 + * Write options to mobility header buffer
13456 +static int prepare_mh_opts(u8 *optdata, int off, struct mipv6_mh_opt *ops)
13458 + u8 *nextopt = optdata;
13459 + int offset = off, pad = 0;
13461 + if (ops == NULL) {
13466 + if (ops->alt_coa) {
13467 + pad = option_pad(MIPV6_OPT_ALTERNATE_COA, offset);
13468 + nextopt += mipv6_add_pad(nextopt, pad);
13469 + memcpy(nextopt, ops->alt_coa, sizeof(struct mipv6_mo_alt_coa));
13470 + nextopt += sizeof(struct mipv6_mo_alt_coa);
13471 + offset += pad + sizeof(struct mipv6_mo_alt_coa);
13474 + if (ops->br_advice) {
13475 + pad = option_pad(MIPV6_OPT_BIND_REFRESH_ADVICE, offset);
13476 + nextopt += mipv6_add_pad(nextopt, pad);
13477 + memcpy(nextopt, ops->br_advice, sizeof(struct mipv6_mo_br_advice));
13478 + nextopt += sizeof(struct mipv6_mo_br_advice);
13479 + offset += pad + sizeof(struct mipv6_mo_br_advice);
13482 + if (ops->nonce_indices) {
13483 + pad = option_pad(MIPV6_OPT_NONCE_INDICES, offset);
13484 + nextopt += mipv6_add_pad(nextopt, pad);
13485 + memcpy(nextopt, ops->nonce_indices, sizeof(struct mipv6_mo_nonce_indices));
13486 + nextopt += sizeof(struct mipv6_mo_nonce_indices);
13487 + offset += pad + sizeof(struct mipv6_mo_nonce_indices);
13490 + if (ops->auth_data) {
13491 + /* This option should always be the last. Header
13492 + * length must be a multiple of 8 octects, so we pad
13493 + * if necessary. */
13494 + pad = optpad(8, 0, offset + ops->auth_data->length + 2);
13495 + nextopt += mipv6_add_pad(nextopt, pad);
13496 + memcpy(nextopt, ops->auth_data, ops->auth_data->length + 2);
13497 + nextopt += ops->auth_data->length + 2;
13504 +static int calculate_mh_opts(struct mipv6_mh_opt *ops, int mh_len)
13506 + int offset = mh_len;
13511 + if (ops->alt_coa)
13512 + offset += sizeof(struct mipv6_mo_alt_coa)
13513 + + option_pad(MIPV6_OPT_ALTERNATE_COA, offset);
13515 + if (ops->br_advice)
13516 + offset += sizeof(struct mipv6_mo_br_advice)
13517 + + option_pad(MIPV6_OPT_BIND_REFRESH_ADVICE, offset);
13519 + if (ops->nonce_indices)
13520 + offset += sizeof(struct mipv6_mo_nonce_indices)
13521 + + option_pad(MIPV6_OPT_NONCE_INDICES, offset);
13523 + if (ops->auth_data) /* no alignment */
13524 + offset += ops->auth_data->length + 2;
13526 + return offset - mh_len;
13531 + * Mobility Header Message send functions
13536 + * send_mh - builds and sends a MH msg
13538 + * @daddr: destination address for packet
13539 + * @saddr: source address for packet
13540 + * @msg_type: type of MH
13541 + * @msg_len: message length
13542 + * @msg: MH type specific data
13543 + * @hao_addr: home address for home address option
13544 + * @rth_addr: routing header address
13545 + * @ops: mobility options
13546 + * @parm: auth data
13548 + * Builds MH, appends the type specific msg data to the header and
13549 + * sends the packet with a home address option, if a home address was
13550 + * given. Returns 0, if everything succeeded and a negative error code
13553 +int send_mh(struct in6_addr *daddr,
13554 + struct in6_addr *saddr,
13555 + u8 msg_type, u8 msg_len, u8 *msg,
13556 + struct in6_addr *hao_addr,
13557 + struct in6_addr *rth_addr,
13558 + struct mipv6_mh_opt *ops,
13559 + struct mipv6_auth_parm *parm)
13562 + struct mipv6_mh *mh;
13563 + struct sock *sk = mipv6_mh_socket->sk;
13564 + struct ipv6_txoptions *txopt = NULL;
13565 + int tot_len = sizeof(struct mipv6_mh) + msg_len;
13566 + int padded_len = 0, txopt_len = 0;
13569 + /* Add length of options */
13570 + tot_len += calculate_mh_opts(ops, tot_len);
13571 + /* Needs to be a multiple of 8 octets */
13572 + padded_len = tot_len + optpad(8, 0, tot_len);
13574 + mh = sock_kmalloc(sk, padded_len, GFP_ATOMIC);
13576 + DEBUG(DBG_ERROR, "memory allocation failed");
13580 + memset(&fl, 0, sizeof(fl));
13581 + fl.proto = IPPROTO_MOBILITY;
13582 + fl.fl6_dst = daddr;
13583 + fl.fl6_src = saddr;
13584 + fl.fl6_flowlabel = 0;
13585 + fl.oif = sk->bound_dev_if;
13587 + if (hao_addr || rth_addr) {
13591 + txopt_len += sizeof(struct mipv6_dstopt_homeaddr) + 6;
13593 + txopt_len += sizeof(struct rt2_hdr);
13595 + txopt_len += sizeof(*txopt);
13596 + txopt = sock_kmalloc(sk, txopt_len, GFP_ATOMIC);
13597 + if (txopt == NULL) {
13598 + DEBUG(DBG_ERROR, "No socket space left");
13599 + sock_kfree_s(sk, mh, padded_len);
13602 + memset(txopt, 0, txopt_len);
13603 + txopt->tot_len = txopt_len;
13604 + opt_ptr = (__u8 *) (txopt + 1);
13606 + int holen = sizeof(struct mipv6_dstopt_homeaddr) + 6;
13607 + txopt->dst1opt = (struct ipv6_opt_hdr *) opt_ptr;
13608 + txopt->opt_flen += holen;
13609 + opt_ptr += holen;
13610 + mipv6_append_dst1opts(txopt->dst1opt, saddr,
13612 + txopt->mipv6_flags = MIPV6_SND_HAO | MIPV6_SND_BU;
13615 + int rtlen = sizeof(struct rt2_hdr);
13616 + txopt->srcrt2 = (struct ipv6_rt_hdr *) opt_ptr;
13617 + txopt->opt_nflen += rtlen;
13618 + opt_ptr += rtlen;
13619 + mipv6_append_rt2hdr(txopt->srcrt2, rth_addr);
13623 + /* Fill in the fields of MH */
13624 + mh->payload = NEXTHDR_NONE;
13625 + mh->length = (padded_len >> 3) - 1; /* Units of 8 octets - 1 */
13626 + mh->type = msg_type;
13627 + mh->reserved = 0;
13628 + mh->checksum = 0;
13630 + memcpy(mh->data, msg, msg_len);
13631 + prepare_mh_opts(mh->data + msg_len, msg_len + sizeof(*mh), ops);
13632 + /* If BAD is present, this is already done. */
13633 + mipv6_add_pad((u8 *)mh + tot_len, padded_len - tot_len);
13635 + if (parm && parm->k_bu && ops && ops->auth_data) {
13636 + /* Calculate the position of the authorization data before adding checksum*/
13637 + mipv6_auth_build(parm->cn_addr, parm->coa, (__u8 *)mh,
13638 + (__u8 *)mh + padded_len - MIPV6_RR_MAC_LENGTH, parm->k_bu);
13640 + /* Calculate the MH checksum */
13641 + mh->checksum = csum_ipv6_magic(fl.fl6_src, fl.fl6_dst,
13642 + padded_len, IPPROTO_MOBILITY,
13643 + csum_partial((char *)mh, padded_len, 0));
13644 + ip6_build_xmit(sk, dstopts_getfrag, mh, &fl, padded_len, txopt, 255,
13646 + /* dst cache must be cleared so RR messages can be routed through
13647 + different interfaces */
13648 + sk_dst_reset(sk);
13651 + sock_kfree_s(sk, txopt, txopt_len);
13652 + sock_kfree_s(sk, mh, padded_len);
13657 + * mipv6_send_brr - send a Binding Refresh Request
13658 + * @saddr: source address for BRR
13659 + * @daddr: destination address for BRR
13660 + * @ops: mobility options
13662 + * Sends a binding request. On a mobile node, use the mobile node's
13663 + * home address for @saddr. Returns 0 on success, negative on
13666 +int mipv6_send_brr(struct in6_addr *saddr, struct in6_addr *daddr,
13667 + struct mipv6_mh_opt *ops)
13669 + struct mipv6_mh_brr br;
13671 + memset(&br, 0, sizeof(br));
13672 + /* We don't need to explicitly add a RH to brr, since it will be
13673 + * included automatically, if a BCE exists
13675 + MIPV6_INC_STATS(n_brr_sent);
13676 + return send_mh(daddr, saddr, MIPV6_MH_BRR, sizeof(br), (u8 *)&br,
13677 + NULL, NULL, ops, NULL);
13681 + * mipv6_send_ba - send a Binding Acknowledgement
13682 + * @saddr: source address for BA
13683 + * @daddr: destination address for BA
13684 + * @reply_coa: destination care-of address of MN
13685 + * @auth_coa: care-of address of MN used for authentication
13686 + * @status: status field value
13687 + * @sequence: sequence number from BU
13688 + * @lifetime: granted lifetime for binding in seconds
13689 + * @ops: mobility options
13691 + * Send a binding acknowledgement. On a mobile node, use the mobile
13692 + * node's home address for saddr. Returns 0 on success, non-zero on
13695 +int mipv6_send_ba(struct in6_addr *saddr, struct in6_addr *daddr,
13696 + struct in6_addr *auth_coa, struct in6_addr *rep_coa,
13697 + u8 status, u16 sequence, u32 lifetime, u8 *k_bu)
13699 + struct mipv6_mh_ba ba;
13700 + struct mipv6_auth_parm parm;
13701 + struct mipv6_mh_opt *ops = NULL;
13702 + int ops_len = 0, ret = 0;
13703 + struct mipv6_bce bc_entry;
13704 + int coming_home = 0;
13705 + int bypass_tnl = 0;
13707 + memset(&ba, 0, sizeof(ba));
13709 + ba.status = status;
13710 + ba.sequence = htons(sequence);
13711 + ba.lifetime = htons(lifetime >> 2);
13713 + DEBUG(DBG_INFO, "sending a status %d BA %s authenticator to MN \n"
13714 + "%x:%x:%x:%x:%x:%x:%x:%x at care of address \n"
13715 + "%x:%x:%x:%x:%x:%x:%x:%x : with lifetime %d and \n"
13716 + " sequence number %d",
13717 + status, k_bu ? "with" : "without",
13718 + NIPV6ADDR(daddr), NIPV6ADDR(auth_coa), lifetime, sequence);
13720 + memset(&parm, 0, sizeof(parm));
13721 + parm.coa = auth_coa;
13722 + parm.cn_addr = saddr;
13725 + ops_len += sizeof(struct mipv6_mo_bauth_data) +
13726 + MIPV6_RR_MAC_LENGTH;
13727 + parm.k_bu = k_bu;
13730 + if (mip6node_cnf.binding_refresh_advice) {
13731 + ops_len += sizeof(struct mipv6_mo_br_advice);
13734 + ops = alloc_mh_opts(ops_len);
13735 + if (ops == NULL) {
13736 + DEBUG(DBG_WARNING, "Out of memory");
13739 + if (mip6node_cnf.binding_refresh_advice > 0) {
13740 + if (append_mh_opt(ops, MIPV6_OPT_BIND_REFRESH_ADVICE, 2,
13741 + &mip6node_cnf.binding_refresh_advice) < 0) {
13742 + DEBUG(DBG_WARNING, "Adding BRA failed");
13749 + if (append_mh_opt(ops, MIPV6_OPT_AUTH_DATA,
13750 + MIPV6_RR_MAC_LENGTH, NULL) < 0) {
13751 + DEBUG(DBG_WARNING, "Adding BAD failed");
13758 + coming_home = !ipv6_addr_cmp(rep_coa, daddr);
13760 + bypass_tnl = (coming_home &&
13761 + !mipv6_bcache_get(daddr, saddr, &bc_entry) &&
13762 + bc_entry.flags&MIPV6_BU_F_HOME &&
13765 + if (bypass_tnl && mip6_fn.bce_tnl_rt_del)
13766 + mip6_fn.bce_tnl_rt_del(&bc_entry.coa,
13767 + &bc_entry.our_addr,
13768 + &bc_entry.home_addr);
13771 + ret = send_mh(daddr, saddr, MIPV6_MH_BA, sizeof(ba), (u8 *)&ba,
13772 + NULL, NULL, ops, &parm);
13774 + ret = send_mh(daddr, saddr, MIPV6_MH_BA, sizeof(ba), (u8 *)&ba,
13775 + NULL, rep_coa, ops, &parm);
13777 + if (bypass_tnl && mip6_fn.bce_tnl_rt_add)
13778 + mip6_fn.bce_tnl_rt_add(&bc_entry.coa,
13779 + &bc_entry.our_addr,
13780 + &bc_entry.home_addr);
13783 + if (status < 128) {
13784 + MIPV6_INC_STATS(n_ba_sent);
13786 + MIPV6_INC_STATS(n_ban_sent);
13797 + * mipv6_send_be - send a Binding Error message
13798 + * @saddr: source address for BE
13799 + * @daddr: destination address for BE
13800 + * @home: Home Address in offending packet (if any)
13802 + * Sends a binding error. On a mobile node, use the mobile node's
13803 + * home address for @saddr. Returns 0 on success, negative on
13806 +int mipv6_send_be(struct in6_addr *saddr, struct in6_addr *daddr,
13807 + struct in6_addr *home, __u8 status)
13809 + struct mipv6_mh_be be;
13811 + struct mipv6_bce bc_entry;
13812 + int bypass_tnl = 0;
13814 + if (ipv6_addr_is_multicast(daddr))
13817 + memset(&be, 0, sizeof(be));
13818 + be.status = status;
13820 + ipv6_addr_copy(&be.home_addr, home);
13822 + if (mipv6_bcache_get(daddr, saddr, &bc_entry) == 0 &&
13823 + bc_entry.flags&MIPV6_BU_F_HOME)
13826 + if (bypass_tnl && mip6_fn.bce_tnl_rt_del)
13827 + mip6_fn.bce_tnl_rt_del(&bc_entry.coa,
13828 + &bc_entry.our_addr,
13829 + &bc_entry.home_addr);
13831 + ret = send_mh(daddr, saddr, MIPV6_MH_BE, sizeof(be), (u8 *)&be,
13832 + NULL, NULL, NULL, NULL);
13834 + if (bypass_tnl && mip6_fn.bce_tnl_rt_add)
13835 + mip6_fn.bce_tnl_rt_add(&bc_entry.coa,
13836 + &bc_entry.our_addr,
13837 + &bc_entry.home_addr);
13840 + MIPV6_INC_STATS(n_be_sent);
13846 + * mipv6_send_addr_test - send a HoT or CoT message
13847 + * @saddr: source address
13848 + * @daddr: destination address
13849 + * @msg_type: HoT or CoT message
13850 + * @init: HoTI or CoTI message
13852 + * Send a reply to HoTI or CoTI message.
13854 +static int mipv6_send_addr_test(struct in6_addr *saddr,
13855 + struct in6_addr *daddr,
13857 + struct mipv6_mh_addr_ti *init)
13859 + u_int8_t *kgen_token = NULL;
13860 + struct mipv6_mh_addr_test addr_test;
13861 + struct mipv6_rr_nonce *nonce;
13862 + struct mipv6_mh_opt *ops = NULL;
13867 + if ((nonce = mipv6_rr_get_new_nonce())== NULL) {
13868 + DEBUG(DBG_WARNING, "Nonce creation failed");
13871 + if (mipv6_rr_cookie_create(daddr, &kgen_token, nonce->index)) {
13872 + DEBUG(DBG_WARNING, "No cookie");
13876 + addr_test.nonce_index = nonce->index;
13877 + memcpy(addr_test.init_cookie, init->init_cookie,
13878 + MIPV6_RR_COOKIE_LENGTH);
13879 + memcpy(addr_test.kgen_token, kgen_token,
13880 + MIPV6_RR_COOKIE_LENGTH);
13882 + /* No options defined */
13883 + ret = send_mh(daddr, saddr, msg_type, sizeof(addr_test),
13884 + (u8 *)&addr_test, NULL, NULL, ops, NULL);
13887 + if (msg_type == MIPV6_MH_HOT) {
13888 + MIPV6_INC_STATS(n_hot_sent);
13890 + MIPV6_INC_STATS(n_cot_sent);
13897 +static void bc_cache_add(int ifindex, struct in6_addr *daddr,
13898 + struct in6_addr *haddr, struct in6_addr *coa,
13899 + struct in6_addr *rep_coa, __u32 lifetime,
13900 + __u16 sequence, __u8 flags, __u8 *k_bu)
13902 + __u8 ba_status = SUCCESS;
13904 + if (lifetime > MAX_RR_BINDING_LIFE)
13905 + lifetime = MAX_RR_BINDING_LIFE;
13907 + if (mipv6_bcache_add(ifindex, daddr, haddr, coa, lifetime,
13908 + sequence, flags, CACHE_ENTRY) != 0) {
13909 + DEBUG(DBG_ERROR, "binding failed.");
13910 + ba_status = INSUFFICIENT_RESOURCES;
13913 + if (flags & MIPV6_BU_F_ACK) {
13914 + DEBUG(DBG_INFO, "sending ack (code=%d)", ba_status);
13915 + mipv6_send_ba(daddr, haddr, coa, rep_coa, ba_status, sequence,
13920 +static void bc_cn_home_add(int ifindex, struct in6_addr *daddr,
13921 + struct in6_addr *haddr, struct in6_addr *coa,
13922 + struct in6_addr *rep_coa, __u32 lifetime,
13923 + __u16 sequence, __u8 flags, __u8 *k_bu)
13925 + mipv6_send_ba(daddr, haddr, coa, rep_coa,
13926 + HOME_REGISTRATION_NOT_SUPPORTED,
13927 + sequence, lifetime, k_bu);
13930 +static void bc_cache_delete(struct in6_addr *daddr, struct in6_addr *haddr,
13931 + struct in6_addr *coa, struct in6_addr *rep_coa,
13932 + __u16 sequence, __u8 flags,
13935 + __u8 status = SUCCESS;
13937 + /* Cached Care-of Address Deregistration */
13938 + if (mipv6_bcache_exists(haddr, daddr) == CACHE_ENTRY) {
13939 + mipv6_bcache_delete(haddr, daddr, CACHE_ENTRY);
13941 + DEBUG(DBG_INFO, "entry is not in cache");
13942 + status = REASON_UNSPECIFIED;
13944 + if (flags & MIPV6_BU_F_ACK) {
13945 + mipv6_send_ba(daddr, haddr, coa, rep_coa, status, sequence,
13950 +static void bc_cn_home_delete(struct in6_addr *daddr, struct in6_addr *haddr,
13951 + struct in6_addr *coa, struct in6_addr *rep_coa,
13952 + __u16 sequence, __u8 flags,
13958 + * parse_mo_tlv - Parse TLV-encoded Mobility Options
13959 + * @mos: pointer to Mobility Options
13960 + * @len: total length of options
13961 + * @opts: structure to store option pointers
13963 + * Parses Mobility Options passed in @mos. Stores pointers in @opts
13964 + * to all valid mobility options found in @mos. Unknown options and
13965 + * padding (%MIPV6_OPT_PAD1 and %MIPV6_OPT_PADN) is ignored and
13968 +int parse_mo_tlv(void *mos, int len, struct mobopt *opts)
13970 + struct mipv6_mo *curr = (struct mipv6_mo *)mos;
13973 + while (left > 0) {
13975 + if (curr->type == MIPV6_OPT_PAD1)
13978 + optlen = 2 + curr->length;
13980 + if (optlen > left)
13983 + switch (curr->type) {
13984 + case MIPV6_OPT_PAD1:
13985 + DEBUG(DBG_DATADUMP, "MIPV6_OPT_PAD1 at %x", curr);
13987 + case MIPV6_OPT_PADN:
13988 + DEBUG(DBG_DATADUMP, "MIPV6_OPT_PADN at %x", curr);
13990 + case MIPV6_OPT_ALTERNATE_COA:
13991 + DEBUG(DBG_DATADUMP, "MIPV6_OPT_ACOA at %x", curr);
13992 + opts->alt_coa = (struct mipv6_mo_alt_coa *)curr;
13994 + case MIPV6_OPT_NONCE_INDICES:
13995 + DEBUG(DBG_DATADUMP, "MIPV6_OPT_NONCE_INDICES at %x", curr);
13996 + opts->nonce_indices =
13997 + (struct mipv6_mo_nonce_indices *)curr;
13999 + case MIPV6_OPT_AUTH_DATA:
14000 + DEBUG(DBG_DATADUMP, "MIPV6_OPT_AUTH_DATA at %x", curr);
14001 + opts->auth_data = (struct mipv6_mo_bauth_data *)curr;
14003 + case MIPV6_OPT_BIND_REFRESH_ADVICE:
14004 + DEBUG(DBG_DATADUMP, "MIPV6_OPT_BIND_REFRESH_ADVICE at %x", curr);
14005 + opts->br_advice = (struct mipv6_mo_br_advice *)curr;
14008 + DEBUG(DBG_INFO, "MO Unknown option type %d at %x, ignoring.",
14009 + curr->type, curr);
14010 + /* unknown mobility option, ignore and skip */
14013 + (u8 *)curr += optlen;
14025 + * Mobility Header Message handlers
14029 +static int mipv6_handle_mh_testinit(struct sk_buff *skb,
14030 + struct in6_addr *cn,
14031 + struct in6_addr *lcoa,
14032 + struct in6_addr *saddr,
14033 + struct in6_addr *fcoa,
14034 + struct mipv6_mh *mh)
14036 + struct mipv6_mh_addr_ti *ti = (struct mipv6_mh_addr_ti *)mh->data;
14037 + int msg_len = (mh->length+1) << 3;
14041 + if (msg_len > skb->len)
14044 + opt_len = msg_len - sizeof(*mh) - sizeof(*ti);
14046 + if (opt_len < 0) {
14047 + __u32 pos = (__u32)&mh->length - (__u32)skb->nh.raw;
14048 + icmpv6_send(skb, ICMPV6_PARAMPROB,
14049 + ICMPV6_HDR_FIELD, pos, skb->dev);
14051 + DEBUG(DBG_INFO, "Mobility Header length less than H/C TestInit");
14054 + if (!mip6node_cnf.accept_ret_rout) {
14055 + DEBUG(DBG_INFO, "Return routability administratively disabled");
14058 + if (lcoa || fcoa) {
14059 + DEBUG(DBG_INFO, "H/C TestInit has HAO or RTH2, dropped.");
14063 + if (mh->type == MIPV6_MH_HOTI) {
14064 + MIPV6_INC_STATS(n_hoti_rcvd);
14065 + return mipv6_send_addr_test(cn, saddr, MIPV6_MH_HOT, ti);
14066 + } else if (mh->type == MIPV6_MH_COTI) {
14067 + MIPV6_INC_STATS(n_coti_rcvd);
14068 + return mipv6_send_addr_test(cn, saddr, MIPV6_MH_COT, ti);
14070 + return -1; /* Impossible to get here */
14074 + * mipv6_handle_mh_bu - Binding Update handler
14075 + * @src: care-of address of sender
14076 + * @dst: our address
14077 + * @haddr: home address of sender
14078 + * @mh: pointer to the beginning of the Mobility Header
14080 + * Handles Binding Update. Packet and offset to option are passed.
14081 + * Returns 0 on success, otherwise negative.
14083 +static int mipv6_handle_mh_bu(struct sk_buff *skb,
14084 + struct in6_addr *dst,
14085 + struct in6_addr *unused,
14086 + struct in6_addr *haddr,
14087 + struct in6_addr *coaddr,
14088 + struct mipv6_mh *mh)
14090 + struct mipv6_mh_bu *bu = (struct mipv6_mh_bu *)mh->data;
14091 + int msg_len = (mh->length+1) << 3;
14094 + int dereg; /* Is this deregistration? */
14097 + struct mipv6_bce bc_entry;
14098 + struct in6_addr *coa, *reply_coa;
14099 + __u8 *key_bu = NULL; /* RR BU authentication key */
14100 + __u8 flags = bu->flags;
14103 + __u16 nonce_ind = (__u16) -1;
14105 + if (msg_len > skb->len)
14108 + opt_len = msg_len - sizeof(*mh) - sizeof(*bu);
14110 + if (opt_len < 0) {
14111 + __u32 pos = (__u32)&mh->length - (__u32)skb->nh.raw;
14112 + icmpv6_send(skb, ICMPV6_PARAMPROB,
14113 + ICMPV6_HDR_FIELD, pos, skb->dev);
14115 + DEBUG(DBG_INFO, "Mobility Header length less than BU");
14116 + MIPV6_INC_STATS(n_bu_drop.invalid);
14120 + addr_type = ipv6_addr_type(haddr);
14121 + if (addr_type&IPV6_ADDR_LINKLOCAL || !(addr_type&IPV6_ADDR_UNICAST))
14124 + /* If HAO not present, CoA == HAddr */
14125 + if (coaddr == NULL)
14129 + addr_type = ipv6_addr_type(coa);
14130 + if (addr_type&IPV6_ADDR_LINKLOCAL ||
14131 + !(addr_type&IPV6_ADDR_UNICAST))
14136 + sequence = ntohs(bu->sequence);
14137 + if (bu->lifetime == 0xffff)
14138 + lifetime = 0xffffffff;
14140 + lifetime = ntohs(bu->lifetime) << 2;
14142 + dereg = (ipv6_addr_cmp(haddr, coa) == 0 || lifetime == 0);
14144 + if (opt_len > 0) {
14145 + struct mobopt opts;
14146 + memset(&opts, 0, sizeof(opts));
14147 + if (parse_mo_tlv(bu + 1, opt_len, &opts) < 0) {
14148 + MIPV6_INC_STATS(n_bu_drop.invalid);
14152 + * MIPV6_OPT_AUTH_DATA, MIPV6_OPT_NONCE_INDICES,
14153 + * MIPV6_OPT_ALT_COA
14155 + if (opts.alt_coa) {
14156 + coa = &opts.alt_coa->addr;
14157 + dereg = (ipv6_addr_cmp(haddr, coa) == 0 || lifetime == 0);
14159 + addr_type = ipv6_addr_type(coa);
14160 + if (addr_type&IPV6_ADDR_LINKLOCAL ||
14161 + !(addr_type&IPV6_ADDR_UNICAST))
14164 + if (flags & MIPV6_BU_F_HOME) {
14165 + if (opts.nonce_indices)
14168 + u8 ba_status = 0;
14169 + u8 *h_ckie = NULL, *c_ckie = NULL; /* Home and care-of cookies */
14171 + /* BUs to CN MUST include authorization data and nonce indices options */
14172 + if (!opts.auth_data || !opts.nonce_indices) {
14173 + DEBUG(DBG_WARNING,
14174 + "Route optimization BU without authorization material, aborting processing");
14175 + return MH_AUTH_FAILED;
14177 + if (mipv6_rr_cookie_create(
14178 + haddr, &h_ckie, opts.nonce_indices->home_nonce_i) < 0) {
14179 + DEBUG(DBG_WARNING,
14180 + "mipv6_rr_cookie_create failed for home cookie");
14181 + ba_status = EXPIRED_HOME_NONCE_INDEX;
14183 + nonce_ind = opts.nonce_indices->home_nonce_i;
14184 + /* Don't create the care-of cookie, if MN deregisters */
14185 + if (!dereg && mipv6_rr_cookie_create(
14187 + opts.nonce_indices->careof_nonce_i) < 0) {
14188 + DEBUG(DBG_WARNING,
14189 + "mipv6_rr_cookie_create failed for coa cookie");
14190 + if (ba_status == 0)
14191 + ba_status = EXPIRED_CAREOF_NONCE_INDEX;
14193 + ba_status = EXPIRED_NONCES;
14195 + if (ba_status == 0) {
14197 + key_bu = mipv6_rr_key_calc(h_ckie, NULL);
14199 + key_bu = mipv6_rr_key_calc(h_ckie, c_ckie);
14200 + mh->checksum = 0;/* TODO: Don't mangle the packet */
14201 + if (key_bu && mipv6_auth_check(
14202 + dst, coa, (__u8 *)mh, msg_len + sizeof(*mh), opts.auth_data, key_bu) == 0) {
14203 + DEBUG(DBG_INFO, "mipv6_auth_check OK for BU");
14206 + DEBUG(DBG_WARNING,
14207 + "BU Authentication failed");
14214 + if (ba_status != 0) {
14215 + MIPV6_INC_STATS(n_bu_drop.auth);
14216 + mipv6_send_ba(dst, haddr, coa,
14217 + reply_coa, ba_status,
14218 + sequence, 0, NULL);
14224 + /* Require authorization option for RO, home reg is protected by IPsec */
14225 + if (!(flags & MIPV6_BU_F_HOME) && !auth) {
14226 + MIPV6_INC_STATS(n_bu_drop.auth);
14229 + return MH_AUTH_FAILED;
14232 + if (mipv6_bcache_get(haddr, dst, &bc_entry) == 0) {
14233 + if ((bc_entry.flags&MIPV6_BU_F_HOME) !=
14234 + (flags&MIPV6_BU_F_HOME)) {
14236 + "Registration type change. Sending BA REG_TYPE_CHANGE_FORBIDDEN");
14237 + mipv6_send_ba(dst, haddr, coa, reply_coa,
14238 + REG_TYPE_CHANGE_FORBIDDEN,
14239 + sequence, lifetime, key_bu);
14242 + if (!MIPV6_SEQ_GT(sequence, bc_entry.seq)) {
14244 + "Sequence number mismatch. Sending BA SEQUENCE_NUMBER_OUT_OF_WINDOW");
14245 + mipv6_send_ba(dst, haddr, coa, reply_coa,
14246 + SEQUENCE_NUMBER_OUT_OF_WINDOW,
14247 + bc_entry.seq, lifetime, key_bu);
14254 + struct rt6_info *rt;
14256 + /* Avoid looping binding cache entries */
14257 + if (mipv6_bcache_get(coa, dst, &bc_entry) == 0) {
14258 + DEBUG(DBG_WARNING, "Looped BU, dropping the packet");
14261 + DEBUG(DBG_INFO, "calling bu_add.");
14262 + if ((rt = rt6_lookup(haddr, dst, 0, 0)) != NULL) {
14263 + ifindex = rt->rt6i_dev->ifindex;
14264 + dst_release(&rt->u.dst);
14267 + * Can't process the BU since the right interface is
14270 + DEBUG(DBG_WARNING, "No route entry found for handling "
14271 + "a BU request, (using 0 as index)");
14274 + if (flags & MIPV6_BU_F_HOME)
14275 + mip6_fn.bce_home_add(ifindex, dst, haddr, coa,
14276 + reply_coa, lifetime, sequence,
14279 + mip6_fn.bce_cache_add(ifindex, dst, haddr, coa,
14280 + reply_coa, lifetime, sequence,
14283 + DEBUG(DBG_INFO, "calling BCE delete.");
14285 + if (flags & MIPV6_BU_F_HOME)
14286 + mip6_fn.bce_home_del(dst, haddr, coa, reply_coa,
14287 + sequence, flags, key_bu);
14289 + mipv6_rr_invalidate_nonce(nonce_ind);
14290 + mip6_fn.bce_cache_del(dst, haddr, coa, reply_coa,
14291 + sequence, flags, key_bu);
14295 + MIPV6_INC_STATS(n_bu_rcvd);
14301 +static int mipv6_mh_rcv(struct sk_buff *skb)
14303 + struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
14304 + struct mipv6_mh *mh;
14305 + struct in6_addr *lhome, *fhome, *lcoa = NULL, *fcoa = NULL;
14308 + fhome = &skb->nh.ipv6h->saddr;
14309 + lhome = &skb->nh.ipv6h->daddr;
14311 + if (opt->hao != 0) {
14312 + struct mipv6_dstopt_homeaddr *hao;
14313 + hao = (struct mipv6_dstopt_homeaddr *)(skb->nh.raw + opt->hao);
14314 + fcoa = &hao->addr;
14317 + if (opt->srcrt2 != 0) {
14318 + struct rt2_hdr *rt2;
14319 + rt2 = (struct rt2_hdr *)((u8 *)skb->nh.raw + opt->srcrt2);
14320 + lcoa = &rt2->addr;
14323 + /* Verify checksum is correct */
14324 + if (skb->ip_summed == CHECKSUM_HW) {
14325 + skb->ip_summed = CHECKSUM_UNNECESSARY;
14326 + if (csum_ipv6_magic(fhome, lhome, skb->len, IPPROTO_MOBILITY,
14328 + if (net_ratelimit())
14329 + printk(KERN_WARNING "MIPv6 MH hw checksum failed\n");
14330 + skb->ip_summed = CHECKSUM_NONE;
14333 + if (skb->ip_summed == CHECKSUM_NONE) {
14334 + if (csum_ipv6_magic(fhome, lhome, skb->len, IPPROTO_MOBILITY,
14335 + skb_checksum(skb, 0, skb->len, 0))) {
14336 + if (net_ratelimit())
14337 + printk(KERN_WARNING "MIPv6 MH checksum failed\n");
14342 + if (!pskb_may_pull(skb, skb->h.raw-skb->data+sizeof(*mh)) ||
14343 + !pskb_may_pull(skb,
14344 + skb->h.raw-skb->data+((skb->h.raw[1]+1)<<3))) {
14345 + DEBUG(DBG_INFO, "MIPv6 MH invalid length");
14350 + mh = (struct mipv6_mh *) skb->h.raw;
14352 + /* Verify there are no more headers after the MH */
14353 + if (mh->payload != NEXTHDR_NONE) {
14354 + __u32 pos = (__u32)&mh->payload - (__u32)skb->nh.raw;
14355 + icmpv6_send(skb, ICMPV6_PARAMPROB,
14356 + ICMPV6_HDR_FIELD, pos, skb->dev);
14358 + DEBUG(DBG_INFO, "MIPv6 MH error");
14362 + if (mh->type > MIPV6_MH_MAX) {
14363 + /* send binding error */
14364 + printk("Invalid mobility header type (%d)\n", mh->type);
14365 + mipv6_send_be(lhome, fcoa ? fcoa : fhome,
14366 + fcoa ? fhome : NULL,
14367 + MIPV6_BE_UNKNOWN_MH_TYPE);
14370 + if (mh_rcv[mh->type].func != NULL) {
14371 + ret = mh_rcv[mh->type].func(skb, lhome, lcoa, fhome, fcoa, mh);
14373 + DEBUG(DBG_INFO, "No handler for MH Type %d", mh->type);
14381 + MIPV6_INC_STATS(n_mh_in_error);
14387 +#if LINUX_VERSION_CODE >= 0x2052a
14388 +struct inet6_protocol mipv6_mh_protocol =
14390 + mipv6_mh_rcv, /* handler */
14391 + NULL /* error control */
14394 +struct inet6_protocol mipv6_mh_protocol =
14396 + mipv6_mh_rcv, /* handler */
14397 + NULL, /* error control */
14399 + IPPROTO_MOBILITY, /* protocol ID */
14402 + "MIPv6 MH" /* name */
14408 + * Code module init/exit functions
14412 +int __init mipv6_mh_common_init(void)
14417 + mip6_fn.bce_home_add = bc_cn_home_add;
14418 + mip6_fn.bce_cache_add = bc_cache_add;
14419 + mip6_fn.bce_home_del = bc_cn_home_delete;
14420 + mip6_fn.bce_cache_del = bc_cache_delete;
14422 + mipv6_mh_socket = sock_alloc();
14423 + if (mipv6_mh_socket == NULL) {
14425 + "Failed to create the MIP6 MH control socket.\n");
14428 + mipv6_mh_socket->type = SOCK_RAW;
14430 + if ((err = sock_create(PF_INET6, SOCK_RAW, IPPROTO_MOBILITY,
14431 + &mipv6_mh_socket)) < 0) {
14433 + "Failed to initialize the MIP6 MH control socket (err %d).\n",
14435 + sock_release(mipv6_mh_socket);
14436 + mipv6_mh_socket = NULL; /* for safety */
14440 + sk = mipv6_mh_socket->sk;
14441 + sk->allocation = GFP_ATOMIC;
14442 + sk->sndbuf = 64 * 1024 + sizeof(struct sk_buff);
14443 + sk->prot->unhash(sk);
14445 + memset(&mh_rcv, 0, sizeof(mh_rcv));
14446 + mh_rcv[MIPV6_MH_HOTI].func = mipv6_handle_mh_testinit;
14447 + mh_rcv[MIPV6_MH_COTI].func = mipv6_handle_mh_testinit;
14448 + mh_rcv[MIPV6_MH_BU].func = mipv6_handle_mh_bu;
14450 +#if LINUX_VERSION_CODE >= 0x2052a
14451 + if (inet6_add_protocol(&mipv6_mh_protocol, IPPROTO_MOBILITY) < 0) {
14452 + printk(KERN_ERR "Failed to register MOBILITY protocol\n");
14453 + sock_release(mipv6_mh_socket);
14454 + mipv6_mh_socket = NULL;
14458 + inet6_add_protocol(&mipv6_mh_protocol);
14460 + /* To disable the use of dst_cache,
14461 + * which slows down the sending of BUs ??
14463 + sk->dst_cache=NULL;
14468 +void __exit mipv6_mh_common_exit(void)
14470 + if (mipv6_mh_socket) sock_release(mipv6_mh_socket);
14471 + mipv6_mh_socket = NULL; /* For safety. */
14473 +#if LINUX_VERSION_CODE >= 0x2052a
14474 + inet6_del_protocol(&mipv6_mh_protocol, IPPROTO_MOBILITY);
14476 + inet6_del_protocol(&mipv6_mh_protocol);
14478 + memset(&mh_rcv, 0, sizeof(mh_rcv));
14481 +++ linux-2.4.27/net/ipv6/mobile_ip6/mobhdr_mn.c
14484 + * Mobile IPv6 Mobility Header Functions for Mobile Node
14487 + * Antti Tuominen <ajtuomin@tml.hut.fi>
14488 + * Niklas Kämpe <nhkampe@cc.hut.fi>
14489 + * Henrik Petander <henrik.petander@hut.fi>
14493 + * This program is free software; you can redistribute it and/or
14494 + * modify it under the terms of the GNU General Public License as
14495 + * published by the Free Software Foundation; either version 2 of
14496 + * the License, or (at your option) any later version.
14500 +#include <linux/types.h>
14501 +#include <linux/sched.h>
14502 +#include <linux/init.h>
14503 +#include <net/ipv6.h>
14504 +#include <net/addrconf.h>
14505 +#include <net/mipv6.h>
14507 +#include "mobhdr.h"
14510 +#include "rr_crypto.h"
14511 +#include "debug.h"
14513 +#include "stats.h"
14515 +int rr_configured = 1;
14517 +/* Return value of mipv6_rr_state() */
14520 +#define RR_FOR_COA 2
14521 +#define INPROGRESS_RR 3
14524 + * send_bu_msg - sends a Binding Update
14525 + * @bulentry : BUL entry with the information for building a BU
14527 + * Function builds a BU msg based on the contents of a bul entry.
14528 + * Does not change the bul entry.
14530 +static int send_bu_msg(struct mipv6_bul_entry *binding)
14532 + int auth = 0; /* Use auth */
14534 + struct mipv6_auth_parm parm;
14535 + struct mipv6_mh_bu bu;
14538 + DEBUG(DBG_ERROR, "called with a null bul entry");
14542 + memset(&parm, 0, sizeof(parm));
14543 + if (mipv6_prefix_compare(&binding->coa, &binding->home_addr, 64))
14544 + parm.coa = &binding->home_addr;
14546 + parm.coa = &binding->coa;
14547 + parm.cn_addr = &binding->cn_addr;
14549 + if (binding->rr && binding->rr->kbu) {
14550 + DEBUG(DBG_INFO, "Binding with key");
14552 + parm.k_bu = binding->rr->kbu;
14554 + memset(&bu, 0, sizeof(bu));
14555 + bu.flags = binding->flags;
14556 + bu.sequence = htons(binding->seq);
14557 + bu.lifetime = htons(binding->lifetime >> 2);
14560 + ret = send_mh(&binding->cn_addr, &binding->home_addr,
14561 + MIPV6_MH_BU, sizeof(bu), (u8 *)&bu,
14562 + &binding->home_addr, NULL,
14563 + binding->ops, &parm);
14566 + MIPV6_INC_STATS(n_bu_sent);
14572 + * mipv6_send_addr_test_init - send a HoTI or CoTI message
14573 + * @saddr: source address for H/CoTI
14574 + * @daddr: destination address for H/CoTI
14575 + * @msg_type: Identifies whether HoTI or CoTI
14576 + * @init_cookie: the HoTi or CoTi init cookie
14578 + * The message will be retransmitted till we get a HoT or CoT message, since
14579 + * our caller (mipv6_RR_start) has entered this message in the BUL with
14580 + * exponential backoff retramission set.
14582 +static int mipv6_send_addr_test_init(struct in6_addr *saddr,
14583 + struct in6_addr *daddr,
14587 + struct mipv6_mh_addr_ti ti;
14588 + struct mipv6_mh_opt *ops = NULL;
14591 + /* Set reserved and copy the cookie from address test init msg */
14593 + mipv6_rr_mn_cookie_create(init_cookie);
14594 + memcpy(ti.init_cookie, init_cookie, MIPV6_RR_COOKIE_LENGTH);
14596 + ret = send_mh(daddr, saddr, msg_type, sizeof(ti), (u8 *)&ti,
14597 + NULL, NULL, ops, NULL);
14599 + if (msg_type == MIPV6_MH_HOTI) {
14600 + MIPV6_INC_STATS(n_hoti_sent);
14602 + MIPV6_INC_STATS(n_coti_sent);
14611 + * Callback handlers for binding update list
14615 +/* Return value 0 means keep entry, non-zero means discard entry. */
14617 +/* Callback for BUs not requiring acknowledgement
14619 +int bul_entry_expired(struct mipv6_bul_entry *bulentry)
14621 + /* Lifetime expired, delete entry. */
14622 + DEBUG(DBG_INFO, "bul entry 0x%p lifetime expired, deleting entry",
14627 +/* Callback for BUs requiring acknowledgement with exponential resending
14629 +static int bul_resend_exp(struct mipv6_bul_entry *bulentry)
14631 + unsigned long now = jiffies;
14633 + DEBUG(DBG_INFO, "(0x%x) resending bu", (int) bulentry);
14636 + /* If sending a de-registration, do not care about the
14637 + * lifetime value, as de-registrations are normally sent with
14638 + * a zero lifetime value. If the entry is a home entry get the
14639 + * current lifetime.
14642 + if (bulentry->lifetime != 0) {
14643 + bulentry->lifetime = mipv6_mn_get_bulifetime(
14644 + &bulentry->home_addr, &bulentry->coa, bulentry->flags);
14646 + bulentry->expire = now + bulentry->lifetime * HZ;
14648 + bulentry->expire = now + HOME_RESEND_EXPIRE * HZ;
14650 + if (bulentry->rr) {
14651 + /* Redo RR, if cookies have expired */
14652 + if (time_after(jiffies, bulentry->rr->home_time + MAX_TOKEN_LIFE * HZ))
14653 + bulentry->rr->rr_state |= RR_WAITH;
14654 + if (time_after(jiffies, bulentry->rr->careof_time + MAX_NONCE_LIFE * HZ))
14655 + bulentry->rr->rr_state |= RR_WAITC;
14657 + if (bulentry->rr->rr_state & RR_WAITH) {
14658 + /* Resend HoTI directly */
14659 + mipv6_send_addr_test_init(&bulentry->home_addr,
14660 + &bulentry->cn_addr, MIPV6_MH_HOTI,
14661 + bulentry->rr->hot_cookie);
14663 + if (bulentry->rr->rr_state & RR_WAITC) {
14664 + /* Resend CoTI directly */
14665 + mipv6_send_addr_test_init(&bulentry->coa,
14666 + &bulentry->cn_addr, MIPV6_MH_COTI,
14667 + bulentry->rr->cot_cookie);
14674 + if (send_bu_msg(bulentry) < 0)
14675 + DEBUG(DBG_ERROR, "Resending of BU failed");
14678 + /* Schedule next retransmission */
14679 + if (bulentry->delay < bulentry->maxdelay) {
14680 + bulentry->delay = 2 * bulentry->delay;
14681 + if (bulentry->delay > bulentry->maxdelay) {
14682 + /* can happen if maxdelay is not power(mindelay, 2) */
14683 + bulentry->delay = bulentry->maxdelay;
14685 + } else if (bulentry->flags & MIPV6_BU_F_HOME) {
14686 + /* Home registration - continue sending BU at maxdelay rate */
14687 + DEBUG(DBG_INFO, "Sending BU to HA after max ack wait time "
14688 + "reached(0x%x)", (int) bulentry);
14689 + bulentry->delay = bulentry->maxdelay;
14690 + } else if (!(bulentry->flags & MIPV6_BU_F_HOME)) {
14691 + /* Failed to get BA from a CN */
14692 + bulentry->callback_time = now;
14696 + bulentry->callback_time = now + bulentry->delay * HZ;
14702 +/* Callback for sending a registration refresh BU
14704 +static int bul_refresh(struct mipv6_bul_entry *bulentry)
14706 + unsigned long now = jiffies;
14708 + /* Refresh interval passed, send new BU */
14709 + DEBUG(DBG_INFO, "bul entry 0x%x refresh interval passed, sending new BU", (int) bulentry);
14710 + if (bulentry->lifetime == 0)
14713 + /* Set new maximum lifetime and expiration time */
14714 + bulentry->lifetime = mipv6_mn_get_bulifetime(&bulentry->home_addr,
14716 + bulentry->flags);
14717 + bulentry->expire = now + bulentry->lifetime * HZ;
14719 + /* Send update */
14720 + if (send_bu_msg(bulentry) < 0)
14721 + DEBUG(DBG_ERROR, "Resending of BU failed");
14723 + if (time_after_eq(now, bulentry->expire)) {
14724 + /* Sanity check */
14725 + DEBUG(DBG_ERROR, "bul entry expire time in history - setting expire to %u secs", ERROR_DEF_LIFETIME);
14726 + bulentry->lifetime = ERROR_DEF_LIFETIME;
14727 + bulentry->expire = now + ERROR_DEF_LIFETIME*HZ;
14730 + /* Set up retransmission */
14731 + bulentry->state = RESEND_EXP;
14732 + bulentry->callback = bul_resend_exp;
14733 + bulentry->callback_time = now + INITIAL_BINDACK_TIMEOUT*HZ;
14734 + bulentry->delay = INITIAL_BINDACK_TIMEOUT;
14735 + bulentry->maxdelay = MAX_BINDACK_TIMEOUT;
14740 +static int mipv6_send_RR_bu(struct mipv6_bul_entry *bulentry)
14746 + DEBUG(DBG_INFO, "Sending BU to CN %x:%x:%x:%x:%x:%x:%x:%x "
14747 + "for home address %x:%x:%x:%x:%x:%x:%x:%x",
14748 + NIPV6ADDR(&bulentry->cn_addr), NIPV6ADDR(&bulentry->home_addr));
14749 + nonces[0] = bulentry->rr->home_nonce_index;
14750 + nonces[1] = bulentry->rr->careof_nonce_index;
14751 + ops_len = sizeof(struct mipv6_mo_bauth_data) + MIPV6_RR_MAC_LENGTH +
14752 + sizeof(struct mipv6_mo_nonce_indices);
14753 + if (bulentry->ops) {
14754 + DEBUG(DBG_WARNING, "Bul entry had existing mobility options, freeing them");
14755 + kfree(bulentry->ops);
14757 + bulentry->ops = alloc_mh_opts(ops_len);
14759 + if (!bulentry->ops)
14761 + if (append_mh_opt(bulentry->ops, MIPV6_OPT_NONCE_INDICES,
14762 + sizeof(struct mipv6_mo_nonce_indices) - 2, nonces) < 0)
14765 + if (append_mh_opt(bulentry->ops, MIPV6_OPT_AUTH_DATA,
14766 + MIPV6_RR_MAC_LENGTH, NULL) < 0)
14768 + /* RR procedure is over, send a BU */
14769 + if (!(bulentry->flags & MIPV6_BU_F_ACK)) {
14770 + DEBUG(DBG_INFO, "Setting bul callback to bul_entry_expired");
14771 + bulentry->state = ACK_OK;
14772 + bulentry->callback = bul_entry_expired;
14773 + bulentry->callback_time = jiffies + HZ * bulentry->lifetime;
14774 + bulentry->expire = jiffies + HZ * bulentry->lifetime;
14777 + bulentry->callback_time = jiffies + HZ;
14778 + bulentry->expire = jiffies + HZ * bulentry->lifetime;
14781 + ret = send_bu_msg(bulentry);
14782 + mipv6_bul_reschedule(bulentry);
14786 +static int mipv6_rr_state(struct mipv6_bul_entry *bul, struct in6_addr *saddr,
14787 + struct in6_addr *coa, __u8 flags)
14789 + if (!rr_configured)
14791 + if (flags & MIPV6_BU_F_HOME) {
14792 + /* We don't need RR, this is a Home Registration */
14795 + if (!bul || !bul->rr) {
14796 + /* First time BU to CN, need RR */
14800 + switch (bul->rr->rr_state) {
14802 + /* Need RR if first BU to CN */
14805 + /* If MN moves to a new coa, do RR for it */
14806 + if (!ipv6_addr_cmp(&bul->coa, coa))
14812 + * We are in the middle of RR, the HoTI and CoTI have been
14813 + * sent. But we haven't got HoT and CoT from the CN, so
14814 + * don't do anything more at this time.
14816 + return INPROGRESS_RR;
14821 + * mipv6_RR_start - Start Return Routability procedure
14822 + * @home_addr: home address
14823 + * @cn_addr: correspondent address
14824 + * @coa: care-of address
14825 + * @entry: binding update list entry (if any)
14826 + * @initdelay: initial ack timeout
14827 + * @maxackdelay: maximum ack timeout
14829 + * @lifetime: lifetime of binding
14830 + * @ops: mobility options
14832 + * Caller must hold @bul_lock (write).
14834 +static int mipv6_RR_start(struct in6_addr *home_addr, struct in6_addr *cn_addr,
14835 + struct in6_addr *coa, struct mipv6_bul_entry *entry,
14836 + __u32 initdelay, __u32 maxackdelay, __u8 flags,
14837 + __u32 lifetime, struct mipv6_mh_opt *ops)
14840 + struct mipv6_bul_entry *bulentry = entry;
14841 + struct mipv6_rr_info *rr = NULL;
14845 + /* Do RR procedure only for care-of address after handoff,
14846 + if home cookie is still valid */
14847 + if (bulentry && bulentry->rr) {
14848 + if (time_before(jiffies, bulentry->rr->home_time + MAX_NONCE_LIFE * HZ) &&
14849 + lifetime && !(ipv6_addr_cmp(home_addr, coa) == 0)) {
14850 + mipv6_rr_mn_cookie_create(bulentry->rr->cot_cookie);
14851 + DEBUG(DBG_INFO, "Bul entry and rr info exist, only doing RR for CoA");
14852 + ipv6_addr_copy(&bulentry->coa, coa);
14853 + bulentry->rr->rr_state |= RR_WAITC;
14854 + } else if (!lifetime) { /* Send only HoTi when returning home */
14855 + mipv6_rr_mn_cookie_create(bulentry->rr->hot_cookie);
14856 + DEBUG(DBG_INFO, "Bul entry and rr info exist, only doing RR for HoA");
14857 + ipv6_addr_copy(&bulentry->coa, coa); /* Home address as CoA */
14858 + bulentry->rr->rr_state |= RR_WAITH;
14861 + DEBUG(DBG_INFO, "Doing RR for both HoA and CoA");
14862 + rr = kmalloc(sizeof(*rr), GFP_ATOMIC);
14863 + memset(rr, 0, sizeof(*rr));
14864 + rr->rr_state = RR_WAITHC;
14867 + if (bulentry->state == ACK_ERROR)
14869 + seq = bulentry->seq + 1;
14872 + /* Save the info in the BUL to retransmit the BU after RR is done */
14873 + /* Caller must hold bul_lock (write) since we don't */
14875 + if ((bulentry = mipv6_bul_add(cn_addr, home_addr, coa,
14876 + min_t(__u32, lifetime, MAX_RR_BINDING_LIFE),
14877 + seq, flags, bul_resend_exp, initdelay,
14878 + RESEND_EXP, initdelay,
14879 + maxackdelay, ops,
14881 + DEBUG(DBG_INFO, "couldn't update BUL for HoTi");
14885 + rr = bulentry->rr;
14886 + if (rr->rr_state&RR_WAITH)
14887 + mipv6_send_addr_test_init(home_addr, cn_addr, MIPV6_MH_HOTI,
14889 + if (ipv6_addr_cmp(home_addr, coa) && lifetime)
14890 + mipv6_send_addr_test_init(coa, cn_addr, MIPV6_MH_COTI, rr->cot_cookie);
14892 + bulentry->rr->rr_state &= ~RR_WAITC;
14900 + * Status codes for mipv6_ba_rcvd()
14902 +#define STATUS_UPDATE 0
14903 +#define STATUS_REMOVE 1
14906 + * mipv6_ba_rcvd - Update BUL for this Binding Acknowledgement
14907 + * @ifindex: interface BA came from
14908 + * @cnaddr: sender IPv6 address
14909 + * @home_addr: home address
14910 + * @sequence: sequence number
14911 + * @lifetime: lifetime granted by Home Agent in seconds
14912 + * @refresh: recommended resend interval
14913 + * @status: %STATUS_UPDATE (ack) or %STATUS_REMOVE (nack)
14915 + * This function must be called to notify the module of the receipt of
14916 + * a binding acknowledgement so that it can cease retransmitting the
14917 + * option. The caller must have validated the acknowledgement before calling
14918 + * this function. 'status' can be either STATUS_UPDATE in which case the
14919 + * binding acknowledgement is assumed to be valid and the corresponding
14920 + * binding update list entry is updated, or STATUS_REMOVE in which case
14921 + * the corresponding binding update list entry is removed (this can be
14922 + * used upon receiving a negative acknowledgement).
14923 + * Returns 0 if a matching binding update has been sent or non-zero if
14926 +static int mipv6_ba_rcvd(int ifindex, struct in6_addr *cnaddr,
14927 + struct in6_addr *home_addr,
14928 + u16 sequence, u32 lifetime,
14929 + u32 refresh, int status)
14931 + struct mipv6_bul_entry *bulentry;
14932 + unsigned long now = jiffies;
14933 + struct in6_addr coa;
14935 + DEBUG(DBG_INFO, "BA received with sequence number 0x%x, status: %d",
14936 + (int) sequence, status);
14938 + /* Find corresponding entry in binding update list. */
14939 + write_lock(&bul_lock);
14940 + if ((bulentry = mipv6_bul_get(cnaddr, home_addr)) == NULL) {
14941 + DEBUG(DBG_INFO, "- discarded, no entry in bul matches BA source address");
14942 + write_unlock(&bul_lock);
14946 + ipv6_addr_copy(&coa, &bulentry->coa);
14947 + if (status == SEQUENCE_NUMBER_OUT_OF_WINDOW) {
14948 + __u32 lifetime = mipv6_mn_get_bulifetime(&bulentry->home_addr,
14950 + bulentry->flags);
14951 + bulentry->seq = sequence;
14953 + mipv6_send_bu(&bulentry->home_addr, &bulentry->cn_addr,
14954 + &bulentry->coa, INITIAL_BINDACK_TIMEOUT,
14955 + MAX_BINDACK_TIMEOUT, 1, bulentry->flags,
14957 + write_unlock(&bul_lock);
14959 + } else if (status >= REASON_UNSPECIFIED) {
14961 + int at_home = MN_NOT_AT_HOME;
14962 + DEBUG(DBG_WARNING, "- NACK - BA status: %d, deleting bul entry", status);
14963 + if (bulentry->flags & MIPV6_BU_F_HOME) {
14964 + struct mn_info *minfo;
14965 + read_lock(&mn_info_lock);
14966 + minfo = mipv6_mninfo_get_by_home(home_addr);
14968 + spin_lock(&minfo->lock);
14969 + if (minfo->is_at_home != MN_NOT_AT_HOME)
14970 + minfo->is_at_home = MN_AT_HOME;
14971 + at_home = minfo->is_at_home;
14972 + minfo->has_home_reg = 0;
14973 + spin_unlock(&minfo->lock);
14975 + read_unlock(&mn_info_lock);
14976 + DEBUG(DBG_ERROR, "Home registration failed: BA status: %d, deleting bul entry", status);
14978 + write_unlock(&bul_lock);
14979 + err = mipv6_bul_delete(cnaddr, home_addr);
14980 + if (at_home == MN_AT_HOME) {
14981 + mipv6_mn_send_home_na(home_addr);
14982 + write_lock_bh(&bul_lock);
14983 + mipv6_bul_iterate(mn_cn_handoff, &coa);
14984 + write_unlock_bh(&bul_lock);
14988 + bulentry->state = ACK_OK;
14990 + if (bulentry->flags & MIPV6_BU_F_HOME && lifetime > 0) {
14991 + /* For home registrations: schedule a refresh binding update.
14992 + * Use the refresh interval given by home agent or 80%
14993 + * of lifetime, whichever is less.
14995 + * Adjust binding lifetime if 'granted' lifetime
14996 + * (lifetime value in received binding acknowledgement)
14997 + * is shorter than 'requested' lifetime (lifetime
14998 + * value sent in corresponding binding update).
14999 + * max((L_remain - (L_update - L_ack)), 0)
15001 + if (lifetime * HZ < (bulentry->expire - bulentry->lastsend)) {
15002 + bulentry->expire =
15003 + max_t(__u32, bulentry->expire -
15004 + ((bulentry->expire - bulentry->lastsend) -
15005 + lifetime * HZ), jiffies +
15006 + ERROR_DEF_LIFETIME * HZ);
15008 + if (refresh > lifetime || refresh == 0)
15009 + refresh = 4 * lifetime / 5;
15010 + DEBUG(DBG_INFO, "setting callback for expiration of"
15011 + " a Home Registration: lifetime:%d, refresh:%d",
15012 + lifetime, refresh);
15013 + bulentry->callback = bul_refresh;
15014 + bulentry->callback_time = now + refresh * HZ;
15015 + bulentry->expire = now + lifetime * HZ;
15016 + bulentry->lifetime = lifetime;
15017 + if (time_after_eq(jiffies, bulentry->expire)) {
15018 + /* Sanity check */
15019 + DEBUG(DBG_ERROR, "bul entry expire time in history - setting expire to %u secs",
15020 + ERROR_DEF_LIFETIME);
15021 + bulentry->expire = jiffies + ERROR_DEF_LIFETIME * HZ;
15023 + mipv6_mn_set_home_reg(home_addr, 1);
15024 + mipv6_bul_iterate(mn_cn_handoff, &coa);
15025 + } else if ((bulentry->flags & MIPV6_BU_F_HOME) && bulentry->lifetime == 0) {
15026 + write_unlock(&bul_lock);
15027 + DEBUG(DBG_INFO, "Got BA for deregistration BU");
15028 + mipv6_mn_set_home_reg(home_addr, 0);
15029 + mipv6_bul_delete(cnaddr, home_addr);
15030 + mipv6_mn_send_home_na(home_addr);
15032 + write_lock_bh(&bul_lock);
15033 + mipv6_bul_iterate(mn_cn_handoff, &coa);
15034 + write_unlock_bh(&bul_lock);
15038 + mipv6_bul_reschedule(bulentry);
15039 + write_unlock(&bul_lock);
15044 +static int mipv6_handle_mh_HC_test(struct sk_buff *skb,
15045 + struct in6_addr *saddr,
15046 + struct in6_addr *fcoa,
15047 + struct in6_addr *cn,
15048 + struct in6_addr *lcoa,
15049 + struct mipv6_mh *mh)
15052 + int msg_len = (mh->length+1) << 3;
15055 + struct mipv6_mh_addr_test *tm = (struct mipv6_mh_addr_test *)mh->data;
15056 + struct mipv6_bul_entry *bulentry;
15060 + if (msg_len > skb->len)
15063 + opt_len = msg_len - sizeof(*mh) - sizeof(*tm);
15065 + if (opt_len < 0) {
15066 + __u32 pos = (__u32)&mh->length - (__u32)skb->nh.raw;
15067 + icmpv6_send(skb, ICMPV6_PARAMPROB,
15068 + ICMPV6_HDR_FIELD, pos, skb->dev);
15070 + DEBUG(DBG_INFO, "Mobility Header length less than H/C Test");
15073 + if (fcoa || lcoa) {
15074 + DEBUG(DBG_INFO, "H/C Test has HAO or RTH2, dropped.");
15077 + write_lock(&bul_lock);
15079 + /* We need to get the home address, since CoT only has the CoA*/
15080 + if (mh->type == MIPV6_MH_COT) {
15081 + if ((bulentry = mipv6_bul_get_by_ccookie(cn, tm->init_cookie)) == NULL) {
15082 + DEBUG(DBG_ERROR, "has no BUL or RR state for "
15083 + "source:%x:%x:%x:%x:%x:%x:%x:%x",
15085 + write_unlock(&bul_lock);
15088 + } else { /* HoT has the home address */
15089 + if (((bulentry = mipv6_bul_get(cn, saddr)) == NULL) || !bulentry->rr) {
15090 + DEBUG(DBG_ERROR, "has no BUL or RR state for "
15091 + "source:%x:%x:%x:%x:%x:%x:%x:%x "
15092 + "dest:%x:%x:%x:%x:%x:%x:%x:%x",
15093 + NIPV6ADDR(cn), NIPV6ADDR(saddr));
15094 + write_unlock(&bul_lock);
15099 + switch (mh->type) {
15100 + case MIPV6_MH_HOT:
15101 + if ((bulentry->rr->rr_state & RR_WAITH) == 0) {
15102 + DEBUG(DBG_ERROR, "Not waiting for a Home Test message");
15106 + * Make sure no home cookies have been received yet.
15107 + * TODO: Check not being put in at this time since subsequent
15108 + * BU's after this time will have home cookie stored.
15111 + /* Check if the cookie received is the right one */
15112 + if (!mipv6_equal_cookies(tm->init_cookie,
15113 + bulentry->rr->hot_cookie)) {
15114 + /* Invalid cookie, might be an old cookie */
15115 + DEBUG(DBG_WARNING, "Received HoT cookie does not match stored cookie");
15118 + DEBUG(DBG_INFO, "Got Care-of Test message");
15119 + bulentry->rr->rr_state &= ~RR_WAITH;
15120 + memcpy(bulentry->rr->home_cookie, tm->kgen_token, MIPV6_COOKIE_LEN);
15121 + bulentry->rr->home_nonce_index = tm->nonce_index;
15122 + bulentry->rr->home_time = jiffies;
15126 + case MIPV6_MH_COT:
15127 + if ((bulentry->rr->rr_state & RR_WAITC) == 0) {
15128 + DEBUG(DBG_ERROR, "Not waiting for a Home Test message");
15132 + * Make sure no home cookies have been received yet.
15133 + * TODO: Check not being put in at this time since subsequent
15134 + * BU's at this time will have careof cookie stored.
15137 + /* Check if the cookie received is the right one */
15138 + if (!mipv6_equal_cookies(tm->init_cookie,
15139 + bulentry->rr->cot_cookie)) {
15140 + DEBUG(DBG_INFO, "Received CoT cookie does not match stored cookie");
15143 + bulentry->rr->rr_state &= ~RR_WAITC;
15144 + memcpy(bulentry->rr->careof_cookie, tm->kgen_token, MIPV6_COOKIE_LEN);
15145 + bulentry->rr->careof_nonce_index = tm->nonce_index;
15146 + bulentry->rr->careof_time = jiffies;
15150 + /* Impossible to get here */
15154 + if (bulentry->rr->rr_state == RR_DONE) {
15155 + if (bulentry->rr->kbu) /* First free any old keys */
15156 + kfree(bulentry->rr->kbu);
15157 + /* Store the session key to be used in BU's */
15158 + if (ipv6_addr_cmp(&bulentry->coa, &bulentry->home_addr) && bulentry->lifetime)
15159 + bulentry->rr->kbu = mipv6_rr_key_calc(bulentry->rr->home_cookie,
15160 + bulentry->rr->careof_cookie);
15162 + bulentry->rr->kbu = mipv6_rr_key_calc(bulentry->rr->home_cookie,
15164 + /* RR procedure is over, send a BU */
15165 + mipv6_send_RR_bu(bulentry);
15167 + write_unlock(&bul_lock);
15172 + * mipv6_handle_mh_brr - Binding Refresh Request handler
15173 + * @home: home address
15174 + * @coa: care-of address
15175 + * @cn: source of this packet
15176 + * @mh: pointer to the beginning of the Mobility Header
15178 + * Handles Binding Refresh Request. Packet and offset to option are
15179 + * passed. Returns 0 on success, otherwise negative.
15181 +static int mipv6_handle_mh_brr(struct sk_buff *skb,
15182 + struct in6_addr *home,
15183 + struct in6_addr *unused1,
15184 + struct in6_addr *cn,
15185 + struct in6_addr *unused2,
15186 + struct mipv6_mh *mh)
15188 + struct mipv6_mh_brr *brr = (struct mipv6_mh_brr *)mh->data;
15189 + struct mipv6_bul_entry *binding;
15190 + int msg_len = (mh->length+1) << 3;
15193 + if (msg_len > skb->len)
15196 + opt_len = msg_len - sizeof(*mh) - sizeof(*brr);
15198 + if (opt_len < 0) {
15199 + __u32 pos = (__u32)&mh->length - (__u32)skb->nh.raw;
15200 + icmpv6_send(skb, ICMPV6_PARAMPROB,
15201 + ICMPV6_HDR_FIELD, pos, skb->dev);
15203 + DEBUG(DBG_WARNING, "Mobility Header length less than BRR");
15204 + MIPV6_INC_STATS(n_brr_drop.invalid);
15208 + /* check we know src, else drop */
15209 + write_lock(&bul_lock);
15210 + if ((binding = mipv6_bul_get(cn, home)) == NULL) {
15211 + MIPV6_INC_STATS(n_brr_drop.misc);
15212 + write_unlock(&bul_lock);
15213 + return MH_UNKNOWN_CN;
15216 + MIPV6_INC_STATS(n_brr_rcvd);
15218 + if (opt_len > 0) {
15219 + struct mobopt opts;
15220 + memset(&opts, 0, sizeof(opts));
15221 + if (parse_mo_tlv(brr + 1, opt_len, &opts) < 0) {
15222 + write_unlock(&bul_lock);
15226 + * MIPV6_OPT_AUTH_DATA
15230 + /* must hold bul_lock (write) */
15231 + mipv6_RR_start(home, cn, &binding->coa, binding, binding->delay,
15232 + binding->maxdelay, binding->flags,
15233 + binding->lifetime, binding->ops);
15235 + write_unlock(&bul_lock);
15236 + /* MAY also decide to delete binding and send zero lifetime BU
15237 + with alt-coa set to home address */
15243 + * mipv6_handle_mh_ba - Binding Acknowledgement handler
15244 + * @src: source of this packet
15245 + * @coa: care-of address
15246 + * @home: home address
15247 + * @mh: pointer to the beginning of the Mobility Header
15250 +static int mipv6_handle_mh_ba(struct sk_buff *skb,
15251 + struct in6_addr *home,
15252 + struct in6_addr *coa,
15253 + struct in6_addr *src,
15254 + struct in6_addr *unused,
15255 + struct mipv6_mh *mh)
15257 + struct mipv6_mh_ba *ba = (struct mipv6_mh_ba *)mh->data;
15258 + struct mipv6_bul_entry *binding = NULL;
15259 + struct mobopt opts;
15260 + int msg_len = (mh->length+1) << 3;
15263 + int auth = 1, req_auth = 1, refresh = -1, ifindex = 0;
15264 + u32 lifetime, sequence;
15266 + if (msg_len > skb->len)
15269 + opt_len = msg_len - sizeof(*mh) - sizeof(*ba);
15271 + if (opt_len < 0) {
15272 + __u32 pos = (__u32)&mh->length - (__u32)skb->nh.raw;
15273 + icmpv6_send(skb, ICMPV6_PARAMPROB,
15274 + ICMPV6_HDR_FIELD, pos, skb->dev);
15276 + DEBUG(DBG_WARNING, "Mobility Header length less than BA");
15277 + MIPV6_INC_STATS(n_ba_drop.invalid);
15281 + lifetime = ntohs(ba->lifetime) << 2;
15282 + sequence = ntohs(ba->sequence);
15284 + if (opt_len > 0) {
15285 + memset(&opts, 0, sizeof(opts));
15286 + if (parse_mo_tlv(ba + 1, opt_len, &opts) < 0)
15289 + * MIPV6_OPT_AUTH_DATA, MIPV6_OPT_BR_ADVICE
15291 + if (opts.br_advice)
15292 + refresh = ntohs(opts.br_advice->refresh_interval);
15295 + if (ba->status >= EXPIRED_HOME_NONCE_INDEX &&
15296 + ba->status <= EXPIRED_NONCES)
15299 + write_lock(&bul_lock);
15300 + binding = mipv6_bul_get(src, home);
15302 + DEBUG(DBG_INFO, "No binding, BA dropped.");
15303 + write_unlock(&bul_lock);
15307 + if (opts.auth_data && binding->rr &&
15308 + (mipv6_auth_check(src, coa, (__u8 *)mh, msg_len,
15309 + opts.auth_data, binding->rr->kbu) == 0))
15312 + if (req_auth && binding->rr && !auth) {
15313 + DEBUG(DBG_INFO, "BA Authentication failed.");
15314 + MIPV6_INC_STATS(n_ba_drop.auth);
15315 + write_unlock(&bul_lock);
15316 + return MH_AUTH_FAILED;
15319 + if (ba->status == SEQUENCE_NUMBER_OUT_OF_WINDOW) {
15321 + "Sequence number out of window, setting seq to %d",
15323 + } else if (binding->seq != sequence) {
15324 + DEBUG(DBG_INFO, "BU/BA Sequence Number mismatch %d != %d",
15325 + binding->seq, sequence);
15326 + MIPV6_INC_STATS(n_ba_drop.invalid);
15327 + write_unlock(&bul_lock);
15328 + return MH_SEQUENCE_MISMATCH;
15330 + if (ba->status == EXPIRED_HOME_NONCE_INDEX || ba->status == EXPIRED_NONCES) {
15331 + if (binding->rr) {
15332 + /* Need to resend home test init to CN */
15333 + binding->rr->rr_state |= RR_WAITH;
15334 + mipv6_send_addr_test_init(&binding->home_addr,
15335 + &binding->cn_addr,
15337 + binding->rr->hot_cookie);
15338 + MIPV6_INC_STATS(n_ban_rcvd);
15340 + DEBUG(DBG_WARNING, "Got BA with status EXPIRED_HOME_NONCE_INDEX"
15341 + "for non-RR BU");
15342 + MIPV6_INC_STATS(n_ba_drop.invalid);
15344 + write_unlock(&bul_lock);
15347 + if (ba->status == EXPIRED_CAREOF_NONCE_INDEX || ba->status == EXPIRED_NONCES) {
15348 + if (binding->rr) {
15349 + /* Need to resend care-of test init to CN */
15350 + binding->rr->rr_state |= RR_WAITC;
15351 + mipv6_send_addr_test_init(&binding->coa,
15352 + &binding->cn_addr,
15354 + binding->rr->cot_cookie);
15355 + MIPV6_INC_STATS(n_ban_rcvd);
15357 + DEBUG(DBG_WARNING, "Got BA with status EXPIRED_HOME_CAREOF_INDEX"
15358 + "for non-RR BU");
15359 + MIPV6_INC_STATS(n_ba_drop.invalid);
15361 + write_unlock(&bul_lock);
15364 + write_unlock(&bul_lock);
15366 + if (ba->status >= REASON_UNSPECIFIED) {
15367 + DEBUG(DBG_INFO, "Binding Ack status : %d indicates error", ba->status);
15368 + mipv6_ba_rcvd(ifindex, src, home, sequence, lifetime,
15369 + refresh, ba->status);
15370 + MIPV6_INC_STATS(n_ban_rcvd);
15373 + MIPV6_INC_STATS(n_ba_rcvd);
15374 + if (mipv6_ba_rcvd(ifindex, src, home, ntohs(ba->sequence), lifetime,
15375 + refresh, ba->status)) {
15376 + DEBUG(DBG_WARNING, "mipv6_ba_rcvd failed");
15383 + * mipv6_handle_mh_be - Binding Error handler
15384 + * @cn: source of this packet
15385 + * @coa: care-of address
15386 + * @home: home address
15387 + * @mh: pointer to the beginning of the Mobility Header
15391 +static int mipv6_handle_mh_be(struct sk_buff *skb,
15392 + struct in6_addr *home,
15393 + struct in6_addr *coa,
15394 + struct in6_addr *cn,
15395 + struct in6_addr *unused,
15396 + struct mipv6_mh *mh)
15398 + struct mipv6_mh_be *be = (struct mipv6_mh_be *)mh->data;
15399 + int msg_len = (mh->length+1) << 3;
15401 + struct in6_addr *hoa;
15402 + struct bul_inval_args args;
15406 + if (msg_len > skb->len)
15409 + opt_len = msg_len - sizeof(*mh) - sizeof(*be);
15411 + if (opt_len < 0) {
15412 + __u32 pos = (__u32)&mh->length - (__u32)skb->nh.raw;
15413 + icmpv6_send(skb, ICMPV6_PARAMPROB,
15414 + ICMPV6_HDR_FIELD, pos, skb->dev);
15416 + DEBUG(DBG_WARNING, "Mobility Header length less than BE");
15417 + MIPV6_INC_STATS(n_be_drop.invalid);
15422 + if (!ipv6_addr_any(&be->home_addr))
15423 + hoa = &be->home_addr;
15427 + MIPV6_INC_STATS(n_be_rcvd);
15429 + args.all_rr_states = 0;
15433 + switch (be->status) {
15434 + case 1: /* Home Address Option used without a binding */
15435 + /* Get ULP information about CN-MN communication. If
15436 + nothing in progress, MUST delete. Otherwise MAY
15438 + args.all_rr_states = 1;
15439 + case 2: /* Received unknown MH type */
15440 + /* If not expecting ack, SHOULD ignore. If MH
15441 + extension in use, stop it. If not, stop RO for
15443 + write_lock(&bul_lock);
15444 + mipv6_bul_iterate(mn_bul_invalidate, &args);
15445 + write_unlock(&bul_lock);
15453 + * mipv6_bu_rate_limit() : Takes a bulentry, a COA and 'flags' to check
15454 + * whether BU being sent is for Home Registration or not.
15456 + * If the number of BU's sent is fewer than MAX_FAST_UPDATES, this BU
15457 + * is allowed to be sent at the MAX_UPDATE_RATE.
15458 + * If the number of BU's sent is greater than or equal to MAX_FAST_UPDATES,
15459 + * this BU is allowed to be sent at the SLOW_UPDATE_RATE.
15461 + * Assumption : This function is not re-entrant. and the caller holds the
15462 + * bulentry lock (by calling mipv6_bul_get()) to stop races with other
15463 + * CPU's executing this same function.
15465 + * Side-Effects. Either of the following could on success :
15466 + * 1. Sets consecutive_sends to 1 if the entry is a Home agent
15467 + * registration or the COA has changed.
15468 + * 2. Increments consecutive_sends if the number of BU's sent so
15469 + * far is less than MAX_FAST_UPDATES, and this BU is being sent
15470 + * atleast MAX_UPDATE_RATE after previous one.
15472 + * Return Value : 0 on Success, -1 on Failure
15474 +static int mipv6_bu_rate_limit(struct mipv6_bul_entry *bulentry,
15475 + struct in6_addr *coa, __u8 flags)
15477 + if ((flags & MIPV6_BU_F_HOME) || ipv6_addr_cmp(&bulentry->coa, coa)) {
15478 + /* Home Agent Registration or different COA - restart from 1 */
15479 + bulentry->consecutive_sends = 1;
15483 + if (bulentry->consecutive_sends < MAX_FAST_UPDATES) {
15484 + /* First MAX_FAST_UPDATES can be sent at MAX_UPDATE_RATE */
15485 + if (jiffies - bulentry->lastsend < MAX_UPDATE_RATE * HZ) {
15488 + bulentry->consecutive_sends ++;
15490 + /* Remaining updates SHOULD be sent at SLOW_UPDATE_RATE */
15491 + if (jiffies - bulentry->lastsend < SLOW_UPDATE_RATE * HZ) {
15494 + /* Don't inc 'consecutive_sends' to avoid overflow to zero */
15496 + /* OK to send a BU */
15501 + * mipv6_send_bu - send a Binding Update
15502 + * @saddr: source address for BU
15503 + * @daddr: destination address for BU
15504 + * @coa: care-of address for MN
15505 + * @initdelay: initial BA wait timeout
15506 + * @maxackdelay: maximum BA wait timeout
15507 + * @exp: exponention back off
15508 + * @flags: flags for BU
15509 + * @lifetime: granted lifetime for binding
15510 + * @ops: mobility options
15512 + * Send a binding update. 'flags' may contain any of %MIPV6_BU_F_ACK,
15513 + * %MIPV6_BU_F_HOME, %MIPV6_BU_F_ROUTER bitwise ORed. If
15514 + * %MIPV6_BU_F_ACK is included retransmission will be attempted until
15515 + * the update has been acknowledged. Retransmission is done if no
15516 + * acknowledgement is received within @initdelay seconds. @exp
15517 + * specifies whether to use exponential backoff (@exp != 0) or linear
15518 + * backoff (@exp == 0). For exponential backoff the time to wait for
15519 + * an acknowledgement is doubled on each retransmission until a delay
15520 + * of @maxackdelay, after which retransmission is no longer attempted.
15521 + * For linear backoff the delay is kept constant and @maxackdelay
15522 + * specifies the maximum number of retransmissions instead. If
15523 + * sub-options are present ops must contain all sub-options to be
15524 + * added. On a mobile node, use the mobile node's home address for
15525 + * @saddr. Returns 0 on success, non-zero on failure.
15527 + * Caller may not hold @bul_lock.
15529 +int mipv6_send_bu(struct in6_addr *saddr, struct in6_addr *daddr,
15530 + struct in6_addr *coa, u32 initdelay,
15531 + u32 maxackdelay, u8 exp, u8 flags, u32 lifetime,
15532 + struct mipv6_mh_opt *ops)
15537 + int (*callback)(struct mipv6_bul_entry *);
15538 + __u32 callback_time;
15539 + struct mipv6_bul_entry *bulentry;
15541 + /* First a sanity check: don't send BU to local addresses */
15542 + if(ipv6_chk_addr(daddr, NULL)) {
15543 + DEBUG(DBG_ERROR, "BUG: Trying to send BU to local address");
15546 + DEBUG(DBG_INFO, "Sending BU to CN %x:%x:%x:%x:%x:%x:%x:%x "
15547 + "for home address %x:%x:%x:%x:%x:%x:%x:%x",
15548 + NIPV6ADDR(daddr), NIPV6ADDR(saddr));
15550 + if ((bulentry = mipv6_bul_get(daddr, saddr)) != NULL) {
15551 + if (bulentry->state == ACK_ERROR) {
15553 + * Don't send any more BU's to nodes which don't
15554 + * understanding one.
15556 + DEBUG(DBG_INFO, "Not sending BU to node which doesn't"
15557 + " understand one");
15560 + if (mipv6_bu_rate_limit(bulentry, coa, flags) < 0) {
15561 + DEBUG(DBG_DATADUMP, "Limiting BU sent.");
15566 + switch (mipv6_rr_state(bulentry, saddr, coa, flags)) {
15567 + case INPROGRESS_RR:
15568 + /* We are already doing RR, don't do BU at this time, it is
15569 + * done automatically later */
15570 + DEBUG(DBG_INFO, "RR in progress not sending BU");
15574 + /* Just do RR and return, BU is done automatically later */
15575 + DEBUG(DBG_INFO, "starting RR" );
15576 + mipv6_RR_start(saddr, daddr, coa, bulentry, initdelay,
15577 + maxackdelay, flags, lifetime, ops);
15581 + DEBUG(DBG_DATADUMP, "No RR necessary" );
15587 + seq = bulentry->seq + 1;
15589 + /* Add to binding update list */
15591 + if (flags & MIPV6_BU_F_ACK) {
15592 + DEBUG(DBG_INFO, "Setting bul callback to bul_resend_exp");
15593 + /* Send using exponential backoff */
15594 + state = RESEND_EXP;
15595 + callback = bul_resend_exp;
15596 + callback_time = initdelay;
15598 + DEBUG(DBG_INFO, "Setting bul callback to bul_entry_expired");
15599 + /* No acknowledgement/resending required */
15600 + state = ACK_OK; /* pretend we got an ack */
15601 + callback = bul_entry_expired;
15602 + callback_time = lifetime;
15605 + /* BU only for the home address */
15606 + /* We must hold bul_lock (write) while calling add */
15607 + if ((bulentry = mipv6_bul_add(daddr, saddr, coa, lifetime, seq,
15608 + flags, callback, callback_time,
15609 + state, initdelay, maxackdelay, ops,
15610 + NULL)) == NULL) {
15611 + DEBUG(DBG_INFO, "couldn't update BUL");
15614 + ret = send_bu_msg(bulentry);
15619 +int __init mipv6_mh_mn_init(void)
15621 + mipv6_mh_register(MIPV6_MH_HOT, mipv6_handle_mh_HC_test);
15622 + mipv6_mh_register(MIPV6_MH_COT, mipv6_handle_mh_HC_test);
15623 + mipv6_mh_register(MIPV6_MH_BA, mipv6_handle_mh_ba);
15624 + mipv6_mh_register(MIPV6_MH_BRR, mipv6_handle_mh_brr);
15625 + mipv6_mh_register(MIPV6_MH_BE, mipv6_handle_mh_be);
15630 +void __exit mipv6_mh_mn_exit(void)
15632 + mipv6_mh_unregister(MIPV6_MH_HOT);
15633 + mipv6_mh_unregister(MIPV6_MH_COT);
15634 + mipv6_mh_unregister(MIPV6_MH_BA);
15635 + mipv6_mh_unregister(MIPV6_MH_BRR);
15636 + mipv6_mh_unregister(MIPV6_MH_BE);
15639 +++ linux-2.4.27/net/ipv6/mobile_ip6/module_cn.c
15642 + * Mobile IPv6 Common Module
15645 + * Sami Kivisaari <skivisaa@cc.hut.fi>
15646 + * Antti Tuominen <ajtuomin@tml.hut.fi>
15650 + * This program is free software; you can redistribute it and/or
15651 + * modify it under the terms of the GNU General Public License
15652 + * as published by the Free Software Foundation; either version
15653 + * 2 of the License, or (at your option) any later version.
15656 +#include <linux/config.h>
15657 +#include <linux/module.h>
15658 +#include <linux/init.h>
15660 +#ifdef CONFIG_SYSCTL
15661 +#include <linux/sysctl.h>
15662 +#endif /* CONFIG_SYSCTL */
15664 +#include <net/mipglue.h>
15666 +#include "bcache.h"
15667 +#include "mipv6_icmp.h"
15668 +#include "stats.h"
15669 +#include "mobhdr.h"
15670 +#include "exthdrs.h"
15672 +int mipv6_debug = 1;
15674 +#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
15675 +MODULE_AUTHOR("MIPL Team");
15676 +MODULE_DESCRIPTION("Mobile IPv6");
15677 +MODULE_LICENSE("GPL");
15678 +MODULE_PARM(mipv6_debug, "i");
15681 +#include "config.h"
15683 +struct mip6_func mip6_fn;
15684 +struct mip6_conf mip6node_cnf = {
15685 + capabilities: CAP_CN,
15686 + accept_ret_rout: 1,
15687 + max_rtr_reachable_time: 0,
15688 + eager_cell_switching: 0,
15689 + max_num_tunnels: 0,
15690 + min_num_tunnels: 0,
15691 + binding_refresh_advice: 0,
15697 +#define MIPV6_BCACHE_SIZE 128
15699 +/**********************************************************************
15701 + * MIPv6 CN Module Init / Cleanup
15703 + **********************************************************************/
15705 +#ifdef CONFIG_SYSCTL
15706 +/* Sysctl table */
15707 +ctl_table mipv6_mobility_table[] = {
15708 + {NET_IPV6_MOBILITY_DEBUG, "debuglevel",
15709 + &mipv6_debug, sizeof(int), 0644, NULL,
15711 + {NET_IPV6_MOBILITY_RETROUT, "accept_return_routability",
15712 + &mip6node_cnf.accept_ret_rout, sizeof(int), 0644, NULL,
15716 +ctl_table mipv6_table[] = {
15717 + {NET_IPV6_MOBILITY, "mobility", NULL, 0, 0555, mipv6_mobility_table},
15721 +static struct ctl_table_header *mipv6_sysctl_header;
15722 +static struct ctl_table mipv6_net_table[];
15723 +static struct ctl_table mipv6_root_table[];
15725 +ctl_table mipv6_net_table[] = {
15726 + {NET_IPV6, "ipv6", NULL, 0, 0555, mipv6_table},
15730 +ctl_table mipv6_root_table[] = {
15731 + {CTL_NET, "net", NULL, 0, 0555, mipv6_net_table},
15734 +#endif /* CONFIG_SYSCTL */
15736 +extern void mipv6_rr_init(void);
15738 +/* Initialize the module */
15739 +static int __init mip6_init(void)
15743 + printk(KERN_INFO "MIPL Mobile IPv6 for Linux Correspondent Node %s (%s)\n",
15744 + MIPLVERSION, MIPV6VERSION);
15746 +#ifdef CONFIG_IPV6_MOBILITY_DEBUG
15747 + printk(KERN_INFO "Debug-level: %d\n", mipv6_debug);
15750 + if ((err = mipv6_bcache_init(MIPV6_BCACHE_SIZE)) < 0)
15751 + goto bcache_fail;
15753 + if ((err = mipv6_icmpv6_init()) < 0)
15756 + if ((err = mipv6_stats_init()) < 0)
15760 +#ifdef CONFIG_SYSCTL
15761 + mipv6_sysctl_header = register_sysctl_table(mipv6_root_table, 0);
15764 + if ((err = mipv6_mh_common_init()) < 0)
15767 + MIPV6_SETCALL(mipv6_modify_txoptions, mipv6_modify_txoptions);
15769 + MIPV6_SETCALL(mipv6_handle_homeaddr, mipv6_handle_homeaddr);
15770 + MIPV6_SETCALL(mipv6_icmp_swap_addrs, mipv6_icmp_swap_addrs);
15775 +#ifdef CONFIG_SYSCTL
15776 + unregister_sysctl_table(mipv6_sysctl_header);
15778 + mipv6_stats_exit();
15780 + mipv6_icmpv6_exit();
15782 + mipv6_bcache_exit();
15786 +module_init(mip6_init);
15789 +/* Cleanup module */
15790 +static void __exit mip6_exit(void)
15792 + printk(KERN_INFO "mip6_base.o exiting.\n");
15793 +#ifdef CONFIG_SYSCTL
15794 + unregister_sysctl_table(mipv6_sysctl_header);
15797 + /* Invalidate all custom kernel hooks. No need to do this
15798 + separately for all hooks. */
15799 + mipv6_invalidate_calls();
15801 + mipv6_mh_common_exit();
15802 + mipv6_stats_exit();
15803 + mipv6_icmpv6_exit();
15804 + mipv6_bcache_exit();
15806 +module_exit(mip6_exit);
15807 +#endif /* MODULE */
15809 +++ linux-2.4.27/net/ipv6/mobile_ip6/module_ha.c
15812 + * Mobile IPv6 Home Agent Module
15815 + * Sami Kivisaari <skivisaa@cc.hut.fi>
15816 + * Antti Tuominen <ajtuomin@tml.hut.fi>
15820 + * This program is free software; you can redistribute it and/or
15821 + * modify it under the terms of the GNU General Public License
15822 + * as published by the Free Software Foundation; either version
15823 + * 2 of the License, or (at your option) any later version.
15826 +#include <linux/config.h>
15827 +#include <linux/module.h>
15828 +#include <linux/init.h>
15830 +#ifdef CONFIG_SYSCTL
15831 +#include <linux/sysctl.h>
15832 +#endif /* CONFIG_SYSCTL */
15834 +#include <net/mipglue.h>
15835 +#include <net/addrconf.h>
15837 +#include "mobhdr.h"
15838 +#include "tunnel_ha.h"
15840 +#include "halist.h"
15841 +#include "mipv6_icmp.h"
15842 +//#include "prefix.h"
15843 +#include "bcache.h"
15844 +#include "debug.h"
15846 +int mipv6_use_auth = 0;
15848 +#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
15849 +MODULE_AUTHOR("MIPL Team");
15850 +MODULE_DESCRIPTION("Mobile IPv6 Home Agent");
15851 +MODULE_LICENSE("GPL");
15854 +#include "config.h"
15856 +#define MIPV6_HALIST_SIZE 128
15857 +struct ha_info_opt {
15865 + * Called from ndisc.c's router_discovery.
15867 +static int mipv6_ha_ra_rcv(struct sk_buff *skb, struct ndisc_options *ndopts)
15869 + unsigned int ha_info_pref = 0, ha_info_lifetime;
15870 + int ifi = ((struct inet6_skb_parm *)skb->cb)->iif;
15871 + struct ra_msg *ra = (struct ra_msg *) skb->h.raw;
15872 + struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
15873 + struct in6_addr ll_addr;
15875 + struct in6_addr prefix;
15877 + struct hal *next;
15882 + ha_info_lifetime = ntohs(ra->icmph.icmp6_rt_lifetime);
15883 + ipv6_addr_copy(&ll_addr, saddr);
15885 + if (ndopts->nd_opts_hai) {
15886 + struct ha_info_opt *hai = (struct ha_info_opt *)ndopts->nd_opts_hai;
15887 + ha_info_pref = ntohs(hai->pref);
15888 + ha_info_lifetime = ntohs(hai->ltime);
15889 + DEBUG(DBG_DATADUMP,
15890 + "received home agent info with preference : %d and lifetime : %d",
15891 + ha_info_pref, ha_info_lifetime);
15893 + if (ndopts->nd_opts_pi) {
15894 + struct nd_opt_hdr *p;
15895 + for (p = ndopts->nd_opts_pi;
15897 + p = ndisc_next_option(p, ndopts->nd_opts_pi_end)) {
15898 + struct prefix_info *pinfo;
15900 + pinfo = (struct prefix_info *) p;
15902 + if (pinfo->router_address) {
15903 + DEBUG(DBG_DATADUMP, "Adding router address to "
15905 + /* If RA has H bit set and Prefix Info
15906 + * Option R bit set, queue this
15907 + * address to be added to Home Agents
15910 + if (ipv6_addr_type(&pinfo->prefix) &
15911 + IPV6_ADDR_LINKLOCAL)
15913 + if (!ra->icmph.icmp6_home_agent || !ha_info_lifetime) {
15914 + mipv6_halist_delete(&pinfo->prefix);
15918 + mipv6_halist_add(ifi, &pinfo->prefix,
15919 + pinfo->prefix_len, &ll_addr,
15920 + ha_info_pref, ha_info_lifetime);
15927 + return MIPV6_ADD_RTR;
15930 +/**********************************************************************
15932 + * MIPv6 Module Init / Cleanup
15934 + **********************************************************************/
15936 +#ifdef CONFIG_SYSCTL
15937 +/* Sysctl table */
15939 +mipv6_max_tnls_sysctl(ctl_table *, int, struct file *, void *, size_t *);
15942 +mipv6_min_tnls_sysctl(ctl_table *, int, struct file *, void *, size_t *);
15944 +int max_adv = ~(u16)0;
15946 +ctl_table mipv6_mobility_table[] = {
15947 + {NET_IPV6_MOBILITY_BINDING_REFRESH, "binding_refresh_advice",
15948 + &mip6node_cnf.binding_refresh_advice, sizeof(int), 0644, NULL,
15949 + &proc_dointvec_minmax, &sysctl_intvec, 0, &min_zero, &max_adv},
15951 + {NET_IPV6_MOBILITY_MAX_TNLS, "max_tnls", &mipv6_max_tnls, sizeof(int),
15952 + 0644, NULL, &mipv6_max_tnls_sysctl},
15953 + {NET_IPV6_MOBILITY_MIN_TNLS, "min_tnls", &mipv6_min_tnls, sizeof(int),
15954 + 0644, NULL, &mipv6_min_tnls_sysctl},
15957 +ctl_table mipv6_table[] = {
15958 + {NET_IPV6_MOBILITY, "mobility", NULL, 0, 0555, mipv6_mobility_table},
15962 +static struct ctl_table_header *mipv6_sysctl_header;
15963 +static struct ctl_table mipv6_net_table[];
15964 +static struct ctl_table mipv6_root_table[];
15966 +ctl_table mipv6_net_table[] = {
15967 + {NET_IPV6, "ipv6", NULL, 0, 0555, mipv6_table},
15971 +ctl_table mipv6_root_table[] = {
15972 + {CTL_NET, "net", NULL, 0, 0555, mipv6_net_table},
15975 +#endif /* CONFIG_SYSCTL */
15977 +extern void mipv6_check_dad(struct in6_addr *haddr);
15978 +extern void mipv6_dad_init(void);
15979 +extern void mipv6_dad_exit(void);
15980 +extern int mipv6_forward(struct sk_buff *);
15982 +/* Initialize the module */
15983 +static int __init mip6_ha_init(void)
15987 + printk(KERN_INFO "MIPL Mobile IPv6 for Linux Home Agent %s (%s)\n",
15988 + MIPLVERSION, MIPV6VERSION);
15989 + mip6node_cnf.capabilities = CAP_CN | CAP_HA;
15991 + mip6_fn.icmpv6_dhaad_rep_rcv = mipv6_icmpv6_no_rcv;
15992 + mip6_fn.icmpv6_dhaad_req_rcv = mipv6_icmpv6_rcv_dhaad_req;
15993 + mip6_fn.icmpv6_pfxadv_rcv = mipv6_icmpv6_no_rcv;
15994 + mip6_fn.icmpv6_pfxsol_rcv = mipv6_icmpv6_no_rcv;
15995 + mip6_fn.icmpv6_paramprob_rcv = mipv6_icmpv6_no_rcv;
15997 +#ifdef CONFIG_IPV6_MOBILITY_DEBUG
15998 + printk(KERN_INFO "Debug-level: %d\n", mipv6_debug);
16001 +#ifdef CONFIG_SYSCTL
16002 + mipv6_sysctl_header = register_sysctl_table(mipv6_root_table, 0);
16004 + mipv6_initialize_tunnel();
16006 + if ((err = mipv6_ha_init()) < 0)
16009 + MIPV6_SETCALL(mipv6_ra_rcv, mipv6_ha_ra_rcv);
16010 + MIPV6_SETCALL(mipv6_forward, mipv6_forward);
16011 + mipv6_dad_init();
16012 + MIPV6_SETCALL(mipv6_check_dad, mipv6_check_dad);
16014 + if ((err = mipv6_halist_init(MIPV6_HALIST_SIZE)) < 0)
16015 + goto halist_fail;
16017 +// mipv6_initialize_pfx_icmpv6();
16022 + mipv6_dad_exit();
16025 + mipv6_shutdown_tunnel();
16027 + mip6_fn.icmpv6_dhaad_rep_rcv = NULL;
16028 + mip6_fn.icmpv6_dhaad_req_rcv = NULL;
16029 + mip6_fn.icmpv6_pfxadv_rcv = NULL;
16030 + mip6_fn.icmpv6_pfxsol_rcv = NULL;
16031 + mip6_fn.icmpv6_paramprob_rcv = NULL;
16033 + MIPV6_RESETCALL(mipv6_ra_rcv);
16034 + MIPV6_RESETCALL(mipv6_forward);
16035 + MIPV6_RESETCALL(mipv6_check_dad);
16037 +#ifdef CONFIG_SYSCTL
16038 + unregister_sysctl_table(mipv6_sysctl_header);
16042 +module_init(mip6_ha_init);
16045 +/* Cleanup module */
16046 +static void __exit mip6_ha_exit(void)
16048 + printk(KERN_INFO "mip6_ha.o exiting.\n");
16049 + mip6node_cnf.capabilities &= ~(int)CAP_HA;
16051 + mipv6_bcache_cleanup(HOME_REGISTRATION);
16053 + MIPV6_RESETCALL(mipv6_ra_rcv);
16054 + MIPV6_RESETCALL(mipv6_forward);
16055 + MIPV6_RESETCALL(mipv6_check_dad);
16057 + mipv6_halist_exit();
16058 +// mipv6_shutdown_pfx_icmpv6();
16060 + mip6_fn.icmpv6_dhaad_rep_rcv = NULL;
16061 + mip6_fn.icmpv6_dhaad_req_rcv = NULL;
16062 + mip6_fn.icmpv6_pfxadv_rcv = NULL;
16063 + mip6_fn.icmpv6_pfxsol_rcv = NULL;
16064 + mip6_fn.icmpv6_paramprob_rcv = NULL;
16066 + mipv6_dad_exit();
16068 + mipv6_shutdown_tunnel();
16069 +#ifdef CONFIG_SYSCTL
16070 + unregister_sysctl_table(mipv6_sysctl_header);
16073 +module_exit(mip6_ha_exit);
16074 +#endif /* MODULE */
16076 +++ linux-2.4.27/net/ipv6/mobile_ip6/module_mn.c
16079 + * Mobile IPv6 Mobile Node Module
16082 + * Sami Kivisaari <skivisaa@cc.hut.fi>
16083 + * Antti Tuominen <ajtuomin@tml.hut.fi>
16087 + * This program is free software; you can redistribute it and/or
16088 + * modify it under the terms of the GNU General Public License
16089 + * as published by the Free Software Foundation; either version
16090 + * 2 of the License, or (at your option) any later version.
16093 +#include <linux/config.h>
16094 +#include <linux/module.h>
16095 +#include <linux/init.h>
16097 +#ifdef CONFIG_SYSCTL
16098 +#include <linux/sysctl.h>
16099 +#endif /* CONFIG_SYSCTL */
16101 +#include <net/mipglue.h>
16103 +extern int mipv6_debug;
16104 +int mipv6_use_auth = 0;
16106 +#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
16107 +MODULE_AUTHOR("MIPL Team");
16108 +MODULE_DESCRIPTION("Mobile IPv6 Mobile Node");
16109 +MODULE_LICENSE("GPL");
16110 +MODULE_PARM(mipv6_debug, "i");
16113 +#include "config.h"
16115 +#include "mobhdr.h"
16117 +#include "mipv6_icmp.h"
16118 +//#include "prefix.h"
16120 +/* TODO: These will go as soon as we get rid of the last two ioctls */
16121 +extern int mipv6_ioctl_mn_init(void);
16122 +extern void mipv6_ioctl_mn_exit(void);
16124 +/**********************************************************************
16126 + * MIPv6 Module Init / Cleanup
16128 + **********************************************************************/
16130 +#ifdef CONFIG_SYSCTL
16131 +/* Sysctl table */
16133 +extern int max_rtr_reach_time;
16134 +extern int eager_cell_switching;
16136 +static int max_reach = 1000;
16137 +static int min_reach = 1;
16138 +static int max_one = 1;
16139 +static int min_zero = 0;
16142 +mipv6_mdetect_mech_sysctl(ctl_table *, int, struct file *, void *, size_t *);
16145 +mipv6_router_reach_sysctl(ctl_table *, int, struct file *, void *, size_t *);
16147 +ctl_table mipv6_mobility_table[] = {
16148 + {NET_IPV6_MOBILITY_BU_F_LLADDR, "bu_flag_lladdr",
16149 + &mip6node_cnf.bu_lladdr, sizeof(int), 0644, NULL,
16150 + &proc_dointvec_minmax, &sysctl_intvec, 0, &min_zero, &max_one},
16151 + {NET_IPV6_MOBILITY_BU_F_KEYMGM, "bu_flag_keymgm",
16152 + &mip6node_cnf.bu_keymgm, sizeof(int), 0644, NULL,
16153 + &proc_dointvec_minmax, &sysctl_intvec, 0, &min_zero, &max_one},
16154 + {NET_IPV6_MOBILITY_BU_F_CN_ACK, "bu_flag_cn_ack",
16155 + &mip6node_cnf.bu_cn_ack, sizeof(int), 0644, NULL,
16156 + &proc_dointvec_minmax, &sysctl_intvec, 0, &min_zero, &max_one},
16158 + {NET_IPV6_MOBILITY_ROUTER_REACH, "max_router_reachable_time",
16159 + &max_rtr_reach_time, sizeof(int), 0644, NULL,
16160 + &proc_dointvec_minmax, &sysctl_intvec, 0, &min_reach, &max_reach},
16162 + {NET_IPV6_MOBILITY_MDETECT_MECHANISM, "eager_cell_switching",
16163 + &eager_cell_switching, sizeof(int), 0644, NULL,
16164 + &proc_dointvec_minmax, &sysctl_intvec, 0, &min_zero, &max_one},
16168 +ctl_table mipv6_table[] = {
16169 + {NET_IPV6_MOBILITY, "mobility", NULL, 0, 0555, mipv6_mobility_table},
16173 +static struct ctl_table_header *mipv6_sysctl_header;
16174 +static struct ctl_table mipv6_net_table[];
16175 +static struct ctl_table mipv6_root_table[];
16177 +ctl_table mipv6_net_table[] = {
16178 + {NET_IPV6, "ipv6", NULL, 0, 0555, mipv6_table},
16182 +ctl_table mipv6_root_table[] = {
16183 + {CTL_NET, "net", NULL, 0, 0555, mipv6_net_table},
16186 +#endif /* CONFIG_SYSCTL */
16188 +/* Initialize the module */
16189 +static int __init mip6_mn_init(void)
16193 + printk(KERN_INFO "MIPL Mobile IPv6 for Linux Mobile Node %s (%s)\n",
16194 + MIPLVERSION, MIPV6VERSION);
16195 + mip6node_cnf.capabilities = CAP_CN | CAP_MN;
16197 +#ifdef CONFIG_IPV6_MOBILITY_DEBUG
16198 + printk(KERN_INFO "Debug-level: %d\n", mipv6_debug);
16201 +#ifdef CONFIG_SYSCTL
16202 + mipv6_sysctl_header = register_sysctl_table(mipv6_root_table, 0);
16204 + if ((err = mipv6_mn_init()) < 0)
16207 + mipv6_mh_mn_init();
16209 + mip6_fn.icmpv6_dhaad_rep_rcv = mipv6_icmpv6_rcv_dhaad_rep;
16210 + mip6_fn.icmpv6_dhaad_req_rcv = mipv6_icmpv6_no_rcv;
16211 + mip6_fn.icmpv6_pfxadv_rcv = mipv6_icmpv6_no_rcv;
16212 + mip6_fn.icmpv6_pfxsol_rcv = mipv6_icmpv6_no_rcv;
16213 + mip6_fn.icmpv6_paramprob_rcv = mipv6_icmpv6_rcv_paramprob;
16215 +// mipv6_initialize_pfx_icmpv6();
16217 + if ((err = mipv6_ioctl_mn_init()) < 0)
16223 +// mipv6_shutdown_pfx_icmpv6();
16225 + mip6_fn.icmpv6_dhaad_rep_rcv = NULL;
16226 + mip6_fn.icmpv6_dhaad_req_rcv = NULL;
16227 + mip6_fn.icmpv6_pfxadv_rcv = NULL;
16228 + mip6_fn.icmpv6_pfxsol_rcv = NULL;
16229 + mip6_fn.icmpv6_paramprob_rcv = NULL;
16231 + mipv6_mh_mn_exit();
16234 +#ifdef CONFIG_SYSCTL
16235 + unregister_sysctl_table(mipv6_sysctl_header);
16239 +module_init(mip6_mn_init);
16242 +/* Cleanup module */
16243 +static void __exit mip6_mn_exit(void)
16245 + printk(KERN_INFO "mip6_mn.o exiting.\n");
16246 + mip6node_cnf.capabilities &= ~(int)CAP_MN;
16248 + mipv6_ioctl_mn_exit();
16249 +// mipv6_shutdown_pfx_icmpv6();
16251 + mip6_fn.icmpv6_dhaad_rep_rcv = NULL;
16252 + mip6_fn.icmpv6_dhaad_req_rcv = NULL;
16253 + mip6_fn.icmpv6_pfxadv_rcv = NULL;
16254 + mip6_fn.icmpv6_pfxsol_rcv = NULL;
16255 + mip6_fn.icmpv6_paramprob_rcv = NULL;
16259 +/* common cleanup */
16260 +#ifdef CONFIG_SYSCTL
16261 + unregister_sysctl_table(mipv6_sysctl_header);
16264 +module_exit(mip6_mn_exit);
16265 +#endif /* MODULE */
16267 +++ linux-2.4.27/net/ipv6/mobile_ip6/multiaccess_ctl.c
16270 + * 2001 (c) Oy L M Ericsson Ab
16272 + * Author: NomadicLab / Ericsson Research <ipv6@nomadiclab.com>
16279 + * Vertical hand-off information manager
16282 +#include <linux/netdevice.h>
16283 +#include <linux/in6.h>
16284 +#include <linux/module.h>
16285 +#include <linux/init.h>
16286 +#include <linux/proc_fs.h>
16287 +#include <linux/string.h>
16288 +#include <linux/kernel.h>
16289 +#include <asm/io.h>
16290 +#include <asm/uaccess.h>
16291 +#include <linux/list.h>
16292 +#include "multiaccess_ctl.h"
16293 +#include "debug.h"
16296 + * Local variables
16298 +static LIST_HEAD(if_list);
16300 +/* Internal interface information list */
16301 +struct ma_if_info {
16302 + struct list_head list;
16303 + int interface_id;
16309 + * ma_ctl_get_preference - get preference value for interface
16310 + * @ifi: interface index
16312 + * Returns integer value preference for given interface.
16314 +int ma_ctl_get_preference(int ifi)
16316 + struct list_head *lh;
16317 + struct ma_if_info *info;
16320 + list_for_each(lh, &if_list) {
16321 + info = list_entry(lh, struct ma_if_info, list);
16322 + if (info->interface_id == ifi) {
16323 + pref = info->preference;
16330 + * ma_ctl_get_preference - get preference value for interface
16331 + * @ifi: interface index
16333 + * Returns integer value interface index for interface with highest preference.
16335 +int ma_ctl_get_preferred_if(void)
16337 + struct list_head *lh;
16338 + struct ma_if_info *info, *pref_if = NULL;
16340 + list_for_each(lh, &if_list) {
16341 + info = list_entry(lh, struct ma_if_info, list);
16342 + if (!pref_if || (info->preference > pref_if->preference)) {
16346 + if (pref_if) return pref_if->interface_id;
16350 + * ma_ctl_set_preference - set preference for interface
16351 + * @arg: ioctl args
16353 + * Sets preference of an existing interface (called by ioctl).
16355 +void ma_ctl_set_preference(unsigned long arg)
16357 + struct list_head *lh;
16358 + struct ma_if_info *info;
16359 + struct ma_if_uinfo uinfo;
16361 + memset(&uinfo, 0, sizeof(struct ma_if_uinfo));
16362 + if (copy_from_user(&uinfo, (struct ma_if_uinfo *)arg,
16363 + sizeof(struct ma_if_uinfo)) < 0) {
16364 + DEBUG(DBG_WARNING, "copy_from_user failed");
16368 + /* check if the interface exists */
16369 + list_for_each(lh, &if_list) {
16370 + info = list_entry(lh, struct ma_if_info, list);
16371 + if (info->interface_id == uinfo.interface_id) {
16372 + info->preference = uinfo.preference;
16379 + * ma_ctl_add_iface - add new interface to list
16380 + * @if_index: interface index
16382 + * Adds new interface entry to preference list. Preference is set to
16383 + * the same value as @if_index. Entry @status is set to
16384 + * %MA_IFACE_NOT_USED.
16386 +void ma_ctl_add_iface(int if_index)
16388 + struct list_head *lh;
16389 + struct ma_if_info *info;
16393 + /* check if the interface already exists */
16394 + list_for_each(lh, &if_list) {
16395 + info = list_entry(lh, struct ma_if_info, list);
16396 + if (info->interface_id == if_index) {
16397 + info->status = MA_IFACE_NOT_USED;
16398 + info->preference = if_index;
16403 + info = kmalloc(sizeof(struct ma_if_info), GFP_ATOMIC);
16404 + if (info == NULL) {
16405 + DEBUG(DBG_ERROR, "Out of memory");
16408 + memset(info, 0, sizeof(struct ma_if_info));
16409 + info->interface_id = if_index;
16410 + info->preference = if_index;
16411 + info->status = MA_IFACE_NOT_USED;
16412 + list_add(&info->list, &if_list);
16416 + * ma_ctl_del_iface - remove entry from the list
16417 + * @if_index: interface index
16419 + * Removes entry for interface @if_index from preference list.
16421 +int ma_ctl_del_iface(int if_index)
16423 + struct list_head *lh, *next;
16424 + struct ma_if_info *info;
16428 + /* if the iface exists, change availability to 0 */
16429 + list_for_each_safe(lh, next, &if_list) {
16430 + info = list_entry(lh, struct ma_if_info, list);
16431 + if (info->interface_id == if_index) {
16432 + list_del(&info->list);
16442 + * ma_ctl_upd_iface - update entry (and list)
16443 + * @if_index: interface to update
16444 + * @status: new status for interface
16445 + * @change_if_index: new interface
16447 + * Updates @if_index entry on preference list. Entry status is set to
16448 + * @status. If new @status is %MA_IFACE_CURRENT, updates list to have
16449 + * only one current device. If @status is %MA_IFACE_NOT_PRESENT,
16450 + * entry is deleted and further if entry had %MA_IFACE_CURRENT set,
16451 + * new current device is looked up and returned in @change_if_index.
16452 + * New preferred interface is also returned if current device changes
16453 + * to %MA_IFACE_NOT_USED. Returns 0 on success, otherwise negative.
16455 +int ma_ctl_upd_iface(int if_index, int status, int *change_if_index)
16457 + struct list_head *lh, *tmp;
16458 + struct ma_if_info *info, *pref = NULL;
16463 + *change_if_index = 0;
16465 + /* check if the interface exists */
16466 + list_for_each_safe(lh, tmp, &if_list) {
16467 + info = list_entry(lh, struct ma_if_info, list);
16468 + if (status == MA_IFACE_NOT_PRESENT) {
16469 + if (info->interface_id == if_index) {
16470 + list_del_init(&info->list);
16475 + } else if (status == MA_IFACE_CURRENT) {
16476 + if (info->interface_id == if_index) {
16477 + info->status |= MA_IFACE_CURRENT;
16480 + info->status |= MA_IFACE_NOT_USED;
16482 + } else if (status == MA_IFACE_NOT_USED) {
16483 + if (info->interface_id == if_index) {
16484 + if (info->status | MA_IFACE_CURRENT) {
16487 + info->status &= !MA_IFACE_CURRENT;
16488 + info->status |= MA_IFACE_NOT_USED;
16489 + info->status &= !MA_IFACE_HAS_ROUTER;
16492 + } else if (status == MA_IFACE_HAS_ROUTER) {
16493 + if (info->interface_id == if_index) {
16494 + info->status |= MA_IFACE_HAS_ROUTER;
16500 + if (status & (MA_IFACE_NOT_USED|MA_IFACE_NOT_PRESENT) && found) {
16501 + /* select new interface */
16502 + list_for_each(lh, &if_list) {
16503 + info = list_entry(lh, struct ma_if_info, list);
16504 + if (pref == NULL || ((info->preference > pref->preference) &&
16505 + info->status & MA_IFACE_HAS_ROUTER))
16509 + *change_if_index = pref->interface_id;
16510 + pref->status |= MA_IFACE_CURRENT;
16512 + *change_if_index = -1;
16517 + if (found) return 0;
16522 +static int if_proc_info(char *buffer, char **start, off_t offset,
16525 + struct list_head *lh;
16526 + struct ma_if_info *info;
16529 + list_for_each(lh, &if_list) {
16530 + info = list_entry(lh, struct ma_if_info, list);
16531 + len += sprintf(buffer + len, "%02d %010d %1d %1d\n",
16532 + info->interface_id, info->preference,
16533 + !!(info->status & MA_IFACE_HAS_ROUTER),
16534 + !!(info->status & MA_IFACE_CURRENT));
16537 + *start = buffer + offset;
16541 + if (len > length) len = length;
16547 +void ma_ctl_init(void)
16549 + proc_net_create("mip6_iface", 0, if_proc_info);
16552 +void ma_ctl_clean(void)
16554 + proc_net_remove("mip6_iface");
16557 +++ linux-2.4.27/net/ipv6/mobile_ip6/multiaccess_ctl.h
16560 + * 2001 (c) Oy L M Ericsson Ab
16562 + * Author: NomadicLab / Ericsson Research <ipv6@nomadiclab.com>
16568 +#ifndef _MULTIACCESS_CTL_H
16569 +#define _MULTIACCESS_CTL_H
16572 +#define MA_IFACE_NOT_PRESENT 0x01
16573 +#define MA_IFACE_NOT_USED 0x02
16574 +#define MA_IFACE_HAS_ROUTER 0x04
16575 +#define MA_IFACE_CURRENT 0x10
16577 +struct ma_if_uinfo {
16578 + int interface_id;
16583 + * @ma_ctl_get_preferred_id: returns most preferred interface id
16585 +int ma_ctl_get_preferred_if(void);
16587 +/* @ma_ctl_get_preference: returns preference for an interface
16588 + * @name: name of the interface (dev->name)
16590 +int ma_ctl_get_preference(int ifi);
16593 + * Public function: ma_ctl_set_preference
16594 + * Description: Set preference of an existing interface (called by ioctl)
16597 +void ma_ctl_set_preference(unsigned long);
16600 + * Public function: ma_ctl_add_iface
16601 + * Description: Inform control module to insert a new interface
16602 + * Returns: 0 if success, any other number means an error
16604 +void ma_ctl_add_iface(int);
16607 + * Public function: ma_ctl_del_iface
16608 + * Description: Inform control module to remove an obsolete interface
16609 + * Returns: 0 if success, any other number means an error
16611 +int ma_ctl_del_iface(int);
16614 + * Public function: ma_ctl_upd_iface
16615 + * Description: Inform control module of status change.
16616 + * Returns: 0 if success, any other number means an error
16618 +int ma_ctl_upd_iface(int, int, int *);
16621 + * Public function: ma_ctl_init
16622 + * Description: XXX
16625 +void ma_ctl_init(void);
16628 + * Public function: ma_ctl_clean
16629 + * Description: XXX
16632 +void ma_ctl_clean(void);
16637 +++ linux-2.4.27/net/ipv6/mobile_ip6/ndisc_ha.c
16640 + * Mobile IPv6 Duplicate Address Detection Functions
16643 + * Krishna Kumar <krkumar@us.ibm.com>
16647 + * This program is free software; you can redistribute it and/or
16648 + * modify it under the terms of the GNU General Public License
16649 + * as published by the Free Software Foundation; either version
16650 + * 2 of the License, or (at your option) any later version.
16654 +#include <linux/autoconf.h>
16655 +#include <linux/types.h>
16656 +#include <linux/init.h>
16657 +#include <linux/skbuff.h>
16658 +#include <linux/in6.h>
16659 +#include <net/ipv6.h>
16660 +#include <net/addrconf.h>
16661 +#include <net/mipv6.h>
16663 +#include "debug.h"
16664 +#include "bcache.h"
16665 +#include "ha.h" /* mipv6_generate_ll_addr */
16668 + * Binding Updates from MN are cached in this structure till DAD is performed.
16669 + * This structure is used to retrieve a pending Binding Update for the HA to
16670 + * reply to after performing DAD. The first cell is different from the rest as
16672 + * 1. The first cell is used to chain the remaining cells.
16673 + * 2. The timeout of the first cell is used to delete expired entries
16674 + * in the list of cells, while the timeout of the other cells are
16675 + * used for timing out a NS request so as to reply to a BU.
16676 + * 3. The only elements of the first cell that are used are :
16677 + * next, prev, and callback_timer.
16679 + * TODO : Don't we need to do pneigh_lookup on the Link Local address ?
16681 +struct mipv6_dad_cell {
16682 + /* Information needed for DAD management */
16683 + struct mipv6_dad_cell *next; /* Next element on the DAD list */
16684 + struct mipv6_dad_cell *prev; /* Prev element on the DAD list */
16685 + __u16 probes; /* Number of times to probe for addr */
16686 + __u16 flags; /* Entry flags - see below */
16687 + struct timer_list callback_timer; /* timeout for entry */
16689 + /* Information needed for performing DAD */
16690 + struct inet6_ifaddr *ifp;
16692 + struct in6_addr daddr;
16693 + struct in6_addr haddr; /* home address */
16694 + struct in6_addr ll_haddr; /* Link Local value of haddr */
16695 + struct in6_addr coa;
16696 + struct in6_addr rep_coa;
16697 + __u32 ba_lifetime;
16702 +/* Values for the 'flags' field in the mipv6_dad_cell */
16703 +#define DAD_INIT_ENTRY 0
16704 +#define DAD_DUPLICATE_ADDRESS 1
16705 +#define DAD_UNIQUE_ADDRESS 2
16707 +/* Head of the pending DAD list */
16708 +static struct mipv6_dad_cell dad_cell_head;
16710 +/* Lock to access the pending DAD list */
16711 +static rwlock_t dad_lock = RW_LOCK_UNLOCKED;
16713 +/* Timer routine which deletes 'expired' entries in the DAD list */
16714 +static void mipv6_dad_delete_old_entries(unsigned long unused)
16716 + struct mipv6_dad_cell *curr, *next;
16717 + unsigned long next_time = 0;
16719 + write_lock(&dad_lock);
16720 + curr = dad_cell_head.next;
16721 + while (curr != &dad_cell_head) {
16722 + next = curr->next;
16723 + if (curr->flags != DAD_INIT_ENTRY) {
16724 + if (curr->callback_timer.expires <= jiffies) {
16725 + /* Entry has expired, free it up. */
16726 + curr->next->prev = curr->prev;
16727 + curr->prev->next = curr->next;
16728 + in6_ifa_put(curr->ifp);
16730 + } else if (next_time <
16731 + curr->callback_timer.expires) {
16732 + next_time = curr->callback_timer.expires;
16737 + write_unlock(&dad_lock);
16740 + * Start another timer if more cells need to be removed at
16743 + dad_cell_head.callback_timer.expires = next_time;
16744 + add_timer(&dad_cell_head.callback_timer);
16749 + * Queue a timeout routine to clean up 'expired' DAD entries.
16751 +static void mipv6_start_dad_head_timer(struct mipv6_dad_cell *cell)
16753 + unsigned long expire = jiffies +
16754 + cell->ifp->idev->nd_parms->retrans_time * 10;
16756 + if (!timer_pending(&dad_cell_head.callback_timer) ||
16757 + expire < dad_cell_head.callback_timer.expires) {
16759 + * Add timer if none pending, or mod the timer if new
16760 + * cell needs to be expired before existing timer runs.
16762 + * We let the cell remain as long as possible, so that
16763 + * new BU's as part of retransmissions don't have to go
16764 + * through DAD before replying.
16766 + dad_cell_head.callback_timer.expires = expire;
16769 + * Keep the cell around for atleast some time to handle
16770 + * retransmissions or BU's due to fast MN movement. This
16771 + * is needed otherwise a previous timeout can delete all
16772 + * expired entries including this new one.
16774 + cell->callback_timer.expires = jiffies +
16775 + cell->ifp->idev->nd_parms->retrans_time * 5;
16776 + if (!timer_pending(&dad_cell_head.callback_timer)) {
16777 + add_timer(&dad_cell_head.callback_timer);
16779 + mod_timer(&dad_cell_head.callback_timer, expire);
16785 +/* Join solicited node MC address */
16786 +static inline void mipv6_join_sol_mc_addr(struct in6_addr *addr,
16787 + struct net_device *dev)
16789 + struct in6_addr maddr;
16791 + /* Join solicited node MC address */
16792 + addrconf_addr_solict_mult(addr, &maddr);
16793 + ipv6_dev_mc_inc(dev, &maddr);
16796 +/* Leave solicited node MC address */
16797 +static inline void mipv6_leave_sol_mc_addr(struct in6_addr *addr,
16798 + struct net_device *dev)
16800 + struct in6_addr maddr;
16802 + addrconf_addr_solict_mult(addr, &maddr);
16803 + ipv6_dev_mc_dec(dev, &maddr);
16807 +static inline void mipv6_dad_send_ns(struct inet6_ifaddr *ifp,
16808 + struct in6_addr *haddr)
16810 + struct in6_addr unspec;
16811 + struct in6_addr mcaddr;
16813 + ipv6_addr_set(&unspec, 0, 0, 0, 0);
16814 + addrconf_addr_solict_mult(haddr, &mcaddr);
16816 + /* addr is 'unspec' since we treat this address as transient */
16817 + ndisc_send_ns(ifp->idev->dev, NULL, haddr, &mcaddr, &unspec);
16821 + * Search for a home address in the list of pending DAD's. Called from
16822 + * Neighbor Advertisement
16823 + * Return values :
16824 + * -1 : No DAD entry found for this advertisement, or entry already
16825 + * finished processing.
16826 + * 0 : Entry found waiting for DAD to finish.
16828 +static int dad_search_haddr(struct in6_addr *ll_haddr,
16829 + struct in6_addr *daddr, struct in6_addr *haddr,
16830 + struct in6_addr *coa, struct in6_addr *rep_coa,
16831 + __u16 * seq, struct inet6_ifaddr **ifp)
16833 + struct mipv6_dad_cell *cell;
16835 + read_lock(&dad_lock);
16836 + cell = dad_cell_head.next;
16837 + while (cell != &dad_cell_head &&
16838 + ipv6_addr_cmp(&cell->ll_haddr, ll_haddr) &&
16839 + ipv6_addr_cmp(&cell->haddr, ll_haddr)) {
16840 + cell = cell->next;
16842 + if (cell == &dad_cell_head || cell->flags != DAD_INIT_ENTRY) {
16843 + /* Not found element, or element already finished processing */
16844 + if (cell != &dad_cell_head) {
16846 + * Set the state to DUPLICATE, even if it was UNIQUE
16847 + * earlier. It is not needed to setup timer via
16848 + * mipv6_start_dad_head_timer since this must have
16849 + * already been done.
16851 + cell->flags = DAD_DUPLICATE_ADDRESS;
16853 + read_unlock(&dad_lock);
16858 + * The NA found an unprocessed entry in the DAD list. Expire this
16859 + * entry since another node advertised this address. Caller should
16860 + * reject BU (DAD failed).
16862 + ipv6_addr_copy(daddr, &cell->daddr);
16863 + ipv6_addr_copy(haddr, &cell->haddr);
16864 + ipv6_addr_copy(coa, &cell->coa);
16865 + ipv6_addr_copy(rep_coa, &cell->rep_coa);
16866 + *seq = cell->sequence;
16867 + *ifp = cell->ifp;
16869 + if (del_timer(&cell->callback_timer) == 0) {
16870 + /* Timer already deleted, race with Timeout Handler */
16871 + /* No action needed */
16874 + cell->flags = DAD_DUPLICATE_ADDRESS;
16876 + /* Now leave this address to avoid future processing of NA's */
16877 + mipv6_leave_sol_mc_addr(&cell->ll_haddr, cell->ifp->idev->dev);
16878 + /* Leave also global address, if link local address was in use */
16879 + if (ipv6_addr_cmp(&cell->ll_haddr, &cell->haddr))
16880 + mipv6_leave_sol_mc_addr(&cell->haddr, cell->ifp->idev->dev);
16881 + /* Start dad_head timer to remove this entry */
16882 + mipv6_start_dad_head_timer(cell);
16884 + read_unlock(&dad_lock);
16889 +/* ENTRY routine called via Neighbor Advertisement */
16890 +void mipv6_check_dad(struct in6_addr *ll_haddr)
16892 + struct in6_addr daddr, haddr, coa, rep_coa;
16893 + struct inet6_ifaddr *ifp;
16896 + if (dad_search_haddr(ll_haddr, &daddr, &haddr, &coa, &rep_coa, &seq,
16899 + * Didn't find entry, or no action needed (the action has
16900 + * already been performed).
16906 + * A DAD cell was present, meaning that there is a pending BU
16907 + * request for 'haddr' - reject the BU.
16909 + mipv6_bu_finish(ifp, 0, DUPLICATE_ADDR_DETECT_FAIL,
16910 + &daddr, &haddr, &coa, &rep_coa, 0, seq, 0, NULL);
16915 + * Check if the passed 'cell' is in the list of pending DAD's. Called from
16916 + * the Timeout Handler.
16918 + * Assumes that the caller is holding the dad_lock in reader mode.
16920 +static int dad_search_cell(struct mipv6_dad_cell *cell)
16922 + struct mipv6_dad_cell *tmp;
16924 + tmp = dad_cell_head.next;
16925 + while (tmp != &dad_cell_head && tmp != cell) {
16928 + if (tmp == cell) {
16929 + if (cell->flags == DAD_INIT_ENTRY) {
16930 + /* Found valid entry */
16931 + if (--cell->probes == 0) {
16933 + * Retransmission's are over - return success.
16935 + cell->flags = DAD_UNIQUE_ADDRESS;
16938 + * Leave this address to avoid future
16939 + * processing of NA's.
16941 + mipv6_leave_sol_mc_addr(&cell->ll_haddr,
16942 + cell->ifp->idev->
16944 + if (ipv6_addr_cmp(&cell->ll_haddr, &cell->haddr))
16945 + mipv6_leave_sol_mc_addr(&cell->haddr,
16946 + cell->ifp->idev->dev);
16947 + /* start timeout to delete this cell. */
16948 + mipv6_start_dad_head_timer(cell);
16952 + * Retransmission not finished, send another NS and
16953 + * return failure.
16955 + mipv6_dad_send_ns(cell->ifp, &cell->ll_haddr);
16956 + if (ipv6_addr_cmp(&cell->ll_haddr, &cell->haddr))
16957 + mipv6_leave_sol_mc_addr(&cell->haddr,
16958 + cell->ifp->idev->dev);
16959 + cell->callback_timer.expires = jiffies +
16960 + cell->ifp->idev->nd_parms->retrans_time;
16961 + add_timer(&cell->callback_timer);
16964 + * This means that an NA was received before the
16965 + * timeout and when the state changed from
16966 + * DAD_INIT_ENTRY, the BU got failed as a result.
16967 + * There is nothing to be done.
16974 +/* ENTRY routine called via Timeout */
16975 +static void mipv6_dad_timeout(unsigned long arg)
16977 + __u8 ba_status = SUCCESS;
16978 + struct in6_addr daddr;
16979 + struct in6_addr haddr;
16980 + struct in6_addr coa;
16981 + struct in6_addr rep_coa;
16982 + struct inet6_ifaddr *ifp;
16984 + __u32 ba_lifetime;
16987 + struct mipv6_dad_cell *cell = (struct mipv6_dad_cell *) arg;
16990 + * If entry is not in the list, we have already sent BU Failure
16991 + * after getting a NA.
16993 + read_lock(&dad_lock);
16994 + if (dad_search_cell(cell) < 0) {
16996 + * 'cell' is no longer valid (may not be in the list or
16997 + * is already processed, due to NA processing), or NS
16998 + * retransmissions are not yet over.
17000 + read_unlock(&dad_lock);
17004 + /* This is the final Timeout. Send Bind Ack Success */
17007 + ifindex = cell->ifindex;
17008 + ba_lifetime = cell->ba_lifetime;
17009 + sequence = cell->sequence;
17010 + flags = cell->bu_flags;
17012 + ipv6_addr_copy(&daddr, &cell->daddr);
17013 + ipv6_addr_copy(&haddr, &cell->haddr);
17014 + ipv6_addr_copy(&coa, &cell->coa);
17015 + ipv6_addr_copy(&rep_coa, &cell->rep_coa);
17016 + read_unlock(&dad_lock);
17018 + /* Send BU Acknowledgement Success */
17019 + mipv6_bu_finish(ifp, ifindex, ba_status,
17020 + &daddr, &haddr, &coa, &rep_coa,
17021 + ba_lifetime, sequence, flags, NULL);
17026 + * Check if original home address exists in our DAD pending list, if so return
17029 + * Assumes that the caller is holding the dad_lock in writer mode.
17031 +static struct mipv6_dad_cell *mipv6_dad_get_cell(struct in6_addr *haddr)
17033 + struct mipv6_dad_cell *cell;
17035 + cell = dad_cell_head.next;
17036 + while (cell != &dad_cell_head
17037 + && ipv6_addr_cmp(&cell->haddr, haddr)) {
17038 + cell = cell->next;
17040 + if (cell == &dad_cell_head) {
17041 + /* Not found element */
17048 + * Save all parameters needed for doing a Bind Ack in the mipv6_dad_cell
17051 +static void mipv6_dad_save_cell(struct mipv6_dad_cell *cell,
17052 + struct inet6_ifaddr *ifp, int ifindex,
17053 + struct in6_addr *daddr,
17054 + struct in6_addr *haddr,
17055 + struct in6_addr *coa,
17056 + struct in6_addr *rep_coa,
17057 + __u32 ba_lifetime,
17058 + __u16 sequence, __u8 flags)
17060 + in6_ifa_hold(ifp);
17062 + cell->ifindex = ifindex;
17064 + ipv6_addr_copy(&cell->daddr, daddr);
17065 + ipv6_addr_copy(&cell->haddr, haddr);
17066 + ipv6_addr_copy(&cell->coa, coa);
17067 + ipv6_addr_copy(&cell->rep_coa, rep_coa);
17069 + /* Convert cell->ll_haddr to Link Local address */
17070 + if (flags & MIPV6_BU_F_LLADDR)
17071 + mipv6_generate_ll_addr(&cell->ll_haddr, haddr);
17073 + ipv6_addr_copy(&cell->ll_haddr, haddr);
17075 + cell->ba_lifetime = ba_lifetime;
17076 + cell->sequence = sequence;
17077 + cell->bu_flags = flags;
17081 + * Top level DAD routine for performing DAD.
17084 + * 0 : Don't need to do DAD.
17085 + * 1 : Need to do DAD.
17086 + * -n : Error, where 'n' is the reason for the error.
17088 + * Assumption : DAD process has been optimized by using cached values upto
17089 + * some time. However sometimes this can cause problems. Eg. when the first
17090 + * BU was received, DAD might have failed. Before the second BU arrived,
17091 + * the node using MN's home address might have stopped using it, but still
17092 + * we will return DAD_DUPLICATE_ADDRESS based on the first DAD's result. Or
17093 + * this can go the other way around. However, it is a very small possibility
17094 + * and thus optimization is turned on by default. It is possible to change
17095 + * this feature (needs a little code-rewriting in this routine), but
17096 + * currently DAD result is being cached for performance reasons.
17098 +int mipv6_dad_start(struct inet6_ifaddr *ifp, int ifindex,
17099 + struct in6_addr *daddr, struct in6_addr *haddr,
17100 + struct in6_addr *coa, struct in6_addr *rep_coa,
17101 + __u32 ba_lifetime, __u16 sequence, __u8 flags)
17104 + struct mipv6_dad_cell *cell;
17105 + struct mipv6_bce bc_entry;
17107 + if (ifp->idev->cnf.dad_transmits == 0) {
17108 + /* DAD is not configured on the HA, return SUCCESS */
17112 + if (mipv6_bcache_get(haddr, daddr, &bc_entry) == 0) {
17114 + * We already have an entry in our cache - don't need to
17115 + * do DAD as we are already defending this home address.
17120 + write_lock(&dad_lock);
17121 + if ((cell = mipv6_dad_get_cell(haddr)) != NULL) {
17123 + * An existing entry for BU was found in our cache due
17124 + * to retransmission of the BU or a new COA registration.
17126 + switch (cell->flags) {
17127 + case DAD_INIT_ENTRY:
17128 + /* Old entry is waiting for DAD to complete */
17130 + case DAD_UNIQUE_ADDRESS:
17131 + /* DAD is finished successfully - return success. */
17132 + write_unlock(&dad_lock);
17134 + case DAD_DUPLICATE_ADDRESS:
17136 + * DAD is finished and we got a NA while doing BU -
17137 + * return failure.
17139 + write_unlock(&dad_lock);
17140 + return -DUPLICATE_ADDR_DETECT_FAIL;
17142 + /* Unknown state - should never happen */
17143 + DEBUG(DBG_WARNING,
17144 + "cell entry in unknown state : %d",
17146 + write_unlock(&dad_lock);
17147 + return -REASON_UNSPECIFIED;
17151 + if ((cell = (struct mipv6_dad_cell *)
17152 + kmalloc(sizeof(struct mipv6_dad_cell), GFP_ATOMIC))
17154 + return -INSUFFICIENT_RESOURCES;
17159 + mipv6_dad_save_cell(cell, ifp, ifindex, daddr, haddr, coa, rep_coa,
17160 + ba_lifetime, sequence, flags);
17163 + cell->flags = DAD_INIT_ENTRY;
17164 + cell->probes = ifp->idev->cnf.dad_transmits;
17166 + /* Insert element on dad_cell_head list */
17167 + dad_cell_head.prev->next = cell;
17168 + cell->next = &dad_cell_head;
17169 + cell->prev = dad_cell_head.prev;
17170 + dad_cell_head.prev = cell;
17171 + write_unlock(&dad_lock);
17172 + if (flags & MIPV6_BU_F_LLADDR) {
17173 + /* join the solicited node MC of the global homeaddr.*/
17174 + mipv6_join_sol_mc_addr(&cell->haddr, ifp->idev->dev);
17176 + mipv6_dad_send_ns(ifp, &cell->haddr);
17178 + /* join the solicited node MC of the homeaddr. */
17179 + mipv6_join_sol_mc_addr(&cell->ll_haddr, ifp->idev->dev);
17182 + mipv6_dad_send_ns(ifp, &cell->ll_haddr);
17184 + /* Initialize timer for this cell to timeout the NS. */
17185 + init_timer(&cell->callback_timer);
17186 + cell->callback_timer.data = (unsigned long) cell;
17187 + cell->callback_timer.function = mipv6_dad_timeout;
17188 + cell->callback_timer.expires = jiffies +
17189 + ifp->idev->nd_parms->retrans_time;
17190 + add_timer(&cell->callback_timer);
17192 + write_unlock(&dad_lock);
17197 +void __init mipv6_dad_init(void)
17199 + dad_cell_head.next = dad_cell_head.prev = &dad_cell_head;
17200 + init_timer(&dad_cell_head.callback_timer);
17201 + dad_cell_head.callback_timer.data = 0;
17202 + dad_cell_head.callback_timer.function =
17203 + mipv6_dad_delete_old_entries;
17206 +void __exit mipv6_dad_exit(void)
17208 + struct mipv6_dad_cell *curr, *next;
17210 + write_lock_bh(&dad_lock);
17211 + del_timer(&dad_cell_head.callback_timer);
17213 + curr = dad_cell_head.next;
17214 + while (curr != &dad_cell_head) {
17215 + next = curr->next;
17216 + del_timer(&curr->callback_timer);
17217 + if (curr->flags == DAD_INIT_ENTRY) {
17219 + * We were in DAD_INIT state and listening to the
17220 + * solicited node MC address - need to stop that.
17222 + mipv6_leave_sol_mc_addr(&curr->ll_haddr,
17223 + curr->ifp->idev->dev);
17224 + if (ipv6_addr_cmp(&curr->ll_haddr, &curr->haddr))
17225 + mipv6_leave_sol_mc_addr(&curr->haddr,
17226 + curr->ifp->idev->dev);
17228 + in6_ifa_put(curr->ifp);
17232 + dad_cell_head.next = dad_cell_head.prev = &dad_cell_head;
17233 + write_unlock_bh(&dad_lock);
17236 +++ linux-2.4.27/net/ipv6/mobile_ip6/prefix.c
17239 + * Prefix solicitation and advertisement
17242 + * Jaakko Laine <medved@iki.fi>
17246 + * This program is free software; you can redistribute it and/or
17247 + * modify it under the terms of the GNU General Public License
17248 + * as published by the Free Software Foundation; either version
17249 + * 2 of the License, or (at your option) any later version.
17252 +#include <linux/config.h>
17253 +#include <linux/icmpv6.h>
17254 +#include <linux/net.h>
17255 +#include <linux/spinlock.h>
17256 +#include <linux/timer.h>
17257 +#include <linux/netdevice.h>
17258 +#include <net/ipv6.h>
17259 +#include <net/addrconf.h>
17260 +#include <net/ip6_route.h>
17261 +#include <net/mipv6.h>
17263 +#include "mipv6_icmp.h"
17264 +#include "debug.h"
17265 +#include "sortedlist.h"
17266 +#include "prefix.h"
17267 +#include "config.h"
17269 +#define INFINITY 0xffffffff
17271 +struct timer_list pfx_timer;
17273 +struct list_head pfx_list;
17274 +rwlock_t pfx_list_lock = RW_LOCK_UNLOCKED;
17276 +int compare_pfx_list_entry(const void *data1, const void *data2,
17279 + struct pfx_list_entry *e1 = (struct pfx_list_entry *) data1;
17280 + struct pfx_list_entry *e2 = (struct pfx_list_entry *) data2;
17282 + return ((ipv6_addr_cmp(&e1->daddr, &e2->daddr) == 0)
17283 + && (e2->ifindex == -1 || e1->ifindex == e2->ifindex));
17287 + * mipv6_pfx_cancel_send - cancel pending items to daddr from saddr
17288 + * @daddr: Destination address
17289 + * @ifindex: pending items on this interface will be canceled
17291 + * if ifindex == -1, all items to daddr will be removed
17293 +void mipv6_pfx_cancel_send(struct in6_addr *daddr, int ifindex)
17295 + unsigned long tmp;
17296 + struct pfx_list_entry entry;
17300 + /* We'll just be comparing these parts... */
17301 + memcpy(&entry.daddr, daddr, sizeof(struct in6_addr));
17302 + entry.ifindex = ifindex;
17304 + write_lock_bh(&pfx_list_lock);
17306 + while (mipv6_slist_del_item(&pfx_list, &entry,
17307 + compare_pfx_list_entry) == 0)
17310 + if ((tmp = mipv6_slist_get_first_key(&pfx_list)))
17311 + mod_timer(&pfx_timer, tmp);
17313 + write_unlock_bh(&pfx_list_lock);
17317 + * mipv6_pfx_add_ha - add a new HA to send prefix solicitations to
17318 + * @daddr: address of HA
17319 + * @saddr: our address to use as source address
17320 + * @ifindex: interface index
17322 +void mipv6_pfx_add_ha(struct in6_addr *daddr, struct in6_addr *saddr,
17325 + unsigned long tmp;
17326 + struct pfx_list_entry entry;
17330 + memcpy(&entry.daddr, daddr, sizeof(struct in6_addr));
17331 + memcpy(&entry.saddr, saddr, sizeof(struct in6_addr));
17332 + entry.retries = 0;
17333 + entry.ifindex = ifindex;
17335 + write_lock_bh(&pfx_list_lock);
17336 + if (mipv6_slist_modify(&pfx_list, &entry, sizeof(struct pfx_list_entry),
17337 + jiffies + INITIAL_SOLICIT_TIMER * HZ,
17338 + compare_pfx_list_entry))
17339 + DEBUG(DBG_WARNING, "Cannot add new HA to pfx list");
17341 + if ((tmp = mipv6_slist_get_first_key(&pfx_list)))
17342 + mod_timer(&pfx_timer, tmp);
17343 + write_unlock_bh(&pfx_list_lock);
17346 +int mipv6_pfx_add_home(int ifindex, struct in6_addr *saddr,
17347 + struct in6_addr *daddr, unsigned long min_expire)
17349 + unsigned long tmp;
17351 + write_lock(&pfx_list_lock);
17353 + if (min_expire != INFINITY) {
17354 + unsigned long expire;
17355 + struct pfx_list_entry entry;
17357 + memcpy(&entry.daddr, saddr, sizeof(struct in6_addr));
17358 + memcpy(&entry.saddr, daddr, sizeof(struct in6_addr));
17359 + entry.retries = 0;
17360 + entry.ifindex = ifindex;
17362 + /* This is against the RFC 3775, but we need to set
17363 + * a minimum interval for a prefix solicitation.
17364 + * Otherwise a prefix solicitation storm will
17365 + * result if valid lifetime of the prefix is
17366 + * smaller than MAX_PFX_ADV_DELAY
17368 + min_expire -= MAX_PFX_ADV_DELAY;
17369 + min_expire = min_expire < MIN_PFX_SOL_DELAY ? MIN_PFX_SOL_DELAY : min_expire;
17371 + expire = jiffies + min_expire * HZ;
17373 + if (mipv6_slist_modify(&pfx_list, &entry,
17374 + sizeof(struct pfx_list_entry),
17376 + compare_pfx_list_entry) != 0)
17377 + DEBUG(DBG_WARNING, "Cannot add new entry to pfx_list");
17380 + if ((tmp = mipv6_slist_get_first_key(&pfx_list)))
17381 + mod_timer(&pfx_timer, tmp);
17383 + write_unlock(&pfx_list_lock);
17389 + * set_ha_pfx_list - manipulate pfx_list for HA when timer goes off
17390 + * @entry: pfx_list_entry that is due
17392 +static void set_ha_pfx_list(struct pfx_list_entry *entry)
17397 + * set_mn_pfx_list - manipulate pfx_list for MN when timer goes off
17398 + * @entry: pfx_list_entry that is due
17400 +static void set_mn_pfx_list(struct pfx_list_entry *entry)
17405 + * pfx_timer_handler - general timer handler
17408 + * calls set_ha_pfx_list and set_mn_pfx_list to do the thing when
17409 + * a timer goes off
17411 +static void pfx_timer_handler(unsigned long dummy)
17413 + unsigned long tmp;
17414 + struct pfx_list_entry *entry;
17418 + write_lock(&pfx_list_lock);
17419 + if (!(entry = mipv6_slist_get_first(&pfx_list)))
17422 + if (mip6node_cnf.capabilities & CAP_HA)
17423 + set_ha_pfx_list(entry);
17424 + if (mip6node_cnf.capabilities & CAP_MN)
17425 + set_mn_pfx_list(entry);
17426 + if ((tmp = mipv6_slist_get_first_key(&pfx_list)))
17427 + mod_timer(&pfx_timer, tmp);
17430 + write_unlock(&pfx_list_lock);
17433 +int mipv6_initialize_pfx_icmpv6(void)
17435 + INIT_LIST_HEAD(&pfx_list);
17437 + init_timer(&pfx_timer);
17438 + pfx_timer.function = pfx_timer_handler;
17443 +void mipv6_shutdown_pfx_icmpv6(void)
17445 + struct prefix_info *tmp;
17447 + if (timer_pending(&pfx_timer))
17448 + del_timer(&pfx_timer);
17450 + write_lock_bh(&pfx_list_lock);
17451 + while ((tmp = mipv6_slist_del_first(&pfx_list)))
17453 + write_unlock_bh(&pfx_list_lock);
17456 +++ linux-2.4.27/net/ipv6/mobile_ip6/prefix.h
17459 + * MIPL Mobile IPv6 Prefix solicitation and advertisement
17463 + * This program is free software; you can redistribute it and/or
17464 + * modify it under the terms of the GNU General Public License
17465 + * as published by the Free Software Foundation; either version
17466 + * 2 of the License, or (at your option) any later version.
17472 +#include <net/addrconf.h>
17474 +struct pfx_list_entry {
17475 + struct in6_addr daddr;
17476 + struct in6_addr saddr;
17481 +extern struct list_head pfx_list;
17482 +extern rwlock_t pfx_list_lock;
17483 +extern struct timer_list pfx_timer;
17485 +int compare_pfx_list_entry(const void *data1, const void *data2,
17489 + * mipv6_pfx_cancel_send - cancel pending pfx_advs/sols to daddr
17490 + * @daddr: destination address
17491 + * @ifindex: pending items on this interface will be canceled
17493 + * if ifindex == -1, all items to daddr will be removed
17495 +void mipv6_pfx_cancel_send(struct in6_addr *daddr, int ifindex);
17498 + * mipv6_pfx_add_ha - add a new HA to send prefix solicitations to
17499 + * @daddr: address of HA
17500 + * @saddr: our address to use as source address
17501 + * @ifindex: interface index
17503 +void mipv6_pfx_add_ha(struct in6_addr *daddr, struct in6_addr *saddr,
17506 +void mipv6_pfxs_modified(struct prefix_info *pinfo, int ifindex);
17508 +int mipv6_pfx_add_home(int ifindex, struct in6_addr *daddr,
17509 + struct in6_addr *saddr, unsigned long min_expire);
17511 +int mipv6_initialize_pfx_icmpv6(void);
17512 +void mipv6_shutdown_pfx_icmpv6(void);
17516 +++ linux-2.4.27/net/ipv6/mobile_ip6/prefix_ha.c
17519 + * Prefix advertisement for Home Agent
17522 + * Jaakko Laine <medved@iki.fi>
17526 + * This program is free software; you can redistribute it and/or
17527 + * modify it under the terms of the GNU General Public License
17528 + * as published by the Free Software Foundation; either version
17529 + * 2 of the License, or (at your option) any later version.
17532 +#include <linux/config.h>
17533 +#include <linux/icmpv6.h>
17534 +#include <linux/net.h>
17535 +#include <linux/spinlock.h>
17536 +#include <linux/timer.h>
17537 +#include <linux/netdevice.h>
17538 +#include <net/ipv6.h>
17539 +#include <net/addrconf.h>
17540 +#include <net/ip6_route.h>
17541 +#include <net/mipv6.h>
17543 +#include "mipv6_icmp.h"
17544 +#include "debug.h"
17545 +#include "sortedlist.h"
17547 +#include "bcache.h"
17548 +#include "config.h"
17549 +#include "prefix.h"
17552 + * pfx_adv_iterator - modify pfx_list entries according to new prefix info
17553 + * @data: MN's home registration bcache_entry
17554 + * @args: new prefix info
17555 + * @sortkey: ignored
17557 +static int pfx_adv_iterator(void *data, void *args, unsigned long sortkey)
17559 + struct mipv6_bce *bc_entry = (struct mipv6_bce *) data;
17560 + struct prefix_info *pinfo = (struct prefix_info *) args;
17562 + if (mipv6_prefix_compare(&bc_entry->coa, &pinfo->prefix,
17563 + pinfo->prefix_len) == 0) {
17564 + struct pfx_list_entry pfx_entry;
17566 + memcpy(&pfx_entry.daddr, &bc_entry->coa,
17567 + sizeof(struct in6_addr));
17568 + memcpy(&pfx_entry.daddr, &bc_entry->our_addr,
17569 + sizeof(struct in6_addr));
17570 + pfx_entry.retries = 0;
17571 + pfx_entry.ifindex = bc_entry->ifindex;
17573 + mipv6_slist_modify(&pfx_list, &pfx_entry,
17574 + sizeof(struct pfx_list_entry),
17576 + net_random() % (MAX_PFX_ADV_DELAY * HZ),
17577 + compare_pfx_list_entry);
17583 +struct homereg_iterator_args {
17584 + struct list_head *head;
17588 +static int homereg_iterator(void *data, void *args, unsigned long *sortkey)
17590 + struct mipv6_bce *entry = (struct mipv6_bce *) data;
17591 + struct homereg_iterator_args *state =
17592 + (struct homereg_iterator_args *) args;
17594 + if (entry->type == HOME_REGISTRATION) {
17595 + mipv6_slist_add(state->head, entry,
17596 + sizeof(struct mipv6_bce),
17603 +static int mipv6_bcache_get_homeregs(struct list_head *head)
17605 + struct homereg_iterator_args args;
17610 + args.head = head;
17612 + mipv6_bcache_iterate(homereg_iterator, &args);
17613 + return args.count;
17617 + * mipv6_prefix_added - prefix was added to interface, act accordingly
17618 + * @pinfo: prefix_info that was added
17619 + * @ifindex: interface index
17621 +void mipv6_pfxs_modified(struct prefix_info *pinfo, int ifindex)
17624 + unsigned long tmp;
17625 + struct list_head home_regs;
17629 + INIT_LIST_HEAD(&home_regs);
17631 + if (!(count = mipv6_bcache_get_homeregs(&home_regs)))
17634 + write_lock_bh(&pfx_list_lock);
17635 + mipv6_slist_for_each(&home_regs, pinfo, pfx_adv_iterator);
17636 + if ((tmp = mipv6_slist_get_first_key(&pfx_list)))
17637 + mod_timer(&pfx_timer, tmp);
17638 + write_unlock_bh(&pfx_list_lock);
17641 +++ linux-2.4.27/net/ipv6/mobile_ip6/rr_crypto.c
17644 + * rr_cookie.c - Mobile IPv6 return routability crypto
17645 + * Author : Henrik Petander <henrik.petander@hut.fi>
17649 + * This program is free software; you can redistribute it and/or
17650 + * modify it under the terms of the GNU General Public License
17651 + * as published by the Free Software Foundation; either version
17652 + * 2 of the License, or (at your option) any later version.
17658 +#include <linux/kernel.h>
17659 +#include <linux/types.h>
17660 +#include <linux/spinlock.h>
17661 +#include <linux/sched.h>
17662 +#include <linux/timer.h>
17663 +#include <linux/in6.h>
17664 +#include <linux/init.h>
17665 +#include <linux/random.h>
17667 +#include <net/ipv6.h>
17669 +#include "debug.h"
17671 +#include "rr_crypto.h"
17675 +u8 k_CN[HMAC_SHA1_KEY_SIZE]; // secret key of CN
17677 +u16 curr_index = 0;
17679 +struct nonce_timestamp nonce_table[MAX_NONCES];
17680 +spinlock_t nonce_lock = SPIN_LOCK_UNLOCKED;
17681 +void update_nonces(void);
17683 +/** nonce_is_fresh - whether the nonce was generated recently
17685 + * @non_ts : table entry containing the nonce and a timestamp
17686 + * @interval : if nonce was generated within interval seconds it is fresh
17688 + * Returns 1 if the nonce is fresh, 0 otherwise.
17690 +static int nonce_is_fresh(struct nonce_timestamp *non_ts, unsigned long interval)
17692 + if (time_before(jiffies, non_ts->timestamp + interval * HZ) && !non_ts->invalid)
17696 +void mipv6_rr_invalidate_nonce(u16 nonce_ind)
17698 + spin_lock_bh(&nonce_lock);
17699 + if (nonce_ind > MAX_NONCES) {
17700 + spin_unlock_bh(&nonce_lock);
17703 + nonce_table[nonce_ind].invalid = 1;
17704 + spin_unlock_bh(&nonce_lock);
17706 +/* Returns a pointer to a new nonce */
17707 +struct mipv6_rr_nonce * mipv6_rr_get_new_nonce(void)
17709 + struct mipv6_rr_nonce *nce = kmalloc(sizeof(*nce), GFP_ATOMIC);
17713 + // Lock nonces here
17714 + spin_lock_bh(&nonce_lock);
17715 + // If nonce is not fresh create new one
17716 + if (!nonce_is_fresh(&nonce_table[curr_index], MIPV6_RR_NONCE_LIFETIME)) {
17717 + // increment the last nonce pointer and create new nonce
17720 + if (curr_index == MAX_NONCES)
17722 + // Get random data to fill the nonce data
17723 + get_random_bytes(nonce_table[curr_index].nonce.data, MIPV6_RR_NONCE_DATA_LENGTH);
17724 + // Fill the index field
17725 + nonce_table[curr_index].nonce.index = curr_index;
17726 + nonce_table[curr_index].invalid = 0;
17727 + nonce_table[curr_index].timestamp = jiffies;
17729 + spin_unlock_bh(&nonce_lock);
17730 + memcpy(nce, &nonce_table[curr_index].nonce, sizeof(*nce));
17734 +/** mipv6_rr_nonce_get_by_index - returns a nonce for index
17735 + * @nonce_ind : index of the nonce
17737 + * Returns a nonce or NULL if the nonce index was invalid or the nonce
17738 + * for the index was not fresh.
17740 +struct mipv6_rr_nonce * mipv6_rr_nonce_get_by_index(u16 nonce_ind)
17742 + struct mipv6_rr_nonce *nce = NULL;
17744 + spin_lock_bh(&nonce_lock);
17745 + if (nonce_ind >= MAX_NONCES) {
17746 + DEBUG(DBG_WARNING, "Nonce index field from BU invalid");
17748 + /* Here a double of the nonce_lifetime is used for freshness
17749 + * verification, since the nonces
17750 + * are not created in response to every initiator packet
17752 + } else if (nonce_is_fresh(&nonce_table[nonce_ind], 2 * MIPV6_RR_NONCE_LIFETIME)) {
17753 + nce = kmalloc(sizeof(*nce), GFP_ATOMIC);
17754 + memcpy(nce, &nonce_table[nonce_ind].nonce, sizeof(*nce));
17756 + spin_unlock_bh(&nonce_lock);
17761 +/* Fills rr test init cookies with random bytes */
17762 +void mipv6_rr_mn_cookie_create(u8 *cookie)
17764 + get_random_bytes(cookie, MIPV6_RR_COOKIE_LENGTH);
17767 +/** mipv6_rr_cookie_create - builds a home or care-of cookie
17769 + * @addr : the home or care-of address from HoTI or CoTI
17770 + * @ckie : memory where the cookie is copied to
17771 + * @nce : pointer to a nonce used for the calculation, nce is freed during the function
17774 +int mipv6_rr_cookie_create(struct in6_addr *addr, u8 **ckie,
17777 + struct ah_processing ah_proc;
17778 + u8 digest[HMAC_SHA1_HASH_LEN];
17779 + struct mipv6_rr_nonce *nce;
17781 + if ((nce = mipv6_rr_nonce_get_by_index(nonce_index))== NULL)
17784 + if (*ckie == NULL && (*ckie = kmalloc(MIPV6_RR_COOKIE_LENGTH,
17785 + GFP_ATOMIC)) == NULL) {
17789 + /* Calculate the full hmac-sha1 digest from address and nonce using the secret key of cn */
17791 + if (ah_hmac_sha1_init(&ah_proc, k_CN, HMAC_SHA1_KEY_SIZE) < 0) {
17792 + DEBUG(DBG_ERROR, "Hmac sha1 initialization failed");
17797 + ah_hmac_sha1_loop(&ah_proc, addr, sizeof(*addr));
17798 + ah_hmac_sha1_loop(&ah_proc, nce->data, MIPV6_RR_NONCE_DATA_LENGTH);
17799 + ah_hmac_sha1_result(&ah_proc, digest);
17802 + /* clean up nonce */
17805 + /* Copy first 64 bits of hash target to the cookie */
17806 + memcpy(*ckie, digest, MIPV6_RR_COOKIE_LENGTH);
17810 +/** mipv6_rr_key_calc - creates BU authentication key
17812 + * @hoc : Home Cookie
17813 + * @coc : Care-of Cookie
17815 + * Returns BU authentication key of length HMAC_SHA1_KEY_SIZE or NULL in error cases,
17816 + * caller needs to free the key.
17818 +u8 *mipv6_rr_key_calc(u8 *hoc, u8 *coc)
17821 + u8 *key_bu = kmalloc(HMAC_SHA1_KEY_SIZE, GFP_ATOMIC);
17825 + DEBUG(DBG_CRITICAL, "Memory allocation failed, could nort create BU authentication key");
17829 + /* Calculate the key from home and care-of cookies
17830 + * Kbu = sha1(home_cookie | care-of cookie)
17831 + * or KBu = sha1(home_cookie), if MN deregisters
17834 + sha1_compute(&c, hoc, MIPV6_RR_COOKIE_LENGTH);
17836 + sha1_compute(&c, coc, MIPV6_RR_COOKIE_LENGTH);
17837 + sha1_final(&c, key_bu);
17838 + DEBUG(DBG_RR, "Home and Care-of cookies used for calculating key ");
17839 + debug_print_buffer(DBG_RR, hoc, MIPV6_RR_COOKIE_LENGTH);
17841 + debug_print_buffer(DBG_RR, coc, MIPV6_RR_COOKIE_LENGTH);
17846 +void mipv6_rr_init(void)
17848 + get_random_bytes(k_CN, HMAC_SHA1_KEY_SIZE);
17849 + memset(nonce_table, 0, MAX_NONCES * sizeof(struct nonce_timestamp));
17852 +#ifdef TEST_MIPV6_RR_CRYPTO
17853 +void mipv6_test_rr(void)
17855 + struct mipv6_rr_nonce *nonce;
17856 + struct in6_addr a1, a2;
17858 + u8 *ckie1 = NULL, *ckie2 = NULL;
17859 + u8 *key_mn = NULL, *key_cn = NULL;
17862 + nonce = mipv6_rr_get_new_nonce();
17864 + printk("mipv6_rr_get_new_nonce() failed, at 1! \n");
17867 + mipv6_rr_cookie_create(&a1, &ckie1, nonce->index);
17868 + ind1 = nonce->index;
17871 + nonce = mipv6_rr_get_new_nonce();
17873 + printk("mipv6_rr_get_new_nonce() failed, at 2! \n");
17877 + mipv6_rr_cookie_create(&a2, &ckie2, nonce->index);
17878 + ind2 = nonce->index;
17879 + key_mn = mipv6_rr_key_calc(ckie1, ckie2);
17881 + /* Create home and coa cookies based on indices */
17882 + mipv6_rr_cookie_create(&a1, &ckie1, ind1);
17883 + mipv6_rr_cookie_create(&a2, &ckie2, ind2);
17884 + key_cn = mipv6_rr_key_calc(ckie1, ckie2);
17885 + if (!key_cn || !key_mn) {
17886 + printk("creation of secret key failed!\n");
17889 + if(memcmp(key_cn, key_mn, HMAC_SHA1_KEY_SIZE))
17890 + printk("mipv6_rr_key_calc produced different keys for MN and CN \n");
17892 + printk("mipv6_rr_crypto test OK\n");
17899 +++ linux-2.4.27/net/ipv6/mobile_ip6/rr_crypto.h
17902 + * MIPL Mobile IPv6 Return routability crypto prototypes
17906 + * This program is free software; you can redistribute it and/or
17907 + * modify it under the terms of the GNU General Public License
17908 + * as published by the Free Software Foundation; either version
17909 + * 2 of the License, or (at your option) any later version.
17912 +#ifndef _RR_CRYPTO
17913 +#define _RR_CRYPTO
17915 +#include <linux/in6.h>
17917 +/* Macros and data structures */
17919 +#define MIPV6_RR_NONCE_LIFETIME 60
17920 +#define MIPV6_RR_NONCE_DATA_LENGTH 8
17921 +#define MIPV6_RR_COOKIE_LENGTH 8
17922 +#define COOKIE_SIZE 8
17923 +#define MAX_NONCES 4
17924 +#define HMAC_SHA1_KEY_SIZE 20
17926 +struct mipv6_rr_nonce {
17928 + u_int8_t data[MIPV6_RR_NONCE_DATA_LENGTH];
17931 +struct nonce_timestamp {
17932 + struct mipv6_rr_nonce nonce;
17933 + unsigned long timestamp;
17934 + u_int8_t invalid;
17937 +/* Function definitions */
17939 +/* Return 1 if equal, 0 if not */
17940 +static __inline__ int mipv6_equal_cookies(u8 *c1, u8 *c2)
17942 + return (memcmp(c1, c2, MIPV6_RR_COOKIE_LENGTH) == 0);
17945 +/* Function declarations */
17947 +/* Create cookie for HoTi and CoTi */
17948 +extern void mipv6_rr_mn_cookie_create(u8 *cookie);
17950 +/* Create cookie for HoT and CoT */
17951 +extern int mipv6_rr_cookie_create(struct in6_addr *addr, u8 **ckie, u16 nonce_index);
17953 +/* Calculate return routability key from home and care-of cookies, key length is
17954 + * HMAC_SHA1_KEY_SIZE
17956 +extern u_int8_t *mipv6_rr_key_calc(u8 *hoc, u8 *coc);
17958 +extern struct mipv6_rr_nonce *mipv6_rr_get_new_nonce(void);
17960 +/* For avoiding replay attacks when MN deregisters */
17961 +extern void mipv6_rr_invalidate_nonce(u16 nonce_index);
17963 + * initializes the return routability crypto
17966 +void mipv6_rr_init(void);
17968 +#ifdef TEST_MIPV6_RR_CRYPTO
17969 +void mipv6_test_rr(void);
17970 +#endif /* TEST_MIPV6_RR_CRYPTO */
17972 +#endif /* RR_CRYPTO */
17974 +++ linux-2.4.27/net/ipv6/mobile_ip6/sortedlist.c
17977 + * Sorted list - linked list with sortkey.
17980 + * Jaakko Laine <medved@iki.fi>
17984 + * This program is free software; you can redistribute it and/or
17985 + * modify it under the terms of the GNU General Public License
17986 + * as published by the Free Software Foundation; either version
17987 + * 2 of the License, or (at your option) any later version.
17990 +#include <linux/kernel.h>
17991 +#include <linux/types.h>
17992 +#include <linux/list.h>
17993 +#include <linux/slab.h>
17994 +#include <linux/spinlock.h>
17995 +#include <linux/string.h>
17997 +struct mipv6_sorted_list_entry {
17998 + struct list_head list;
18001 + unsigned long sortkey;
18005 + * compare - compares two arbitrary data items
18006 + * @data1: first data item
18007 + * @data2: second data item
18008 + * @datalen: length of data items in bits
18010 + * datalen is in bits!
18012 +int mipv6_bitwise_compare(const void *data1, const void *data2, int datalen)
18015 + __u8 * ptr1 = (__u8 *)data1;
18016 + __u8 * ptr2 = (__u8 *)data2;
18018 + for (; n>=0; n-=8, ptr1++, ptr2++) {
18020 + if (*ptr1 != *ptr2)
18023 + if ((*ptr1 ^ *ptr2) & ((~0) << (8 - n)))
18032 + * mipv6_slist_add - add an entry to sorted list
18033 + * @head: list_head of the sorted list
18034 + * @data: item to store
18035 + * @datalen: length of data (in bytes)
18036 + * @key: sortkey of item
18038 + * Allocates memory for entry and data
18040 +int mipv6_slist_add(struct list_head *head, void *data, int datalen,
18041 + unsigned long sortkey)
18043 + struct list_head *pos;
18044 + struct mipv6_sorted_list_entry *entry, *tmp, *next;
18046 + entry = kmalloc(sizeof(struct mipv6_sorted_list_entry), GFP_ATOMIC);
18051 + entry->data = kmalloc(datalen, GFP_ATOMIC);
18053 + if (!entry->data) {
18058 + memcpy(entry->data, data, datalen);
18059 + entry->datalen = datalen;
18060 + entry->sortkey = sortkey;
18062 + if ((pos = head->next) == head) {
18063 + list_add(&entry->list, head);
18067 + tmp = list_entry(pos, struct mipv6_sorted_list_entry, list);
18068 + if (entry->sortkey < tmp->sortkey) {
18069 + list_add(&entry->list, head);
18073 + for (; pos != head; pos = pos->next) {
18074 + tmp = list_entry(pos, struct mipv6_sorted_list_entry, list);
18075 + if (pos->next == head) {
18076 + list_add(&entry->list, &tmp->list);
18079 + next = list_entry(pos->next, struct mipv6_sorted_list_entry, list);
18080 + if (entry->sortkey >= tmp->sortkey && entry->sortkey < next->sortkey) {
18081 + list_add(&entry->list, &tmp->list);
18086 + /* never reached */
18091 + * mipv6_slist_get_first - get the first data item in the list
18092 + * @head: list_head of the sorted list
18094 + * Returns the actual data item, not copy, so don't kfree it
18096 +void *mipv6_slist_get_first(struct list_head *head)
18098 + struct mipv6_sorted_list_entry *entry;
18100 + if (list_empty(head))
18103 + entry = list_entry(head->next, struct mipv6_sorted_list_entry, list);
18104 + return entry->data;
18108 + * mipv6_slist_del_first - delete (and get) the first item in list
18109 + * @head: list_head of the sorted list
18111 + * Remember to kfree the item
18113 +void *mipv6_slist_del_first(struct list_head *head)
18116 + struct mipv6_sorted_list_entry *entry;
18118 + if (list_empty(head))
18121 + entry = list_entry(head->next, struct mipv6_sorted_list_entry, list);
18122 + tmp = entry->data;
18124 + list_del(head->next);
18131 + * mipv6_slist_del_item - delete entry
18132 + * @head: list_head of the sorted list
18133 + * @data: item to delete
18134 + * @compare: function used for comparing the data items
18136 + * compare function needs to have prototype
18137 + * int (*compare)(const void *data1, const void *data2, int datalen)
18139 +int mipv6_slist_del_item(struct list_head *head, void *data,
18140 + int (*compare)(const void *data1, const void *data2,
18143 + struct list_head *pos;
18144 + struct mipv6_sorted_list_entry *entry;
18146 + for(pos = head->next; pos != head; pos = pos->next) {
18147 + entry = list_entry(pos, struct mipv6_sorted_list_entry, list);
18148 + if (compare(data, entry->data, entry->datalen)) {
18150 + kfree(entry->data);
18160 + * mipv6_slist_get_first_key - get sortkey of the first item
18161 + * @head: list_head of the sorted list
18163 +unsigned long mipv6_slist_get_first_key(struct list_head *head)
18165 + struct mipv6_sorted_list_entry *entry;
18167 + if (list_empty(head))
18170 + entry = list_entry(head->next, struct mipv6_sorted_list_entry, list);
18171 + return entry->sortkey;
18175 + * mipv6_slist_get_key - get sortkey of the data item
18176 + * @head: list_head of the sorted list
18177 + * @data: the item to search for
18178 + * @compare: function used for comparing the data items
18180 + * compare function needs to have prototype
18181 + * int (*compare)(const void *data1, const void *data2, int datalen)
18183 +unsigned long mipv6_slist_get_key(struct list_head *head, void *data,
18184 + int (*compare)(const void *data1,
18185 + const void *data2,
18188 + struct list_head *pos;
18189 + struct mipv6_sorted_list_entry *entry;
18191 + for(pos = head->next; pos != head; pos = pos->next) {
18192 + entry = list_entry(pos, struct mipv6_sorted_list_entry, list);
18193 + if (compare(data, entry->data, entry->datalen))
18194 + return entry->sortkey;
18201 + * mipv6_slist_get_data - get the data item identified by sortkey
18202 + * @head: list_head of the sorted list
18203 + * @key: sortkey of the item
18205 + * Returns the actual data item, not copy, so don't kfree it
18207 +void *mipv6_slist_get_data(struct list_head *head, unsigned long sortkey)
18209 + struct list_head *pos;
18210 + struct mipv6_sorted_list_entry *entry;
18212 + list_for_each(pos, head) {
18213 + entry = list_entry(pos, struct mipv6_sorted_list_entry, list);
18214 + if (entry->sortkey == sortkey)
18215 + return entry->data;
18222 + * reorder_entry - move an entry to a new position according to sortkey
18223 + * @head: list_head of the sorted list
18224 + * @entry_pos: current place of the entry
18225 + * @key: new sortkey
18227 +static void reorder_entry(struct list_head *head, struct list_head *entry_pos,
18228 + unsigned long sortkey)
18230 + struct list_head *pos;
18231 + struct mipv6_sorted_list_entry *entry;
18233 + list_del(entry_pos);
18235 + for (pos = head->next; pos != head; pos = pos->next) {
18236 + entry = list_entry(pos, struct mipv6_sorted_list_entry, list);
18237 + if (sortkey >= entry->sortkey) {
18238 + list_add(entry_pos, &entry->list);
18243 + list_add(entry_pos, head);
18247 + * mipv6_slist_modify - modify data item
18248 + * @head: list_head of the sorted list
18249 + * @data: item, whose sortkey is to be modified
18250 + * @datalen: datalen in bytes
18251 + * @new_key: new sortkey
18252 + * @compare: function used for comparing the data items
18254 + * Compies the new data on top of the old one, if compare function returns
18255 + * true. If there's no matching entry, new one will be created.
18256 + * Compare function needs to have prototype
18257 + * int (*compare)(const void *data1, const void *data2, int datalen)
18259 +int mipv6_slist_modify(struct list_head *head, void *data, int datalen,
18260 + unsigned long new_key,
18261 + int (*compare)(const void *data1, const void *data2,
18264 + struct list_head *pos;
18265 + struct mipv6_sorted_list_entry *entry;
18267 + for (pos = head->next; pos != head; pos = pos->next) {
18268 + entry = list_entry(pos, struct mipv6_sorted_list_entry, list);
18269 + if (compare(data, entry->data, datalen)) {
18270 + memcpy(entry->data, data, datalen);
18271 + entry->sortkey = new_key;
18272 + reorder_entry(head, &entry->list, new_key);
18277 + return mipv6_slist_add(head, data, datalen, new_key);
18281 + * mipv6_slist_push_first - move the first entry to place indicated by new_key
18282 + * @head: list_head of the sorted list
18283 + * @new_key: new sortkey
18285 +int mipv6_slist_push_first(struct list_head *head, unsigned long new_key)
18287 + struct mipv6_sorted_list_entry *entry;
18289 + if (list_empty(head))
18292 + entry = list_entry(head->next, struct mipv6_sorted_list_entry, list);
18293 + entry->sortkey = new_key;
18295 + reorder_entry(head, head->next, new_key);
18300 + * mipv6_slist_for_each - apply func to every item in list
18301 + * @head: list_head of the sorted list
18302 + * @args: args to pass to func
18303 + * @func: function to use
18305 + * function must be of type
18306 + * int (*func)(void *data, void *args, unsigned long sortkey)
18307 + * List iteration will stop once func has been applied to every item
18308 + * or when func returns true
18310 +int mipv6_slist_for_each(struct list_head *head, void *args,
18311 + int (*func)(void *data, void *args,
18312 + unsigned long sortkey))
18314 + struct list_head *pos;
18315 + struct mipv6_sorted_list_entry *entry;
18317 + list_for_each(pos, head) {
18318 + entry = list_entry(pos, struct mipv6_sorted_list_entry, list);
18319 + if (func(entry->data, args, entry->sortkey))
18326 +++ linux-2.4.27/net/ipv6/mobile_ip6/sortedlist.h
18329 + * Sorted list - linked list with sortkey
18333 + * This program is free software; you can redistribute it and/or
18334 + * modify it under the terms of the GNU General Public License
18335 + * as published by the Free Software Foundation; either version
18336 + * 2 of the License, or (at your option) any later version.
18340 + * compare - compares two arbitrary data items
18341 + * @data1: first data item
18342 + * @data2: second data item
18343 + * @datalen: length of data items in bits
18345 + * datalen is in bits!
18347 +int mipv6_bitwise_compare(const void *data1, const void *data2, int datalen);
18350 + * mipv6_slist_add - add an entry to sorted list
18351 + * @head: list_head of the sorted list
18352 + * @data: item to store
18353 + * @datalen: length of data (in bytes)
18354 + * @key: sortkey of item
18356 + * Allocates memory for entry and data
18358 +int mipv6_slist_add(struct list_head *head, void *data, int datalen,
18359 + unsigned long sortkey);
18362 + * mipv6_slist_get_first - get the first data item in the list
18363 + * @head: list_head of the sorted list
18365 + * Returns the actual data item, not copy, so don't kfree it
18367 +void *mipv6_slist_get_first(struct list_head *head);
18370 + * mipv6_slist_del_first - delete (and get) the first item in list
18371 + * @head: list_head of the sorted list
18373 + * Remember to kfree the item
18375 +void *mipv6_slist_del_first(struct list_head *head);
18378 + * mipv6_slist_del_item - delete entry
18379 + * @head: list_head of the sorted list
18380 + * @data: item to delete
18381 + * @compare: function used for comparing the data items
18383 + * compare function needs to have prototype
18384 + * int (*compare)(const void *data1, const void *data2, int datalen) where
18385 + * datalen is in bits
18387 +int mipv6_slist_del_item(struct list_head *head, void *data,
18388 + int (*compare)(const void *data1, const void *data2,
18392 + * mipv6_slist_get_first_key - get sortkey of the first item
18393 + * @head: list_head of the sorted list
18395 +unsigned long mipv6_slist_get_first_key(struct list_head *head);
18398 + * mipv6_slist_get_key - get sortkey of the data item
18399 + * @head: list_head of the sorted list
18400 + * @data: the item to search for
18401 + * @compare: function used for comparing the data items
18403 + * compare function needs to have prototype
18404 + * int (*compare)(const void *data1, const void *data2, int datalen) where
18405 + * datalen is in bits
18407 +unsigned long mipv6_slist_get_key(struct list_head *head, void *data,
18408 + int (*compare)(const void *data1,
18409 + const void *data2,
18413 + * mipv6_slist_get_data - get the data item identified by sortkey
18414 + * @head: list_head of the sorted list
18415 + * @key: sortkey of the item
18417 + * Returns the actual data item, not copy, so don't kfree it
18419 +void *mipv6_slist_get_data(struct list_head *head, unsigned long sortkey);
18422 + * mipv6_slist_modify - modify data item
18423 + * @head: list_head of the sorted list
18424 + * @data: item, whose sortkey is to be modified
18425 + * @datalen: datalen in bytes
18426 + * @new_key: new sortkey
18427 + * @compare: function used for comparing the data items
18429 + * Compies the new data on top of the old one, if compare function returns
18430 + * non-negative. If there's no matching entry, new one will be created.
18431 + * Compare function needs to have prototype
18432 + * int (*compare)(const void *data1, const void *data2, int datalen) where
18433 + * datalen is in bits.
18435 +int mipv6_slist_modify(struct list_head *head, void *data, int datalen,
18436 + unsigned long new_key,
18437 + int (*compare)(const void *data1, const void *data2,
18441 + * mipv6_slist_push_first - move the first entry to place indicated by new_key
18442 + * @head: list_head of the sorted list
18443 + * @new_key: new sortkey
18445 +int mipv6_slist_push_first(struct list_head *head, unsigned long new_key);
18448 + * mipv6_slist_for_each - apply func to every item in list
18449 + * @head: list_head of the sorted list
18450 + * @args: args to pass to func
18451 + * @func: function to use
18453 + * function must be of type
18454 + * int (*func)(void *data, void *args, unsigned long sortkey)
18455 + * List iteration will stop once func has been applied to every item
18456 + * or when func returns true
18458 +int mipv6_slist_for_each(struct list_head *head, void *args,
18459 + int (*func)(void *data, void *args,
18460 + unsigned long sortkey));
18462 +++ linux-2.4.27/net/ipv6/mobile_ip6/stats.c
18465 + * Statistics module
18468 + * Sami Kivisaari <skivisaa@cc.hut.fi>
18472 + * This program is free software; you can redistribute it and/or
18473 + * modify it under the terms of the GNU General Public License
18474 + * as published by the Free Software Foundation; either version
18475 + * 2 of the License, or (at your option) any later version.
18479 + * Venkata Jagana : SMP locking fix
18482 +#include <linux/config.h>
18483 +#include <linux/proc_fs.h>
18484 +#include "stats.h"
18486 +struct mipv6_statistics mipv6_stats;
18488 +static int proc_info_dump(
18489 + char *buffer, char **start,
18490 + off_t offset, int length)
18495 + } int_stats[] = {
18496 + {"NEncapsulations", &mipv6_stats.n_encapsulations},
18497 + {"NDecapsulations", &mipv6_stats.n_decapsulations},
18498 + {"NBindRefreshRqsRcvd", &mipv6_stats.n_brr_rcvd},
18499 + {"NHomeTestInitsRcvd", &mipv6_stats.n_hoti_rcvd},
18500 + {"NCareofTestInitsRcvd", &mipv6_stats.n_coti_rcvd},
18501 + {"NHomeTestRcvd", &mipv6_stats.n_hot_rcvd},
18502 + {"NCareofTestRcvd", &mipv6_stats.n_cot_rcvd},
18503 + {"NBindUpdatesRcvd", &mipv6_stats.n_bu_rcvd},
18504 + {"NBindAcksRcvd", &mipv6_stats.n_ba_rcvd},
18505 + {"NBindNAcksRcvd", &mipv6_stats.n_ban_rcvd},
18506 + {"NBindErrorsRcvd", &mipv6_stats.n_be_rcvd},
18507 + {"NBindRefreshRqsSent", &mipv6_stats.n_brr_sent},
18508 + {"NHomeTestInitsSent", &mipv6_stats.n_hoti_sent},
18509 + {"NCareofTestInitsSent", &mipv6_stats.n_coti_sent},
18510 + {"NHomeTestSent", &mipv6_stats.n_hot_sent},
18511 + {"NCareofTestSent", &mipv6_stats.n_cot_sent},
18512 + {"NBindUpdatesSent", &mipv6_stats.n_bu_sent},
18513 + {"NBindAcksSent", &mipv6_stats.n_ba_sent},
18514 + {"NBindNAcksSent", &mipv6_stats.n_ban_sent},
18515 + {"NBindErrorsSent", &mipv6_stats.n_be_sent},
18516 + {"NBindUpdatesDropAuth", &mipv6_stats.n_bu_drop.auth},
18517 + {"NBindUpdatesDropInvalid", &mipv6_stats.n_bu_drop.invalid},
18518 + {"NBindUpdatesDropMisc", &mipv6_stats.n_bu_drop.misc},
18519 + {"NBindAcksDropAuth", &mipv6_stats.n_bu_drop.auth},
18520 + {"NBindAcksDropInvalid", &mipv6_stats.n_bu_drop.invalid},
18521 + {"NBindAcksDropMisc", &mipv6_stats.n_bu_drop.misc},
18522 + {"NBindRqsDropAuth", &mipv6_stats.n_bu_drop.auth},
18523 + {"NBindRqsDropInvalid", &mipv6_stats.n_bu_drop.invalid},
18524 + {"NBindRqsDropMisc", &mipv6_stats.n_bu_drop.misc}
18529 + for(i=0; i<sizeof(int_stats) / sizeof(struct inf); i++) {
18530 + len += sprintf(buffer + len, "%s = %d\n",
18531 + int_stats[i].name, *int_stats[i].value);
18534 + *start = buffer + offset;
18538 + if(len > length) len = length;
18543 +int mipv6_stats_init(void)
18545 + memset(&mipv6_stats, 0, sizeof(struct mipv6_statistics));
18546 + proc_net_create("mip6_stat", 0, proc_info_dump);
18550 +void mipv6_stats_exit(void)
18552 + proc_net_remove("mip6_stat");
18555 +++ linux-2.4.27/net/ipv6/mobile_ip6/stats.h
18558 + * MIPL Mobile IPv6 Statistics header file
18562 + * This program is free software; you can redistribute it and/or
18563 + * modify it under the terms of the GNU General Public License
18564 + * as published by the Free Software Foundation; either version
18565 + * 2 of the License, or (at your option) any later version.
18571 +struct mipv6_drop {
18577 +struct mipv6_statistics {
18578 + int n_encapsulations;
18579 + int n_decapsulations;
18581 + int n_mh_in_error;
18582 + int n_mh_out_msg;
18583 + int n_mh_out_error;
18608 + struct mipv6_drop n_bu_drop;
18609 + struct mipv6_drop n_ba_drop;
18610 + struct mipv6_drop n_brr_drop;
18611 + struct mipv6_drop n_be_drop;
18612 + struct mipv6_drop n_ha_drop;
18615 +extern struct mipv6_statistics mipv6_stats;
18618 +/* atomic_t is max 24 bits long */
18619 +#define MIPV6_INC_STATS(X) atomic_inc((atomic_t *)&mipv6_stats.X);
18621 +#define MIPV6_INC_STATS(X) mipv6_stats.X++;
18624 +int mipv6_stats_init(void);
18625 +void mipv6_stats_exit(void);
18629 +++ linux-2.4.27/net/ipv6/mobile_ip6/tunnel.h
18632 + * MIPL Mobile IPv6 IP6-IP6 tunneling header file
18636 + * This program is free software; you can redistribute it and/or
18637 + * modify it under the terms of the GNU General Public License
18638 + * as published by the Free Software Foundation; either version
18639 + * 2 of the License, or (at your option) any later version.
18645 +#include <linux/in6.h>
18646 +#include <linux/if_arp.h>
18647 +#include <net/ipv6_tunnel.h>
18649 +static __inline__ int is_mip6_tnl(struct ip6_tnl *t)
18651 + return (t != NULL &&
18652 + t->parms.flags & IP6_TNL_F_KERNEL_DEV &&
18653 + t->parms.flags & IP6_TNL_F_MIP6_DEV);
18657 +static __inline__ int dev_is_mip6_tnl(struct net_device *dev)
18659 + struct ip6_tnl *t = (struct ip6_tnl *)dev->priv;
18660 + return (dev->type == ARPHRD_TUNNEL6 && is_mip6_tnl(t));
18667 +++ linux-2.4.27/net/ipv6/mobile_ip6/tunnel_ha.c
18670 + * IPv6-IPv6 tunneling module
18673 + * Sami Kivisaari <skivisaa@cc.hut.fi>
18674 + * Ville Nuorvala <vnuorval@tml.hut.fi>
18678 + * This program is free software; you can redistribute it and/or
18679 + * modify it under the terms of the GNU General Public License
18680 + * as published by the Free Software Foundation; either version
18681 + * 2 of the License, or (at your option) any later version.
18685 +#include <linux/net.h>
18686 +#include <linux/skbuff.h>
18687 +#include <linux/ipv6.h>
18688 +#include <linux/net.h>
18689 +#include <linux/netdevice.h>
18690 +#include <linux/init.h>
18691 +#include <linux/route.h>
18692 +#include <linux/ipv6_route.h>
18694 +#ifdef CONFIG_SYSCTL
18695 +#include <linux/sysctl.h>
18696 +#endif /* CONFIG_SYSCTL */
18698 +#include <net/protocol.h>
18699 +#include <net/ipv6.h>
18700 +#include <net/ip6_route.h>
18701 +#include <net/dst.h>
18702 +#include <net/addrconf.h>
18704 +#include "tunnel.h"
18705 +#include "debug.h"
18706 +#include "stats.h"
18707 +#include "config.h"
18709 +#define MIPV6_TNL_MAX IP6_TNL_MAX
18710 +#define MIPV6_TNL_MIN 1
18712 +int mipv6_max_tnls = 3;
18713 +int mipv6_min_tnls = 1;
18715 +DECLARE_MUTEX(tnl_sem);
18717 +int mipv6_max_tnls_sysctl(ctl_table *ctl, int write, struct file *filp,
18718 + void *buffer, size_t *lenp)
18727 + int old_max_tnls = mipv6_max_tnls;
18728 + err = proc_dointvec(ctl, write, filp, buffer, lenp);
18731 + if (mipv6_max_tnls < mipv6_min_tnls ||
18732 + mipv6_max_tnls > MIPV6_TNL_MAX) {
18733 + mipv6_max_tnls = old_max_tnls;
18736 + if (mipv6_max_tnls < old_max_tnls) {
18737 + diff = old_max_tnls - mipv6_max_tnls;
18738 + ip6ip6_tnl_dec_max_kdev_count(diff);
18739 + } else if (mipv6_max_tnls > old_max_tnls) {
18740 + diff = mipv6_max_tnls - old_max_tnls;
18741 + ip6ip6_tnl_inc_max_kdev_count(diff);
18744 + err = proc_dointvec(ctl, write, filp, buffer, lenp);
18751 +int mipv6_min_tnls_sysctl(ctl_table *ctl, int write, struct file *filp,
18752 + void *buffer, size_t *lenp)
18761 + int old_min_tnls = mipv6_min_tnls;
18762 + err = proc_dointvec(ctl, write, filp, buffer, lenp);
18765 + if (mipv6_min_tnls > mipv6_max_tnls ||
18766 + mipv6_min_tnls < MIPV6_TNL_MIN) {
18767 + mipv6_min_tnls = old_min_tnls;
18770 + if (mipv6_min_tnls < old_min_tnls) {
18771 + diff = old_min_tnls - mipv6_min_tnls;
18772 + ip6ip6_tnl_dec_min_kdev_count(diff);
18773 + } else if (mipv6_min_tnls > old_min_tnls) {
18774 + diff = mipv6_min_tnls - old_min_tnls;
18775 + ip6ip6_tnl_inc_min_kdev_count(diff);
18778 + err = proc_dointvec(ctl, write, filp, buffer, lenp);
18785 +static __inline__ int mipv6_tnl_add(struct in6_addr *remote,
18786 + struct in6_addr *local)
18788 + struct ip6_tnl_parm p;
18793 + memset(&p, 0, sizeof(p));
18794 + p.proto = IPPROTO_IPV6;
18795 + ipv6_addr_copy(&p.laddr, local);
18796 + ipv6_addr_copy(&p.raddr, remote);
18797 + p.hop_limit = 255;
18798 + p.flags = (IP6_TNL_F_KERNEL_DEV | IP6_TNL_F_MIP6_DEV |
18799 + IP6_TNL_F_IGN_ENCAP_LIMIT);
18801 + ret = ip6ip6_kernel_tnl_add(&p);
18803 + DEBUG(DBG_INFO, "added tunnel from: "
18804 + "%x:%x:%x:%x:%x:%x:%x:%x to: %x:%x:%x:%x:%x:%x:%x:%x",
18805 + NIPV6ADDR(local), NIPV6ADDR(remote));
18807 + DEBUG(DBG_WARNING, "unable to add tunnel from: "
18808 + "%x:%x:%x:%x:%x:%x:%x:%x to: %x:%x:%x:%x:%x:%x:%x:%x",
18809 + NIPV6ADDR(local), NIPV6ADDR(remote));
18814 +static __inline__ int mipv6_tnl_del(struct in6_addr *remote,
18815 + struct in6_addr *local)
18817 + struct ip6_tnl *t = ip6ip6_tnl_lookup(remote, local);
18821 + if (t != NULL && (t->parms.flags & IP6_TNL_F_MIP6_DEV)) {
18822 + DEBUG(DBG_INFO, "deleting tunnel from: "
18823 + "%x:%x:%x:%x:%x:%x:%x:%x to: %x:%x:%x:%x:%x:%x:%x:%x",
18824 + NIPV6ADDR(local), NIPV6ADDR(remote));
18826 + return ip6ip6_kernel_tnl_del(t);
18831 +static int add_route_to_mn(struct in6_addr *coa, struct in6_addr *ha_addr,
18832 + struct in6_addr *home_addr)
18834 + struct in6_rtmsg rtmsg;
18836 + struct ip6_tnl *t = ip6ip6_tnl_lookup(coa, ha_addr);
18838 + if (!is_mip6_tnl(t)) {
18839 + DEBUG(DBG_CRITICAL,"Tunnel missing");
18843 + DEBUG(DBG_INFO, "adding route to: %x:%x:%x:%x:%x:%x:%x:%x via "
18844 + "tunnel device", NIPV6ADDR(home_addr));
18846 + memset(&rtmsg, 0, sizeof(rtmsg));
18847 + ipv6_addr_copy(&rtmsg.rtmsg_dst, home_addr);
18848 + rtmsg.rtmsg_dst_len = 128;
18849 + rtmsg.rtmsg_type = RTMSG_NEWROUTE;
18850 + rtmsg.rtmsg_flags = RTF_UP | RTF_NONEXTHOP | RTF_HOST | RTF_MOBILENODE;
18851 + rtmsg.rtmsg_ifindex = t->dev->ifindex;
18852 + rtmsg.rtmsg_metric = IP6_RT_PRIO_MIPV6;
18853 + if ((err = ip6_route_add(&rtmsg, NULL)) == -EEXIST) {
18859 +static void del_route_to_mn(struct in6_addr *coa, struct in6_addr *ha_addr,
18860 + struct in6_addr *home_addr)
18862 + struct ip6_tnl *t = ip6ip6_tnl_lookup(coa, ha_addr);
18866 + if (is_mip6_tnl(t)) {
18867 + struct in6_rtmsg rtmsg;
18869 + DEBUG(DBG_INFO, "deleting route to: %x:%x:%x:%x:%x:%x:%x:%x "
18870 + " via tunnel device", NIPV6ADDR(home_addr));
18872 + memset(&rtmsg, 0, sizeof(rtmsg));
18873 + ipv6_addr_copy(&rtmsg.rtmsg_dst, home_addr);
18874 + rtmsg.rtmsg_dst_len = 128;
18875 + rtmsg.rtmsg_ifindex = t->dev->ifindex;
18876 + rtmsg.rtmsg_metric = IP6_RT_PRIO_MIPV6;
18877 + ip6_route_del(&rtmsg, NULL);
18882 +int mipv6_add_tnl_to_mn(struct in6_addr *coa,
18883 + struct in6_addr *ha_addr,
18884 + struct in6_addr *home_addr)
18890 + ret = mipv6_tnl_add(coa, ha_addr);
18893 + int err = add_route_to_mn(coa, ha_addr, home_addr);
18895 + if (err != -ENODEV) {
18896 + mipv6_tnl_del(coa, ha_addr);
18904 +int mipv6_del_tnl_to_mn(struct in6_addr *coa,
18905 + struct in6_addr *ha_addr,
18906 + struct in6_addr *home_addr)
18909 + del_route_to_mn(coa, ha_addr, home_addr);
18910 + return mipv6_tnl_del(coa, ha_addr);
18913 +__init void mipv6_initialize_tunnel(void)
18916 + ip6ip6_tnl_inc_max_kdev_count(mipv6_max_tnls);
18917 + ip6ip6_tnl_inc_min_kdev_count(mipv6_min_tnls);
18919 + mip6_fn.bce_tnl_rt_add = add_route_to_mn;
18920 + mip6_fn.bce_tnl_rt_del = del_route_to_mn;
18923 +__exit void mipv6_shutdown_tunnel(void)
18925 + mip6_fn.bce_tnl_rt_del = NULL;
18926 + mip6_fn.bce_tnl_rt_add = NULL;
18928 + ip6ip6_tnl_dec_min_kdev_count(mipv6_min_tnls);
18929 + ip6ip6_tnl_dec_max_kdev_count(mipv6_max_tnls);
18934 +++ linux-2.4.27/net/ipv6/mobile_ip6/tunnel_ha.h
18936 +#ifndef _TUNNEL_HA_H
18937 +#define _TUNNEL_HA_H
18939 +#include "tunnel.h"
18941 +extern int mipv6_max_tnls;
18942 +extern int mipv6_min_tnls;
18944 +extern void mipv6_initialize_tunnel(void);
18945 +extern void mipv6_shutdown_tunnel(void);
18947 +extern int mipv6_add_tnl_to_mn(struct in6_addr *coa,
18948 + struct in6_addr *ha_addr,
18949 + struct in6_addr *home_addr);
18951 +extern int mipv6_del_tnl_to_mn(struct in6_addr *coa,
18952 + struct in6_addr *ha_addr,
18953 + struct in6_addr *home_addr);
18957 +++ linux-2.4.27/net/ipv6/mobile_ip6/tunnel_mn.c
18960 + * IPv6-IPv6 tunneling module
18963 + * Sami Kivisaari <skivisaa@cc.hut.fi>
18964 + * Ville Nuorvala <vnuorval@tml.hut.fi>
18968 + * This program is free software; you can redistribute it and/or
18969 + * modify it under the terms of the GNU General Public License
18970 + * as published by the Free Software Foundation; either version
18971 + * 2 of the License, or (at your option) any later version.
18975 +#include <linux/net.h>
18976 +#include <linux/skbuff.h>
18977 +#include <linux/ipv6.h>
18978 +#include <linux/net.h>
18979 +#include <linux/netdevice.h>
18980 +#include <linux/init.h>
18981 +#include <linux/route.h>
18982 +#include <linux/ipv6_route.h>
18984 +#ifdef CONFIG_SYSCTL
18985 +#include <linux/sysctl.h>
18986 +#endif /* CONFIG_SYSCTL */
18988 +#include <net/protocol.h>
18989 +#include <net/ipv6.h>
18990 +#include <net/ip6_route.h>
18991 +#include <net/dst.h>
18992 +#include <net/addrconf.h>
18994 +#include "tunnel.h"
18995 +#include "debug.h"
18996 +#include "stats.h"
18998 +static struct net_device *mn_ha_tdev;
19000 +static spinlock_t mn_ha_lock = SPIN_LOCK_UNLOCKED;
19002 +static __inline__ int add_reverse_route(struct in6_addr *ha_addr,
19003 + struct in6_addr *home_addr,
19004 + struct net_device *tdev)
19006 + struct in6_rtmsg rtmsg;
19011 + memset(&rtmsg, 0, sizeof(rtmsg));
19012 + rtmsg.rtmsg_type = RTMSG_NEWROUTE;
19013 + ipv6_addr_copy(&rtmsg.rtmsg_src, home_addr);
19014 + rtmsg.rtmsg_src_len = 128;
19015 + rtmsg.rtmsg_flags = RTF_UP | RTF_DEFAULT;
19016 + rtmsg.rtmsg_ifindex = tdev->ifindex;
19017 + rtmsg.rtmsg_metric = IP6_RT_PRIO_MIPV6;
19018 + if ((err = ip6_route_add(&rtmsg, NULL)) == -EEXIST) {
19024 +static __inline__ void del_reverse_route(struct in6_addr *ha_addr,
19025 + struct in6_addr *home_addr,
19026 + struct net_device *tdev)
19028 + struct in6_rtmsg rtmsg;
19030 + DEBUG(DBG_INFO, "removing reverse route via tunnel device");
19032 + memset(&rtmsg, 0, sizeof(rtmsg));
19033 + ipv6_addr_copy(&rtmsg.rtmsg_src, home_addr);
19034 + rtmsg.rtmsg_src_len = 128;
19035 + rtmsg.rtmsg_ifindex = tdev->ifindex;
19036 + rtmsg.rtmsg_metric = IP6_RT_PRIO_MIPV6;
19037 + ip6_route_del(&rtmsg, NULL);
19040 +int mipv6_add_tnl_to_ha(void)
19042 + struct ip6_tnl_parm p;
19043 + struct ip6_tnl *t;
19048 + memset(&p, 0, sizeof(p));
19049 + p.proto = IPPROTO_IPV6;
19050 + p.hop_limit = 255;
19051 + p.flags = (IP6_TNL_F_KERNEL_DEV | IP6_TNL_F_MIP6_DEV |
19052 + IP6_TNL_F_IGN_ENCAP_LIMIT);
19053 + strcpy(p.name, "mip6mnha1");
19056 + if ((err = ip6ip6_tnl_create(&p, &t))) {
19060 + spin_lock_bh(&mn_ha_lock);
19062 + if (!mn_ha_tdev) {
19063 + mn_ha_tdev = t->dev;
19064 + dev_hold(mn_ha_tdev);
19066 + spin_unlock_bh(&mn_ha_lock);
19067 + dev_open(t->dev);
19072 +int mipv6_mv_tnl_to_ha(struct in6_addr *ha_addr,
19073 + struct in6_addr *coa,
19074 + struct in6_addr *home_addr)
19076 + int err = -ENODEV;
19080 + spin_lock_bh(&mn_ha_lock);
19081 + if (mn_ha_tdev) {
19082 + struct ip6_tnl_parm p;
19083 + memset(&p, 0, sizeof(p));
19084 + p.proto = IPPROTO_IPV6;
19085 + ipv6_addr_copy(&p.laddr, coa);
19086 + ipv6_addr_copy(&p.raddr, ha_addr);
19087 + p.hop_limit = 255;
19088 + p.flags = (IP6_TNL_F_KERNEL_DEV | IP6_TNL_F_MIP6_DEV |
19089 + IP6_TNL_F_IGN_ENCAP_LIMIT);
19091 + ip6ip6_tnl_change((struct ip6_tnl *) mn_ha_tdev->priv, &p);
19092 + if (ipv6_addr_cmp(coa, home_addr)) {
19093 + err = add_reverse_route(ha_addr, home_addr,
19096 + del_reverse_route(ha_addr, home_addr, mn_ha_tdev);
19100 + spin_unlock_bh(&mn_ha_lock);
19104 +void mipv6_del_tnl_to_ha(void)
19106 + struct net_device *dev;
19111 + spin_lock_bh(&mn_ha_lock);
19112 + dev = mn_ha_tdev;
19113 + mn_ha_tdev = NULL;
19114 + spin_unlock_bh(&mn_ha_lock);
19116 + unregister_netdevice(dev);
19120 +++ linux-2.4.27/net/ipv6/mobile_ip6/tunnel_mn.h
19122 +#ifndef _TUNNEL_MN_H
19123 +#define _TUNNEL_MN_H
19125 +#include "tunnel.h"
19127 +extern int mipv6_add_tnl_to_ha(void);
19129 +extern int mipv6_mv_tnl_to_ha(struct in6_addr *ha_addr,
19130 + struct in6_addr *coa,
19131 + struct in6_addr *home_addr);
19133 +extern int mipv6_del_tnl_to_ha(void);
19137 +++ linux-2.4.27/net/ipv6/mobile_ip6/util.h
19140 + * MIPL Mobile IPv6 Utility functions
19144 + * This program is free software; you can redistribute it and/or
19145 + * modify it under the terms of the GNU General Public License
19146 + * as published by the Free Software Foundation; either version
19147 + * 2 of the License, or (at your option) any later version.
19153 +#include <linux/in6.h>
19154 +#include <asm/byteorder.h>
19157 + * mipv6_prefix_compare - Compare two IPv6 prefixes
19158 + * @addr: IPv6 address
19159 + * @prefix: IPv6 address
19160 + * @nprefix: number of bits to compare
19162 + * Perform prefix comparison bitwise for the @nprefix first bits
19163 + * Returns 1, if the prefixes are the same, 0 otherwise
19165 +static inline int mipv6_prefix_compare(const struct in6_addr *addr,
19166 + const struct in6_addr *prefix,
19167 + const unsigned int pfix_len)
19170 + unsigned int nprefix = pfix_len;
19172 + if (nprefix > 128)
19175 + for (i = 0; nprefix > 0; nprefix -= 32, i++) {
19176 + if (nprefix >= 32) {
19177 + if (addr->s6_addr32[i] != prefix->s6_addr32[i])
19180 + if (((addr->s6_addr32[i] ^ prefix->s6_addr32[i]) &
19181 + ((~0) << (32 - nprefix))) != 0)
19191 + * homeagent_anycast - Compute Home Agent anycast address
19192 + * @ac_addr: append home agent anycast suffix to passed prefix
19193 + * @prefix: prefix ha anycast address is generated from
19194 + * @plen: length of prefix in bits
19196 + * Calculate corresponding Home Agent Anycast Address (RFC2526) in a
19200 +mipv6_ha_anycast(struct in6_addr *ac_addr, struct in6_addr *prefix, int plen)
19202 + if (plen <= 0 || plen > 120) {
19203 + /* error, interface id should be minimum 8 bits */
19206 + ipv6_addr_copy(ac_addr, prefix);
19209 + ac_addr->s6_addr32[0] |= htonl((u32)(~0) >> plen);
19211 + ac_addr->s6_addr32[1] |= htonl((u32)(~0) >> (plen > 32 ? plen % 32 : 0));
19213 + ac_addr->s6_addr32[2] |= htonl((u32)(~0) >> (plen > 64 ? plen % 32 : 0));
19215 + ac_addr->s6_addr32[3] |= htonl((u32)(~0) >> (plen > 92 ? plen % 32 : 0));
19217 + /* RFC2526: for interface identifiers in EUI-64
19218 + * format, the universal/local bit in the interface
19219 + * identifier MUST be set to 0. */
19220 + if (plen == 64) {
19221 + ac_addr->s6_addr32[2] &= (int)htonl(0xfdffffff);
19223 + /* Mobile IPv6 Home-Agents anycast id (0x7e) */
19224 + ac_addr->s6_addr32[3] &= (int)htonl(0xfffffffe);
19229 +#endif /* _UTIL_H */
19230 --- linux-2.4.27/net/ipv6/ndisc.c~mipv6-1.1-v2.4.26
19231 +++ linux-2.4.27/net/ipv6/ndisc.c
19233 * and moved to net/core.
19234 * Pekka Savola : RFC2461 validation
19235 * YOSHIFUJI Hideaki @USAGI : Verify ND options properly
19236 + * Ville Nuorvala : RFC2461 fixes to proxy ND
19239 /* Set to 3 to get tracing... */
19241 #include <net/ip6_route.h>
19242 #include <net/addrconf.h>
19243 #include <net/icmp.h>
19244 +#include <net/mipglue.h>
19246 #include <net/checksum.h>
19247 #include <linux/proc_fs.h>
19248 @@ -187,6 +189,8 @@
19249 case ND_OPT_TARGET_LL_ADDR:
19251 case ND_OPT_REDIRECT_HDR:
19252 + case ND_OPT_RTR_ADV_INTERVAL:
19253 + case ND_OPT_HOME_AGENT_INFO:
19254 if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) {
19255 ND_PRINTK2((KERN_WARNING
19256 "ndisc_parse_options(): duplicated ND6 option found: type=%d\n",
19257 @@ -372,8 +376,8 @@
19260 void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
19261 - struct in6_addr *daddr, struct in6_addr *solicited_addr,
19262 - int router, int solicited, int override, int inc_opt)
19263 + struct in6_addr *daddr, struct in6_addr *solicited_addr,
19264 + int router, int solicited, int override, int inc_opt)
19266 static struct in6_addr tmpaddr;
19267 struct inet6_ifaddr *ifp;
19268 @@ -766,7 +770,8 @@
19269 int addr_type = ipv6_addr_type(saddr);
19271 if (in6_dev && in6_dev->cnf.forwarding &&
19272 - (addr_type & IPV6_ADDR_UNICAST) &&
19273 + (addr_type & IPV6_ADDR_UNICAST ||
19274 + addr_type == IPV6_ADDR_ANY) &&
19275 pneigh_lookup(&nd_tbl, &msg->target, dev, 0)) {
19276 int inc = ipv6_addr_type(daddr)&IPV6_ADDR_MULTICAST;
19278 @@ -778,13 +783,21 @@
19279 nd_tbl.stats.rcv_probes_mcast++;
19281 nd_tbl.stats.rcv_probes_ucast++;
19283 - neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, dev);
19286 - ndisc_send_na(dev, neigh, saddr, &msg->target,
19288 - neigh_release(neigh);
19289 + if (addr_type & IPV6_ADDR_UNICAST) {
19290 + neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, dev);
19293 + ndisc_send_na(dev, neigh, saddr, &msg->target,
19295 + neigh_release(neigh);
19298 + /* the proxy should also protect against DAD */
19299 + struct in6_addr maddr;
19300 + ipv6_addr_all_nodes(&maddr);
19301 + ndisc_send_na(dev, NULL, &maddr, &msg->target,
19305 struct sk_buff *n = skb_clone(skb, GFP_ATOMIC);
19306 @@ -849,6 +862,9 @@
19307 if (ifp->flags & IFA_F_TENTATIVE) {
19308 addrconf_dad_failure(ifp);
19310 + } else if (ndisc_mip_mn_ha_probe(ifp, lladdr)) {
19311 + in6_ifa_put(ifp);
19314 /* What should we make now? The advertisement
19315 is invalid, but ndisc specs say nothing
19316 @@ -887,6 +903,7 @@
19317 msg->icmph.icmp6_override, 1);
19318 neigh_release(neigh);
19320 + ndisc_check_mipv6_dad(&msg->target);
19323 static void ndisc_router_discovery(struct sk_buff *skb)
19324 @@ -894,6 +911,7 @@
19325 struct ra_msg *ra_msg = (struct ra_msg *) skb->h.raw;
19326 struct neighbour *neigh;
19327 struct inet6_dev *in6_dev;
19329 struct rt6_info *rt;
19331 struct ndisc_options ndopts;
19332 @@ -923,10 +941,6 @@
19333 ND_PRINTK1("RA: can't find in6 device\n");
19336 - if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_ra) {
19337 - in6_dev_put(in6_dev);
19341 if (!ndisc_parse_options(opt, optlen, &ndopts)) {
19342 in6_dev_put(in6_dev);
19343 @@ -935,7 +949,12 @@
19344 "ICMP6 RA: invalid ND option, ignored.\n");
19347 + change_rtr = ndisc_mipv6_ra_rcv(skb, &ndopts);
19349 + if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_ra) {
19350 + in6_dev_put(in6_dev);
19353 if (in6_dev->if_flags & IF_RS_SENT) {
19355 * flag that an RA was received after an RS was sent
19356 @@ -963,8 +982,7 @@
19357 ip6_del_rt(rt, NULL);
19361 - if (rt == NULL && lifetime) {
19362 + if (rt == NULL && lifetime && change_rtr) {
19363 ND_PRINTK2("ndisc_rdisc: adding default router\n");
19365 rt = rt6_add_dflt_router(&skb->nh.ipv6h->saddr, skb->dev);
19366 @@ -1087,6 +1105,8 @@
19368 dst_release(&rt->u.dst);
19369 in6_dev_put(in6_dev);
19371 + ndisc_mipv6_change_router(change_rtr);
19374 static void ndisc_redirect_rcv(struct sk_buff *skb)
19375 --- linux-2.4.27/net/ipv6/raw.c~mipv6-1.1-v2.4.26
19376 +++ linux-2.4.27/net/ipv6/raw.c
19378 #include <net/transp_v6.h>
19379 #include <net/udp.h>
19380 #include <net/inet_common.h>
19381 +#include <net/mipglue.h>
19383 #include <net/rawv6.h>
19385 @@ -641,6 +642,7 @@
19389 + hdr.daddr = mipv6_get_fake_hdr_daddr(hdr.daddr, daddr);
19391 err = ip6_build_xmit(sk, rawv6_frag_cksum, &hdr, &fl, len,
19392 opt, hlimit, msg->msg_flags);
19393 --- linux-2.4.27/net/ipv6/route.c~mipv6-1.1-v2.4.26
19394 +++ linux-2.4.27/net/ipv6/route.c
19396 #include <net/addrconf.h>
19397 #include <net/tcp.h>
19398 #include <linux/rtnetlink.h>
19399 +#include <net/mipglue.h>
19401 #include <asm/uaccess.h>
19403 @@ -363,12 +364,8 @@
19404 rt->u.dst.flags |= DST_HOST;
19406 #ifdef CONFIG_IPV6_SUBTREES
19407 - if (rt->rt6i_src.plen && saddr) {
19408 - ipv6_addr_copy(&rt->rt6i_src.addr, saddr);
19409 - rt->rt6i_src.plen = 128;
19411 + rt->rt6i_src.plen = ort->rt6i_src.plen;
19414 rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway);
19416 dst_hold(&rt->u.dst);
19417 @@ -511,14 +508,19 @@
19418 struct rt6_info *rt;
19421 + struct in6_addr *saddr;
19423 + if (ipv6_chk_addr(fl->nl_u.ip6_u.daddr, NULL))
19426 + saddr = fl->nl_u.ip6_u.saddr;
19428 strict = ipv6_addr_type(fl->nl_u.ip6_u.daddr) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL);
19431 read_lock_bh(&rt6_lock);
19433 - fn = fib6_lookup(&ip6_routing_table, fl->nl_u.ip6_u.daddr,
19434 - fl->nl_u.ip6_u.saddr);
19435 + fn = fib6_lookup(&ip6_routing_table, fl->nl_u.ip6_u.daddr, saddr);
19439 @@ -663,25 +665,6 @@
19440 return (atomic_read(&ip6_dst_ops.entries) > ip6_rt_max_size);
19443 -/* Clean host part of a prefix. Not necessary in radix tree,
19444 - but results in cleaner routing tables.
19446 - Remove it only when all the things will work!
19449 -static void ipv6_addr_prefix(struct in6_addr *pfx,
19450 - const struct in6_addr *addr, int plen)
19452 - int b = plen&0x7;
19455 - memcpy(pfx->s6_addr, addr, o);
19457 - memset(pfx->s6_addr + o, 0, 16 - o);
19459 - pfx->s6_addr[o] = addr->s6_addr[o]&(0xff00 >> b);
19462 static int ipv6_get_mtu(struct net_device *dev)
19464 int mtu = IPV6_MIN_MTU;
19465 @@ -810,7 +793,7 @@
19466 if (!(gwa_type&IPV6_ADDR_UNICAST))
19469 - grt = rt6_lookup(gw_addr, NULL, rtmsg->rtmsg_ifindex, 1);
19470 + grt = rt6_lookup(gw_addr, &rtmsg->rtmsg_src, rtmsg->rtmsg_ifindex, 1);
19472 err = -EHOSTUNREACH;
19474 @@ -848,7 +831,15 @@
19479 +#ifdef USE_IPV6_MOBILITY
19480 + /* If destination is mobile node, add special skb->dst->input
19481 + * function for proxy ND.
19483 + if (rtmsg->rtmsg_flags & RTF_MOBILENODE) {
19484 + rt->u.dst.input = ip6_mipv6_forward;
19486 +#endif /* CONFIG_IPV6_MOBILITY */
19488 if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr))
19489 rt->rt6i_hoplimit = IPV6_DEFAULT_MCASTHOPS;
19491 @@ -936,7 +927,7 @@
19492 struct rt6_info *rt, *nrt;
19494 /* Locate old route to this destination. */
19495 - rt = rt6_lookup(dest, NULL, neigh->dev->ifindex, 1);
19496 + rt = rt6_lookup(dest, saddr, neigh->dev->ifindex, 1);
19500 @@ -1003,6 +994,9 @@
19501 nrt = ip6_rt_copy(rt);
19504 +#ifdef CONFIG_IPV6_SUBTREES
19505 + nrt->rt6i_src.plen = rt->rt6i_src.plen;
19508 nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
19510 @@ -1104,6 +1098,9 @@
19511 nrt = ip6_rt_copy(rt);
19514 +#ifdef CONFIG_IPV6_SUBTREES
19515 + nrt->rt6i_src.plen = rt->rt6i_src.plen;
19517 ipv6_addr_copy(&nrt->rt6i_dst.addr, daddr);
19518 nrt->rt6i_dst.plen = 128;
19519 nrt->u.dst.flags |= DST_HOST;
19520 --- linux-2.4.27/net/ipv6/tcp_ipv6.c~mipv6-1.1-v2.4.26
19521 +++ linux-2.4.27/net/ipv6/tcp_ipv6.c
19523 #include <net/addrconf.h>
19524 #include <net/ip6_route.h>
19525 #include <net/inet_ecn.h>
19526 +#include <net/mipglue.h>
19528 #include <asm/uaccess.h>
19530 @@ -557,6 +558,7 @@
19532 struct dst_entry *dst;
19537 if (addr_len < SIN6_LEN_RFC2133)
19538 @@ -660,7 +662,7 @@
19540 fl.proto = IPPROTO_TCP;
19541 fl.fl6_dst = &np->daddr;
19542 - fl.fl6_src = saddr;
19543 + fl.fl6_src = saddr;
19544 fl.oif = sk->bound_dev_if;
19545 fl.uli_u.ports.dport = usin->sin6_port;
19546 fl.uli_u.ports.sport = sk->sport;
19547 @@ -669,31 +671,46 @@
19548 struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
19549 fl.nl_u.ip6_u.daddr = rt0->addr;
19552 dst = ip6_route_output(sk, &fl);
19554 +#ifdef CONFIG_IPV6_SUBTREES
19555 + reroute = (saddr == NULL);
19557 if ((err = dst->error) != 0) {
19562 - ip6_dst_store(sk, dst, NULL);
19563 - sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM;
19566 + ip6_dst_store(sk, dst, NULL, NULL);
19567 + sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM;
19569 if (saddr == NULL) {
19570 err = ipv6_get_saddr(dst, &np->daddr, &saddr_buf);
19573 + dst_release(dst);
19577 saddr = &saddr_buf;
19578 + ipv6_addr_copy(&np->rcv_saddr, saddr);
19579 +#ifdef CONFIG_IPV6_SUBTREES
19580 + fl.fl6_src = saddr;
19581 + dst = ip6_route_output(sk, &fl);
19583 + if ((err = dst->error) != 0) {
19584 + dst_release(dst);
19587 + ip6_dst_store(sk, dst, NULL, NULL);
19588 + sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM;
19592 /* set the source address */
19593 - ipv6_addr_copy(&np->rcv_saddr, saddr);
19594 ipv6_addr_copy(&np->saddr, saddr);
19595 sk->rcv_saddr= LOOPBACK4_IPV6;
19597 - tp->ext_header_len = 0;
19598 + tp->ext_header_len = tcp_v6_get_mipv6_header_len();
19600 tp->ext_header_len = np->opt->opt_flen+np->opt->opt_nflen;
19601 tp->mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
19602 @@ -1338,7 +1355,7 @@
19606 - ip6_dst_store(newsk, dst, NULL);
19607 + ip6_dst_store(newsk, dst, NULL, NULL);
19608 sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM;
19610 newtp = &(newsk->tp_pinfo.af_tcp);
19611 @@ -1383,7 +1400,7 @@
19612 sock_kfree_s(sk, opt, opt->tot_len);
19615 - newtp->ext_header_len = 0;
19616 + newtp->ext_header_len = tcp_v6_get_mipv6_header_len();
19618 newtp->ext_header_len = np->opt->opt_nflen + np->opt->opt_flen;
19620 @@ -1710,7 +1727,7 @@
19624 - ip6_dst_store(sk, dst, NULL);
19625 + ip6_dst_store(sk, dst, NULL, NULL);
19626 sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM;
19629 @@ -1749,7 +1766,7 @@
19630 return -sk->err_soft;
19633 - ip6_dst_store(sk, dst, NULL);
19634 + ip6_dst_store(sk, dst, NULL, NULL);
19637 skb->dst = dst_clone(dst);
19638 --- linux-2.4.27/net/ipv6/udp.c~mipv6-1.1-v2.4.26
19639 +++ linux-2.4.27/net/ipv6/udp.c
19641 #include <net/ip.h>
19642 #include <net/udp.h>
19643 #include <net/inet_common.h>
19644 +#include <net/mipglue.h>
19646 #include <net/checksum.h>
19648 @@ -232,6 +233,7 @@
19649 struct ip6_flowlabel *flowlabel = NULL;
19654 if (usin->sin6_family == AF_INET) {
19655 if (__ipv6_only_sock(sk))
19656 @@ -331,7 +333,7 @@
19658 fl.proto = IPPROTO_UDP;
19659 fl.fl6_dst = &np->daddr;
19660 - fl.fl6_src = &saddr;
19661 + fl.fl6_src = NULL;
19662 fl.oif = sk->bound_dev_if;
19663 fl.uli_u.ports.dport = sk->dport;
19664 fl.uli_u.ports.sport = sk->sport;
19665 @@ -348,29 +350,44 @@
19666 struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
19667 fl.fl6_dst = rt0->addr;
19670 dst = ip6_route_output(sk, &fl);
19672 if ((err = dst->error) != 0) {
19674 fl6_sock_release(flowlabel);
19678 - ip6_dst_store(sk, dst, fl.fl6_dst);
19682 +#ifdef CONFIG_IPV6_SUBTREES
19683 + reroute = (fl.fl6_src == NULL);
19685 /* get the source adddress used in the apropriate device */
19687 err = ipv6_get_saddr(dst, daddr, &saddr);
19690 + dst_release(dst);
19693 - if(ipv6_addr_any(&np->saddr))
19694 +#ifdef CONFIG_IPV6_SUBTREES
19696 + fl.fl6_src = &saddr;
19697 + dst = ip6_route_output(sk, &fl);
19698 + if ((err = dst->error) != 0) {
19699 + dst_release(dst);
19700 + fl6_sock_release(flowlabel);
19705 + if(ipv6_addr_any(&np->saddr)) {
19706 ipv6_addr_copy(&np->saddr, &saddr);
19708 + fl.fl6_src = &np->saddr;
19710 if(ipv6_addr_any(&np->rcv_saddr)) {
19711 ipv6_addr_copy(&np->rcv_saddr, &saddr);
19712 sk->rcv_saddr = LOOPBACK4_IPV6;
19714 + ip6_dst_store(sk, dst, fl.fl6_dst,
19715 + fl.fl6_src == &np->saddr ? fl.fl6_src : NULL);
19716 sk->state = TCP_ESTABLISHED;
19718 fl6_sock_release(flowlabel);
19719 @@ -889,6 +906,7 @@
19720 opt = fl6_merge_options(&opt_space, flowlabel, opt);
19721 if (opt && opt->srcrt)
19723 + udh.daddr = mipv6_get_fake_hdr_daddr(udh.daddr, daddr);
19725 udh.uh.source = sk->sport;
19726 udh.uh.len = len < 0x10000 ? htons(len) : 0;
19727 --- linux-2.4.27/net/netsyms.c~mipv6-1.1-v2.4.26
19728 +++ linux-2.4.27/net/netsyms.c
19729 @@ -190,6 +190,7 @@
19731 EXPORT_SYMBOL(pneigh_lookup);
19732 EXPORT_SYMBOL(pneigh_enqueue);
19733 +EXPORT_SYMBOL(pneigh_delete);
19734 EXPORT_SYMBOL(neigh_destroy);
19735 EXPORT_SYMBOL(neigh_parms_alloc);
19736 EXPORT_SYMBOL(neigh_parms_release);