1 diff -uprN linux-2.4.25.old/Documentation/Configure.help linux-2.4.25/Documentation/Configure.help
2 --- linux-2.4.25.old/Documentation/Configure.help 2004-06-26 11:22:00.000000000 +0100
3 +++ linux-2.4.25/Documentation/Configure.help 2004-06-26 11:29:29.000000000 +0100
4 @@ -6204,6 +6204,57 @@ CONFIG_IPV6
6 It is safe to say N here for now.
8 +IPv6: IPv6 over IPv6 Tunneling (EXPERIMENTAL)
10 + Experimental IP6-IP6 tunneling. You must select this, if you want
11 + to use CONFIG_IPV6_MOBILITY. More information in MIPL Mobile IPv6
14 + If you don't want IP6-IP6 tunnels and Mobile IPv6, say N.
16 +IPv6: Mobility Support (EXPERIMENTAL)
18 + This is experimental support for the upcoming specification of
19 + Mobile IPv6. Mobile IPv6 allows nodes to seamlessly move between
20 + networks without changing their IP addresses, thus allowing them to
21 + maintain upper layer connections (e.g. TCP). Selecting this option
22 + allows your computer to act as a Correspondent Node (CN). A MIPv6
23 + Mobile Node will be able to communicate with the CN and use route
26 + For more information and configuration details, see
27 + http://www.mipl.mediapoli.com/.
31 +MIPv6: Mobile Node Support
32 +CONFIG_IPV6_MOBILITY_MN
33 + If you want your computer to be a MIPv6 Mobile Node (MN), select
34 + this option. You must configure MN using the userspace tools
35 + available at http://www.mipl.mediapoli.com/download/mipv6-tools/.
37 + If your computer is stationary, or you are unsure if you need this,
38 + say N. Note that you will need a properly configured MIPv6 Home
39 + Agent to use any Mobile Nodes.
41 +MIPv6: Home Agent Support
42 +CONFIG_IPV6_MOBILITY_HA
43 + If you want your router to serve as a MIPv6 Home Agent (HA), select
44 + this option. You must configure HA using the userspace tools
45 + available at http://www.mipl.mediapoli.com/download/mipv6-tools/.
47 + If your computer is not a router, or you are unsure if you need
50 +MIPv6: Debug messages
51 +CONFIG_IPV6_MOBILITY_DEBUG
52 + MIPL Mobile IPv6 can produce a lot of debugging messages. There are
53 + eight debug levels (0 through 7) and the level is controlled via
54 + /proc/sys/net/ipv6/mobility/debuglevel. Since MIPL is still
55 + experimental, you might want to say Y here.
57 + Be sure to say Y and record debug messages when submitting a bug
59 The SCTP Protocol (EXPERIMENTAL)
61 Stream Control Transmission Protocol
62 diff -uprN linux-2.4.25.old/Documentation/DocBook/Makefile linux-2.4.25/Documentation/DocBook/Makefile
63 --- linux-2.4.25.old/Documentation/DocBook/Makefile 2002-11-28 23:53:08.000000000 +0000
64 +++ linux-2.4.25/Documentation/DocBook/Makefile 2004-06-26 11:29:29.000000000 +0100
65 @@ -2,7 +2,7 @@ BOOKS := wanbook.sgml z8530book.sgml mca
66 kernel-api.sgml parportbook.sgml kernel-hacking.sgml \
67 kernel-locking.sgml via-audio.sgml mousedrivers.sgml sis900.sgml \
68 deviceiobook.sgml procfs-guide.sgml tulip-user.sgml \
70 + journal-api.sgml mip6-func.sgml
72 PS := $(patsubst %.sgml, %.ps, $(BOOKS))
73 PDF := $(patsubst %.sgml, %.pdf, $(BOOKS))
74 @@ -86,6 +86,9 @@ videobook.sgml: videobook.tmpl $(TOPDIR)
75 procfs-guide.sgml: procfs-guide.tmpl procfs_example.sgml
76 $(TOPDIR)/scripts/docgen < procfs-guide.tmpl >$@
78 +mip6-func.sgml: mip6-func.tmpl
79 + $(TOPDIR)/scripts/docgen <$< >$@
81 APISOURCES := $(TOPDIR)/drivers/media/video/videodev.c \
82 $(TOPDIR)/arch/i386/kernel/irq.c \
83 $(TOPDIR)/arch/i386/kernel/mca.c \
84 diff -uprN linux-2.4.25.old/Documentation/DocBook/mip6-func.tmpl linux-2.4.25/Documentation/DocBook/mip6-func.tmpl
85 --- linux-2.4.25.old/Documentation/DocBook/mip6-func.tmpl 1970-01-01 01:00:00.000000000 +0100
86 +++ linux-2.4.25/Documentation/DocBook/mip6-func.tmpl 2004-06-26 11:29:29.000000000 +0100
88 +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
89 +<book id="LinuxMobileIPv6">
91 + <title>MIPL Mobile IPv6 Function Reference Guide</title>
95 + <othername>MIPL Mobile IPv6 for Linux Team</othername>
97 + <orgname>Helsinki University of Technology</orgname>
98 + <orgdiv>Telecommunications Software and Multimedia Lab</orgdiv>
100 + <pob>PO BOX 9201</pob>
101 + <postcode>FIN-02015 HUT</postcode>
102 + <country>Finland</country>
103 + <email>mipl@list.mipl.mediapoli.com</email>
110 + <year>2000-2001</year>
111 + <holder>Helsinki University of Technology</holder>
116 + Copyright (c) 2001, 2002 MIPL Mobile IPv6 for Linux Team.
119 + Permission is granted to copy, distribute and/or modify this
120 + document under the terms of the GNU Free Documentation License,
121 + Version 1.1 published by the Free Software Foundation; with the
122 + Invariant Sections being "Introduction", with the Front-Cover
123 + Texts being "MIPL Mobile IPv6 Function Reference Guide", "MIPL
124 + Mobile IPv6 for Linux Team" and "Helsinki University of
125 + Technology". A copy of the license is included in <xref
134 + <preface id="intro">
135 + <title>Introduction</title>
138 + MIPL Mobile IPv6 for Linux is an implementation of Mobility
139 + Support in IPv6 IETF mobile-ip working groups Internet-Draft
140 + (draft-ietf-mobileip-ipv6). This implementation has been
141 + developed in the Telecommunications Software and Multimedia
142 + Laboratory at Helsinki University of Technology.
146 + MIPL is fully open source, licensed under the GNU General
147 + Public License. Latest source for MIPL can be downloaded from
148 + the MIPL website at:
151 + http://www.mipl.mediapoli.com/.
154 + Developers and users interested in MIPL can subscribe to the
155 + MIPL mailing list by sending e-mail to
156 + <email>majordomo@list.mipl.mediapoli.com</email> with
162 + in the body of the message.
166 + This document is a reference guide to MIPL functions. Intended
167 + audience is developers wishing to contribute to the project.
168 + Hopefully this document will make it easier and quicker to
169 + understand and adopt the inner workings of MIPL Mobile IPv6.
173 + MIPL Mobile IPv6 for Linux Team members (past and present):
178 + Sami Kivisaari <email>Sami.Kivisaari@hut.fi</email>
183 + Niklas Kampe <email>Niklas.Kampe@hut.fi</email>
188 + Juha Mynttinen <email>Juha.Mynttinen@hut.fi</email>
193 + Toni Nykanen <email>Toni.Nykanen@iki.fi</email>
198 + Henrik Petander <email>Henrik.Petander@hut.fi</email>
203 + Antti Tuominen <email>ajtuomin@tml.hut.fi</email>
216 + Ville Nuorvala <email>vnuorval@tcs.hut.fi</email>
221 + Jaakko Laine <email>Jaakko.Laine@hut.fi</email>
229 + <chapter id="common">
230 + <title>Common functions for all entities</title>
232 + <sect1><title>Low-level functions</title>
234 + These functions implement memory allocation used by others.
235 + Hashlist functions implement a linked list with hash lookup,
236 + which is used with Binding Update List, Binding Cache, Home
239 +!Inet/ipv6/mobile_ip6/mempool.h
240 +!Inet/ipv6/mobile_ip6/hashlist.h
243 + <sect1><title>Debug functions</title>
245 + Debug and utility functions. These functions are available if
246 + <constant>CONFIG_IPV6_MOBILITY_DEBUG</constant> is set.
247 + Otherwise macros expand to no operation.
249 +!Inet/ipv6/mobile_ip6/debug.h
250 +!Inet/ipv6/mobile_ip6/mipv6.c
253 + <sect1><title>Extension Header functions</title>
255 + These functions create and handle extension headers that are
258 +!Inet/ipv6/mobile_ip6/exthdrs.c
261 + <sect1><title>Mobility Header functions</title>
263 + MIPv6 specifies a new protocol called Mobility Header.
264 + Mobility Header has several message types. Messages may also
265 + carry Mobility Options. These functions are used to create and
266 + handle Mobility Headers and Mobility Options.
268 +!Inet/ipv6/mobile_ip6/sendopts.c
269 +!Inet/ipv6/mobile_ip6/mh_recv.c
270 +!Inet/ipv6/mobile_ip6/auth_subopt.c
273 + <sect1><title>Binding Cache</title>
275 + All Mobile IPv6 entities have a binding cache. These functions
276 + provide easy manipulation of the binding cache.
278 +!Inet/ipv6/mobile_ip6/bcache.c
281 + <sect1><title>Security</title>
284 + These functions are common authentication functions and
285 + implement Draft 13 style IPSec AH support for Binding Updates.
287 +!Inet/ipv6/mobile_ip6/ah_algo.c
288 +!Inet/ipv6/mobile_ip6/sadb.c
289 +!Inet/ipv6/mobile_ip6/ah.c
292 + <sect1><title>Utility functions</title>
295 + These functions are general utility functions commonly used by
298 +!Inet/ipv6/mobile_ip6/util.c
304 + <title>Mobile Node functions</title>
305 + <sect1><title>General functions</title>
308 +!Inet/ipv6/mobile_ip6/mn.c
311 + <sect1><title>Binding Update List</title>
313 + Mobile Node keeps track of sent binding updates in Binding
316 +!Inet/ipv6/mobile_ip6/bul.c
319 + <sect1><title>Movement detection</title>
322 + These functions are used by the mobile node for movement
325 +!Inet/ipv6/mobile_ip6/mdetect.c
330 + <title>Home Agent functions</title>
331 + <sect1><title>General functions</title>
334 +!Inet/ipv6/mobile_ip6/ha.c
337 + <sect1><title>Duplicate Address Detection functions</title>
339 + Home Agent does Duplicate Address Detection for Mobile Nodes'
340 + addresses. These functions implement MIPv6 specific DAD
343 +!Inet/ipv6/mobile_ip6/dad.c
347 + <appendix id="gfdl">
348 + <title>GNU Free Documentation License</title>
351 + Version 1.1, March 2000
355 + Copyright (C) 2000 Free Software Foundation, Inc.
356 + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
357 + Everyone is permitted to copy and distribute verbatim copies
358 + of this license document, but changing it is not allowed.
361 + <sect1><title>0. PREAMBLE</title>
364 + The purpose of this License is to make a manual, textbook, or
365 + other written document "free" in the sense of freedom: to
366 + assure everyone the effective freedom to copy and redistribute
367 + it, with or without modifying it, either commercially or
368 + noncommercially. Secondarily, this License preserves for the
369 + author and publisher a way to get credit for their work, while
370 + not being considered responsible for modifications made by
375 + This License is a kind of "copyleft", which means that
376 + derivative works of the document must themselves be free in the
377 + same sense. It complements the GNU General Public License,
378 + which is a copyleft license designed for free software.
382 + We have designed this License in order to use it for manuals
383 + for free software, because free software needs free
384 + documentation: a free program should come with manuals
385 + providing the same freedoms that the software does. But this
386 + License is not limited to software manuals; it can be used for
387 + any textual work, regardless of subject matter or whether it is
388 + published as a printed book. We recommend this License
389 + principally for works whose purpose is instruction or
394 + <sect1><title>1. APPLICABILITY AND DEFINITIONS</title>
397 + This License applies to any manual or other work that contains
398 + a notice placed by the copyright holder saying it can be
399 + distributed under the terms of this License. The "Document",
400 + below, refers to any such manual or work. Any member of the
401 + public is a licensee, and is addressed as "you".
405 + A "Modified Version" of the Document means any work containing
406 + the Document or a portion of it, either copied verbatim, or
407 + with modifications and/or translated into another language.
411 + A "Secondary Section" is a named appendix or a front-matter
412 + section of the Document that deals exclusively with the
413 + relationship of the publishers or authors of the Document to
414 + the Document's overall subject (or to related matters) and
415 + contains nothing that could fall directly within that overall
416 + subject. (For example, if the Document is in part a textbook of
417 + mathematics, a Secondary Section may not explain any
418 + mathematics.) The relationship could be a matter of historical
419 + connection with the subject or with related matters, or of
420 + legal, commercial, philosophical, ethical or political position
425 + The "Invariant Sections" are certain Secondary Sections whose
426 + titles are designated, as being those of Invariant Sections, in
427 + the notice that says that the Document is released under this
432 + The "Cover Texts" are certain short passages of text that are
433 + listed, as Front-Cover Texts or Back-Cover Texts, in the notice
434 + that says that the Document is released under this License.
438 + A "Transparent" copy of the Document means a machine-readable
439 + copy, represented in a format whose specification is available
440 + to the general public, whose contents can be viewed and edited
441 + directly and straightforwardly with generic text editors or
442 + (for images composed of pixels) generic paint programs or (for
443 + drawings) some widely available drawing editor, and that is
444 + suitable for input to text formatters or for automatic
445 + translation to a variety of formats suitable for input to text
446 + formatters. A copy made in an otherwise Transparent file format
447 + whose markup has been designed to thwart or discourage
448 + subsequent modification by readers is not Transparent. A copy
449 + that is not "Transparent" is called "Opaque".
453 + Examples of suitable formats for Transparent copies include
454 + plain ASCII without markup, Texinfo input format, LaTeX input
455 + format, SGML or XML using a publicly available DTD, and
456 + standard-conforming simple HTML designed for human
457 + modification. Opaque formats include PostScript, PDF,
458 + proprietary formats that can be read and edited only by
459 + proprietary word processors, SGML or XML for which the DTD
460 + and/or processing tools are not generally available, and the
461 + machine-generated HTML produced by some word processors for
462 + output purposes only.
466 + The "Title Page" means, for a printed book, the title page
467 + itself, plus such following pages as are needed to hold,
468 + legibly, the material this License requires to appear in the
469 + title page. For works in formats which do not have any title
470 + page as such, "Title Page" means the text near the most
471 + prominent appearance of the work's title, preceding the
472 + beginning of the body of the text.
476 + <sect1><title>2. VERBATIM COPYING</title>
479 + You may copy and distribute the Document in any medium, either
480 + commercially or noncommercially, provided that this License,
481 + the copyright notices, and the license notice saying this
482 + License applies to the Document are reproduced in all copies,
483 + and that you add no other conditions whatsoever to those of
484 + this License. You may not use technical measures to obstruct or
485 + control the reading or further copying of the copies you make
486 + or distribute. However, you may accept compensation in exchange
487 + for copies. If you distribute a large enough number of copies
488 + you must also follow the conditions in section 3.
492 + You may also lend copies, under the same conditions stated
493 + above, and you may publicly display copies.
497 + <sect1><title>3. COPYING IN QUANTITY</title>
500 + If you publish printed copies of the Document numbering more
501 + than 100, and the Document's license notice requires Cover
502 + Texts, you must enclose the copies in covers that carry,
503 + clearly and legibly, all these Cover Texts: Front-Cover Texts
504 + on the front cover, and Back-Cover Texts on the back
505 + cover. Both covers must also clearly and legibly identify you
506 + as the publisher of these copies. The front cover must present
507 + the full title with all words of the title equally prominent
508 + and visible. You may add other material on the covers in
509 + addition. Copying with changes limited to the covers, as long
510 + as they preserve the title of the Document and satisfy these
511 + conditions, can be treated as verbatim copying in other
516 + If the required texts for either cover are too voluminous to
517 + fit legibly, you should put the first ones listed (as many as
518 + fit reasonably) on the actual cover, and continue the rest onto
523 + If you publish or distribute Opaque copies of the Document
524 + numbering more than 100, you must either include a
525 + machine-readable Transparent copy along with each Opaque copy,
526 + or state in or with each Opaque copy a publicly-accessible
527 + computer-network location containing a complete Transparent
528 + copy of the Document, free of added material, which the general
529 + network-using public has access to download anonymously at no
530 + charge using public-standard network protocols. If you use the
531 + latter option, you must take reasonably prudent steps, when you
532 + begin distribution of Opaque copies in quantity, to ensure that
533 + this Transparent copy will remain thus accessible at the stated
534 + location until at least one year after the last time you
535 + distribute an Opaque copy (directly or through your agents or
536 + retailers) of that edition to the public.
540 + It is requested, but not required, that you contact the authors
541 + of the Document well before redistributing any large number of
542 + copies, to give them a chance to provide you with an updated
543 + version of the Document.
547 + <sect1><title>4. MODIFICATIONS</title>
550 + You may copy and distribute a Modified Version of the Document
551 + under the conditions of sections 2 and 3 above, provided that
552 + you release the Modified Version under precisely this License,
553 + with the Modified Version filling the role of the Document,
554 + thus licensing distribution and modification of the Modified
555 + Version to whoever possesses a copy of it. In addition, you
556 + must do these things in the Modified Version:
560 + <itemizedlist spacing=compact>
563 + A. Use in the Title Page (and on the covers, if any) a title
564 + distinct from that of the Document, and from those of previous
565 + versions (which should, if there were any, be listed in the
566 + History section of the Document). You may use the same title
567 + as a previous version if the original publisher of that
568 + version gives permission.
573 + B. List on the Title Page, as authors, one or more persons
574 + or entities responsible for authorship of the modifications in
575 + the Modified Version, together with at least five of the
576 + principal authors of the Document (all of its principal
577 + authors, if it has less than five).
582 + C. State on the Title page the name of the publisher of the
583 + Modified Version, as the publisher.
588 + D. Preserve all the copyright notices of the Document.
593 + E. Add an appropriate copyright notice for your
594 + modifications adjacent to the other copyright notices.
599 + F. Include, immediately after the copyright notices, a
600 + license notice giving the public permission to use the
601 + Modified Version under the terms of this License, in the form
602 + shown in the Addendum below.
607 + G. Preserve in that license notice the full lists of
608 + Invariant Sections and required Cover Texts given in the
609 + Document's license notice.
614 + H. Include an unaltered copy of this License.
619 + I. Preserve the section entitled "History", and its title,
620 + and add to it an item stating at least the title, year, new
621 + authors, and publisher of the Modified Version as given on the
622 + Title Page. If there is no section entitled "History" in the
623 + Document, create one stating the title, year, authors, and
624 + publisher of the Document as given on its Title Page, then add
625 + an item describing the Modified Version as stated in the
631 + J. Preserve the network location, if any, given in the
632 + Document for public access to a Transparent copy of the
633 + Document, and likewise the network locations given in the
634 + Document for previous versions it was based on. These may be
635 + placed in the "History" section. You may omit a network
636 + location for a work that was published at least four years
637 + before the Document itself, or if the original publisher of
638 + the version it refers to gives permission.
643 + K. In any section entitled "Acknowledgements" or
644 + "Dedications", preserve the section's title, and preserve in
645 + the section all the substance and tone of each of the
646 + contributor acknowledgements and/or dedications given therein.
651 + L. Preserve all the Invariant Sections of the Document,
652 + unaltered in their text and in their titles. Section numbers
653 + or the equivalent are not considered part of the section
659 + M. Delete any section entitled "Endorsements". Such a
660 + section may not be included in the Modified Version.
665 + N. Do not retitle any existing section as "Endorsements" or
666 + to conflict in title with any Invariant Section.
673 + If the Modified Version includes new front-matter sections or
674 + appendices that qualify as Secondary Sections and contain no
675 + material copied from the Document, you may at your option
676 + designate some or all of these sections as invariant. To do
677 + this, add their titles to the list of Invariant Sections in the
678 + Modified Version's license notice. These titles must be
679 + distinct from any other section titles.
683 + You may add a section entitled "Endorsements", provided it
684 + contains nothing but endorsements of your Modified Version by
685 + various parties--for example, statements of peer review or that
686 + the text has been approved by an organization as the
687 + authoritative definition of a standard.
691 + You may add a passage of up to five words as a Front-Cover
692 + Text, and a passage of up to 25 words as a Back-Cover Text, to
693 + the end of the list of Cover Texts in the Modified
694 + Version. Only one passage of Front-Cover Text and one of
695 + Back-Cover Text may be added by (or through arrangements made
696 + by) any one entity. If the Document already includes a cover
697 + text for the same cover, previously added by you or by
698 + arrangement made by the same entity you are acting on behalf
699 + of, you may not add another; but you may replace the old one,
700 + on explicit permission from the previous publisher that added
705 + The author(s) and publisher(s) of the Document do not by this
706 + License give permission to use their names for publicity for or
707 + to assert or imply endorsement of any Modified Version.
711 + <sect1><title>5. COMBINING DOCUMENTS</title>
714 + You may combine the Document with other documents released
715 + under this License, under the terms defined in section 4 above
716 + for modified versions, provided that you include in the
717 + combination all of the Invariant Sections of all of the
718 + original documents, unmodified, and list them all as Invariant
719 + Sections of your combined work in its license notice.
723 + The combined work need only contain one copy of this License,
724 + and multiple identical Invariant Sections may be replaced with
725 + a single copy. If there are multiple Invariant Sections with
726 + the same name but different contents, make the title of each
727 + such section unique by adding at the end of it, in parentheses,
728 + the name of the original author or publisher of that section if
729 + known, or else a unique number. Make the same adjustment to the
730 + section titles in the list of Invariant Sections in the license
731 + notice of the combined work.
735 + In the combination, you must combine any sections entitled
736 + "History" in the various original documents, forming one
737 + section entitled "History"; likewise combine any sections
738 + entitled "Acknowledgements", and any sections entitled
739 + "Dedications". You must delete all sections entitled
744 + <sect1><title>6. COLLECTIONS OF DOCUMENTS</title>
747 + You may make a collection consisting of the Document and other
748 + documents released under this License, and replace the
749 + individual copies of this License in the various documents with
750 + a single copy that is included in the collection, provided that
751 + you follow the rules of this License for verbatim copying of
752 + each of the documents in all other respects.
756 + You may extract a single document from such a collection, and
757 + distribute it individually under this License, provided you
758 + insert a copy of this License into the extracted document, and
759 + follow this License in all other respects regarding verbatim
760 + copying of that document.
764 + <sect1><title>7. AGGREGATION WITH INDEPENDENT WORKS</title>
767 + A compilation of the Document or its derivatives with other
768 + separate and independent documents or works, in or on a volume
769 + of a storage or distribution medium, does not as a whole count
770 + as a Modified Version of the Document, provided no compilation
771 + copyright is claimed for the compilation. Such a compilation is
772 + called an "aggregate", and this License does not apply to the
773 + other self-contained works thus compiled with the Document, on
774 + account of their being thus compiled, if they are not
775 + themselves derivative works of the Document.
779 + If the Cover Text requirement of section 3 is applicable to
780 + these copies of the Document, then if the Document is less than
781 + one quarter of the entire aggregate, the Document's Cover Texts
782 + may be placed on covers that surround only the Document within
783 + the aggregate. Otherwise they must appear on covers around the
788 + <sect1><title>8. TRANSLATION</title>
791 + Translation is considered a kind of modification, so you may
792 + distribute translations of the Document under the terms of
793 + section 4. Replacing Invariant Sections with translations
794 + requires special permission from their copyright holders, but
795 + you may include translations of some or all Invariant Sections
796 + in addition to the original versions of these Invariant
797 + Sections. You may include a translation of this License
798 + provided that you also include the original English version of
799 + this License. In case of a disagreement between the translation
800 + and the original English version of this License, the original
801 + English version will prevail.
805 + <sect1><title>9. TERMINATION</title>
808 + You may not copy, modify, sublicense, or distribute the
809 + Document except as expressly provided for under this
810 + License. Any other attempt to copy, modify, sublicense or
811 + distribute the Document is void, and will automatically
812 + terminate your rights under this License. However, parties who
813 + have received copies, or rights, from you under this License
814 + will not have their licenses terminated so long as such parties
815 + remain in full compliance.
819 + <sect1><title>10. FUTURE REVISIONS OF THIS LICENSE</title>
822 + The Free Software Foundation may publish new, revised versions
823 + of the GNU Free Documentation License from time to time. Such
824 + new versions will be similar in spirit to the present version,
825 + but may differ in detail to address new problems or
826 + concerns. See http://www.gnu.org/copyleft/.
830 + Each version of the License is given a distinguishing version
831 + number. If the Document specifies that a particular numbered
832 + version of this License "or any later version" applies to it,
833 + you have the option of following the terms and conditions
834 + either of that specified version or of any later version that
835 + has been published (not as a draft) by the Free Software
836 + Foundation. If the Document does not specify a version number
837 + of this License, you may choose any version ever published (not
838 + as a draft) by the Free Software Foundation.
844 diff -uprN linux-2.4.25.old/include/linux/icmpv6.h linux-2.4.25/include/linux/icmpv6.h
845 --- linux-2.4.25.old/include/linux/icmpv6.h 2003-08-25 12:44:44.000000000 +0100
846 +++ linux-2.4.25/include/linux/icmpv6.h 2004-06-26 11:29:29.000000000 +0100
847 @@ -40,14 +40,16 @@ struct icmp6hdr {
848 struct icmpv6_nd_ra {
850 #if defined(__LITTLE_ENDIAN_BITFIELD)
857 #elif defined(__BIG_ENDIAN_BITFIELD)
864 #error "Please fix <asm/byteorder.h>"
866 @@ -70,6 +72,7 @@ struct icmp6hdr {
867 #define icmp6_addrconf_managed icmp6_dataun.u_nd_ra.managed
868 #define icmp6_addrconf_other icmp6_dataun.u_nd_ra.other
869 #define icmp6_rt_lifetime icmp6_dataun.u_nd_ra.rt_lifetime
870 +#define icmp6_home_agent icmp6_dataun.u_nd_ra.home_agent
874 diff -uprN linux-2.4.25.old/include/linux/if_arp.h linux-2.4.25/include/linux/if_arp.h
875 --- linux-2.4.25.old/include/linux/if_arp.h 2002-02-25 19:38:13.000000000 +0000
876 +++ linux-2.4.25/include/linux/if_arp.h 2004-06-26 11:29:29.000000000 +0100
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 diff -uprN linux-2.4.25.old/include/linux/in6.h linux-2.4.25/include/linux/in6.h
887 --- linux-2.4.25.old/include/linux/in6.h 2003-06-13 15:51:38.000000000 +0100
888 +++ linux-2.4.25/include/linux/in6.h 2004-06-26 11:29:29.000000000 +0100
889 @@ -142,6 +142,11 @@ struct in6_flowlabel_req
890 #define IPV6_TLV_JUMBO 194
893 + * Mobile IPv6 TLV options.
895 +#define MIPV6_TLV_HOMEADDR 201
898 * IPV6 socket options
901 diff -uprN linux-2.4.25.old/include/linux/ipv6.h linux-2.4.25/include/linux/ipv6.h
902 --- linux-2.4.25.old/include/linux/ipv6.h 2003-11-28 18:26:21.000000000 +0000
903 +++ linux-2.4.25/include/linux/ipv6.h 2004-06-26 11:29:29.000000000 +0100
904 @@ -29,6 +29,7 @@ struct in6_ifreq {
906 #define IPV6_SRCRT_STRICT 0x01 /* this hop must be a neighbor */
907 #define IPV6_SRCRT_TYPE_0 0 /* IPv6 type 0 Routing Header */
908 +#define IPV6_SRCRT_TYPE_2 2 /* type 2 for Mobile IPv6 */
912 @@ -71,6 +72,19 @@ struct rt0_hdr {
913 struct in6_addr addr[0];
915 #define rt0_type rt_hdr.type
920 + * routing header type 2
924 + struct ipv6_rt_hdr rt_hdr;
926 + struct in6_addr addr;
928 +#define rt2_type rt_hdr.type;
932 @@ -156,12 +170,16 @@ enum {
933 struct inet6_skb_parm
945 + struct in6_addr hoa;
949 diff -uprN linux-2.4.25.old/include/linux/ipv6_route.h linux-2.4.25/include/linux/ipv6_route.h
950 --- linux-2.4.25.old/include/linux/ipv6_route.h 2003-11-28 18:26:21.000000000 +0000
951 +++ linux-2.4.25/include/linux/ipv6_route.h 2004-06-26 11:29:29.000000000 +0100
952 @@ -33,6 +33,7 @@ enum
953 #define RTF_CACHE 0x01000000 /* cache entry */
954 #define RTF_FLOW 0x02000000 /* flow significant route */
955 #define RTF_POLICY 0x04000000 /* policy route */
956 +#define RTF_MOBILENODE 0x10000000 /* for routing to Mobile Node */
958 #define RTF_LOCAL 0x80000000
960 diff -uprN linux-2.4.25.old/include/linux/ipv6_tunnel.h linux-2.4.25/include/linux/ipv6_tunnel.h
961 --- linux-2.4.25.old/include/linux/ipv6_tunnel.h 1970-01-01 01:00:00.000000000 +0100
962 +++ linux-2.4.25/include/linux/ipv6_tunnel.h 2004-06-26 11:29:29.000000000 +0100
968 +#ifndef _IPV6_TUNNEL_H
969 +#define _IPV6_TUNNEL_H
971 +#define IPV6_TLV_TNL_ENCAP_LIMIT 4
972 +#define IPV6_DEFAULT_TNL_ENCAP_LIMIT 4
974 +/* don't add encapsulation limit if one isn't present in inner packet */
975 +#define IP6_TNL_F_IGN_ENCAP_LIMIT 0x1
976 +/* copy the traffic class field from the inner packet */
977 +#define IP6_TNL_F_USE_ORIG_TCLASS 0x2
978 +/* copy the flowlabel from the inner packet */
979 +#define IP6_TNL_F_USE_ORIG_FLOWLABEL 0x4
980 +/* created and maintained from within the kernel */
981 +#define IP6_TNL_F_KERNEL_DEV 0x8
982 +/* being used for Mobile IPv6 */
983 +#define IP6_TNL_F_MIP6_DEV 0x10
985 +struct ip6_tnl_parm {
986 + char name[IFNAMSIZ]; /* name of tunnel device */
987 + int link; /* ifindex of underlying L2 interface */
988 + __u8 proto; /* tunnel protocol */
989 + __u8 encap_limit; /* encapsulation limit for tunnel */
990 + __u8 hop_limit; /* hop limit for tunnel */
991 + __u32 flowinfo; /* traffic class and flowlabel for tunnel */
992 + __u32 flags; /* tunnel flags */
993 + struct in6_addr laddr; /* local tunnel end-point address */
994 + struct in6_addr raddr; /* remote tunnel end-point address */
998 diff -uprN linux-2.4.25.old/include/linux/rtnetlink.h linux-2.4.25/include/linux/rtnetlink.h
999 --- linux-2.4.25.old/include/linux/rtnetlink.h 2004-02-18 13:36:32.000000000 +0000
1000 +++ linux-2.4.25/include/linux/rtnetlink.h 2004-06-26 11:29:29.000000000 +0100
1001 @@ -309,15 +309,17 @@ enum
1010 -#define IFA_MAX IFA_CACHEINFO
1011 +#define IFA_MAX IFA_HOMEAGENT
1015 #define IFA_F_SECONDARY 0x01
1017 +#define IFA_F_HOMEADDR 0x10
1018 #define IFA_F_DEPRECATED 0x20
1019 #define IFA_F_TENTATIVE 0x40
1020 #define IFA_F_PERMANENT 0x80
1021 diff -uprN linux-2.4.25.old/include/linux/skbuff.h linux-2.4.25/include/linux/skbuff.h
1022 --- linux-2.4.25.old/include/linux/skbuff.h 2003-08-25 12:44:44.000000000 +0100
1023 +++ linux-2.4.25/include/linux/skbuff.h 2004-06-26 11:29:29.000000000 +0100
1024 @@ -177,7 +177,7 @@ struct sk_buff {
1025 * want to keep them across layers you have to do a skb_clone()
1026 * first. This is owned by whoever has the skb queued ATM.
1031 unsigned int len; /* Length of actual data */
1032 unsigned int data_len;
1033 diff -uprN linux-2.4.25.old/include/linux/sysctl.h linux-2.4.25/include/linux/sysctl.h
1034 --- linux-2.4.25.old/include/linux/sysctl.h 2004-02-18 13:36:32.000000000 +0000
1035 +++ linux-2.4.25/include/linux/sysctl.h 2004-06-26 11:29:29.000000000 +0100
1036 @@ -387,7 +387,24 @@ enum {
1040 - NET_IPV6_BINDV6ONLY=20
1041 + NET_IPV6_BINDV6ONLY=20,
1042 + NET_IPV6_MOBILITY=26
1045 +/* /proc/sys/net/ipv6/mobility */
1047 + NET_IPV6_MOBILITY_DEBUG=1,
1048 + NET_IPV6_MOBILITY_TUNNEL_SITELOCAL=2,
1049 + NET_IPV6_MOBILITY_ROUTER_SOLICITATION_MAX_SENDTIME=3,
1050 + NET_IPV6_MOBILITY_ROUTER_REACH=4,
1051 + NET_IPV6_MOBILITY_MDETECT_MECHANISM=5,
1052 + NET_IPV6_MOBILITY_RETROUT=6,
1053 + NET_IPV6_MOBILITY_MAX_TNLS=7,
1054 + NET_IPV6_MOBILITY_MIN_TNLS=8,
1055 + NET_IPV6_MOBILITY_BINDING_REFRESH=9,
1056 + NET_IPV6_MOBILITY_BU_F_LLADDR=10,
1057 + NET_IPV6_MOBILITY_BU_F_KEYMGM=11,
1058 + NET_IPV6_MOBILITY_BU_F_CN_ACK=12
1062 diff -uprN linux-2.4.25.old/include/net/addrconf.h linux-2.4.25/include/net/addrconf.h
1063 --- linux-2.4.25.old/include/net/addrconf.h 2003-08-25 12:44:44.000000000 +0100
1064 +++ linux-2.4.25/include/net/addrconf.h 2004-06-26 11:29:29.000000000 +0100
1065 @@ -16,9 +16,11 @@ struct prefix_info {
1066 #if defined(__BIG_ENDIAN_BITFIELD)
1070 + router_address : 1,
1072 #elif defined(__LITTLE_ENDIAN_BITFIELD)
1073 - __u8 reserved : 6,
1074 + __u8 reserved : 5,
1075 + router_address : 1,
1079 @@ -55,6 +57,7 @@ extern int ipv6_chk_addr(struct in6_ad
1080 struct net_device *dev);
1081 extern struct inet6_ifaddr * ipv6_get_ifaddr(struct in6_addr *addr,
1082 struct net_device *dev);
1083 +extern void ipv6_del_addr(struct inet6_ifaddr *ifp);
1084 extern int ipv6_get_saddr(struct dst_entry *dst,
1085 struct in6_addr *daddr,
1086 struct in6_addr *saddr);
1087 @@ -85,7 +88,9 @@ extern void ipv6_mc_up(struct inet6_dev
1088 extern void ipv6_mc_down(struct inet6_dev *idev);
1089 extern void ipv6_mc_init_dev(struct inet6_dev *idev);
1090 extern void ipv6_mc_destroy_dev(struct inet6_dev *idev);
1091 +extern void addrconf_dad_start(struct inet6_ifaddr *ifp, int flags);
1092 extern void addrconf_dad_failure(struct inet6_ifaddr *ifp);
1093 +extern void addrconf_dad_completed(struct inet6_ifaddr *ifp);
1095 extern int ipv6_chk_mcast_addr(struct net_device *dev, struct in6_addr *group,
1096 struct in6_addr *src_addr);
1097 @@ -116,6 +121,9 @@ extern int ipv6_chk_acast_addr(struct
1098 extern int register_inet6addr_notifier(struct notifier_block *nb);
1099 extern int unregister_inet6addr_notifier(struct notifier_block *nb);
1101 +extern int ipv6_generate_eui64(u8 *eui, struct net_device *dev);
1102 +extern int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev);
1104 static inline struct inet6_dev *
1105 __in6_dev_get(struct net_device *dev)
1107 diff -uprN linux-2.4.25.old/include/net/ip6_route.h linux-2.4.25/include/net/ip6_route.h
1108 --- linux-2.4.25.old/include/net/ip6_route.h 2003-06-13 15:51:39.000000000 +0100
1109 +++ linux-2.4.25/include/net/ip6_route.h 2004-06-26 11:29:29.000000000 +0100
1111 #define _NET_IP6_ROUTE_H
1113 #define IP6_RT_PRIO_FW 16
1114 +#define IP6_RT_PRIO_MIPV6 64
1115 #define IP6_RT_PRIO_USER 1024
1116 #define IP6_RT_PRIO_ADDRCONF 256
1117 #define IP6_RT_PRIO_KERN 512
1118 @@ -40,6 +41,9 @@ extern int ipv6_route_ioctl(unsigned i
1120 extern int ip6_route_add(struct in6_rtmsg *rtmsg,
1123 +extern int ip6_route_del(struct in6_rtmsg *rtmsg,
1124 + struct nlmsghdr *);
1125 extern int ip6_del_rt(struct rt6_info *,
1128 @@ -99,7 +103,8 @@ extern rwlock_t rt6_lock;
1131 static inline void ip6_dst_store(struct sock *sk, struct dst_entry *dst,
1132 - struct in6_addr *daddr)
1133 + struct in6_addr *daddr,
1134 + struct in6_addr *saddr)
1136 struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
1137 struct rt6_info *rt = (struct rt6_info *) dst;
1138 @@ -107,6 +112,9 @@ static inline void ip6_dst_store(struct
1139 write_lock(&sk->dst_lock);
1140 __sk_dst_set(sk, dst);
1141 np->daddr_cache = daddr;
1142 +#ifdef CONFIG_IPV6_SUBTREES
1143 + np->saddr_cache = saddr;
1145 np->dst_cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0;
1146 write_unlock(&sk->dst_lock);
1148 diff -uprN linux-2.4.25.old/include/net/ipv6.h linux-2.4.25/include/net/ipv6.h
1149 --- linux-2.4.25.old/include/net/ipv6.h 2003-11-28 18:26:21.000000000 +0000
1150 +++ linux-2.4.25/include/net/ipv6.h 2004-06-26 11:29:29.000000000 +0100
1152 #define NEXTHDR_ICMP 58 /* ICMP for IPv6. */
1153 #define NEXTHDR_NONE 59 /* No next header */
1154 #define NEXTHDR_DEST 60 /* Destination options header. */
1155 +#define NEXTHDR_MH 135 /* Mobility header, RFC 3775 */
1157 #define NEXTHDR_MAX 255
1159 @@ -145,9 +146,12 @@ struct ipv6_txoptions
1160 __u16 opt_flen; /* after fragment hdr */
1161 __u16 opt_nflen; /* before fragment hdr */
1163 + __u8 mipv6_flags; /* flags set by MIPv6 */
1165 struct ipv6_opt_hdr *hopopt;
1166 struct ipv6_opt_hdr *dst0opt;
1167 - struct ipv6_rt_hdr *srcrt; /* Routing Header */
1168 + struct ipv6_rt_hdr *srcrt; /* Routing Header Type 0 */
1169 + struct ipv6_rt_hdr *srcrt2; /* Routing Header Type 2 */
1170 struct ipv6_opt_hdr *auth;
1171 struct ipv6_opt_hdr *dst1opt;
1173 @@ -256,6 +260,38 @@ static inline int ipv6_addr_any(const st
1174 a->s6_addr32[2] | a->s6_addr32[3] ) == 0);
1177 +static inline void ipv6_addr_prefix(struct in6_addr *pfx,
1178 + const struct in6_addr *addr, int plen)
1180 + /* caller must guarantee 0 <= plen <= 128 */
1181 + int o = plen >> 3,
1184 + memcpy(pfx->s6_addr, addr, o);
1186 + pfx->s6_addr[o] = addr->s6_addr[o] & (0xff00 >> b);
1190 + memset(pfx->s6_addr + o, 0, 16 - o);
1193 +static inline int ipv6_prefix_cmp(const struct in6_addr *p1,
1194 + const struct in6_addr *p2, int plen)
1201 + res = memcmp(&p1->s6_addr[0], &p2->s6_addr[0], o);
1202 + if (res == 0 && b > 0) {
1203 + __u8 m = (0xff00 >> b) & 0xff;
1204 + res = (p1->s6_addr[o] & m) - (p2->s6_addr[o] & m);
1210 * Prototypes exported by ipv6
1212 diff -uprN linux-2.4.25.old/include/net/ipv6_tunnel.h linux-2.4.25/include/net/ipv6_tunnel.h
1213 --- linux-2.4.25.old/include/net/ipv6_tunnel.h 1970-01-01 01:00:00.000000000 +0100
1214 +++ linux-2.4.25/include/net/ipv6_tunnel.h 2004-06-26 11:29:29.000000000 +0100
1220 +#ifndef _NET_IPV6_TUNNEL_H
1221 +#define _NET_IPV6_TUNNEL_H
1223 +#include <linux/ipv6.h>
1224 +#include <linux/netdevice.h>
1225 +#include <linux/ipv6_tunnel.h>
1226 +#include <linux/skbuff.h>
1227 +#include <asm/atomic.h>
1229 +/* capable of sending packets */
1230 +#define IP6_TNL_F_CAP_XMIT 0x10000
1231 +/* capable of receiving packets */
1232 +#define IP6_TNL_F_CAP_RCV 0x20000
1234 +#define IP6_TNL_MAX 128
1239 + struct ip6_tnl *next; /* next tunnel in list */
1240 + struct net_device *dev; /* virtual device associated with tunnel */
1241 + struct net_device_stats stat; /* statistics for tunnel device */
1242 + int recursion; /* depth of hard_start_xmit recursion */
1243 + struct ip6_tnl_parm parms; /* tunnel configuration paramters */
1244 + struct flowi fl; /* flowi template for xmit */
1245 + atomic_t refcnt; /* nr of identical tunnels used by kernel */
1246 + struct socket *sock;
1249 +#define IP6_TNL_PRE_ENCAP 0
1250 +#define IP6_TNL_PRE_DECAP 1
1251 +#define IP6_TNL_MAXHOOKS 2
1253 +#define IP6_TNL_DROP 0
1254 +#define IP6_TNL_ACCEPT 1
1256 +typedef int ip6_tnl_hookfn(struct ip6_tnl *t, struct sk_buff *skb);
1258 +struct ip6_tnl_hook_ops {
1259 + struct list_head list;
1260 + unsigned int hooknum;
1262 + ip6_tnl_hookfn *hook;
1265 +enum ip6_tnl_hook_priorities {
1266 + IP6_TNL_PRI_FIRST = INT_MIN,
1267 + IP6_TNL_PRI_LAST = INT_MAX
1270 +/* Tunnel encapsulation limit destination sub-option */
1272 +struct ipv6_tlv_tnl_enc_lim {
1273 + __u8 type; /* type-code for option */
1274 + __u8 length; /* option length */
1275 + __u8 encap_limit; /* tunnel encapsulation limit */
1276 +} __attribute__ ((packed));
1279 +extern int ip6ip6_tnl_create(struct ip6_tnl_parm *p, struct ip6_tnl **pt);
1281 +extern struct ip6_tnl *ip6ip6_tnl_lookup(struct in6_addr *remote,
1282 + struct in6_addr *local);
1284 +void ip6ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p);
1286 +extern int ip6ip6_kernel_tnl_add(struct ip6_tnl_parm *p);
1288 +extern int ip6ip6_kernel_tnl_del(struct ip6_tnl *t);
1290 +extern unsigned int ip6ip6_tnl_inc_max_kdev_count(unsigned int n);
1292 +extern unsigned int ip6ip6_tnl_dec_max_kdev_count(unsigned int n);
1294 +extern unsigned int ip6ip6_tnl_inc_min_kdev_count(unsigned int n);
1296 +extern unsigned int ip6ip6_tnl_dec_min_kdev_count(unsigned int n);
1298 +extern void ip6ip6_tnl_register_hook(struct ip6_tnl_hook_ops *reg);
1300 +extern void ip6ip6_tnl_unregister_hook(struct ip6_tnl_hook_ops *reg);
1302 +#ifdef CONFIG_IPV6_TUNNEL
1303 +extern int __init ip6_tunnel_init(void);
1304 +extern void ip6_tunnel_cleanup(void);
1308 diff -uprN linux-2.4.25.old/include/net/mipglue.h linux-2.4.25/include/net/mipglue.h
1309 --- linux-2.4.25.old/include/net/mipglue.h 1970-01-01 01:00:00.000000000 +0100
1310 +++ linux-2.4.25/include/net/mipglue.h 2004-06-26 11:29:29.000000000 +0100
1313 + * Glue for Mobility support integration to IPv6
1316 + * Antti Tuominen <ajtuomin@cc.hut.fi>
1320 + * This program is free software; you can redistribute it and/or
1321 + * modify it under the terms of the GNU General Public License
1322 + * as published by the Free Software Foundation; either version
1323 + * 2 of the License, or (at your option) any later version.
1327 +#ifndef _NET_MIPGLUE_H
1328 +#define _NET_MIPGLUE_H
1330 +#ifndef USE_IPV6_MOBILITY
1331 +#if defined(CONFIG_IPV6_MOBILITY) || defined(CONFIG_IPV6_MOBILITY_MODULE)
1332 +#define USE_IPV6_MOBILITY
1336 +/* symbols to indicate whether destination options received should take
1337 + * effect or not (see exthdrs.c, procrcv.c)
1339 +#define MIPV6_DSTOPTS_ACCEPT 1
1340 +#define MIPV6_DSTOPTS_DISCARD 0
1342 +#define MIPV6_IGN_RTR 0
1343 +#define MIPV6_ADD_RTR 1
1344 +#define MIPV6_CHG_RTR 2
1346 +/* MIPV6: Approximate maximum for mobile IPv6 options and headers */
1347 +#define MIPV6_HEADERS 48
1350 +#include <net/mipv6.h>
1351 +#include <linux/slab.h>
1352 +#include <net/ipv6.h>
1355 +struct ndisc_options;
1357 +struct ipv6_txoptions;
1361 +struct inet6_ifaddr;
1363 +#ifdef USE_IPV6_MOBILITY
1365 +/* calls a procedure from mipv6-module */
1366 +#define MIPV6_CALLPROC(X) if(mipv6_functions.X) mipv6_functions.X
1368 +/* calls a function from mipv6-module, default-value if function not defined
1370 +#define MIPV6_CALLFUNC(X,Y) (!mipv6_functions.X)?(Y):mipv6_functions.X
1372 +/* sets a handler-function to process a call */
1373 +#define MIPV6_SETCALL(X,Y) if(mipv6_functions.X) printk("mipv6: Warning, function assigned twice!\n"); \
1374 + mipv6_functions.X = Y
1375 +#define MIPV6_RESETCALL(X) mipv6_functions.X = NULL
1377 +/* pointers to mipv6 callable functions */
1378 +struct mipv6_callable_functions {
1379 + void (*mipv6_initialize_dstopt_rcv) (struct sk_buff *skb);
1380 + int (*mipv6_finalize_dstopt_rcv) (int process);
1381 + int (*mipv6_handle_homeaddr) (struct sk_buff *skb, int optoff);
1382 + int (*mipv6_ra_rcv) (struct sk_buff *skb,
1383 + struct ndisc_options *ndopts);
1384 + void (*mipv6_icmp_rcv) (struct sk_buff *skb);
1385 + struct ipv6_txoptions * (*mipv6_modify_txoptions) (
1387 + struct sk_buff *skb,
1388 + struct ipv6_txoptions *opt,
1390 + struct dst_entry **dst);
1391 + void (*mipv6_set_home) (int ifindex, struct in6_addr *homeaddr,
1392 + int plen, struct in6_addr *homeagent,
1394 + void (*mipv6_get_home_address) (struct in6_addr *home_addr);
1395 + void (*mipv6_get_care_of_address)(struct in6_addr *homeaddr,
1396 + struct in6_addr *coa);
1397 + int (*mipv6_is_home_addr)(struct in6_addr *addr);
1398 + void (*mipv6_change_router)(void);
1399 + void (*mipv6_check_dad)(struct in6_addr *home_addr);
1400 + void (*mipv6_icmp_swap_addrs)(struct sk_buff *skb);
1401 + int (*mipv6_forward)(struct sk_buff *skb);
1402 + int (*mipv6_mn_ha_probe)(struct inet6_ifaddr *ifp, u8 *lladdr);
1405 +extern struct mipv6_callable_functions mipv6_functions;
1407 +extern void mipv6_invalidate_calls(void);
1409 +extern int mipv6_handle_dstopt(struct sk_buff *skb, int optoff);
1412 +ndisc_mip_mn_ha_probe(struct inet6_ifaddr *ifp, u8 *lladdr)
1414 + return MIPV6_CALLFUNC(mipv6_mn_ha_probe, 0)(ifp, lladdr);
1417 +/* Must only be called for HA, no checks here */
1418 +static inline int ip6_mipv6_forward(struct sk_buff *skb)
1420 + return MIPV6_CALLFUNC(mipv6_forward, 0)(skb);
1424 + * Avoid adding new default routers if the old one is still in use
1427 +static inline int ndisc_mipv6_ra_rcv(struct sk_buff *skb,
1428 + struct ndisc_options *ndopts)
1430 + return MIPV6_CALLFUNC(mipv6_ra_rcv, MIPV6_ADD_RTR)(skb, ndopts);
1433 +static inline int ipv6_chk_mip_home_addr(struct in6_addr *addr)
1435 + return MIPV6_CALLFUNC(mipv6_is_home_addr, 0)(addr);
1438 +static inline void ndisc_mipv6_change_router(int change_rtr)
1440 + if (change_rtr == MIPV6_CHG_RTR)
1441 + MIPV6_CALLPROC(mipv6_change_router)();
1444 +static inline void ndisc_check_mipv6_dad(struct in6_addr *target)
1446 + MIPV6_CALLPROC(mipv6_check_dad)(target);
1449 +static inline void icmpv6_swap_mipv6_addrs(struct sk_buff *skb)
1451 + MIPV6_CALLPROC(mipv6_icmp_swap_addrs)(skb);
1454 +static inline void mipv6_icmp_rcv(struct sk_buff *skb)
1456 + MIPV6_CALLPROC(mipv6_icmp_rcv)(skb);
1459 +static inline int tcp_v6_get_mipv6_header_len(void)
1461 + return MIPV6_HEADERS;
1464 +static inline struct in6_addr *
1465 +mipv6_get_fake_hdr_daddr(struct in6_addr *hdaddr, struct in6_addr *daddr)
1471 +addrconf_set_mipv6_mn_home(int ifindex, struct in6_addr *homeaddr, int plen,
1472 + struct in6_addr *homeagent, int plen2)
1474 + MIPV6_CALLPROC(mipv6_set_home)(ifindex, homeaddr, plen, homeagent, plen2);
1477 +static inline void addrconf_get_mipv6_home_address(struct in6_addr *saddr)
1479 + MIPV6_CALLPROC(mipv6_get_home_address)(saddr);
1482 +static inline struct ipv6_txoptions *
1483 +ip6_add_mipv6_txoptions(struct sock *sk, struct sk_buff *skb,
1484 + struct ipv6_txoptions *opt, struct flowi *fl,
1485 + struct dst_entry **dst)
1487 + return MIPV6_CALLFUNC(mipv6_modify_txoptions, opt)(sk, skb, opt, fl, dst);
1492 +ip6_mark_mipv6_packet(struct ipv6_txoptions *txopt, struct sk_buff *skb)
1494 + struct inet6_skb_parm *opt;
1496 + opt = (struct inet6_skb_parm *)skb->cb;
1497 + opt->mipv6_flags = txopt->mipv6_flags;
1502 +ip6_free_mipv6_txoptions(struct ipv6_txoptions *opt,
1503 + struct ipv6_txoptions *orig_opt)
1505 + if (opt && opt != orig_opt)
1509 +#else /* USE_IPV6_MOBILITY */
1511 +#define mipv6_handle_dstopt ip6_tlvopt_unknown
1514 +ndisc_mip_mn_ha_probe(struct inet6_ifaddr *ifp, u8 *lladdr)
1519 +static inline int ip6_mipv6_forward(struct sk_buff *skb)
1524 +static inline int ndisc_mipv6_ra_rcv(struct sk_buff *skb,
1525 + struct ndisc_options *ndopts)
1527 + return MIPV6_ADD_RTR;
1530 +static inline int ipv6_chk_mip_home_addr(struct in6_addr *addr)
1535 +static inline void ndisc_mipv6_change_router(int change_rtr) {}
1537 +static inline void ndisc_check_mipv6_dad(struct in6_addr *target) {}
1539 +static inline void icmpv6_swap_mipv6_addrs(struct sk_buff *skb) {}
1541 +static inline void mipv6_icmp_rcv(struct sk_buff *skb) {}
1543 +static inline int tcp_v6_get_mipv6_header_len(void)
1548 +static inline struct in6_addr *
1549 +mipv6_get_fake_hdr_daddr(struct in6_addr *hdaddr, struct in6_addr *daddr)
1555 +addrconf_set_mipv6_mn_home(int ifindex, struct in6_addr *homeaddr, int plen,
1556 + struct in6_addr *homeagent, int plen2) {}
1558 +static inline void addrconf_get_mipv6_home_address(struct in6_addr *saddr) {}
1560 +static inline struct ipv6_txoptions *
1561 +ip6_add_mipv6_txoptions(struct sock *sk, struct sk_buff *skb,
1562 + struct ipv6_txoptions *opt, struct flowi *fl,
1563 + struct dst_entry **dst)
1569 +ip6_mark_mipv6_packet(struct ipv6_txoptions *txopt, struct sk_buff *skb) {}
1572 +ip6_free_mipv6_txoptions(struct ipv6_txoptions *opt,
1573 + struct ipv6_txoptions *orig_opt) {}
1575 +#endif /* USE_IPV6_MOBILITY */
1576 +#endif /* __KERNEL__ */
1577 +#endif /* _NET_MIPGLUE_H */
1578 diff -uprN linux-2.4.25.old/include/net/mipv6.h linux-2.4.25/include/net/mipv6.h
1579 --- linux-2.4.25.old/include/net/mipv6.h 1970-01-01 01:00:00.000000000 +0100
1580 +++ linux-2.4.25/include/net/mipv6.h 2004-06-26 11:29:29.000000000 +0100
1583 + * Mobile IPv6 header-file
1586 + * Sami Kivisaari <skivisaa@cc.hut.fi>
1590 + * This program is free software; you can redistribute it and/or
1591 + * modify it under the terms of the GNU General Public License
1592 + * as published by the Free Software Foundation; either version
1593 + * 2 of the License, or (at your option) any later version.
1597 +#ifndef _NET_MIPV6_H
1598 +#define _NET_MIPV6_H
1600 +#include <linux/types.h>
1601 +#include <asm/byteorder.h>
1602 +#include <linux/in6.h>
1606 + * Mobile IPv6 Protocol constants
1609 +#define DHAAD_RETRIES 4 /* transmissions */
1610 +#define INITIAL_BINDACK_TIMEOUT 1 /* seconds */
1611 +#define INITIAL_DHAAD_TIMEOUT 3 /* seconds */
1612 +#define INITIAL_SOLICIT_TIMER 3 /* seconds */
1613 +#define MAX_BINDACK_TIMEOUT 32 /* seconds */
1614 +#define MAX_NONCE_LIFE 240 /* seconds */
1615 +#define MAX_TOKEN_LIFE 210 /* seconds */
1616 +#define MAX_RR_BINDING_LIFE 420 /* seconds */
1617 +#define MAX_UPDATE_RATE 3 /* 1/s (min delay=1s) */
1618 +#define PREFIX_ADV_RETRIES 3 /* transmissions */
1619 +#define PREFIX_ADV_TIMEOUT 3 /* seconds */
1621 +#define MAX_FAST_UPDATES 5 /* transmissions */
1622 +#define MAX_PFX_ADV_DELAY 1000 /* seconds */
1623 +#define SLOW_UPDATE_RATE 10 /* 1/10s (max delay=10s)*/
1624 +#define INITIAL_BINDACK_DAD_TIMEOUT 2 /* seconds */
1628 + * Mobile IPv6 (RFC 3775) Protocol configuration variable defaults
1631 +#define DefHomeRtrAdvInterval 1000 /* seconds */
1632 +#define DefMaxMobPfxAdvInterval 86400 /* seconds */
1633 +#define DefMinDelayBetweenRAs 3 /* seconds (min 0.03) */
1634 +#define DefMinMobPfxAdvInterval 600 /* seconds */
1635 +#define DefInitialBindackTimeoutFirstReg 1.5 /* seconds */
1637 +/* This is not actually specified in the draft, but is needed to avoid
1638 + * prefix solicitation storm when valid lifetime of a prefix is smaller
1639 + * than MAX_PFX_ADV_DELAY
1641 +#define MIN_PFX_SOL_DELAY 5 /* seconds */
1643 +/* Mobile IPv6 ICMP types */
1645 + * Official numbers from RFC 3775
1647 +#define MIPV6_DHAAD_REQUEST 144
1648 +#define MIPV6_DHAAD_REPLY 145
1649 +#define MIPV6_PREFIX_SOLICIT 146
1650 +#define MIPV6_PREFIX_ADV 147
1652 +/* Binding update flag codes */
1653 +#define MIPV6_BU_F_ACK 0x80
1654 +#define MIPV6_BU_F_HOME 0x40
1655 +#define MIPV6_BU_F_LLADDR 0x20
1656 +#define MIPV6_BU_F_KEYMGM 0x10
1658 +/* Binding ackknowledgment flag codes */
1659 +#define MIPV6_BA_F_KEYMGM 0x80
1661 +/* Binding error status */
1662 +#define MIPV6_BE_HAO_WO_BINDING 1
1663 +#define MIPV6_BE_UNKNOWN_MH_TYPE 2
1665 +/* Mobility Header */
1668 + __u8 payload; /* Payload Protocol */
1669 + __u8 length; /* MH Length */
1670 + __u8 type; /* MH Type */
1671 + __u8 reserved; /* Reserved */
1672 + __u16 checksum; /* Checksum */
1673 + __u8 data[0]; /* Message specific data */
1674 +} __attribute__ ((packed));
1676 +/* Mobility Header type */
1677 +#define IPPROTO_MOBILITY 135 /* RFC 3775*/
1678 +/* Mobility Header Message Types */
1680 +#define MIPV6_MH_BRR 0
1681 +#define MIPV6_MH_HOTI 1
1682 +#define MIPV6_MH_COTI 2
1683 +#define MIPV6_MH_HOT 3
1684 +#define MIPV6_MH_COT 4
1685 +#define MIPV6_MH_BU 5
1686 +#define MIPV6_MH_BA 6
1687 +#define MIPV6_MH_BE 7
1690 + * Status codes for Binding Acknowledgements
1693 +#define REASON_UNSPECIFIED 128
1694 +#define ADMINISTRATIVELY_PROHIBITED 129
1695 +#define INSUFFICIENT_RESOURCES 130
1696 +#define HOME_REGISTRATION_NOT_SUPPORTED 131
1697 +#define NOT_HOME_SUBNET 132
1698 +#define NOT_HA_FOR_MN 133
1699 +#define DUPLICATE_ADDR_DETECT_FAIL 134
1700 +#define SEQUENCE_NUMBER_OUT_OF_WINDOW 135
1701 +#define EXPIRED_HOME_NONCE_INDEX 136
1702 +#define EXPIRED_CAREOF_NONCE_INDEX 137
1703 +#define EXPIRED_NONCES 138
1704 +#define REG_TYPE_CHANGE_FORBIDDEN 139
1706 + * Values for mipv6_flags in struct inet6_skb_parm
1709 +#define MIPV6_RCV_TUNNEL 0x1
1710 +#define MIPV6_SND_HAO 0x2
1711 +#define MIPV6_SND_BU 0x4
1714 + * Mobility Header Message structures
1717 +struct mipv6_mh_brr
1720 + /* Mobility options */
1721 +} __attribute__ ((packed));
1725 + __u16 sequence; /* sequence number of BU */
1726 + __u8 flags; /* flags */
1727 + __u8 reserved; /* reserved bits */
1728 + __u16 lifetime; /* lifetime of BU */
1729 + /* Mobility options */
1730 +} __attribute__ ((packed));
1734 + __u8 status; /* statuscode */
1735 + __u8 reserved; /* reserved bits */
1736 + __u16 sequence; /* sequence number of BA */
1737 + __u16 lifetime; /* lifetime in CN's bcache */
1738 + /* Mobility options */
1739 +} __attribute__ ((packed));
1745 + struct in6_addr home_addr;
1746 + /* Mobility options */
1747 +} __attribute__ ((packed));
1749 +struct mipv6_mh_addr_ti
1751 + __u16 reserved; /* Reserved */
1752 + u_int8_t init_cookie[8]; /* HoT/CoT Init Cookie */
1753 + /* Mobility options */
1754 +} __attribute__ ((packed));
1756 +struct mipv6_mh_addr_test
1758 + __u16 nonce_index; /* Home/Care-of Nonce Index */
1759 + u_int8_t init_cookie[8]; /* HoT/CoT Init Cookie */
1760 + u_int8_t kgen_token[8]; /* Home/Care-of key generation token */
1761 + /* Mobility options */
1762 +} __attribute__ ((packed));
1765 + * Mobility Options for various MH types.
1767 +#define MIPV6_OPT_PAD1 0x00
1768 +#define MIPV6_OPT_PADN 0x01
1769 +#define MIPV6_OPT_BIND_REFRESH_ADVICE 0x02
1770 +#define MIPV6_OPT_ALTERNATE_COA 0x03
1771 +#define MIPV6_OPT_NONCE_INDICES 0x04
1772 +#define MIPV6_OPT_AUTH_DATA 0x05
1774 +#define MIPV6_SEQ_GT(x,y) \
1775 + ((short int)(((__u16)(x)) - ((__u16)(y))) > 0)
1778 + * Mobility Option structures
1785 + __u8 value[0]; /* type specific data */
1786 +} __attribute__ ((packed));
1788 +struct mipv6_mo_pad1
1791 +} __attribute__ ((packed));
1793 +struct mipv6_mo_padn
1798 +} __attribute__ ((packed));
1800 +struct mipv6_mo_alt_coa
1804 + struct in6_addr addr; /* alternate care-of-address */
1805 +} __attribute__ ((packed));
1807 +struct mipv6_mo_nonce_indices
1811 + __u16 home_nonce_i; /* Home Nonce Index */
1812 + __u16 careof_nonce_i; /* Careof Nonce Index */
1813 +} __attribute__ ((packed));
1815 +struct mipv6_mo_bauth_data
1820 +} __attribute__ ((packed));
1822 +struct mipv6_mo_br_advice
1826 + __u16 refresh_interval; /* Refresh Interval */
1827 +} __attribute__ ((packed));
1830 + * Home Address Destination Option structure
1832 +struct mipv6_dstopt_homeaddr
1834 + __u8 type; /* type-code for option */
1835 + __u8 length; /* option length */
1836 + struct in6_addr addr; /* home address */
1837 +} __attribute__ ((packed));
1839 +#endif /* _NET_MIPV6_H */
1840 diff -uprN linux-2.4.25.old/include/net/ndisc.h linux-2.4.25/include/net/ndisc.h
1841 --- linux-2.4.25.old/include/net/ndisc.h 2002-11-28 23:53:15.000000000 +0000
1842 +++ linux-2.4.25/include/net/ndisc.h 2004-06-26 11:29:29.000000000 +0100
1844 #define ND_OPT_REDIRECT_HDR 4
1845 #define ND_OPT_MTU 5
1847 +/* Mobile IPv6 specific ndisc options */
1848 +#define ND_OPT_RTR_ADV_INTERVAL 7
1849 +#define ND_OPT_HOME_AGENT_INFO 8
1851 #define MAX_RTR_SOLICITATION_DELAY HZ
1853 #define ND_REACHABLE_TIME (30*HZ)
1854 @@ -57,7 +61,7 @@ struct nd_opt_hdr {
1855 } __attribute__((__packed__));
1857 struct ndisc_options {
1858 - struct nd_opt_hdr *nd_opt_array[7];
1859 + struct nd_opt_hdr *nd_opt_array[10];
1860 struct nd_opt_hdr *nd_opt_piend;
1863 @@ -67,6 +71,8 @@ struct ndisc_options {
1864 #define nd_opts_pi_end nd_opt_piend
1865 #define nd_opts_rh nd_opt_array[ND_OPT_REDIRECT_HDR]
1866 #define nd_opts_mtu nd_opt_array[ND_OPT_MTU]
1867 +#define nd_opts_rai nd_opt_array[ND_OPT_RTR_ADV_INTERVAL]
1868 +#define nd_opts_hai nd_opt_array[ND_OPT_HOME_AGENT_INFO]
1870 extern struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur, struct nd_opt_hdr *end);
1871 extern struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len, struct ndisc_options *ndopts);
1872 @@ -83,6 +89,15 @@ extern void ndisc_send_ns(struct net_d
1873 struct in6_addr *daddr,
1874 struct in6_addr *saddr);
1876 +extern void ndisc_send_na(struct net_device *dev,
1877 + struct neighbour *neigh,
1878 + struct in6_addr *daddr,
1879 + struct in6_addr *solicited_addr,
1885 extern void ndisc_send_rs(struct net_device *dev,
1886 struct in6_addr *saddr,
1887 struct in6_addr *daddr);
1888 diff -uprN linux-2.4.25.old/include/net/sock.h linux-2.4.25/include/net/sock.h
1889 --- linux-2.4.25.old/include/net/sock.h 2004-02-18 13:36:32.000000000 +0000
1890 +++ linux-2.4.25/include/net/sock.h 2004-06-26 11:29:30.000000000 +0100
1891 @@ -149,7 +149,9 @@ struct ipv6_pinfo {
1892 struct in6_addr rcv_saddr;
1893 struct in6_addr daddr;
1894 struct in6_addr *daddr_cache;
1896 +#if defined(CONFIG_IPV6_SUBTREES)
1897 + struct in6_addr *saddr_cache;
1902 diff -uprN linux-2.4.25.old/net/Makefile linux-2.4.25/net/Makefile
1903 --- linux-2.4.25.old/net/Makefile 2004-06-26 11:22:00.000000000 +0100
1904 +++ linux-2.4.25/net/Makefile 2004-06-26 11:29:30.000000000 +0100
1907 O_TARGET := network.o
1909 -mod-subdirs := ipv4/netfilter ipv6/netfilter ipx irda bluetooth atm netlink sched core sctp
1910 +mod-subdirs := ipv4/netfilter ipv6/netfilter ipx irda bluetooth atm netlink sched core sctp ipv6
1911 export-objs := netsyms.o
1913 subdir-y := core ethernet
1914 @@ -25,6 +25,7 @@ subdir-$(CONFIG_IP_SCTP) += sctp
1915 ifneq ($(CONFIG_IPV6),n)
1916 ifneq ($(CONFIG_IPV6),)
1917 subdir-$(CONFIG_NETFILTER) += ipv6/netfilter
1918 +subdir-$(CONFIG_IPV6_MOBILITY) += ipv6/mobile_ip6
1922 diff -uprN linux-2.4.25.old/net/core/neighbour.c linux-2.4.25/net/core/neighbour.c
1923 --- linux-2.4.25.old/net/core/neighbour.c 2004-02-18 13:36:32.000000000 +0000
1924 +++ linux-2.4.25/net/core/neighbour.c 2004-06-26 11:29:30.000000000 +0100
1925 @@ -386,7 +386,7 @@ struct pneigh_entry * pneigh_lookup(stru
1929 - n = kmalloc(sizeof(*n) + key_len, GFP_KERNEL);
1930 + n = kmalloc(sizeof(*n) + key_len, GFP_ATOMIC);
1934 diff -uprN linux-2.4.25.old/net/ipv6/Config.in linux-2.4.25/net/ipv6/Config.in
1935 --- linux-2.4.25.old/net/ipv6/Config.in 2001-12-21 17:42:05.000000000 +0000
1936 +++ linux-2.4.25/net/ipv6/Config.in 2004-06-26 11:29:30.000000000 +0100
1939 # IPv6 configuration
1942 +bool ' IPv6: routing by source address (EXPERIMENTAL)' CONFIG_IPV6_SUBTREES
1943 #bool ' IPv6: flow policy support' CONFIG_RT6_POLICY
1944 #bool ' IPv6: firewall support' CONFIG_IPV6_FIREWALL
1946 +if [ "$CONFIG_IPV6" != "n" ]; then
1947 + dep_tristate ' IPv6: IPv6 over IPv6 Tunneling (EXPERIMENTAL)' CONFIG_IPV6_TUNNEL $CONFIG_IPV6
1950 +source net/ipv6/mobile_ip6/Config.in
1952 if [ "$CONFIG_NETFILTER" != "n" ]; then
1953 source net/ipv6/netfilter/Config.in
1955 diff -uprN linux-2.4.25.old/net/ipv6/Makefile linux-2.4.25/net/ipv6/Makefile
1956 --- linux-2.4.25.old/net/ipv6/Makefile 2003-11-28 18:26:21.000000000 +0000
1957 +++ linux-2.4.25/net/ipv6/Makefile 2004-06-26 11:29:30.000000000 +0100
1959 # unless it's something special (ie not a .c file).
1962 +export-objs := ipv6_syms.o ipv6_tunnel.o
1965 +#list-multi := ipv6.o ipv6_tunnel.o
1967 -obj-y := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o sit.o \
1968 - route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o raw.o \
1969 - protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \
1970 - exthdrs.o sysctl_net_ipv6.o datagram.o proc.o \
1971 - ip6_flowlabel.o ipv6_syms.o
1972 +ipv6-objs := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o \
1973 + sit.o route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o \
1974 + raw.o protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \
1975 + exthdrs.o sysctl_net_ipv6.o datagram.o proc.o \
1976 + ip6_flowlabel.o ipv6_syms.o
1978 +ifneq ($(CONFIG_IPV6_MOBILITY),n)
1979 +ifneq ($(CONFIG_IPV6_MOBILITY),)
1980 +ipv6-objs += mipglue.o
1984 -export-objs := ipv6_syms.o
1985 +obj-$(CONFIG_IPV6) += ipv6.o
1986 +obj-$(CONFIG_IPV6_TUNNEL) += ipv6_tunnel.o
1988 +ipv6.o: $(ipv6-objs)
1989 + $(LD) -r -o $@ $(ipv6-objs)
1991 -obj-m := $(O_TARGET)
1993 #obj-$(CONFIG_IPV6_FIREWALL) += ip6_fw.o
1995 diff -uprN linux-2.4.25.old/net/ipv6/addrconf.c linux-2.4.25/net/ipv6/addrconf.c
1996 --- linux-2.4.25.old/net/ipv6/addrconf.c 2003-11-28 18:26:21.000000000 +0000
1997 +++ linux-2.4.25/net/ipv6/addrconf.c 2004-06-26 11:29:30.000000000 +0100
2000 #include <asm/uaccess.h>
2002 +#include <net/mipglue.h>
2004 #define IPV6_MAX_ADDRESSES 16
2006 /* Set to 3 to get tracing... */
2007 @@ -103,9 +105,9 @@ static spinlock_t addrconf_verify_lock =
2009 static int addrconf_ifdown(struct net_device *dev, int how);
2011 -static void addrconf_dad_start(struct inet6_ifaddr *ifp, int flags);
2012 +void addrconf_dad_start(struct inet6_ifaddr *ifp, int flags);
2013 static void addrconf_dad_timer(unsigned long data);
2014 -static void addrconf_dad_completed(struct inet6_ifaddr *ifp);
2015 +void addrconf_dad_completed(struct inet6_ifaddr *ifp);
2016 static void addrconf_rs_timer(unsigned long data);
2017 static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa);
2019 @@ -330,38 +332,6 @@ static struct inet6_dev * ipv6_find_idev
2023 -void ipv6_addr_prefix(struct in6_addr *prefix,
2024 - struct in6_addr *addr, int prefix_len)
2026 - unsigned long mask;
2029 - memset(prefix, 0, sizeof(*prefix));
2031 - if (prefix_len <= 0)
2033 - if (prefix_len > 128)
2036 - ncopy = prefix_len / 32;
2038 - case 4: prefix->s6_addr32[3] = addr->s6_addr32[3];
2039 - case 3: prefix->s6_addr32[2] = addr->s6_addr32[2];
2040 - case 2: prefix->s6_addr32[1] = addr->s6_addr32[1];
2041 - case 1: prefix->s6_addr32[0] = addr->s6_addr32[0];
2044 - nbits = prefix_len % 32;
2048 - mask = ~((1 << (32 - nbits)) - 1);
2049 - mask = htonl(mask);
2051 - prefix->s6_addr32[ncopy] = addr->s6_addr32[ncopy] & mask;
2055 static void dev_forward_change(struct inet6_dev *idev)
2057 struct net_device *dev;
2058 @@ -513,7 +483,7 @@ ipv6_add_addr(struct inet6_dev *idev, co
2060 /* This function wants to get referenced ifp and releases it before return */
2062 -static void ipv6_del_addr(struct inet6_ifaddr *ifp)
2063 +void ipv6_del_addr(struct inet6_ifaddr *ifp)
2065 struct inet6_ifaddr *ifa, **ifap;
2066 struct inet6_dev *idev = ifp->idev;
2067 @@ -662,6 +632,12 @@ out:
2071 + /* The home address is always used as source address in
2072 + * MIPL mobile IPv6
2074 + if (scope != IFA_HOST && scope != IFA_LINK)
2075 + addrconf_get_mipv6_home_address(saddr);
2080 @@ -815,7 +791,7 @@ void addrconf_leave_solict(struct net_de
2084 -static int ipv6_generate_eui64(u8 *eui, struct net_device *dev)
2085 +int ipv6_generate_eui64(u8 *eui, struct net_device *dev)
2087 switch (dev->type) {
2089 @@ -840,7 +816,7 @@ static int ipv6_generate_eui64(u8 *eui,
2093 -static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev)
2094 +int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev)
2097 struct inet6_ifaddr *ifp;
2098 @@ -1407,6 +1383,24 @@ static void addrconf_sit_config(struct n
2103 + * addrconf_ipv6_tunnel_config - configure IPv6 tunnel device
2104 + * @dev: tunnel device
2107 +static void addrconf_ipv6_tunnel_config(struct net_device *dev)
2109 + struct inet6_dev *idev;
2113 + /* Assign inet6_dev structure to tunnel device */
2114 + if ((idev = ipv6_find_idev(dev)) == NULL) {
2115 + printk(KERN_DEBUG "init ipv6 tunnel: add_dev failed\n");
2121 int addrconf_notify(struct notifier_block *this, unsigned long event,
2123 @@ -1421,6 +1415,10 @@ int addrconf_notify(struct notifier_bloc
2124 addrconf_sit_config(dev);
2127 + case ARPHRD_TUNNEL6:
2128 + addrconf_ipv6_tunnel_config(dev);
2131 case ARPHRD_LOOPBACK:
2134 @@ -1602,7 +1600,7 @@ out:
2136 * Duplicate Address Detection
2138 -static void addrconf_dad_start(struct inet6_ifaddr *ifp, int flags)
2139 +void addrconf_dad_start(struct inet6_ifaddr *ifp, int flags)
2141 struct net_device *dev;
2142 unsigned long rand_num;
2143 @@ -1667,7 +1665,7 @@ static void addrconf_dad_timer(unsigned
2147 -static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
2148 +void addrconf_dad_completed(struct inet6_ifaddr *ifp)
2150 struct net_device * dev = ifp->idev->dev;
2152 @@ -1676,7 +1674,7 @@ static void addrconf_dad_completed(struc
2155 ipv6_ifa_notify(RTM_NEWADDR, ifp);
2157 + notifier_call_chain(&inet6addr_chain,NETDEV_UP,ifp);
2158 /* If added prefix is link local and forwarding is off,
2159 start sending router solicitations.
2161 @@ -1877,8 +1875,20 @@ inet6_rtm_newaddr(struct sk_buff *skb, s
2162 if (rta[IFA_LOCAL-1]) {
2163 if (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx)))
2165 + if (ifm->ifa_flags & IFA_F_HOMEADDR && !rta[IFA_HOMEAGENT-1])
2167 pfx = RTA_DATA(rta[IFA_LOCAL-1]);
2169 + if (rta[IFA_HOMEAGENT-1]) {
2170 + struct in6_addr *ha;
2171 + if (pfx == NULL || !(ifm->ifa_flags & IFA_F_HOMEADDR))
2173 + if (RTA_PAYLOAD(rta[IFA_HOMEAGENT-1]) < sizeof(*ha))
2175 + ha = RTA_DATA(rta[IFA_HOMEAGENT-1]);
2176 + addrconf_set_mipv6_mn_home(ifm->ifa_index, pfx, ifm->ifa_prefixlen,
2177 + ha, ifm->ifa_prefixlen);
2182 diff -uprN linux-2.4.25.old/net/ipv6/af_inet6.c linux-2.4.25/net/ipv6/af_inet6.c
2183 --- linux-2.4.25.old/net/ipv6/af_inet6.c 2003-11-28 18:26:21.000000000 +0000
2184 +++ linux-2.4.25/net/ipv6/af_inet6.c 2004-06-26 11:29:30.000000000 +0100
2186 #include <net/transp_v6.h>
2187 #include <net/ip6_route.h>
2188 #include <net/addrconf.h>
2189 +#ifdef CONFIG_IPV6_TUNNEL
2190 +#include <net/ipv6_tunnel.h>
2193 #include <asm/uaccess.h>
2194 #include <asm/system.h>
2195 @@ -646,6 +649,11 @@ static int __init inet6_init(void)
2196 err = ndisc_init(&inet6_family_ops);
2199 +#ifdef CONFIG_IPV6_TUNNEL
2200 + err = ip6_tunnel_init();
2202 + goto ip6_tunnel_fail;
2204 err = igmp6_init(&inet6_family_ops);
2207 @@ -698,6 +706,10 @@ proc_raw6_fail:
2211 +#ifdef CONFIG_IPV6_TUNNEL
2212 + ip6_tunnel_cleanup();
2218 @@ -730,6 +742,9 @@ static void inet6_exit(void)
2219 ip6_route_cleanup();
2220 ipv6_packet_cleanup();
2222 +#ifdef CONFIG_IPV6_TUNNEL
2223 + ip6_tunnel_cleanup();
2227 #ifdef CONFIG_SYSCTL
2228 diff -uprN linux-2.4.25.old/net/ipv6/exthdrs.c linux-2.4.25/net/ipv6/exthdrs.c
2229 --- linux-2.4.25.old/net/ipv6/exthdrs.c 2003-08-25 12:44:44.000000000 +0100
2230 +++ linux-2.4.25/net/ipv6/exthdrs.c 2004-06-26 11:29:30.000000000 +0100
2232 #include <net/ip6_route.h>
2233 #include <net/addrconf.h>
2235 +#include <net/mipglue.h>
2236 +#include <net/mipv6.h>
2238 #include <asm/uaccess.h>
2241 @@ -160,7 +163,8 @@ bad:
2242 *****************************/
2244 struct tlvtype_proc tlvprocdestopt_lst[] = {
2245 - /* No destination options are defined now */
2246 + /* Mobility Support destination options */
2247 + {MIPV6_TLV_HOMEADDR, mipv6_handle_dstopt},
2251 @@ -210,6 +214,7 @@ static int ipv6_routing_header(struct sk
2253 struct ipv6_rt_hdr *hdr;
2254 struct rt0_hdr *rthdr;
2255 + struct rt2_hdr *rt2hdr;
2257 if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
2258 !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
2259 @@ -225,17 +230,25 @@ static int ipv6_routing_header(struct sk
2264 + /* Silently discard invalid packets containing RTH type 2 */
2265 + if (hdr->type == IPV6_SRCRT_TYPE_2 &&
2266 + (hdr->hdrlen != 2 || hdr->segments_left != 1)) {
2271 if (hdr->segments_left == 0) {
2272 - opt->srcrt = skb->h.raw - skb->nh.raw;
2273 + if (hdr->type == IPV6_SRCRT_TYPE_0)
2274 + opt->srcrt = skb->h.raw - skb->nh.raw;
2275 + else if (hdr->type == IPV6_SRCRT_TYPE_2)
2276 + opt->srcrt2 = skb->h.raw - skb->nh.raw;
2277 skb->h.raw += (hdr->hdrlen + 1) << 3;
2278 opt->dst0 = opt->dst1;
2280 return (&hdr->nexthdr) - skb->nh.raw;
2283 - if (hdr->type != IPV6_SRCRT_TYPE_0) {
2284 + if (hdr->type != IPV6_SRCRT_TYPE_0 && hdr->type != IPV6_SRCRT_TYPE_2) {
2285 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw);
2288 @@ -275,9 +288,20 @@ looped_back:
2290 i = n - --hdr->segments_left;
2292 - rthdr = (struct rt0_hdr *) hdr;
2293 - addr = rthdr->addr;
2295 + if (hdr->type == IPV6_SRCRT_TYPE_0) {
2296 + rthdr = (struct rt0_hdr *) hdr;
2297 + addr = rthdr->addr;
2300 + /* check that address is this node's home address */
2301 + rt2hdr = (struct rt2_hdr *) hdr;
2302 + addr = &rt2hdr->addr;
2303 + if (!ipv6_chk_addr(addr, NULL) ||
2304 + !ipv6_chk_mip_home_addr(addr)) {
2310 addr_type = ipv6_addr_type(addr);
2312 @@ -330,6 +354,10 @@ looped_back:
2313 temporary (or permanent) backdoor.
2314 If listening socket set IPV6_RTHDR to 2, then we invert header.
2317 + By the Mobile IPv6 specification Type 2 routing header MUST NOT be
2322 struct ipv6_txoptions *
2323 @@ -352,6 +380,18 @@ ipv6_invert_rthdr(struct sock *sk, struc
2324 struct ipv6_txoptions *opt;
2325 int hdrlen = ipv6_optlen(hdr);
2327 + if (hdr->type == IPV6_SRCRT_TYPE_2) {
2328 + opt = sock_kmalloc(sk, sizeof(*opt) + hdrlen, GFP_ATOMIC);
2331 + memset(opt, 0, sizeof(*opt));
2332 + opt->tot_len = sizeof(*opt) + hdrlen;
2333 + opt->srcrt = (void*)(opt+1);
2334 + opt->opt_nflen = hdrlen;
2335 + memcpy(opt->srcrt, hdr, sizeof(struct rt2_hdr));
2339 if (hdr->segments_left ||
2340 hdr->type != IPV6_SRCRT_TYPE_0 ||
2342 @@ -622,8 +662,18 @@ u8 *ipv6_build_nfrag_opts(struct sk_buff
2345 prev_hdr = ipv6_build_exthdr(skb, prev_hdr, NEXTHDR_DEST, opt->dst0opt);
2347 - prev_hdr = ipv6_build_rthdr(skb, prev_hdr, opt->srcrt, daddr);
2349 + if (opt->srcrt2) {
2350 + struct in6_addr *rt2_hop = &((struct rt2_hdr *)opt->srcrt2)->addr;
2351 + prev_hdr = ipv6_build_rthdr(skb, prev_hdr, opt->srcrt, rt2_hop);
2353 + prev_hdr = ipv6_build_rthdr(skb, prev_hdr, opt->srcrt, daddr);
2355 + if (opt->srcrt2) {
2356 + struct inet6_skb_parm *parm = (struct inet6_skb_parm *)skb->cb;
2357 + ipv6_addr_copy(&parm->hoa, daddr);
2358 + prev_hdr = ipv6_build_rthdr(skb, prev_hdr, opt->srcrt2, daddr);
2363 @@ -684,6 +734,11 @@ void ipv6_push_nfrag_opts(struct sk_buff
2365 struct in6_addr **daddr)
2367 + if (opt->srcrt2) {
2368 + struct inet6_skb_parm *parm = (struct inet6_skb_parm *)skb->cb;
2369 + ipv6_addr_copy(&parm->hoa, *daddr);
2370 + ipv6_push_rthdr(skb, proto, opt->srcrt2, daddr);
2373 ipv6_push_rthdr(skb, proto, opt->srcrt, daddr);
2375 @@ -719,6 +774,8 @@ ipv6_dup_options(struct sock *sk, struct
2376 *((char**)&opt2->auth) += dif;
2378 *((char**)&opt2->srcrt) += dif;
2380 + *((char**)&opt2->srcrt2) += dif;
2384 diff -uprN linux-2.4.25.old/net/ipv6/icmp.c linux-2.4.25/net/ipv6/icmp.c
2385 --- linux-2.4.25.old/net/ipv6/icmp.c 2003-11-28 18:26:21.000000000 +0000
2386 +++ linux-2.4.25/net/ipv6/icmp.c 2004-06-26 11:29:30.000000000 +0100
2388 #include <net/addrconf.h>
2389 #include <net/icmp.h>
2391 +#include <net/mipglue.h>
2393 #include <asm/uaccess.h>
2394 #include <asm/system.h>
2396 @@ -364,6 +366,8 @@ void icmpv6_send(struct sk_buff *skb, in
2400 + icmpv6_swap_mipv6_addrs(skb);
2402 ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, len, NULL, -1,
2404 if (type >= ICMPV6_DEST_UNREACH && type <= ICMPV6_PARAMPROB)
2405 @@ -562,13 +566,13 @@ int icmpv6_rcv(struct sk_buff *skb)
2406 rt6_pmtu_discovery(&orig_hdr->daddr, &orig_hdr->saddr, dev,
2407 ntohl(hdr->icmp6_mtu));
2410 - * Drop through to notify
2412 + icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
2415 case ICMPV6_DEST_UNREACH:
2416 - case ICMPV6_TIME_EXCEED:
2417 case ICMPV6_PARAMPROB:
2418 + mipv6_icmp_rcv(skb);
2419 + case ICMPV6_TIME_EXCEED:
2420 icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
2423 @@ -597,6 +601,13 @@ int icmpv6_rcv(struct sk_buff *skb)
2424 case ICMPV6_MGM_REDUCTION:
2427 + case MIPV6_DHAAD_REQUEST:
2428 + case MIPV6_DHAAD_REPLY:
2429 + case MIPV6_PREFIX_SOLICIT:
2430 + case MIPV6_PREFIX_ADV:
2431 + mipv6_icmp_rcv(skb);
2435 if (net_ratelimit())
2436 printk(KERN_DEBUG "icmpv6: msg of unkown type\n");
2437 diff -uprN linux-2.4.25.old/net/ipv6/ip6_fib.c linux-2.4.25/net/ipv6/ip6_fib.c
2438 --- linux-2.4.25.old/net/ipv6/ip6_fib.c 2003-08-25 12:44:44.000000000 +0100
2439 +++ linux-2.4.25/net/ipv6/ip6_fib.c 2004-06-26 11:29:30.000000000 +0100
2441 * Yuji SEKIYA @USAGI: Support default route on router node;
2442 * remove ip6_null_entry from the top of
2444 + * Ville Nuorvala: Fixes to source address based routing
2446 #include <linux/config.h>
2447 #include <linux/errno.h>
2449 #include <net/ip6_route.h>
2452 -#undef CONFIG_IPV6_SUBTREES
2455 #define RT6_TRACE(x...) printk(KERN_DEBUG x)
2456 @@ -500,6 +500,8 @@ static __inline__ void fib6_start_gc(str
2457 mod_timer(&ip6_fib_timer, jiffies + ip6_rt_gc_interval);
2460 +static struct rt6_info * fib6_find_prefix(struct fib6_node *fn);
2463 * Add routing information to the routing tree.
2464 * <destination addr>/<source addr>
2465 @@ -508,17 +510,19 @@ static __inline__ void fib6_start_gc(str
2467 int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nlmsghdr *nlh)
2469 - struct fib6_node *fn;
2470 + struct fib6_node *fn = root;
2473 - fn = fib6_add_1(root, &rt->rt6i_dst.addr, sizeof(struct in6_addr),
2474 - rt->rt6i_dst.plen, (u8*) &rt->rt6i_dst - (u8*) rt);
2475 +#ifdef CONFIG_IPV6_SUBTREES
2476 + struct fib6_node *pn = NULL;
2478 + fn = fib6_add_1(root, &rt->rt6i_src.addr, sizeof(struct in6_addr),
2479 + rt->rt6i_src.plen, (u8*) &rt->rt6i_src - (u8*) rt);
2484 -#ifdef CONFIG_IPV6_SUBTREES
2485 - if (rt->rt6i_src.plen) {
2486 + if (rt->rt6i_dst.plen) {
2487 struct fib6_node *sn;
2489 if (fn->subtree == NULL) {
2490 @@ -546,9 +550,9 @@ int fib6_add(struct fib6_node *root, str
2492 /* Now add the first leaf node to new subtree */
2494 - sn = fib6_add_1(sfn, &rt->rt6i_src.addr,
2495 - sizeof(struct in6_addr), rt->rt6i_src.plen,
2496 - (u8*) &rt->rt6i_src - (u8*) rt);
2497 + sn = fib6_add_1(sfn, &rt->rt6i_dst.addr,
2498 + sizeof(struct in6_addr), rt->rt6i_dst.plen,
2499 + (u8*) &rt->rt6i_dst - (u8*) rt);
2502 /* If it is failed, discard just allocated
2503 @@ -562,21 +566,30 @@ int fib6_add(struct fib6_node *root, str
2504 /* Now link new subtree to main tree */
2507 - if (fn->leaf == NULL) {
2509 - atomic_inc(&rt->rt6i_ref);
2512 - sn = fib6_add_1(fn->subtree, &rt->rt6i_src.addr,
2513 - sizeof(struct in6_addr), rt->rt6i_src.plen,
2514 - (u8*) &rt->rt6i_src - (u8*) rt);
2515 + sn = fib6_add_1(fn->subtree, &rt->rt6i_dst.addr,
2516 + sizeof(struct in6_addr), rt->rt6i_dst.plen,
2517 + (u8*) &rt->rt6i_dst - (u8*) rt);
2523 + /* fib6_add_1 might have cleared the old leaf pointer */
2524 + if (fn->leaf == NULL) {
2526 + atomic_inc(&rt->rt6i_ref);
2533 + fn = fib6_add_1(root, &rt->rt6i_dst.addr, sizeof(struct in6_addr),
2534 + rt->rt6i_dst.plen, (u8*) &rt->rt6i_dst - (u8*) rt);
2540 err = fib6_add_rt2node(fn, rt, nlh);
2541 @@ -588,8 +601,30 @@ int fib6_add(struct fib6_node *root, str
2547 +#ifdef CONFIG_IPV6_SUBTREES
2549 + /* If fib6_add_1 has cleared the old leaf pointer in the
2550 + super-tree leaf node, we have to find a new one for it.
2552 + This situation will never arise in the sub-tree since
2553 + the node will at least have the route that caused
2554 + fib6_add_rt2node to fail.
2557 + if (pn && !(pn->fn_flags & RTN_RTINFO)) {
2558 + pn->leaf = fib6_find_prefix(pn);
2561 + BUG_TRAP(pn->leaf);
2562 + pn->leaf = &ip6_null_entry;
2565 + atomic_inc(&pn->leaf->rt6i_ref);
2568 dst_free(&rt->u.dst);
2572 #ifdef CONFIG_IPV6_SUBTREES
2573 @@ -597,8 +632,8 @@ out:
2574 is orphan. If it is, shoot it.
2577 - if (fn && !(fn->fn_flags&RTN_RTINFO|RTN_ROOT))
2578 - fib_repair_tree(fn);
2579 + if (fn && !(fn->fn_flags & (RTN_RTINFO | RTN_ROOT)))
2580 + fib6_repair_tree(fn);
2581 dst_free(&rt->u.dst);
2584 @@ -641,22 +676,28 @@ static struct fib6_node * fib6_lookup_1(
2588 - while ((fn->fn_flags & RTN_ROOT) == 0) {
2590 #ifdef CONFIG_IPV6_SUBTREES
2592 - struct fib6_node *st;
2593 - struct lookup_args *narg;
2598 - st = fib6_lookup_1(fn->subtree, narg);
2599 + struct rt6key *key;
2601 - if (st && !(st->fn_flags & RTN_ROOT))
2603 + key = (struct rt6key *) ((u8 *) fn->leaf +
2606 + if (addr_match(&key->addr, args->addr, key->plen)) {
2607 + struct fib6_node *st;
2608 + struct lookup_args *narg = args + 1;
2609 + if (!ipv6_addr_any(narg->addr)) {
2610 + st = fib6_lookup_1(fn->subtree, narg);
2612 + if (st && !(st->fn_flags & RTN_ROOT))
2618 + if (fn->fn_flags & RTN_ROOT)
2621 if (fn->fn_flags & RTN_RTINFO) {
2623 @@ -680,13 +721,22 @@ struct fib6_node * fib6_lookup(struct fi
2624 struct lookup_args args[2];
2625 struct rt6_info *rt = NULL;
2626 struct fib6_node *fn;
2627 +#ifdef CONFIG_IPV6_SUBTREES
2628 + struct in6_addr saddr_buf;
2631 +#ifdef CONFIG_IPV6_SUBTREES
2632 + if (saddr == NULL) {
2633 + memset(&saddr_buf, 0, sizeof(struct in6_addr));
2634 + saddr = &saddr_buf;
2636 + args[0].offset = (u8*) &rt->rt6i_src - (u8*) rt;
2637 + args[0].addr = saddr;
2638 + args[1].offset = (u8*) &rt->rt6i_dst - (u8*) rt;
2639 + args[1].addr = daddr;
2641 args[0].offset = (u8*) &rt->rt6i_dst - (u8*) rt;
2642 args[0].addr = daddr;
2644 -#ifdef CONFIG_IPV6_SUBTREES
2645 - args[1].offset = (u8*) &rt->rt6i_src - (u8*) rt;
2646 - args[1].addr = saddr;
2649 fn = fib6_lookup_1(root, args);
2650 @@ -739,19 +789,25 @@ struct fib6_node * fib6_locate(struct fi
2652 struct rt6_info *rt = NULL;
2653 struct fib6_node *fn;
2655 - fn = fib6_locate_1(root, daddr, dst_len,
2656 - (u8*) &rt->rt6i_dst - (u8*) rt);
2658 #ifdef CONFIG_IPV6_SUBTREES
2660 - BUG_TRAP(saddr!=NULL);
2663 + struct in6_addr saddr_buf;
2665 + if (saddr == NULL) {
2666 + memset(&saddr_buf, 0, sizeof(struct in6_addr));
2667 + saddr = &saddr_buf;
2669 + fn = fib6_locate_1(root, saddr, src_len,
2670 + (u8*) &rt->rt6i_src - (u8*) rt);
2673 - fn = fib6_locate_1(fn, saddr, src_len,
2674 - (u8*) &rt->rt6i_src - (u8*) rt);
2675 + fn = fib6_locate_1(fn->subtree, daddr, dst_len,
2676 + (u8*) &rt->rt6i_dst - (u8*) rt);
2681 + fn = fib6_locate_1(root, daddr, dst_len,
2682 + (u8*) &rt->rt6i_dst - (u8*) rt);
2685 if (fn && fn->fn_flags&RTN_RTINFO)
2686 @@ -939,7 +995,7 @@ static void fib6_del_route(struct fib6_n
2690 - /* No more references are possiible at this point. */
2691 + /* No more references are possible at this point. */
2692 if (atomic_read(&rt->rt6i_ref) != 1) BUG();
2695 diff -uprN linux-2.4.25.old/net/ipv6/ip6_input.c linux-2.4.25/net/ipv6/ip6_input.c
2696 --- linux-2.4.25.old/net/ipv6/ip6_input.c 2003-08-25 12:44:44.000000000 +0100
2697 +++ linux-2.4.25/net/ipv6/ip6_input.c 2004-06-26 11:29:30.000000000 +0100
2699 #include <net/ip6_route.h>
2700 #include <net/addrconf.h>
2702 +static inline int ip6_proxy_chk(struct sk_buff *skb)
2704 + struct ipv6hdr *hdr = skb->nh.ipv6h;
2707 + if (ipv6_addr_type(&hdr->daddr)&IPV6_ADDR_UNICAST &&
2708 + pneigh_lookup(&nd_tbl, &hdr->daddr, skb->dev, 0)) {
2709 + u8 nexthdr = hdr->nexthdr;
2711 + struct icmp6hdr msg;
2713 + if (ipv6_ext_hdr(nexthdr)) {
2714 + offset = ipv6_skip_exthdr(skb, sizeof(*hdr), &nexthdr,
2715 + skb->len - sizeof(*hdr));
2719 + offset = sizeof(*hdr);
2721 + /* capture unicast NUD probes on behalf of the proxied node */
2723 + if (nexthdr == IPPROTO_ICMPV6 &&
2724 + !skb_copy_bits(skb, offset, &msg, sizeof(msg)) &&
2725 + msg.icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) {
2732 static inline int ip6_rcv_finish( struct sk_buff *skb)
2734 - if (skb->dst == NULL)
2735 - ip6_route_input(skb);
2737 + if (skb->dst == NULL) {
2738 + if (ip6_proxy_chk(skb))
2739 + return ip6_input(skb);
2740 + ip6_route_input(skb);
2742 return skb->dst->input(skb);
2745 diff -uprN linux-2.4.25.old/net/ipv6/ip6_output.c linux-2.4.25/net/ipv6/ip6_output.c
2746 --- linux-2.4.25.old/net/ipv6/ip6_output.c 2003-08-25 12:44:44.000000000 +0100
2747 +++ linux-2.4.25/net/ipv6/ip6_output.c 2004-06-26 11:29:30.000000000 +0100
2749 #include <net/rawv6.h>
2750 #include <net/icmp.h>
2752 +#include <net/mipglue.h>
2754 static __inline__ void ipv6_select_ident(struct sk_buff *skb, struct frag_hdr *fhdr)
2756 static u32 ipv6_fragmentation_id = 1;
2757 @@ -194,7 +196,14 @@ int ip6_xmit(struct sock *sk, struct sk_
2758 u8 proto = fl->proto;
2759 int seg_len = skb->len;
2762 + struct ipv6_txoptions *orig_opt = opt;
2764 + opt = ip6_add_mipv6_txoptions(sk, skb, orig_opt, fl, &dst);
2766 + if(orig_opt && !opt)
2772 @@ -209,8 +218,11 @@ int ip6_xmit(struct sock *sk, struct sk_
2773 struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room);
2777 + if (skb == NULL) {
2778 + ip6_free_mipv6_txoptions(opt, orig_opt);
2783 skb_set_owner_w(skb, sk);
2785 @@ -242,7 +254,10 @@ int ip6_xmit(struct sock *sk, struct sk_
2787 if (skb->len <= dst->pmtu) {
2788 IP6_INC_STATS(Ip6OutRequests);
2789 - return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_maybe_reroute);
2790 + ip6_mark_mipv6_packet(opt, skb);
2791 + retval = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_maybe_reroute);
2792 + ip6_free_mipv6_txoptions(opt, orig_opt);
2796 if (net_ratelimit())
2797 @@ -250,6 +265,9 @@ int ip6_xmit(struct sock *sk, struct sk_
2798 skb->dev = dst->dev;
2799 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst->pmtu, skb->dev);
2802 + ip6_free_mipv6_txoptions(opt, orig_opt);
2807 @@ -473,6 +491,7 @@ static int ip6_frag_xmit(struct sock *sk
2809 IP6_INC_STATS(Ip6FragCreates);
2810 IP6_INC_STATS(Ip6OutRequests);
2811 + ip6_mark_mipv6_packet(opt, skb);
2812 err = NF_HOOK(PF_INET6,NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_maybe_reroute);
2814 kfree_skb(last_skb);
2815 @@ -499,6 +518,7 @@ static int ip6_frag_xmit(struct sock *sk
2816 IP6_INC_STATS(Ip6FragCreates);
2817 IP6_INC_STATS(Ip6FragOKs);
2818 IP6_INC_STATS(Ip6OutRequests);
2819 + ip6_mark_mipv6_packet(opt, last_skb);
2820 return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, last_skb, NULL,dst->dev, ip6_maybe_reroute);
2823 @@ -509,26 +529,43 @@ int ip6_build_xmit(struct sock *sk, inet
2824 struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
2825 struct in6_addr *final_dst = NULL;
2826 struct dst_entry *dst;
2827 + struct rt6_info *rt;
2829 unsigned int pktlength, jumbolen, mtu;
2830 struct in6_addr saddr;
2831 + struct ipv6_txoptions *orig_opt = opt;
2832 +#ifdef CONFIG_IPV6_SUBTREES
2833 + struct dst_entry *org_dst;
2836 + opt = ip6_add_mipv6_txoptions(sk, NULL, orig_opt, fl, NULL);
2838 + if(orig_opt && !opt)
2841 if (opt && opt->srcrt) {
2842 struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
2843 final_dst = fl->fl6_dst;
2844 fl->fl6_dst = rt0->addr;
2846 + } else if (opt && opt->srcrt2) {
2847 + struct rt2_hdr *rt2 = (struct rt2_hdr *) opt->srcrt2;
2848 + final_dst = fl->fl6_dst;
2849 + fl->fl6_dst = &rt2->addr;
2852 if (!fl->oif && ipv6_addr_is_multicast(fl->nl_u.ip6_u.daddr))
2853 fl->oif = np->mcast_oif;
2855 dst = __sk_dst_check(sk, np->dst_cookie);
2856 +#ifdef CONFIG_IPV6_SUBTREES
2860 - struct rt6_info *rt = (struct rt6_info*)dst;
2861 + rt = (struct rt6_info*)dst;
2863 /* Yes, checking route validity in not connected
2864 case is not very simple. Take into account,
2865 - that we do not support routing by source, TOS,
2866 + that we do not support routing by TOS,
2867 and MSG_DONTROUTE --ANK (980726)
2869 1. If route was host route, check that
2870 @@ -548,6 +585,13 @@ int ip6_build_xmit(struct sock *sk, inet
2871 ipv6_addr_cmp(fl->fl6_dst, &rt->rt6i_dst.addr))
2872 && (np->daddr_cache == NULL ||
2873 ipv6_addr_cmp(fl->fl6_dst, np->daddr_cache)))
2874 +#ifdef CONFIG_IPV6_SUBTREES
2875 + || (fl->fl6_src != NULL
2876 + && (rt->rt6i_src.plen != 128 ||
2877 + ipv6_addr_cmp(fl->fl6_src, &rt->rt6i_src.addr))
2878 + && (np->saddr_cache == NULL ||
2879 + ipv6_addr_cmp(fl->fl6_src, np->saddr_cache)))
2881 || (fl->oif && fl->oif != dst->dev->ifindex)) {
2884 @@ -560,21 +604,42 @@ int ip6_build_xmit(struct sock *sk, inet
2886 IP6_INC_STATS(Ip6OutNoRoutes);
2888 + ip6_free_mipv6_txoptions(opt, orig_opt);
2889 return -ENETUNREACH;
2892 if (fl->fl6_src == NULL) {
2893 err = ipv6_get_saddr(dst, fl->fl6_dst, &saddr);
2897 printk(KERN_DEBUG "ip6_build_xmit: "
2898 "no available source address\n");
2901 +#ifdef CONFIG_IPV6_SUBTREES
2902 + if (dst != org_dst) {
2909 fl->fl6_src = &saddr;
2911 +#ifdef CONFIG_IPV6_SUBTREES
2912 + rt = (struct rt6_info*)dst;
2913 + if (dst != org_dst || rt->rt6i_src.plen != 128 ||
2914 + ipv6_addr_cmp(fl->fl6_src, &rt->rt6i_src.addr)) {
2916 + dst = ip6_route_output(sk, fl);
2918 + IP6_INC_STATS(Ip6OutNoRoutes);
2920 + ip6_free_mipv6_txoptions(opt, orig_opt);
2921 + return -ENETUNREACH;
2928 @@ -667,6 +732,7 @@ int ip6_build_xmit(struct sock *sk, inet
2931 IP6_INC_STATS(Ip6OutRequests);
2932 + ip6_mark_mipv6_packet(opt, skb);
2933 err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_maybe_reroute);
2936 @@ -688,9 +754,14 @@ int ip6_build_xmit(struct sock *sk, inet
2940 - ip6_dst_store(sk, dst, fl->nl_u.ip6_u.daddr == &np->daddr ? &np->daddr : NULL);
2941 + ip6_dst_store(sk, dst,
2942 + fl->nl_u.ip6_u.daddr == &np->daddr ? &np->daddr : NULL,
2943 + fl->nl_u.ip6_u.saddr == &np->saddr ? &np->saddr : NULL);
2945 err = np->recverr ? net_xmit_errno(err) : 0;
2947 + ip6_free_mipv6_txoptions(opt, orig_opt);
2952 @@ -769,6 +840,15 @@ int ip6_forward(struct sk_buff *skb)
2956 + /* The proxying router can't forward traffic sent to a link-local
2957 + address, so signal the sender and discard the packet. This
2958 + behavior is required by the MIPv6 specification. */
2960 + if (ipv6_addr_type(&hdr->daddr) & IPV6_ADDR_LINKLOCAL &&
2961 + skb->dev && pneigh_lookup(&nd_tbl, &hdr->daddr, skb->dev, 0)) {
2962 + dst_link_failure(skb);
2965 /* IPv6 specs say nothing about it, but it is clear that we cannot
2966 send redirects to source routed frames.
2968 diff -uprN linux-2.4.25.old/net/ipv6/ipv6_syms.c linux-2.4.25/net/ipv6/ipv6_syms.c
2969 --- linux-2.4.25.old/net/ipv6/ipv6_syms.c 2003-11-28 18:26:21.000000000 +0000
2970 +++ linux-2.4.25/net/ipv6/ipv6_syms.c 2004-06-26 11:29:30.000000000 +0100
2972 #include <net/ipv6.h>
2973 #include <net/addrconf.h>
2974 #include <net/ip6_route.h>
2975 +#include <net/ndisc.h>
2976 +#include <net/mipglue.h>
2978 EXPORT_SYMBOL(ipv6_addr_type);
2979 EXPORT_SYMBOL(icmpv6_send);
2980 @@ -33,3 +35,48 @@ EXPORT_SYMBOL(inet6_ioctl);
2981 EXPORT_SYMBOL(ipv6_get_saddr);
2982 EXPORT_SYMBOL(ipv6_chk_addr);
2983 EXPORT_SYMBOL(in6_dev_finish_destroy);
2985 +#if defined(CONFIG_IPV6_TUNNEL_MODULE) || defined(CONFIG_IPV6_MOBILITY_MODULE)
2986 +EXPORT_SYMBOL(ip6_build_xmit);
2987 +EXPORT_SYMBOL(rt6_lookup);
2988 +EXPORT_SYMBOL(ipv6_ext_hdr);
2990 +#ifdef CONFIG_IPV6_MOBILITY_MODULE
2991 +EXPORT_SYMBOL(mipv6_functions);
2992 +EXPORT_SYMBOL(mipv6_invalidate_calls);
2993 +#if defined(CONFIG_IPV6_MOBILITY_HA_MODULE) || defined(CONFIG_IPV6_MOBILITY_MN_MODULE)
2994 +EXPORT_SYMBOL(ip6_route_add);
2995 +EXPORT_SYMBOL(ip6_route_del);
2996 +EXPORT_SYMBOL(ipv6_get_lladdr);
2997 +EXPORT_SYMBOL(ipv6_get_ifaddr);
2998 +EXPORT_SYMBOL(nd_tbl);
2999 +EXPORT_SYMBOL(ndisc_send_ns);
3000 +EXPORT_SYMBOL(ndisc_send_na);
3001 +EXPORT_SYMBOL(ndisc_next_option);
3002 +EXPORT_SYMBOL(inet6_ifa_finish_destroy);
3004 +#ifdef CONFIG_IPV6_MOBILITY_HA_MODULE
3005 +EXPORT_SYMBOL(ipv6_dev_ac_dec);
3006 +EXPORT_SYMBOL(ipv6_dev_ac_inc);
3007 +EXPORT_SYMBOL(ipv6_dev_mc_dec);
3008 +EXPORT_SYMBOL(ipv6_dev_mc_inc);
3009 +EXPORT_SYMBOL(ip6_forward);
3010 +EXPORT_SYMBOL(ip6_input);
3011 +EXPORT_SYMBOL(ipv6_chk_acast_addr);
3013 +#ifdef CONFIG_IPV6_MOBILITY_MN_MODULE
3015 +EXPORT_SYMBOL(addrconf_add_ifaddr);
3016 +EXPORT_SYMBOL(addrconf_del_ifaddr);
3017 +EXPORT_SYMBOL(addrconf_dad_start);
3018 +EXPORT_SYMBOL(ip6_del_rt);
3019 +EXPORT_SYMBOL(ip6_routing_table);
3020 +EXPORT_SYMBOL(rt6_get_dflt_router);
3021 +EXPORT_SYMBOL(rt6_purge_dflt_routers);
3022 +EXPORT_SYMBOL(rt6_lock);
3023 +EXPORT_SYMBOL(ndisc_send_rs);
3024 +EXPORT_SYMBOL(fib6_clean_tree);
3025 +EXPORT_SYMBOL(ipv6_del_addr);
3026 +EXPORT_SYMBOL(ipv6_generate_eui64);
3027 +EXPORT_SYMBOL(ipv6_inherit_eui64);
3029 diff -uprN linux-2.4.25.old/net/ipv6/ipv6_tunnel.c linux-2.4.25/net/ipv6/ipv6_tunnel.c
3030 --- linux-2.4.25.old/net/ipv6/ipv6_tunnel.c 1970-01-01 01:00:00.000000000 +0100
3031 +++ linux-2.4.25/net/ipv6/ipv6_tunnel.c 2004-06-26 11:29:30.000000000 +0100
3034 + * IPv6 over IPv6 tunnel device
3035 + * Linux INET6 implementation
3038 + * Ville Nuorvala <vnuorval@tcs.hut.fi>
3043 + * linux/net/ipv6/sit.c
3047 + * This program is free software; you can redistribute it and/or
3048 + * modify it under the terms of the GNU General Public License
3049 + * as published by the Free Software Foundation; either version
3050 + * 2 of the License, or (at your option) any later version.
3054 +#include <linux/config.h>
3055 +#include <linux/module.h>
3056 +#include <linux/errno.h>
3057 +#include <linux/types.h>
3058 +#include <linux/socket.h>
3059 +#include <linux/sockios.h>
3060 +#include <linux/if.h>
3061 +#include <linux/in.h>
3062 +#include <linux/ip.h>
3063 +#include <linux/if_tunnel.h>
3064 +#include <linux/net.h>
3065 +#include <linux/in6.h>
3066 +#include <linux/netdevice.h>
3067 +#include <linux/if_arp.h>
3068 +#include <linux/icmpv6.h>
3069 +#include <linux/init.h>
3070 +#include <linux/route.h>
3071 +#include <linux/rtnetlink.h>
3072 +#include <linux/tqueue.h>
3074 +#include <asm/uaccess.h>
3075 +#include <asm/atomic.h>
3077 +#include <net/sock.h>
3078 +#include <net/ipv6.h>
3079 +#include <net/protocol.h>
3080 +#include <net/ip6_route.h>
3081 +#include <net/addrconf.h>
3082 +#include <net/ipv6_tunnel.h>
3084 +MODULE_AUTHOR("Ville Nuorvala");
3085 +MODULE_DESCRIPTION("IPv6-in-IPv6 tunnel");
3086 +MODULE_LICENSE("GPL");
3088 +#define IPV6_TLV_TEL_DST_SIZE 8
3090 +#ifdef IP6_TNL_DEBUG
3091 +#define IP6_TNL_TRACE(x...) printk(KERN_DEBUG "%s:" x "\n", __FUNCTION__)
3093 +#define IP6_TNL_TRACE(x...) do {;} while(0)
3096 +#define IPV6_TCLASS_MASK (IPV6_FLOWINFO_MASK & ~IPV6_FLOWLABEL_MASK)
3098 +#define HASH_SIZE 32
3100 +#define HASH(addr) (((addr)->s6_addr32[0] ^ (addr)->s6_addr32[1] ^ \
3101 + (addr)->s6_addr32[2] ^ (addr)->s6_addr32[3]) & \
3104 +static int ip6ip6_fb_tnl_dev_init(struct net_device *dev);
3105 +static int ip6ip6_tnl_dev_init(struct net_device *dev);
3107 +/* the IPv6 IPv6 tunnel fallback device */
3108 +static struct net_device ip6ip6_fb_tnl_dev = {
3110 + init: ip6ip6_fb_tnl_dev_init
3113 +/* the IPv6 IPv6 fallback tunnel */
3114 +static struct ip6_tnl ip6ip6_fb_tnl = {
3115 + dev: &ip6ip6_fb_tnl_dev,
3116 + parms:{name: "ip6tnl0", proto: IPPROTO_IPV6}
3119 +/* lists for storing tunnels in use */
3120 +static struct ip6_tnl *tnls_r_l[HASH_SIZE];
3121 +static struct ip6_tnl *tnls_wc[1];
3122 +static struct ip6_tnl **tnls[2] = { tnls_wc, tnls_r_l };
3124 +/* list for unused cached kernel tunnels */
3125 +static struct ip6_tnl *tnls_kernel[1];
3126 +/* maximum number of cached kernel tunnels */
3127 +static unsigned int max_kdev_count = 0;
3128 +/* minimum number of cached kernel tunnels */
3129 +static unsigned int min_kdev_count = 0;
3130 +/* current number of cached kernel tunnels */
3131 +static unsigned int kdev_count = 0;
3133 +/* lists for tunnel hook functions */
3134 +static struct list_head hooks[IP6_TNL_MAXHOOKS];
3136 +/* locks for the different lists */
3137 +static rwlock_t ip6ip6_lock = RW_LOCK_UNLOCKED;
3138 +static rwlock_t ip6ip6_kernel_lock = RW_LOCK_UNLOCKED;
3139 +static rwlock_t ip6ip6_hook_lock = RW_LOCK_UNLOCKED;
3141 +/* flag indicating if the module is being removed */
3142 +static int shutdown = 0;
3145 + * ip6ip6_tnl_lookup - fetch tunnel matching the end-point addresses
3146 + * @remote: the address of the tunnel exit-point
3147 + * @local: the address of the tunnel entry-point
3150 + * tunnel matching given end-points if found,
3151 + * else fallback tunnel if its device is up,
3156 +ip6ip6_tnl_lookup(struct in6_addr *remote, struct in6_addr *local)
3158 + unsigned h0 = HASH(remote);
3159 + unsigned h1 = HASH(local);
3160 + struct ip6_tnl *t;
3162 + for (t = tnls_r_l[h0 ^ h1]; t; t = t->next) {
3163 + if (!ipv6_addr_cmp(local, &t->parms.laddr) &&
3164 + !ipv6_addr_cmp(remote, &t->parms.raddr) &&
3165 + (t->dev->flags & IFF_UP))
3168 + if ((t = tnls_wc[0]) != NULL && (t->dev->flags & IFF_UP))
3175 + * ip6ip6_bucket - get head of list matching given tunnel parameters
3176 + * @p: parameters containing tunnel end-points
3179 + * ip6ip6_bucket() returns the head of the list matching the
3180 + * &struct in6_addr entries laddr and raddr in @p.
3182 + * Return: head of IPv6 tunnel list
3185 +static struct ip6_tnl **
3186 +ip6ip6_bucket(struct ip6_tnl_parm *p)
3188 + struct in6_addr *remote = &p->raddr;
3189 + struct in6_addr *local = &p->laddr;
3193 + if (!ipv6_addr_any(remote) || !ipv6_addr_any(local)) {
3195 + h = HASH(remote) ^ HASH(local);
3197 + return &tnls[prio][h];
3201 + * ip6ip6_kernel_tnl_link - add new kernel tunnel to cache
3202 + * @t: kernel tunnel
3205 + * %IP6_TNL_F_KERNEL_DEV is assumed to be raised in t->parms.flags.
3206 + * See the comments on ip6ip6_kernel_tnl_add() for more information.
3210 +ip6ip6_kernel_tnl_link(struct ip6_tnl *t)
3212 + write_lock_bh(&ip6ip6_kernel_lock);
3213 + t->next = tnls_kernel[0];
3214 + tnls_kernel[0] = t;
3216 + write_unlock_bh(&ip6ip6_kernel_lock);
3220 + * ip6ip6_kernel_tnl_unlink - remove first kernel tunnel from cache
3222 + * Return: first free kernel tunnel
3225 + * See the comments on ip6ip6_kernel_tnl_add() for more information.
3228 +static inline struct ip6_tnl *
3229 +ip6ip6_kernel_tnl_unlink(void)
3231 + struct ip6_tnl *t;
3233 + write_lock_bh(&ip6ip6_kernel_lock);
3234 + if ((t = tnls_kernel[0]) != NULL) {
3235 + tnls_kernel[0] = t->next;
3238 + write_unlock_bh(&ip6ip6_kernel_lock);
3243 + * ip6ip6_tnl_link - add tunnel to hash table
3244 + * @t: tunnel to be added
3248 +ip6ip6_tnl_link(struct ip6_tnl *t)
3250 + struct ip6_tnl **tp = ip6ip6_bucket(&t->parms);
3252 + write_lock_bh(&ip6ip6_lock);
3255 + write_unlock_bh(&ip6ip6_lock);
3259 + * ip6ip6_tnl_unlink - remove tunnel from hash table
3260 + * @t: tunnel to be removed
3264 +ip6ip6_tnl_unlink(struct ip6_tnl *t)
3266 + struct ip6_tnl **tp;
3268 + write_lock_bh(&ip6ip6_lock);
3269 + for (tp = ip6ip6_bucket(&t->parms); *tp; tp = &(*tp)->next) {
3275 + write_unlock_bh(&ip6ip6_lock);
3279 + * ip6ip6_tnl_create() - create a new tunnel
3280 + * @p: tunnel parameters
3281 + * @pt: pointer to new tunnel
3284 + * Create tunnel matching given parameters. New kernel managed devices are
3285 + * not put in the normal hash structure, but are instead cached for later
3293 +static int __ip6ip6_tnl_create(struct ip6_tnl_parm *p,
3294 + struct ip6_tnl **pt,
3297 + struct net_device *dev;
3298 + int err = -ENOBUFS;
3299 + struct ip6_tnl *t;
3301 + MOD_INC_USE_COUNT;
3302 + dev = kmalloc(sizeof (*dev) + sizeof (*t), GFP_KERNEL);
3304 + MOD_DEC_USE_COUNT;
3307 + memset(dev, 0, sizeof (*dev) + sizeof (*t));
3308 + dev->priv = (void *) (dev + 1);
3309 + t = (struct ip6_tnl *) dev->priv;
3311 + dev->init = ip6ip6_tnl_dev_init;
3312 + dev->features |= NETIF_F_DYNALLOC;
3313 + if (kernel_list) {
3314 + memcpy(t->parms.name, p->name, IFNAMSIZ - 1);
3315 + t->parms.proto = IPPROTO_IPV6;
3316 + t->parms.flags = IP6_TNL_F_KERNEL_DEV;
3318 + memcpy(&t->parms, p, sizeof (*p));
3320 + t->parms.name[IFNAMSIZ - 1] = '\0';
3321 + strcpy(dev->name, t->parms.name);
3322 + if (!dev->name[0]) {
3324 + for (i = 0; i < IP6_TNL_MAX; i++) {
3325 + sprintf(dev->name, "ip6tnl%d", i);
3326 + if (__dev_get_by_name(dev->name) == NULL)
3330 + if (i == IP6_TNL_MAX) {
3333 + memcpy(t->parms.name, dev->name, IFNAMSIZ);
3335 + if ((err = register_netdevice(dev)) < 0) {
3339 + if (kernel_list) {
3340 + ip6ip6_kernel_tnl_link(t);
3342 + ip6ip6_tnl_link(t);
3348 + MOD_DEC_USE_COUNT;
3353 +int ip6ip6_tnl_create(struct ip6_tnl_parm *p, struct ip6_tnl **pt)
3355 + return __ip6ip6_tnl_create(p, pt, 0);
3359 +static void manage_kernel_tnls(void *foo);
3361 +static struct tq_struct manager_task = {
3362 + routine:manage_kernel_tnls,
3367 + * manage_kernel_tnls() - create and destroy kernel tunnels
3370 + * manage_kernel_tnls() creates new kernel devices if there
3371 + * are less than $min_kdev_count of them and deletes old ones if
3372 + * there are less than $max_kdev_count of them in the cache
3375 + * Schedules itself to be run later in process context if called from
3376 + * interrupt. Therefore only works synchronously when called from process
3381 +manage_kernel_tnls(void *foo)
3383 + struct ip6_tnl *t = NULL;
3384 + struct ip6_tnl_parm parm;
3386 + /* We can't do this processing in interrupt
3387 + context so schedule it for later */
3388 + if (in_interrupt()) {
3389 + read_lock(&ip6ip6_kernel_lock);
3391 + (kdev_count < min_kdev_count ||
3392 + kdev_count > max_kdev_count)) {
3393 + schedule_task(&manager_task);
3395 + read_unlock(&ip6ip6_kernel_lock);
3400 + read_lock_bh(&ip6ip6_kernel_lock);
3401 + memset(&parm, 0, sizeof (parm));
3402 + parm.flags = IP6_TNL_F_KERNEL_DEV;
3403 + /* Create tunnels until there are at least min_kdev_count */
3404 + while (kdev_count < min_kdev_count) {
3405 + read_unlock_bh(&ip6ip6_kernel_lock);
3406 + if (!__ip6ip6_tnl_create(&parm, &t, 1)) {
3411 + read_lock_bh(&ip6ip6_kernel_lock);
3414 + /* Destroy tunnels until there are at most max_kdev_count */
3415 + while (kdev_count > max_kdev_count) {
3416 + read_unlock_bh(&ip6ip6_kernel_lock);
3417 + if ((t = ip6ip6_kernel_tnl_unlink()) != NULL) {
3418 + unregister_netdevice(t->dev);
3422 + read_lock_bh(&ip6ip6_kernel_lock);
3424 + read_unlock_bh(&ip6ip6_kernel_lock);
3430 + * ip6ip6_tnl_inc_max_kdev_count() - increase max kernel dev cache size
3431 + * @n: size increase
3433 + * Increase the upper limit for the number of kernel devices allowed in the
3434 + * cache at any on time.
3438 +ip6ip6_tnl_inc_max_kdev_count(unsigned int n)
3440 + write_lock_bh(&ip6ip6_kernel_lock);
3441 + max_kdev_count += n;
3442 + write_unlock_bh(&ip6ip6_kernel_lock);
3443 + manage_kernel_tnls(NULL);
3444 + return max_kdev_count;
3448 + * ip6ip6_tnl_dec_max_kdev_count() - decrease max kernel dev cache size
3449 + * @n: size decrement
3451 + * Decrease the upper limit for the number of kernel devices allowed in the
3452 + * cache at any on time.
3456 +ip6ip6_tnl_dec_max_kdev_count(unsigned int n)
3458 + write_lock_bh(&ip6ip6_kernel_lock);
3459 + max_kdev_count -= min(max_kdev_count, n);
3460 + if (max_kdev_count < min_kdev_count)
3461 + min_kdev_count = max_kdev_count;
3462 + write_unlock_bh(&ip6ip6_kernel_lock);
3463 + manage_kernel_tnls(NULL);
3464 + return max_kdev_count;
3468 + * ip6ip6_tnl_inc_min_kdev_count() - increase min kernel dev cache size
3469 + * @n: size increase
3471 + * Increase the lower limit for the number of kernel devices allowed in the
3472 + * cache at any on time.
3476 +ip6ip6_tnl_inc_min_kdev_count(unsigned int n)
3478 + write_lock_bh(&ip6ip6_kernel_lock);
3479 + min_kdev_count += n;
3480 + if (min_kdev_count > max_kdev_count)
3481 + max_kdev_count = min_kdev_count;
3482 + write_unlock_bh(&ip6ip6_kernel_lock);
3483 + manage_kernel_tnls(NULL);
3484 + return min_kdev_count;
3488 + * ip6ip6_tnl_dec_min_kdev_count() - decrease min kernel dev cache size
3489 + * @n: size decrement
3491 + * Decrease the lower limit for the number of kernel devices allowed in the
3492 + * cache at any on time.
3496 +ip6ip6_tnl_dec_min_kdev_count(unsigned int n)
3498 + write_lock_bh(&ip6ip6_kernel_lock);
3499 + min_kdev_count -= min(min_kdev_count, n);
3500 + write_unlock_bh(&ip6ip6_kernel_lock);
3501 + manage_kernel_tnls(NULL);
3502 + return min_kdev_count;
3506 + * ip6ip6_tnl_locate - find or create tunnel matching given parameters
3507 + * @p: tunnel parameters
3508 + * @create: != 0 if allowed to create new tunnel if no match found
3511 + * ip6ip6_tnl_locate() first tries to locate an existing tunnel
3512 + * based on @parms. If this is unsuccessful, but @create is set a new
3513 + * tunnel device is created and registered for use.
3516 + * 0 if tunnel located or created,
3517 + * -EINVAL if parameters incorrect,
3518 + * -ENODEV if no matching tunnel available
3521 +int ip6ip6_tnl_locate(struct ip6_tnl_parm *p, struct ip6_tnl **pt, int create)
3523 + struct in6_addr *remote = &p->raddr;
3524 + struct in6_addr *local = &p->laddr;
3525 + struct ip6_tnl *t;
3527 + if (p->proto != IPPROTO_IPV6)
3530 + for (t = *ip6ip6_bucket(p); t; t = t->next) {
3531 + if (!ipv6_addr_cmp(local, &t->parms.laddr) &&
3532 + !ipv6_addr_cmp(remote, &t->parms.raddr)) {
3534 + return (create ? -EEXIST : 0);
3537 + return ip6ip6_tnl_create(p, pt);
3541 + * ip6ip6_tnl_dev_destructor - tunnel device destructor
3542 + * @dev: the device to be destroyed
3546 +ip6ip6_tnl_dev_destructor(struct net_device *dev)
3548 + if (dev != &ip6ip6_fb_tnl_dev) {
3549 + MOD_DEC_USE_COUNT;
3554 + * ip6ip6_tnl_dev_uninit - tunnel device uninitializer
3555 + * @dev: the device to be destroyed
3558 + * ip6ip6_tnl_dev_uninit() removes tunnel from its list
3562 +ip6ip6_tnl_dev_uninit(struct net_device *dev)
3564 + struct ip6_tnl *t = (struct ip6_tnl *) dev->priv;
3566 + if (dev == &ip6ip6_fb_tnl_dev) {
3567 + write_lock_bh(&ip6ip6_lock);
3568 + tnls_wc[0] = NULL;
3569 + write_unlock_bh(&ip6ip6_lock);
3571 + ip6ip6_tnl_unlink(t);
3573 + sock_release(t->sock);
3578 + * parse_tvl_tnl_enc_lim - handle encapsulation limit option
3579 + * @skb: received socket buffer
3582 + * 0 if none was found,
3583 + * else index to encapsulation limit
3587 +parse_tlv_tnl_enc_lim(struct sk_buff *skb, __u8 * raw)
3589 + struct ipv6hdr *ipv6h = (struct ipv6hdr *) raw;
3590 + __u8 nexthdr = ipv6h->nexthdr;
3591 + __u16 off = sizeof (*ipv6h);
3593 + while (ipv6_ext_hdr(nexthdr) && nexthdr != NEXTHDR_NONE) {
3595 + struct ipv6_opt_hdr *hdr;
3596 + if (raw + off + sizeof (*hdr) > skb->data &&
3597 + !pskb_may_pull(skb, raw - skb->data + off + sizeof (*hdr)))
3600 + hdr = (struct ipv6_opt_hdr *) (raw + off);
3601 + if (nexthdr == NEXTHDR_FRAGMENT) {
3602 + struct frag_hdr *frag_hdr = (struct frag_hdr *) hdr;
3603 + if (frag_hdr->frag_off)
3606 + } else if (nexthdr == NEXTHDR_AUTH) {
3607 + optlen = (hdr->hdrlen + 2) << 2;
3609 + optlen = ipv6_optlen(hdr);
3611 + if (nexthdr == NEXTHDR_DEST) {
3612 + __u16 i = off + 2;
3614 + struct ipv6_tlv_tnl_enc_lim *tel;
3616 + /* No more room for encapsulation limit */
3617 + if (i + sizeof (*tel) > off + optlen)
3620 + tel = (struct ipv6_tlv_tnl_enc_lim *) &raw[i];
3621 + /* return index of option if found and valid */
3622 + if (tel->type == IPV6_TLV_TNL_ENCAP_LIMIT &&
3625 + /* else jump to next option */
3627 + i += tel->length + 2;
3632 + nexthdr = hdr->nexthdr;
3639 + * ip6ip6_err - tunnel error handler
3642 + * ip6ip6_err() should handle errors in the tunnel according
3643 + * to the specifications in RFC 2473.
3646 +void ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
3647 + int type, int code, int offset, __u32 info)
3649 + struct ipv6hdr *ipv6h = (struct ipv6hdr *) skb->data;
3650 + struct ip6_tnl *t;
3652 + int rel_type = ICMPV6_DEST_UNREACH;
3653 + int rel_code = ICMPV6_ADDR_UNREACH;
3654 + __u32 rel_info = 0;
3657 + /* If the packet doesn't contain the original IPv6 header we are
3658 + in trouble since we might need the source address for furter
3659 + processing of the error. */
3661 + read_lock(&ip6ip6_lock);
3662 + if ((t = ip6ip6_tnl_lookup(&ipv6h->daddr, &ipv6h->saddr)) == NULL)
3667 + struct ipv6_tlv_tnl_enc_lim *tel;
3669 + case ICMPV6_DEST_UNREACH:
3670 + if (net_ratelimit())
3671 + printk(KERN_WARNING
3672 + "%s: Path to destination invalid "
3673 + "or inactive!\n", t->parms.name);
3676 + case ICMPV6_TIME_EXCEED:
3677 + if (code == ICMPV6_EXC_HOPLIMIT) {
3678 + if (net_ratelimit())
3679 + printk(KERN_WARNING
3680 + "%s: Too small hop limit or "
3681 + "routing loop in tunnel!\n",
3686 + case ICMPV6_PARAMPROB:
3687 + /* ignore if parameter problem not caused by a tunnel
3688 + encapsulation limit sub-option */
3689 + if (code != ICMPV6_HDR_FIELD) {
3692 + teli = parse_tlv_tnl_enc_lim(skb, skb->data);
3694 + if (teli && teli == ntohl(info) - 2) {
3695 + tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->data[teli];
3696 + if (tel->encap_limit == 0) {
3697 + if (net_ratelimit())
3698 + printk(KERN_WARNING
3699 + "%s: Too small encapsulation "
3700 + "limit or routing loop in "
3701 + "tunnel!\n", t->parms.name);
3706 + case ICMPV6_PKT_TOOBIG:
3707 + mtu = ntohl(info) - offset;
3708 + if (mtu < IPV6_MIN_MTU)
3709 + mtu = IPV6_MIN_MTU;
3710 + t->dev->mtu = mtu;
3712 + if ((len = sizeof (*ipv6h) + ipv6h->payload_len) > mtu) {
3713 + rel_type = ICMPV6_PKT_TOOBIG;
3720 + if (rel_msg && pskb_may_pull(skb, offset + sizeof (*ipv6h))) {
3721 + struct rt6_info *rt;
3722 + struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
3726 + dst_release(skb2->dst);
3728 + skb_pull(skb2, offset);
3729 + skb2->nh.raw = skb2->data;
3731 + /* Try to guess incoming interface */
3732 + rt = rt6_lookup(&skb2->nh.ipv6h->saddr, NULL, 0, 0);
3734 + if (rt && rt->rt6i_dev)
3735 + skb2->dev = rt->rt6i_dev;
3737 + icmpv6_send(skb2, rel_type, rel_code, rel_info, skb2->dev);
3740 + dst_release(&rt->u.dst);
3745 + read_unlock(&ip6ip6_lock);
3749 + * call_hooks - call ipv6 tunnel hooks
3750 + * @hooknum: hook number, either %IP6_TNL_PRE_ENCAP, or
3751 + * %IP6_TNL_PRE_DECAP
3752 + * @t: the current tunnel
3753 + * @skb: the tunneled packet
3756 + * Pass packet to all the hook functions until %IP6_TNL_DROP
3759 + * %IP6_TNL_ACCEPT or %IP6_TNL_DROP
3763 +call_hooks(unsigned int hooknum, struct ip6_tnl *t, struct sk_buff *skb)
3765 + struct ip6_tnl_hook_ops *h;
3766 + int accept = IP6_TNL_ACCEPT;
3768 + if (hooknum < IP6_TNL_MAXHOOKS) {
3769 + struct list_head *i;
3770 + read_lock(&ip6ip6_hook_lock);
3771 + for (i = hooks[hooknum].next; i != &hooks[hooknum]; i = i->next) {
3772 + h = (struct ip6_tnl_hook_ops *) i;
3775 + accept = h->hook(t, skb);
3777 + if (accept != IP6_TNL_ACCEPT)
3781 + read_unlock(&ip6ip6_hook_lock);
3787 + * ip6ip6_rcv - decapsulate IPv6 packet and retransmit it locally
3788 + * @skb: received socket buffer
3793 +int ip6ip6_rcv(struct sk_buff *skb)
3795 + struct ipv6hdr *ipv6h;
3796 + struct ip6_tnl *t;
3798 + if (!pskb_may_pull(skb, sizeof (*ipv6h)))
3801 + ipv6h = skb->nh.ipv6h;
3803 + read_lock(&ip6ip6_lock);
3805 + if ((t = ip6ip6_tnl_lookup(&ipv6h->saddr, &ipv6h->daddr)) != NULL) {
3806 + if (!(t->parms.flags & IP6_TNL_F_CAP_RCV) ||
3807 + call_hooks(IP6_TNL_PRE_DECAP, t, skb) != IP6_TNL_ACCEPT) {
3808 + t->stat.rx_dropped++;
3809 + read_unlock(&ip6ip6_lock);
3812 + skb->mac.raw = skb->nh.raw;
3813 + skb->nh.raw = skb->data;
3814 + skb->protocol = htons(ETH_P_IPV6);
3815 + skb->pkt_type = PACKET_HOST;
3816 + memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
3817 + skb->dev = t->dev;
3818 + dst_release(skb->dst);
3820 + t->stat.rx_packets++;
3821 + t->stat.rx_bytes += skb->len;
3823 + read_unlock(&ip6ip6_lock);
3826 + read_unlock(&ip6ip6_lock);
3827 + icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, skb->dev);
3833 +static inline struct ipv6_txoptions *create_tel(__u8 encap_limit)
3835 + struct ipv6_tlv_tnl_enc_lim *tel;
3836 + struct ipv6_txoptions *opt;
3839 + int opt_len = sizeof(*opt) + IPV6_TLV_TEL_DST_SIZE;
3841 + if (!(opt = kmalloc(opt_len, GFP_ATOMIC))) {
3844 + memset(opt, 0, opt_len);
3845 + opt->tot_len = opt_len;
3846 + opt->dst0opt = (struct ipv6_opt_hdr *) (opt + 1);
3847 + opt->opt_nflen = 8;
3849 + tel = (struct ipv6_tlv_tnl_enc_lim *) (opt->dst0opt + 1);
3850 + tel->type = IPV6_TLV_TNL_ENCAP_LIMIT;
3852 + tel->encap_limit = encap_limit;
3854 + raw = (__u8 *) opt->dst0opt;
3855 + raw[5] = IPV6_TLV_PADN;
3862 +ip6ip6_getfrag(const void *data, struct in6_addr *addr,
3863 + char *buff, unsigned int offset, unsigned int len)
3865 + memcpy(buff, data + offset, len);
3870 + * ip6ip6_tnl_addr_conflict - compare packet addresses to tunnel's own
3871 + * @t: the outgoing tunnel device
3872 + * @hdr: IPv6 header from the incoming packet
3875 + * Avoid trivial tunneling loop by checking that tunnel exit-point
3876 + * doesn't match source of incoming packet.
3884 +ip6ip6_tnl_addr_conflict(struct ip6_tnl *t, struct ipv6hdr *hdr)
3886 + return !ipv6_addr_cmp(&t->parms.raddr, &hdr->saddr);
3890 + * ip6ip6_tnl_xmit - encapsulate packet and send
3891 + * @skb: the outgoing socket buffer
3892 + * @dev: the outgoing tunnel device
3895 + * Build new header and do some sanity checks on the packet before sending
3896 + * it to ip6_build_xmit().
3902 +int ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
3904 + struct ip6_tnl *t = (struct ip6_tnl *) dev->priv;
3905 + struct net_device_stats *stats = &t->stat;
3906 + struct ipv6hdr *ipv6h = skb->nh.ipv6h;
3907 + struct ipv6_txoptions *opt = NULL;
3908 + int encap_limit = -1;
3912 + struct dst_entry *dst;
3913 + struct sock *sk = t->sock->sk;
3914 + struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
3917 + if (t->recursion++) {
3918 + stats->collisions++;
3921 + if (skb->protocol != htons(ETH_P_IPV6) ||
3922 + !(t->parms.flags & IP6_TNL_F_CAP_XMIT) ||
3923 + ip6ip6_tnl_addr_conflict(t, ipv6h)) {
3926 + if ((offset = parse_tlv_tnl_enc_lim(skb, skb->nh.raw)) > 0) {
3927 + struct ipv6_tlv_tnl_enc_lim *tel;
3928 + tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->nh.raw[offset];
3929 + if (tel->encap_limit == 0) {
3930 + icmpv6_send(skb, ICMPV6_PARAMPROB,
3931 + ICMPV6_HDR_FIELD, offset + 2, skb->dev);
3934 + encap_limit = tel->encap_limit - 1;
3935 + } else if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) {
3936 + encap_limit = t->parms.encap_limit;
3938 + if (call_hooks(IP6_TNL_PRE_ENCAP, t, skb) != IP6_TNL_ACCEPT)
3940 + memcpy(&fl, &t->fl, sizeof (fl));
3942 + if ((t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS))
3943 + fl.fl6_flowlabel |= (*(__u32 *) ipv6h & IPV6_TCLASS_MASK);
3944 + if ((t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL))
3945 + fl.fl6_flowlabel |= (*(__u32 *) ipv6h & IPV6_FLOWLABEL_MASK);
3947 + if (encap_limit >= 0 && (opt = create_tel(encap_limit)) == NULL)
3950 + dst = __sk_dst_check(sk, np->dst_cookie);
3953 + if (np->daddr_cache == NULL ||
3954 + ipv6_addr_cmp(fl.fl6_dst, np->daddr_cache) ||
3955 +#ifdef CONFIG_IPV6_SUBTREES
3956 + np->saddr_cache == NULL ||
3957 + ipv6_addr_cmp(fl.fl6_src, np->saddr_cache) ||
3959 + (fl.oif && fl.oif != dst->dev->ifindex)) {
3965 + if (dst == NULL) {
3966 + dst = ip6_route_output(sk, &fl);
3968 + stats->tx_carrier_errors++;
3969 + dst_link_failure(skb);
3970 + goto tx_err_dst_release;
3972 + /* local routing loop */
3973 + if (dst->dev == dev) {
3974 + stats->collisions++;
3975 + if (net_ratelimit())
3976 + printk(KERN_WARNING
3977 + "%s: Local routing loop detected!\n",
3979 + goto tx_err_dst_release;
3982 + mtu = dst->pmtu - sizeof (*ipv6h);
3984 + mtu -= (opt->opt_nflen + opt->opt_flen);
3986 + if (mtu < IPV6_MIN_MTU)
3987 + mtu = IPV6_MIN_MTU;
3988 + if (skb->dst && mtu < skb->dst->pmtu) {
3989 + struct rt6_info *rt = (struct rt6_info *) skb->dst;
3990 + rt->rt6i_flags |= RTF_MODIFIED;
3991 + rt->u.dst.pmtu = mtu;
3993 + if (skb->len > mtu) {
3994 + icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev);
3995 + goto tx_err_dst_release;
3997 + ip6_dst_store(sk, dst, &np->daddr, &np->saddr);
3998 + err = ip6_build_xmit(sk, ip6ip6_getfrag, (void *) skb->nh.raw,
3999 + &fl, skb->len, opt, t->parms.hop_limit,
4002 + if (err == NET_XMIT_SUCCESS || err == NET_XMIT_CN) {
4003 + stats->tx_bytes += skb->len;
4004 + stats->tx_packets++;
4006 + stats->tx_errors++;
4007 + stats->tx_aborted_errors++;
4014 +tx_err_dst_release:
4019 + stats->tx_errors++;
4021 + stats->tx_dropped++;
4027 +static void ip6_tnl_set_cap(struct ip6_tnl *t)
4029 + struct ip6_tnl_parm *p = &t->parms;
4030 + struct in6_addr *laddr = &p->laddr;
4031 + struct in6_addr *raddr = &p->raddr;
4032 + int ltype = ipv6_addr_type(laddr);
4033 + int rtype = ipv6_addr_type(raddr);
4035 + p->flags &= ~(IP6_TNL_F_CAP_XMIT|IP6_TNL_F_CAP_RCV);
4037 + if (ltype != IPV6_ADDR_ANY && rtype != IPV6_ADDR_ANY &&
4039 + (IPV6_ADDR_UNICAST|
4040 + IPV6_ADDR_LOOPBACK|IPV6_ADDR_LINKLOCAL|
4041 + IPV6_ADDR_MAPPED|IPV6_ADDR_RESERVED)) == IPV6_ADDR_UNICAST) {
4042 + struct net_device *ldev = NULL;
4047 + ldev = dev_get_by_index(p->link);
4049 + if ((ltype&IPV6_ADDR_UNICAST) && !ipv6_chk_addr(laddr, ldev))
4052 + if ((rtype&IPV6_ADDR_UNICAST) && ipv6_chk_addr(raddr, NULL))
4055 + if (l_ok && r_ok) {
4056 + if (ltype&IPV6_ADDR_UNICAST)
4057 + p->flags |= IP6_TNL_F_CAP_XMIT;
4058 + if (rtype&IPV6_ADDR_UNICAST)
4059 + p->flags |= IP6_TNL_F_CAP_RCV;
4066 +static void ip6ip6_tnl_link_config(struct ip6_tnl *t)
4068 + struct net_device *dev = t->dev;
4069 + struct ip6_tnl_parm *p = &t->parms;
4070 + struct flowi *fl = &t->fl;
4072 + /* Set up flowi template */
4073 + fl->fl6_src = &p->laddr;
4074 + fl->fl6_dst = &p->raddr;
4075 + fl->oif = p->link;
4076 + fl->fl6_flowlabel = 0;
4078 + if (!(p->flags&IP6_TNL_F_USE_ORIG_TCLASS))
4079 + fl->fl6_flowlabel |= IPV6_TCLASS_MASK & htonl(p->flowinfo);
4080 + if (!(p->flags&IP6_TNL_F_USE_ORIG_FLOWLABEL))
4081 + fl->fl6_flowlabel |= IPV6_FLOWLABEL_MASK & htonl(p->flowinfo);
4083 + ip6_tnl_set_cap(t);
4085 + if (p->flags&IP6_TNL_F_CAP_XMIT && p->flags&IP6_TNL_F_CAP_RCV)
4086 + dev->flags |= IFF_POINTOPOINT;
4088 + dev->flags &= ~IFF_POINTOPOINT;
4090 + if (p->flags & IP6_TNL_F_CAP_XMIT) {
4091 + struct rt6_info *rt = rt6_lookup(&p->raddr, &p->laddr,
4097 + if (rt->rt6i_dev) {
4098 + dev->iflink = rt->rt6i_dev->ifindex;
4100 + dev->hard_header_len = rt->rt6i_dev->hard_header_len +
4101 + sizeof (struct ipv6hdr);
4103 + dev->mtu = rt->rt6i_dev->mtu - sizeof (struct ipv6hdr);
4105 + if (dev->mtu < IPV6_MIN_MTU)
4106 + dev->mtu = IPV6_MIN_MTU;
4108 + dst_release(&rt->u.dst);
4113 + * __ip6ip6_tnl_change - update the tunnel parameters
4114 + * @t: tunnel to be changed
4115 + * @p: tunnel configuration parameters
4118 + * __ip6ip6_tnl_change() updates the tunnel parameters
4122 +__ip6ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p)
4124 + ipv6_addr_copy(&t->parms.laddr, &p->laddr);
4125 + ipv6_addr_copy(&t->parms.raddr, &p->raddr);
4126 + t->parms.flags = p->flags;
4127 + t->parms.hop_limit = p->hop_limit;
4128 + t->parms.encap_limit = p->encap_limit;
4129 + t->parms.flowinfo = p->flowinfo;
4130 + ip6ip6_tnl_link_config(t);
4133 +void ip6ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p)
4135 + ip6ip6_tnl_unlink(t);
4136 + __ip6ip6_tnl_change(t, p);
4137 + ip6ip6_tnl_link(t);
4141 + * ip6ip6_kernel_tnl_add - configure and add kernel tunnel to hash
4142 + * @p: kernel tunnel configuration parameters
4145 + * ip6ip6_kernel_tnl_add() fetches an unused kernel tunnel configures
4146 + * it according to @p and places it among the active tunnels.
4149 + * number of references to tunnel on success,
4150 + * %-EEXIST if there is already a device matching description
4151 + * %-EINVAL if p->flags doesn't have %IP6_TNL_F_KERNEL_DEV raised,
4152 + * %-ENODEV if there are no unused kernel tunnels available
4155 + * The code for creating, opening, closing and destroying network devices
4156 + * must be called from process context, while the Mobile IP code, which
4157 + * needs the tunnel devices, unfortunately runs in interrupt context.
4159 + * The devices must be created and opened in advance, then placed in a
4160 + * list where the kernel can fetch and ready them for use at a later time.
4165 +ip6ip6_kernel_tnl_add(struct ip6_tnl_parm *p)
4167 + struct ip6_tnl *t;
4169 + if (!(p->flags & IP6_TNL_F_KERNEL_DEV))
4171 + if ((t = ip6ip6_tnl_lookup(&p->raddr, &p->laddr)) != NULL &&
4172 + t != &ip6ip6_fb_tnl) {
4173 + /* Handle duplicate tunnels by incrementing
4174 + reference count */
4175 + atomic_inc(&t->refcnt);
4178 + if ((t = ip6ip6_kernel_tnl_unlink()) == NULL)
4180 + __ip6ip6_tnl_change(t, p);
4182 + atomic_inc(&t->refcnt);
4184 + ip6ip6_tnl_link(t);
4186 + manage_kernel_tnls(NULL);
4188 + return atomic_read(&t->refcnt);
4192 + * ip6ip6_kernel_tnl_del - delete no longer needed kernel tunnel
4193 + * @t: kernel tunnel to be removed from hash
4196 + * ip6ip6_kernel_tnl_del() removes and deconfigures the tunnel @t
4197 + * and places it among the unused kernel devices.
4200 + * number of references on success,
4201 + * %-EINVAL if p->flags doesn't have %IP6_TNL_F_KERNEL_DEV raised,
4204 + * See the comments on ip6ip6_kernel_tnl_add() for more information.
4208 +ip6ip6_kernel_tnl_del(struct ip6_tnl *t)
4213 + if (!(t->parms.flags & IP6_TNL_F_KERNEL_DEV))
4216 + if (atomic_dec_and_test(&t->refcnt)) {
4217 + struct ip6_tnl_parm p;
4218 + ip6ip6_tnl_unlink(t);
4219 + memset(&p, 0, sizeof (p));
4220 + p.flags = IP6_TNL_F_KERNEL_DEV;
4222 + __ip6ip6_tnl_change(t, &p);
4224 + ip6ip6_kernel_tnl_link(t);
4226 + manage_kernel_tnls(NULL);
4228 + return atomic_read(&t->refcnt);
4232 + * ip6ip6_tnl_ioctl - configure ipv6 tunnels from userspace
4233 + * @dev: virtual device associated with tunnel
4234 + * @ifr: parameters passed from userspace
4235 + * @cmd: command to be performed
4238 + * ip6ip6_tnl_ioctl() is used for managing IPv6 tunnels
4241 + * The possible commands are the following:
4242 + * %SIOCGETTUNNEL: get tunnel parameters for device
4243 + * %SIOCADDTUNNEL: add tunnel matching given tunnel parameters
4244 + * %SIOCCHGTUNNEL: change tunnel parameters to those given
4245 + * %SIOCDELTUNNEL: delete tunnel
4247 + * The fallback device "ip6tnl0", created during module
4248 + * initialization, can be used for creating other tunnel devices.
4252 + * %-EFAULT if unable to copy data to or from userspace,
4253 + * %-EPERM if current process hasn't %CAP_NET_ADMIN set or attempting
4254 + * to configure kernel devices from userspace,
4255 + * %-EINVAL if passed tunnel parameters are invalid,
4256 + * %-EEXIST if changing a tunnel's parameters would cause a conflict
4257 + * %-ENODEV if attempting to change or delete a nonexisting device
4260 + * See the comments on ip6ip6_kernel_tnl_add() for more information
4261 + * about kernel tunnels.
4265 +ip6ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
4269 + struct ip6_tnl_parm p;
4270 + struct ip6_tnl *t = NULL;
4272 + MOD_INC_USE_COUNT;
4275 + case SIOCGETTUNNEL:
4276 + if (dev == &ip6ip6_fb_tnl_dev) {
4277 + if (copy_from_user(&p,
4278 + ifr->ifr_ifru.ifru_data,
4283 + if ((err = ip6ip6_tnl_locate(&p, &t, 0)) == -ENODEV)
4284 + t = (struct ip6_tnl *) dev->priv;
4288 + t = (struct ip6_tnl *) dev->priv;
4290 + memcpy(&p, &t->parms, sizeof (p));
4291 + if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof (p))) {
4295 + case SIOCADDTUNNEL:
4296 + case SIOCCHGTUNNEL:
4298 + create = (cmd == SIOCADDTUNNEL);
4299 + if (!capable(CAP_NET_ADMIN))
4301 + if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p))) {
4305 + if (p.flags & IP6_TNL_F_KERNEL_DEV) {
4308 + if (!create && dev != &ip6ip6_fb_tnl_dev) {
4309 + t = (struct ip6_tnl *) dev->priv;
4311 + if (!t && (err = ip6ip6_tnl_locate(&p, &t, create))) {
4314 + if (cmd == SIOCCHGTUNNEL) {
4315 + if (t->dev != dev) {
4319 + if (t->parms.flags & IP6_TNL_F_KERNEL_DEV) {
4323 + ip6ip6_tnl_change(t, &p);
4324 + netdev_state_change(dev);
4326 + if (copy_to_user(ifr->ifr_ifru.ifru_data,
4327 + &t->parms, sizeof (p))) {
4333 + case SIOCDELTUNNEL:
4335 + if (!capable(CAP_NET_ADMIN))
4338 + if (dev == &ip6ip6_fb_tnl_dev) {
4339 + if (copy_from_user(&p, ifr->ifr_ifru.ifru_data,
4344 + err = ip6ip6_tnl_locate(&p, &t, 0);
4347 + if (t == &ip6ip6_fb_tnl) {
4352 + t = (struct ip6_tnl *) dev->priv;
4354 + if (t->parms.flags & IP6_TNL_F_KERNEL_DEV)
4357 + err = unregister_netdevice(t->dev);
4362 + MOD_DEC_USE_COUNT;
4367 + * ip6ip6_tnl_get_stats - return the stats for tunnel device
4368 + * @dev: virtual device associated with tunnel
4370 + * Return: stats for device
4373 +static struct net_device_stats *
4374 +ip6ip6_tnl_get_stats(struct net_device *dev)
4376 + return &(((struct ip6_tnl *) dev->priv)->stat);
4380 + * ip6ip6_tnl_change_mtu - change mtu manually for tunnel device
4381 + * @dev: virtual device associated with tunnel
4382 + * @new_mtu: the new mtu
4386 + * %-EINVAL if mtu too small
4390 +ip6ip6_tnl_change_mtu(struct net_device *dev, int new_mtu)
4392 + if (new_mtu < IPV6_MIN_MTU) {
4395 + dev->mtu = new_mtu;
4400 + * ip6ip6_tnl_dev_init_gen - general initializer for all tunnel devices
4401 + * @dev: virtual device associated with tunnel
4404 + * Set function pointers and initialize the &struct flowi template used
4409 +ip6ip6_tnl_dev_init_gen(struct net_device *dev)
4411 + struct ip6_tnl *t = (struct ip6_tnl *) dev->priv;
4412 + struct flowi *fl = &t->fl;
4416 + if ((err = sock_create(PF_INET6, SOCK_RAW, IPPROTO_IPV6, &t->sock))) {
4418 + "Failed to create IPv6 tunnel socket (err %d).\n", err);
4421 + t->sock->inode->i_uid = 0;
4422 + t->sock->inode->i_gid = 0;
4425 + sk->allocation = GFP_ATOMIC;
4426 + sk->net_pinfo.af_inet6.hop_limit = 254;
4427 + sk->net_pinfo.af_inet6.mc_loop = 0;
4428 + sk->prot->unhash(sk);
4430 + memset(fl, 0, sizeof (*fl));
4431 + fl->proto = IPPROTO_IPV6;
4433 + dev->destructor = ip6ip6_tnl_dev_destructor;
4434 + dev->uninit = ip6ip6_tnl_dev_uninit;
4435 + dev->hard_start_xmit = ip6ip6_tnl_xmit;
4436 + dev->get_stats = ip6ip6_tnl_get_stats;
4437 + dev->do_ioctl = ip6ip6_tnl_ioctl;
4438 + dev->change_mtu = ip6ip6_tnl_change_mtu;
4440 + dev->type = ARPHRD_TUNNEL6;
4441 + dev->hard_header_len = LL_MAX_HEADER + sizeof (struct ipv6hdr);
4442 + dev->mtu = ETH_DATA_LEN - sizeof (struct ipv6hdr);
4443 + dev->flags |= IFF_NOARP;
4445 + /* Hmm... MAX_ADDR_LEN is 8, so the ipv6 addresses can't be
4446 + copied to dev->dev_addr and dev->broadcast, like the ipv4
4447 + addresses were in ipip.c, ip_gre.c and sit.c. */
4448 + dev->addr_len = 0;
4453 + * ip6ip6_tnl_dev_init - initializer for all non fallback tunnel devices
4454 + * @dev: virtual device associated with tunnel
4458 +ip6ip6_tnl_dev_init(struct net_device *dev)
4460 + struct ip6_tnl *t = (struct ip6_tnl *) dev->priv;
4461 + ip6ip6_tnl_dev_init_gen(dev);
4462 + ip6ip6_tnl_link_config(t);
4469 + * ip6ip6_fb_tnl_open - function called when fallback device opened
4470 + * @dev: fallback device
4476 +ip6ip6_fb_tnl_open(struct net_device *dev)
4478 + MOD_INC_USE_COUNT;
4483 + * ip6ip6_fb_tnl_close - function called when fallback device closed
4484 + * @dev: fallback device
4490 +ip6ip6_fb_tnl_close(struct net_device *dev)
4492 + MOD_DEC_USE_COUNT;
4498 + * ip6ip6_fb_tnl_dev_init - initializer for fallback tunnel device
4499 + * @dev: fallback device
4505 +ip6ip6_fb_tnl_dev_init(struct net_device *dev)
4507 + ip6ip6_tnl_dev_init_gen(dev);
4509 + dev->open = ip6ip6_fb_tnl_open;
4510 + dev->stop = ip6ip6_fb_tnl_close;
4513 + tnls_wc[0] = &ip6ip6_fb_tnl;
4518 + * ip6ip6_tnl_register_hook - add hook for processing of tunneled packets
4519 + * @reg: hook function and its parameters
4522 + * Add a netfilter like hook function for special handling of tunneled
4523 + * packets. The hook functions are called before encapsulation
4524 + * (%IP6_TNL_PRE_ENCAP) and before decapsulation
4525 + * (%IP6_TNL_PRE_DECAP). The possible return values by the hook
4526 + * functions are %IP6_TNL_DROP, %IP6_TNL_ACCEPT and
4527 + * %IP6_TNL_STOLEN (in case the hook function took care of the packet
4528 + * and it doesn't have to be processed any further).
4532 +ip6ip6_tnl_register_hook(struct ip6_tnl_hook_ops *reg)
4534 + if (reg->hooknum < IP6_TNL_MAXHOOKS) {
4535 + struct list_head *i;
4537 + write_lock_bh(&ip6ip6_hook_lock);
4538 + for (i = hooks[reg->hooknum].next;
4539 + i != &hooks[reg->hooknum]; i = i->next) {
4540 + if (reg->priority <
4541 + ((struct ip6_tnl_hook_ops *) i)->priority) {
4545 + list_add(®->list, i->prev);
4546 + write_unlock_bh(&ip6ip6_hook_lock);
4551 + * ip6ip6_tnl_unregister_hook - remove tunnel hook
4552 + * @reg: hook function and its parameters
4556 +ip6ip6_tnl_unregister_hook(struct ip6_tnl_hook_ops *reg)
4558 + if (reg->hooknum < IP6_TNL_MAXHOOKS) {
4559 + write_lock_bh(&ip6ip6_hook_lock);
4560 + list_del(®->list);
4561 + write_unlock_bh(&ip6ip6_hook_lock);
4566 +/* the IPv6 over IPv6 protocol structure */
4567 +static struct inet6_protocol ip6ip6_protocol = {
4568 + ip6ip6_rcv, /* IPv6 handler */
4569 + ip6ip6_err, /* IPv6 error control */
4571 + IPPROTO_IPV6, /* protocol ID */
4574 + "IPv6 over IPv6" /* name */
4578 + * ip6_tunnel_init - register protocol and reserve needed resources
4580 + * Return: 0 on success
4583 +int __init ip6_tunnel_init(void)
4587 + ip6ip6_fb_tnl_dev.priv = (void *) &ip6ip6_fb_tnl;
4589 + for (i = 0; i < IP6_TNL_MAXHOOKS; i++) {
4590 + INIT_LIST_HEAD(&hooks[i]);
4592 + if ((err = register_netdev(&ip6ip6_fb_tnl_dev)))
4595 + inet6_add_protocol(&ip6ip6_protocol);
4600 + * ip6_tunnel_cleanup - free resources and unregister protocol
4603 +void ip6_tunnel_cleanup(void)
4605 + write_lock_bh(&ip6ip6_kernel_lock);
4607 + write_unlock_bh(&ip6ip6_kernel_lock);
4608 + flush_scheduled_tasks();
4609 + manage_kernel_tnls(NULL);
4610 + inet6_del_protocol(&ip6ip6_protocol);
4611 + unregister_netdev(&ip6ip6_fb_tnl_dev);
4615 +module_init(ip6_tunnel_init);
4616 +module_exit(ip6_tunnel_cleanup);
4619 +#if defined(CONFIG_IPV6_MOBILITY_HA_MODULE) || defined(CONFIG_IPV6_MOBILITY_MN_MODULE)
4620 +EXPORT_SYMBOL(ip6ip6_tnl_register_hook);
4621 +EXPORT_SYMBOL(ip6ip6_tnl_unregister_hook);
4623 +#ifdef CONFIG_IPV6_MOBILITY_HA_MODULE
4624 +EXPORT_SYMBOL(ip6ip6_tnl_dec_max_kdev_count);
4625 +EXPORT_SYMBOL(ip6ip6_tnl_inc_max_kdev_count);
4626 +EXPORT_SYMBOL(ip6ip6_tnl_dec_min_kdev_count);
4627 +EXPORT_SYMBOL(ip6ip6_tnl_inc_min_kdev_count);
4628 +EXPORT_SYMBOL(ip6ip6_kernel_tnl_add);
4629 +EXPORT_SYMBOL(ip6ip6_kernel_tnl_del);
4630 +EXPORT_SYMBOL(ip6ip6_tnl_lookup);
4632 +#ifdef CONFIG_IPV6_MOBILITY_MN_MODULE
4633 +EXPORT_SYMBOL(ip6ip6_tnl_create);
4634 +EXPORT_SYMBOL(ip6ip6_tnl_change);
4637 diff -uprN linux-2.4.25.old/net/ipv6/mipglue.c linux-2.4.25/net/ipv6/mipglue.c
4638 --- linux-2.4.25.old/net/ipv6/mipglue.c 1970-01-01 01:00:00.000000000 +0100
4639 +++ linux-2.4.25/net/ipv6/mipglue.c 2004-06-26 11:29:30.000000000 +0100
4642 + * Glue for Mobility support integration to IPv6
4645 + * Antti Tuominen <ajtuomin@cc.hut.fi>
4649 + * This program is free software; you can redistribute it and/or
4650 + * modify it under the terms of the GNU General Public License
4651 + * as published by the Free Software Foundation; either version
4652 + * 2 of the License, or (at your option) any later version.
4656 +#include <linux/sched.h>
4658 +#include <net/ipv6.h>
4659 +#include <net/addrconf.h>
4660 +#include <net/neighbour.h>
4661 +#include <net/mipglue.h>
4663 +extern int ip6_tlvopt_unknown(struct sk_buff *skb, int optoff);
4665 +/* Initialize all zero */
4666 +struct mipv6_callable_functions mipv6_functions = { NULL };
4668 +/* Sets mipv6_functions struct to zero to invalidate all successive
4669 + * calls to mipv6 functions. Used on module unload. */
4671 +void mipv6_invalidate_calls(void)
4673 + memset(&mipv6_functions, 0, sizeof(mipv6_functions));
4677 +/* Selects correct handler for tlv encoded destination option. Called
4678 + * by ip6_parse_tlv. Checks if mipv6 calls are valid before calling. */
4680 +int mipv6_handle_dstopt(struct sk_buff *skb, int optoff)
4684 + switch (skb->nh.raw[optoff]) {
4685 + case MIPV6_TLV_HOMEADDR:
4686 + ret = MIPV6_CALLFUNC(mipv6_handle_homeaddr, 0)(skb, optoff);
4689 + /* Should never happen */
4690 + printk(KERN_ERR __FILE__ ": Invalid destination option code (%d)\n",
4691 + skb->nh.raw[optoff]);
4696 + /* If mipv6 handlers are not valid, pass the packet to
4697 + * ip6_tlvopt_unknown() for correct handling. */
4699 + return ip6_tlvopt_unknown(skb, optoff);
4704 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/Config.in linux-2.4.25/net/ipv6/mobile_ip6/Config.in
4705 --- linux-2.4.25.old/net/ipv6/mobile_ip6/Config.in 1970-01-01 01:00:00.000000000 +0100
4706 +++ linux-2.4.25/net/ipv6/mobile_ip6/Config.in 2004-06-26 11:29:30.000000000 +0100
4709 +# Mobile IPv6 Configuration
4711 +dep_tristate ' IPv6: Mobility Support (Correspondent Node)' CONFIG_IPV6_MOBILITY $CONFIG_IPV6
4712 +if [ "$CONFIG_IPV6_IPV6_TUNNEL" != "n" ]; then
4713 + dep_tristate ' MIPv6: Mobile Node Support' CONFIG_IPV6_MOBILITY_MN $CONFIG_IPV6_MOBILITY
4715 + dep_tristate ' MIPv6: Home Agent Support' CONFIG_IPV6_MOBILITY_HA $CONFIG_IPV6_MOBILITY
4717 +if [ "$CONFIG_IPV6_MOBILITY" != "n" ]; then
4718 + bool ' MIPv6: Debug messages' CONFIG_IPV6_MOBILITY_DEBUG
4720 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/Makefile linux-2.4.25/net/ipv6/mobile_ip6/Makefile
4721 --- linux-2.4.25.old/net/ipv6/mobile_ip6/Makefile 1970-01-01 01:00:00.000000000 +0100
4722 +++ linux-2.4.25/net/ipv6/mobile_ip6/Makefile 2004-06-26 11:29:30.000000000 +0100
4725 +# Makefile for the MIPL Mobile IPv6 for Linux.
4727 +# Note! Dependencies are done automagically by 'make dep', which also
4728 +# removes any old dependencies. DON'T put your own dependencies here
4729 +# unless it's something special (ie not a .c file).
4733 +O_TARGET := mip6_base.o
4735 +list-multi := mip6_ha.o mip6_mn.o
4737 +obj-y := hashlist.o bcache.o mobhdr_common.o stats.o exthdrs.o \
4738 + rr_crypto.o hmac.o auth_opt.o mipv6_icmp.o module_cn.o
4740 +obj-m := $(O_TARGET)
4742 +mip6_ha-objs := halist.o mipv6_icmp_ha.o tunnel_ha.o \
4743 + ndisc_ha.o ha.o module_ha.o
4745 +mip6_mn-objs := mipv6_icmp_mn.o ioctl_mn.o tunnel_mn.o \
4746 + mdetect.o bul.o multiaccess_ctl.o mobhdr_mn.o mn.o \
4749 +obj-$(CONFIG_IPV6_MOBILITY_HA) += mip6_ha.o
4750 +obj-$(CONFIG_IPV6_MOBILITY_MN) += mip6_mn.o
4752 +include $(TOPDIR)/Rules.make
4754 +mip6_ha.o: $(mip6_ha-objs)
4755 + $(LD) -r -o $@ $(mip6_ha-objs)
4757 +mip6_mn.o: $(mip6_mn-objs)
4758 + $(LD) -r -o $@ $(mip6_mn-objs)
4759 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/README linux-2.4.25/net/ipv6/mobile_ip6/README
4760 --- linux-2.4.25.old/net/ipv6/mobile_ip6/README 1970-01-01 01:00:00.000000000 +0100
4761 +++ linux-2.4.25/net/ipv6/mobile_ip6/README 2004-06-26 11:29:30.000000000 +0100
4763 +MIPL Mobile IPv6 for Linux
4765 +More information at http://www.mipl.mediapoli.com/.
4767 +To join MIPL Mobile IPv6 for Linux mailing lists go to:
4769 + http://www.mipl.mediapoli.com/cgi-bin/mailman/listinfo
4771 +Or send mail with subject "subscribe" for the general list to:
4773 + mipl-request@list.mipl.mediapoli.com
4775 +or for the developer list to:
4777 + mipl-devel-request@list.mail.mediapoli.com
4778 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/auth_opt.c linux-2.4.25/net/ipv6/mobile_ip6/auth_opt.c
4779 --- linux-2.4.25.old/net/ipv6/mobile_ip6/auth_opt.c 1970-01-01 01:00:00.000000000 +0100
4780 +++ linux-2.4.25/net/ipv6/mobile_ip6/auth_opt.c 2004-06-26 11:29:30.000000000 +0100
4783 + * MIPv6 Binding Authentication Data Option functions
4786 + * Henrik Petander <lpetande@tml.hut.fi>
4790 + * This program is free software; you can redistribute it and/or
4791 + * modify it under the terms of the GNU General Public License
4792 + * as published by the Free Software Foundation; either version
4793 + * 2 of the License, or (at your option) any later version.
4796 +#include <linux/autoconf.h>
4797 +#include <linux/icmpv6.h>
4798 +#include <net/mipv6.h>
4802 +#include "mobhdr.h"
4806 +int mipv6_auth_build(struct in6_addr *cn_addr, struct in6_addr *coa,
4807 + __u8 *mh, __u8 *aud_data, __u8 *k_bu)
4809 + /* First look up the peer from sadb based on his address */
4810 + struct ah_processing ahp;
4812 + /* Don't add any other options or this system is screwed */
4814 + __u8 buf[MAX_HASH_LENGTH];
4818 + DEBUG(DBG_ERROR, "k_bu missing, aborting");
4821 + DEBUG(DBG_KEY, "Key for building authenticator:");
4822 + debug_print_buffer(DBG_KEY, k_bu, HMAC_SHA1_KEY_SIZE);
4824 + if (ah_hmac_sha1_init(&ahp, k_bu, HMAC_SHA1_KEY_SIZE) < 0) {
4825 + DEBUG(DBG_ERROR, "Failed to initialize hmac sha1");
4829 + DEBUG(DBG_KEY, "coa: ");
4830 + debug_print_buffer(DBG_KEY, coa, 16);
4831 + DEBUG(DBG_KEY, "cn_addr: ");
4832 + debug_print_buffer(DBG_KEY, cn_addr, 16);
4833 + DEBUG(DBG_KEY, "MH contents: ");
4834 + debug_print_buffer(DBG_KEY, mh, aud_data - mh);
4836 + /* First the common part */
4837 + ah_hmac_sha1_loop(&ahp, coa, sizeof(struct in6_addr));
4838 + ah_hmac_sha1_loop(&ahp, cn_addr, sizeof(struct in6_addr));
4839 + ah_hmac_sha1_loop(&ahp, mh, aud_data - mh);
4840 + ah_hmac_sha1_result(&ahp, buf);
4842 + memcpy(aud_data, buf, MIPV6_RR_MAC_LENGTH);
4847 +int mipv6_auth_check(struct in6_addr *cn_addr, struct in6_addr *coa,
4848 + __u8 *opt, __u8 optlen,
4849 + struct mipv6_mo_bauth_data *aud, __u8 *k_bu)
4852 + struct ah_processing ahp;
4853 + __u8 htarget[MAX_HASH_LENGTH];
4855 + /* Look up peer by home address */
4857 + DEBUG(DBG_ERROR, "k_bu missing, aborting");
4861 + DEBUG(DBG_KEY, "Key for checking authenticator:");
4862 + debug_print_buffer(DBG_KEY, k_bu, HMAC_SHA1_KEY_SIZE);
4864 + if (!aud || !coa) {
4865 + DEBUG(DBG_INFO, "%s is NULL", aud ? "coa" : "aud");
4869 + if (aud->length != MIPV6_RR_MAC_LENGTH) {
4871 + ": Incorrect authentication option length %d", aud->length);
4875 + if (ah_hmac_sha1_init(&ahp, k_bu, HMAC_SHA1_KEY_SIZE) < 0) {
4877 + "internal error in initialization of authentication algorithm");
4880 + DEBUG(DBG_KEY, "coa: ");
4881 + debug_print_buffer(DBG_KEY, coa, 16);
4882 + DEBUG(DBG_KEY, "cn_addr: ");
4883 + debug_print_buffer(DBG_KEY, cn_addr, 16);
4884 + DEBUG(DBG_KEY, "MH contents: ");
4885 + debug_print_buffer(DBG_KEY, opt, (u8*) aud->data - opt);
4887 + ah_hmac_sha1_loop(&ahp, coa, sizeof(struct in6_addr));
4888 + ah_hmac_sha1_loop(&ahp, cn_addr, sizeof(struct in6_addr));
4891 + * Process MH + options till the start of the authenticator in
4892 + * Auth. data option
4894 + ah_hmac_sha1_loop(&ahp, opt, (u8 *)aud->data - opt);
4895 + ah_hmac_sha1_result(&ahp, htarget);
4896 + if (memcmp(htarget, aud->data, MIPV6_RR_MAC_LENGTH) == 0)
4899 + DEBUG(DBG_ERROR, "returning %d", ret);
4903 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/bcache.c linux-2.4.25/net/ipv6/mobile_ip6/bcache.c
4904 --- linux-2.4.25.old/net/ipv6/mobile_ip6/bcache.c 1970-01-01 01:00:00.000000000 +0100
4905 +++ linux-2.4.25/net/ipv6/mobile_ip6/bcache.c 2004-06-26 11:29:30.000000000 +0100
4911 + * Juha Mynttinen <jmynttin@cc.hut.fi>
4915 + * This program is free software; you can redistribute it and/or
4916 + * modify it under the terms of the GNU General Public License
4917 + * as published by the Free Software Foundation; either version
4918 + * 2 of the License, or (at your option) any later version.
4924 + * Nanno Langstraat : Timer code cleaned up, active socket
4928 +#include <linux/autoconf.h>
4929 +#include <linux/sched.h>
4930 +#include <linux/timer.h>
4931 +#include <linux/in6.h>
4932 +#include <linux/init.h>
4933 +#include <linux/spinlock.h>
4934 +#include <linux/proc_fs.h>
4935 +#include <linux/ipv6_route.h>
4936 +#include <net/ipv6.h>
4937 +#include <net/addrconf.h>
4938 +#include <net/tcp.h>
4939 +#include <net/udp.h>
4940 +#include <net/ip6_route.h>
4941 +#include <net/mipv6.h>
4943 +#include "bcache.h"
4944 +#include "hashlist.h"
4946 +#include "mobhdr.h"
4947 +#include "tunnel.h"
4948 +#include "config.h"
4950 +#define TIMERDELAY HZ/10
4952 +struct mipv6_bcache {
4953 + struct hashlist *entries;
4955 + struct timer_list callback_timer;
4958 +struct in6_addr_pair {
4959 + struct in6_addr *a1;
4960 + struct in6_addr *a2;
4963 +static rwlock_t bcache_lock = RW_LOCK_UNLOCKED;
4965 +static struct mipv6_bcache bcache;
4967 +static int bcache_proc_info(char *buffer, char **start, off_t offset,
4970 +#define MIPV6_BCACHE_HASHSIZE 32
4972 +/* Moment of transmission of a BR, in seconds before bcache entry expiry */
4973 +#define BCACHE_BR_SEND_LEAD 3
4975 +#define MIPV6_MAX_BRR 3 /* Send 3 BRRs before deleting BC entry */
4976 +#define MIPV6_BRR_RATE HZ /* Send BRRs once per second */
4979 + * Internal functions.
4982 +struct cache_entry_iterator_args {
4983 + struct mipv6_bce **entry;
4986 +static int find_first_cache_entry_iterator(void *data, void *args,
4987 + unsigned long *lifetime)
4989 + struct mipv6_bce *entry =
4990 + (struct mipv6_bce *) data;
4991 + struct cache_entry_iterator_args *state =
4992 + (struct cache_entry_iterator_args *) args;
4994 + ASSERT(entry != NULL);
4996 + if (entry->type == CACHE_ENTRY) {
4997 + *(state->entry) = entry;
4998 + return ITERATOR_STOP; /* stop iteration */
5000 + return ITERATOR_CONT; /* continue iteration */
5006 + * Get memory for a new bcache entry. If bcache is full, a cache
5007 + * entry may be deleted to get space for a home registration, but not
5010 +static struct mipv6_bce *mipv6_bce_alloc(__u8 type)
5012 + struct mipv6_bce *entry;
5013 + struct cache_entry_iterator_args args;
5017 + entry = (struct mipv6_bce *)
5018 + hashlist_alloc(bcache.entries, SLAB_ATOMIC);
5020 + /* Cache replacement policy: always replace the CACHE_ENTRY
5021 + closest to expiration. Type HOME_REGISTRATION entry may
5022 + never be deleted before expiration. */
5023 + if (entry == NULL) {
5024 + /* cache full, try to delete a CACHE_ENTRY */
5025 + args.entry = &entry;
5026 + hashlist_iterate(bcache.entries, &args,
5027 + find_first_cache_entry_iterator);
5028 + if (entry == NULL)
5030 + hashlist_delete(bcache.entries,
5031 + (struct hashlist_entry *)entry);
5032 + entry = (struct mipv6_bce *)
5033 + hashlist_alloc(bcache.entries, SLAB_ATOMIC);
5039 + * Frees entry's memory allocated with mipv6_bce_alloc
5041 +static void mipv6_bce_free(struct mipv6_bce *entry)
5043 + hashlist_free(bcache.entries, (void *) entry);
5047 + * Removes all expired entries
5049 +static void expire(void)
5051 + struct mipv6_bce *entry;
5053 + struct in6_addr daddr;
5054 + struct in6_addr saddr;
5055 + struct br_addrs *next;
5057 + struct br_addrs *br_info = NULL;
5061 + write_lock(&bcache_lock);
5063 + while ((entry = (struct mipv6_bce *)
5064 + hashlist_get_first(bcache.entries)) != NULL) {
5065 + struct rt6_info *rt;
5066 + if (time_after_eq(jiffies, entry->callback_time)) {
5068 + DEBUG(DBG_INFO, "an entry expired");
5070 + if (entry->type & HOME_REGISTRATION) {
5071 + mip6_fn.proxy_del(&entry->home_addr, entry);
5073 + hashlist_delete(bcache.entries, (void *)entry);
5074 + mipv6_bce_free(entry);
5076 + } else if (entry->br_callback_time != 0 &&
5077 + time_after_eq(jiffies, entry->br_callback_time) &&
5078 + entry->br_count < MIPV6_MAX_BRR &&
5079 + (rt = rt6_lookup(&entry->home_addr, &entry->our_addr, 0, 0)) != NULL){
5080 + /* Do we have a destination cache entry for the home address */
5081 + if (rt->rt6i_flags & RTF_CACHE) {
5082 + struct br_addrs *tmp;
5085 + "bcache entry recently used. Sending BR.");
5086 + /* queue for sending */
5087 + br_info = kmalloc(sizeof(struct br_addrs),
5090 + ipv6_addr_copy(&br_info->saddr,
5091 + &entry->our_addr);
5092 + ipv6_addr_copy(&br_info->daddr,
5093 + &entry->home_addr);
5094 + br_info->next = tmp;
5095 + entry->last_br = jiffies;
5096 + entry->br_callback_time = jiffies + MIPV6_BRR_RATE;
5097 + entry->br_count++;
5100 + DEBUG(DBG_ERROR, "Out of memory");
5104 + entry->br_callback_time = 0;
5105 + dst_release(&rt->u.dst);
5107 + entry->br_callback_time = 0;
5111 + write_unlock(&bcache_lock);
5114 + struct br_addrs *tmp = br_info->next;
5115 + if (mipv6_send_brr(&br_info->saddr, &br_info->daddr, NULL) < 0)
5116 + DEBUG(DBG_WARNING,
5117 + "BR send for %x:%x:%x:%x:%x:%x:%x:%x failed",
5118 + NIPV6ADDR(&br_info->daddr));
5124 +static void set_timer(void)
5126 + struct mipv6_bce *entry;
5127 + unsigned long callback_time;
5131 + entry = (struct mipv6_bce *)
5132 + hashlist_get_first(bcache.entries);
5133 + if (entry != NULL) {
5134 + if (entry->br_callback_time > 0 &&
5135 + time_after(entry->br_callback_time, jiffies))
5136 + callback_time = entry->br_callback_time;
5137 + else if (time_after(entry->callback_time, jiffies))
5138 + callback_time = entry->callback_time;
5140 + DEBUG(DBG_WARNING,
5141 + "bcache timer attempted to schedule"
5142 + " for a historical jiffies count!");
5143 + callback_time = jiffies + TIMERDELAY;
5146 + DEBUG(DBG_INFO, "setting timer to now");
5147 + mod_timer(&bcache.callback_timer, callback_time);
5149 + del_timer(&bcache.callback_timer);
5150 + DEBUG(DBG_INFO, "BC empty, not setting a new timer");
5155 + * The function that is scheduled to do the callback functions. May be
5156 + * modified e.g to allow Binding Requests, now only calls expire() and
5157 + * schedules a new timer.
5159 +static void timer_handler(unsigned long dummy)
5162 + write_lock(&bcache_lock);
5164 + write_unlock(&bcache_lock);
5168 + * Interface functions visible to other modules
5172 + * mipv6_bcache_add - add Binding Cache entry
5173 + * @ifindex: interface index
5174 + * @our_addr: own address
5175 + * @home_addr_org: MN's home address
5176 + * @coa: MN's care-of address
5177 + * @lifetime: lifetime for this binding
5178 + * @prefix: prefix length
5179 + * @seq: sequence number
5180 + * @flags: flags received in BU
5181 + * @type: type of entry
5183 + * Adds an entry for this @home_addr_org in the Binding Cache. If entry
5184 + * already exists, old entry is updated. @type may be %CACHE_ENTRY or
5185 + * %HOME_REGISTRATION.
5187 +int mipv6_bcache_add(int ifindex,
5188 + struct in6_addr *our_addr,
5189 + struct in6_addr *home_addr,
5190 + struct in6_addr *coa,
5191 + __u32 lifetime, __u16 seq, __u8 flags, __u8 type)
5193 + struct mipv6_bce *entry;
5195 + int create_tunnel = 0;
5196 + unsigned long now = jiffies;
5197 + struct in6_addr_pair hashkey;
5202 + hashkey.a1 = home_addr;
5203 + hashkey.a2 = our_addr;
5205 + write_lock(&bcache_lock);
5207 + if (type == HOME_REGISTRATION && !(mip6node_cnf.capabilities&CAP_HA))
5210 + if (unlikely(bcache.entries == NULL)) {
5215 + if ((entry = (struct mipv6_bce *)
5216 + hashlist_get(bcache.entries, &hashkey)) != NULL) {
5217 + /* if an entry for this home_addr exists (with smaller
5218 + * seq than the new seq), update it by removing it
5221 + if (!MIPV6_SEQ_GT(seq, entry->seq)) {
5222 + DEBUG(DBG_INFO, "smaller seq than existing, not updating");
5225 + DEBUG(DBG_INFO, "updating an existing entry");
5228 + /* H-flag is already checked in BU handler. */
5229 + /* XXX: Should we care about the other flags?*/
5230 + if (flags != entry->flags) {
5231 + DEBUG(DBG_INFO, "entry/BU flag mismatch");
5234 + if (type == HOME_REGISTRATION) {
5235 + create_tunnel = (ipv6_addr_cmp(&entry->coa, coa) ||
5236 + entry->ifindex != ifindex);
5239 + /* no entry for this home_addr, try to create a new entry */
5240 + DEBUG(DBG_INFO, "creating a new entry");
5243 + entry = mipv6_bce_alloc(type);
5244 + if (entry == NULL) {
5245 + DEBUG(DBG_INFO, "cache full, entry not added");
5249 + create_tunnel = (type == HOME_REGISTRATION);
5252 + if (create_tunnel) {
5254 + mip6_fn.proxy_del(&entry->home_addr, entry);
5255 + if (mip6_fn.proxy_create(flags, ifindex, coa, our_addr, home_addr) < 0) {
5260 + ipv6_addr_copy(&(entry->our_addr), our_addr);
5261 + ipv6_addr_copy(&(entry->home_addr), home_addr);
5262 + ipv6_addr_copy(&(entry->coa), coa);
5263 + entry->ifindex = ifindex;
5265 + entry->type = type;
5266 + entry->flags = flags;
5268 + entry->last_br = 0;
5269 + entry->destunr_count = 0;
5270 + entry->callback_time = now + lifetime * HZ;
5271 + if (entry->type & HOME_REGISTRATION)
5272 + entry->br_callback_time = 0;
5274 + entry->br_callback_time = now +
5275 + (lifetime - BCACHE_BR_SEND_LEAD) * HZ;
5278 + DEBUG(DBG_INFO, "updating entry : %x", entry);
5279 + hashlist_reposition(bcache.entries, (void *)entry,
5280 + entry->callback_time);
5282 + DEBUG(DBG_INFO, "adding entry: %x", entry);
5283 + if ((hashlist_add(bcache.entries,
5285 + entry->callback_time, entry)) < 0) {
5287 + DEBUG(DBG_ERROR, "Hash add failed");
5288 + goto err_hashlist;
5295 + write_unlock(&bcache_lock);
5299 + if (create_tunnel) {
5300 + mip6_fn.proxy_del(home_addr, entry);
5304 + hashlist_delete(bcache.entries, (void *)entry);
5306 + mipv6_bce_free(entry);
5308 + write_unlock(&bcache_lock);
5312 +int mipv6_bcache_icmp_err(struct in6_addr *home_addr,
5313 + struct in6_addr *our_addr,
5314 + int destunr_count)
5316 + struct mipv6_bce *entry;
5317 + struct in6_addr_pair hashkey;
5319 + int ret = -ENOENT;
5323 + hashkey.a1 = home_addr;
5324 + hashkey.a2 = our_addr;
5326 + write_lock(&bcache_lock);
5327 + if (unlikely(bcache.entries == NULL)) {
5332 + if ((entry = (struct mipv6_bce *)
5333 + hashlist_get(bcache.entries, &hashkey)) != NULL) {
5334 + entry->last_destunr = jiffies;
5335 + entry->destunr_count = destunr_count;
5339 + write_unlock(&bcache_lock);
5345 + * mipv6_bcache_delete - delete Binding Cache entry
5346 + * @home_addr: MN's home address
5347 + * @our_addr: our address
5348 + * @type: type of entry
5350 + * Deletes an entry associated with @home_addr from Binding Cache.
5351 + * Valid values for @type are %CACHE_ENTRY, %HOME_REGISTRATION and
5352 + * %ANY_ENTRY. %ANY_ENTRY deletes any type of entry.
5354 +int mipv6_bcache_delete(struct in6_addr *home_addr,
5355 + struct in6_addr *our_addr, __u8 type)
5357 + struct mipv6_bce *entry;
5358 + struct in6_addr_pair hashkey;
5363 + if (home_addr == NULL || our_addr == NULL) {
5364 + DEBUG(DBG_INFO, "error in arguments");
5368 + hashkey.a1 = home_addr;
5369 + hashkey.a2 = our_addr;
5371 + write_lock(&bcache_lock);
5373 + if (unlikely(bcache.entries == NULL) ||
5374 + (entry = (struct mipv6_bce *)
5375 + hashlist_get(bcache.entries, &hashkey)) == NULL ||
5376 + !(entry->type & type)) {
5377 + DEBUG(DBG_INFO, "No matching entry found");
5382 + hashlist_delete(bcache.entries, (void *) entry);
5383 + mipv6_bce_free(entry);
5387 + write_unlock(&bcache_lock);
5392 + * mipv6_bcache_exists - check if entry exists
5393 + * @home_addr: home address to check
5394 + * @our_addr: our address
5396 + * Determines if a binding exists for @home_addr. Returns type of the
5397 + * entry or negative if entry does not exist.
5399 +int mipv6_bcache_exists(struct in6_addr *home_addr,
5400 + struct in6_addr *our_addr)
5402 + struct mipv6_bce *entry;
5403 + struct in6_addr_pair hashkey;
5404 + int type = -ENOENT;
5408 + if (home_addr == NULL || our_addr == NULL)
5411 + hashkey.a1 = home_addr;
5412 + hashkey.a2 = our_addr;
5414 + read_lock(&bcache_lock);
5415 + if (likely(bcache.entries != NULL) &&
5416 + (entry = (struct mipv6_bce *)
5417 + hashlist_get(bcache.entries, &hashkey)) != NULL) {
5418 + type = entry->type;
5420 + read_unlock(&bcache_lock);
5426 + * mipv6_bcache_get - get entry from Binding Cache
5427 + * @home_addr: home address to search
5428 + * @our_addr: our address
5429 + * @entry: pointer to buffer
5431 + * Gets a copy of Binding Cache entry for @home_addr. If entry
5432 + * exists entry is copied to @entry and zero is returned.
5433 + * Otherwise returns negative.
5435 +int mipv6_bcache_get(struct in6_addr *home_addr,
5436 + struct in6_addr *our_addr,
5437 + struct mipv6_bce *entry)
5439 + struct mipv6_bce *entry2;
5440 + struct in6_addr_pair hashkey;
5441 + int ret = -ENOENT;
5445 + if (home_addr == NULL || our_addr == NULL || entry == NULL)
5448 + hashkey.a1 = home_addr;
5449 + hashkey.a2 = our_addr;
5451 + read_lock_bh(&bcache_lock);
5453 + entry2 = (struct mipv6_bce *)
5454 + hashlist_get(bcache.entries, &hashkey);
5455 + if (entry2 != NULL) {
5456 + memcpy(entry, entry2, sizeof(struct mipv6_bce));
5459 + read_unlock_bh(&bcache_lock);
5463 +int mipv6_bcache_iterate(hashlist_iterator_t func, void *args)
5467 + read_lock_bh(&bcache_lock);
5468 + ret = hashlist_iterate(bcache.entries, args, func);
5469 + read_unlock_bh(&bcache_lock);
5475 + * Proc-filesystem functions
5478 +#define BC_INFO_LEN 80
5480 +struct procinfo_iterator_args {
5488 +static int procinfo_iterator(void *data, void *args, unsigned long *pref)
5490 + struct procinfo_iterator_args *arg =
5491 + (struct procinfo_iterator_args *) args;
5492 + struct mipv6_bce *entry =
5493 + (struct mipv6_bce *) data;
5495 + ASSERT(entry != NULL);
5497 + if (arg->skip < arg->offset / BC_INFO_LEN) {
5499 + return ITERATOR_CONT;
5502 + if (arg->len >= arg->length)
5503 + return ITERATOR_CONT;
5505 + /* HoA CoA CallbackInSecs Type */
5506 + arg->len += sprintf(arg->buffer + arg->len,
5507 + "%08x%08x%08x%08x %08x%08x%08x%08x %010lu %02d\n",
5508 + ntohl(entry->home_addr.s6_addr32[0]),
5509 + ntohl(entry->home_addr.s6_addr32[1]),
5510 + ntohl(entry->home_addr.s6_addr32[2]),
5511 + ntohl(entry->home_addr.s6_addr32[3]),
5512 + ntohl(entry->coa.s6_addr32[0]),
5513 + ntohl(entry->coa.s6_addr32[1]),
5514 + ntohl(entry->coa.s6_addr32[2]),
5515 + ntohl(entry->coa.s6_addr32[3]),
5516 + ((entry->callback_time) - jiffies) / HZ,
5517 + (int) entry->type);
5519 + return ITERATOR_CONT;
5523 + * Callback function for proc filesystem.
5525 +static int bcache_proc_info(char *buffer, char **start, off_t offset,
5528 + struct procinfo_iterator_args args;
5532 + args.buffer = buffer;
5533 + args.offset = offset;
5534 + args.length = length;
5538 + read_lock_bh(&bcache_lock);
5539 + hashlist_iterate(bcache.entries, &args, procinfo_iterator);
5540 + read_unlock_bh(&bcache_lock);
5544 + *start += offset % BC_INFO_LEN;
5546 + args.len -= offset % BC_INFO_LEN;
5548 + if (args.len > length)
5549 + args.len = length;
5556 +static int bcache_compare(void *data, void *hashkey)
5558 + struct in6_addr_pair *p = (struct in6_addr_pair *) hashkey;
5559 + struct mipv6_bce *e = (struct mipv6_bce *) data;
5561 + if (ipv6_addr_cmp(&e->home_addr, p->a1) == 0
5562 + && ipv6_addr_cmp(&e->our_addr, p->a2) == 0)
5568 +static __u32 bcache_hash(void *hashkey)
5570 + struct in6_addr_pair *p = (struct in6_addr_pair *) hashkey;
5572 + return p->a1->s6_addr32[0] ^ p->a1->s6_addr32[1] ^
5573 + p->a2->s6_addr32[2] ^ p->a2->s6_addr32[3];
5577 + * Initialization and shutdown functions
5580 +int __init mipv6_bcache_init(__u32 size)
5583 + DEBUG(DBG_ERROR, "Binding cache size must be at least 1");
5586 + bcache.entries = hashlist_create(MIPV6_BCACHE_HASHSIZE, size,
5587 + sizeof(struct mipv6_bce),
5588 + "mip6_bcache", NULL, NULL,
5589 + bcache_compare, bcache_hash);
5591 + if (bcache.entries == NULL) {
5592 + DEBUG(DBG_ERROR, "Failed to initialize hashlist");
5596 + init_timer(&bcache.callback_timer);
5597 + bcache.callback_timer.data = 0;
5598 + bcache.callback_timer.function = timer_handler;
5599 + bcache.size = size;
5601 + proc_net_create("mip6_bcache", 0, bcache_proc_info);
5603 + DEBUG(DBG_INFO, "Binding cache initialized");
5608 +bce_cleanup_iterator(void *rawentry, void *args, unsigned long *sortkey)
5610 + int type = (int) args;
5611 + struct mipv6_bce *entry = (struct mipv6_bce *) rawentry;
5612 + if (entry->type == type) {
5613 + if (entry->type & HOME_REGISTRATION) {
5614 + if (unlikely(mip6_fn.proxy_del == NULL))
5615 + DEBUG(DBG_ERROR, "proxy_del unitialized");
5617 + mip6_fn.proxy_del(&entry->home_addr, entry);
5619 + return ITERATOR_DELETE_ENTRY;
5621 + return ITERATOR_CONT;
5625 +void mipv6_bcache_cleanup(int type)
5627 + write_lock_bh(&bcache_lock);
5628 + hashlist_iterate(bcache.entries,(void *) type, bce_cleanup_iterator);
5629 + write_unlock_bh(&bcache_lock);
5632 +int __exit mipv6_bcache_exit(void)
5634 + struct hashlist *entries;
5638 + proc_net_remove("mip6_bcache");
5640 + write_lock_bh(&bcache_lock);
5641 + DEBUG(DBG_INFO, "Stopping the bcache timer");
5642 + del_timer(&bcache.callback_timer);
5643 + hashlist_iterate(bcache.entries,(void *)CACHE_ENTRY,
5644 + bce_cleanup_iterator);
5646 + entries = bcache.entries;
5647 + bcache.entries = NULL;
5648 + write_unlock_bh(&bcache_lock);
5650 + hashlist_destroy(entries);
5653 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/bcache.h linux-2.4.25/net/ipv6/mobile_ip6/bcache.h
5654 --- linux-2.4.25.old/net/ipv6/mobile_ip6/bcache.h 1970-01-01 01:00:00.000000000 +0100
5655 +++ linux-2.4.25/net/ipv6/mobile_ip6/bcache.h 2004-06-26 11:29:30.000000000 +0100
5658 + * MIPL Mobile IPv6 Binding Cache header file
5662 + * This program is free software; you can redistribute it and/or
5663 + * modify it under the terms of the GNU General Public License
5664 + * as published by the Free Software Foundation; either version
5665 + * 2 of the License, or (at your option) any later version.
5671 +#include <linux/in6.h>
5672 +#include <linux/timer.h>
5673 +#include "hashlist.h"
5675 +#define CACHE_ENTRY 1 /* this and HOME_REGISTRATION are the entry types */
5676 +#define HOME_REGISTRATION 2
5677 +#define ANY_ENTRY 3
5679 +#define MIPV6_MAX_DESTUNREACH 5 /* Delete CN BCEs after 5 destination unreachables */
5680 +#define MIPV6_DEST_UNR_IVAL 10 /* What is the max interval of destination
5681 + unreacahable error messages for them to be persistent*/
5684 + struct hashlist_entry e;
5685 + int ifindex; /* Interface identifier */
5686 + struct in6_addr our_addr; /* our address (as seen by the MN) */
5687 + struct in6_addr home_addr; /* MN home address */
5688 + struct in6_addr coa; /* MN care-of address */
5689 + unsigned long callback_time; /* time of expiration (in jiffies) */
5690 + unsigned long br_callback_time; /* time for sending a BR (in jiffies) */
5691 + int (*callback_function)(struct mipv6_bce *entry);
5692 + __u8 type; /* home registration */
5693 + __u8 router; /* mn is router */
5694 + __u8 flags; /* flags received in BU */
5695 + __u16 seq; /* sequence number */
5696 + unsigned long last_br; /* time when last BR sent */
5697 + unsigned long last_destunr; /* time when last ICMP destination unreachable received */
5698 + int br_count; /* How many BRRs have sent */
5699 + int destunr_count; /* Number of destination unreachables received */
5702 +int mipv6_bcache_add(int ifindex, struct in6_addr *our_addr,
5703 + struct in6_addr *home_addr, struct in6_addr *coa,
5704 + __u32 lifetime, __u16 seq, __u8 flags, __u8 type);
5706 +int mipv6_bcache_icmp_err(struct in6_addr *home_addr,
5707 + struct in6_addr *our_addr,
5708 + int destunr_count);
5710 +int mipv6_bcache_delete(struct in6_addr *home_addr, struct in6_addr *our_addr,
5713 +int mipv6_bcache_exists(struct in6_addr *home_addr,
5714 + struct in6_addr *our_addr);
5716 +int mipv6_bcache_get(struct in6_addr *home_addr,
5717 + struct in6_addr *our_addr,
5718 + struct mipv6_bce *entry);
5720 +int mipv6_bcache_iterate(int (*func)(void *, void *, unsigned long *), void *args);
5722 +void mipv6_bcache_cleanup(int type);
5724 +int mipv6_bcache_init(__u32 size);
5726 +int mipv6_bcache_exit(void);
5728 +#endif /* _BCACHE_H */
5729 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/bul.c linux-2.4.25/net/ipv6/mobile_ip6/bul.c
5730 --- linux-2.4.25.old/net/ipv6/mobile_ip6/bul.c 1970-01-01 01:00:00.000000000 +0100
5731 +++ linux-2.4.25/net/ipv6/mobile_ip6/bul.c 2004-06-26 11:29:30.000000000 +0100
5734 + * Binding update list
5737 + * Juha Mynttinen <jmynttin@cc.hut.fi>
5741 + * This program is free software; you can redistribute it and/or
5742 + * modify it under the terms of the GNU General Public License
5743 + * as published by the Free Software Foundation; either version
5744 + * 2 of the License, or (at your option) any later version.
5750 + * Nanno Langstraat : Timer code cleaned up
5753 +#include <linux/autoconf.h>
5754 +#include <linux/sched.h>
5755 +#include <linux/timer.h>
5756 +#include <linux/in6.h>
5757 +#include <linux/init.h>
5758 +#include <linux/spinlock.h>
5759 +#include <net/ipv6.h>
5760 +#include <net/mipv6.h>
5761 +#include <linux/proc_fs.h>
5765 +#include "hashlist.h"
5766 +#include "tunnel_mn.h"
5767 +#include "mobhdr.h"
5769 +#define MIPV6_BUL_HASHSIZE 32
5771 +rwlock_t bul_lock = RW_LOCK_UNLOCKED;
5774 + struct hashlist *entries;
5775 + struct timer_list callback_timer;
5778 +static struct mipv6_bul bul;
5780 +struct in6_addr_pair {
5781 + struct in6_addr *a1;
5782 + struct in6_addr *a2;
5785 +/**********************************************************************
5787 + * Private functions
5789 + **********************************************************************/
5791 +static int bul_compare(void *data, void *hashkey)
5793 + struct in6_addr_pair *p = (struct in6_addr_pair *)hashkey;
5794 + struct mipv6_bul_entry *e = (struct mipv6_bul_entry *)data;
5796 + if (ipv6_addr_cmp(&e->cn_addr, p->a1) == 0
5797 + && ipv6_addr_cmp(&e->home_addr, p->a2) == 0)
5804 + struct in6_addr *addr;
5808 +static int bul_compare_cookie(void *data, void *keys)
5810 + struct test_keys *p = (struct test_keys *)keys;
5811 + struct mipv6_bul_entry *e = (struct mipv6_bul_entry *)data;
5813 + if (ipv6_addr_cmp(&e->cn_addr, p->addr) == 0 && e->rr
5814 + && memcmp(&e->rr->cot_cookie, p->cookie, 8) == 0)
5820 +static u32 bul_hash(void *hashkey)
5822 + struct in6_addr_pair *p = (struct in6_addr_pair *)hashkey;
5824 + return p->a1->s6_addr32[0] ^
5825 + p->a1->s6_addr32[1] ^
5826 + p->a1->s6_addr32[2] ^
5827 + p->a1->s6_addr32[3];
5830 +static int bul_proc_info(char *buffer, char **start, off_t offset,
5833 +static struct mipv6_bul_entry *mipv6_bul_get_entry(void)
5836 + return ((struct mipv6_bul_entry *)
5837 + hashlist_alloc(bul.entries, SLAB_ATOMIC));
5840 +static void mipv6_bul_entry_free(struct mipv6_bul_entry *entry)
5845 + if (entry->rr->kbu)
5846 + kfree(entry->rr->kbu);
5850 + kfree(entry->ops);
5851 + hashlist_free(bul.entries, (void *)entry);
5854 +static __inline__ int del_bul_entry_tnl(struct mipv6_bul_entry *entry)
5856 + if (entry->flags & MIPV6_BU_F_HOME) {
5857 + return mipv6_mv_tnl_to_ha(&entry->cn_addr,
5859 + &entry->home_addr);
5864 +static void timer_update(void)
5866 + struct mipv6_bul_entry *entry;
5870 + entry = hashlist_get_first(bul.entries);
5872 + while (entry && time_after_eq(jiffies, entry->callback_time)) {
5873 + if (time_after_eq(jiffies, entry->expire) ||
5874 + entry->callback(entry) != 0) {
5876 + * Either the entry has expired, or the callback
5877 + * indicated that it should be deleted.
5879 + hashlist_delete(bul.entries, (void *)entry);
5881 + del_bul_entry_tnl(entry);
5882 + mipv6_bul_entry_free(entry);
5883 + DEBUG(DBG_INFO, "Entry deleted (was expired) from "
5884 + "binding update list");
5886 + /* move entry to its right place in the hashlist */
5887 + DEBUG(DBG_INFO, "Rescheduling");
5888 + hashlist_reposition(bul.entries, (void *)entry,
5889 + entry->callback_time);
5891 + entry = (struct mipv6_bul_entry *)
5892 + hashlist_get_first(bul.entries);
5895 + if (entry == NULL) {
5896 + DEBUG(DBG_INFO, "bul empty, not setting a new timer");
5897 + del_timer(&bul.callback_timer);
5899 + mod_timer(&bul.callback_timer, entry->callback_time);
5903 +static void timer_handler(unsigned long dummy)
5907 + write_lock(&bul_lock);
5909 + write_unlock(&bul_lock);
5912 +/**********************************************************************
5914 + * Public interface functions
5916 + **********************************************************************/
5919 + * mipv6_bul_iterate - apply interator function to all entries
5920 + * @func: function to apply
5921 + * @args: extra arguments for iterator
5923 + * Applies @func for each entry in Binding Update List. Extra
5924 + * arguments given in @args are also passed to the iterator function.
5925 + * Caller must hold @bul_lock.
5927 +int mipv6_bul_iterate(hashlist_iterator_t func, void *args)
5931 + return hashlist_iterate(bul.entries, args, func);
5935 + * mipv6_bul_exists - check if Binding Update List entry exists
5936 + * @cn: address to check
5938 + * Checks if Binding Update List has an entry for @cn. Returns true
5939 + * if entry exists, false otherwise. Caller may not hold @bul_lock.
5941 +int mipv6_bul_exists(struct in6_addr *cn, struct in6_addr *haddr)
5944 + struct in6_addr_pair hashkey;
5949 + hashkey.a2 = haddr;
5951 + read_lock_bh(&bul_lock);
5953 + if (unlikely(bul.entries == NULL))
5956 + exists = (hashlist_get(bul.entries, &hashkey) != NULL);
5958 + read_unlock_bh(&bul_lock);
5963 + * mipv6_bul_get - get Binding Update List entry
5964 + * @cn_addr: CN address to search
5965 + * @home_addr: home address to search
5967 + * Returns Binding Update List entry for @cn_addr if it exists.
5968 + * Otherwise returns %NULL. Caller must hold @bul_lock.
5970 +struct mipv6_bul_entry *mipv6_bul_get(struct in6_addr *cn_addr,
5971 + struct in6_addr *home_addr)
5973 + struct mipv6_bul_entry *entry;
5974 + struct in6_addr_pair hashkey;
5978 + if (unlikely(bul.entries == NULL)) {
5981 + hashkey.a1 = cn_addr;
5982 + hashkey.a2 = home_addr;
5984 + entry = (struct mipv6_bul_entry *)
5985 + hashlist_get(bul.entries, &hashkey);
5990 +struct mipv6_bul_entry *mipv6_bul_get_by_ccookie(
5991 + struct in6_addr *cn_addr, u8 *cookie)
5993 + struct test_keys key;
5997 + if (unlikely(bul.entries == NULL))
5999 + key.addr = cn_addr;
6000 + key.cookie = cookie;
6002 + return (struct mipv6_bul_entry *)
6003 + hashlist_get_ex(bul.entries, &key,
6004 + bul_compare_cookie);
6008 + * mipv6_bul_reschedule - reschedule Binding Update List entry
6009 + * @entry: entry to reschedule
6011 + * Reschedules a Binding Update List entry. Must be called after
6012 + * modifying entry lifetime. Caller must hold @bul_lock (write).
6014 +void mipv6_bul_reschedule(struct mipv6_bul_entry *entry)
6018 + hashlist_reposition(bul.entries,
6020 + entry->callback_time);
6025 + * mipv6_bul_add - add binding update to Binding Update List
6026 + * @cn_addr: IPv6 address where BU was sent
6027 + * @home_addr: Home address for this binding
6028 + * @coa: Care-of address for this binding
6029 + * @lifetime: expiration time of the binding in seconds
6030 + * @seq: sequence number of the BU
6031 + * @flags: %MIPV6_BU_F_* flags
6032 + * @callback: callback function called on expiration
6033 + * @callback_time: expiration time for callback
6034 + * @state: binding send state
6035 + * @delay: retransmission delay
6036 + * @maxdelay: retransmission maximum delay
6037 + * @ops: Mobility header options for BU
6038 + * @rr: Return routability information
6040 + * Adds a binding update sent to @cn_addr for @home_addr to the
6041 + * Binding Update List. If entry already exists, it is updated.
6042 + * Entry is set to expire in @lifetime seconds. Entry has a callback
6043 + * function @callback that is called at @callback_time. Entry @state
6044 + * controls resending of this binding update and it can be set to
6045 + * %ACK_OK, %RESEND_EXP or %ACK_ERROR. Returns a pointer to the newly
6046 + * created or updated entry. Caller must hold @bul_lock (write).
6048 +struct mipv6_bul_entry *mipv6_bul_add(
6049 + struct in6_addr *cn_addr, struct in6_addr *home_addr,
6050 + struct in6_addr *coa,
6051 + __u32 lifetime, __u16 seq, __u8 flags,
6052 + int (*callback)(struct mipv6_bul_entry *entry),
6053 + __u32 callback_time,
6054 + __u8 state, __u32 delay, __u32 maxdelay,
6055 + struct mipv6_mh_opt *ops,
6056 + struct mipv6_rr_info *rr)
6058 + struct mipv6_bul_entry *entry;
6060 + struct in6_addr_pair hashkey;
6064 + if (unlikely(bul.entries == NULL))
6067 + if (cn_addr == NULL || home_addr == NULL || coa == NULL ||
6068 + lifetime < 0 || callback == NULL || callback_time < 0 ||
6069 + (state != ACK_OK && state != RESEND_EXP && state != ACK_ERROR) ||
6070 + delay < 0 || maxdelay < 0) {
6071 + DEBUG(DBG_ERROR, "invalid arguments");
6074 + DEBUG(DBG_INFO, "cn_addr: %x:%x:%x:%x:%x:%x:%x:%x, "
6075 + "home_addr: %x:%x:%x:%x:%x:%x:%x:%x"
6076 + "coaddr: %x:%x:%x:%x:%x:%x:%x:%x", NIPV6ADDR(cn_addr),
6077 + NIPV6ADDR(home_addr), NIPV6ADDR(coa));
6078 + hashkey.a1 = cn_addr;
6079 + hashkey.a2 = home_addr;
6082 + * decide whether to add a new entry or update existing, also
6083 + * check if there's room for a new entry when adding a new
6084 + * entry (latter is handled by mipv6_bul_get_entry()
6086 + if ((entry = (struct mipv6_bul_entry *)
6087 + hashlist_get(bul.entries, &hashkey)) != NULL) {
6088 + /* if an entry for this cn_addr exists (with smaller
6089 + * seq than the new entry's seq), update it */
6091 + if (MIPV6_SEQ_GT(seq, entry->seq)) {
6092 + DEBUG(DBG_INFO, "updating an existing entry");
6095 + DEBUG(DBG_INFO, "smaller seq than existing, not updating");
6099 + entry = mipv6_bul_get_entry();
6100 + if (entry == NULL) {
6101 + DEBUG(DBG_WARNING, "binding update list full, can't add!!!");
6104 + memset(entry, 0, sizeof(*entry));
6105 + /* First BU send happens here, save count in the entry */
6106 + entry->consecutive_sends = 1;
6110 + ipv6_addr_copy(&(entry->cn_addr), cn_addr);
6111 + ipv6_addr_copy(&(entry->home_addr), home_addr);
6114 + /* Add Return Routability info to bul entry */
6121 + ipv6_addr_copy(&(entry->coa), coa);
6122 + entry->lifetime = lifetime;
6124 + entry->expire = jiffies + lifetime * HZ;
6125 + else if (flags & MIPV6_BU_F_ACK)
6126 + entry->expire = jiffies + HOME_RESEND_EXPIRE * HZ;
6128 + entry->flags = flags;
6129 + entry->lastsend = jiffies; /* current time = last use of the entry */
6130 + entry->state = state;
6131 + entry->delay = delay;
6132 + entry->maxdelay = maxdelay;
6133 + entry->callback_time = jiffies + callback_time * HZ;
6134 + entry->callback = callback;
6136 + if (flags & MIPV6_BU_F_HOME &&
6137 + mipv6_mv_tnl_to_ha(cn_addr, coa, home_addr)) {
6138 + DEBUG(DBG_ERROR, "reconfiguration of the tunnel failed");
6141 + DEBUG(DBG_INFO, "updating entry: %x", entry);
6142 + hashlist_reposition(bul.entries, (void *)entry,
6143 + entry->callback_time);
6145 + DEBUG(DBG_INFO, "adding entry: %x", entry);
6147 + hashkey.a1 = &entry->cn_addr;
6148 + hashkey.a2 = &entry->home_addr;
6150 + if ((hashlist_add(bul.entries, &hashkey,
6151 + entry->callback_time,
6153 + DEBUG(DBG_ERROR, "Hash add failed");
6154 + mipv6_bul_entry_free(entry);
6164 + * mipv6_bul_delete - delete Binding Update List entry
6165 + * @cn_addr: address for entry to delete
6167 + * Deletes the entry for @cn_addr from the Binding Update List.
6168 + * Returns zero if entry was deleted succesfully, otherwise returns
6169 + * negative. Caller may not hold @bul_lock.
6171 +int mipv6_bul_delete(struct in6_addr *cn_addr, struct in6_addr *home_addr)
6173 + struct mipv6_bul_entry *entry;
6174 + struct in6_addr_pair hashkey;
6178 + hashkey.a1 = cn_addr;
6179 + hashkey.a2 = home_addr;
6181 + write_lock(&bul_lock);
6183 + if (unlikely(bul.entries == NULL) ||
6184 + (entry = (struct mipv6_bul_entry *)
6185 + hashlist_get(bul.entries, &hashkey)) == NULL) {
6186 + write_unlock(&bul_lock);
6187 + DEBUG(DBG_INFO, "No such entry");
6191 + hashlist_delete(bul.entries, (void *)entry);
6193 + del_bul_entry_tnl(entry);
6195 + mipv6_bul_entry_free(entry);
6197 + write_unlock(&bul_lock);
6199 + DEBUG(DBG_INFO, "Binding update list entry deleted");
6204 +/**********************************************************************
6206 + * Proc interface functions
6208 + **********************************************************************/
6210 +#define BUL_INFO_LEN 152
6212 +struct procinfo_iterator_args {
6220 +static int procinfo_iterator(void *data, void *args,
6221 + unsigned long *sortkey)
6223 + struct procinfo_iterator_args *arg =
6224 + (struct procinfo_iterator_args *)args;
6225 + struct mipv6_bul_entry *entry =
6226 + (struct mipv6_bul_entry *)data;
6227 + unsigned long callback_seconds;
6231 + if (entry == NULL) return ITERATOR_ERR;
6233 + if (time_after(jiffies, entry->callback_time))
6234 + callback_seconds = 0;
6236 + callback_seconds = (entry->callback_time - jiffies) / HZ;
6238 + if (arg->skip < arg->offset / BUL_INFO_LEN) {
6240 + return ITERATOR_CONT;
6243 + if (arg->len >= arg->length)
6244 + return ITERATOR_CONT;
6246 + /* CN HoA CoA ExpInSecs SeqNum State Delay MaxDelay CallbackInSecs */
6247 + arg->len += sprintf(arg->buffer + arg->len,
6248 + "%08x%08x%08x%08x %08x%08x%08x%08x %08x%08x%08x%08x\n"
6249 + "%010lu %05d %02d %010d %010d %010lu\n",
6250 + ntohl(entry->cn_addr.s6_addr32[0]),
6251 + ntohl(entry->cn_addr.s6_addr32[1]),
6252 + ntohl(entry->cn_addr.s6_addr32[2]),
6253 + ntohl(entry->cn_addr.s6_addr32[3]),
6254 + ntohl(entry->home_addr.s6_addr32[0]),
6255 + ntohl(entry->home_addr.s6_addr32[1]),
6256 + ntohl(entry->home_addr.s6_addr32[2]),
6257 + ntohl(entry->home_addr.s6_addr32[3]),
6258 + ntohl(entry->coa.s6_addr32[0]),
6259 + ntohl(entry->coa.s6_addr32[1]),
6260 + ntohl(entry->coa.s6_addr32[2]),
6261 + ntohl(entry->coa.s6_addr32[3]),
6262 + (entry->expire - jiffies) / HZ,
6263 + entry->seq, entry->state, entry->delay,
6264 + entry->maxdelay, callback_seconds);
6266 + return ITERATOR_CONT;
6271 + * Callback function for proc filesystem.
6273 +static int bul_proc_info(char *buffer, char **start, off_t offset,
6276 + struct procinfo_iterator_args args;
6280 + args.buffer = buffer;
6281 + args.offset = offset;
6282 + args.length = length;
6286 + read_lock_bh(&bul_lock);
6287 + hashlist_iterate(bul.entries, &args, procinfo_iterator);
6288 + read_unlock_bh(&bul_lock);
6292 + *start += offset % BUL_INFO_LEN;
6294 + args.len -= offset % BUL_INFO_LEN;
6296 + if (args.len > length)
6297 + args.len = length;
6304 +/**********************************************************************
6306 + * Code module init/fini functions
6308 + **********************************************************************/
6310 +int __init mipv6_bul_init(__u32 size)
6315 + DEBUG(DBG_CRITICAL,
6316 + "Binding update list size must be at least 1");
6319 + bul.entries = hashlist_create(MIPV6_BUL_HASHSIZE, size,
6320 + sizeof(struct mipv6_bul_entry),
6321 + "mip6_bul", NULL, NULL,
6322 + bul_compare, bul_hash);
6324 + if (bul.entries == NULL) {
6325 + DEBUG(DBG_CRITICAL, "Couldn't allocate memory for "
6326 + "hashlist when creating a binding update list");
6329 + init_timer(&bul.callback_timer);
6330 + bul.callback_timer.data = 0;
6331 + bul.callback_timer.function = timer_handler;
6332 + proc_net_create("mip6_bul", 0, bul_proc_info);
6333 + DEBUG(DBG_INFO, "Binding update list initialized");
6337 +void __exit mipv6_bul_exit()
6339 + struct mipv6_bul_entry *entry;
6340 + struct hashlist *entries;
6344 + proc_net_remove("mip6_bul");
6346 + write_lock_bh(&bul_lock);
6348 + DEBUG(DBG_INFO, "Stopping the bul timer");
6349 + del_timer(&bul.callback_timer);
6351 + while ((entry = (struct mipv6_bul_entry *)
6352 + hashlist_get_first(bul.entries)) != NULL) {
6353 + hashlist_delete(bul.entries, (void *)entry);
6355 + del_bul_entry_tnl(entry);
6357 + mipv6_bul_entry_free(entry);
6359 + entries = bul.entries;
6360 + bul.entries = NULL;
6361 + write_unlock_bh(&bul_lock);
6363 + hashlist_destroy(entries);
6365 + DEBUG(DBG_INFO, "binding update list destroyed");
6367 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/bul.h linux-2.4.25/net/ipv6/mobile_ip6/bul.h
6368 --- linux-2.4.25.old/net/ipv6/mobile_ip6/bul.h 1970-01-01 01:00:00.000000000 +0100
6369 +++ linux-2.4.25/net/ipv6/mobile_ip6/bul.h 2004-06-26 11:29:30.000000000 +0100
6372 + * MIPL Mobile IPv6 Binding Update List header file
6376 + * This program is free software; you can redistribute it and/or
6377 + * modify it under the terms of the GNU General Public License
6378 + * as published by the Free Software Foundation; either version
6379 + * 2 of the License, or (at your option) any later version.
6385 +#include "hashlist.h"
6387 +#define ACK_OK 0x01
6388 +#define RESEND_EXP 0x02
6389 +#define ACK_ERROR 0x04
6391 +#define HOME_RESEND_EXPIRE 3600
6392 +#define MIPV6_COOKIE_LEN 8
6393 +struct mipv6_rr_info {
6394 + /* RR information */
6395 + u16 rr_state; /* State of the RR */
6396 + u16 rr_flags; /* Flags for the RR */
6397 + u8 hot_cookie[MIPV6_COOKIE_LEN]; /* HoT Cookie */
6398 + u8 cot_cookie[MIPV6_COOKIE_LEN]; /* CoT Cookie */
6399 + u8 home_cookie[MIPV6_COOKIE_LEN]; /* Home Cookie */
6400 + u8 careof_cookie[MIPV6_COOKIE_LEN]; /* Careof Cookie */
6401 + u32 lastsend_hoti; /* When HoTI was last sent (jiffies) */
6402 + u32 lastsend_coti; /* When CoTI was last sent (jiffies) */
6403 + u32 home_time; /* when Care-of cookie was received */
6404 + u32 careof_time; /* when Home cookie was received */
6405 + int home_nonce_index; /* Home cookie nonce index */
6406 + int careof_nonce_index; /* Care-of cookie nonce index */
6407 + u8 *kbu; /* Binding authentication key */
6409 +struct mipv6_bul_entry {
6410 + struct hashlist_entry e;
6411 + struct in6_addr cn_addr; /* CN to which BU was sent */
6412 + struct in6_addr home_addr; /* home address of this binding */
6413 + struct in6_addr coa; /* care-of address of the sent BU */
6415 + unsigned long expire; /* entry's expiration time (jiffies) */
6416 + __u32 lifetime; /* lifetime sent in this BU */
6417 + __u32 lastsend; /* last time when BU sent (jiffies) */
6418 + __u32 consecutive_sends; /* Number of consecutive BU's sent */
6419 + __u16 seq; /* sequence number of the latest BU */
6420 + __u8 flags; /* BU send flags */
6421 + __u8 state; /* resend state */
6422 + __u32 initdelay; /* initial ack wait */
6423 + __u32 delay; /* current ack wait */
6424 + __u32 maxdelay; /* maximum ack wait */
6426 + struct mipv6_rr_info *rr;
6427 + struct mipv6_mh_opt *ops; /* saved option values */
6429 + unsigned long callback_time;
6430 + int (*callback)(struct mipv6_bul_entry *entry);
6433 +extern rwlock_t bul_lock;
6435 +int mipv6_bul_init(__u32 size);
6437 +void mipv6_bul_exit(void);
6439 +struct mipv6_bul_entry *mipv6_bul_add(
6440 + struct in6_addr *cn_addr, struct in6_addr *home_addr,
6441 + struct in6_addr *coa, __u32 lifetime, __u16 seq, __u8 flags,
6442 + int (*callback)(struct mipv6_bul_entry *entry), __u32 callback_time,
6443 + __u8 state, __u32 delay, __u32 maxdelay, struct mipv6_mh_opt *ops,
6444 + struct mipv6_rr_info *rr);
6446 +int mipv6_bul_delete(struct in6_addr *cn_addr, struct in6_addr *home_addr);
6448 +int mipv6_bul_exists(struct in6_addr *cnaddr, struct in6_addr *home_addr);
6450 +struct mipv6_bul_entry *mipv6_bul_get(struct in6_addr *cnaddr,
6451 + struct in6_addr *home_addr);
6452 +struct mipv6_bul_entry *mipv6_bul_get_by_ccookie(struct in6_addr *cn_addr,
6455 +int bul_entry_expired(struct mipv6_bul_entry *bulentry);
6457 +void mipv6_bul_reschedule(struct mipv6_bul_entry *entry);
6459 +int mipv6_bul_iterate(int (*func)(void *, void *, unsigned long *), void *args);
6462 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/config.h linux-2.4.25/net/ipv6/mobile_ip6/config.h
6463 --- linux-2.4.25.old/net/ipv6/mobile_ip6/config.h 1970-01-01 01:00:00.000000000 +0100
6464 +++ linux-2.4.25/net/ipv6/mobile_ip6/config.h 2004-06-26 11:29:30.000000000 +0100
6467 + * Configuration parameters
6472 +#define MIPV6VERSION "D24"
6473 +#define MIPLVERSION "v1.0"
6475 +#define CAP_CN 0x01
6476 +#define CAP_HA 0x02
6477 +#define CAP_MN 0x04
6482 + int accept_ret_rout;
6483 + int max_rtr_reachable_time;
6484 + int eager_cell_switching;
6485 + int max_num_tunnels;
6486 + int min_num_tunnels;
6487 + int binding_refresh_advice;
6493 +extern struct mip6_conf mip6node_cnf;
6498 + void (*bce_home_add) (int ifindex, struct in6_addr *daddr,
6499 + struct in6_addr *haddr, struct in6_addr *coa,
6500 + struct in6_addr *rep_coa, __u32 lifetime,
6501 + __u16 sequence, __u8 flags, __u8 *k_bu);
6502 + void (*bce_cache_add) (int ifindex, struct in6_addr *daddr,
6503 + struct in6_addr *haddr, struct in6_addr *coa,
6504 + struct in6_addr *rep_coa, __u32 lifetime,
6505 + __u16 sequence, __u8 flags, __u8 *k_bu);
6506 + void (*bce_home_del) (struct in6_addr *daddr, struct in6_addr *haddr,
6507 + struct in6_addr *coa, struct in6_addr *rep_coa,
6508 + __u16 sequence, __u8 flags,
6510 + void (*bce_cache_del) (struct in6_addr *daddr, struct in6_addr *haddr,
6511 + struct in6_addr *coa, struct in6_addr *rep_coa,
6512 + __u16 sequence, __u8 flags,
6515 + int (*bce_tnl_rt_add) (struct in6_addr *coa,
6516 + struct in6_addr *ha_addr,
6517 + struct in6_addr *home_addr);
6519 + void (*bce_tnl_rt_del) (struct in6_addr *coa,
6520 + struct in6_addr *ha_addr,
6521 + struct in6_addr *home_addr);
6523 + void (*proxy_del) (struct in6_addr *home_addr, struct mipv6_bce *entry);
6524 + int (*proxy_create) (int flags, int ifindex, struct in6_addr *coa,
6525 + struct in6_addr *our_addr, struct in6_addr *home_addr);
6527 + int (*icmpv6_dhaad_rep_rcv) (struct sk_buff *skb);
6528 + int (*icmpv6_dhaad_req_rcv) (struct sk_buff *skb);
6529 + int (*icmpv6_pfxadv_rcv) (struct sk_buff *skb);
6530 + int (*icmpv6_pfxsol_rcv) (struct sk_buff *skb);
6531 + int (*icmpv6_paramprob_rcv) (struct sk_buff *skb);
6533 + int (*mn_use_hao) (struct in6_addr *daddr, struct in6_addr *saddr);
6534 + void (*mn_check_tunneled_packet) (struct sk_buff *skb);
6537 +extern struct mip6_func mip6_fn;
6538 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/debug.h linux-2.4.25/net/ipv6/mobile_ip6/debug.h
6539 --- linux-2.4.25.old/net/ipv6/mobile_ip6/debug.h 1970-01-01 01:00:00.000000000 +0100
6540 +++ linux-2.4.25/net/ipv6/mobile_ip6/debug.h 2004-06-26 11:29:30.000000000 +0100
6543 + * MIPL Mobile IPv6 Debugging macros and functions
6547 + * This program is free software; you can redistribute it and/or
6548 + * modify it under the terms of the GNU General Public License
6549 + * as published by the Free Software Foundation; either version
6550 + * 2 of the License, or (at your option) any later version.
6556 +#include <linux/autoconf.h>
6558 +/* priorities for different debug conditions */
6560 +#define DBG_CRITICAL 0 /* unrecoverable error */
6561 +#define DBG_ERROR 1 /* error (recoverable) */
6562 +#define DBG_WARNING 2 /* unusual situation but not a real error */
6563 +#define DBG_INFO 3 /* generally useful information */
6564 +#define DBG_EXTRA 4 /* extra information */
6565 +#define DBG_FUNC_ENTRY 6 /* use to indicate function entry and exit */
6566 +#define DBG_DATADUMP 7 /* packet dumps, etc. lots of flood */
6569 + * NIPV6ADDR - macro for IPv6 addresses
6570 + * @addr: Network byte order IPv6 address
6572 + * Macro for printing IPv6 addresses. Used in conjunction with
6573 + * printk() or derivatives (such as DEBUG macro).
6575 +#define NIPV6ADDR(addr) \
6576 + ntohs(((u16 *)addr)[0]), \
6577 + ntohs(((u16 *)addr)[1]), \
6578 + ntohs(((u16 *)addr)[2]), \
6579 + ntohs(((u16 *)addr)[3]), \
6580 + ntohs(((u16 *)addr)[4]), \
6581 + ntohs(((u16 *)addr)[5]), \
6582 + ntohs(((u16 *)addr)[6]), \
6583 + ntohs(((u16 *)addr)[7])
6585 +#ifdef CONFIG_IPV6_MOBILITY_DEBUG
6586 +extern int mipv6_debug;
6589 + * debug_print - print debug message
6590 + * @debug_level: message priority
6591 + * @fname: calling function's name
6592 + * @fmt: printf-style formatting string
6594 + * Prints a debug message to system log if @debug_level is less or
6595 + * equal to @mipv6_debug. Should always be called using DEBUG()
6596 + * macro, not directly.
6598 +static void debug_print(int debug_level, const char *fname, const char* fmt, ...)
6603 + if (mipv6_debug < debug_level)
6606 + va_start(args, fmt);
6607 + vsprintf(s, fmt, args);
6608 + printk("mip6[%s]: %s\n", fname, s);
6613 + * debug_print_buffer - print arbitrary buffer to system log
6614 + * @debug_level: message priority
6615 + * @data: pointer to buffer
6616 + * @len: number of bytes to print
6618 + * Prints @len bytes from buffer @data to system log. @debug_level
6619 + * tells on which debug level message gets printed. For
6620 + * debug_print_buffer() priority %DBG_DATADUMP should be used.
6622 +#define debug_print_buffer(debug_level,data,len) { \
6623 + if (mipv6_debug >= debug_level) { \
6625 + for (i=0; i<len; i++) { \
6626 + if (i%16 == 0) printk("\n%04x: ", i); \
6627 + printk("%02x ", ((unsigned char *)data)[i]); \
6633 +#define DEBUG(x,y,z...) debug_print(x,__FUNCTION__,y,##z)
6634 +#define DEBUG_FUNC() \
6635 +DEBUG(DBG_FUNC_ENTRY, "%s(%d)/%s: ", __FILE__,__LINE__,__FUNCTION__)
6638 +#define DEBUG(x,y,z...)
6639 +#define DEBUG_FUNC()
6640 +#define debug_print_buffer(x,y,z)
6644 +#define ASSERT(expression) { \
6645 + if (!(expression)) { \
6646 + (void)printk(KERN_ERR \
6647 + "Assertion \"%s\" failed: file \"%s\", function \"%s\", line %d\n", \
6648 + #expression, __FILE__, __FUNCTION__, __LINE__); \
6653 +#endif /* _DEBUG_H */
6654 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/exthdrs.c linux-2.4.25/net/ipv6/mobile_ip6/exthdrs.c
6655 --- linux-2.4.25.old/net/ipv6/mobile_ip6/exthdrs.c 1970-01-01 01:00:00.000000000 +0100
6656 +++ linux-2.4.25/net/ipv6/mobile_ip6/exthdrs.c 2004-06-26 11:29:30.000000000 +0100
6659 + * Extension Header handling and adding code
6662 + * Sami Kivisaari <skivisaa@cc.hut.fi>
6666 + * This program is free software; you can redistribute it and/or
6667 + * modify it under the terms of the GNU General Public License
6668 + * as published by the Free Software Foundation; either version
6669 + * 2 of the License, or (at your option) any later version.
6672 +#include <linux/types.h>
6673 +#include <linux/slab.h>
6675 +#include <net/ipv6.h>
6676 +#include <net/ip6_route.h>
6677 +#include <net/addrconf.h>
6678 +#include <net/mipv6.h>
6682 +#include "mobhdr.h"
6683 +#include "bcache.h"
6684 +#include "config.h"
6687 + * mipv6_append_home_addr - Add Home Address Option
6688 + * @opt: buffer for Home Address Option
6689 + * @offset: offset from beginning of @opt
6690 + * @addr: address for HAO
6692 + * Adds a Home Address Option to a packet. Option is stored in
6693 + * @offset from beginning of @opt. The option is created but the
6694 + * original source address in IPv6 header is left intact. The source
6695 + * address will be changed from home address to CoA after the checksum
6696 + * has been calculated in getfrag. Padding is done automatically, and
6697 + * @opt must have allocated space for both actual option and pad.
6698 + * Returns offset from @opt to end of options.
6700 +int mipv6_append_home_addr(__u8 *opt, int offset, struct in6_addr *addr)
6703 + struct mipv6_dstopt_homeaddr *ho;
6705 + DEBUG(DBG_DATADUMP, "HAO: %x:%x:%x:%x:%x:%x:%x:%x",
6708 + pad = (6 - offset) & 7;
6709 + mipv6_add_pad(opt + offset, pad);
6711 + ho = (struct mipv6_dstopt_homeaddr *)(opt + offset + pad);
6712 + ho->type = MIPV6_TLV_HOMEADDR;
6713 + ho->length = sizeof(*ho) - 2;
6714 + ipv6_addr_copy(&ho->addr, addr);
6716 + return offset + pad + sizeof(*ho);
6718 +static inline int check_hao_validity(struct mipv6_dstopt_homeaddr *haopt,
6720 + struct in6_addr *saddr,
6721 + struct in6_addr *daddr)
6723 + int addr_type = ipv6_addr_type(&haopt->addr);
6724 + struct mipv6_bce bc_entry;
6726 + if (addr_type & IPV6_ADDR_LINKLOCAL ||
6727 + !(addr_type & IPV6_ADDR_UNICAST)) {
6728 + DEBUG(DBG_INFO, "HAO with link local or non-unicast HoA, "
6729 + "not sending BE to "
6731 + "%x:%x:%x:%x:%x:%x:%x:%x ",
6732 + "care-of address %x:%x:%x:%x:%x:%x:%x:%x",
6733 + NIPV6ADDR(&haopt->addr),
6734 + NIPV6ADDR(saddr));
6736 + } else if (dst1[0] != IPPROTO_MOBILITY &&
6737 + (mipv6_bcache_get(&haopt->addr,
6738 + daddr, &bc_entry) != 0 ||
6739 + ipv6_addr_cmp(saddr, &bc_entry.coa))) {
6740 + DEBUG(DBG_INFO, "HAO without binding or incorrect CoA, "
6741 + "sending BE code 1: "
6742 + "home address %x:%x:%x:%x:%x:%x:%x:%x",
6743 + "to care-of address %x:%x:%x:%x:%x:%x:%x:%x",
6744 + NIPV6ADDR(&haopt->addr),
6745 + NIPV6ADDR(saddr));
6751 + * mipv6_handle_homeaddr - Home Address Destination Option handler
6752 + * @skb: packet buffer
6753 + * @optoff: offset to where option begins
6755 + * Handles Home Address Option in IPv6 Destination Option header.
6756 + * Packet and offset to option are passed. If HAO is used without
6757 + * binding, sends a Binding Error code 1. When sending BE, notify bit
6758 + * is cleared to prevent IPv6 error handling from sending ICMP
6759 + * Parameter Problem. Returns 1 on success, otherwise zero.
6761 +int mipv6_handle_homeaddr(struct sk_buff *skb, int optoff)
6763 + struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
6764 + struct in6_addr coaddr;
6765 + struct inet6_skb_parm *opt = (struct inet6_skb_parm *) skb->cb;
6766 + struct mipv6_dstopt_homeaddr *haopt =
6767 + (struct mipv6_dstopt_homeaddr *) &skb->nh.raw[optoff];
6773 + if (haopt->length != sizeof(*haopt) - 2) {
6774 + DEBUG(DBG_WARNING, "HAO has invalid length");
6775 + MIPV6_INC_STATS(n_ha_drop.invalid);
6778 + dst1 = (u8 *)skb->h.raw;
6779 + err = check_hao_validity(haopt, dst1, saddr, &skb->nh.ipv6h->daddr);
6782 + haopt->type &= ~(0x80); /* clear notify bit */
6783 + if (err == -ENOENT)
6784 + mipv6_send_be(&skb->nh.ipv6h->daddr, saddr,
6785 + &haopt->addr, MIPV6_BE_HAO_WO_BINDING);
6786 + MIPV6_INC_STATS(n_ha_drop.misc);
6789 + ipv6_addr_copy(&coaddr, saddr);
6790 + ipv6_addr_copy(saddr, &haopt->addr);
6791 + ipv6_addr_copy(&haopt->addr, &coaddr);
6792 + opt->hao = optoff;
6793 + if (mip6_fn.mn_check_tunneled_packet != NULL)
6794 + mip6_fn.mn_check_tunneled_packet(skb);
6796 + MIPV6_INC_STATS(n_ha_rcvd);
6801 + * mipv6_icmp_swap_addrs - Switch HAO and src and RT2 and dest for ICMP errors
6802 + * @skb: packet buffer
6804 + * Reset the source address and the Home Address option in skb before
6805 + * appending it to an ICMP error message, so original packet appears
6806 + * in the error message rather than mangled.
6808 +void mipv6_icmp_swap_addrs(struct sk_buff *skb)
6810 + struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
6811 + struct in6_addr tmp;
6812 + struct in6_addr *hoa;
6814 + if (opt->srcrt2) {
6815 + struct rt2_hdr *rt2;
6816 + rt2 = (struct rt2_hdr *)(skb->nh.raw + opt->srcrt2);
6819 + ipv6_addr_copy(&tmp, hoa);
6820 + ipv6_addr_copy(hoa, &skb->nh.ipv6h->daddr);
6821 + ipv6_addr_copy(&skb->nh.ipv6h->daddr, &tmp);
6822 + rt2->rt_hdr.segments_left++;
6823 + skb->nh.ipv6h->hop_limit++;
6826 + struct mipv6_dstopt_homeaddr *hao;
6827 + hao = (struct mipv6_dstopt_homeaddr *)(skb->nh.raw + opt->hao);
6830 + ipv6_addr_copy(&tmp, hoa);
6831 + ipv6_addr_copy(hoa, &skb->nh.ipv6h->saddr);
6832 + ipv6_addr_copy(&skb->nh.ipv6h->saddr, &tmp);
6837 + * mipv6_append_rt2hdr - Add Type 2 Routing Header
6838 + * @rt: buffer for new routing header
6839 + * @addr: intermediate hop address
6841 + * Adds a Routing Header Type 2 in a packet. Stores newly created
6842 + * routing header in buffer @rt. Type 2 RT only carries one address,
6843 + * so there is no need to process old routing header. @rt must have
6844 + * allocated space for 24 bytes.
6846 +void mipv6_append_rt2hdr(struct ipv6_rt_hdr *rt, struct in6_addr *addr)
6848 + struct rt2_hdr *rt2 = (struct rt2_hdr *)rt;
6850 + DEBUG(DBG_DATADUMP, "RT2: %x:%x:%x:%x:%x:%x:%x:%x",
6853 + if (ipv6_addr_type(addr) == IPV6_ADDR_MULTICAST) {
6854 + DEBUG(DBG_ERROR, "destination address not unicast");
6858 + memset(rt2, 0, sizeof(*rt2));
6859 + rt2->rt_hdr.type = 2;
6860 + rt2->rt_hdr.hdrlen = 2;
6861 + rt2->rt_hdr.segments_left = 1;
6862 + ipv6_addr_copy(&rt2->addr, addr);
6866 + * mipv6_append_dst1opts - Add Destination Option (1) Headers
6867 + * @dst1opt: buffer for new destination options
6868 + * @saddr: address for Home Address Option
6869 + * @old_dst1opt: old destination options
6870 + * @len: length of options
6872 + * Adds Destination Option (1) Header to a packet. New options are
6873 + * stored in @dst1opt. If old destination options exist, they are
6874 + * copied from @old_dst1opt. Only Home Address Option is destination
6875 + * option. @dstopt must have allocated space for @len bytes. @len
6876 + * includes Destination Option Header (2 bytes), Home Address Option
6877 + * (18 bytes) and possible HAO pad (8n+6).
6880 + * ISSUE: Home Address Destination Option should really be added to a
6881 + * new destination option header specified in Mobile IPv6 spec which
6882 + * should be placed after routing header(s), but before fragmentation
6883 + * header. Putting HAO in DO1 works for now, but support for the new
6884 + * placement should be added to the IPv6 stack.
6887 +mipv6_append_dst1opts(struct ipv6_opt_hdr *dst1opt, struct in6_addr *saddr,
6888 + struct ipv6_opt_hdr *old_dst1opt, int len)
6892 + if (old_dst1opt) {
6893 + memcpy(dst1opt, old_dst1opt, ipv6_optlen(old_dst1opt));
6894 + offset = ipv6_optlen(old_dst1opt);
6896 + offset = sizeof (*dst1opt);
6898 + dst1opt->hdrlen = (len >> 3) - 1;
6899 + mipv6_append_home_addr((__u8 *) dst1opt, offset, saddr);
6903 + * mipv6_modify_txoptions - Modify outgoing packets
6905 + * @skb: packet buffer for outgoing packet
6906 + * @old_opt: transmit options
6907 + * @fl: packet flow structure
6908 + * @dst: pointer to destination cache entry
6910 + * Adds Home Address Option (for MN packets, when not at home) and
6911 + * Routing Header Type 2 (for CN packets when sending to an MN) to
6912 + * data packets. Old extension headers are copied from @old_opt (if
6913 + * any). Extension headers are _explicitly_ added for packets with
6914 + * Mobility Header. Returns the new header structure, or old if no
6917 +struct ipv6_txoptions *
6918 +mipv6_modify_txoptions(struct sock *sk, struct sk_buff *skb,
6919 + struct ipv6_txoptions *old_opt, struct flowi *fl,
6920 + struct dst_entry **dst)
6922 + struct ipv6_opt_hdr *old_hopopt = NULL;
6923 + struct ipv6_opt_hdr *old_dst1opt = NULL;
6924 + struct ipv6_rt_hdr *old_srcrt = NULL;
6926 + int srcrtlen = 0, dst1len = 0;
6927 + int tot_len, use_hao = 0;
6928 + struct ipv6_txoptions *opt;
6929 + struct mipv6_bce bc_entry;
6930 + struct in6_addr tmpaddr, *saddr, *daddr, coaddr;
6935 + if (fl->proto == IPPROTO_MOBILITY) return old_opt;
6937 + * we have to be prepared to the fact that saddr might not be present,
6938 + * if that is the case, we acquire saddr just as kernel does.
6940 + saddr = fl ? fl->fl6_src : NULL;
6941 + daddr = fl ? fl->fl6_dst : NULL;
6943 + if (daddr == NULL)
6945 + if (saddr == NULL) {
6946 + int err = ipv6_get_saddr(NULL, daddr, &tmpaddr);
6953 + DEBUG(DBG_DATADUMP,
6954 + "dest. address of packet: %x:%x:%x:%x:%x:%x:%x:%x",
6955 + NIPV6ADDR(daddr));
6956 + DEBUG(DBG_DATADUMP, " and src. address: %x:%x:%x:%x:%x:%x:%x:%x",
6957 + NIPV6ADDR(saddr));
6960 + old_hopopt = old_opt->hopopt;
6961 + old_dst1opt = old_opt->dst1opt;
6962 + old_srcrt = old_opt->srcrt;
6965 + if (mip6_fn.mn_use_hao != NULL)
6966 + use_hao = mip6_fn.mn_use_hao(daddr, saddr);
6970 + dst1len = ipv6_optlen(old_dst1opt);
6971 + dst1len += sizeof(struct mipv6_dstopt_homeaddr) +
6972 + ((6 - dst1len) & 7); /* padding */
6975 + if (mipv6_bcache_get(daddr, saddr, &bc_entry) == 0)
6976 + srcrtlen = sizeof(struct rt2_hdr);
6978 + if ((tot_len = srcrtlen + dst1len) == 0) {
6982 + tot_len += sizeof(*opt);
6984 + if (!(opt = kmalloc(tot_len, GFP_ATOMIC))) {
6987 + memset(opt, 0, tot_len);
6988 + opt->tot_len = tot_len;
6989 + opt_ptr = (__u8 *) (opt + 1);
6992 + opt->srcrt = old_srcrt;
6993 + opt->opt_nflen += ipv6_optlen(old_srcrt);
6997 + DEBUG(DBG_DATADUMP, "Binding exists. Adding routing header");
6999 + opt->srcrt2 = (struct ipv6_rt_hdr *) opt_ptr;
7000 + opt->opt_nflen += srcrtlen;
7001 + opt_ptr += srcrtlen;
7004 + * Append care-of-address to routing header (original
7005 + * destination address is home address, the first
7006 + * source route segment gets put to the destination
7007 + * address and the home address gets to the last
7008 + * segment of source route (just as it should))
7011 + ipv6_addr_copy(&coaddr, &bc_entry.coa);
7013 + mipv6_append_rt2hdr(opt->srcrt2, &coaddr);
7016 + * reroute output (we have to do this in case of TCP
7017 + * segment) unless a routing header of type 0 is also added
7019 + if (dst && !opt->srcrt) {
7020 + struct in6_addr *tmp = fl->fl6_dst;
7021 + fl->fl6_dst = &coaddr;
7023 + dst_release(*dst);
7024 + *dst = ip6_route_output(sk, fl);
7027 + fl->fl6_dst = tmp;
7029 + DEBUG(DBG_DATADUMP, "Rerouted outgoing packet");
7033 + /* Only home address option is inserted to first dst opt header */
7035 + opt->dst1opt = (struct ipv6_opt_hdr *) opt_ptr;
7036 + opt->opt_flen += dst1len;
7037 + opt_ptr += dst1len;
7038 + mipv6_append_dst1opts(opt->dst1opt, saddr,
7039 + old_dst1opt, dst1len);
7040 + opt->mipv6_flags = MIPV6_SND_HAO;
7041 + } else if (old_dst1opt) {
7042 + opt->dst1opt = old_dst1opt;
7043 + opt->opt_flen += ipv6_optlen(old_dst1opt);
7046 + opt->hopopt = old_hopopt;
7047 + opt->opt_nflen += ipv6_optlen(old_hopopt);
7052 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/exthdrs.h linux-2.4.25/net/ipv6/mobile_ip6/exthdrs.h
7053 --- linux-2.4.25.old/net/ipv6/mobile_ip6/exthdrs.h 1970-01-01 01:00:00.000000000 +0100
7054 +++ linux-2.4.25/net/ipv6/mobile_ip6/exthdrs.h 2004-06-26 11:29:30.000000000 +0100
7057 + * MIPL Mobile IPv6 Extension Headers header file
7061 + * This program is free software; you can redistribute it and/or
7062 + * modify it under the terms of the GNU General Public License
7063 + * as published by the Free Software Foundation; either version
7064 + * 2 of the License, or (at your option) any later version.
7067 +#ifndef _MIPV6_EXTHDRS_H
7068 +#define _MIPV6_EXTHDRS_H
7072 +struct ipv6_rt_hdr;
7073 +struct ipv6_opt_hdr;
7074 +struct ipv6_txoptions;
7078 + * Home Address Destination Option function prototypes
7080 +int mipv6_append_home_addr(__u8 *opt, int offset, struct in6_addr *addr);
7082 +int mipv6_handle_homeaddr(struct sk_buff *skb, int optoff);
7084 +void mipv6_icmp_swap_addrs(struct sk_buff *skb);
7087 + * Creates a routing header of type 2.
7089 +void mipv6_append_rt2hdr(struct ipv6_rt_hdr *srcrt, struct in6_addr *addr);
7091 +/* Function to add the first destination option header, which may
7092 + * include a home address option.
7094 +void mipv6_append_dst1opts(struct ipv6_opt_hdr *dst1opt, struct in6_addr *saddr,
7095 + struct ipv6_opt_hdr *old_dst1opt, int len);
7097 +struct ipv6_txoptions *mipv6_modify_txoptions(
7098 + struct sock *sk, struct sk_buff *skb,
7099 + struct ipv6_txoptions *old_opt, struct flowi *fl,
7100 + struct dst_entry **dst);
7102 +#endif /* _MIPV6_EXTHDRS_H */
7103 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/ha.c linux-2.4.25/net/ipv6/mobile_ip6/ha.c
7104 --- linux-2.4.25.old/net/ipv6/mobile_ip6/ha.c 1970-01-01 01:00:00.000000000 +0100
7105 +++ linux-2.4.25/net/ipv6/mobile_ip6/ha.c 2004-06-26 11:29:30.000000000 +0100
7108 + * Home-agent functionality
7111 + * Sami Kivisaari <skivisaa@cc.hut.fi>
7112 + * Henrik Petander <lpetande@cc.hut.fi>
7116 + * This program is free software; you can redistribute it and/or
7117 + * modify it under the terms of the GNU General Public License
7118 + * as published by the Free Software Foundation; either version
7119 + * 2 of the License, or (at your option) any later version.
7121 + * Changes: Venkata Jagana,
7122 + * Krishna Kumar : Statistics fix
7123 + * Masahide Nakamura : Use of mipv6_forward
7127 +#include <linux/autoconf.h>
7128 +#include <linux/net.h>
7129 +#include <linux/skbuff.h>
7130 +#include <linux/if_ether.h>
7131 +#include <linux/netdevice.h>
7132 +#include <linux/in6.h>
7133 +#include <linux/init.h>
7134 +#include <linux/netfilter.h>
7135 +#include <linux/netfilter_ipv6.h>
7136 +#ifdef CONFIG_SYSCTL
7137 +#include <linux/sysctl.h>
7140 +#include <net/neighbour.h>
7141 +#include <net/ipv6.h>
7142 +#include <net/ip6_fib.h>
7143 +#include <net/ip6_route.h>
7144 +#include <net/ndisc.h>
7145 +#include <net/addrconf.h>
7146 +#include <net/neighbour.h>
7148 +#include "tunnel_ha.h"
7149 +#include "bcache.h"
7154 +#include "config.h"
7155 +#include "mobhdr.h"
7157 +static int mipv6_ha_tunnel_sitelocal = 0;
7159 +#ifdef CONFIG_SYSCTL
7161 +static struct ctl_table_header *mipv6_ha_sysctl_header;
7163 +static struct mipv6_ha_sysctl_table
7165 + struct ctl_table_header *sysctl_header;
7166 + ctl_table mipv6_vars[3];
7167 + ctl_table mipv6_mobility_table[2];
7168 + ctl_table mipv6_proto_table[2];
7169 + ctl_table mipv6_root_table[2];
7170 +} mipv6_ha_sysctl = {
7173 + {{NET_IPV6_MOBILITY_TUNNEL_SITELOCAL, "tunnel_sitelocal",
7174 + &mipv6_ha_tunnel_sitelocal, sizeof(int), 0644, NULL,
7178 + {{NET_IPV6_MOBILITY, "mobility", NULL, 0, 0555,
7179 + mipv6_ha_sysctl.mipv6_vars}, {0}},
7180 + {{NET_IPV6, "ipv6", NULL, 0, 0555,
7181 + mipv6_ha_sysctl.mipv6_mobility_table}, {0}},
7182 + {{CTL_NET, "net", NULL, 0, 0555,
7183 + mipv6_ha_sysctl.mipv6_proto_table}, {0}}
7186 +#endif /* CONFIG_SYSCTL */
7189 +/* this is defined in kernel IPv6 module (sockglue.c) */
7190 +extern struct packet_type ipv6_packet_type;
7192 +/* mipv6_forward: Intercept NS packets destined to home address of MN */
7193 +int mipv6_forward(struct sk_buff *skb)
7195 + struct ipv6hdr *ipv6h;
7196 + struct in6_addr *daddr, *saddr;
7200 + if (skb == NULL) return 0;
7202 + ipv6h = skb->nh.ipv6h;
7203 + daddr = &ipv6h->daddr;
7204 + saddr = &ipv6h->saddr;
7206 + nexthdr = ipv6h->nexthdr;
7207 + nhoff = sizeof(*ipv6h);
7209 + if (ipv6_ext_hdr(nexthdr))
7210 + nhoff = ipv6_skip_exthdr(skb, nhoff, &nexthdr,
7211 + skb->len - sizeof(*ipv6h));
7213 + /* Do not to forward Neighbor Solicitation to Home Address of MN */
7214 + if (nexthdr == IPPROTO_ICMPV6) {
7215 + struct icmp6hdr *icmp6h;
7218 + if (nhoff < 0 || !pskb_may_pull(skb, nhoff +
7219 + sizeof(struct icmp6hdr))) {
7224 + dest_type = ipv6_addr_type(daddr);
7225 + icmp6h = (struct icmp6hdr *)&skb->nh.raw[nhoff];
7227 + /* Intercepts NS to HoA of MN */
7229 + if ((icmp6h->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) ||
7230 + ((dest_type & IPV6_ADDR_MULTICAST) &&
7231 + (icmp6h->icmp6_type == NDISC_ROUTER_ADVERTISEMENT))) {
7244 + * mipv6_proxy_nd_rem - stop acting as a proxy for @home_address
7245 + * @home_addr: address to remove
7246 + * @ha_addr: home agent's address on home link
7247 + * @linklocal: link-local compatibility bit
7249 + * When Home Agent acts as a proxy for an address it must leave the
7250 + * solicited node multicast group for that address and stop responding
7251 + * to neighbour solicitations.
7253 +static int mipv6_proxy_nd_rem(struct in6_addr *home_addr,
7254 + int ifindex, int linklocal)
7256 + /* When MN returns home HA leaves the solicited mcast groups
7257 + * for MNs home addresses
7260 + struct net_device *dev;
7264 + if ((dev = dev_get_by_index(ifindex)) == NULL) {
7265 + DEBUG(DBG_ERROR, "couldn't get dev");
7269 + /* Remove link-local entry */
7271 + struct in6_addr ll_addr;
7272 + mipv6_generate_ll_addr(&ll_addr, home_addr);
7273 + if ((err = pneigh_delete(&nd_tbl, &ll_addr, dev)) < 0) {
7275 + "peigh_delete failed for "
7276 + "%x:%x:%x:%x:%x:%x:%x:%x",
7277 + NIPV6ADDR(&ll_addr));
7281 + /* Remove global (or site-local) entry */
7282 + if ((err = pneigh_delete(&nd_tbl, home_addr, dev)) < 0) {
7284 + "peigh_delete failed for "
7285 + "%x:%x:%x:%x:%x:%x:%x:%x",
7286 + NIPV6ADDR(home_addr));
7293 + * mipv6_proxy_nd - join multicast group for this address
7294 + * @home_addr: address to defend
7295 + * @ha_addr: home agent's address on home link
7296 + * @linklocal: link-local compatibility bit
7298 + * While Mobile Node is away from home, Home Agent acts as a proxy for
7299 + * @home_address. HA responds to neighbour solicitations for @home_address
7300 + * thus getting all packets destined to home address of MN.
7302 +static int mipv6_proxy_nd(struct in6_addr *home_addr,
7303 + int ifindex, int linklocal)
7305 + /* The HA sends a proxy ndisc_na message to all hosts on MN's
7306 + * home subnet by sending a neighbor advertisement with the
7307 + * home address or all addresses of the mobile node if the
7308 + * prefix is not 0. The addresses are formed by combining the
7309 + * suffix or the host part of the address with each subnet
7310 + * prefix that exists in the home subnet
7313 + /* Since no previous entry for MN exists a proxy_nd advertisement
7314 + * is sent to all nodes link local multicast address
7318 + struct net_device *dev;
7319 + struct in6_addr na_saddr;
7320 + struct in6_addr ll_addr;
7321 + struct pneigh_entry *ll_pneigh;
7322 + struct in6_addr mcdest;
7323 + int send_ll_na = 0;
7325 + int solicited = 0;
7330 + if ((dev = dev_get_by_index(ifindex)) == NULL) {
7331 + DEBUG(DBG_ERROR, "couldn't get dev");
7335 + if (!pneigh_lookup(&nd_tbl, home_addr, dev, 1)) {
7337 + "peigh_lookup failed for "
7338 + "%x:%x:%x:%x:%x:%x:%x:%x",
7339 + NIPV6ADDR(home_addr));
7344 + mipv6_generate_ll_addr(&ll_addr, home_addr);
7346 + if ((ll_pneigh = pneigh_lookup(&nd_tbl, &ll_addr,
7347 + dev, 1)) == NULL) {
7349 + "peigh_lookup failed for "
7350 + "%x:%x:%x:%x:%x:%x:%x:%x",
7351 + NIPV6ADDR(&ll_addr));
7352 + pneigh_delete(&nd_tbl, home_addr, dev);
7361 + /* Proxy neighbor advertisement of MN's home address
7362 + * to all nodes solicited multicast address
7364 + if (!ipv6_get_lladdr(dev, &na_saddr)) {
7365 + ipv6_addr_all_nodes(&mcdest);
7366 + ndisc_send_na(dev, NULL, &mcdest, home_addr, 0,
7367 + solicited, override, inc_opt);
7370 + ndisc_send_na(dev, NULL, &mcdest, &ll_addr,
7371 + 0, solicited, override, inc_opt);
7376 + DEBUG(DBG_ERROR, "failed to get link local address for sending proxy NA");
7384 +struct inet6_ifaddr *is_on_link_ipv6_address(struct in6_addr *mn_haddr,
7385 + struct in6_addr *ha_addr)
7387 + struct inet6_ifaddr *ifp;
7388 + struct inet6_dev *in6_dev;
7389 + struct inet6_ifaddr *oifp = NULL;
7391 + if ((ifp = ipv6_get_ifaddr(ha_addr, 0)) == NULL)
7394 + if ((in6_dev = ifp->idev) != NULL) {
7395 + in6_dev_hold(in6_dev);
7396 + oifp = in6_dev->addr_list;
7397 + while (oifp != NULL) {
7398 + spin_lock(&oifp->lock);
7399 + if (mipv6_prefix_compare(&oifp->addr, mn_haddr,
7400 + oifp->prefix_len) &&
7401 + !(oifp->flags & IFA_F_TENTATIVE)) {
7402 + spin_unlock(&oifp->lock);
7403 + DEBUG(DBG_INFO, "Home Addr Opt: on-link");
7404 + in6_ifa_hold(oifp);
7407 + spin_unlock(&oifp->lock);
7408 + oifp = oifp->if_next;
7410 + in6_dev_put(in6_dev);
7413 +/* DEBUG(DBG_WARNING, "Home Addr Opt NOT on-link"); */
7419 + * Lifetime checks. ifp->valid_lft >= ifp->prefered_lft always (see addrconf.c)
7420 + * Returned value is in seconds.
7423 +static __u32 get_min_lifetime(struct inet6_ifaddr *ifp, __u32 lifetime)
7425 + __u32 rem_lifetime = 0;
7426 + unsigned long now = jiffies;
7428 + if (ifp->valid_lft == 0) {
7429 + rem_lifetime = lifetime;
7431 + __u32 valid_lft_left =
7432 + ifp->valid_lft - ((now - ifp->tstamp) / HZ);
7434 + min_t(unsigned long, valid_lft_left, lifetime);
7437 + return rem_lifetime;
7440 +#define MAX_LIFETIME 1000
7443 + * mipv6_lifetime_check - check maximum lifetime is not exceeded
7444 + * @lifetime: lifetime to check
7446 + * Checks @lifetime does not exceed %MAX_LIFETIME. Returns @lifetime
7447 + * if not exceeded, otherwise returns %MAX_LIFETIME.
7449 +static int mipv6_lifetime_check(int lifetime)
7451 + return (lifetime > MAX_LIFETIME) ? MAX_LIFETIME : lifetime;
7454 +/* Generic routine handling finish of BU processing */
7455 +void mipv6_bu_finish(struct inet6_ifaddr *ifp, int ifindex, __u8 ba_status,
7456 + struct in6_addr *daddr, struct in6_addr *haddr,
7457 + struct in6_addr *coa, struct in6_addr *rep_coa,
7458 + __u32 ba_lifetime, __u16 sequence, __u8 flags, __u8 *k_bu)
7462 + if (ba_status >= REASON_UNSPECIFIED) {
7467 + ba_lifetime = get_min_lifetime(ifp, ba_lifetime);
7468 + ba_lifetime = mipv6_lifetime_check(ba_lifetime);
7470 + if ((err = mipv6_bcache_add(ifindex, daddr, haddr, coa,
7471 + ba_lifetime, sequence, flags,
7472 + HOME_REGISTRATION)) != 0 ) {
7473 + DEBUG(DBG_WARNING, "home reg failed.");
7475 + if (err == -ENOMEDIUM)
7478 + ba_status = INSUFFICIENT_RESOURCES;
7480 + DEBUG(DBG_INFO, "home reg succeeded.");
7483 + DEBUG(DBG_DATADUMP, "home_addr: %x:%x:%x:%x:%x:%x:%x:%x",
7484 + NIPV6ADDR(haddr));
7485 + DEBUG(DBG_DATADUMP, "coa: %x:%x:%x:%x:%x:%x:%x:%x",
7487 + DEBUG(DBG_DATADUMP, "lifet:%d, seq:%d", ba_lifetime, sequence);
7489 + mipv6_send_ba(daddr, haddr, coa, rep_coa, ba_status, sequence,
7490 + ba_lifetime, k_bu);
7493 +static int ha_proxy_create(int flags, int ifindex, struct in6_addr *coa,
7494 + struct in6_addr *our_addr, struct in6_addr *home_addr)
7498 + if ((ret = mipv6_add_tnl_to_mn(coa, our_addr, home_addr)) <= 0) {
7499 + if (ret != -ENOMEDIUM) {
7500 + DEBUG(DBG_ERROR, "unable to configure tunnel to MN!");
7504 + if (mipv6_proxy_nd(home_addr, ifindex,
7505 + flags & MIPV6_BU_F_LLADDR) != 0) {
7506 + DEBUG(DBG_ERROR, "mipv6_proxy_nd failed!");
7507 + mipv6_del_tnl_to_mn(coa, our_addr, home_addr);
7513 +static void ha_proxy_del(struct in6_addr *home_addr, struct mipv6_bce *entry)
7515 + if (mipv6_proxy_nd_rem(&entry->home_addr, entry->ifindex,
7516 + entry->flags & MIPV6_BU_F_LLADDR) == 0) {
7517 + DEBUG(DBG_INFO, "proxy_nd succ");
7519 + DEBUG(DBG_INFO, "proxy_nd fail");
7521 + mipv6_del_tnl_to_mn(&entry->coa, &entry->our_addr, home_addr);
7524 +static void bc_home_add(int ifindex,
7525 + struct in6_addr *daddr, struct in6_addr *haddr,
7526 + struct in6_addr *coa, struct in6_addr *rep_coa,
7527 + __u32 lifetime, __u16 sequence, __u8 flags,
7530 + struct inet6_ifaddr *ifp = NULL;
7531 + __u8 ba_status = SUCCESS;
7535 + ifp = is_on_link_ipv6_address(haddr, daddr);
7537 + if (ifp == NULL) {
7538 + ba_status = NOT_HOME_SUBNET;
7539 + } else if (((ipv6_addr_type(haddr) & IPV6_ADDR_SITELOCAL) ||
7540 + (ipv6_addr_type(coa) & IPV6_ADDR_SITELOCAL))
7541 + && !mipv6_ha_tunnel_sitelocal) {
7542 + /* Site-local home or care-of addresses are not
7543 + accepted by default */
7544 + ba_status = ADMINISTRATIVELY_PROHIBITED;
7548 + ifindex = ifp->idev->dev->ifindex;
7550 + if ((ret = mipv6_dad_start(ifp, ifindex, daddr,
7551 + haddr, coa, rep_coa, lifetime,
7552 + sequence, flags)) < 0) {
7553 + /* An error occurred */
7556 + /* DAD is needed to be performed. */
7562 + mipv6_bu_finish(ifp, ifindex, ba_status, daddr, haddr, coa,
7563 + rep_coa, lifetime, sequence, flags, k_bu);
7568 +static void bc_home_delete(struct in6_addr *daddr, struct in6_addr *haddr,
7569 + struct in6_addr *coa, struct in6_addr *rep_coa,
7570 + __u16 sequence, __u8 flags, __u8 *k_bu)
7572 + __u8 status = SUCCESS;
7573 + struct mipv6_bce bce;
7575 + /* Primary Care-of Address Deregistration */
7576 + if (mipv6_bcache_get(haddr, daddr, &bce) < 0) {
7577 + DEBUG(DBG_INFO, "entry is not in cache");
7578 + status = NOT_HA_FOR_MN;
7580 + ha_proxy_del(&bce.home_addr, &bce);
7581 + mipv6_bcache_delete(haddr, daddr, HOME_REGISTRATION);
7583 + mipv6_send_ba(daddr, haddr, coa, rep_coa, status, sequence, 0, k_bu);
7586 +extern int mipv6_ra_rcv_ptr(struct sk_buff *skb, struct icmp6hdr *msg);
7590 +mipv6_ha_tnl_xmit_stats_hook(struct ip6_tnl *t, struct sk_buff *skb)
7593 + if (is_mip6_tnl(t))
7594 + MIPV6_INC_STATS(n_encapsulations);
7595 + return IP6_TNL_ACCEPT;
7598 +static struct ip6_tnl_hook_ops mipv6_ha_tnl_xmit_stats_ops = {
7600 + IP6_TNL_PRE_ENCAP,
7602 + mipv6_ha_tnl_xmit_stats_hook
7606 +mipv6_ha_tnl_rcv_stats_hook(struct ip6_tnl *t, struct sk_buff *skb)
7609 + if (is_mip6_tnl(t))
7610 + MIPV6_INC_STATS(n_decapsulations);
7611 + return IP6_TNL_ACCEPT;
7614 +static struct ip6_tnl_hook_ops mipv6_ha_tnl_rcv_stats_ops = {
7616 + IP6_TNL_PRE_DECAP,
7618 + mipv6_ha_tnl_rcv_stats_hook
7621 +static struct mip6_func old;
7623 +int __init mipv6_ha_init(void)
7627 +#ifdef CONFIG_SYSCTL
7628 + if (!(mipv6_ha_sysctl_header =
7629 + register_sysctl_table(mipv6_ha_sysctl.mipv6_root_table, 0)))
7630 + printk(KERN_ERR "Failed to register sysctl handlers!");
7632 + memcpy(&old, &mip6_fn, sizeof(struct mip6_func));
7633 + mip6_fn.bce_home_add = bc_home_add;
7634 + mip6_fn.bce_home_del = bc_home_delete;
7635 + mip6_fn.proxy_del = ha_proxy_del;
7636 + mip6_fn.proxy_create = ha_proxy_create;
7637 + /* register packet interception hooks */
7638 + ip6ip6_tnl_register_hook(&mipv6_ha_tnl_xmit_stats_ops);
7639 + ip6ip6_tnl_register_hook(&mipv6_ha_tnl_rcv_stats_ops);
7643 +void __exit mipv6_ha_exit(void)
7647 +#ifdef CONFIG_SYSCTL
7648 + unregister_sysctl_table(mipv6_ha_sysctl_header);
7651 + /* remove packet interception hooks */
7652 + ip6ip6_tnl_unregister_hook(&mipv6_ha_tnl_rcv_stats_ops);
7653 + ip6ip6_tnl_unregister_hook(&mipv6_ha_tnl_xmit_stats_ops);
7655 + mip6_fn.bce_home_add = old.bce_home_add;
7656 + mip6_fn.bce_home_del = old.bce_home_del;
7657 + mip6_fn.proxy_del = old.proxy_del;
7658 + mip6_fn.proxy_create = old.proxy_create;
7660 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/ha.h linux-2.4.25/net/ipv6/mobile_ip6/ha.h
7661 --- linux-2.4.25.old/net/ipv6/mobile_ip6/ha.h 1970-01-01 01:00:00.000000000 +0100
7662 +++ linux-2.4.25/net/ipv6/mobile_ip6/ha.h 2004-06-26 11:29:30.000000000 +0100
7665 + * MIPL Mobile IPv6 Home Agent header file
7669 + * This program is free software; you can redistribute it and/or
7670 + * modify it under the terms of the GNU General Public License
7671 + * as published by the Free Software Foundation; either version
7672 + * 2 of the License, or (at your option) any later version.
7678 +int mipv6_ha_init(void);
7679 +void mipv6_ha_exit(void);
7681 +int mipv6_dad_start(struct inet6_ifaddr *ifp, int ifindex,
7682 + struct in6_addr *daddr, struct in6_addr *haddr,
7683 + struct in6_addr *coa, struct in6_addr *rep_coa,
7684 + __u32 ba_lifetime, __u16 sequence, __u8 flags);
7686 +void mipv6_bu_finish(struct inet6_ifaddr *ifp, int ifindex,
7687 + __u8 ba_status, struct in6_addr *daddr,
7688 + struct in6_addr *haddr, struct in6_addr *coa,
7689 + struct in6_addr *rep_coa, __u32 ba_lifetime,
7690 + __u16 sequence, __u8 flags, __u8 *k_bu);
7693 +static __inline__ void mipv6_generate_ll_addr(struct in6_addr *ll_addr,
7694 + struct in6_addr *addr)
7696 + ll_addr->s6_addr32[0] = htonl(0xfe800000);
7697 + ll_addr->s6_addr32[1] = 0;
7698 + ll_addr->s6_addr32[2] = addr->s6_addr32[2];
7699 + ll_addr->s6_addr32[3] = addr->s6_addr32[3];
7703 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/halist.c linux-2.4.25/net/ipv6/mobile_ip6/halist.c
7704 --- linux-2.4.25.old/net/ipv6/mobile_ip6/halist.c 1970-01-01 01:00:00.000000000 +0100
7705 +++ linux-2.4.25/net/ipv6/mobile_ip6/halist.c 2004-06-26 11:29:30.000000000 +0100
7708 + * Home Agents List
7711 + * Antti Tuominen <ajtuomin@tml.hut.fi>
7715 + * This program is free software; you can redistribute it and/or
7716 + * modify it under the terms of the GNU General Public License
7717 + * as published by the Free Software Foundation; either version
7718 + * 2 of the License, or (at your option) any later version.
7722 +#define PREF_BASE 0xffff /* MAX value for u16 field in RA */
7724 +#include <linux/autoconf.h>
7725 +#include <linux/sched.h>
7726 +#include <linux/timer.h>
7727 +#include <linux/proc_fs.h>
7728 +#include <linux/init.h>
7729 +#include <net/ipv6.h>
7730 +#include <net/addrconf.h>
7732 +#include "hashlist.h"
7736 +struct mipv6_halist {
7737 + struct hashlist *entries;
7738 + struct timer_list expire_timer;
7741 +static rwlock_t home_agents_lock = RW_LOCK_UNLOCKED;
7743 +static struct mipv6_halist home_agents;
7745 +struct mipv6_halist_entry {
7746 + struct hashlist_entry e;
7747 + int ifindex; /* Link identifier */
7748 + struct in6_addr link_local_addr; /* HA's link-local address */
7749 + struct in6_addr global_addr; /* HA's Global address */
7751 + long preference; /* The preference for this HA */
7752 + unsigned long expire; /* expiration time (jiffies) */
7755 +static inline void mipv6_ha_ac_add(struct in6_addr *ll_addr, int ifindex,
7756 + struct in6_addr *glob_addr, int plen)
7758 + struct net_device *dev;
7760 + if ((dev = __dev_get_by_index(ifindex)) && ipv6_chk_addr(ll_addr, dev)) {
7761 + struct in6_addr addr;
7762 + mipv6_ha_anycast(&addr, glob_addr, plen);
7763 + ipv6_dev_ac_inc(dev, &addr);
7767 +static inline void mipv6_ha_ac_del(struct in6_addr *ll_addr, int ifindex,
7768 + struct in6_addr *glob_addr, int plen)
7770 + struct net_device *dev;
7772 + if ((dev = __dev_get_by_index(ifindex)) && ipv6_chk_addr(ll_addr, dev)) {
7773 + struct in6_addr addr;
7774 + mipv6_ha_anycast(&addr, glob_addr, plen);
7775 + ipv6_dev_ac_dec(dev, &addr);
7779 +struct preflist_iterator_args {
7783 + struct in6_addr *list;
7786 +static int preflist_iterator(void *data, void *args,
7787 + unsigned long *pref)
7789 + struct preflist_iterator_args *state =
7790 + (struct preflist_iterator_args *)args;
7791 + struct mipv6_halist_entry *entry =
7792 + (struct mipv6_halist_entry *)data;
7793 + struct in6_addr *newaddr =
7794 + (struct in6_addr *)state->list + state->count;
7796 + if (state->count >= state->requested)
7797 + return ITERATOR_STOP;
7799 + if (time_after(jiffies, entry->expire)) {
7800 + if (!ipv6_addr_any(&entry->link_local_addr)) {
7801 + mipv6_ha_ac_del(&entry->link_local_addr,
7803 + &entry->global_addr, entry->plen);
7805 + DEBUG(DBG_INFO, "preflist_iterator: Deleting entry with address %x:%x:%x:%x:%x:%x:%x:%x to list", NIPV6ADDR(&entry->global_addr));
7806 + return ITERATOR_DELETE_ENTRY;
7808 + if (state->ifindex != entry->ifindex)
7809 + return ITERATOR_CONT;
7811 + ipv6_addr_copy(newaddr, &entry->global_addr);
7812 + DEBUG(DBG_INFO, "preflist_iterator: adding new entry with address %x:%x:%x:%x:%x:%x:%x:%x to list", NIPV6ADDR(&entry->global_addr));
7815 + return ITERATOR_CONT;
7818 +static int gc_iterator(void *data, void *args,
7819 + unsigned long *pref)
7821 + struct mipv6_halist_entry *entry =
7822 + (struct mipv6_halist_entry *)data;
7824 + int *type = (int *)args;
7826 + if (*type == 1 || time_after(jiffies, entry->expire)) {
7827 + if (!ipv6_addr_any(&entry->link_local_addr)) {
7828 + mipv6_ha_ac_del(&entry->link_local_addr,
7830 + &entry->global_addr, entry->plen);
7832 + return ITERATOR_DELETE_ENTRY;
7835 + return ITERATOR_CONT;
7838 +static int mipv6_halist_gc(int type)
7841 + hashlist_iterate(home_agents.entries, &type, gc_iterator);
7845 +static void mipv6_halist_expire(unsigned long dummy)
7849 + write_lock(&home_agents_lock);
7850 + mipv6_halist_gc(0);
7851 + write_unlock(&home_agents_lock);
7855 +static struct mipv6_halist_entry *mipv6_halist_new_entry(void)
7857 + struct mipv6_halist_entry *entry;
7861 + entry = hashlist_alloc(home_agents.entries, SLAB_ATOMIC);
7869 + * mipv6_halist_add - Add new home agent to the Home Agents List
7870 + * @ifindex: interface identifier
7871 + * @glob_addr: home agent's global address
7872 + * @ll_addr: home agent's link-local address
7873 + * @pref: relative preference for this home agent
7874 + * @lifetime: lifetime for the entry
7876 + * Adds new home agent to the Home Agents List. The list is interface
7877 + * specific and @ifindex tells through which interface the home agent
7878 + * was heard. Returns zero on success and negative on failure.
7881 +int mipv6_halist_add(int ifindex, struct in6_addr *glob_addr, int plen,
7882 + struct in6_addr *ll_addr, unsigned int pref, __u32 lifetime)
7884 + int update = 0, ret = 0;
7885 + unsigned int mpref;
7886 + struct mipv6_halist_entry *entry = NULL;
7890 + write_lock(&home_agents_lock);
7892 + if (glob_addr == NULL || lifetime <= 0) {
7893 + DEBUG(DBG_WARNING, "invalid arguments");
7897 + mpref = PREF_BASE - pref;
7898 + if ((entry = (struct mipv6_halist_entry *)
7899 + hashlist_get(home_agents.entries, glob_addr)) != NULL) {
7900 + if (entry->ifindex == ifindex) {
7901 + DEBUG(DBG_DATADUMP, "updating old entry with address %x:%x:%x:%x:%x:%x:%x:%x", NIPV6ADDR(glob_addr));
7904 + DEBUG(DBG_INFO, "halist_add : adding new entry with address %x:%x:%x:%x:%x:%x:%x:%x", NIPV6ADDR(glob_addr));
7909 + entry->expire = jiffies + lifetime * HZ;
7910 + if (entry->preference != mpref) {
7911 + entry->preference = mpref;
7912 + ret = hashlist_reposition(home_agents.entries,
7913 + (void *)entry, mpref);
7916 + entry = mipv6_halist_new_entry();
7917 + if (entry == NULL) {
7918 + DEBUG(DBG_INFO, "list full");
7922 + entry->ifindex = ifindex;
7924 + ipv6_addr_copy(&entry->link_local_addr, ll_addr);
7925 + mipv6_ha_ac_add(ll_addr, ifindex, glob_addr, plen);
7927 + ipv6_addr_set(&entry->link_local_addr, 0, 0, 0, 0);
7929 + ipv6_addr_copy(&entry->global_addr, glob_addr);
7930 + entry->plen = plen;
7931 + entry->preference = mpref;
7932 + entry->expire = jiffies + lifetime * HZ;
7933 + ret = hashlist_add(home_agents.entries, glob_addr, mpref,
7937 + write_unlock(&home_agents_lock);
7942 + * mipv6_halist_delete - delete home agent from Home Agents List
7943 + * @glob_addr: home agent's global address
7945 + * Deletes entry for home agent @glob_addr from the Home Agent List.
7947 +int mipv6_halist_delete(struct in6_addr *glob_addr)
7949 + struct hashlist_entry *e;
7950 + struct mipv6_halist_entry *entry;
7953 + if (glob_addr == NULL) {
7954 + DEBUG(DBG_WARNING, "invalid glob addr");
7957 + write_lock(&home_agents_lock);
7958 + if ((e = hashlist_get(home_agents.entries, glob_addr)) == NULL) {
7959 + write_unlock(&home_agents_lock);
7962 + hashlist_delete(home_agents.entries, e);
7963 + entry = (struct mipv6_halist_entry *)e;
7964 + if (!ipv6_addr_any(&entry->link_local_addr)) {
7965 + mipv6_ha_ac_del(&entry->link_local_addr, entry->ifindex,
7966 + &entry->global_addr, entry->plen);
7968 + hashlist_free(home_agents.entries, e);
7969 + write_unlock(&home_agents_lock);
7974 + * mipv6_ha_get_pref_list - Get list of preferred home agents
7975 + * @ifindex: interface identifier
7976 + * @addrs: pointer to a buffer to store the list
7977 + * @max: maximum number of home agents to return
7979 + * Creates a list of @max preferred (or all known if less than @max)
7980 + * home agents. Home Agents List is interface specific so you must
7981 + * supply @ifindex. Stores list in addrs and returns number of home
7982 + * agents stored. On failure, returns a negative value.
7984 +int mipv6_ha_get_pref_list(int ifindex, struct in6_addr **addrs, int max)
7986 + struct preflist_iterator_args args;
7995 + args.requested = max;
7996 + args.ifindex = ifindex;
7997 + args.list = kmalloc(max * sizeof(struct in6_addr), GFP_ATOMIC);
7999 + if (args.list == NULL) return -ENOMEM;
8001 + read_lock(&home_agents_lock);
8002 + hashlist_iterate(home_agents.entries, &args, preflist_iterator);
8003 + read_unlock(&home_agents_lock);
8005 + if (args.count >= 0) {
8006 + *addrs = args.list;
8012 + return args.count;
8015 +struct getaddr_iterator_args {
8016 + struct net_device *dev;
8017 + struct in6_addr *addr;
8020 +static int getaddr_iterator(void *data, void *args,
8021 + unsigned long *pref)
8023 + struct mipv6_halist_entry *entry =
8024 + (struct mipv6_halist_entry *)data;
8025 + struct getaddr_iterator_args *state =
8026 + (struct getaddr_iterator_args *)args;
8028 + if (entry->ifindex != state->dev->ifindex)
8029 + return ITERATOR_CONT;
8031 + if (ipv6_chk_addr(&entry->global_addr, state->dev)) {
8032 + ipv6_addr_copy(state->addr, &entry->global_addr);
8033 + return ITERATOR_STOP;
8035 + return ITERATOR_CONT;
8039 + * Get Home Agent Address for given interface. If node is not serving
8040 + * as a HA for this interface returns negative error value.
8042 +int mipv6_ha_get_addr(int ifindex, struct in6_addr *addr)
8044 + struct getaddr_iterator_args args;
8045 + struct net_device *dev;
8050 + if ((dev = dev_get_by_index(ifindex)) == NULL)
8053 + memset(addr, 0, sizeof(struct in6_addr));
8056 + read_lock(&home_agents_lock);
8057 + hashlist_iterate(home_agents.entries, &args, getaddr_iterator);
8058 + read_unlock(&home_agents_lock);
8061 + if (ipv6_addr_any(addr))
8067 +#define HALIST_INFO_LEN 81
8069 +struct procinfo_iterator_args {
8077 +static int procinfo_iterator(void *data, void *args,
8078 + unsigned long *pref)
8080 + struct procinfo_iterator_args *arg =
8081 + (struct procinfo_iterator_args *)args;
8082 + struct mipv6_halist_entry *entry =
8083 + (struct mipv6_halist_entry *)data;
8084 + unsigned long int expire;
8088 + if (entry == NULL) return ITERATOR_ERR;
8090 + if (time_after(jiffies, entry->expire)) {
8091 + if (!ipv6_addr_any(&entry->link_local_addr)) {
8092 + mipv6_ha_ac_del(&entry->link_local_addr,
8094 + &entry->global_addr, entry->plen);
8096 + return ITERATOR_DELETE_ENTRY;
8098 + if (arg->skip < arg->offset / HALIST_INFO_LEN) {
8100 + return ITERATOR_CONT;
8103 + if (arg->len >= arg->length)
8104 + return ITERATOR_CONT;
8106 + expire = (entry->expire - jiffies) / HZ;
8108 + arg->len += sprintf(arg->buffer + arg->len,
8109 + "%02d %08x%08x%08x%08x %08x%08x%08x%08x %05ld %05ld\n",
8111 + ntohl(entry->global_addr.s6_addr32[0]),
8112 + ntohl(entry->global_addr.s6_addr32[1]),
8113 + ntohl(entry->global_addr.s6_addr32[2]),
8114 + ntohl(entry->global_addr.s6_addr32[3]),
8115 + ntohl(entry->link_local_addr.s6_addr32[0]),
8116 + ntohl(entry->link_local_addr.s6_addr32[1]),
8117 + ntohl(entry->link_local_addr.s6_addr32[2]),
8118 + ntohl(entry->link_local_addr.s6_addr32[3]),
8119 + -(entry->preference - PREF_BASE), expire);
8121 + return ITERATOR_CONT;
8124 +static int halist_proc_info(char *buffer, char **start, off_t offset,
8127 + struct procinfo_iterator_args args;
8131 + args.buffer = buffer;
8132 + args.offset = offset;
8133 + args.length = length;
8137 + read_lock_bh(&home_agents_lock);
8138 + hashlist_iterate(home_agents.entries, &args, procinfo_iterator);
8139 + read_unlock_bh(&home_agents_lock);
8143 + *start += offset % HALIST_INFO_LEN;
8145 + args.len -= offset % HALIST_INFO_LEN;
8147 + if (args.len > length)
8148 + args.len = length;
8155 +static int halist_compare(void *data, void *hashkey)
8157 + struct mipv6_halist_entry *e = (struct mipv6_halist_entry *)data;
8158 + struct in6_addr *key = (struct in6_addr *)hashkey;
8160 + return ipv6_addr_cmp(&e->global_addr, key);
8163 +static __u32 halist_hash(void *hashkey)
8165 + struct in6_addr *key = (struct in6_addr *)hashkey;
8168 + hash = key->s6_addr32[0] ^
8169 + key->s6_addr32[1] ^
8170 + key->s6_addr32[2] ^
8171 + key->s6_addr32[3];
8176 +int __init mipv6_halist_init(__u32 size)
8181 + DEBUG(DBG_ERROR, "size must be at least 1");
8184 + init_timer(&home_agents.expire_timer);
8185 + home_agents.expire_timer.data = 0;
8186 + home_agents.expire_timer.function = mipv6_halist_expire;
8187 + home_agents_lock = RW_LOCK_UNLOCKED;
8189 + home_agents.entries = hashlist_create(16, size, sizeof(struct mipv6_halist_entry),
8190 + "mip6_halist", NULL, NULL,
8191 + halist_compare, halist_hash);
8193 + if (home_agents.entries == NULL) {
8194 + DEBUG(DBG_ERROR, "Failed to initialize hashlist");
8198 + proc_net_create("mip6_home_agents", 0, halist_proc_info);
8199 + DEBUG(DBG_INFO, "Home Agents List initialized");
8203 +void __exit mipv6_halist_exit(void)
8206 + proc_net_remove("mip6_home_agents");
8207 + write_lock_bh(&home_agents_lock);
8208 + DEBUG(DBG_INFO, "Stopping the halist timer");
8209 + del_timer(&home_agents.expire_timer);
8210 + mipv6_halist_gc(1);
8211 + write_unlock_bh(&home_agents_lock);
8212 + hashlist_destroy(home_agents.entries);
8214 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/halist.h linux-2.4.25/net/ipv6/mobile_ip6/halist.h
8215 --- linux-2.4.25.old/net/ipv6/mobile_ip6/halist.h 1970-01-01 01:00:00.000000000 +0100
8216 +++ linux-2.4.25/net/ipv6/mobile_ip6/halist.h 2004-06-26 11:29:30.000000000 +0100
8219 + * MIPL Mobile IPv6 Home Agents List header file
8223 + * This program is free software; you can redistribute it and/or
8224 + * modify it under the terms of the GNU General Public License
8225 + * as published by the Free Software Foundation; either version
8226 + * 2 of the License, or (at your option) any later version.
8232 +int mipv6_halist_init(__u32 size);
8234 +void mipv6_halist_exit(void);
8236 +int mipv6_halist_add(int ifindex, struct in6_addr *glob_addr, int plen,
8237 + struct in6_addr *ll_addr, unsigned int pref, __u32 lifetime);
8239 +int mipv6_halist_delete(struct in6_addr *glob_addr);
8241 +int mipv6_ha_get_pref_list(int ifindex, struct in6_addr **addrs, int max);
8243 +int mipv6_ha_get_addr(int ifindex, struct in6_addr *addr);
8245 +#endif /* _HALIST_H */
8246 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/hashlist.c linux-2.4.25/net/ipv6/mobile_ip6/hashlist.c
8247 --- linux-2.4.25.old/net/ipv6/mobile_ip6/hashlist.c 1970-01-01 01:00:00.000000000 +0100
8248 +++ linux-2.4.25/net/ipv6/mobile_ip6/hashlist.c 2004-06-26 11:29:31.000000000 +0100
8251 + * Generic hashtable with chaining. Supports secodary sort order
8252 + * with doubly linked-list.
8255 + * Sami Kivisaari <skivisaa@cc.hut.fi>
8256 + * Antti Tuominen <ajtuomin@tml.hut.fi>
8258 + * $Id: s.hashlist.c 1.21 02/10/07 19:31:52+03:00 antti@traci.mipl.mediapoli.com $
8260 + * This program is free software; you can redistribute it and/or
8261 + * modify it under the terms of the GNU General Public License as
8262 + * published by the Free Software Foundation; either version 2 of
8263 + * the License, or (at your option) any later version.
8266 +#include <linux/slab.h>
8267 +#include "hashlist.h"
8271 + int count; /* entry count */
8272 + int maxcount; /* max entries */
8273 + __u32 bucketnum; /* hash buckets */
8275 + kmem_cache_t *kmem;
8277 + struct list_head *hashtable;
8278 + struct list_head sortedlist;
8280 + int (*compare)(void *data, void *hashkey);
8281 + __u32 (*hash_function)(void *hashkey);
8285 + * hashlist_create - Create new hashlist
8286 + * @bucketnum: number of hash buckets
8287 + * @maxentries: maximum number of entries (0 = no limit)
8288 + * @size: entry size in bytes
8289 + * @name: name for kmem_cache_t
8290 + * @ctor: kmem_cache_t constructor
8291 + * @dtor: kmem_cache_t destructor
8292 + * @compare: compare function for key
8293 + * @hash_function: hash function
8295 + * Creates a hashlist structure with @max_entries entries of @size
8296 + * bytes. User must supply @hash_function and @compare function for
8297 + * the hashlist. User can also supply @ctor and @dtor for kmem_cache.
8299 +struct hashlist *hashlist_create(int bucketnum, int max_entries, size_t size,
8301 + void (*ctor)(void *, kmem_cache_t *, unsigned long),
8302 + void (*dtor)(void *, kmem_cache_t *, unsigned long),
8303 + int (*compare)(void *data, void *hashkey),
8304 + __u32 (*hash_function)(void *hashkey))
8307 + struct hashlist *hl;
8309 + if (!compare || !hash_function)
8312 + hl = kmalloc(sizeof(struct hashlist), GFP_ATOMIC);
8313 + if (!hl) goto hlfailed;
8315 + hl->kmem = kmem_cache_create(name, size, 0, 0, ctor, dtor);
8316 + if (!hl->kmem) goto poolfailed;
8318 + hl->hashtable = kmalloc(
8319 + sizeof(struct list_head) * bucketnum, GFP_ATOMIC);
8320 + if (!hl->hashtable) goto hashfailed;
8322 + for (i = 0; i < bucketnum; i++)
8323 + INIT_LIST_HEAD(&hl->hashtable[i]);
8325 + INIT_LIST_HEAD(&hl->sortedlist);
8327 + hl->maxcount = max_entries;
8329 + hl->bucketnum = bucketnum;
8330 + hl->compare = compare;
8331 + hl->hash_function = hash_function;
8336 + kmem_cache_destroy(hl->kmem);
8343 + DEBUG(DBG_ERROR, "could not create hashlist");
8349 + * hashlist_destroy - Destroy hashlist
8350 + * @hashlist: hashlist to destroy
8352 + * Frees all memory allocated for a hashlist.
8354 +void hashlist_destroy(struct hashlist *hashlist)
8358 + if (hashlist == NULL) return;
8360 + if (hashlist->hashtable) {
8361 + kfree(hashlist->hashtable);
8362 + hashlist->hashtable = NULL;
8365 + if (hashlist->kmem) {
8366 + kmem_cache_destroy(hashlist->kmem);
8367 + hashlist->kmem = NULL;
8376 + * Insert a chain of entries to hashlist into correct order. The
8377 + * entries are assumed to have valid hashkeys. We use time_after_eq
8378 + * for comparing, since it handles wrap-around correctly, and the
8379 + * sortkey is usually jiffies.
8381 +static void sorted_insert(struct list_head *lh, struct hashlist_entry *he)
8383 + struct list_head *p;
8384 + struct hashlist_entry *hlp = NULL;
8385 + unsigned long sortkey = he->sortkey;
8387 + if (list_empty(lh)) {
8388 + list_add(&he->sorted, lh);
8392 + list_for_each(p, lh) {
8393 + hlp = list_entry(p, typeof(*hlp), sorted);
8394 + if (time_after_eq(hlp->sortkey, sortkey)) {
8395 + list_add(&he->sorted, hlp->sorted.prev);
8399 + list_add(&he->sorted, &hlp->sorted);
8403 + * hashlist_iterate - Apply function for all elements in a hash list
8404 + * @hashlist: pointer to hashlist
8405 + * @args: data to pass to the function
8406 + * @func: pointer to a function
8408 + * Apply arbitrary function @func to all elements in a hash list.
8409 + * @func must be a pointer to a function with the following prototype:
8410 + * int func(void *entry, void *arg, struct in6_addr *hashkey, unsigned
8411 + * long *sortkey). Function must return %ITERATOR_STOP,
8412 + * %ITERATOR_CONT or %ITERATOR_DELETE_ENTRY. %ITERATOR_STOP stops
8413 + * iterator and returns last return value from the function.
8414 + * %ITERATOR_CONT continues with iteration. %ITERATOR_DELETE_ENTRY
8415 + * deletes current entry from the hashlist. If function changes
8416 + * hashlist element's sortkey, iterator automatically schedules
8417 + * element to be reinserted after all elements have been processed.
8419 +int hashlist_iterate(
8420 + struct hashlist *hashlist, void *args,
8421 + hashlist_iterator_t func)
8423 + int res = ITERATOR_CONT;
8424 + unsigned long skey;
8425 + struct list_head *p, *n, repos;
8426 + struct hashlist_entry *he;
8429 + INIT_LIST_HEAD(&repos);
8431 + list_for_each_safe(p, n, &hashlist->sortedlist) {
8432 + he = list_entry(p, typeof(*he), sorted);
8433 + if (res == ITERATOR_STOP)
8435 + skey = he->sortkey;
8436 + res = func(he, args, &he->sortkey);
8437 + if (res == ITERATOR_DELETE_ENTRY) {
8438 + hashlist_delete(hashlist, he);
8439 + hashlist_free(hashlist, he);
8440 + } else if (skey != he->sortkey) {
8441 + /* iterator changed the sortkey, schedule for
8442 + * repositioning */
8443 + list_move(&he->sorted, &repos);
8446 + list_for_each_safe(p, n, &repos) {
8447 + he = list_entry(p, typeof(*he), sorted);
8448 + sorted_insert(&hashlist->sortedlist, he);
8454 + * hashlist_alloc - Allocate memory for a hashlist entry
8455 + * @hashlist: hashlist for allocated entry
8456 + * @size: size of entry in bytes
8458 + * Allocates @size bytes memory from @hashlist->kmem.
8460 +void *hashlist_alloc(struct hashlist *hashlist, int type)
8462 + if (hashlist == NULL) return NULL;
8463 + return kmem_cache_alloc(hashlist->kmem, type);
8467 + * hashlist_free - Free hashlist entry
8468 + * @hashlist: hashlist where @he is
8469 + * @he: entry to free
8471 + * Frees an allocated hashlist entry.
8473 +void hashlist_free(struct hashlist *hashlist, struct hashlist_entry *he)
8475 + kmem_cache_free(hashlist->kmem, he);
8479 + * hashlist_add - Add element to hashlist
8480 + * @hashlist: pointer to hashlist
8481 + * @hashkey: hashkey for the element
8482 + * @sortkey: key for sorting
8483 + * @data: element data
8485 + * Add element to hashlist. Hashlist is also sorted in a linked list
8488 +int hashlist_add(struct hashlist *hashlist, void *hashkey,
8489 + unsigned long sortkey, void *entry)
8491 + struct hashlist_entry *he = (struct hashlist_entry *)entry;
8492 + unsigned int hash;
8494 + if (hashlist->count >= hashlist->maxcount)
8497 + hashlist->count++;
8499 + /* link the entry to sorted order */
8500 + he->sortkey = sortkey;
8501 + sorted_insert(&hashlist->sortedlist, he);
8503 + /* hash the entry */
8504 + hash = hashlist->hash_function(hashkey) % hashlist->bucketnum;
8505 + list_add(&he->hashlist, &hashlist->hashtable[hash]);
8511 + * hashlist_get_ex - Get element from hashlist
8512 + * @hashlist: hashlist
8513 + * @hashkey: hashkey of the desired entry
8515 + * Lookup entry with @hashkey from the hash table using @compare
8516 + * function for entry comparison. Returns entry on success, otherwise
8519 +struct hashlist_entry *hashlist_get_ex(
8520 + struct hashlist *hashlist, void *hashkey,
8521 + int (*compare)(void *data, void *hashkey))
8523 + struct list_head *p, *bkt;
8526 + hash = hashlist->hash_function(hashkey) % hashlist->bucketnum;
8527 + bkt = &hashlist->hashtable[hash];
8529 + /* scan the entries within the same hashbucket */
8530 + list_for_each(p, bkt) {
8531 + struct hashlist_entry *he = list_entry(p, typeof(*he),
8533 + if (compare(he, hashkey) == 0)
8541 + * hashlist_get - Get element from hashlist
8542 + * @hashlist: hashlist
8543 + * @hashkey: hashkey of the desired entry
8545 + * Lookup entry with @hashkey from the hash table. Returns entry on
8546 + * success, otherwise %NULL.
8548 +struct hashlist_entry *hashlist_get(struct hashlist *hashlist, void *hashkey)
8550 + return hashlist_get_ex(hashlist, hashkey, hashlist->compare);
8554 + * hashlist_reposition - set entry to new position in the list
8555 + * @hashlist: hashlist
8556 + * @he: entry to reposition
8557 + * @sortkey: new sortkey of the entry
8559 + * If secondary order sortkey changes, entry must be repositioned in
8560 + * the sorted list.
8562 +int hashlist_reposition(struct hashlist *hashlist, struct hashlist_entry *he,
8563 + unsigned long sortkey)
8565 + list_del(&he->sorted);
8566 + he->sortkey = sortkey;
8567 + sorted_insert(&hashlist->sortedlist, he);
8573 + * hashlist_delete - Delete entry from hashlist
8574 + * @hashlist: hashlist where entry is
8575 + * @he: entry to delete
8577 + * Deletes an entry from the hashlist and sorted list.
8579 +void hashlist_delete(struct hashlist *hashlist,
8580 + struct hashlist_entry *he)
8582 + list_del_init(&he->hashlist);
8583 + list_del_init(&he->sorted);
8585 + hashlist->count--;
8589 + * hashlist_get_first - Get first item from sorted list
8590 + * @hashlist: pointer to hashlist
8592 + * Returns first item in the secondary sort order.
8594 +void * hashlist_get_first(struct hashlist *hashlist)
8596 + if (list_empty(&hashlist->sortedlist))
8599 + return list_entry(hashlist->sortedlist.next, struct hashlist_entry, sorted);
8601 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/hashlist.h linux-2.4.25/net/ipv6/mobile_ip6/hashlist.h
8602 --- linux-2.4.25.old/net/ipv6/mobile_ip6/hashlist.h 1970-01-01 01:00:00.000000000 +0100
8603 +++ linux-2.4.25/net/ipv6/mobile_ip6/hashlist.h 2004-06-26 11:29:31.000000000 +0100
8606 + * MIPL Mobile IPv6 Hashlist header file
8610 + * This program is free software; you can redistribute it and/or
8611 + * modify it under the terms of the GNU General Public License
8612 + * as published by the Free Software Foundation; either version
8613 + * 2 of the License, or (at your option) any later version.
8616 +#ifndef _HASHLIST_H
8617 +#define _HASHLIST_H
8619 +#define ITERATOR_ERR -1
8620 +#define ITERATOR_CONT 0
8621 +#define ITERATOR_STOP 1
8622 +#define ITERATOR_DELETE_ENTRY 2
8624 +struct kmem_cache_t;
8626 +struct hashlist_entry {
8627 + unsigned long sortkey;
8628 + struct list_head sorted;
8629 + struct list_head hashlist;
8632 +struct hashlist * hashlist_create(
8633 + int bucketnum, int max_entries, size_t size, char *name,
8634 + void (*ctor)(void *, kmem_cache_t *, unsigned long),
8635 + void (*dtor)(void *, kmem_cache_t *, unsigned long),
8636 + int (*compare)(void *data, void *hashkey),
8637 + __u32 (*hash_function)(void *hashkey));
8639 +void hashlist_destroy(struct hashlist *hashlist);
8641 +void *hashlist_alloc(struct hashlist *hashlist, int type);
8643 +void hashlist_free(struct hashlist *hashlist, struct hashlist_entry *he);
8645 +struct hashlist_entry *hashlist_get(struct hashlist *hashlist, void *hashkey);
8647 +struct hashlist_entry *hashlist_get_ex(
8648 + struct hashlist *hashlist, void *hashkey,
8649 + int (*compare)(void *data, void *hashkey));
8651 +int hashlist_add(struct hashlist *hashlist, void *hashkey,
8652 + unsigned long sortkey, void *data);
8654 +void hashlist_delete(struct hashlist *hashlist, struct hashlist_entry *he);
8656 +/* iterator function */
8657 +typedef int (*hashlist_iterator_t)(void *, void *, unsigned long *);
8659 +int hashlist_iterate(struct hashlist *hashlist, void *args,
8660 + hashlist_iterator_t func);
8662 +void * hashlist_get_first(struct hashlist *hashlist);
8664 +int hashlist_reposition(struct hashlist *hashlist, struct hashlist_entry *he,
8665 + unsigned long sortkey);
8668 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/hmac.c linux-2.4.25/net/ipv6/mobile_ip6/hmac.c
8669 --- linux-2.4.25.old/net/ipv6/mobile_ip6/hmac.c 1970-01-01 01:00:00.000000000 +0100
8670 +++ linux-2.4.25/net/ipv6/mobile_ip6/hmac.c 2004-06-26 11:29:31.000000000 +0100
8672 +/* Authentication algorithms
8675 + * Alexis Olivereau <Alexis.Olivereau@crm.mot.com>
8679 + * This program is free software; you can redistribute it and/or
8680 + * modify it under the terms of the GNU General Public License
8681 + * as published by the Free Software Foundation; either version
8682 + * 2 of the License, or (at your option) any later version.
8685 + * Henrik Petander : Cleaned up unused parts
8689 +#include <linux/sched.h>
8690 +#include <linux/tty.h>
8691 +#include <linux/types.h>
8692 +#include <linux/slab.h>
8693 +#include <linux/in6.h>
8696 +#define LROLL(x, s) (((x) << (s)) | ((x) >> (32 - (s))))
8699 +#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
8700 +#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
8701 +#define H(x, y, z) ((x) ^ (y) ^ (z))
8702 +#define I(x, y, z) ((y) ^ ((x) | ~(z)))
8704 +#define FF(a, b, c, d, m, s, t) { \
8705 + (a) += F ((b), (c), (d)) + (m) + (t); \
8706 + (a) = LROLL((a), (s)); \
8709 +#define GG(a, b, c, d, m, s, t) { \
8710 + (a) += G ((b), (c), (d)) + (m) + (t); \
8711 + (a) = LROLL((a), (s)); \
8714 +#define HH(a, b, c, d, m, s, t) { \
8715 + (a) += H ((b), (c), (d)) + (m) + (t); \
8716 + (a) = LROLL((a), (s)); \
8719 +#define II(a, b, c, d, m, s, t) { \
8720 + (a) += I ((b), (c), (d)) + (m) + (t); \
8721 + (a) = LROLL((a), (s)); \
8743 +#define f(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
8744 +#define g(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
8745 +#define h(x, y, z) ((x) ^ (y) ^ (z))
8747 +#define K1 0x5a827999
8748 +#define K2 0x6ed9eba1
8749 +#define K3 0x8f1bbcdc
8750 +#define K4 0xca62c1d6
8752 +int ah_hmac_md5_init(struct ah_processing *ahp, u_int8_t *key, u_int32_t key_len)
8756 + uint32_t ipad = 0x36363636;
8757 + uint8_t extkey[64];
8759 + ahp->key_auth = key;
8760 + ahp->key_auth_len = key_len;
8761 + ahp->context = (void *) kmalloc(sizeof(MD5_CTX), GFP_ATOMIC);
8762 + if (ahp->context == NULL)
8764 + md5_init((MD5_CTX *) ahp->context);
8765 + if ((64 * sizeof(uint8_t)) < ahp->key_auth_len) {
8766 + printk("buffer overflow!");
8769 + memcpy(extkey, ahp->key_auth, ahp->key_auth_len);
8770 + if (ahp->key_auth_len % 4) {
8771 + memset(extkey + ahp->key_auth_len, 0,
8772 + 4 - (ahp->key_auth_len % 4));
8774 + key_up4 = ((ahp->key_auth_len + 0x3) & 0xFFFFFFFC) / 4;
8776 + for (i = 0; i < key_up4; i++)
8777 + ((uint32_t *) extkey)[i] = ((uint32_t *) extkey)[i] ^ ipad;
8778 + for (i = key_up4; i < 16; i++)
8779 + ((uint32_t *) extkey)[i] = ipad;
8781 + md5_compute((MD5_CTX *) ahp->context, extkey, 64);
8785 +void ah_hmac_md5_loop(struct ah_processing *ahp, void *str, uint32_t len)
8787 + md5_compute((MD5_CTX *) ahp->context, str, len);
8790 +void ah_hmac_md5_result(struct ah_processing *ahp, char *digest)
8792 + uint8_t inner[HMAC_MD5_HASH_LEN];
8795 + uint32_t opad = 0x5c5c5c5c;
8796 + uint8_t extkey[64];
8798 + md5_final((MD5_CTX *) ahp->context, inner);
8799 + md5_init((MD5_CTX *) ahp->context);
8801 + memcpy(extkey, ahp->key_auth, ahp->key_auth_len);
8802 + if (ahp->key_auth_len % 4) {
8803 + memset(extkey + ahp->key_auth_len, 0,
8804 + 4 - (ahp->key_auth_len % 4));
8806 + key_up4 = ((ahp->key_auth_len + 0x3) & 0xFFFFFFFC) / 4;
8808 + for (i = 0; i < key_up4; i++)
8809 + ((uint32_t *) extkey)[i] = ((uint32_t *) extkey)[i] ^ opad;
8810 + for (i = key_up4; i < 16; i++)
8811 + ((uint32_t *) extkey)[i] = opad;
8813 + md5_compute((MD5_CTX *) ahp->context, extkey, 64);
8814 + md5_compute((MD5_CTX *) ahp->context, inner, HMAC_MD5_HASH_LEN);
8816 + md5_final((MD5_CTX *) ahp->context, digest);
8818 + kfree(ahp->context);
8821 +int ah_hmac_sha1_init(struct ah_processing *ahp, u_int8_t *key, u_int32_t key_len)
8825 + uint32_t ipad = 0x36363636;
8826 + uint8_t extkey[64];
8828 + ahp->key_auth = key;
8829 + ahp->key_auth_len = key_len;
8831 + ahp->context = (void *) kmalloc(sizeof(SHA1_CTX), GFP_ATOMIC);
8832 + //if (ahp->context == NULL)
8835 + sha1_init((SHA1_CTX *) ahp->context);
8837 + memcpy(extkey, ahp->key_auth, ahp->key_auth_len);
8838 + if (ahp->key_auth_len % 4) {
8839 + memset(extkey + ahp->key_auth_len, 0,
8840 + 4 - (ahp->key_auth_len % 4));
8842 + key_up4 = ((ahp->key_auth_len + 0x3) & 0xFFFFFFFC) / 4;
8844 + for (i = 0; i < key_up4; i++)
8845 + ((uint32_t *) extkey)[i] = ((uint32_t *) extkey)[i] ^ ipad;
8846 + for (i = key_up4; i < 16; i++)
8847 + ((uint32_t *) extkey)[i] = ipad;
8849 + sha1_compute((SHA1_CTX *) ahp->context, extkey, 64);
8853 +void ah_hmac_sha1_loop(struct ah_processing *ahp, void *str, uint32_t len)
8857 + sha1_compute((SHA1_CTX *) ahp->context, str, len);
8860 +void ah_hmac_sha1_result(struct ah_processing *ahp, char *digest)
8862 + uint8_t inner[HMAC_SHA1_HASH_LEN];
8865 + uint32_t opad = 0x5c5c5c5c;
8866 + uint8_t extkey[64];
8870 + sha1_final((SHA1_CTX *) ahp->context, inner);
8871 + sha1_init((SHA1_CTX *) ahp->context);
8873 + memcpy(extkey, ahp->key_auth, ahp->key_auth_len);
8874 + if (ahp->key_auth_len % 4) {
8875 + memset(extkey + ahp->key_auth_len, 0,
8876 + 4 - (ahp->key_auth_len % 4));
8878 + key_up4 = ((ahp->key_auth_len + 0x3) & 0xFFFFFFFC) / 4;
8880 + for (i = 0; i < key_up4; i++)
8881 + ((uint32_t *) extkey)[i] = ((uint32_t *) extkey)[i] ^ opad;
8882 + for (i = key_up4; i < 16; i++)
8883 + ((uint32_t *) extkey)[i] = opad;
8885 + sha1_compute((SHA1_CTX *) ahp->context, extkey, 64);
8886 + sha1_compute((SHA1_CTX *) ahp->context, inner,
8887 + HMAC_SHA1_HASH_LEN);
8889 + sha1_final((SHA1_CTX *) ahp->context, digest);
8891 + kfree(ahp->context);
8894 +void md5_init(MD5_CTX * ctx)
8896 + ctx->A = 0x67452301;
8897 + ctx->B = 0xefcdab89;
8898 + ctx->C = 0x98badcfe;
8899 + ctx->D = 0x10325476;
8900 + ctx->buf_cur = ctx->buf;
8901 + ctx->bitlen[0] = ctx->bitlen[1] = 0;
8902 + memset(ctx->buf, 0, 64);
8905 +void md5_over_block(MD5_CTX * ctx, uint8_t * data)
8908 + uint32_t a = ctx->A;
8909 + uint32_t b = ctx->B;
8910 + uint32_t c = ctx->C;
8911 + uint32_t d = ctx->D;
8913 + create_M_blocks(M, data);
8916 + FF(a, b, c, d, M[0], s11, 0xd76aa478); /* 1 */
8917 + FF(d, a, b, c, M[1], s12, 0xe8c7b756); /* 2 */
8918 + FF(c, d, a, b, M[2], s13, 0x242070db); /* 3 */
8919 + FF(b, c, d, a, M[3], s14, 0xc1bdceee); /* 4 */
8920 + FF(a, b, c, d, M[4], s11, 0xf57c0faf); /* 5 */
8921 + FF(d, a, b, c, M[5], s12, 0x4787c62a); /* 6 */
8922 + FF(c, d, a, b, M[6], s13, 0xa8304613); /* 7 */
8923 + FF(b, c, d, a, M[7], s14, 0xfd469501); /* 8 */
8924 + FF(a, b, c, d, M[8], s11, 0x698098d8); /* 9 */
8925 + FF(d, a, b, c, M[9], s12, 0x8b44f7af); /* 10 */
8926 + FF(c, d, a, b, M[10], s13, 0xffff5bb1); /* 11 */
8927 + FF(b, c, d, a, M[11], s14, 0x895cd7be); /* 12 */
8928 + FF(a, b, c, d, M[12], s11, 0x6b901122); /* 13 */
8929 + FF(d, a, b, c, M[13], s12, 0xfd987193); /* 14 */
8930 + FF(c, d, a, b, M[14], s13, 0xa679438e); /* 15 */
8931 + FF(b, c, d, a, M[15], s14, 0x49b40821); /* 16 */
8934 + GG(a, b, c, d, M[1], s21, 0xf61e2562); /* 17 */
8935 + GG(d, a, b, c, M[6], s22, 0xc040b340); /* 18 */
8936 + GG(c, d, a, b, M[11], s23, 0x265e5a51); /* 19 */
8937 + GG(b, c, d, a, M[0], s24, 0xe9b6c7aa); /* 20 */
8938 + GG(a, b, c, d, M[5], s21, 0xd62f105d); /* 21 */
8939 + GG(d, a, b, c, M[10], s22, 0x02441453); /* 22 */
8940 + GG(c, d, a, b, M[15], s23, 0xd8a1e681); /* 23 */
8941 + GG(b, c, d, a, M[4], s24, 0xe7d3fbc8); /* 24 */
8942 + GG(a, b, c, d, M[9], s21, 0x21e1cde6); /* 25 */
8943 + GG(d, a, b, c, M[14], s22, 0xc33707d6); /* 26 */
8944 + GG(c, d, a, b, M[3], s23, 0xf4d50d87); /* 27 */
8945 + GG(b, c, d, a, M[8], s24, 0x455a14ed); /* 28 */
8946 + GG(a, b, c, d, M[13], s21, 0xa9e3e905); /* 29 */
8947 + GG(d, a, b, c, M[2], s22, 0xfcefa3f8); /* 30 */
8948 + GG(c, d, a, b, M[7], s23, 0x676f02d9); /* 31 */
8949 + GG(b, c, d, a, M[12], s24, 0x8d2a4c8a); /* 32 */
8952 + HH(a, b, c, d, M[5], s31, 0xfffa3942); /* 33 */
8953 + HH(d, a, b, c, M[8], s32, 0x8771f681); /* 34 */
8954 + HH(c, d, a, b, M[11], s33, 0x6d9d6122); /* 35 */
8955 + HH(b, c, d, a, M[14], s34, 0xfde5380c); /* 36 */
8956 + HH(a, b, c, d, M[1], s31, 0xa4beea44); /* 37 */
8957 + HH(d, a, b, c, M[4], s32, 0x4bdecfa9); /* 38 */
8958 + HH(c, d, a, b, M[7], s33, 0xf6bb4b60); /* 39 */
8959 + HH(b, c, d, a, M[10], s34, 0xbebfbc70); /* 40 */
8960 + HH(a, b, c, d, M[13], s31, 0x289b7ec6); /* 41 */
8961 + HH(d, a, b, c, M[0], s32, 0xeaa127fa); /* 42 */
8962 + HH(c, d, a, b, M[3], s33, 0xd4ef3085); /* 43 */
8963 + HH(b, c, d, a, M[6], s34, 0x4881d05); /* 44 */
8964 + HH(a, b, c, d, M[9], s31, 0xd9d4d039); /* 45 */
8965 + HH(d, a, b, c, M[12], s32, 0xe6db99e5); /* 46 */
8966 + HH(c, d, a, b, M[15], s33, 0x1fa27cf8); /* 47 */
8967 + HH(b, c, d, a, M[2], s34, 0xc4ac5665); /* 48 */
8970 + II(a, b, c, d, M[0], s41, 0xf4292244); /* 49 */
8971 + II(d, a, b, c, M[7], s42, 0x432aff97); /* 50 */
8972 + II(c, d, a, b, M[14], s43, 0xab9423a7); /* 51 */
8973 + II(b, c, d, a, M[5], s44, 0xfc93a039); /* 52 */
8974 + II(a, b, c, d, M[12], s41, 0x655b59c3); /* 53 */
8975 + II(d, a, b, c, M[3], s42, 0x8f0ccc92); /* 54 */
8976 + II(c, d, a, b, M[10], s43, 0xffeff47d); /* 55 */
8977 + II(b, c, d, a, M[1], s44, 0x85845dd1); /* 56 */
8978 + II(a, b, c, d, M[8], s41, 0x6fa87e4f); /* 57 */
8979 + II(d, a, b, c, M[15], s42, 0xfe2ce6e0); /* 58 */
8980 + II(c, d, a, b, M[6], s43, 0xa3014314); /* 59 */
8981 + II(b, c, d, a, M[13], s44, 0x4e0811a1); /* 60 */
8982 + II(a, b, c, d, M[4], s41, 0xf7537e82); /* 61 */
8983 + II(d, a, b, c, M[11], s42, 0xbd3af235); /* 62 */
8984 + II(c, d, a, b, M[2], s43, 0x2ad7d2bb); /* 63 */
8985 + II(b, c, d, a, M[9], s44, 0xeb86d391); /* 64 */
8993 +void create_M_blocks(uint32_t * M, uint8_t * data)
8995 +#ifdef HAVE_LITTLE_ENDIAN
8996 + memcpy((uint8_t *) M, data, 64);
8997 +#endif /* HAVE_LITTLE_ENDIAN */
8999 +#ifdef HAVE_BIG_ENDIAN
9001 + for (i = 0; i < 16; i++, data += 4) {
9002 + ((uint8_t *) (&M[i]))[0] = data[3];
9003 + ((uint8_t *) (&M[i]))[1] = data[2];
9004 + ((uint8_t *) (&M[i]))[2] = data[1];
9005 + ((uint8_t *) (&M[i]))[3] = data[0];
9007 +#endif /* HAVE_BIG_ENDIAN */
9010 +void md5_compute(MD5_CTX * ctx, uint8_t * data, uint32_t len)
9012 + uint8_t pos = ((ctx->bitlen[0] >> 3) & 0x3f);
9014 + /* First we update the bit length */
9015 + if ((ctx->bitlen[0] += (len << 3)) < (len << 3))
9017 + ctx->bitlen[1] += (len >> 29); /* len is expressed in bytes */
9020 + /* Buffer is not empty */
9021 + if (64 - pos >= len) {
9022 + memcpy(ctx->buf_cur, data, len);
9023 + ctx->buf_cur += len;
9026 + /* The current block is over */
9027 + md5_over_block(ctx, ctx->buf);
9028 + ctx->buf_cur = ctx->buf;
9032 + memcpy(ctx->buf_cur, data, 64 - pos);
9033 + md5_over_block(ctx, ctx->buf);
9034 + len -= (64 - pos);
9035 + data += (64 - pos);
9036 + ctx->buf_cur = ctx->buf;
9039 + while (len >= 64) {
9040 + md5_over_block(ctx, data);
9045 + memcpy(ctx->buf_cur, data, len);
9046 + ctx->buf_cur += len;
9050 +void md5_final(MD5_CTX * ctx, uint8_t * digest)
9052 + uint32_t rem_size;
9053 + uint8_t *buf_cur = ctx->buf_cur;
9056 + rem_size = 64 - ((ctx->bitlen[0] >> 3) & 0x3f);
9057 + *(buf_cur++) = 0x80;
9059 + if (rem_size > 8 + 1) {
9060 + /* We have enough room in the current block */
9061 + for (i = 0; i < rem_size - 8 - 1; i++) {
9065 + /* We do not have enough room and need therefore to add a new
9067 + for (i = 0; i < rem_size - 1; i++) {
9070 + md5_over_block(ctx, ctx->buf);
9072 + buf_cur = ctx->buf;
9073 + for (i = 0; i < 64 - 8; i++) {
9077 +#ifdef HAVE_LITTLE_ENDIAN
9078 + memcpy(buf_cur, (uint8_t *) ctx->bitlen, 8);
9079 +#endif /* HAVE_LITTLE_ENDIAN */
9081 +#ifdef HAVE_BIG_ENDIAN
9082 + *(buf_cur++) = (ctx->bitlen[0] >> 24) & 0xff;
9083 + *(buf_cur++) = (ctx->bitlen[0] >> 16) & 0xff;
9084 + *(buf_cur++) = (ctx->bitlen[0] >> 8) & 0xff;
9085 + *(buf_cur++) = (ctx->bitlen[0] >> 0) & 0xff;
9086 + *(buf_cur++) = (ctx->bitlen[1] >> 24) & 0xff;
9087 + *(buf_cur++) = (ctx->bitlen[1] >> 16) & 0xff;
9088 + *(buf_cur++) = (ctx->bitlen[1] >> 8) & 0xff;
9089 + *(buf_cur++) = (ctx->bitlen[1] >> 0) & 0xff;
9090 +#endif /* HAVE_BIG_ENDIAN */
9092 + md5_over_block(ctx, ctx->buf);
9094 +#ifdef HAVE_LITTLE_ENDIAN
9095 + memcpy(digest + 0, (uint8_t *) (&(ctx->A)), sizeof(uint32_t));
9096 + memcpy(digest + 4, (uint8_t *) (&(ctx->B)), sizeof(uint32_t));
9097 + memcpy(digest + 8, (uint8_t *) (&(ctx->C)), sizeof(uint32_t));
9098 + memcpy(digest + 12, (uint8_t *) (&(ctx->D)), sizeof(uint32_t));
9099 +#endif /* HAVE_LITTLE_ENDIAN */
9101 +#ifdef HAVE_BIG_ENDIAN
9102 + digest[0] = ((ctx->A) >> 24) & 0xff;
9103 + digest[1] = ((ctx->A) >> 16) & 0xff;
9104 + digest[2] = ((ctx->A) >> 8) & 0xff;
9105 + digest[3] = ((ctx->A) >> 0) & 0xff;
9106 + digest[4] = ((ctx->B) >> 24) & 0xff;
9107 + digest[5] = ((ctx->B) >> 16) & 0xff;
9108 + digest[6] = ((ctx->B) >> 8) & 0xff;
9109 + digest[7] = ((ctx->B) >> 0) & 0xff;
9110 + digest[8] = ((ctx->C) >> 24) & 0xff;
9111 + digest[9] = ((ctx->C) >> 16) & 0xff;
9112 + digest[10] = ((ctx->C) >> 8) & 0xff;
9113 + digest[11] = ((ctx->C) >> 0) & 0xff;
9114 + digest[12] = ((ctx->D) >> 24) & 0xff;
9115 + digest[13] = ((ctx->D) >> 16) & 0xff;
9116 + digest[14] = ((ctx->D) >> 8) & 0xff;
9117 + digest[15] = ((ctx->D) >> 0) & 0xff;
9118 +#endif /* HAVE_BIG_ENDIAN */
9121 +void sha1_init(SHA1_CTX * ctx)
9123 + ctx->A = 0x67452301;
9124 + ctx->B = 0xefcdab89;
9125 + ctx->C = 0x98badcfe;
9126 + ctx->D = 0x10325476;
9127 + ctx->E = 0xc3d2e1f0;
9128 + ctx->buf_cur = ctx->buf;
9129 + ctx->bitlen[0] = ctx->bitlen[1] = 0;
9130 + memset(ctx->buf, 0, 64);
9133 +void sha1_over_block(SHA1_CTX * ctx, uint8_t * data)
9137 + uint32_t a = ctx->A;
9138 + uint32_t b = ctx->B;
9139 + uint32_t c = ctx->C;
9140 + uint32_t d = ctx->D;
9141 + uint32_t e = ctx->E;
9144 + create_W_blocks(W, data);
9147 + for (i = 0; i < 20; i++) {
9148 + temp = LROLL(a, 5) + f(b, c, d) + e + W[i] + K1;
9157 + for (i = 20; i < 40; i++) {
9158 + temp = LROLL(a, 5) + h(b, c, d) + e + W[i] + K2;
9167 + for (i = 40; i < 60; i++) {
9168 + temp = LROLL(a, 5) + g(b, c, d) + e + W[i] + K3;
9177 + for (i = 60; i < 80; i++) {
9178 + temp = LROLL(a, 5) + h(b, c, d) + e + W[i] + K4;
9193 +void create_W_blocks(uint32_t * W, uint8_t * data)
9197 +#ifdef HAVE_BIG_ENDIAN
9198 + memcpy((uint8_t *) W, data, 64);
9199 +#endif /* HAVE_BIG_ENDIAN */
9201 +#ifdef HAVE_LITTLE_ENDIAN
9202 + for (i = 0; i < 16; i++, data += 4) {
9203 + ((uint8_t *) (&W[i]))[0] = data[3];
9204 + ((uint8_t *) (&W[i]))[1] = data[2];
9205 + ((uint8_t *) (&W[i]))[2] = data[1];
9206 + ((uint8_t *) (&W[i]))[3] = data[0];
9208 +#endif /* HAVE_LITTLE_ENDIAN */
9209 + for (i = 16; i < 80; i++) {
9210 + W[i] = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16];
9211 + W[i] = LROLL(W[i], 1);
9215 +void sha1_compute(SHA1_CTX * ctx, uint8_t * data, uint32_t len)
9217 + uint8_t pos = ((ctx->bitlen[0] >> 3) & 0x3f);
9219 + /* First we update the bit length */
9220 + if ((ctx->bitlen[0] += (len << 3)) < (len << 3))
9222 + ctx->bitlen[1] += (len >> 29); /* len is expressed in bytes */
9225 + /* Buffer is not empty */
9226 + if (64 - pos >= len) {
9227 + memcpy(ctx->buf_cur, data, len);
9228 + ctx->buf_cur += len;
9231 + /* The current block is over */
9232 + sha1_over_block(ctx, ctx->buf);
9233 + ctx->buf_cur = ctx->buf;
9237 + memcpy(ctx->buf_cur, data, 64 - pos);
9238 + sha1_over_block(ctx, ctx->buf);
9239 + len -= (64 - pos);
9240 + data += (64 - pos);
9241 + ctx->buf_cur = ctx->buf;
9244 + while (len >= 64) {
9245 + sha1_over_block(ctx, data);
9250 + memcpy(ctx->buf_cur, data, len);
9251 + ctx->buf_cur += len;
9255 +void sha1_final(SHA1_CTX * ctx, uint8_t * digest)
9257 + uint32_t rem_size;
9258 + uint8_t *buf_cur = ctx->buf_cur;
9261 + rem_size = 64 - ((ctx->bitlen[0] >> 3) & 0x3f);
9262 + *(buf_cur++) = 0x80;
9264 + if (rem_size > 8 + 1) {
9265 + /* We have enough room in the current block */
9266 + for (i = 0; i < rem_size - 8 - 1; i++) {
9270 + /* We do not have enough room and need therefore to add a new
9272 + for (i = 0; i < rem_size - 1; i++) {
9275 + sha1_over_block(ctx, ctx->buf);
9277 + buf_cur = ctx->buf;
9278 + for (i = 0; i < 64 - 8; i++) {
9282 +#ifdef HAVE_BIG_ENDIAN
9283 + memcpy(buf_cur, (uint8_t *) ctx->bitlen, 8);
9284 +#endif /* HAVE_BIG_ENDIAN */
9286 +#ifdef HAVE_LITTLE_ENDIAN
9287 + *(buf_cur++) = (ctx->bitlen[1] >> 24) & 0xff;
9288 + *(buf_cur++) = (ctx->bitlen[1] >> 16) & 0xff;
9289 + *(buf_cur++) = (ctx->bitlen[1] >> 8) & 0xff;
9290 + *(buf_cur++) = (ctx->bitlen[1] >> 0) & 0xff;
9291 + *(buf_cur++) = (ctx->bitlen[0] >> 24) & 0xff;
9292 + *(buf_cur++) = (ctx->bitlen[0] >> 16) & 0xff;
9293 + *(buf_cur++) = (ctx->bitlen[0] >> 8) & 0xff;
9294 + *(buf_cur++) = (ctx->bitlen[0] >> 0) & 0xff;
9295 +#endif /* HAVE_LITTLE_ENDIAN */
9297 + sha1_over_block(ctx, ctx->buf);
9299 +#ifdef HAVE_BIG_ENDIAN
9300 + memcpy(digest + 0, (uint8_t *) (&(ctx->A)), sizeof(uint32_t));
9301 + memcpy(digest + 4, (uint8_t *) (&(ctx->B)), sizeof(uint32_t));
9302 + memcpy(digest + 8, (uint8_t *) (&(ctx->C)), sizeof(uint32_t));
9303 + memcpy(digest + 12, (uint8_t *) (&(ctx->D)), sizeof(uint32_t));
9304 + memcpy(digest + 16, (uint8_t *) (&(ctx->E)), sizeof(uint32_t));
9305 +#endif /* HAVE_BIG_ENDIAN */
9307 +#ifdef HAVE_LITTLE_ENDIAN
9308 + digest[0] = ((ctx->A) >> 24) & 0xff;
9309 + digest[1] = ((ctx->A) >> 16) & 0xff;
9310 + digest[2] = ((ctx->A) >> 8) & 0xff;
9311 + digest[3] = ((ctx->A) >> 0) & 0xff;
9312 + digest[4] = ((ctx->B) >> 24) & 0xff;
9313 + digest[5] = ((ctx->B) >> 16) & 0xff;
9314 + digest[6] = ((ctx->B) >> 8) & 0xff;
9315 + digest[7] = ((ctx->B) >> 0) & 0xff;
9316 + digest[8] = ((ctx->C) >> 24) & 0xff;
9317 + digest[9] = ((ctx->C) >> 16) & 0xff;
9318 + digest[10] = ((ctx->C) >> 8) & 0xff;
9319 + digest[11] = ((ctx->C) >> 0) & 0xff;
9320 + digest[12] = ((ctx->D) >> 24) & 0xff;
9321 + digest[13] = ((ctx->D) >> 16) & 0xff;
9322 + digest[14] = ((ctx->D) >> 8) & 0xff;
9323 + digest[15] = ((ctx->D) >> 0) & 0xff;
9324 + digest[16] = ((ctx->E) >> 24) & 0xff;
9325 + digest[17] = ((ctx->E) >> 16) & 0xff;
9326 + digest[18] = ((ctx->E) >> 8) & 0xff;
9327 + digest[19] = ((ctx->E) >> 0) & 0xff;
9328 +#endif /* HAVE_LITTLE_ENDIAN */
9330 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/hmac.h linux-2.4.25/net/ipv6/mobile_ip6/hmac.h
9331 --- linux-2.4.25.old/net/ipv6/mobile_ip6/hmac.h 1970-01-01 01:00:00.000000000 +0100
9332 +++ linux-2.4.25/net/ipv6/mobile_ip6/hmac.h 2004-06-26 11:29:31.000000000 +0100
9335 + * MIPL Mobile IPv6 Message authentication algorithms
9339 + * This program is free software; you can redistribute it and/or
9340 + * modify it under the terms of the GNU General Public License
9341 + * as published by the Free Software Foundation; either version
9342 + * 2 of the License, or (at your option) any later version.
9348 +#include <linux/types.h>
9349 +#include <linux/in6.h>
9351 +#define HAVE_LITTLE_ENDIAN
9353 +#define NO_EXPIRY 1 /* For sec_as */
9355 +#define ALG_AUTH_NONE 0
9356 +#define ALG_AUTH_HMAC_MD5 1
9357 +#define ALG_AUTH_HMAC_SHA1 2
9360 +struct ah_processing {
9362 + struct sec_as *sas;
9363 + u_int8_t *key_auth;
9364 + u_int32_t key_auth_len;
9367 +struct antireplay {
9373 + u_int32_t A, B, C, D;
9374 + u_int32_t bitlen[2];
9375 + u_int8_t* buf_cur;
9380 + u_int32_t A, B, C, D, E;
9381 + u_int32_t bitlen[2];
9382 + u_int8_t* buf_cur;
9388 +int ah_hmac_md5_init (struct ah_processing *ahp, u_int8_t *key, u_int32_t key_len);
9389 +void ah_hmac_md5_loop(struct ah_processing*, void*, u_int32_t);
9390 +void ah_hmac_md5_result(struct ah_processing*, char*);
9391 +int ah_hmac_sha1_init(struct ah_processing*, u_int8_t *key, u_int32_t key_len);
9392 +void ah_hmac_sha1_loop(struct ah_processing*, void*, u_int32_t);
9393 +void ah_hmac_sha1_result(struct ah_processing*, char*);
9396 +#define AH_HDR_LEN 12 /* # of bytes for Next Header, Payload Length,
9397 + RESERVED, Security Parameters Index and
9399 + Sequence Number Field */
9401 +void md5_init(MD5_CTX *ctx);
9402 +void md5_over_block(MD5_CTX *ctx, u_int8_t* data);
9403 +void create_M_blocks(u_int32_t* M, u_int8_t* data);
9404 +void md5_compute(MD5_CTX *ctx, u_int8_t* data, u_int32_t len);
9405 +void md5_final(MD5_CTX *ctx, u_int8_t* digest);
9407 +void sha1_init(SHA1_CTX *ctx);
9408 +void sha1_over_block(SHA1_CTX *ctx, u_int8_t* data);
9409 +void create_W_blocks(u_int32_t* W, u_int8_t* data);
9410 +void sha1_compute(SHA1_CTX *ctx, u_int8_t* data, u_int32_t len);
9411 +void sha1_final(SHA1_CTX *ctx, u_int8_t* digest);
9414 + struct in6_addr coa;
9415 + struct in6_addr haddr;
9416 + struct in6_addr peer;
9419 +#define MIPV6_MAX_AUTH_DATA 20
9421 +#define HMAC_MD5_HASH_LEN 16
9422 +#define HMAC_SHA1_HASH_LEN 20
9423 +#define HMAC_SHA1_KEY_SIZE 20
9424 +#define HMAC_MD5_ICV_LEN 12 /* RFC 2403 */
9425 +#define HMAC_SHA1_ICV_LEN 12 /* RFC 2404 */
9427 +#endif /* _HMAC_H */
9428 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/ioctl_mn.c linux-2.4.25/net/ipv6/mobile_ip6/ioctl_mn.c
9429 --- linux-2.4.25.old/net/ipv6/mobile_ip6/ioctl_mn.c 1970-01-01 01:00:00.000000000 +0100
9430 +++ linux-2.4.25/net/ipv6/mobile_ip6/ioctl_mn.c 2004-06-26 11:29:31.000000000 +0100
9433 + * Mobile Node IOCTL Control device
9436 + * Henrik Petander <lpetande@tml.hut.fi>
9440 + * This program is free software; you can redistribute it and/or
9441 + * modify it under the terms of the GNU General Public License
9442 + * as published by the Free Software Foundation; either version
9443 + * 2 of the License, or (at your option) any later version.
9446 +#include <linux/config.h>
9447 +#include <linux/module.h>
9448 +#include <linux/fs.h>
9449 +#include <linux/poll.h>
9450 +#include <linux/ioctl.h>
9451 +#include <net/ipv6.h>
9452 +#include <asm/uaccess.h>
9455 +#include "mdetect.h"
9456 +#include "multiaccess_ctl.h"
9458 +/* Reserved for local / experimental use */
9459 +#define MAJOR_NUM 0xf9
9461 +/* Get Care-of address information for Mobile Node */
9462 +#define IOCTL_GET_CAREOFADDR _IOWR(MAJOR_NUM, 9, void *)
9464 +#define MA_IOCTL_SET_IFACE_PREFERENCE _IOR (MAJOR_NUM, 13, void *)
9466 +/* The name of the device file */
9467 +#define CTLFILE "mipv6_dev"
9469 +static int inuse = 0;
9471 +static int mipv6_open(struct inode *inode, struct file *file)
9473 + DEBUG(DBG_INFO, "(%p)\n", file);
9480 + MOD_INC_USE_COUNT;
9485 +static int mipv6_close(struct inode *inode, struct file *file)
9487 + DEBUG(DBG_INFO, "(%p,%p)\n", inode, file);
9490 + MOD_DEC_USE_COUNT;
9495 +int mipv6_ioctl(struct inode *inode, struct file *file,
9496 + unsigned int ioctl_num, /* The number of the ioctl */
9497 + unsigned long arg) /* The parameter to it */
9499 + struct in6_addr careofaddr;
9501 + /* Switch according to the ioctl called */
9502 + switch (ioctl_num) {
9503 + case IOCTL_GET_CAREOFADDR:
9504 + DEBUG(DBG_DATADUMP, "IOCTL_GET_CAREOFADDR");
9505 + /* First get home address from user and then look up
9506 + * the care-of address and return it
9508 + if (copy_from_user(&careofaddr, (struct in6_addr *)arg,
9509 + sizeof(struct in6_addr)) < 0) {
9510 + DEBUG(DBG_WARNING, "Copy from user failed");
9513 + mipv6_get_care_of_address(&careofaddr, &careofaddr);
9514 + if (copy_to_user((struct in6_addr *)arg, &careofaddr,
9515 + sizeof(struct in6_addr)) < 0) {
9516 + DEBUG(DBG_WARNING, "copy_to_user failed");
9520 + case MA_IOCTL_SET_IFACE_PREFERENCE:
9521 + DEBUG(DBG_INFO, "MA_IOCTL_SET_IFACE_PREFERENCE");
9522 + ma_ctl_set_preference(arg);
9526 + DEBUG(DBG_WARNING, "Unknown ioctl cmd (%d)", ioctl_num);
9532 +struct file_operations Fops = {
9533 + owner: THIS_MODULE,
9537 + ioctl: mipv6_ioctl,
9539 + release: mipv6_close
9543 +/* Initialize the module - Register the character device */
9544 +int mipv6_ioctl_mn_init(void)
9548 + /* Register the character device (atleast try) */
9549 + ret_val = register_chrdev(MAJOR_NUM, CTLFILE, &Fops);
9551 + /* Negative values signify an error */
9552 + if (ret_val < 0) {
9553 + DEBUG(DBG_ERROR, "failed registering char device (err=%d)",
9558 + DEBUG(DBG_INFO, "Device number %x, success", MAJOR_NUM);
9563 +/* Cleanup - unregister the appropriate file from /proc */
9564 +void mipv6_ioctl_mn_exit(void)
9567 + /* Unregister the device */
9568 + ret = unregister_chrdev(MAJOR_NUM, CTLFILE);
9570 + /* If there's an error, report it */
9572 + DEBUG(DBG_ERROR, "errorcode: %d\n", ret);
9574 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/mdetect.c linux-2.4.25/net/ipv6/mobile_ip6/mdetect.c
9575 --- linux-2.4.25.old/net/ipv6/mobile_ip6/mdetect.c 1970-01-01 01:00:00.000000000 +0100
9576 +++ linux-2.4.25/net/ipv6/mobile_ip6/mdetect.c 2004-06-26 11:29:31.000000000 +0100
9579 + * Movement Detection Module
9582 + * Henrik Petander <lpetande@cc.hut.fi>
9586 + * This program is free software; you can redistribute it and/or
9587 + * modify it under the terms of the GNU General Public License
9588 + * as published by the Free Software Foundation; either version
9589 + * 2 of the License, or (at your option) any later version.
9591 + * Handles the L3 movement detection of mobile node and also
9592 + * changing of its routes.
9599 + * Nanno Langstraat : Locking fixes
9600 + * Venkata Jagana : Locking fix
9603 +#include <linux/autoconf.h>
9604 +#include <linux/errno.h>
9605 +#include <linux/init.h>
9606 +#include <linux/if_arp.h>
9607 +#include <linux/route.h>
9608 +#include <net/ipv6.h>
9609 +#include <net/ip6_route.h>
9610 +#include <net/addrconf.h>
9611 +#include <net/mipglue.h>
9612 +#ifdef CONFIG_SYSCTL
9613 +#include <linux/sysctl.h>
9614 +#endif /* CONFIG_SYSCTL */
9617 +#include "mdetect.h"
9620 +#include "multiaccess_ctl.h"
9625 +#define DEBUG_MDETECT 7
9627 +#define DEF_RTR_POLL_IVAL 5 /* In seconds */
9630 +#define RTR_SUSPECT 1
9631 +#define CURR_RTR_OK 2
9637 +#define MIPV6_MDF_NONE 0x0
9638 +#define MIPV6_MDF_HAS_RTR_PREV 0x1
9640 +#define ROUTER_REACHABLE 1
9641 +#define RADV_MISSED 2
9642 +#define NOT_REACHABLE 3
9644 +/* R_TIME_OUT paramater is used to make the decision when to change the
9645 + * default router, if the current one is unreachable. 2s is pretty aggressive
9646 + * and may result in hopping between two routers. OTOH a small value enhances
9649 +#define R_TIME_OUT 30*HZ
9651 +/* maximum RA interval for router unreachability detection */
9652 +#define MAX_RADV_INTERVAL 6*HZ /* 6000 ms... */
9654 +/* Threshold for exponential resending of router solicitations */
9655 +#define RS_RESEND_LINEAR 10*HZ
9657 +#define EAGER_CELL_SWITCHING 1
9658 +#define LAZY_CELL_SWITCHING 0
9659 +#define RESPECT_DAD 1
9661 +#define ROUTER_ADDRESS 0x20
9664 +#define ND_RA_FLAG_MANAGED 0x80
9665 +#define ND_RA_FLAG_OTHER 0x40
9666 +#define ND_RA_FLAG_HA 0x20
9668 +/* DAD flags for global and link local addresses */
9670 +#define COA_TENTATIVE 0x10
9671 +#define LLADDR_TENTATIVE 0x01
9674 + struct list_head list;
9675 + struct in6_addr ll_addr;
9676 + struct in6_addr raddr; /* Also contains prefix */
9677 + __u8 link_addr[MAX_ADDR_LEN]; /* link layer address */
9678 + __u8 link_addr_len;
9683 + int pfix_len; /* Length of the network prefix */
9684 + unsigned long lifetime; /* from ra */
9685 + __u32 last_ns_sent;
9686 + __u32 last_ra_rcvd;
9687 + __u32 interval; /* ra interval in milliseconds, 0 if not set */
9688 + int glob_addr; /*Whether raddr contains also routers global address*/
9689 + __u8 flags; /* RA flags, for example ha */
9690 + struct in6_addr CoA; /* care-off address used with this router */
9691 + int extra_addr_route;
9694 +/* dad could also be RESPECT_DAD for duplicate address detection of
9695 + new care-of addresses */
9696 +static int dad = 0;
9698 +/* Only one choice, nothing else implemented */
9699 +int max_rtr_reach_time = DEF_RTR_POLL_IVAL;
9702 +int eager_cell_switching = EAGER_CELL_SWITCHING; /* Can be set to 0 via proc */
9703 +static spinlock_t router_lock;
9704 +static spinlock_t ho_lock;
9706 +static void coa_timer_handler(unsigned long arg);
9707 +static void timer_handler(unsigned long foo);
9708 +static struct router *curr_router = NULL, *next_router = NULL;
9709 +static struct timer_list r_timer = { function: timer_handler };
9710 +static struct timer_list coa_timer = { function: coa_timer_handler };
9711 +#define MAX_ROUTERS 1000
9712 +static LIST_HEAD(rtr_list);
9713 +static int num_routers = 0;
9714 +static struct handoff *_ho = NULL;
9716 + * Functions for handling the default router list, which movement
9717 + * detection uses for avoiding loops etc.
9720 +/* TODO: Send NS to router after MAX interval has passed from last RA */
9721 +static int mipv6_router_state(struct router *rtr) {
9722 + if (rtr->interval) {
9723 + if (time_before(jiffies, (rtr->last_ra_rcvd + (rtr->interval * HZ) / 1000)))
9724 + return ROUTER_REACHABLE;
9726 + return NOT_REACHABLE;
9729 + if (time_after(jiffies, rtr->last_ra_rcvd + (rtr->lifetime * HZ)))
9730 + return NOT_REACHABLE;
9731 + return ROUTER_REACHABLE;
9734 +/* searches for a specific router or any router that is reachable,
9735 + * if address is NULL. Also deletes obsolete routers.
9737 +static void mipv6_router_gc(void)
9739 + struct router *curr = NULL;
9740 + struct list_head *lh, *lh_tmp;
9744 + list_for_each_safe(lh, lh_tmp, &rtr_list) {
9745 + curr = list_entry(lh, struct router, list);
9746 + if (mipv6_router_state(curr) == NOT_REACHABLE && !curr->is_current) {
9748 + list_del_init(&curr->list);
9749 + DEBUG(DBG_DATADUMP, "Deleting unreachable router %x:%x:%x:%x:%x:%x:%x:%x",
9750 + NIPV6ADDR(&curr->raddr));
9754 + DEBUG(DBG_DATADUMP, "NOT Deleting router %x:%x:%x:%x:%x:%x:%x:%x",
9755 + NIPV6ADDR(&curr->raddr));
9760 +static struct router *mipv6_rtr_get(struct in6_addr *search_addr)
9762 + struct router *rtr = NULL;
9763 + struct list_head *lh;
9767 + if (search_addr == NULL)
9769 + list_for_each(lh, &rtr_list) {
9770 + rtr = list_entry(lh, struct router, list);
9771 + if(!ipv6_addr_cmp(search_addr, &rtr->raddr)) {
9779 + * Adds router to list
9781 +static struct router *mipv6_rtr_add(struct router *nrt)
9784 + struct router *rptr;
9788 + /* check if someone is trying DoS attack, or we just have some
9789 + memory leaks... */
9790 + if (num_routers > MAX_ROUTERS) {
9791 + DEBUG(DBG_CRITICAL,
9792 + "failed to add new router, MAX_ROUTERS exceeded");
9796 + rptr = kmalloc(sizeof(struct router), GFP_ATOMIC);
9798 + memcpy(rptr, nrt, sizeof(struct router));
9799 + list_add(&rptr->list, &rtr_list);
9802 + DEBUG(DBG_INFO, "Adding router: %x:%x:%x:%x:%x:%x:%x:%x, "
9803 + "lifetime : %d sec, adv.interval: %d millisec",
9804 + NIPV6ADDR(&rptr->raddr), rptr->lifetime, rptr->interval);
9806 + DEBUG(DBG_INFO, "num_routers after addition: %d", num_routers);
9810 +/* Cleans up the list */
9811 +static void list_free(struct router **curr_router_p)
9813 + struct router *tmp;
9814 + struct list_head *lh, *lh_tmp;
9818 + DEBUG(DBG_INFO, "Freeing the router list");
9819 + /* set curr_router->prev_router and curr_router NULL */
9820 + *curr_router_p = NULL;
9821 + list_for_each_safe(lh, lh_tmp, &rtr_list) {
9822 + tmp = list_entry(lh, struct router, list);
9823 + DEBUG(DBG_INFO, "%x:%x:%x:%x:%x:%x:%x:%x",
9824 + NIPV6ADDR(&tmp->ll_addr));
9825 + list_del(&tmp->list);
9831 +int rs_state = START;
9833 +/* Sends router solicitations to all valid devices
9834 + * source = link local address (of sending interface)
9835 + * dstaddr = all routers multicast address
9836 + * Solicitations are sent at an exponentially decreasing rate
9838 + * TODO: send solicitation first at a normal rate (from ipv6) and
9839 + * after that use the exponentially increasing intervals
9841 +static int rs_send(void)
9843 + struct net_device *dev;
9844 + struct in6_addr raddr, lladdr;
9845 + struct inet6_dev *in6_dev = NULL;
9846 + static int num_rs;
9848 + if (rs_state == START) {
9850 + rs_state = CONTINUE;
9851 + } else if (num_rs++ > MAX_RTR_SOLICITATIONS)
9854 + ipv6_addr_all_routers(&raddr);
9855 + read_lock(&dev_base_lock);
9857 + /* Send router solicitations to all interfaces */
9858 + for (dev = dev_base; dev; dev = dev->next) {
9859 + if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ETHER) {
9860 + DEBUG(DBG_DATADUMP, "Sending RS to device %s",
9862 + if (!ipv6_get_lladdr(dev, &lladdr)) {
9863 + ndisc_send_rs(dev, &lladdr, &raddr);
9864 + in6_dev = in6_dev_get(dev);
9865 + in6_dev->if_flags |= IF_RS_SENT;
9866 + in6_dev_put(in6_dev);
9868 + DEBUG(DBG_DATADUMP, "%s: device doesn't have link-local address!\n", dev->name);
9874 + read_unlock(&dev_base_lock);
9875 + return RTR_SOLICITATION_INTERVAL;
9878 +/* Create a new CoA for MN and also add a route to it if it is still tentative
9879 + to allow MN to get packets to the address immediately
9881 +static int form_coa(struct in6_addr *coa, struct in6_addr *pfix,
9882 + int plen, int ifindex)
9884 + struct net_device *dev;
9885 + struct inet6_dev *in6_dev;
9888 + if ((dev = dev_get_by_index(ifindex)) == NULL) {
9889 + DEBUG(DBG_WARNING, "Device is not present");
9892 + if ((in6_dev = in6_dev_get(dev)) == NULL) {
9893 + DEBUG(DBG_WARNING, "inet6_dev is not present");
9897 + coa->s6_addr32[0] = pfix->s6_addr32[0];
9898 + coa->s6_addr32[1] = pfix->s6_addr32[1];
9900 + if (ipv6_generate_eui64(coa->s6_addr + 8, dev) &&
9901 + ipv6_inherit_eui64(coa->s6_addr + 8, in6_dev)) {
9902 + in6_dev_put(in6_dev);
9906 + if (ipv6_chk_addr(coa, dev) == 0) {
9907 + DEBUG(DBG_WARNING, "care-of address still tentative");
9910 + DEBUG(DBG_INFO, "Formed new CoA: %x:%x:%x:%x:%x:%x:%x:%x",
9913 + in6_dev_put(in6_dev);
9918 +static inline int rtr_is_gw(struct router *rtr, struct rt6_info *rt)
9920 + return ((rt->rt6i_flags & RTF_GATEWAY) &&
9921 + !ipv6_addr_cmp(&rt->rt6i_gateway, &rtr->ll_addr));
9924 +static inline int is_prefix_route(struct router *rtr, struct rt6_info *rt)
9926 + return (!(rt->rt6i_flags & RTF_GATEWAY) &&
9927 + mipv6_prefix_compare(&rt->rt6i_dst.addr, &rtr->raddr,
9932 + * Function that determines whether given rt6_info should be destroyed
9933 + * (negative => destroy rt6_info, zero or positive => do nothing)
9935 +static int mn_route_cleaner(struct rt6_info *rt, void *arg)
9939 + struct router *rtr = (struct router *)arg;
9945 + if (!rt || !rtr) {
9946 + DEBUG(DBG_ERROR, "mn_route_cleaner: rt or rtr NULL");
9950 + /* Do not delete routes to local addresses or to multicast
9951 + * addresses, since we need them to get router advertisements
9952 + * etc. Multicast addresses are more tricky, but we don't
9953 + * delete them in any case. The routing mechanism is not optimal for
9956 + * Also keep all new prefix routes, gateway routes through rtr and
9957 + * all remaining default routes (including those used for reverse
9960 + type = ipv6_addr_type(&rt->rt6i_dst.addr);
9962 + if ((type & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL)) ||
9963 + rt->rt6i_dev == &loopback_dev || rtr_is_gw(rtr, rt) ||
9964 + is_prefix_route(rtr, rt) || (rt->rt6i_flags & RTF_DEFAULT))
9967 + /* delete all others */
9969 + if (rt->rt6i_dev != &loopback_dev) {
9970 + DEBUG(DEBUG_MDETECT,
9973 + "gw: %x:%x:%x:%x:%x:%x:%x:%x,\n"
9976 + "src: %x:%x:%x:%x:%x:%x:%x:%x,\n"
9977 + "dst: %x:%x:%x:%x:%x:%x:%x:%x,\n"
9979 + (ret ? "Deleting" : "Keeping"),
9980 + rt->rt6i_dev->name,
9981 + NIPV6ADDR(&rt->rt6i_gateway),
9984 + NIPV6ADDR(&rt->rt6i_src.addr),
9985 + NIPV6ADDR(&rt->rt6i_dst.addr),
9986 + rt->rt6i_dst.plen);
9992 + * Deletes old routes
9994 +static __inline__ void delete_routes(struct router *rtr)
9998 + /* Routing table is locked to ensure that nobody uses its */
9999 + write_lock_bh(&rt6_lock);
10000 + DEBUG(DBG_INFO, "mipv6: Purging routes");
10001 + /* TODO: Does not prune, should it? */
10002 + fib6_clean_tree(&ip6_routing_table,
10003 + mn_route_cleaner, 0, rtr);
10004 + write_unlock_bh(&rt6_lock);
10009 +static __inline__ void delete_coas(struct router *rtr)
10011 + struct net_device *dev;
10012 + struct inet6_dev *idev;
10013 + struct inet6_ifaddr *ifa;
10015 + dev = dev_get_by_index(rtr->ifindex);
10019 + idev = in6_dev_get(dev);
10022 + read_lock_bh(&idev->lock);
10023 + ifa = idev->addr_list;
10026 + spin_lock(&ifa->lock);
10028 + keep = (ifa->flags&(IFA_F_PERMANENT|IFA_F_HOMEADDR) ||
10029 + !ipv6_addr_cmp(&ifa->addr, &rtr->CoA));
10031 + spin_unlock(&ifa->lock);
10034 + ifa = ifa->if_next;
10036 + in6_ifa_hold(ifa);
10037 + read_unlock_bh(&idev->lock);
10039 + ipv6_del_addr(ifa);
10041 + read_lock_bh(&idev->lock);
10042 + ifa = idev->addr_list;
10045 + read_unlock_bh(&idev->lock);
10046 + in6_dev_put(idev);
10051 +int next_mdet_state[3][3] = {{CURR_RTR_OK, NO_RTR, NO_RTR},
10052 + {CURR_RTR_OK, CURR_RTR_OK, NO_RTR},
10053 + {CURR_RTR_OK, CURR_RTR_OK, RTR_SUSPECT}};
10055 +char *states[3] = {"NO_RTR", "RTR_SUSPECT", "CURR_RTR_OK"};
10056 +char *events[3] = {"RA_RCVD", "NA_RCVD", "TIMEOUT"};
10058 +/* State transitions
10059 + * NO_RTR, RA_RCVD -> CURR_RTR_OK
10060 + * NO_RTR, NA_RCVD -> NO_RTR
10061 + * NO_RTR, TIMEOUT -> NO_RTR
10063 + * RTR_SUSPECT, RA_RCVD -> CURR_RTR_OK
10064 + * RTR_SUSPECT, NA_RCVD -> CURR_RTR_OK
10065 + * RTR_SUSPECT, TIMEOUT -> NO_RTR
10067 + * CURR_RTR_OK, RA_RCVD -> CURR_RTR_OK
10068 + * CURR_RTR_OK, NA_RCVD -> CURR_RTR_OK
10069 + * CURR_RTR_OK, TIMEOUT -> RTR_SUSPECT
10071 +static int _curr_state = NO_RTR;
10074 +static int get_mdet_state(void){
10076 + spin_lock_bh(&router_lock);
10077 + state = _curr_state;
10078 + spin_unlock_bh(&router_lock);
10083 +/* Needs to be called with router_lock locked */
10084 +static int mdet_statemachine(int event)
10087 + if (event > 2 || _curr_state > 2) {
10088 + DEBUG(DBG_ERROR, "Got illegal event or curr_state");
10092 + DEBUG(DBG_DATADUMP, "Got event %s and curr_state is %s",
10093 + events[event], states[_curr_state]);
10095 + _curr_state = next_mdet_state[_curr_state][event];
10096 + DEBUG(DBG_DATADUMP, "Next state is %s", states[_curr_state]);
10097 + return _curr_state;
10100 +static void mipv6_do_ll_dad(int ifindex)
10102 + struct net_device *dev = dev_get_by_index(ifindex);
10104 + struct in6_addr lladdr;
10105 + struct inet6_ifaddr *ifa;
10106 + if (!ipv6_get_lladdr(dev, &lladdr) &&
10107 + (ifa = ipv6_get_ifaddr(&lladdr, dev)) != NULL) {
10108 + spin_lock_bh(&ifa->lock);
10109 + if (!(ifa->flags & IFA_F_TENTATIVE)) {
10110 + ifa->flags |= IFA_F_TENTATIVE;
10111 + spin_unlock_bh(&ifa->lock);
10112 + addrconf_dad_start(ifa, 0);
10114 + spin_unlock_bh(&ifa->lock);
10121 + * Changes the router, called from ndisc.c if mipv6_router_event
10125 +static void mipv6_change_router(void)
10127 + struct in6_addr coa;
10128 + int ret, ifindex;
10133 + if (next_router == NULL)
10136 + spin_lock(&router_lock);
10139 + if (curr_router != NULL &&
10140 + !ipv6_addr_cmp(&curr_router->ll_addr, &next_router->ll_addr)) {
10141 + DEBUG(DBG_INFO,"Trying to handoff from: "
10142 + "%x:%x:%x:%x:%x:%x:%x:%x",
10143 + NIPV6ADDR(&curr_router->ll_addr));
10144 + DEBUG(DBG_INFO,"Trying to handoff to: "
10145 + "%x:%x:%x:%x:%x:%x:%x:%x",
10146 + NIPV6ADDR(&next_router->ll_addr));
10147 + next_router = NULL; /* Let's not leave dangling pointers */
10148 + spin_unlock(&router_lock);
10151 + ret = form_coa(&next_router->CoA, &next_router->raddr,
10152 + next_router->pfix_len, next_router->ifindex);
10154 + DEBUG(DBG_ERROR, "handoff: Creation of coa failed");
10155 + spin_unlock(&router_lock);
10157 + } else if (ret > 0)
10158 + next_router->flags |= COA_TENTATIVE;
10160 + mdet_statemachine(RA_RCVD); /* TODO: What if DAD fails... */
10161 + if (next_router->interval)
10162 + mod_timer(&r_timer, jiffies +
10163 + (next_router->interval * HZ)/1000);
10165 + mod_timer(&r_timer, jiffies + max_rtr_reach_time * HZ);
10169 + ipv6_addr_copy(&coa, &next_router->CoA);
10170 + ifindex = next_router->ifindex;
10171 + spin_unlock(&router_lock);
10172 + mipv6_mdet_finalize_ho(&coa, ifindex);
10175 + spin_unlock(&router_lock);
10178 +static unsigned long ns_send(void)
10180 + struct neighbour *neigh;
10181 + struct net_device *dev;
10182 + struct in6_addr *raddr;
10184 + DEBUG(DBG_DATADUMP, "Sending Neighbour solicitation to default router to verify its reachability");
10185 + if (!curr_router)
10187 + if ((dev = dev_get_by_index(curr_router->ifindex)) == NULL)
10189 + if ((neigh = ndisc_get_neigh(dev, &curr_router->ll_addr)) == NULL) {
10193 + if (curr_router->glob_addr)
10194 + raddr = &curr_router->raddr;
10196 + raddr = &curr_router->ll_addr;
10198 + curr_router->last_ns_sent = jiffies;
10199 + ndisc_send_ns(dev, neigh, raddr, raddr, NULL);
10201 + neigh_release(neigh);
10203 + return HZ/5; /* Wait 200ms for a reply */
10206 +static int na_rcvd(void)
10208 + int neigh_ok = 0;
10209 + struct neighbour *neigh;
10210 + struct net_device *dev;
10212 + if (!curr_router)
10214 + if ((dev = dev_get_by_index(curr_router->ifindex)) == NULL)
10216 + if ((neigh = ndisc_get_neigh(dev, &curr_router->ll_addr)) == NULL) {
10220 + if (neigh->flags & NTF_ROUTER &&
10221 + (time_after(neigh->confirmed, curr_router->last_ns_sent) ||
10222 + neigh->confirmed == curr_router->last_ns_sent)) {
10224 + DEBUG(DBG_DATADUMP, "Mdetect event: NA rcvd from curr rtr");
10226 + DEBUG(DBG_DATADUMP, "Mdetect event: NA NOT rcvd from curr rtr within time limit");
10227 + neigh_release(neigh);
10232 +static void coa_timer_handler(unsigned long dummy)
10235 + spin_lock_bh(&ho_lock);
10237 + DEBUG(DBG_INFO, "Starting handoff after DAD");
10238 + mipv6_mobile_node_moved(_ho);
10242 + spin_unlock_bh(&ho_lock);
10244 +static void timer_handler(unsigned long foo)
10246 + unsigned long timeout;
10248 + spin_lock_bh(&router_lock);
10250 + if (_curr_state != NO_RTR)
10251 + rs_state = START;
10253 + if (_curr_state == RTR_SUSPECT && na_rcvd()) {
10254 + state = mdet_statemachine(NA_RCVD);
10255 + timeout = curr_router->interval ? curr_router->interval : max_rtr_reach_time * HZ;
10257 + state = mdet_statemachine(TIMEOUT);
10258 + if (state == NO_RTR)
10259 + timeout = rs_send();
10260 + else /* RTR_SUSPECT */
10261 + timeout = ns_send();
10266 + mipv6_router_gc();
10267 + mod_timer(&r_timer, jiffies + timeout);
10268 + spin_unlock_bh(&router_lock);
10272 + * mipv6_get_care_of_address - get node's care-of primary address
10273 + * @homeaddr: one of node's home addresses
10274 + * @coaddr: buffer to store care-of address
10276 + * Stores the current care-of address in the @coaddr, assumes
10277 + * addresses in EUI-64 format. Since node might have several home
10278 + * addresses caller MUST supply @homeaddr. If node is at home
10279 + * @homeaddr is stored in @coaddr. Returns 0 on success, otherwise a
10280 + * negative value.
10282 +int mipv6_get_care_of_address(
10283 + struct in6_addr *homeaddr, struct in6_addr *coaddr)
10288 + if (homeaddr == NULL)
10290 + spin_lock_bh(&router_lock);
10291 + if (curr_router == NULL || mipv6_mn_is_at_home(homeaddr) ||
10292 + mipv6_prefix_compare(homeaddr, &curr_router->raddr, 64) ||
10293 + curr_router->flags&COA_TENTATIVE) {
10295 + "mipv6_get_care_of_address: returning home address");
10296 + ipv6_addr_copy(coaddr, homeaddr);
10297 + spin_unlock_bh(&router_lock);
10302 + /* At home or address check failure probably due to dad wait */
10303 + if (mipv6_prefix_compare(&curr_router->raddr, homeaddr,
10304 + curr_router->pfix_len)
10305 + || (dad == RESPECT_DAD &&
10306 + (ipv6_chk_addr(coaddr, NULL) == 0))) {
10307 + ipv6_addr_copy(coaddr, homeaddr);
10309 + ipv6_addr_copy(coaddr, &curr_router->CoA);
10312 + spin_unlock_bh(&router_lock);
10316 +int mipv6_mdet_del_if(int ifindex)
10318 + struct router *curr = NULL;
10319 + struct list_head *lh, *lh_tmp;
10321 + spin_lock_bh(&router_lock);
10322 + list_for_each_safe(lh, lh_tmp, &rtr_list) {
10323 + curr = list_entry(lh, struct router, list);
10324 + if (curr->ifindex == ifindex) {
10326 + list_del_init(&curr->list);
10327 + DEBUG(DBG_DATADUMP, "Deleting router %x:%x:%x:%x:%x:%x:%x:%x on interface %d",
10328 + NIPV6ADDR(&curr->raddr), ifindex);
10329 + if (curr_router == curr)
10330 + curr_router = NULL;
10334 + spin_unlock_bh(&router_lock);
10338 +void mipv6_mdet_retrigger_ho(void)
10340 + struct handoff ho;
10342 + spin_lock_bh(&router_lock);
10343 + if (curr_router != NULL) {
10344 + ho.coa = &curr_router->CoA;
10345 + ho.plen = curr_router->pfix_len;
10346 + ho.ifindex = curr_router->ifindex;
10347 + ipv6_addr_copy(&ho.rtr_addr, &curr_router->raddr);
10348 + ho.home_address = (curr_router->glob_addr &&
10349 + curr_router->flags&ND_RA_FLAG_HA);
10351 + spin_unlock_bh(&router_lock);
10352 + mipv6_mobile_node_moved(&ho);
10355 +void mipv6_mdet_set_curr_rtr_reachable(int reachable)
10357 + spin_lock_bh(&router_lock);
10358 + if (curr_router != NULL) {
10359 + curr_router->reachable = reachable;
10361 + spin_unlock_bh(&router_lock);
10365 +int mipv6_mdet_finalize_ho(const struct in6_addr *coa, const int ifindex)
10368 + struct handoff ho;
10369 + struct router *tmp;
10370 + struct net_device *dev;
10371 + struct in6_addr ll_addr;
10373 + spin_lock_bh(&router_lock);
10375 + if (!next_router) {
10376 + spin_unlock_bh(&router_lock);
10380 + dev = dev_get_by_index(next_router->ifindex);
10382 + if (ipv6_get_lladdr(dev, &ll_addr) == 0) {
10383 + if (ipv6_addr_cmp(&ll_addr, coa) == 0)
10384 + DEBUG(DBG_INFO, "DAD for link local address completed");
10385 + next_router->flags &= ~LLADDR_TENTATIVE;
10390 + if (mipv6_prefix_compare(coa, &next_router->CoA,
10391 + next_router->pfix_len)) {
10392 + DEBUG(DBG_INFO, "DAD for Care-of address completed");
10393 + next_router->flags &= ~COA_TENTATIVE;
10395 + if (!(next_router->flags&LLADDR_TENTATIVE) && !(next_router->flags&COA_TENTATIVE)) {
10396 + DEBUG(DBG_INFO, "%s: Proceeding with handoff after DAD\n", __FUNCTION__);
10397 + tmp = curr_router;
10398 + curr_router = next_router;
10399 + curr_router->is_current = 1;
10400 + next_router = NULL;
10401 + curr_router->flags &= ~COA_TENTATIVE;
10402 + delete_routes(curr_router);
10403 + delete_coas(curr_router);
10405 + struct net_device *dev_old = dev_get_by_index(tmp->ifindex);
10406 + struct rt6_info *rt = NULL;
10408 + rt = rt6_get_dflt_router(&tmp->ll_addr, dev_old);
10409 + dev_put(dev_old);
10412 + ip6_del_rt(rt, NULL);
10413 + tmp->is_current = 0;
10416 + ma_ctl_upd_iface(curr_router->ifindex, MA_IFACE_CURRENT, &dummy);
10417 + ma_ctl_upd_iface(curr_router->ifindex, MA_IFACE_CURRENT, &dummy);
10420 + ho.coa = &curr_router->CoA;
10421 + ho.plen = curr_router->pfix_len;
10422 + ho.ifindex = curr_router->ifindex;
10423 + ipv6_addr_copy(&ho.rtr_addr, &curr_router->raddr);
10424 + ho.home_address = (curr_router->glob_addr &&
10425 + curr_router->flags&ND_RA_FLAG_HA);
10427 + spin_unlock_bh(&router_lock);
10428 + mipv6_mobile_node_moved(&ho);
10430 + spin_unlock_bh(&router_lock);
10433 +/* Decides whether router candidate is the same router as current rtr
10434 + * based on prefix / global addresses of the routers and their link local
10437 +static int is_current_rtr(struct router *nrt, struct router *crt)
10441 + DEBUG(DEBUG_MDETECT, "Current router: "
10442 + "%x:%x:%x:%x:%x:%x:%x:%x and", NIPV6ADDR(&crt->raddr));
10443 + DEBUG(DEBUG_MDETECT, "Candidate router: "
10444 + "%x:%x:%x:%x:%x:%x:%x:%x", NIPV6ADDR(&nrt->raddr));
10446 + return (!ipv6_addr_cmp(&nrt->raddr,&crt->raddr) &&
10447 + !ipv6_addr_cmp(&nrt->ll_addr, &crt->ll_addr));
10451 + * Change next router to nrtr
10452 + * Returns 1, if router has been changed.
10455 +static int change_next_rtr(struct router *nrtr, struct router *ortr)
10460 + if (!next_router || ipv6_addr_cmp(&nrtr->raddr, &next_router->raddr)) {
10463 + next_router = nrtr;
10466 +static int clean_ncache(struct router *nrt, struct router *ort, int same_if)
10468 + struct net_device *ortdev;
10471 + /* Always call ifdown after a handoff to ensure proper routing */
10475 + if ((ortdev = dev_get_by_index(ort->ifindex)) == NULL) {
10476 + DEBUG(DBG_WARNING, "Device is not present");
10479 + neigh_ifdown(&nd_tbl, ortdev);
10484 +static int mdet_get_if_preference(int ifi)
10490 + pref = ma_ctl_get_preference(ifi);
10492 + DEBUG(DEBUG_MDETECT, "ifi: %d preference %d", ifi, pref);
10498 + * Called from mipv6_mn_ra_rcv to determine whether to do a handoff.
10500 +static int mipv6_router_event(struct router *rptr)
10502 + struct router *nrt = NULL;
10503 + int new_router = 0, same_if = 1;
10504 + int oldstate = _curr_state;
10505 + int addrtype = ipv6_addr_type(&rptr->raddr);
10509 + if (rptr->lifetime == 0)
10510 + return MIPV6_IGN_RTR;
10511 + DEBUG(DEBUG_MDETECT, "Received a RA from router: "
10512 + "%x:%x:%x:%x:%x:%x:%x:%x", NIPV6ADDR(&rptr->raddr));
10513 + spin_lock(&router_lock);
10515 + /* Add or update router entry */
10516 + if ((nrt = mipv6_rtr_get(&rptr->raddr)) == NULL) {
10517 + if (addrtype == IPV6_ADDR_ANY || (nrt = mipv6_rtr_add(rptr)) == NULL) {
10518 + spin_unlock(&router_lock);
10519 + return MIPV6_IGN_RTR;
10521 + DEBUG(DBG_INFO, "Router not on list,adding it to the list");
10524 + nrt->last_ra_rcvd = jiffies;
10525 + nrt->state = ROUTER_REACHABLE;
10526 + nrt->interval = rptr->interval;
10527 + nrt->lifetime = rptr->lifetime;
10528 + nrt->ifindex = rptr->ifindex;
10529 + nrt->flags = rptr->flags;
10530 + nrt->glob_addr = rptr->glob_addr;
10532 + /* Whether from current router */
10533 + if (curr_router && curr_router->reachable &&
10534 + is_current_rtr(nrt, curr_router)) {
10535 + if (nrt->interval)
10536 + mod_timer(&r_timer, jiffies + (nrt->interval * HZ)/1000);
10538 + mod_timer(&r_timer, jiffies + max_rtr_reach_time * HZ);
10539 + mdet_statemachine(RA_RCVD);
10540 + spin_unlock(&router_lock);
10541 + return MIPV6_ADD_RTR;
10542 + } else if (oldstate == NO_RTR) {
10543 + rt6_purge_dflt_routers(0); /* For multiple interface case */
10544 + DEBUG(DBG_INFO, "No router or router not reachable, switching to new one");
10547 + if (!curr_router) {
10551 + /* Router behind same interface as current one ?*/
10552 + same_if = (nrt->ifindex == curr_router->ifindex);
10553 + /* Switch to new router behind same interface if eager cell
10554 + * switching is used or if the interface is preferred
10556 + if ((new_router && eager_cell_switching && same_if) ||
10557 + (mdet_get_if_preference(nrt->ifindex) >
10558 + mdet_get_if_preference(curr_router->ifindex))) {
10559 + DEBUG(DBG_INFO, "Switching to new router.");
10563 + /* No handoff, don't add default route */
10564 + DEBUG(DEBUG_MDETECT, "Ignoring RA");
10565 + spin_unlock(&router_lock);
10566 + return MIPV6_IGN_RTR;
10568 + clean_ncache(nrt, curr_router, same_if);
10569 + nrt->reachable = 1;
10570 + if (same_if && change_next_rtr(nrt, curr_router)) {
10571 + mipv6_do_ll_dad(nrt->ifindex);
10572 + nrt->flags |= LLADDR_TENTATIVE;
10574 + spin_unlock(&router_lock);
10576 + return MIPV6_CHG_RTR;
10580 + * Called from ndisc.c's router_discovery.
10583 +static inline int ret_to_ha(struct in6_addr *addr)
10586 + struct mn_info *minfo;
10587 + read_lock(&mn_info_lock);
10588 + minfo = mipv6_mninfo_get_by_ha(addr);
10589 + if (minfo != NULL) {
10590 + spin_lock(&minfo->lock);
10591 + if (minfo->has_home_reg) {
10594 + spin_unlock(&minfo->lock);
10596 + read_unlock(&mn_info_lock);
10600 +static int mipv6_mn_ra_rcv(struct sk_buff *skb, struct ndisc_options *ndopts)
10602 + int ifi = ((struct inet6_skb_parm *)skb->cb)->iif;
10603 + struct ra_msg *ra = (struct ra_msg *) skb->h.raw;
10604 + struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
10605 + struct router nrt;
10606 + struct in6_addr *ha = NULL;
10607 + u8 *lladdr = NULL;
10611 + memset(&nrt, 0, sizeof(struct router));
10613 + if (ra->icmph.icmp6_home_agent) {
10614 + nrt.flags |= ND_RA_FLAG_HA;
10615 + DEBUG(DBG_DATADUMP, "RA has ND_RA_FLAG_HA up");
10618 + if (ra->icmph.icmp6_addrconf_managed) {
10619 + nrt.flags |= ND_RA_FLAG_MANAGED;
10620 + DEBUG(DBG_DATADUMP, "RA has ND_RA_FLAG_MANAGED up");
10623 + if (ra->icmph.icmp6_addrconf_other) {
10624 + nrt.flags |= ND_RA_FLAG_OTHER;
10625 + DEBUG(DBG_DATADUMP, "RA has ND_RA_FLAG_OTHER up");
10628 + ipv6_addr_copy(&nrt.ll_addr, saddr);
10629 + nrt.ifindex = ifi;
10630 + nrt.lifetime = ntohs(ra->icmph.icmp6_rt_lifetime);
10632 + if (ndopts->nd_opts_src_lladdr) {
10633 + lladdr = (u8 *) ndopts->nd_opts_src_lladdr+2;
10634 + nrt.link_addr_len = skb->dev->addr_len;
10635 + memcpy(nrt.link_addr, lladdr, nrt.link_addr_len);
10637 + if (ndopts->nd_opts_pi) {
10638 + struct nd_opt_hdr *p;
10639 + for (p = ndopts->nd_opts_pi;
10641 + p = ndisc_next_option(p, ndopts->nd_opts_pi_end)) {
10642 + struct prefix_info *pinfo;
10645 + pinfo = (struct prefix_info *) p;
10647 + if (!pinfo->autoconf)
10650 + if ((pinfo->router_address &&
10651 + (update = ret_to_ha(&pinfo->prefix))) ||
10652 + ipv6_addr_type(&nrt.raddr) != IPV6_ADDR_UNICAST) {
10653 + ipv6_addr_copy(&nrt.raddr, &pinfo->prefix);
10654 + nrt.pfix_len = pinfo->prefix_len;
10655 + if (pinfo->router_address)
10656 + nrt.glob_addr = 1;
10658 + nrt.glob_addr = 0;
10660 + ha = &pinfo->prefix;
10661 + DEBUG(DBG_DATADUMP, "Address of the received "
10662 + "prefix info option: %x:%x:%x:%x:%x:%x:%x:%x",
10663 + NIPV6ADDR(&nrt.raddr));
10664 + DEBUG(DBG_DATADUMP, "the length of the prefix is %d",
10669 + if (ndopts->nd_opts_rai) {
10670 + nrt.interval = ntohl(*(__u32 *)(ndopts->nd_opts_rai+4));
10671 + DEBUG(DBG_DATADUMP,
10672 + "received router interval option with interval : %d ",
10673 + nrt.interval / HZ);
10675 + if (nrt.interval > MAX_RADV_INTERVAL) {
10676 + nrt.interval = 0;
10677 + DEBUG(DBG_DATADUMP, "but we are using: %d, "
10678 + "because interval>MAX_RADV_INTERVAL",
10679 + nrt.interval / HZ);
10683 + res = mipv6_router_event(&nrt);
10685 + if (ha && lladdr) {
10686 + mipv6_mn_ha_nd_update(__dev_get_by_index(ifi), ha, lladdr);
10691 +int __init mipv6_initialize_mdetect(void)
10696 + spin_lock_init(&router_lock);
10697 + spin_lock_init(&ho_lock);
10698 + init_timer(&coa_timer);
10699 + init_timer(&r_timer);
10700 + r_timer.expires = jiffies + HZ;
10701 + add_timer(&r_timer);
10703 + /* Actual HO, also deletes old routes after the addition of new ones
10705 + MIPV6_SETCALL(mipv6_change_router, mipv6_change_router);
10707 + MIPV6_SETCALL(mipv6_ra_rcv, mipv6_mn_ra_rcv);
10712 +int __exit mipv6_shutdown_mdetect()
10717 + MIPV6_RESETCALL(mipv6_ra_rcv);
10718 + MIPV6_RESETCALL(mipv6_change_router);
10719 + spin_lock_bh(&router_lock);
10720 + spin_lock(&ho_lock);
10721 + del_timer(&coa_timer);
10722 + del_timer(&r_timer);
10723 + /* Free the memory allocated by router list */
10724 + list_free(&curr_router);
10727 + spin_unlock(&ho_lock);
10728 + spin_unlock_bh(&router_lock);
10731 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/mdetect.h linux-2.4.25/net/ipv6/mobile_ip6/mdetect.h
10732 --- linux-2.4.25.old/net/ipv6/mobile_ip6/mdetect.h 1970-01-01 01:00:00.000000000 +0100
10733 +++ linux-2.4.25/net/ipv6/mobile_ip6/mdetect.h 2004-06-26 11:29:31.000000000 +0100
10736 + * MIPL Mobile IPv6 Movement detection module header file
10740 + * This program is free software; you can redistribute it and/or
10741 + * modify it under the terms of the GNU General Public License
10742 + * as published by the Free Software Foundation; either version
10743 + * 2 of the License, or (at your option) any later version.
10746 +#ifndef _MDETECT_H
10747 +#define _MDETECT_H
10750 + int home_address; /* Is the coa a home address */
10753 + struct in6_addr *coa;
10754 + struct in6_addr rtr_addr; /* Prefix or rtr address if coa is home address */
10757 +int mipv6_initialize_mdetect(void);
10759 +int mipv6_shutdown_mdetect(void);
10761 +int mipv6_get_care_of_address(struct in6_addr *homeaddr, struct in6_addr *coa);
10763 +int mipv6_mdet_del_if(int ifindex);
10765 +int mipv6_mdet_finalize_ho(const struct in6_addr *coa, const int ifindex);
10767 +void mipv6_mdet_retrigger_ho(void);
10769 +void mipv6_mdet_set_curr_rtr_reachable(int reachable);
10771 +#endif /* _MDETECT_H */
10772 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/mipv6_icmp.c linux-2.4.25/net/ipv6/mobile_ip6/mipv6_icmp.c
10773 --- linux-2.4.25.old/net/ipv6/mobile_ip6/mipv6_icmp.c 1970-01-01 01:00:00.000000000 +0100
10774 +++ linux-2.4.25/net/ipv6/mobile_ip6/mipv6_icmp.c 2004-06-26 11:29:31.000000000 +0100
10777 + * Generic icmp routines
10780 + * Jaakko Laine <medved@iki.fi>,
10781 + * Ville Nuorvala <vnuorval@tcs.hut.fi>
10785 + * This program is free software; you can redistribute it and/or
10786 + * modify it under the terms of the GNU General Public License
10787 + * as published by the Free Software Foundation; either version
10788 + * 2 of the License, or (at your option) any later version.
10791 +#include <linux/config.h>
10792 +#include <linux/icmpv6.h>
10793 +#include <net/checksum.h>
10794 +#include <net/ipv6.h>
10795 +#include <net/ip6_route.h>
10796 +#include <net/mipv6.h>
10797 +#include <net/mipglue.h>
10799 +#include "debug.h"
10800 +#include "bcache.h"
10801 +#include "mipv6_icmp.h"
10802 +#include "config.h"
10804 +struct mipv6_icmpv6_msg {
10805 + struct icmp6hdr icmph;
10807 + struct in6_addr *daddr;
10812 +#define MIPV6_ICMP_HOP_LIMIT 64
10814 +static struct socket *mipv6_icmpv6_socket = NULL;
10815 +static __u16 identifier = 0;
10817 +int mipv6_icmpv6_no_rcv(struct sk_buff *skb)
10822 +static int mipv6_icmpv6_xmit_holder = -1;
10824 +static int mipv6_icmpv6_xmit_lock_bh(void)
10826 + if (!spin_trylock(&mipv6_icmpv6_socket->sk->lock.slock)) {
10827 + if (mipv6_icmpv6_xmit_holder == smp_processor_id())
10829 + spin_lock(&mipv6_icmpv6_socket->sk->lock.slock);
10831 + mipv6_icmpv6_xmit_holder = smp_processor_id();
10835 +static __inline__ int mipv6_icmpv6_xmit_lock(void)
10838 + local_bh_disable();
10839 + ret = mipv6_icmpv6_xmit_lock_bh();
10841 + local_bh_enable();
10845 +static void mipv6_icmpv6_xmit_unlock_bh(void)
10847 + mipv6_icmpv6_xmit_holder = -1;
10848 + spin_unlock(&mipv6_icmpv6_socket->sk->lock.slock);
10851 +static __inline__ void mipv6_icmpv6_xmit_unlock(void)
10853 + mipv6_icmpv6_xmit_unlock_bh();
10854 + local_bh_enable();
10859 + * mipv6_icmpv6_dest_unreach - Destination Unreachable ICMP error message handler
10860 + * @skb: buffer containing ICMP error message
10862 + * Special Mobile IPv6 ICMP handling. If Correspondent Node receives
10863 + * persistent ICMP Destination Unreachable messages for a destination
10864 + * in its Binding Cache, the binding should be deleted. See draft
10867 +static int mipv6_icmpv6_rcv_dest_unreach(struct sk_buff *skb)
10869 + struct icmp6hdr *icmph = (struct icmp6hdr *) skb->h.raw;
10870 + struct ipv6hdr *ipv6h = (struct ipv6hdr *) (icmph + 1);
10871 + int left = (skb->tail - skb->h.raw) - sizeof(*icmph)- sizeof(ipv6h);
10872 + struct ipv6_opt_hdr *eh;
10873 + struct rt2_hdr *rt2h = NULL;
10874 + struct in6_addr *daddr = &ipv6h->daddr;
10875 + struct in6_addr *saddr = &ipv6h->saddr;
10876 + int hdrlen, nexthdr = ipv6h->nexthdr;
10877 + struct mipv6_bce bce;
10880 + eh = (struct ipv6_opt_hdr *) (ipv6h + 1);
10882 + while (left > 0) {
10883 + if (nexthdr != NEXTHDR_HOP && nexthdr != NEXTHDR_DEST &&
10884 + nexthdr != NEXTHDR_ROUTING)
10887 + hdrlen = ipv6_optlen(eh);
10888 + if (hdrlen > left)
10891 + if (nexthdr == NEXTHDR_ROUTING) {
10892 + struct ipv6_rt_hdr *rth = (struct ipv6_rt_hdr *) eh;
10894 + if (rth->type == IPV6_SRCRT_TYPE_2) {
10895 + if (hdrlen != sizeof(struct rt2_hdr))
10898 + rt2h = (struct rt2_hdr *) rth;
10900 + if (rt2h->rt_hdr.segments_left > 0)
10901 + daddr = &rt2h->addr;
10905 + /* check for home address option in case this node is a MN */
10906 + if (nexthdr == NEXTHDR_DEST) {
10907 + __u8 *raw = (__u8 *) eh;
10910 + struct mipv6_dstopt_homeaddr *hao;
10912 + if (i + sizeof (*hao) > hdrlen)
10915 + hao = (struct mipv6_dstopt_homeaddr *) &raw[i];
10917 + if (hao->type == MIPV6_TLV_HOMEADDR &&
10918 + hao->length == sizeof(struct in6_addr)) {
10919 + saddr = &hao->addr;
10923 + i += hao->length + 2;
10929 + nexthdr = eh->nexthdr;
10930 + eh = (struct ipv6_opt_hdr *) ((u8 *) eh + hdrlen);
10933 + if (rt2h == NULL) return 0;
10935 + if (mipv6_bcache_get(daddr, saddr, &bce) == 0 && !(bce.flags&HOME_REGISTRATION)) {
10936 + /* A primitive algorithm for detecting persistent ICMP destination unreachable messages */
10937 + if (bce.destunr_count &&
10938 + time_after(jiffies,
10939 + bce.last_destunr + MIPV6_DEST_UNR_IVAL*HZ))
10940 + bce.destunr_count = 0;
10942 + bce.destunr_count++;
10944 + mipv6_bcache_icmp_err(daddr, saddr, bce.destunr_count);
10946 + if (bce.destunr_count > MIPV6_MAX_DESTUNREACH && mipv6_bcache_delete(daddr, saddr, CACHE_ENTRY) == 0) {
10947 + DEBUG(DBG_INFO, "Deleted bcache entry "
10948 + "%x:%x:%x:%x:%x:%x:%x:%x "
10949 + "%x:%x:%x:%x:%x:%x:%x:%x (reason: "
10950 + "%d dest unreachables) ",
10951 + NIPV6ADDR(daddr), NIPV6ADDR(saddr), bce.destunr_count);
10957 +static int mipv6_icmpv6_getfrag(const void *data, struct in6_addr *saddr,
10958 + char *buff, unsigned int offset,
10959 + unsigned int len)
10961 + struct mipv6_icmpv6_msg *msg = (struct mipv6_icmpv6_msg *) data;
10962 + struct icmp6hdr *icmph;
10966 + msg->csum = csum_partial_copy_nocheck(msg->data + offset -
10967 + sizeof(*icmph), buff,
10972 + csum = csum_partial_copy_nocheck((__u8 *) &msg->icmph, buff,
10973 + sizeof(*icmph), msg->csum);
10975 + csum = csum_partial_copy_nocheck(msg->data, buff + sizeof(*icmph),
10976 + len - sizeof(*icmph), csum);
10978 + icmph = (struct icmp6hdr *) buff;
10980 + icmph->icmp6_cksum = csum_ipv6_magic(saddr, msg->daddr, msg->len,
10981 + IPPROTO_ICMPV6, csum);
10986 + * mipv6_icmpv6_send - generic icmpv6 message send
10987 + * @daddr: destination address
10988 + * @saddr: source address
10989 + * @type: icmp type
10990 + * @code: icmp code
10991 + * @id: packet identifier. If null, uses internal counter to get new id
10992 + * @data: packet data
10993 + * @datalen: length of data in bytes
10995 +void mipv6_icmpv6_send(struct in6_addr *daddr, struct in6_addr *saddr, int type,
10996 + int code, __u16 *id, __u16 flags, void *data, int datalen)
10998 + struct sock *sk = mipv6_icmpv6_socket->sk;
11000 + struct mipv6_icmpv6_msg msg;
11004 + fl.proto = IPPROTO_ICMPV6;
11005 + fl.fl6_dst = daddr;
11006 + fl.fl6_src = saddr;
11007 + fl.fl6_flowlabel = 0;
11008 + fl.uli_u.icmpt.type = type;
11009 + fl.uli_u.icmpt.code = code;
11011 + msg.icmph.icmp6_type = type;
11012 + msg.icmph.icmp6_code = code;
11013 + msg.icmph.icmp6_cksum = 0;
11016 + msg.icmph.icmp6_identifier = htons(*id);
11018 + msg.icmph.icmp6_identifier = htons(identifier++);
11020 + msg.icmph.icmp6_sequence = htons(flags);
11023 + msg.len = datalen + sizeof(struct icmp6hdr);
11024 + msg.daddr = daddr;
11026 + if (mipv6_icmpv6_xmit_lock())
11029 + ip6_build_xmit(sk, mipv6_icmpv6_getfrag, &msg, &fl, msg.len, NULL, -1,
11032 + ICMP6_INC_STATS_BH(Icmp6OutMsgs);
11033 + mipv6_icmpv6_xmit_unlock();
11037 + * icmp6_rcv - ICMPv6 receive and multiplex
11038 + * @skb: buffer containing ICMP message
11040 + * Generic ICMPv6 receive function to multiplex messages to approriate
11041 + * handlers. Only used for ICMP messages with special handling in
11044 +static void icmp6_rcv(struct sk_buff *skb)
11046 + struct icmp6hdr *hdr;
11048 + if (skb_is_nonlinear(skb) &&
11049 + skb_linearize(skb, GFP_ATOMIC) != 0) {
11053 + __skb_push(skb, skb->data-skb->h.raw);
11055 + hdr = (struct icmp6hdr *) skb->h.raw;
11057 + switch (hdr->icmp6_type) {
11058 + case ICMPV6_DEST_UNREACH:
11059 + mipv6_icmpv6_rcv_dest_unreach(skb);
11062 + case ICMPV6_PARAMPROB:
11063 + mip6_fn.icmpv6_paramprob_rcv(skb);
11066 + case MIPV6_DHAAD_REPLY:
11067 + mip6_fn.icmpv6_dhaad_rep_rcv(skb);
11070 + case MIPV6_PREFIX_ADV:
11071 + mip6_fn.icmpv6_pfxadv_rcv(skb);
11074 + case MIPV6_DHAAD_REQUEST:
11075 + mip6_fn.icmpv6_dhaad_req_rcv(skb);
11078 + case MIPV6_PREFIX_SOLICIT:
11079 + mip6_fn.icmpv6_pfxsol_rcv(skb);
11084 +int mipv6_icmpv6_init(void)
11089 + if ((mipv6_icmpv6_socket = sock_alloc()) == NULL) {
11090 + DEBUG(DBG_ERROR, "Cannot allocate mipv6_icmpv6_socket");
11093 + mipv6_icmpv6_socket->type = SOCK_RAW;
11095 + if ((err = sock_create(PF_INET6, SOCK_RAW, IPPROTO_ICMP,
11096 + &mipv6_icmpv6_socket)) < 0) {
11097 + DEBUG(DBG_ERROR, "Cannot initialize mipv6_icmpv6_socket");
11098 + sock_release(mipv6_icmpv6_socket);
11099 + mipv6_icmpv6_socket = NULL; /* For safety */
11102 + sk = mipv6_icmpv6_socket->sk;
11103 + sk->allocation = GFP_ATOMIC;
11104 + sk->prot->unhash(sk);
11106 + /* Register our ICMP handler */
11107 + MIPV6_SETCALL(mipv6_icmp_rcv, icmp6_rcv);
11111 +void mipv6_icmpv6_exit(void)
11113 + MIPV6_RESETCALL(mipv6_icmp_rcv);
11114 + if (mipv6_icmpv6_socket)
11115 + sock_release(mipv6_icmpv6_socket);
11116 + mipv6_icmpv6_socket = NULL; /* For safety */
11118 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/mipv6_icmp.h linux-2.4.25/net/ipv6/mobile_ip6/mipv6_icmp.h
11119 --- linux-2.4.25.old/net/ipv6/mobile_ip6/mipv6_icmp.h 1970-01-01 01:00:00.000000000 +0100
11120 +++ linux-2.4.25/net/ipv6/mobile_ip6/mipv6_icmp.h 2004-06-26 11:29:31.000000000 +0100
11123 + * MIPL Mobile IPv6 ICMP send and receive prototypes
11127 + * This program is free software; you can redistribute it and/or
11128 + * modify it under the terms of the GNU General Public License
11129 + * as published by the Free Software Foundation; either version
11130 + * 2 of the License, or (at your option) any later version.
11133 +#ifndef _MIPV6_ICMP
11134 +#define _MIPV6_ICMP
11136 +#include <linux/config.h>
11137 +#include <linux/in6.h>
11139 +void mipv6_icmpv6_send(struct in6_addr *daddr, struct in6_addr *saddr,
11140 + int type, int code, __u16 *id, __u16 flags,
11141 + void *data, int datalen);
11143 +void mipv6_icmpv6_send_dhaad_req(struct in6_addr *home_addr, int plen, __u16 dhaad_id);
11145 +void mipv6_icmpv6_send_dhaad_rep(int ifindex, __u16 id, struct in6_addr *daddr);
11147 +int mipv6_icmpv6_no_rcv(struct sk_buff *skb);
11149 +/* Receive DHAAD Reply message */
11150 +int mipv6_icmpv6_rcv_dhaad_rep(struct sk_buff *skb);
11151 +/* Receive Parameter Problem message */
11152 +int mipv6_icmpv6_rcv_paramprob(struct sk_buff *skb);
11153 +/* Receive prefix advertisements */
11154 +int mipv6_icmpv6_rcv_pfx_adv(struct sk_buff *skb);
11156 +/* Receive DHAAD Request message */
11157 +int mipv6_icmpv6_rcv_dhaad_req(struct sk_buff *skb);
11158 +/* Receive prefix solicitations */
11159 +int mipv6_icmpv6_rcv_pfx_sol(struct sk_buff *skb);
11161 +int mipv6_icmpv6_init(void);
11162 +void mipv6_icmpv6_exit(void);
11165 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/mipv6_icmp_ha.c linux-2.4.25/net/ipv6/mobile_ip6/mipv6_icmp_ha.c
11166 --- linux-2.4.25.old/net/ipv6/mobile_ip6/mipv6_icmp_ha.c 1970-01-01 01:00:00.000000000 +0100
11167 +++ linux-2.4.25/net/ipv6/mobile_ip6/mipv6_icmp_ha.c 2004-06-26 11:29:31.000000000 +0100
11170 + * Home Agent specific ICMP routines
11173 + * Antti Tuominen <ajtuomin@tml.hut.fi>
11174 + * Jaakko Laine <medved@iki.fi>
11178 + * This program is free software; you can redistribute it and/or
11179 + * modify it under the terms of the GNU General Public License
11180 + * as published by the Free Software Foundation; either version
11181 + * 2 of the License, or (at your option) any later version.
11184 +#include <linux/autoconf.h>
11185 +#include <linux/sched.h>
11186 +#include <net/ipv6.h>
11187 +#include <net/addrconf.h>
11188 +#include <net/ip6_route.h>
11189 +#include <net/mipv6.h>
11191 +#include "halist.h"
11192 +#include "debug.h"
11193 +#include "mipv6_icmp.h"
11194 +//#include "prefix.h"
11196 +/* Is this the easiest way of checking on
11197 + * which interface an anycast address is ?
11199 +static int find_ac_dev(struct in6_addr *addr)
11202 + struct net_device *dev;
11203 + read_lock(&dev_base_lock);
11204 + for (dev=dev_base; dev; dev=dev->next) {
11205 + if (ipv6_chk_acast_addr(dev, addr)) {
11206 + ifindex = dev->ifindex;
11210 + read_unlock(&dev_base_lock);
11215 + * mipv6_icmpv6_send_dhaad_rep - Reply to DHAAD Request
11216 + * @ifindex: index of interface request was received from
11217 + * @id: request's identification number
11218 + * @daddr: requester's IPv6 address
11220 + * When Home Agent receives Dynamic Home Agent Address Discovery
11221 + * request, it replies with a list of home agents available on the
11224 +void mipv6_icmpv6_send_dhaad_rep(int ifindex, __u16 id, struct in6_addr *daddr)
11226 + __u8 *data = NULL;
11227 + struct in6_addr home, *ha_addrs = NULL;
11228 + int addr_count, max_addrs, size = 0;
11230 + if (daddr == NULL)
11233 + if (mipv6_ha_get_addr(ifindex, &home) < 0) {
11234 + DEBUG(DBG_INFO, "Not Home Agent in this interface");
11238 + /* We send all available HA addresses, not exceeding a maximum
11239 + * number we can fit in a packet with minimum IPv6 MTU (to
11240 + * avoid fragmentation).
11243 + addr_count = mipv6_ha_get_pref_list(ifindex, &ha_addrs, max_addrs);
11245 + if (addr_count < 0) return;
11247 + if (addr_count != 0 && ha_addrs == NULL) {
11248 + DEBUG(DBG_ERROR, "addr_count = %d but return no addresses",
11252 + data = (u8 *)ha_addrs;
11254 + size = addr_count * sizeof(struct in6_addr);
11256 + mipv6_icmpv6_send(daddr, &home, MIPV6_DHAAD_REPLY,
11257 + 0, &id, 0, data, size);
11265 + * mipv6_icmpv6_dhaad_req - Home Agent Address Discovery Request ICMP handler
11266 + * @skb: buffer containing ICMP information message
11268 + * Special Mobile IPv6 ICMP message. Handles Dynamic Home Agent
11269 + * Address Discovery Request messages.
11271 +int mipv6_icmpv6_rcv_dhaad_req(struct sk_buff *skb)
11273 + struct icmp6hdr *phdr = (struct icmp6hdr *) skb->h.raw;
11274 + struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
11275 + struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
11276 + __u16 identifier;
11281 + /* Invalid packet checks. */
11282 + if (phdr->icmp6_code != 0)
11285 + identifier = ntohs(phdr->icmp6_identifier);
11288 + * Make sure we have the right ifindex (if the
11289 + * req came through another interface.
11291 + ifindex = find_ac_dev(daddr);
11292 + if (ifindex == 0) {
11293 + DEBUG(DBG_WARNING, "received dhaad request to anycast address %x:%x:%x:%x:%x:%x:%x:%x"
11294 + " on which prefix we are not HA",
11295 + NIPV6ADDR(daddr));
11300 + * send reply with list
11302 + mipv6_icmpv6_send_dhaad_rep(ifindex, identifier, saddr);
11307 + * mipv6_icmpv6_handle_pfx_sol - handle prefix solicitations
11308 + * @skb: sk_buff including the icmp6 message
11310 +int mipv6_icmpv6_rcv_pfx_sol(struct sk_buff *skb)
11312 + struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
11313 + struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
11314 + struct inet6_ifaddr *ifp;
11318 + if (!(ifp = ipv6_get_ifaddr(daddr, NULL)))
11321 + in6_ifa_put(ifp);
11322 + mipv6_pfx_cancel_send(saddr, -1);
11327 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/mipv6_icmp_mn.c linux-2.4.25/net/ipv6/mobile_ip6/mipv6_icmp_mn.c
11328 --- linux-2.4.25.old/net/ipv6/mobile_ip6/mipv6_icmp_mn.c 1970-01-01 01:00:00.000000000 +0100
11329 +++ linux-2.4.25/net/ipv6/mobile_ip6/mipv6_icmp_mn.c 2004-06-26 11:29:31.000000000 +0100
11332 + * Mobile Node specific ICMP routines
11335 + * Antti Tuominen <ajtuomin@tml.hut.fi>
11336 + * Jaakko Laine <medved@iki.fi>
11340 + * This program is free software; you can redistribute it and/or
11341 + * modify it under the terms of the GNU General Public License
11342 + * as published by the Free Software Foundation; either version
11343 + * 2 of the License, or (at your option) any later version.
11346 +#include <linux/sched.h>
11347 +#include <net/ipv6.h>
11348 +#include <net/ip6_route.h>
11349 +#include <net/addrconf.h>
11350 +#include <net/mipv6.h>
11354 +#include "mdetect.h"
11355 +#include "debug.h"
11356 +#include "mipv6_icmp.h"
11358 +//#include "prefix.h"
11360 +#define INFINITY 0xffffffff
11363 + * mipv6_icmpv6_paramprob - Parameter Problem ICMP error message handler
11364 + * @skb: buffer containing ICMP error message
11366 + * Special Mobile IPv6 ICMP handling. If Mobile Node receives ICMP
11367 + * Parameter Problem message when using a Home Address Option,
11368 + * offending node should be logged and error message dropped. If
11369 + * error is received because of a Binding Update, offending node
11370 + * should be recorded in Binding Update List and no more Binding
11371 + * Updates should be sent to this destination. See RFC 3775 section
11374 +int mipv6_icmpv6_rcv_paramprob(struct sk_buff *skb)
11376 + struct icmp6hdr *phdr = (struct icmp6hdr *) skb->h.raw;
11377 + struct in6_addr *saddr = skb ? &skb->nh.ipv6h->saddr : NULL;
11378 + struct in6_addr *daddr = skb ? &skb->nh.ipv6h->daddr : NULL;
11379 + struct ipv6hdr *hdr = (struct ipv6hdr *) (phdr + 1);
11380 + int ulen = (skb->tail - (unsigned char *) (phdr + 1));
11387 + /* We only handle code 1 & 2 messages. */
11388 + if (phdr->icmp6_code != ICMPV6_UNK_NEXTHDR &&
11389 + phdr->icmp6_code != ICMPV6_UNK_OPTION)
11392 + /* Find offending octet in the original packet. */
11393 + errptr = ntohl(phdr->icmp6_pointer);
11395 + /* There is not enough of the original packet left to figure
11396 + * out what went wrong. Bail out. */
11397 + if (ulen <= errptr)
11400 + off_octet = ((__u8 *) hdr + errptr);
11401 + DEBUG(DBG_INFO, "Parameter problem: offending octet %d [0x%2x]",
11402 + errptr, *off_octet);
11404 + /* If CN did not understand Mobility Header, set BUL entry to
11405 + * ACK_ERROR so no further BUs are sumbitted to this CN. */
11406 + if (phdr->icmp6_code == ICMPV6_UNK_NEXTHDR &&
11407 + *off_octet == IPPROTO_MOBILITY) {
11408 + struct bul_inval_args args;
11409 + args.all_rr_states = 1;
11412 + write_lock(&bul_lock);
11413 + mipv6_bul_iterate(mn_bul_invalidate, &args);
11414 + write_unlock(&bul_lock);
11417 + /* If CN did not understand Home Address Option, we log an
11418 + * error and discard the error message. */
11419 + if (phdr->icmp6_code == ICMPV6_UNK_OPTION &&
11420 + *off_octet == MIPV6_TLV_HOMEADDR) {
11421 + DEBUG(DBG_WARNING, "Correspondent node does not "
11422 + "implement Home Address Option receipt.");
11429 + * mipv6_mn_dhaad_send_req - Send DHAAD Request to home network
11430 + * @home_addr: address to do DHAAD for
11431 + * @plen: prefix length for @home_addr
11433 + * Send Dynamic Home Agent Address Discovery Request to the Home
11434 + * Agents anycast address in the nodes home network.
11437 +mipv6_icmpv6_send_dhaad_req(struct in6_addr *home_addr, int plen, __u16 dhaad_id)
11439 + struct in6_addr ha_anycast;
11440 + struct in6_addr careofaddr;
11442 + if (mipv6_get_care_of_address(home_addr, &careofaddr) < 0) {
11443 + DEBUG(DBG_WARNING, "Could not get node's Care-of Address");
11447 + if (mipv6_ha_anycast(&ha_anycast, home_addr, plen) < 0) {
11448 + DEBUG(DBG_WARNING,
11449 + "Could not get Home Agent Anycast address for home address %x:%x.%x:%x:%x:%x:%x:%x/%d",
11450 + NIPV6ADDR(home_addr), plen);
11454 + mipv6_icmpv6_send(&ha_anycast, &careofaddr, MIPV6_DHAAD_REQUEST, 0,
11455 + &dhaad_id, 0, NULL, 0);
11460 + * mipv6_icmpv6_dhaad_rep - Home Agent Address Discovery Reply ICMP handler
11461 + * @skb: buffer containing ICMP information message
11463 + * Special Mobile IPv6 ICMP message. Handles Dynamic Home Agent
11464 + * Address Discovery Reply messages.
11466 +int mipv6_icmpv6_rcv_dhaad_rep(struct sk_buff *skb)
11468 + struct icmp6hdr *phdr = (struct icmp6hdr *) skb->h.raw;
11469 + struct in6_addr *address;
11470 + struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
11471 + __u16 identifier;
11472 + int ulen = (skb->tail - (unsigned char *) ((__u32 *) phdr + 2));
11474 + struct in6_addr home_addr, coa;
11475 + struct in6_addr *first_ha = NULL;
11476 + struct mn_info *minfo;
11477 + int n_addr = ulen / sizeof(struct in6_addr);
11481 + /* Invalid packet checks. */
11482 + if (ulen % sizeof(struct in6_addr) != 0)
11485 + if (phdr->icmp6_code != 0)
11488 + identifier = ntohs(phdr->icmp6_identifier);
11490 + address = (struct in6_addr *) ((__u32 *) phdr + 2);
11496 + /* receive list of home agent addresses
11497 + * add to home agents list
11499 + DEBUG(DBG_INFO, "DHAAD: got %d home agents", n_addr);
11501 + first_ha = address;
11503 + /* lookup H@ with identifier */
11504 + read_lock(&mn_info_lock);
11505 + minfo = mipv6_mninfo_get_by_id(identifier);
11507 + read_unlock(&mn_info_lock);
11508 + DEBUG(DBG_INFO, "no mninfo with id %d",
11512 + spin_lock(&minfo->lock);
11515 + * 1. if old HA on list, prefer it
11516 + * 2. otherwise first HA on list prefered
11518 + for (i = 0; i < n_addr; i++) {
11519 + DEBUG(DBG_INFO, "HA[%d] %x:%x:%x:%x:%x:%x:%x:%x",
11520 + i, NIPV6ADDR(address));
11521 + if (ipv6_addr_cmp(&minfo->ha, address) == 0) {
11522 + spin_unlock(&minfo->lock);
11523 + read_unlock(&mn_info_lock);
11528 + ipv6_addr_copy(&minfo->ha, first_ha);
11529 + spin_unlock(&minfo->lock);
11530 + ipv6_addr_copy(&home_addr, &minfo->home_addr);
11531 + read_unlock(&mn_info_lock);
11533 + mipv6_get_care_of_address(&home_addr, &coa);
11534 + init_home_registration(&home_addr, &coa);
11540 + * mipv6_icmpv6_handle_pfx_adv - handle prefix advertisements
11541 + * @skb: sk_buff including the icmp6 message
11543 +int mipv6_icmpv6_rcv_pfx_adv(struct sk_buff *skb)
11545 + struct icmp6hdr *hdr = (struct icmp6hdr *) skb->h.raw;
11546 + struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
11547 + struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
11548 + __u8 *opt = (__u8 *) (hdr + 1);
11549 + int optlen = (skb->tail - opt);
11550 + unsigned long min_expire = INFINITY;
11551 + struct inet6_skb_parm *parm = (struct inet6_skb_parm *) skb->cb;
11555 + while (optlen > 0) {
11556 + int len = opt[1] << 3;
11560 + if (opt[0] == ND_OPT_PREFIX_INFO) {
11562 + unsigned long expire;
11563 + struct prefix_info *pinfo =
11564 + (struct prefix_info *) opt;
11565 + struct net_device *dev;
11566 + struct mn_info *mninfo;
11568 + read_lock(&mn_info_lock);
11569 + mninfo = mipv6_mninfo_get_by_ha(saddr);
11570 + if (mninfo == NULL) {
11573 + spin_lock(&mninfo->lock);
11574 + ifindex = mninfo->ifindex;
11575 + spin_unlock(&mninfo->lock);
11578 + read_unlock(&mn_info_lock);
11580 + if (!(dev = dev_get_by_index(ifindex))) {
11581 + DEBUG(DBG_WARNING, "Cannot find device by index %d", parm->iif);
11585 + expire = ntohl(pinfo->valid);
11586 + expire = expire == 0 ? INFINITY : expire;
11588 + min_expire = expire < min_expire ? expire : min_expire;
11600 + mipv6_pfx_add_home(parm->iif, saddr, daddr, min_expire);
11604 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/mn.c linux-2.4.25/net/ipv6/mobile_ip6/mn.c
11605 --- linux-2.4.25.old/net/ipv6/mobile_ip6/mn.c 1970-01-01 01:00:00.000000000 +0100
11606 +++ linux-2.4.25/net/ipv6/mobile_ip6/mn.c 2004-06-26 11:29:31.000000000 +0100
11609 + * Mobile-node functionality
11612 + * Sami Kivisaari <skivisaa@cc.hut.fi>
11616 + * This program is free software; you can redistribute it and/or
11617 + * modify it under the terms of the GNU General Public License
11618 + * as published by the Free Software Foundation; either version
11619 + * 2 of the License, or (at your option) any later version.
11623 +#include <linux/autoconf.h>
11624 +#include <linux/sched.h>
11625 +#include <linux/ipv6.h>
11626 +#include <linux/net.h>
11627 +#include <linux/init.h>
11628 +#include <linux/skbuff.h>
11629 +#include <linux/rtnetlink.h>
11630 +#include <linux/if_arp.h>
11631 +#include <linux/ipsec.h>
11632 +#include <linux/notifier.h>
11633 +#include <linux/list.h>
11634 +#include <linux/route.h>
11635 +#include <linux/netfilter.h>
11636 +#include <linux/netfilter_ipv6.h>
11637 +#include <linux/tqueue.h>
11638 +#include <linux/proc_fs.h>
11640 +#include <asm/uaccess.h>
11642 +#include <net/ipv6.h>
11643 +#include <net/addrconf.h>
11644 +#include <net/neighbour.h>
11645 +#include <net/ndisc.h>
11646 +#include <net/ip6_route.h>
11647 +#include <net/mipglue.h>
11650 +#include "mdetect.h"
11652 +#include "mobhdr.h"
11653 +#include "debug.h"
11655 +#include "mipv6_icmp.h"
11656 +#include "multiaccess_ctl.h"
11657 +//#include "prefix.h"
11658 +#include "tunnel_mn.h"
11659 +#include "stats.h"
11660 +#include "config.h"
11662 +#define MIPV6_BUL_SIZE 128
11664 +static LIST_HEAD(mn_info_list);
11666 +/* Lock for list of MN infos */
11667 +rwlock_t mn_info_lock = RW_LOCK_UNLOCKED;
11669 +static spinlock_t ifrh_lock = SPIN_LOCK_UNLOCKED;
11671 +struct ifr_holder {
11672 + struct list_head list;
11673 + struct in6_ifreq ifr;
11675 + struct handoff *ho;
11678 +LIST_HEAD(ifrh_list);
11680 +static struct tq_struct mv_home_addr_task;
11682 +/* Determines whether manually configured home addresses are preferred as
11683 + * source addresses over dynamically configured ones
11685 +int mipv6_use_preconfigured_hoaddr = 1;
11687 +/* Determines whether home addresses, which are at home are preferred as
11688 + * source addresses over other home addresses
11690 +int mipv6_use_topol_corr_hoaddr = 0;
11692 +static spinlock_t icmpv6_id_lock = SPIN_LOCK_UNLOCKED;
11693 +static __u16 icmpv6_id = 0;
11695 +static inline __u16 mipv6_get_dhaad_id(void)
11698 + spin_lock_bh(&icmpv6_id_lock);
11699 + ret = ++icmpv6_id;
11700 + spin_unlock_bh(&icmpv6_id_lock);
11705 + * mipv6_mninfo_get_by_home - Returns mn_info for a home address
11706 + * @haddr: home address of MN
11708 + * Returns mn_info on success %NULL otherwise. Caller MUST hold
11709 + * @mn_info_lock (read or write).
11711 +struct mn_info *mipv6_mninfo_get_by_home(struct in6_addr *haddr)
11713 + struct list_head *lh;
11714 + struct mn_info *minfo;
11721 + list_for_each(lh, &mn_info_list) {
11722 + minfo = list_entry(lh, struct mn_info, list);
11723 + spin_lock(&minfo->lock);
11724 + if (!ipv6_addr_cmp(&minfo->home_addr, haddr)) {
11725 + spin_unlock(&minfo->lock);
11728 + spin_unlock(&minfo->lock);
11734 + * mipv6_mninfo_get_by_ha - Lookup mn_info with Home Agent address
11735 + * @home_agent: Home Agent address
11737 + * Searches for a mn_info entry with @ha set to @home_agent. You MUST
11738 + * hold @mn_info_lock when calling this function. Returns pointer to
11739 + * mn_info entry or %NULL on failure.
11741 +struct mn_info *mipv6_mninfo_get_by_ha(struct in6_addr *home_agent)
11743 + struct list_head *lh;
11744 + struct mn_info *minfo;
11749 + list_for_each(lh, &mn_info_list) {
11750 + minfo = list_entry(lh, struct mn_info, list);
11751 + spin_lock(&minfo->lock);
11752 + if (!ipv6_addr_cmp(&minfo->ha, home_agent)) {
11753 + spin_unlock(&minfo->lock);
11756 + spin_unlock(&minfo->lock);
11762 + * mipv6_mninfo_get_by_id - Lookup mn_info with id
11763 + * @id: DHAAD identifier
11765 + * Searches for a mn_info entry with @dhaad_id set to @id. You MUST
11766 + * hold @mn_info_lock when calling this function. Returns pointer to
11767 + * mn_info entry or %NULL on failure.
11769 +struct mn_info *mipv6_mninfo_get_by_id(unsigned short id)
11771 + struct list_head *lh;
11772 + struct mn_info *minfo = 0;
11774 + list_for_each(lh, &mn_info_list) {
11775 + minfo = list_entry(lh, struct mn_info, list);
11776 + spin_lock(&minfo->lock);
11777 + if (minfo->dhaad_id == id) {
11778 + spin_unlock(&minfo->lock);
11781 + spin_unlock(&minfo->lock);
11787 + * mipv6_mninfo_add - Adds a new home info for MN
11788 + * @ifindex: Interface for home address
11789 + * @home_addr: Home address of MN, must be set
11790 + * @plen: prefix length of the home address, must be set
11791 + * @isathome : home address at home
11792 + * @lifetime: lifetime of the home address, 0 is infinite
11793 + * @ha: home agent for the home address
11794 + * @ha_plen: prefix length of home agent's address, can be zero
11795 + * @ha_lifetime: Lifetime of the home address, 0 is infinite
11797 + * The function adds a new home info entry for MN, allowing it to
11798 + * register the home address with the home agent. Starts home
11799 + * registration process. If @ha is %ADDRANY, DHAAD is performed to
11800 + * find a home agent. Returns 0 on success, a negative value
11801 + * otherwise. Caller MUST NOT hold @mn_info_lock or
11802 + * @addrconf_hash_lock.
11804 +void mipv6_mninfo_add(int ifindex, struct in6_addr *home_addr, int plen,
11805 + int isathome, unsigned long lifetime, struct in6_addr *ha,
11806 + int ha_plen, unsigned long ha_lifetime, int man_conf)
11808 + struct mn_info *minfo;
11809 + struct in6_addr coa;
11813 + write_lock_bh(&mn_info_lock);
11814 + if ((minfo = mipv6_mninfo_get_by_home(home_addr)) != NULL){
11815 + DEBUG(1, "MN info already exists");
11816 + write_unlock_bh(&mn_info_lock);
11819 + minfo = kmalloc(sizeof(struct mn_info), GFP_ATOMIC);
11821 + write_unlock_bh(&mn_info_lock);
11824 + memset(minfo, 0, sizeof(struct mn_info));
11825 + spin_lock_init(&minfo->lock);
11828 + ipv6_addr_copy(&minfo->home_addr, home_addr);
11831 + ipv6_addr_copy(&minfo->ha, ha);
11832 + if (ha_plen < 128 && ha_plen > 0)
11833 + minfo->home_plen = ha_plen;
11834 + else minfo->home_plen = 64;
11836 + minfo->ifindex_user = ifindex; /* Ifindex for tunnel interface */
11837 + minfo->ifindex = ifindex; /* Interface on which home address is currently conf'd */
11838 + /* TODO: we should get home address lifetime from somewhere */
11839 + /* minfo->home_addr_expires = jiffies + lifetime * HZ; */
11841 + /* manual configuration flag cannot be unset by dynamic updates
11842 + * from prefix advertisements
11844 + if (!minfo->man_conf) minfo->man_conf = man_conf;
11845 + minfo->is_at_home = isathome;
11847 + list_add(&minfo->list, &mn_info_list);
11848 + write_unlock_bh(&mn_info_lock);
11850 + if (mipv6_get_care_of_address(home_addr, &coa) == 0)
11851 + init_home_registration(home_addr, &coa);
11855 + * mipv6_mninfo_del - Delete home info for MN
11856 + * @home_addr : Home address or prefix
11857 + * @del_dyn_only : Delete only dynamically created home entries
11859 + * Deletes every mn_info entry that matches the first plen bits of
11860 + * @home_addr. Returns number of deleted entries on success and a
11861 + * negative value otherwise. Caller MUST NOT hold @mn_info_lock.
11863 +int mipv6_mninfo_del(struct in6_addr *home_addr, int del_dyn_only)
11865 + struct list_head *lh, *next;
11866 + struct mn_info *minfo;
11871 + write_lock(&mn_info_lock);
11873 + list_for_each_safe(lh, next, &mn_info_list) {
11874 + minfo = list_entry(lh, struct mn_info, list);
11875 + if (ipv6_addr_cmp(&minfo->home_addr, home_addr) == 0
11876 + && ((!minfo->man_conf && del_dyn_only) || !del_dyn_only)){
11877 + list_del(&minfo->list);
11882 + write_unlock(&mn_info_lock);
11886 +void mipv6_mn_set_home(int ifindex, struct in6_addr *homeaddr, int plen,
11887 + struct in6_addr *homeagent, int ha_plen)
11889 + mipv6_mninfo_add(ifindex, homeaddr, plen, 0, 0,
11890 + homeagent, ha_plen, 0, 1);
11893 +static int skip_dad(struct in6_addr *addr)
11895 + struct mn_info *minfo;
11898 + if (addr == NULL) {
11899 + DEBUG(DBG_CRITICAL, "Null argument");
11902 + read_lock_bh(&mn_info_lock);
11903 + if ((minfo = mipv6_mninfo_get_by_home(addr)) != NULL) {
11904 + if ((minfo->is_at_home != MN_NOT_AT_HOME) && (minfo->has_home_reg))
11906 + DEBUG(DBG_INFO, "minfo->is_at_home = %d, minfo->has_home_reg = %d",
11907 + minfo->is_at_home, minfo->has_home_reg);
11909 + read_unlock_bh(&mn_info_lock);
11914 + * mipv6_mn_is_home_addr - Determines if addr is node's home address
11915 + * @addr: IPv6 address
11917 + * Returns 1 if addr is node's home address. Otherwise returns zero.
11919 +int mipv6_mn_is_home_addr(struct in6_addr *addr)
11923 + if (addr == NULL) {
11924 + DEBUG(DBG_CRITICAL, "Null argument");
11927 + read_lock_bh(&mn_info_lock);
11928 + if (mipv6_mninfo_get_by_home(addr))
11930 + read_unlock_bh(&mn_info_lock);
11936 + * mipv6_mn_is_at_home - determine if node is home for a home address
11937 + * @home_addr : home address of MN
11939 + * Returns 1 if home address in question is in the home network, 0
11940 + * otherwise. Caller MUST NOT not hold @mn_info_lock.
11942 +int mipv6_mn_is_at_home(struct in6_addr *home_addr)
11944 + struct mn_info *minfo;
11946 + read_lock_bh(&mn_info_lock);
11947 + if ((minfo = mipv6_mninfo_get_by_home(home_addr)) != NULL) {
11948 + spin_lock(&minfo->lock);
11949 + ret = (minfo->is_at_home == MN_AT_HOME);
11950 + spin_unlock(&minfo->lock);
11952 + read_unlock_bh(&mn_info_lock);
11955 +void mipv6_mn_set_home_reg(struct in6_addr *home_addr, int has_home_reg)
11957 + struct mn_info *minfo;
11958 + read_lock_bh(&mn_info_lock);
11960 + if ((minfo = mipv6_mninfo_get_by_home(home_addr)) != NULL) {
11961 + spin_lock(&minfo->lock);
11962 + minfo->has_home_reg = has_home_reg;
11963 + spin_unlock(&minfo->lock);
11965 + read_unlock_bh(&mn_info_lock);
11968 +static int mn_inet6addr_event(
11969 + struct notifier_block *nb, unsigned long event, void *ptr)
11971 + struct inet6_ifaddr *ifp = (struct inet6_ifaddr *)ptr;
11975 + /* Is address a valid coa ?*/
11976 + if (!(ifp->flags & IFA_F_TENTATIVE))
11977 + mipv6_mdet_finalize_ho(&ifp->addr,
11978 + ifp->idev->dev->ifindex);
11979 + else if(skip_dad(&ifp->addr))
11980 + ifp->flags &= ~IFA_F_TENTATIVE;
11982 + case NETDEV_DOWN:
11984 + /* This is useless with manually configured home
11985 + addresses, which will not expire
11987 + mipv6_mninfo_del(&ifp->addr, 0);
11993 + return NOTIFY_DONE;
11996 +struct notifier_block mipv6_mn_inet6addr_notifier = {
11997 + mn_inet6addr_event,
11999 + 0 /* check if using zero is ok */
12002 +static void mipv6_get_saddr_hook(struct in6_addr *homeaddr)
12004 + int found = 0, reiter = 0;
12005 + struct list_head *lh;
12006 + struct mn_info *minfo = NULL;
12007 + struct in6_addr coa;
12009 + read_lock_bh(&mn_info_lock);
12011 + list_for_each(lh, &mn_info_list) {
12012 + minfo = list_entry(lh, struct mn_info, list);
12013 + if ((ipv6_addr_scope(homeaddr) != ipv6_addr_scope(&minfo->home_addr))
12014 + || ipv6_chk_addr(&minfo->home_addr, NULL) == 0)
12017 + spin_lock(&minfo->lock);
12018 + if (minfo->is_at_home == MN_AT_HOME || minfo->has_home_reg) {
12019 + if ((mipv6_use_topol_corr_hoaddr &&
12020 + minfo->is_at_home == MN_AT_HOME) ||
12021 + (mipv6_use_preconfigured_hoaddr &&
12022 + minfo->man_conf) ||
12023 + (!(mipv6_use_preconfigured_hoaddr ||
12024 + mipv6_use_topol_corr_hoaddr) || reiter)) {
12025 + spin_unlock(&minfo->lock);
12026 + ipv6_addr_copy(homeaddr, &minfo->home_addr);
12031 + spin_unlock(&minfo->lock);
12033 + if (!found && !reiter) {
12038 + if (!found && minfo &&
12039 + !mipv6_get_care_of_address(&minfo->home_addr, &coa)) {
12040 + ipv6_addr_copy(homeaddr, &coa);
12042 + read_unlock_bh(&mn_info_lock);
12044 + DEBUG(DBG_DATADUMP, "Source address selection: %x:%x:%x:%x:%x:%x:%x:%x",
12045 + NIPV6ADDR(homeaddr));
12049 +static void mv_home_addr(void *arg)
12051 + mm_segment_t oldfs;
12052 + int err = 0, new_if = 0;
12053 + struct list_head *lh, *next;
12054 + struct ifr_holder *ifrh;
12057 + DEBUG(DBG_INFO, "mipv6 move home address task");
12059 + spin_lock_bh(&ifrh_lock);
12060 + list_splice_init(&ifrh_list, &list);
12061 + spin_unlock_bh(&ifrh_lock);
12063 + oldfs = get_fs(); set_fs(KERNEL_DS);
12064 + list_for_each_safe(lh, next, &list) {
12065 + ifrh = list_entry(lh, struct ifr_holder, list);
12066 + if (ifrh->old_ifi) {
12067 + new_if = ifrh->ifr.ifr6_ifindex;
12068 + ifrh->ifr.ifr6_ifindex = ifrh->old_ifi;
12069 + err = addrconf_del_ifaddr(&ifrh->ifr);
12070 + ifrh->ifr.ifr6_ifindex = new_if;
12072 + DEBUG(DBG_WARNING, "removal of home address %x:%x:%x:%x:%x:%x:%x:%x from"
12073 + " old interface %d failed with status %d",
12074 + NIPV6ADDR(&ifrh->ifr.ifr6_addr), ifrh->old_ifi, err);
12077 + err = addrconf_add_ifaddr(&ifrh->ifr);
12080 + DEBUG(DBG_INFO, "Calling mobile_node moved after moving home address to new if");
12081 + mipv6_mobile_node_moved(ifrh->ho);
12083 + list_del(&ifrh->list);
12089 + DEBUG(DBG_WARNING, "adding of home address to a new interface %d failed %d", new_if, err);
12091 + DEBUG(DBG_WARNING, "adding of home address to a new interface OK");
12095 +struct dhaad_halist {
12096 + struct list_head list;
12097 + struct in6_addr addr;
12101 +/* clear all has from candidate list. do this when a new dhaad reply
12102 + * is received. */
12103 +int mipv6_mn_flush_ha_candidate(struct list_head *ha)
12105 + struct list_head *p, *tmp;
12106 + struct dhaad_halist *e;
12108 + list_for_each_safe(p, tmp, ha) {
12109 + e = list_entry(p, struct dhaad_halist, list);
12117 +/* add new ha to candidates. only done when dhaad reply is received. */
12118 +int mipv6_mn_add_ha_candidate(struct list_head *ha, struct in6_addr *addr)
12120 + struct dhaad_halist *e;
12122 + e = kmalloc(sizeof(*e), GFP_ATOMIC);
12123 + memset(e, 0, sizeof(*e));
12124 + ipv6_addr_copy(&e->addr, addr);
12126 + list_add_tail(&e->list, ha);
12130 +#define MAX_RETRIES_PER_HA 3
12132 +/* get next ha candidate. this is done when dhaad reply has been
12133 + * received and we want to register with the best available ha. */
12134 +int mipv6_mn_get_ha_candidate(struct list_head *ha, struct in6_addr *addr)
12136 + struct list_head *p;
12138 + list_for_each(p, ha) {
12139 + struct dhaad_halist *e;
12140 + e = list_entry(p, typeof(*e), list);
12141 + if (e->retry >= 0 && e->retry < MAX_RETRIES_PER_HA) {
12142 + ipv6_addr_copy(addr, &e->addr);
12149 +/* change candidate status. if registration with ha fails, we
12150 + * increase retry for ha candidate. if retry is >= 3 we set it to -1
12151 + * (failed), do get_ha_candidate() again */
12152 +int mipv6_mn_try_ha_candidate(struct list_head *ha, struct in6_addr *addr)
12154 + struct list_head *p;
12156 + list_for_each(p, ha) {
12157 + struct dhaad_halist *e;
12158 + e = list_entry(p, typeof(*e), list);
12159 + if (ipv6_addr_cmp(addr, &e->addr) == 0) {
12160 + if (e->retry >= MAX_RETRIES_PER_HA) e->retry = -1;
12161 + else if (e->retry >= 0) e->retry++;
12169 + * mipv6_mn_get_bulifetime - Get lifetime for a binding update
12170 + * @home_addr: home address for BU
12171 + * @coa: care-of address for BU
12172 + * @flags: flags used for BU
12174 + * Returns maximum lifetime for BUs determined by the lifetime of
12175 + * care-of address and the lifetime of home address.
12177 +__u32 mipv6_mn_get_bulifetime(struct in6_addr *home_addr, struct in6_addr *coa,
12180 + struct inet6_ifaddr *ifp_hoa, *ifp_coa;
12181 + __u32 lifetime = (flags & MIPV6_BU_F_HOME ?
12182 + HA_BU_DEF_LIFETIME : CN_BU_DEF_LIFETIME);
12184 + ifp_hoa = ipv6_get_ifaddr(home_addr, NULL);
12186 + DEBUG(DBG_INFO, "home address missing");
12189 + if (!(ifp_hoa->flags & IFA_F_PERMANENT)){
12190 + if (ifp_hoa->valid_lft)
12191 + lifetime = min_t(__u32, lifetime, ifp_hoa->valid_lft);
12193 + DEBUG(DBG_ERROR, "Zero lifetime for home address");
12195 + in6_ifa_put(ifp_hoa);
12197 + ifp_coa = ipv6_get_ifaddr(coa, NULL);
12199 + DEBUG(DBG_INFO, "care-of address missing");
12202 + if (!(ifp_coa->flags & IFA_F_PERMANENT)) {
12203 + if(ifp_coa->valid_lft)
12204 + lifetime = min_t(__u32, lifetime, ifp_coa->valid_lft);
12207 + "Zero lifetime for care-of address");
12209 + in6_ifa_put(ifp_coa);
12211 + DEBUG(DBG_INFO, "Lifetime for binding is %ld", lifetime);
12216 +mipv6_mn_tnl_rcv_send_bu_hook(struct ip6_tnl *t, struct sk_buff *skb)
12218 + struct ipv6hdr *inner;
12219 + struct ipv6hdr *outer = skb->nh.ipv6h;
12220 + struct mn_info *minfo = NULL;
12222 + __u8 user_flags = 0;
12226 + if (!is_mip6_tnl(t))
12227 + return IP6_TNL_ACCEPT;
12229 + if (!mip6node_cnf.accept_ret_rout) {
12230 + DEBUG(DBG_INFO, "Return routability administratively disabled"
12231 + " not doing route optimization");
12232 + return IP6_TNL_ACCEPT;
12234 + if (!pskb_may_pull(skb, skb->h.raw-skb->data+sizeof(*inner)))
12235 + return IP6_TNL_DROP;
12237 + inner = (struct ipv6hdr *)skb->h.raw;
12239 + read_lock(&mn_info_lock);
12240 + minfo = mipv6_mninfo_get_by_home(&inner->daddr);
12243 + DEBUG(DBG_WARNING, "MN info missing");
12244 + read_unlock(&mn_info_lock);
12245 + return IP6_TNL_ACCEPT;
12247 + DEBUG(DBG_DATADUMP, "MIPV6 MN: Received a tunneled IPv6 packet"
12248 + " to %x:%x:%x:%x:%x:%x:%x:%x,"
12249 + " from %x:%x:%x:%x:%x:%x:%x:%x with\n tunnel header"
12250 + "daddr: %x:%x:%x:%x:%x:%x:%x:%x,"
12251 + "saddr: %x:%x:%x:%x:%x:%x:%x:%x",
12252 + NIPV6ADDR(&inner->daddr), NIPV6ADDR(&inner->saddr),
12253 + NIPV6ADDR(&outer->daddr), NIPV6ADDR(&outer->saddr));
12255 + spin_lock(&minfo->lock);
12257 + /* We don't send bus in response to all tunneled packets */
12259 + if (!ipv6_addr_cmp(&minfo->ha, &inner->saddr)) {
12260 + spin_unlock(&minfo->lock);
12261 + read_unlock(&mn_info_lock);
12262 + DEBUG(DBG_ERROR, "HA BUG: Received a tunneled packet "
12263 + "originally sent by home agent, not sending BU");
12264 + return IP6_TNL_ACCEPT;
12266 + spin_unlock(&minfo->lock);
12267 + read_unlock(&mn_info_lock);
12269 + DEBUG(DBG_DATADUMP, "Sending BU to correspondent node");
12271 + user_flags |= mip6node_cnf.bu_cn_ack ? MIPV6_BU_F_ACK : 0;
12273 + if (inner->nexthdr != IPPROTO_DSTOPTS &&
12274 + inner->nexthdr != IPPROTO_MOBILITY) {
12275 + struct in6_addr coa;
12276 + /* Don't start RR when receiving ICMP error messages */
12277 + if (inner->nexthdr == IPPROTO_ICMPV6) {
12278 + int ptr = (u8*)(inner+1) - skb->data;
12281 + if (skb_copy_bits(skb,
12282 + ptr+offsetof(struct icmp6hdr,
12285 + || !(type & ICMPV6_INFOMSG_MASK)) {
12286 + return IP6_TNL_ACCEPT;
12289 + lifetime = mipv6_mn_get_bulifetime(&inner->daddr,
12290 + &outer->daddr, 0);
12292 + !mipv6_get_care_of_address(&inner->daddr, &coa)) {
12293 + write_lock(&bul_lock);
12294 + mipv6_send_bu(&inner->daddr, &inner->saddr, &coa,
12295 + INITIAL_BINDACK_TIMEOUT,
12296 + MAX_BINDACK_TIMEOUT, 1,
12299 + write_unlock(&bul_lock);
12302 + DEBUG(DBG_DATADUMP, "setting rcv_tunnel flag in skb");
12303 + skb->security |= MIPV6_RCV_TUNNEL;
12304 + return IP6_TNL_ACCEPT;
12307 +static struct ip6_tnl_hook_ops mipv6_mn_tnl_rcv_send_bu_ops = {
12309 + IP6_TNL_PRE_DECAP,
12310 + IP6_TNL_PRI_FIRST,
12311 + mipv6_mn_tnl_rcv_send_bu_hook
12315 +mipv6_mn_tnl_xmit_stats_hook(struct ip6_tnl *t, struct sk_buff *skb)
12318 + if (is_mip6_tnl(t))
12319 + MIPV6_INC_STATS(n_encapsulations);
12320 + return IP6_TNL_ACCEPT;
12323 +static struct ip6_tnl_hook_ops mipv6_mn_tnl_xmit_stats_ops = {
12325 + IP6_TNL_PRE_ENCAP,
12326 + IP6_TNL_PRI_LAST,
12327 + mipv6_mn_tnl_xmit_stats_hook
12331 +mipv6_mn_tnl_rcv_stats_hook(struct ip6_tnl *t, struct sk_buff *skb)
12334 + if (is_mip6_tnl(t))
12335 + MIPV6_INC_STATS(n_decapsulations);
12336 + return IP6_TNL_ACCEPT;
12339 +static struct ip6_tnl_hook_ops mipv6_mn_tnl_rcv_stats_ops = {
12341 + IP6_TNL_PRE_DECAP,
12342 + IP6_TNL_PRI_LAST,
12343 + mipv6_mn_tnl_rcv_stats_hook
12346 +static void mn_check_tunneled_packet(struct sk_buff *skb)
12349 + /* If tunnel flag was set */
12350 + if (skb->security & MIPV6_RCV_TUNNEL) {
12351 + struct in6_addr coa;
12353 + __u8 user_flags = 0;
12354 + int ptr = (u8*)(skb->nh.ipv6h+1) - skb->data;
12355 + int len = skb->len - ptr;
12356 + __u8 nexthdr = skb->nh.ipv6h->nexthdr;
12361 + ptr = ipv6_skip_exthdr(skb, ptr, &nexthdr, len);
12365 + if (!mip6node_cnf.accept_ret_rout) {
12366 + DEBUG(DBG_INFO, "Return routability administratively disabled");
12369 + if (nexthdr == IPPROTO_MOBILITY)
12372 + /* Don't start RR when receiving ICMP error messages */
12373 + if (nexthdr == IPPROTO_ICMPV6) {
12376 + if (skb_copy_bits(skb,
12377 + ptr+offsetof(struct icmp6hdr,
12380 + || !(type & ICMPV6_INFOMSG_MASK)) {
12384 + user_flags |= mip6node_cnf.bu_cn_ack ? MIPV6_BU_F_ACK : 0;
12385 + mipv6_get_care_of_address(&skb->nh.ipv6h->daddr, &coa);
12386 + lifetime = mipv6_mn_get_bulifetime(&skb->nh.ipv6h->daddr,
12389 + DEBUG(DBG_WARNING, "packet to address %x:%x:%x:%x:%x:%x:%x:%x"
12390 + "was tunneled. Sending BU to CN"
12391 + "%x:%x:%x:%x:%x:%x:%x:%x",
12392 + NIPV6ADDR(&skb->nh.ipv6h->daddr),
12393 + NIPV6ADDR(&skb->nh.ipv6h->saddr));
12394 + /* This should work also with home address option */
12396 + write_lock(&bul_lock);
12397 + mipv6_send_bu(&skb->nh.ipv6h->daddr, &skb->nh.ipv6h->saddr,
12398 + &coa, INITIAL_BINDACK_TIMEOUT,
12399 + MAX_BINDACK_TIMEOUT, 1, user_flags,
12401 + write_unlock(&bul_lock);
12405 +static int sched_mv_home_addr_task(struct in6_addr *haddr, int plen_new,
12406 + int newif, int oldif, struct handoff *ho)
12409 + struct ifr_holder *ifrh;
12411 + alloc_size = sizeof(*ifrh) + (ho ? sizeof(*ho): 0);
12412 + if ((ifrh = kmalloc(alloc_size, GFP_ATOMIC)) == NULL) {
12413 + DEBUG(DBG_ERROR, "Out of memory");
12417 + ifrh->ho = (struct handoff *)((struct ifr_holder *)(ifrh + 1));
12418 + memcpy(ifrh->ho, ho, sizeof(*ho));
12422 + /* must queue task to avoid deadlock with rtnl */
12423 + ifrh->ifr.ifr6_ifindex = newif;
12424 + ifrh->ifr.ifr6_prefixlen = plen_new;
12425 + ipv6_addr_copy(&ifrh->ifr.ifr6_addr, haddr);
12426 + ifrh->old_ifi = oldif;
12428 + spin_lock_bh(&ifrh_lock);
12429 + list_add_tail(&ifrh->list, &ifrh_list);
12430 + spin_unlock_bh(&ifrh_lock);
12432 + schedule_task(&mv_home_addr_task);
12437 +static void send_ret_home_ns(struct in6_addr *ha_addr,
12438 + struct in6_addr *home_addr,
12441 + struct in6_addr nil;
12442 + struct in6_addr mcaddr;
12443 + struct net_device *dev = dev_get_by_index(ifindex);
12446 + memset(&nil, 0, sizeof(nil));
12447 + addrconf_addr_solict_mult(home_addr, &mcaddr);
12448 + ndisc_send_ns(dev, NULL, home_addr, &mcaddr, &nil);
12452 +static inline int ha_is_reachable(int ifindex, struct in6_addr *ha)
12454 + struct net_device *dev;
12455 + int reachable = 0;
12457 + dev = dev_get_by_index(ifindex);
12459 + struct neighbour *neigh;
12460 + if ((neigh = ndisc_get_neigh(dev, ha)) != NULL) {
12461 + read_lock_bh(&neigh->lock);
12462 + if (neigh->nud_state&NUD_VALID)
12464 + read_unlock_bh(&neigh->lock);
12465 + neigh_release(neigh);
12469 + return reachable;
12472 +static int mn_ha_handoff(struct handoff *ho)
12474 + struct list_head *lh;
12475 + struct mn_info *minfo;
12476 + struct in6_addr *coa= ho->coa;
12477 + int wait_mv_home = 0;
12479 + read_lock_bh(&mn_info_lock);
12480 + list_for_each(lh, &mn_info_list) {
12481 + __u8 has_home_reg;
12483 + struct in6_addr ha;
12486 + struct mipv6_bul_entry *entry = NULL;
12488 + minfo = list_entry(lh, struct mn_info, list);
12489 + spin_lock(&minfo->lock);
12490 + has_home_reg = minfo->has_home_reg;
12491 + ifindex = minfo->ifindex;
12492 + ipv6_addr_copy(&ha, &minfo->ha);
12494 + if (mipv6_prefix_compare(&ho->rtr_addr, &minfo->home_addr,
12496 + if (minfo->has_home_reg)
12497 + athome = minfo->is_at_home = MN_RETURNING_HOME;
12499 + athome = minfo->is_at_home = MN_AT_HOME;
12500 + coa = &minfo->home_addr;
12502 + spin_unlock(&minfo->lock);
12504 + /* Cancel prefix solicitation, rtr is our HA */
12505 + mipv6_pfx_cancel_send(&ho->rtr_addr, ifindex);
12507 + minfo->ifindex = ho->ifindex;
12509 + if (minfo->has_home_reg &&
12510 + !ha_is_reachable(ho->ifindex, &minfo->ha)) {
12511 + send_ret_home_ns(&minfo->ha,
12512 + &minfo->home_addr,
12514 + mipv6_mdet_set_curr_rtr_reachable(0);
12517 + if (ifindex != ho->ifindex){
12520 + "Moving home address back to "
12521 + "the home interface");
12522 + sched_mv_home_addr_task(&minfo->home_addr,
12527 + if (!has_home_reg || wait_mv_home)
12533 + athome = minfo->is_at_home = MN_NOT_AT_HOME;
12534 + if (minfo->ifindex_user != minfo->ifindex) {
12535 + DEBUG(DBG_INFO, "Scheduling home address move to virtual interface");
12536 + sched_mv_home_addr_task(&minfo->home_addr,
12538 + minfo->ifindex_user,
12539 + minfo->ifindex, ho); /* Is minfo->ifindex correct */
12543 + minfo->ifindex = minfo->ifindex_user;
12544 + spin_unlock(&minfo->lock);
12545 + if (wait_mv_home)
12547 + if (!has_home_reg &&
12548 + init_home_registration(&minfo->home_addr,
12552 + lifetime = mipv6_mn_get_bulifetime(&minfo->home_addr,
12554 + MIPV6_BU_F_HOME);
12557 + write_lock(&bul_lock);
12558 + if (!(entry = mipv6_bul_get(&ha, &minfo->home_addr)) ||
12559 + !(entry->flags & MIPV6_BU_F_HOME)) {
12561 + "Unable to find home registration for "
12562 + "home address: %x:%x:%x:%x:%x:%x:%x:%x!\n",
12563 + NIPV6ADDR(&minfo->home_addr));
12564 + write_unlock(&bul_lock);
12567 + DEBUG(DBG_INFO, "Sending home de ? %d registration for "
12568 + "home address: %x:%x:%x:%x:%x:%x:%x:%x\n"
12569 + "to home agent %x:%x:%x:%x:%x:%x:%x:%x, "
12570 + "with lifetime %ld",
12571 + (athome != MN_NOT_AT_HOME),
12572 + NIPV6ADDR(&entry->home_addr),
12573 + NIPV6ADDR(&entry->cn_addr), lifetime);
12574 + mipv6_send_bu(&entry->home_addr, &entry->cn_addr,
12575 + coa, INITIAL_BINDACK_TIMEOUT,
12576 + MAX_BINDACK_TIMEOUT, 1, entry->flags,
12578 + write_unlock(&bul_lock);
12581 + read_unlock_bh(&mn_info_lock);
12582 + return wait_mv_home;
12585 + * mn_cn_handoff - called for every bul entry to send BU to CN
12586 + * @rawentry: bul entry
12587 + * @args: handoff event
12590 + * Since MN can have many home addresses and home networks, every BUL
12591 + * entry needs to be checked
12593 +int mn_cn_handoff(void *rawentry, void *args, unsigned long *sortkey)
12595 + struct mipv6_bul_entry *entry = (struct mipv6_bul_entry *)rawentry;
12596 + struct in6_addr *coa = (struct in6_addr *)args;
12600 + /* Home registrations already handled by mn_ha_handoff */
12601 + if (entry->flags & MIPV6_BU_F_HOME)
12602 + return ITERATOR_CONT;
12604 + /* BUL is locked by mipv6_mobile_node_moved which calls us
12605 + through mipv6_bul_iterate */
12607 + if (mipv6_prefix_compare(coa,
12608 + &entry->home_addr,
12610 + mipv6_send_bu(&entry->home_addr, &entry->cn_addr,
12611 + &entry->home_addr, INITIAL_BINDACK_TIMEOUT,
12612 + MAX_BINDACK_TIMEOUT, 1, entry->flags, 0,
12615 + u32 lifetime = mipv6_mn_get_bulifetime(&entry->home_addr,
12618 + mipv6_send_bu(&entry->home_addr, &entry->cn_addr,
12619 + coa, INITIAL_BINDACK_TIMEOUT,
12620 + MAX_BINDACK_TIMEOUT, 1, entry->flags,
12623 + return ITERATOR_CONT;
12627 +int mn_bul_invalidate(void *rawentry, void *args, unsigned long *sortkey)
12629 + struct mipv6_bul_entry *bul = (struct mipv6_bul_entry *)rawentry;
12630 + struct bul_inval_args *arg = (struct bul_inval_args *)args;
12634 + if (!ipv6_addr_cmp(arg->cn, &bul->cn_addr) &&
12635 + (!ipv6_addr_cmp(arg->mn, &bul->home_addr) ||
12636 + !ipv6_addr_cmp(arg->mn, &bul->coa))) {
12637 + if (arg->all_rr_states || !bul->rr ||
12638 + (bul->rr->rr_state != RR_INIT &&
12639 + bul->rr->rr_state != RR_DONE)) {
12640 + bul->state = ACK_ERROR;
12641 + bul->callback = bul_entry_expired;
12642 + bul->callback_time = jiffies +
12643 + DUMB_CN_BU_LIFETIME * HZ;
12644 + bul->expire = bul->callback_time;
12645 + DEBUG(DBG_INFO, "BUL entry set to ACK_ERROR");
12646 + mipv6_bul_reschedule(bul);
12649 + return ITERATOR_CONT;
12652 + * init_home_registration - start Home Registration process
12653 + * @home_addr: home address
12654 + * @coa: care-of address
12656 + * Checks whether we have a Home Agent address for this home address.
12657 + * If not starts Dynamic Home Agent Address Discovery. Otherwise
12658 + * tries to register with home agent if not already registered.
12659 + * Returns 1, if home registration process is started and 0 otherwise
12661 +int init_home_registration(struct in6_addr *home_addr, struct in6_addr *coa)
12663 + struct mn_info *hinfo;
12664 + struct in6_addr ha;
12668 + __u8 user_flags = 0, flags;
12672 + read_lock_bh(&mn_info_lock);
12673 + if ((hinfo = mipv6_mninfo_get_by_home(home_addr)) == NULL) {
12674 + DEBUG(DBG_ERROR, "No mn_info found for address: "
12675 + "%x:%x:%x:%x:%x:%x:%x:%x",
12676 + NIPV6ADDR(home_addr));
12677 + read_unlock_bh(&mn_info_lock);
12680 + spin_lock(&hinfo->lock);
12681 + if (mipv6_prefix_compare(&hinfo->home_addr, coa, hinfo->home_plen)) {
12682 + spin_unlock(&hinfo->lock);
12683 + read_unlock_bh(&mn_info_lock);
12684 + DEBUG(DBG_INFO, "Adding home address, MN at home");
12687 + if (ipv6_addr_any(&hinfo->ha)) {
12688 + int dhaad_id = mipv6_get_dhaad_id();
12689 + hinfo->dhaad_id = dhaad_id;
12690 + spin_unlock(&hinfo->lock);
12691 + mipv6_icmpv6_send_dhaad_req(home_addr, hinfo->home_plen, dhaad_id);
12692 + read_unlock_bh(&mn_info_lock);
12694 + "Home Agent address not set, initiating DHAAD");
12697 + ipv6_addr_copy(&ha, &hinfo->ha);
12698 + man_conf = hinfo->man_conf;
12699 + ifindex = hinfo->ifindex;
12700 + spin_unlock(&hinfo->lock);
12701 + read_unlock_bh(&mn_info_lock);
12704 + mipv6_pfx_add_ha(&ha, coa, ifindex);
12706 + if (mipv6_bul_exists(&ha, home_addr)) {
12707 + DEBUG(DBG_INFO, "BU already sent to HA");
12710 + /* user flags received through sysctl */
12711 + user_flags |= mip6node_cnf.bu_lladdr ? MIPV6_BU_F_LLADDR : 0;
12712 + user_flags |= mip6node_cnf.bu_keymgm ? MIPV6_BU_F_KEYMGM : 0;
12714 + flags = MIPV6_BU_F_HOME | MIPV6_BU_F_ACK | user_flags;
12716 + lifetime = mipv6_mn_get_bulifetime(home_addr, coa, flags);
12718 + DEBUG(DBG_INFO, "Sending initial home registration for "
12719 + "home address: %x:%x:%x:%x:%x:%x:%x:%x\n"
12720 + "to home agent %x:%x:%x:%x:%x:%x:%x:%x, "
12721 + "with lifetime %ld, prefixlength %d",
12722 + NIPV6ADDR(home_addr), NIPV6ADDR(&ha), lifetime, 0);
12724 + write_lock_bh(&bul_lock);
12725 + mipv6_send_bu(home_addr, &ha, coa, INITIAL_BINDACK_DAD_TIMEOUT,
12726 + MAX_BINDACK_TIMEOUT, 1, flags, lifetime, NULL);
12727 + write_unlock_bh(&bul_lock);
12733 + * mipv6_mobile_node_moved - Send BUs to all HAs and CNs
12734 + * @ho: handoff structure contains the new and previous routers
12736 + * Event for handoff. Sends BUs everyone on Binding Update List.
12738 +int mipv6_mobile_node_moved(struct handoff *ho)
12741 + int bu_to_prev_router = 1;
12747 + ma_ctl_upd_iface(ho->ifindex,
12748 + MA_IFACE_CURRENT | MA_IFACE_HAS_ROUTER, &dummy);
12750 + /* First send BU to HA, then to all other nodes that are on BU list */
12751 + if (mn_ha_handoff(ho) != 0)
12752 + return 0; /* Wait for move home address task */
12754 + /* Add current care-of address to mn_info list, if current router acts
12757 + if (ho->home_address && bu_to_prev_router)
12758 + mipv6_mninfo_add(ho->coa, ho->plen,
12759 + MN_AT_HOME, 0, &ho->rtr_addr,
12760 + ho->plen, ROUTER_BU_DEF_LIFETIME,
12768 + * mipv6_mn_send_home_na - send NA when returning home
12769 + * @haddr: home address to advertise
12771 + * After returning home, MN must advertise all its valid addresses in
12772 + * home link to all nodes.
12774 +void mipv6_mn_send_home_na(struct in6_addr *haddr)
12776 + struct net_device *dev = NULL;
12777 + struct in6_addr mc_allnodes;
12778 + struct mn_info *hinfo = NULL;
12780 + read_lock(&mn_info_lock);
12781 + hinfo = mipv6_mninfo_get_by_home(haddr);
12783 + read_unlock(&mn_info_lock);
12786 + spin_lock(&hinfo->lock);
12787 + hinfo->is_at_home = MN_AT_HOME;
12788 + dev = dev_get_by_index(hinfo->ifindex);
12789 + spin_unlock(&hinfo->lock);
12790 + read_unlock(&mn_info_lock);
12791 + if (dev == NULL) {
12792 + DEBUG(DBG_ERROR, "Send home_na: device not found.");
12796 + ipv6_addr_all_nodes(&mc_allnodes);
12797 + ndisc_send_na(dev, NULL, &mc_allnodes, haddr, 0, 0, 1, 1);
12801 +static int mn_use_hao(struct in6_addr *daddr, struct in6_addr *saddr)
12803 + struct mipv6_bul_entry *entry;
12804 + struct mn_info *minfo = NULL;
12807 + read_lock_bh(&mn_info_lock);
12808 + minfo = mipv6_mninfo_get_by_home(saddr);
12809 + if (minfo && minfo->is_at_home != MN_AT_HOME) {
12810 + read_lock_bh(&bul_lock);
12811 + if ((entry = mipv6_bul_get(daddr, saddr)) == NULL) {
12812 + read_unlock_bh(&bul_lock);
12813 + read_unlock_bh(&mn_info_lock);
12816 + add_ha = (entry->state != ACK_ERROR &&
12817 + (!entry->rr || entry->rr->rr_state == RR_DONE ||
12818 + entry->flags & MIPV6_BU_F_HOME));
12819 + read_unlock_bh(&bul_lock);
12821 + read_unlock_bh(&mn_info_lock);
12826 +mn_dev_event(struct notifier_block *nb, unsigned long event, void *ptr)
12828 + struct net_device *dev = ptr;
12829 + struct list_head *lh;
12830 + struct mn_info *minfo;
12833 + /* here are probably the events we need to worry about */
12836 + DEBUG(DBG_DATADUMP, "New netdevice %s registered.", dev->name);
12837 + if (dev->type != ARPHRD_LOOPBACK && !dev_is_mip6_tnl(dev))
12838 + ma_ctl_add_iface(dev->ifindex);
12841 + case NETDEV_GOING_DOWN:
12842 + DEBUG(DBG_DATADUMP, "Netdevice %s disappeared.", dev->name);
12844 + * Go through mn_info list and move all home addresses on the
12845 + * netdev going down to a new device. This will make it
12846 + * practically impossible for the home address to return home,
12847 + * but allow MN to retain its connections using the address.
12850 + read_lock_bh(&mn_info_lock);
12851 + list_for_each(lh, &mn_info_list) {
12852 + minfo = list_entry(lh, struct mn_info, list);
12853 + spin_lock(&minfo->lock);
12854 + if (minfo->ifindex == dev->ifindex) {
12855 + if (sched_mv_home_addr_task(&minfo->home_addr, 128,
12856 + minfo->ifindex_user,
12858 + minfo->ifindex = 0;
12859 + spin_unlock(&minfo->lock);
12860 + read_unlock_bh(&mn_info_lock);
12861 + return NOTIFY_DONE;
12863 + minfo->ifindex = minfo->ifindex_user;
12864 + if (minfo->is_at_home) {
12865 + minfo->is_at_home = 0;
12868 + newif = minfo->ifindex_user;
12871 + spin_unlock(&minfo->lock);
12874 + read_unlock_bh(&mn_info_lock);
12876 + ma_ctl_upd_iface(dev->ifindex, MA_IFACE_NOT_PRESENT, &newif);
12877 + mipv6_mdet_del_if(dev->ifindex);
12879 + return NOTIFY_DONE;
12882 +struct notifier_block mipv6_mn_dev_notifier = {
12885 + 0 /* check if using zero is ok */
12888 +static void deprecate_addr(struct mn_info *minfo)
12891 + * Lookup address from IPv6 address list and set deprecated flag
12897 + * Required because we can only modify addresses after the packet is
12898 + * constructed. We otherwise mess with higher level protocol
12899 + * pseudoheaders. With strict protocol layering life would be SO much
12902 +static unsigned int modify_xmit_addrs(unsigned int hooknum,
12903 + struct sk_buff **pskb,
12904 + const struct net_device *in,
12905 + const struct net_device *out,
12906 + int (*okfn) (struct sk_buff *))
12908 + struct sk_buff *skb = *pskb;
12913 + struct ipv6hdr *hdr = skb->nh.ipv6h;
12914 + struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
12915 + struct mipv6_bul_entry *bule;
12916 + struct in6_addr *daddr;
12918 + if (!ipv6_addr_any(&opt->hoa))
12919 + daddr = &opt->hoa;
12921 + daddr = &hdr->daddr;
12923 + /* We don't consult bul when sending a BU to avoid deadlock, since
12924 + * BUL is already locked.
12928 + if (opt->mipv6_flags & MIPV6_SND_HAO &&
12929 + !(opt->mipv6_flags & MIPV6_SND_BU)) {
12930 + write_lock(&bul_lock);
12931 + bule = mipv6_bul_get(daddr, &hdr->saddr);
12933 + write_unlock(&bul_lock);
12934 + return NF_ACCEPT;
12936 + if (!bule->rr || bule->rr->rr_state == RR_DONE ||
12937 + bule->flags & MIPV6_BU_F_HOME) {
12938 + DEBUG(DBG_DATADUMP,
12939 + "Replace source address with CoA and reroute");
12940 + ipv6_addr_copy(&hdr->saddr, &bule->coa);
12941 + skb->nfcache |= NFC_ALTERED;
12943 + write_unlock(&bul_lock);
12944 + } else if (opt->mipv6_flags & MIPV6_SND_HAO) {
12945 + mipv6_get_care_of_address(&hdr->saddr, &hdr->saddr);
12946 + skb->nfcache |= NFC_ALTERED;
12949 + return NF_ACCEPT;
12952 +/* We set a netfilter hook so that we can modify outgoing packet's
12953 + * source addresses
12955 +struct nf_hook_ops addr_modify_hook_ops = {
12956 + {NULL, NULL}, /* List head, no predecessor, no successor */
12957 + modify_xmit_addrs,
12959 + NF_IP6_LOCAL_OUT,
12960 + NF_IP6_PRI_FIRST /* Should be of EXTREMELY high priority since we
12961 + * do not want to mess with IPSec (possibly
12962 + * implemented as packet filter)
12966 +#define MN_INFO_LEN 77
12968 +static int mn_proc_info(char *buffer, char **start, off_t offset,
12971 + struct list_head *p;
12972 + struct mn_info *minfo;
12973 + int len = 0, skip = 0;
12977 + read_lock_bh(&mn_info_lock);
12978 + list_for_each(p, &mn_info_list) {
12979 + if (len < offset / MN_INFO_LEN) {
12983 + if (len >= length)
12985 + minfo = list_entry(p, struct mn_info, list);
12986 + spin_lock(&minfo->lock);
12987 + len += sprintf(buffer + len, "%02d %08x%08x%08x%08x %02x "
12988 + "%08x%08x%08x%08x %d %d\n",
12990 + ntohl(minfo->home_addr.s6_addr32[0]),
12991 + ntohl(minfo->home_addr.s6_addr32[1]),
12992 + ntohl(minfo->home_addr.s6_addr32[2]),
12993 + ntohl(minfo->home_addr.s6_addr32[3]),
12994 + minfo->home_plen,
12995 + ntohl(minfo->ha.s6_addr32[0]),
12996 + ntohl(minfo->ha.s6_addr32[1]),
12997 + ntohl(minfo->ha.s6_addr32[2]),
12998 + ntohl(minfo->ha.s6_addr32[3]),
12999 + minfo->is_at_home, minfo->has_home_reg);
13000 + spin_unlock(&minfo->lock);
13002 + read_unlock_bh(&mn_info_lock);
13006 + *start += offset % MN_INFO_LEN;
13008 + len -= offset % MN_INFO_LEN;
13010 + if (len > length)
13018 +int mipv6_mn_ha_nd_update(struct net_device *dev,
13019 + struct in6_addr *ha, u8 *lladdr)
13022 + struct neighbour *neigh;
13023 + if ((neigh = ndisc_get_neigh(dev, ha))) {
13024 + read_lock(&neigh->lock);
13025 + valid = neigh->nud_state & NUD_VALID;
13026 + read_unlock(&neigh->lock);
13027 + if (!valid && lladdr)
13028 + neigh_update(neigh, lladdr, NUD_REACHABLE, 0, 1);
13029 + neigh_release(neigh);
13034 +int mipv6_mn_ha_probe(struct inet6_ifaddr *ifp, u8 *lladdr)
13036 + struct mn_info *minfo;
13038 + if (!(minfo = mipv6_mninfo_get_by_home(&ifp->addr)) ||
13039 + ipv6_addr_any(&minfo->ha))
13042 + if (mipv6_mn_ha_nd_update(ifp->idev->dev, &minfo->ha, lladdr))
13043 + mipv6_mdet_retrigger_ho();
13047 +int __init mipv6_mn_init(void)
13049 + struct net_device *dev;
13053 + if (mipv6_add_tnl_to_ha())
13056 + mipv6_bul_init(MIPV6_BUL_SIZE);
13057 + mip6_fn.mn_use_hao = mn_use_hao;
13058 + mip6_fn.mn_check_tunneled_packet = mn_check_tunneled_packet;
13059 + INIT_TQUEUE(&mv_home_addr_task, mv_home_addr, NULL);
13062 + for (dev = dev_base; dev; dev = dev->next) {
13063 + if (dev->flags & IFF_UP &&
13064 + dev->type != ARPHRD_LOOPBACK && !dev_is_mip6_tnl(dev)) {
13065 + ma_ctl_add_iface(dev->ifindex);
13068 + DEBUG(DBG_INFO, "Multiaccess support initialized");
13070 + register_netdevice_notifier(&mipv6_mn_dev_notifier);
13071 + register_inet6addr_notifier(&mipv6_mn_inet6addr_notifier);
13073 + ip6ip6_tnl_register_hook(&mipv6_mn_tnl_rcv_send_bu_ops);
13074 + ip6ip6_tnl_register_hook(&mipv6_mn_tnl_xmit_stats_ops);
13075 + ip6ip6_tnl_register_hook(&mipv6_mn_tnl_rcv_stats_ops);
13077 + MIPV6_SETCALL(mipv6_set_home, mipv6_mn_set_home);
13079 + mipv6_initialize_mdetect();
13081 + /* COA to home transformation hook */
13082 + MIPV6_SETCALL(mipv6_get_home_address, mipv6_get_saddr_hook);
13083 + MIPV6_SETCALL(mipv6_mn_ha_probe, mipv6_mn_ha_probe);
13084 + MIPV6_SETCALL(mipv6_is_home_addr, mipv6_mn_is_home_addr);
13085 + proc_net_create("mip6_mninfo", 0, mn_proc_info);
13086 + /* Set packet modification hook (source addresses) */
13087 + nf_register_hook(&addr_modify_hook_ops);
13092 +void __exit mipv6_mn_exit(void)
13094 + struct list_head *lh, *tmp;
13095 + struct mn_info *minfo;
13098 + mip6_fn.mn_use_hao = NULL;
13099 + mip6_fn.mn_check_tunneled_packet = NULL;
13101 + MIPV6_RESETCALL(mipv6_set_home);
13102 + MIPV6_RESETCALL(mipv6_get_home_address);
13103 + MIPV6_RESETCALL(mipv6_mn_ha_probe);
13104 + MIPV6_RESETCALL(mipv6_is_home_addr);
13105 + nf_unregister_hook(&addr_modify_hook_ops);
13106 + proc_net_remove("mip6_mninfo");
13107 + mipv6_shutdown_mdetect();
13108 + ip6ip6_tnl_unregister_hook(&mipv6_mn_tnl_rcv_stats_ops);
13109 + ip6ip6_tnl_unregister_hook(&mipv6_mn_tnl_xmit_stats_ops);
13110 + ip6ip6_tnl_unregister_hook(&mipv6_mn_tnl_rcv_send_bu_ops);
13113 + unregister_inet6addr_notifier(&mipv6_mn_inet6addr_notifier);
13114 + unregister_netdevice_notifier(&mipv6_mn_dev_notifier);
13115 + write_lock_bh(&mn_info_lock);
13117 + list_for_each_safe(lh, tmp, &mn_info_list) {
13118 + minfo = list_entry(lh, struct mn_info, list);
13119 + if (minfo->is_at_home == MN_NOT_AT_HOME)
13120 + deprecate_addr(minfo);
13121 + list_del(&minfo->list);
13124 + write_unlock_bh(&mn_info_lock);
13125 + mipv6_bul_exit();
13126 + flush_scheduled_tasks();
13127 + mipv6_del_tnl_to_ha();
13129 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/mn.h linux-2.4.25/net/ipv6/mobile_ip6/mn.h
13130 --- linux-2.4.25.old/net/ipv6/mobile_ip6/mn.h 1970-01-01 01:00:00.000000000 +0100
13131 +++ linux-2.4.25/net/ipv6/mobile_ip6/mn.h 2004-06-26 11:29:31.000000000 +0100
13134 + * MIPL Mobile IPv6 Mobile Node header file
13138 + * This program is free software; you can redistribute it and/or
13139 + * modify it under the terms of the GNU General Public License
13140 + * as published by the Free Software Foundation; either version
13141 + * 2 of the License, or (at your option) any later version.
13147 +#include <linux/in6.h>
13149 +/* constants for sending of BUs*/
13150 +#define HA_BU_DEF_LIFETIME 10000
13151 +#define CN_BU_DEF_LIFETIME 420 /* Max lifetime for RR bindings from RFC 3775 */
13152 +#define DUMB_CN_BU_LIFETIME 600 /* BUL entry lifetime in case of dumb CN */
13153 +#define ROUTER_BU_DEF_LIFETIME 30 /* For packet forwarding from previous coa */
13154 +#define ERROR_DEF_LIFETIME DUMB_CN_BU_LIFETIME
13156 +extern rwlock_t mn_info_lock;
13158 +#define MN_NOT_AT_HOME 0
13159 +#define MN_RETURNING_HOME 1
13160 +#define MN_AT_HOME 2
13163 + * Mobile Node information record
13166 + struct in6_addr home_addr;
13167 + struct in6_addr ha;
13170 + __u8 has_home_reg;
13173 + int ifindex_user;
13174 + unsigned long home_addr_expires;
13175 + unsigned short dhaad_id;
13176 + struct list_head list;
13180 +/* prototypes for interface functions */
13181 +int mipv6_mn_init(void);
13182 +void mipv6_mn_exit(void);
13186 +/* Interface to movement detection */
13187 +int mipv6_mobile_node_moved(struct handoff *ho);
13189 +void mipv6_mn_send_home_na(struct in6_addr *haddr);
13190 +/* Init home reg. with coa */
13191 +int init_home_registration(struct in6_addr *home_addr, struct in6_addr *coa);
13193 +/* mn_info functions that require locking by caller */
13194 +struct mn_info *mipv6_mninfo_get_by_home(struct in6_addr *haddr);
13196 +struct mn_info *mipv6_mninfo_get_by_ha(struct in6_addr *home_agent);
13198 +struct mn_info *mipv6_mninfo_get_by_id(unsigned short id);
13200 +/* "safe" mn_info functions */
13201 +void mipv6_mninfo_add(int ifindex, struct in6_addr *home_addr, int plen,
13202 + int isathome, unsigned long lifetime, struct in6_addr *ha,
13203 + int ha_plen, unsigned long ha_lifetime, int man_conf);
13205 +int mipv6_mninfo_del(struct in6_addr *home_addr, int del_dyn_only);
13207 +void mipv6_mn_set_home_reg(struct in6_addr *home_addr, int has_home_reg);
13209 +int mipv6_mn_is_at_home(struct in6_addr *addr);
13211 +int mipv6_mn_is_home_addr(struct in6_addr *addr);
13213 +__u32 mipv6_mn_get_bulifetime(struct in6_addr *home_addr,
13214 + struct in6_addr *coa, __u8 flags);
13215 +int mn_cn_handoff(void *rawentry, void *args, unsigned long *sortkey);
13217 +int mipv6_mn_ha_nd_update(struct net_device *dev,
13218 + struct in6_addr *ha, u8 *lladdr);
13220 +struct bul_inval_args {
13221 + int all_rr_states;
13222 + struct in6_addr *cn;
13223 + struct in6_addr *mn;
13226 +int mn_bul_invalidate(void *rawentry, void *args, unsigned long *sortkey);
13228 +#endif /* _MN_H */
13229 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/mobhdr.h linux-2.4.25/net/ipv6/mobile_ip6/mobhdr.h
13230 --- linux-2.4.25.old/net/ipv6/mobile_ip6/mobhdr.h 1970-01-01 01:00:00.000000000 +0100
13231 +++ linux-2.4.25/net/ipv6/mobile_ip6/mobhdr.h 2004-06-26 11:29:31.000000000 +0100
13234 + * MIPL Mobile IPv6 Mobility Header send and receive
13238 + * This program is free software; you can redistribute it and/or
13239 + * modify it under the terms of the GNU General Public License
13240 + * as published by the Free Software Foundation; either version
13241 + * 2 of the License, or (at your option) any later version.
13247 +#include <net/mipv6.h>
13249 +/* RR states for mipv6_send_bu() */
13250 +#define RR_INIT 0x00
13251 +#define RR_WAITH 0x01
13252 +#define RR_WAITC 0x02
13253 +#define RR_WAITHC 0x13
13254 +#define RR_DONE 0x10
13256 +#define MH_UNKNOWN_CN 1
13257 +#define MH_AUTH_FAILED 2
13258 +#define MH_SEQUENCE_MISMATCH 3
13260 +struct mipv6_bul_entry;
13263 +int mipv6_mh_common_init(void);
13264 +void mipv6_mh_common_exit(void);
13265 +int mipv6_mh_mn_init(void);
13266 +void mipv6_mh_mn_exit(void);
13268 +struct mipv6_mh_opt {
13269 + struct mipv6_mo_alt_coa *alt_coa;
13270 + struct mipv6_mo_nonce_indices *nonce_indices;
13271 + struct mipv6_mo_bauth_data *auth_data;
13272 + struct mipv6_mo_br_advice *br_advice;
13280 + struct mipv6_mo_alt_coa *alt_coa;
13281 + struct mipv6_mo_nonce_indices *nonce_indices;
13282 + struct mipv6_mo_bauth_data *auth_data;
13283 + struct mipv6_mo_br_advice *br_advice;
13286 +struct mipv6_mh_opt *alloc_mh_opts(int totlen);
13287 +int append_mh_opt(struct mipv6_mh_opt *ops, u8 type, u8 len, void *data);
13288 +int parse_mo_tlv(void *mos, int len, struct mobopt *opts);
13289 +int mipv6_add_pad(u8 *data, int n);
13291 +struct mipv6_auth_parm {
13292 + struct in6_addr *coa;
13293 + struct in6_addr *cn_addr;
13297 +int send_mh(struct in6_addr *daddr, struct in6_addr *saddr,
13298 + u8 msg_type, u8 msg_len, u8 *msg,
13299 + struct in6_addr *hao_addr, struct in6_addr *rth_addr,
13300 + struct mipv6_mh_opt *ops, struct mipv6_auth_parm *parm);
13302 +int mipv6_mh_register(int type, int (*func)(struct sk_buff *,
13303 + struct in6_addr *, struct in6_addr *,
13304 + struct in6_addr *, struct in6_addr *, struct mipv6_mh *));
13306 +void mipv6_mh_unregister(int type);
13308 +int mipv6_send_brr(struct in6_addr *saddr, struct in6_addr *daddr,
13309 + struct mipv6_mh_opt *ops);
13311 +int mipv6_send_bu(struct in6_addr *saddr, struct in6_addr *daddr,
13312 + struct in6_addr *coa, __u32 initdelay,
13313 + __u32 maxackdelay, __u8 exp, __u8 flags,
13314 + __u32 lifetime, struct mipv6_mh_opt *ops);
13316 +int mipv6_send_be(struct in6_addr *saddr, struct in6_addr *daddr,
13317 + struct in6_addr *home, __u8 status);
13319 +int mipv6_send_ba(struct in6_addr *saddr, struct in6_addr *daddr,
13320 + struct in6_addr *auth_coa, struct in6_addr *rep_coa,
13321 + u8 status, u16 sequence, u32 lifetime, u8 *k_bu);
13323 +/* Binding Authentication Data Option routines */
13324 +#define MAX_HASH_LENGTH 20
13325 +#define MIPV6_RR_MAC_LENGTH 12
13327 +int mipv6_auth_build(struct in6_addr *cn_addr, struct in6_addr *coa,
13328 + __u8 *opt, __u8 *aud_data, __u8 *k_bu);
13330 +int mipv6_auth_check(struct in6_addr *cn_addr, struct in6_addr *coa,
13331 + __u8 *opt, __u8 optlen, struct mipv6_mo_bauth_data *aud,
13333 +#endif /* _MOBHDR_H */
13334 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/mobhdr_common.c linux-2.4.25/net/ipv6/mobile_ip6/mobhdr_common.c
13335 --- linux-2.4.25.old/net/ipv6/mobile_ip6/mobhdr_common.c 1970-01-01 01:00:00.000000000 +0100
13336 +++ linux-2.4.25/net/ipv6/mobile_ip6/mobhdr_common.c 2004-06-26 11:29:31.000000000 +0100
13339 + * Mobile IPv6 Mobility Header Common Functions
13342 + * Antti Tuominen <ajtuomin@tml.hut.fi>
13344 + * $Id: s.mh_recv.c 1.159 02/10/16 15:01:29+03:00 antti@traci.mipl.mediapoli.com $
13346 + * This program is free software; you can redistribute it and/or
13347 + * modify it under the terms of the GNU General Public License
13348 + * as published by the Free Software Foundation; either version
13349 + * 2 of the License, or (at your option) any later version.
13353 +#include <linux/autoconf.h>
13354 +#include <linux/types.h>
13355 +#include <linux/in6.h>
13356 +#include <linux/skbuff.h>
13357 +#include <linux/ipsec.h>
13358 +#include <linux/init.h>
13359 +#include <net/ipv6.h>
13360 +#include <net/ip6_route.h>
13361 +#include <net/addrconf.h>
13362 +#include <net/mipv6.h>
13363 +#include <net/checksum.h>
13364 +#include <net/protocol.h>
13366 +#include "stats.h"
13367 +#include "debug.h"
13368 +#include "mobhdr.h"
13369 +#include "bcache.h"
13371 +#include "rr_crypto.h"
13372 +#include "exthdrs.h"
13373 +#include "config.h"
13375 +#define MIPV6_MH_MAX MIPV6_MH_BE
13377 + int (*func) (struct sk_buff *,
13378 + struct in6_addr *, struct in6_addr *,
13379 + struct in6_addr *, struct in6_addr *,
13380 + struct mipv6_mh *);
13383 +static struct mh_proto mh_rcv[MIPV6_MH_MAX];
13385 +int mipv6_mh_register(int type, int (*func)(struct sk_buff *,
13386 + struct in6_addr *, struct in6_addr *,
13387 + struct in6_addr *, struct in6_addr *, struct mipv6_mh *))
13389 + if (mh_rcv[type].func != NULL)
13392 + mh_rcv[type].func = func;
13397 +void mipv6_mh_unregister(int type)
13399 + if (type < 0 || type > MIPV6_MH_MAX)
13402 + mh_rcv[type].func = NULL;
13405 +struct socket *mipv6_mh_socket = NULL;
13407 +/* TODO: Fix fragmentation */
13408 +static int dstopts_getfrag(
13409 + const void *data, struct in6_addr *addr,
13410 + char *buff, unsigned int offset, unsigned int len)
13412 + memcpy(buff, data + offset, len);
13416 +struct mipv6_mh_opt *alloc_mh_opts(int totlen)
13418 + struct mipv6_mh_opt *ops;
13420 + ops = kmalloc(sizeof(*ops) + totlen, GFP_ATOMIC);
13424 + memset(ops, 0, sizeof(*ops));
13425 + ops->next_free = ops->data;
13426 + ops->freelen = totlen;
13431 +int append_mh_opt(struct mipv6_mh_opt *ops, u8 type, u8 len, void *data)
13433 + struct mipv6_mo *mo;
13435 + if (ops->next_free == NULL) {
13436 + DEBUG(DBG_ERROR, "No free room for option");
13439 + if (ops->freelen < len + 2) {
13440 + DEBUG(DBG_ERROR, "No free room for option");
13444 + ops->freelen -= (len + 2);
13445 + ops->totlen += (len + 2);
13448 + mo = (struct mipv6_mo *)ops->next_free;
13450 + mo->length = len;
13453 + case MIPV6_OPT_ALTERNATE_COA:
13454 + ops->alt_coa = (struct mipv6_mo_alt_coa *)mo;
13455 + ipv6_addr_copy(&ops->alt_coa->addr, (struct in6_addr *)data);
13457 + case MIPV6_OPT_NONCE_INDICES:
13458 + DEBUG(DBG_INFO, "Added nonce indices pointer");
13459 + ops->nonce_indices = (struct mipv6_mo_nonce_indices *)mo;
13460 + ops->nonce_indices->home_nonce_i = *(__u16 *)data;
13461 + ops->nonce_indices->careof_nonce_i = *((__u16 *)data + 1);
13463 + case MIPV6_OPT_AUTH_DATA:
13464 + DEBUG(DBG_INFO, "Added opt auth_data pointer");
13465 + ops->auth_data = (struct mipv6_mo_bauth_data *)mo;
13467 + case MIPV6_OPT_BIND_REFRESH_ADVICE:
13468 + ops->br_advice = (struct mipv6_mo_br_advice *)mo;
13469 + ops->br_advice->refresh_interval = htons(*(u16 *)data);
13472 + DEBUG(DBG_ERROR, "Unknow option type");
13476 + if (ops->freelen == 0)
13477 + ops->next_free = NULL;
13479 + ops->next_free += (len + 2);
13485 + * Calculates required padding with xn + y requirement with offset
13487 +static inline int optpad(int xn, int y, int offset)
13489 + return ((y - offset) & (xn - 1));
13492 +static int option_pad(int type, int offset)
13494 + if (type == MIPV6_OPT_ALTERNATE_COA)
13495 + return optpad(8, 6, offset); /* 8n + 6 */
13496 + if (type == MIPV6_OPT_BIND_REFRESH_ADVICE ||
13497 + type == MIPV6_OPT_NONCE_INDICES)
13498 + return optpad(2, 0, offset); /* 2n */
13503 + * Add Pad1 or PadN option to data
13505 +int mipv6_add_pad(u8 *data, int n)
13507 + struct mipv6_mo_padn *padn;
13509 + if (n <= 0) return 0;
13511 + *data = MIPV6_OPT_PAD1;
13514 + padn = (struct mipv6_mo_padn *)data;
13515 + padn->type = MIPV6_OPT_PADN;
13516 + padn->length = n - 2;
13517 + memset(padn->data, 0, n - 2);
13522 + * Write options to mobility header buffer
13524 +static int prepare_mh_opts(u8 *optdata, int off, struct mipv6_mh_opt *ops)
13526 + u8 *nextopt = optdata;
13527 + int offset = off, pad = 0;
13529 + if (ops == NULL) {
13534 + if (ops->alt_coa) {
13535 + pad = option_pad(MIPV6_OPT_ALTERNATE_COA, offset);
13536 + nextopt += mipv6_add_pad(nextopt, pad);
13537 + memcpy(nextopt, ops->alt_coa, sizeof(struct mipv6_mo_alt_coa));
13538 + nextopt += sizeof(struct mipv6_mo_alt_coa);
13539 + offset += pad + sizeof(struct mipv6_mo_alt_coa);
13542 + if (ops->br_advice) {
13543 + pad = option_pad(MIPV6_OPT_BIND_REFRESH_ADVICE, offset);
13544 + nextopt += mipv6_add_pad(nextopt, pad);
13545 + memcpy(nextopt, ops->br_advice, sizeof(struct mipv6_mo_br_advice));
13546 + nextopt += sizeof(struct mipv6_mo_br_advice);
13547 + offset += pad + sizeof(struct mipv6_mo_br_advice);
13550 + if (ops->nonce_indices) {
13551 + pad = option_pad(MIPV6_OPT_NONCE_INDICES, offset);
13552 + nextopt += mipv6_add_pad(nextopt, pad);
13553 + memcpy(nextopt, ops->nonce_indices, sizeof(struct mipv6_mo_nonce_indices));
13554 + nextopt += sizeof(struct mipv6_mo_nonce_indices);
13555 + offset += pad + sizeof(struct mipv6_mo_nonce_indices);
13558 + if (ops->auth_data) {
13559 + /* This option should always be the last. Header
13560 + * length must be a multiple of 8 octects, so we pad
13561 + * if necessary. */
13562 + pad = optpad(8, 0, offset + ops->auth_data->length + 2);
13563 + nextopt += mipv6_add_pad(nextopt, pad);
13564 + memcpy(nextopt, ops->auth_data, ops->auth_data->length + 2);
13565 + nextopt += ops->auth_data->length + 2;
13572 +static int calculate_mh_opts(struct mipv6_mh_opt *ops, int mh_len)
13574 + int offset = mh_len;
13579 + if (ops->alt_coa)
13580 + offset += sizeof(struct mipv6_mo_alt_coa)
13581 + + option_pad(MIPV6_OPT_ALTERNATE_COA, offset);
13583 + if (ops->br_advice)
13584 + offset += sizeof(struct mipv6_mo_br_advice)
13585 + + option_pad(MIPV6_OPT_BIND_REFRESH_ADVICE, offset);
13587 + if (ops->nonce_indices)
13588 + offset += sizeof(struct mipv6_mo_nonce_indices)
13589 + + option_pad(MIPV6_OPT_NONCE_INDICES, offset);
13591 + if (ops->auth_data) /* no alignment */
13592 + offset += ops->auth_data->length + 2;
13594 + return offset - mh_len;
13599 + * Mobility Header Message send functions
13604 + * send_mh - builds and sends a MH msg
13606 + * @daddr: destination address for packet
13607 + * @saddr: source address for packet
13608 + * @msg_type: type of MH
13609 + * @msg_len: message length
13610 + * @msg: MH type specific data
13611 + * @hao_addr: home address for home address option
13612 + * @rth_addr: routing header address
13613 + * @ops: mobility options
13614 + * @parm: auth data
13616 + * Builds MH, appends the type specific msg data to the header and
13617 + * sends the packet with a home address option, if a home address was
13618 + * given. Returns 0, if everything succeeded and a negative error code
13621 +int send_mh(struct in6_addr *daddr,
13622 + struct in6_addr *saddr,
13623 + u8 msg_type, u8 msg_len, u8 *msg,
13624 + struct in6_addr *hao_addr,
13625 + struct in6_addr *rth_addr,
13626 + struct mipv6_mh_opt *ops,
13627 + struct mipv6_auth_parm *parm)
13630 + struct mipv6_mh *mh;
13631 + struct sock *sk = mipv6_mh_socket->sk;
13632 + struct ipv6_txoptions *txopt = NULL;
13633 + int tot_len = sizeof(struct mipv6_mh) + msg_len;
13634 + int padded_len = 0, txopt_len = 0;
13637 + /* Add length of options */
13638 + tot_len += calculate_mh_opts(ops, tot_len);
13639 + /* Needs to be a multiple of 8 octets */
13640 + padded_len = tot_len + optpad(8, 0, tot_len);
13642 + mh = sock_kmalloc(sk, padded_len, GFP_ATOMIC);
13644 + DEBUG(DBG_ERROR, "memory allocation failed");
13648 + memset(&fl, 0, sizeof(fl));
13649 + fl.proto = IPPROTO_MOBILITY;
13650 + fl.fl6_dst = daddr;
13651 + fl.fl6_src = saddr;
13652 + fl.fl6_flowlabel = 0;
13653 + fl.oif = sk->bound_dev_if;
13655 + if (hao_addr || rth_addr) {
13659 + txopt_len += sizeof(struct mipv6_dstopt_homeaddr) + 6;
13661 + txopt_len += sizeof(struct rt2_hdr);
13663 + txopt_len += sizeof(*txopt);
13664 + txopt = sock_kmalloc(sk, txopt_len, GFP_ATOMIC);
13665 + if (txopt == NULL) {
13666 + DEBUG(DBG_ERROR, "No socket space left");
13667 + sock_kfree_s(sk, mh, padded_len);
13670 + memset(txopt, 0, txopt_len);
13671 + txopt->tot_len = txopt_len;
13672 + opt_ptr = (__u8 *) (txopt + 1);
13674 + int holen = sizeof(struct mipv6_dstopt_homeaddr) + 6;
13675 + txopt->dst1opt = (struct ipv6_opt_hdr *) opt_ptr;
13676 + txopt->opt_flen += holen;
13677 + opt_ptr += holen;
13678 + mipv6_append_dst1opts(txopt->dst1opt, saddr,
13680 + txopt->mipv6_flags = MIPV6_SND_HAO | MIPV6_SND_BU;
13683 + int rtlen = sizeof(struct rt2_hdr);
13684 + txopt->srcrt2 = (struct ipv6_rt_hdr *) opt_ptr;
13685 + txopt->opt_nflen += rtlen;
13686 + opt_ptr += rtlen;
13687 + mipv6_append_rt2hdr(txopt->srcrt2, rth_addr);
13691 + /* Fill in the fields of MH */
13692 + mh->payload = NEXTHDR_NONE;
13693 + mh->length = (padded_len >> 3) - 1; /* Units of 8 octets - 1 */
13694 + mh->type = msg_type;
13695 + mh->reserved = 0;
13696 + mh->checksum = 0;
13698 + memcpy(mh->data, msg, msg_len);
13699 + prepare_mh_opts(mh->data + msg_len, msg_len + sizeof(*mh), ops);
13700 + /* If BAD is present, this is already done. */
13701 + mipv6_add_pad((u8 *)mh + tot_len, padded_len - tot_len);
13703 + if (parm && parm->k_bu && ops && ops->auth_data) {
13704 + /* Calculate the position of the authorization data before adding checksum*/
13705 + mipv6_auth_build(parm->cn_addr, parm->coa, (__u8 *)mh,
13706 + (__u8 *)mh + padded_len - MIPV6_RR_MAC_LENGTH, parm->k_bu);
13708 + /* Calculate the MH checksum */
13709 + mh->checksum = csum_ipv6_magic(fl.fl6_src, fl.fl6_dst,
13710 + padded_len, IPPROTO_MOBILITY,
13711 + csum_partial((char *)mh, padded_len, 0));
13712 + ip6_build_xmit(sk, dstopts_getfrag, mh, &fl, padded_len, txopt, 255,
13714 + /* dst cache must be cleared so RR messages can be routed through
13715 + different interfaces */
13716 + sk_dst_reset(sk);
13719 + sock_kfree_s(sk, txopt, txopt_len);
13720 + sock_kfree_s(sk, mh, padded_len);
13725 + * mipv6_send_brr - send a Binding Refresh Request
13726 + * @saddr: source address for BRR
13727 + * @daddr: destination address for BRR
13728 + * @ops: mobility options
13730 + * Sends a binding request. On a mobile node, use the mobile node's
13731 + * home address for @saddr. Returns 0 on success, negative on
13734 +int mipv6_send_brr(struct in6_addr *saddr, struct in6_addr *daddr,
13735 + struct mipv6_mh_opt *ops)
13737 + struct mipv6_mh_brr br;
13739 + memset(&br, 0, sizeof(br));
13740 + /* We don't need to explicitly add a RH to brr, since it will be
13741 + * included automatically, if a BCE exists
13743 + MIPV6_INC_STATS(n_brr_sent);
13744 + return send_mh(daddr, saddr, MIPV6_MH_BRR, sizeof(br), (u8 *)&br,
13745 + NULL, NULL, ops, NULL);
13749 + * mipv6_send_ba - send a Binding Acknowledgement
13750 + * @saddr: source address for BA
13751 + * @daddr: destination address for BA
13752 + * @reply_coa: destination care-of address of MN
13753 + * @auth_coa: care-of address of MN used for authentication
13754 + * @status: status field value
13755 + * @sequence: sequence number from BU
13756 + * @lifetime: granted lifetime for binding in seconds
13757 + * @ops: mobility options
13759 + * Send a binding acknowledgement. On a mobile node, use the mobile
13760 + * node's home address for saddr. Returns 0 on success, non-zero on
13763 +int mipv6_send_ba(struct in6_addr *saddr, struct in6_addr *daddr,
13764 + struct in6_addr *auth_coa, struct in6_addr *rep_coa,
13765 + u8 status, u16 sequence, u32 lifetime, u8 *k_bu)
13767 + struct mipv6_mh_ba ba;
13768 + struct mipv6_auth_parm parm;
13769 + struct mipv6_mh_opt *ops = NULL;
13770 + int ops_len = 0, ret = 0;
13771 + struct mipv6_bce bc_entry;
13772 + int coming_home = 0;
13773 + int bypass_tnl = 0;
13775 + memset(&ba, 0, sizeof(ba));
13777 + ba.status = status;
13778 + ba.sequence = htons(sequence);
13779 + ba.lifetime = htons(lifetime >> 2);
13781 + DEBUG(DBG_INFO, "sending a status %d BA %s authenticator to MN \n"
13782 + "%x:%x:%x:%x:%x:%x:%x:%x at care of address \n"
13783 + "%x:%x:%x:%x:%x:%x:%x:%x : with lifetime %d and \n"
13784 + " sequence number %d",
13785 + status, k_bu ? "with" : "without",
13786 + NIPV6ADDR(daddr), NIPV6ADDR(auth_coa), lifetime, sequence);
13788 + memset(&parm, 0, sizeof(parm));
13789 + parm.coa = auth_coa;
13790 + parm.cn_addr = saddr;
13793 + ops_len += sizeof(struct mipv6_mo_bauth_data) +
13794 + MIPV6_RR_MAC_LENGTH;
13795 + parm.k_bu = k_bu;
13798 + if (mip6node_cnf.binding_refresh_advice) {
13799 + ops_len += sizeof(struct mipv6_mo_br_advice);
13802 + ops = alloc_mh_opts(ops_len);
13803 + if (ops == NULL) {
13804 + DEBUG(DBG_WARNING, "Out of memory");
13807 + if (mip6node_cnf.binding_refresh_advice > 0) {
13808 + if (append_mh_opt(ops, MIPV6_OPT_BIND_REFRESH_ADVICE, 2,
13809 + &mip6node_cnf.binding_refresh_advice) < 0) {
13810 + DEBUG(DBG_WARNING, "Adding BRA failed");
13817 + if (append_mh_opt(ops, MIPV6_OPT_AUTH_DATA,
13818 + MIPV6_RR_MAC_LENGTH, NULL) < 0) {
13819 + DEBUG(DBG_WARNING, "Adding BAD failed");
13826 + coming_home = !ipv6_addr_cmp(rep_coa, daddr);
13828 + bypass_tnl = (coming_home &&
13829 + !mipv6_bcache_get(daddr, saddr, &bc_entry) &&
13830 + bc_entry.flags&MIPV6_BU_F_HOME &&
13833 + if (bypass_tnl && mip6_fn.bce_tnl_rt_del)
13834 + mip6_fn.bce_tnl_rt_del(&bc_entry.coa,
13835 + &bc_entry.our_addr,
13836 + &bc_entry.home_addr);
13839 + ret = send_mh(daddr, saddr, MIPV6_MH_BA, sizeof(ba), (u8 *)&ba,
13840 + NULL, NULL, ops, &parm);
13842 + ret = send_mh(daddr, saddr, MIPV6_MH_BA, sizeof(ba), (u8 *)&ba,
13843 + NULL, rep_coa, ops, &parm);
13845 + if (bypass_tnl && mip6_fn.bce_tnl_rt_add)
13846 + mip6_fn.bce_tnl_rt_add(&bc_entry.coa,
13847 + &bc_entry.our_addr,
13848 + &bc_entry.home_addr);
13851 + if (status < 128) {
13852 + MIPV6_INC_STATS(n_ba_sent);
13854 + MIPV6_INC_STATS(n_ban_sent);
13865 + * mipv6_send_be - send a Binding Error message
13866 + * @saddr: source address for BE
13867 + * @daddr: destination address for BE
13868 + * @home: Home Address in offending packet (if any)
13870 + * Sends a binding error. On a mobile node, use the mobile node's
13871 + * home address for @saddr. Returns 0 on success, negative on
13874 +int mipv6_send_be(struct in6_addr *saddr, struct in6_addr *daddr,
13875 + struct in6_addr *home, __u8 status)
13877 + struct mipv6_mh_be be;
13879 + struct mipv6_bce bc_entry;
13880 + int bypass_tnl = 0;
13882 + if (ipv6_addr_is_multicast(daddr))
13885 + memset(&be, 0, sizeof(be));
13886 + be.status = status;
13888 + ipv6_addr_copy(&be.home_addr, home);
13890 + if (mipv6_bcache_get(daddr, saddr, &bc_entry) == 0 &&
13891 + bc_entry.flags&MIPV6_BU_F_HOME)
13894 + if (bypass_tnl && mip6_fn.bce_tnl_rt_del)
13895 + mip6_fn.bce_tnl_rt_del(&bc_entry.coa,
13896 + &bc_entry.our_addr,
13897 + &bc_entry.home_addr);
13899 + ret = send_mh(daddr, saddr, MIPV6_MH_BE, sizeof(be), (u8 *)&be,
13900 + NULL, NULL, NULL, NULL);
13902 + if (bypass_tnl && mip6_fn.bce_tnl_rt_add)
13903 + mip6_fn.bce_tnl_rt_add(&bc_entry.coa,
13904 + &bc_entry.our_addr,
13905 + &bc_entry.home_addr);
13908 + MIPV6_INC_STATS(n_be_sent);
13914 + * mipv6_send_addr_test - send a HoT or CoT message
13915 + * @saddr: source address
13916 + * @daddr: destination address
13917 + * @msg_type: HoT or CoT message
13918 + * @init: HoTI or CoTI message
13920 + * Send a reply to HoTI or CoTI message.
13922 +static int mipv6_send_addr_test(struct in6_addr *saddr,
13923 + struct in6_addr *daddr,
13925 + struct mipv6_mh_addr_ti *init)
13927 + u_int8_t *kgen_token = NULL;
13928 + struct mipv6_mh_addr_test addr_test;
13929 + struct mipv6_rr_nonce *nonce;
13930 + struct mipv6_mh_opt *ops = NULL;
13935 + if ((nonce = mipv6_rr_get_new_nonce())== NULL) {
13936 + DEBUG(DBG_WARNING, "Nonce creation failed");
13939 + if (mipv6_rr_cookie_create(daddr, &kgen_token, nonce->index)) {
13940 + DEBUG(DBG_WARNING, "No cookie");
13944 + addr_test.nonce_index = nonce->index;
13945 + memcpy(addr_test.init_cookie, init->init_cookie,
13946 + MIPV6_RR_COOKIE_LENGTH);
13947 + memcpy(addr_test.kgen_token, kgen_token,
13948 + MIPV6_RR_COOKIE_LENGTH);
13950 + /* No options defined */
13951 + ret = send_mh(daddr, saddr, msg_type, sizeof(addr_test),
13952 + (u8 *)&addr_test, NULL, NULL, ops, NULL);
13955 + if (msg_type == MIPV6_MH_HOT) {
13956 + MIPV6_INC_STATS(n_hot_sent);
13958 + MIPV6_INC_STATS(n_cot_sent);
13965 +static void bc_cache_add(int ifindex, struct in6_addr *daddr,
13966 + struct in6_addr *haddr, struct in6_addr *coa,
13967 + struct in6_addr *rep_coa, __u32 lifetime,
13968 + __u16 sequence, __u8 flags, __u8 *k_bu)
13970 + __u8 ba_status = SUCCESS;
13972 + if (lifetime > MAX_RR_BINDING_LIFE)
13973 + lifetime = MAX_RR_BINDING_LIFE;
13975 + if (mipv6_bcache_add(ifindex, daddr, haddr, coa, lifetime,
13976 + sequence, flags, CACHE_ENTRY) != 0) {
13977 + DEBUG(DBG_ERROR, "binding failed.");
13978 + ba_status = INSUFFICIENT_RESOURCES;
13981 + if (flags & MIPV6_BU_F_ACK) {
13982 + DEBUG(DBG_INFO, "sending ack (code=%d)", ba_status);
13983 + mipv6_send_ba(daddr, haddr, coa, rep_coa, ba_status, sequence,
13988 +static void bc_cn_home_add(int ifindex, struct in6_addr *daddr,
13989 + struct in6_addr *haddr, struct in6_addr *coa,
13990 + struct in6_addr *rep_coa, __u32 lifetime,
13991 + __u16 sequence, __u8 flags, __u8 *k_bu)
13993 + mipv6_send_ba(daddr, haddr, coa, rep_coa,
13994 + HOME_REGISTRATION_NOT_SUPPORTED,
13995 + sequence, lifetime, k_bu);
13998 +static void bc_cache_delete(struct in6_addr *daddr, struct in6_addr *haddr,
13999 + struct in6_addr *coa, struct in6_addr *rep_coa,
14000 + __u16 sequence, __u8 flags,
14003 + __u8 status = SUCCESS;
14005 + /* Cached Care-of Address Deregistration */
14006 + if (mipv6_bcache_exists(haddr, daddr) == CACHE_ENTRY) {
14007 + mipv6_bcache_delete(haddr, daddr, CACHE_ENTRY);
14009 + DEBUG(DBG_INFO, "entry is not in cache");
14010 + status = REASON_UNSPECIFIED;
14012 + if (flags & MIPV6_BU_F_ACK) {
14013 + mipv6_send_ba(daddr, haddr, coa, rep_coa, status, sequence,
14018 +static void bc_cn_home_delete(struct in6_addr *daddr, struct in6_addr *haddr,
14019 + struct in6_addr *coa, struct in6_addr *rep_coa,
14020 + __u16 sequence, __u8 flags,
14026 + * parse_mo_tlv - Parse TLV-encoded Mobility Options
14027 + * @mos: pointer to Mobility Options
14028 + * @len: total length of options
14029 + * @opts: structure to store option pointers
14031 + * Parses Mobility Options passed in @mos. Stores pointers in @opts
14032 + * to all valid mobility options found in @mos. Unknown options and
14033 + * padding (%MIPV6_OPT_PAD1 and %MIPV6_OPT_PADN) is ignored and
14036 +int parse_mo_tlv(void *mos, int len, struct mobopt *opts)
14038 + struct mipv6_mo *curr = (struct mipv6_mo *)mos;
14041 + while (left > 0) {
14043 + if (curr->type == MIPV6_OPT_PAD1)
14046 + optlen = 2 + curr->length;
14048 + if (optlen > left)
14051 + switch (curr->type) {
14052 + case MIPV6_OPT_PAD1:
14053 + DEBUG(DBG_DATADUMP, "MIPV6_OPT_PAD1 at %x", curr);
14055 + case MIPV6_OPT_PADN:
14056 + DEBUG(DBG_DATADUMP, "MIPV6_OPT_PADN at %x", curr);
14058 + case MIPV6_OPT_ALTERNATE_COA:
14059 + DEBUG(DBG_DATADUMP, "MIPV6_OPT_ACOA at %x", curr);
14060 + opts->alt_coa = (struct mipv6_mo_alt_coa *)curr;
14062 + case MIPV6_OPT_NONCE_INDICES:
14063 + DEBUG(DBG_DATADUMP, "MIPV6_OPT_NONCE_INDICES at %x", curr);
14064 + opts->nonce_indices =
14065 + (struct mipv6_mo_nonce_indices *)curr;
14067 + case MIPV6_OPT_AUTH_DATA:
14068 + DEBUG(DBG_DATADUMP, "MIPV6_OPT_AUTH_DATA at %x", curr);
14069 + opts->auth_data = (struct mipv6_mo_bauth_data *)curr;
14071 + case MIPV6_OPT_BIND_REFRESH_ADVICE:
14072 + DEBUG(DBG_DATADUMP, "MIPV6_OPT_BIND_REFRESH_ADVICE at %x", curr);
14073 + opts->br_advice = (struct mipv6_mo_br_advice *)curr;
14076 + DEBUG(DBG_INFO, "MO Unknown option type %d at %x, ignoring.",
14077 + curr->type, curr);
14078 + /* unknown mobility option, ignore and skip */
14081 + (u8 *)curr += optlen;
14093 + * Mobility Header Message handlers
14097 +static int mipv6_handle_mh_testinit(struct sk_buff *skb,
14098 + struct in6_addr *cn,
14099 + struct in6_addr *lcoa,
14100 + struct in6_addr *saddr,
14101 + struct in6_addr *fcoa,
14102 + struct mipv6_mh *mh)
14104 + struct mipv6_mh_addr_ti *ti = (struct mipv6_mh_addr_ti *)mh->data;
14105 + int msg_len = (mh->length+1) << 3;
14109 + if (msg_len > skb->len)
14112 + opt_len = msg_len - sizeof(*mh) - sizeof(*ti);
14114 + if (opt_len < 0) {
14115 + __u32 pos = (__u32)&mh->length - (__u32)skb->nh.raw;
14116 + icmpv6_send(skb, ICMPV6_PARAMPROB,
14117 + ICMPV6_HDR_FIELD, pos, skb->dev);
14119 + DEBUG(DBG_INFO, "Mobility Header length less than H/C TestInit");
14122 + if (!mip6node_cnf.accept_ret_rout) {
14123 + DEBUG(DBG_INFO, "Return routability administratively disabled");
14126 + if (lcoa || fcoa) {
14127 + DEBUG(DBG_INFO, "H/C TestInit has HAO or RTH2, dropped.");
14131 + if (mh->type == MIPV6_MH_HOTI) {
14132 + MIPV6_INC_STATS(n_hoti_rcvd);
14133 + return mipv6_send_addr_test(cn, saddr, MIPV6_MH_HOT, ti);
14134 + } else if (mh->type == MIPV6_MH_COTI) {
14135 + MIPV6_INC_STATS(n_coti_rcvd);
14136 + return mipv6_send_addr_test(cn, saddr, MIPV6_MH_COT, ti);
14138 + return -1; /* Impossible to get here */
14142 + * mipv6_handle_mh_bu - Binding Update handler
14143 + * @src: care-of address of sender
14144 + * @dst: our address
14145 + * @haddr: home address of sender
14146 + * @mh: pointer to the beginning of the Mobility Header
14148 + * Handles Binding Update. Packet and offset to option are passed.
14149 + * Returns 0 on success, otherwise negative.
14151 +static int mipv6_handle_mh_bu(struct sk_buff *skb,
14152 + struct in6_addr *dst,
14153 + struct in6_addr *unused,
14154 + struct in6_addr *haddr,
14155 + struct in6_addr *coaddr,
14156 + struct mipv6_mh *mh)
14158 + struct mipv6_mh_bu *bu = (struct mipv6_mh_bu *)mh->data;
14159 + int msg_len = (mh->length+1) << 3;
14162 + int dereg; /* Is this deregistration? */
14165 + struct mipv6_bce bc_entry;
14166 + struct in6_addr *coa, *reply_coa;
14167 + __u8 *key_bu = NULL; /* RR BU authentication key */
14168 + __u8 flags = bu->flags;
14171 + __u16 nonce_ind = (__u16) -1;
14173 + if (msg_len > skb->len)
14176 + opt_len = msg_len - sizeof(*mh) - sizeof(*bu);
14178 + if (opt_len < 0) {
14179 + __u32 pos = (__u32)&mh->length - (__u32)skb->nh.raw;
14180 + icmpv6_send(skb, ICMPV6_PARAMPROB,
14181 + ICMPV6_HDR_FIELD, pos, skb->dev);
14183 + DEBUG(DBG_INFO, "Mobility Header length less than BU");
14184 + MIPV6_INC_STATS(n_bu_drop.invalid);
14188 + addr_type = ipv6_addr_type(haddr);
14189 + if (addr_type&IPV6_ADDR_LINKLOCAL || !(addr_type&IPV6_ADDR_UNICAST))
14192 + /* If HAO not present, CoA == HAddr */
14193 + if (coaddr == NULL)
14197 + addr_type = ipv6_addr_type(coa);
14198 + if (addr_type&IPV6_ADDR_LINKLOCAL ||
14199 + !(addr_type&IPV6_ADDR_UNICAST))
14204 + sequence = ntohs(bu->sequence);
14205 + if (bu->lifetime == 0xffff)
14206 + lifetime = 0xffffffff;
14208 + lifetime = ntohs(bu->lifetime) << 2;
14210 + dereg = (ipv6_addr_cmp(haddr, coa) == 0 || lifetime == 0);
14212 + if (opt_len > 0) {
14213 + struct mobopt opts;
14214 + memset(&opts, 0, sizeof(opts));
14215 + if (parse_mo_tlv(bu + 1, opt_len, &opts) < 0) {
14216 + MIPV6_INC_STATS(n_bu_drop.invalid);
14220 + * MIPV6_OPT_AUTH_DATA, MIPV6_OPT_NONCE_INDICES,
14221 + * MIPV6_OPT_ALT_COA
14223 + if (opts.alt_coa) {
14224 + coa = &opts.alt_coa->addr;
14225 + dereg = (ipv6_addr_cmp(haddr, coa) == 0 || lifetime == 0);
14227 + addr_type = ipv6_addr_type(coa);
14228 + if (addr_type&IPV6_ADDR_LINKLOCAL ||
14229 + !(addr_type&IPV6_ADDR_UNICAST))
14232 + if (flags & MIPV6_BU_F_HOME) {
14233 + if (opts.nonce_indices)
14236 + u8 ba_status = 0;
14237 + u8 *h_ckie = NULL, *c_ckie = NULL; /* Home and care-of cookies */
14239 + /* BUs to CN MUST include authorization data and nonce indices options */
14240 + if (!opts.auth_data || !opts.nonce_indices) {
14241 + DEBUG(DBG_WARNING,
14242 + "Route optimization BU without authorization material, aborting processing");
14243 + return MH_AUTH_FAILED;
14245 + if (mipv6_rr_cookie_create(
14246 + haddr, &h_ckie, opts.nonce_indices->home_nonce_i) < 0) {
14247 + DEBUG(DBG_WARNING,
14248 + "mipv6_rr_cookie_create failed for home cookie");
14249 + ba_status = EXPIRED_HOME_NONCE_INDEX;
14251 + nonce_ind = opts.nonce_indices->home_nonce_i;
14252 + /* Don't create the care-of cookie, if MN deregisters */
14253 + if (!dereg && mipv6_rr_cookie_create(
14255 + opts.nonce_indices->careof_nonce_i) < 0) {
14256 + DEBUG(DBG_WARNING,
14257 + "mipv6_rr_cookie_create failed for coa cookie");
14258 + if (ba_status == 0)
14259 + ba_status = EXPIRED_CAREOF_NONCE_INDEX;
14261 + ba_status = EXPIRED_NONCES;
14263 + if (ba_status == 0) {
14265 + key_bu = mipv6_rr_key_calc(h_ckie, NULL);
14267 + key_bu = mipv6_rr_key_calc(h_ckie, c_ckie);
14268 + mh->checksum = 0;/* TODO: Don't mangle the packet */
14269 + if (key_bu && mipv6_auth_check(
14270 + dst, coa, (__u8 *)mh, msg_len + sizeof(*mh), opts.auth_data, key_bu) == 0) {
14271 + DEBUG(DBG_INFO, "mipv6_auth_check OK for BU");
14274 + DEBUG(DBG_WARNING,
14275 + "BU Authentication failed");
14282 + if (ba_status != 0) {
14283 + MIPV6_INC_STATS(n_bu_drop.auth);
14284 + mipv6_send_ba(dst, haddr, coa,
14285 + reply_coa, ba_status,
14286 + sequence, 0, NULL);
14292 + /* Require authorization option for RO, home reg is protected by IPsec */
14293 + if (!(flags & MIPV6_BU_F_HOME) && !auth) {
14294 + MIPV6_INC_STATS(n_bu_drop.auth);
14297 + return MH_AUTH_FAILED;
14300 + if (mipv6_bcache_get(haddr, dst, &bc_entry) == 0) {
14301 + if ((bc_entry.flags&MIPV6_BU_F_HOME) !=
14302 + (flags&MIPV6_BU_F_HOME)) {
14304 + "Registration type change. Sending BA REG_TYPE_CHANGE_FORBIDDEN");
14305 + mipv6_send_ba(dst, haddr, coa, reply_coa,
14306 + REG_TYPE_CHANGE_FORBIDDEN,
14307 + sequence, lifetime, key_bu);
14310 + if (!MIPV6_SEQ_GT(sequence, bc_entry.seq)) {
14312 + "Sequence number mismatch. Sending BA SEQUENCE_NUMBER_OUT_OF_WINDOW");
14313 + mipv6_send_ba(dst, haddr, coa, reply_coa,
14314 + SEQUENCE_NUMBER_OUT_OF_WINDOW,
14315 + bc_entry.seq, lifetime, key_bu);
14322 + struct rt6_info *rt;
14324 + /* Avoid looping binding cache entries */
14325 + if (mipv6_bcache_get(coa, dst, &bc_entry) == 0) {
14326 + DEBUG(DBG_WARNING, "Looped BU, dropping the packet");
14329 + DEBUG(DBG_INFO, "calling bu_add.");
14330 + if ((rt = rt6_lookup(haddr, dst, 0, 0)) != NULL) {
14331 + ifindex = rt->rt6i_dev->ifindex;
14332 + dst_release(&rt->u.dst);
14335 + * Can't process the BU since the right interface is
14338 + DEBUG(DBG_WARNING, "No route entry found for handling "
14339 + "a BU request, (using 0 as index)");
14342 + if (flags & MIPV6_BU_F_HOME)
14343 + mip6_fn.bce_home_add(ifindex, dst, haddr, coa,
14344 + reply_coa, lifetime, sequence,
14347 + mip6_fn.bce_cache_add(ifindex, dst, haddr, coa,
14348 + reply_coa, lifetime, sequence,
14351 + DEBUG(DBG_INFO, "calling BCE delete.");
14353 + if (flags & MIPV6_BU_F_HOME)
14354 + mip6_fn.bce_home_del(dst, haddr, coa, reply_coa,
14355 + sequence, flags, key_bu);
14357 + mipv6_rr_invalidate_nonce(nonce_ind);
14358 + mip6_fn.bce_cache_del(dst, haddr, coa, reply_coa,
14359 + sequence, flags, key_bu);
14363 + MIPV6_INC_STATS(n_bu_rcvd);
14369 +static int mipv6_mh_rcv(struct sk_buff *skb)
14371 + struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
14372 + struct mipv6_mh *mh;
14373 + struct in6_addr *lhome, *fhome, *lcoa = NULL, *fcoa = NULL;
14376 + fhome = &skb->nh.ipv6h->saddr;
14377 + lhome = &skb->nh.ipv6h->daddr;
14379 + if (opt->hao != 0) {
14380 + struct mipv6_dstopt_homeaddr *hao;
14381 + hao = (struct mipv6_dstopt_homeaddr *)(skb->nh.raw + opt->hao);
14382 + fcoa = &hao->addr;
14385 + if (opt->srcrt2 != 0) {
14386 + struct rt2_hdr *rt2;
14387 + rt2 = (struct rt2_hdr *)((u8 *)skb->nh.raw + opt->srcrt2);
14388 + lcoa = &rt2->addr;
14391 + /* Verify checksum is correct */
14392 + if (skb->ip_summed == CHECKSUM_HW) {
14393 + skb->ip_summed = CHECKSUM_UNNECESSARY;
14394 + if (csum_ipv6_magic(fhome, lhome, skb->len, IPPROTO_MOBILITY,
14396 + if (net_ratelimit())
14397 + printk(KERN_WARNING "MIPv6 MH hw checksum failed\n");
14398 + skb->ip_summed = CHECKSUM_NONE;
14401 + if (skb->ip_summed == CHECKSUM_NONE) {
14402 + if (csum_ipv6_magic(fhome, lhome, skb->len, IPPROTO_MOBILITY,
14403 + skb_checksum(skb, 0, skb->len, 0))) {
14404 + if (net_ratelimit())
14405 + printk(KERN_WARNING "MIPv6 MH checksum failed\n");
14410 + if (!pskb_may_pull(skb, skb->h.raw-skb->data+sizeof(*mh)) ||
14411 + !pskb_may_pull(skb,
14412 + skb->h.raw-skb->data+((skb->h.raw[1]+1)<<3))) {
14413 + DEBUG(DBG_INFO, "MIPv6 MH invalid length");
14418 + mh = (struct mipv6_mh *) skb->h.raw;
14420 + /* Verify there are no more headers after the MH */
14421 + if (mh->payload != NEXTHDR_NONE) {
14422 + __u32 pos = (__u32)&mh->payload - (__u32)skb->nh.raw;
14423 + icmpv6_send(skb, ICMPV6_PARAMPROB,
14424 + ICMPV6_HDR_FIELD, pos, skb->dev);
14426 + DEBUG(DBG_INFO, "MIPv6 MH error");
14430 + if (mh->type > MIPV6_MH_MAX) {
14431 + /* send binding error */
14432 + printk("Invalid mobility header type (%d)\n", mh->type);
14433 + mipv6_send_be(lhome, fcoa ? fcoa : fhome,
14434 + fcoa ? fhome : NULL,
14435 + MIPV6_BE_UNKNOWN_MH_TYPE);
14438 + if (mh_rcv[mh->type].func != NULL) {
14439 + ret = mh_rcv[mh->type].func(skb, lhome, lcoa, fhome, fcoa, mh);
14441 + DEBUG(DBG_INFO, "No handler for MH Type %d", mh->type);
14449 + MIPV6_INC_STATS(n_mh_in_error);
14455 +#if LINUX_VERSION_CODE >= 0x2052a
14456 +struct inet6_protocol mipv6_mh_protocol =
14458 + mipv6_mh_rcv, /* handler */
14459 + NULL /* error control */
14462 +struct inet6_protocol mipv6_mh_protocol =
14464 + mipv6_mh_rcv, /* handler */
14465 + NULL, /* error control */
14467 + IPPROTO_MOBILITY, /* protocol ID */
14470 + "MIPv6 MH" /* name */
14476 + * Code module init/exit functions
14480 +int __init mipv6_mh_common_init(void)
14485 + mip6_fn.bce_home_add = bc_cn_home_add;
14486 + mip6_fn.bce_cache_add = bc_cache_add;
14487 + mip6_fn.bce_home_del = bc_cn_home_delete;
14488 + mip6_fn.bce_cache_del = bc_cache_delete;
14490 + mipv6_mh_socket = sock_alloc();
14491 + if (mipv6_mh_socket == NULL) {
14493 + "Failed to create the MIP6 MH control socket.\n");
14496 + mipv6_mh_socket->type = SOCK_RAW;
14498 + if ((err = sock_create(PF_INET6, SOCK_RAW, IPPROTO_MOBILITY,
14499 + &mipv6_mh_socket)) < 0) {
14501 + "Failed to initialize the MIP6 MH control socket (err %d).\n",
14503 + sock_release(mipv6_mh_socket);
14504 + mipv6_mh_socket = NULL; /* for safety */
14508 + sk = mipv6_mh_socket->sk;
14509 + sk->allocation = GFP_ATOMIC;
14510 + sk->sndbuf = 64 * 1024 + sizeof(struct sk_buff);
14511 + sk->prot->unhash(sk);
14513 + memset(&mh_rcv, 0, sizeof(mh_rcv));
14514 + mh_rcv[MIPV6_MH_HOTI].func = mipv6_handle_mh_testinit;
14515 + mh_rcv[MIPV6_MH_COTI].func = mipv6_handle_mh_testinit;
14516 + mh_rcv[MIPV6_MH_BU].func = mipv6_handle_mh_bu;
14518 +#if LINUX_VERSION_CODE >= 0x2052a
14519 + if (inet6_add_protocol(&mipv6_mh_protocol, IPPROTO_MOBILITY) < 0) {
14520 + printk(KERN_ERR "Failed to register MOBILITY protocol\n");
14521 + sock_release(mipv6_mh_socket);
14522 + mipv6_mh_socket = NULL;
14526 + inet6_add_protocol(&mipv6_mh_protocol);
14528 + /* To disable the use of dst_cache,
14529 + * which slows down the sending of BUs ??
14531 + sk->dst_cache=NULL;
14536 +void __exit mipv6_mh_common_exit(void)
14538 + if (mipv6_mh_socket) sock_release(mipv6_mh_socket);
14539 + mipv6_mh_socket = NULL; /* For safety. */
14541 +#if LINUX_VERSION_CODE >= 0x2052a
14542 + inet6_del_protocol(&mipv6_mh_protocol, IPPROTO_MOBILITY);
14544 + inet6_del_protocol(&mipv6_mh_protocol);
14546 + memset(&mh_rcv, 0, sizeof(mh_rcv));
14548 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/mobhdr_mn.c linux-2.4.25/net/ipv6/mobile_ip6/mobhdr_mn.c
14549 --- linux-2.4.25.old/net/ipv6/mobile_ip6/mobhdr_mn.c 1970-01-01 01:00:00.000000000 +0100
14550 +++ linux-2.4.25/net/ipv6/mobile_ip6/mobhdr_mn.c 2004-06-26 11:29:32.000000000 +0100
14553 + * Mobile IPv6 Mobility Header Functions for Mobile Node
14556 + * Antti Tuominen <ajtuomin@tml.hut.fi>
14557 + * Niklas Kämpe <nhkampe@cc.hut.fi>
14558 + * Henrik Petander <henrik.petander@hut.fi>
14562 + * This program is free software; you can redistribute it and/or
14563 + * modify it under the terms of the GNU General Public License as
14564 + * published by the Free Software Foundation; either version 2 of
14565 + * the License, or (at your option) any later version.
14569 +#include <linux/types.h>
14570 +#include <linux/sched.h>
14571 +#include <linux/init.h>
14572 +#include <net/ipv6.h>
14573 +#include <net/addrconf.h>
14574 +#include <net/mipv6.h>
14576 +#include "mobhdr.h"
14579 +#include "rr_crypto.h"
14580 +#include "debug.h"
14582 +#include "stats.h"
14584 +int rr_configured = 1;
14586 +/* Return value of mipv6_rr_state() */
14589 +#define RR_FOR_COA 2
14590 +#define INPROGRESS_RR 3
14593 + * send_bu_msg - sends a Binding Update
14594 + * @bulentry : BUL entry with the information for building a BU
14596 + * Function builds a BU msg based on the contents of a bul entry.
14597 + * Does not change the bul entry.
14599 +static int send_bu_msg(struct mipv6_bul_entry *binding)
14601 + int auth = 0; /* Use auth */
14603 + struct mipv6_auth_parm parm;
14604 + struct mipv6_mh_bu bu;
14607 + DEBUG(DBG_ERROR, "called with a null bul entry");
14611 + memset(&parm, 0, sizeof(parm));
14612 + if (mipv6_prefix_compare(&binding->coa, &binding->home_addr, 64))
14613 + parm.coa = &binding->home_addr;
14615 + parm.coa = &binding->coa;
14616 + parm.cn_addr = &binding->cn_addr;
14618 + if (binding->rr && binding->rr->kbu) {
14619 + DEBUG(DBG_INFO, "Binding with key");
14621 + parm.k_bu = binding->rr->kbu;
14623 + memset(&bu, 0, sizeof(bu));
14624 + bu.flags = binding->flags;
14625 + bu.sequence = htons(binding->seq);
14626 + bu.lifetime = htons(binding->lifetime >> 2);
14629 + ret = send_mh(&binding->cn_addr, &binding->home_addr,
14630 + MIPV6_MH_BU, sizeof(bu), (u8 *)&bu,
14631 + &binding->home_addr, NULL,
14632 + binding->ops, &parm);
14635 + MIPV6_INC_STATS(n_bu_sent);
14641 + * mipv6_send_addr_test_init - send a HoTI or CoTI message
14642 + * @saddr: source address for H/CoTI
14643 + * @daddr: destination address for H/CoTI
14644 + * @msg_type: Identifies whether HoTI or CoTI
14645 + * @init_cookie: the HoTi or CoTi init cookie
14647 + * The message will be retransmitted till we get a HoT or CoT message, since
14648 + * our caller (mipv6_RR_start) has entered this message in the BUL with
14649 + * exponential backoff retramission set.
14651 +static int mipv6_send_addr_test_init(struct in6_addr *saddr,
14652 + struct in6_addr *daddr,
14656 + struct mipv6_mh_addr_ti ti;
14657 + struct mipv6_mh_opt *ops = NULL;
14660 + /* Set reserved and copy the cookie from address test init msg */
14662 + mipv6_rr_mn_cookie_create(init_cookie);
14663 + memcpy(ti.init_cookie, init_cookie, MIPV6_RR_COOKIE_LENGTH);
14665 + ret = send_mh(daddr, saddr, msg_type, sizeof(ti), (u8 *)&ti,
14666 + NULL, NULL, ops, NULL);
14668 + if (msg_type == MIPV6_MH_HOTI) {
14669 + MIPV6_INC_STATS(n_hoti_sent);
14671 + MIPV6_INC_STATS(n_coti_sent);
14680 + * Callback handlers for binding update list
14684 +/* Return value 0 means keep entry, non-zero means discard entry. */
14686 +/* Callback for BUs not requiring acknowledgement
14688 +int bul_entry_expired(struct mipv6_bul_entry *bulentry)
14690 + /* Lifetime expired, delete entry. */
14691 + DEBUG(DBG_INFO, "bul entry 0x%p lifetime expired, deleting entry",
14696 +/* Callback for BUs requiring acknowledgement with exponential resending
14698 +static int bul_resend_exp(struct mipv6_bul_entry *bulentry)
14700 + unsigned long now = jiffies;
14702 + DEBUG(DBG_INFO, "(0x%x) resending bu", (int) bulentry);
14705 + /* If sending a de-registration, do not care about the
14706 + * lifetime value, as de-registrations are normally sent with
14707 + * a zero lifetime value. If the entry is a home entry get the
14708 + * current lifetime.
14711 + if (bulentry->lifetime != 0) {
14712 + bulentry->lifetime = mipv6_mn_get_bulifetime(
14713 + &bulentry->home_addr, &bulentry->coa, bulentry->flags);
14715 + bulentry->expire = now + bulentry->lifetime * HZ;
14717 + bulentry->expire = now + HOME_RESEND_EXPIRE * HZ;
14719 + if (bulentry->rr) {
14720 + /* Redo RR, if cookies have expired */
14721 + if (time_after(jiffies, bulentry->rr->home_time + MAX_TOKEN_LIFE * HZ))
14722 + bulentry->rr->rr_state |= RR_WAITH;
14723 + if (time_after(jiffies, bulentry->rr->careof_time + MAX_NONCE_LIFE * HZ))
14724 + bulentry->rr->rr_state |= RR_WAITC;
14726 + if (bulentry->rr->rr_state & RR_WAITH) {
14727 + /* Resend HoTI directly */
14728 + mipv6_send_addr_test_init(&bulentry->home_addr,
14729 + &bulentry->cn_addr, MIPV6_MH_HOTI,
14730 + bulentry->rr->hot_cookie);
14732 + if (bulentry->rr->rr_state & RR_WAITC) {
14733 + /* Resend CoTI directly */
14734 + mipv6_send_addr_test_init(&bulentry->coa,
14735 + &bulentry->cn_addr, MIPV6_MH_COTI,
14736 + bulentry->rr->cot_cookie);
14743 + if (send_bu_msg(bulentry) < 0)
14744 + DEBUG(DBG_ERROR, "Resending of BU failed");
14747 + /* Schedule next retransmission */
14748 + if (bulentry->delay < bulentry->maxdelay) {
14749 + bulentry->delay = 2 * bulentry->delay;
14750 + if (bulentry->delay > bulentry->maxdelay) {
14751 + /* can happen if maxdelay is not power(mindelay, 2) */
14752 + bulentry->delay = bulentry->maxdelay;
14754 + } else if (bulentry->flags & MIPV6_BU_F_HOME) {
14755 + /* Home registration - continue sending BU at maxdelay rate */
14756 + DEBUG(DBG_INFO, "Sending BU to HA after max ack wait time "
14757 + "reached(0x%x)", (int) bulentry);
14758 + bulentry->delay = bulentry->maxdelay;
14759 + } else if (!(bulentry->flags & MIPV6_BU_F_HOME)) {
14760 + /* Failed to get BA from a CN */
14761 + bulentry->callback_time = now;
14765 + bulentry->callback_time = now + bulentry->delay * HZ;
14771 +/* Callback for sending a registration refresh BU
14773 +static int bul_refresh(struct mipv6_bul_entry *bulentry)
14775 + unsigned long now = jiffies;
14777 + /* Refresh interval passed, send new BU */
14778 + DEBUG(DBG_INFO, "bul entry 0x%x refresh interval passed, sending new BU", (int) bulentry);
14779 + if (bulentry->lifetime == 0)
14782 + /* Set new maximum lifetime and expiration time */
14783 + bulentry->lifetime = mipv6_mn_get_bulifetime(&bulentry->home_addr,
14785 + bulentry->flags);
14786 + bulentry->expire = now + bulentry->lifetime * HZ;
14788 + /* Send update */
14789 + if (send_bu_msg(bulentry) < 0)
14790 + DEBUG(DBG_ERROR, "Resending of BU failed");
14792 + if (time_after_eq(now, bulentry->expire)) {
14793 + /* Sanity check */
14794 + DEBUG(DBG_ERROR, "bul entry expire time in history - setting expire to %u secs", ERROR_DEF_LIFETIME);
14795 + bulentry->lifetime = ERROR_DEF_LIFETIME;
14796 + bulentry->expire = now + ERROR_DEF_LIFETIME*HZ;
14799 + /* Set up retransmission */
14800 + bulentry->state = RESEND_EXP;
14801 + bulentry->callback = bul_resend_exp;
14802 + bulentry->callback_time = now + INITIAL_BINDACK_TIMEOUT*HZ;
14803 + bulentry->delay = INITIAL_BINDACK_TIMEOUT;
14804 + bulentry->maxdelay = MAX_BINDACK_TIMEOUT;
14809 +static int mipv6_send_RR_bu(struct mipv6_bul_entry *bulentry)
14815 + DEBUG(DBG_INFO, "Sending BU to CN %x:%x:%x:%x:%x:%x:%x:%x "
14816 + "for home address %x:%x:%x:%x:%x:%x:%x:%x",
14817 + NIPV6ADDR(&bulentry->cn_addr), NIPV6ADDR(&bulentry->home_addr));
14818 + nonces[0] = bulentry->rr->home_nonce_index;
14819 + nonces[1] = bulentry->rr->careof_nonce_index;
14820 + ops_len = sizeof(struct mipv6_mo_bauth_data) + MIPV6_RR_MAC_LENGTH +
14821 + sizeof(struct mipv6_mo_nonce_indices);
14822 + if (bulentry->ops) {
14823 + DEBUG(DBG_WARNING, "Bul entry had existing mobility options, freeing them");
14824 + kfree(bulentry->ops);
14826 + bulentry->ops = alloc_mh_opts(ops_len);
14828 + if (!bulentry->ops)
14830 + if (append_mh_opt(bulentry->ops, MIPV6_OPT_NONCE_INDICES,
14831 + sizeof(struct mipv6_mo_nonce_indices) - 2, nonces) < 0)
14834 + if (append_mh_opt(bulentry->ops, MIPV6_OPT_AUTH_DATA,
14835 + MIPV6_RR_MAC_LENGTH, NULL) < 0)
14837 + /* RR procedure is over, send a BU */
14838 + if (!(bulentry->flags & MIPV6_BU_F_ACK)) {
14839 + DEBUG(DBG_INFO, "Setting bul callback to bul_entry_expired");
14840 + bulentry->state = ACK_OK;
14841 + bulentry->callback = bul_entry_expired;
14842 + bulentry->callback_time = jiffies + HZ * bulentry->lifetime;
14843 + bulentry->expire = jiffies + HZ * bulentry->lifetime;
14846 + bulentry->callback_time = jiffies + HZ;
14847 + bulentry->expire = jiffies + HZ * bulentry->lifetime;
14850 + ret = send_bu_msg(bulentry);
14851 + mipv6_bul_reschedule(bulentry);
14855 +static int mipv6_rr_state(struct mipv6_bul_entry *bul, struct in6_addr *saddr,
14856 + struct in6_addr *coa, __u8 flags)
14858 + if (!rr_configured)
14860 + if (flags & MIPV6_BU_F_HOME) {
14861 + /* We don't need RR, this is a Home Registration */
14864 + if (!bul || !bul->rr) {
14865 + /* First time BU to CN, need RR */
14869 + switch (bul->rr->rr_state) {
14871 + /* Need RR if first BU to CN */
14874 + /* If MN moves to a new coa, do RR for it */
14875 + if (!ipv6_addr_cmp(&bul->coa, coa))
14881 + * We are in the middle of RR, the HoTI and CoTI have been
14882 + * sent. But we haven't got HoT and CoT from the CN, so
14883 + * don't do anything more at this time.
14885 + return INPROGRESS_RR;
14890 + * mipv6_RR_start - Start Return Routability procedure
14891 + * @home_addr: home address
14892 + * @cn_addr: correspondent address
14893 + * @coa: care-of address
14894 + * @entry: binding update list entry (if any)
14895 + * @initdelay: initial ack timeout
14896 + * @maxackdelay: maximum ack timeout
14898 + * @lifetime: lifetime of binding
14899 + * @ops: mobility options
14901 + * Caller must hold @bul_lock (write).
14903 +static int mipv6_RR_start(struct in6_addr *home_addr, struct in6_addr *cn_addr,
14904 + struct in6_addr *coa, struct mipv6_bul_entry *entry,
14905 + __u32 initdelay, __u32 maxackdelay, __u8 flags,
14906 + __u32 lifetime, struct mipv6_mh_opt *ops)
14909 + struct mipv6_bul_entry *bulentry = entry;
14910 + struct mipv6_rr_info *rr = NULL;
14914 + /* Do RR procedure only for care-of address after handoff,
14915 + if home cookie is still valid */
14916 + if (bulentry && bulentry->rr) {
14917 + if (time_before(jiffies, bulentry->rr->home_time + MAX_NONCE_LIFE * HZ) &&
14918 + lifetime && !(ipv6_addr_cmp(home_addr, coa) == 0)) {
14919 + mipv6_rr_mn_cookie_create(bulentry->rr->cot_cookie);
14920 + DEBUG(DBG_INFO, "Bul entry and rr info exist, only doing RR for CoA");
14921 + ipv6_addr_copy(&bulentry->coa, coa);
14922 + bulentry->rr->rr_state |= RR_WAITC;
14923 + } else if (!lifetime) { /* Send only HoTi when returning home */
14924 + mipv6_rr_mn_cookie_create(bulentry->rr->hot_cookie);
14925 + DEBUG(DBG_INFO, "Bul entry and rr info exist, only doing RR for HoA");
14926 + ipv6_addr_copy(&bulentry->coa, coa); /* Home address as CoA */
14927 + bulentry->rr->rr_state |= RR_WAITH;
14930 + DEBUG(DBG_INFO, "Doing RR for both HoA and CoA");
14931 + rr = kmalloc(sizeof(*rr), GFP_ATOMIC);
14932 + memset(rr, 0, sizeof(*rr));
14933 + rr->rr_state = RR_WAITHC;
14936 + if (bulentry->state == ACK_ERROR)
14938 + seq = bulentry->seq + 1;
14941 + /* Save the info in the BUL to retransmit the BU after RR is done */
14942 + /* Caller must hold bul_lock (write) since we don't */
14944 + if ((bulentry = mipv6_bul_add(cn_addr, home_addr, coa,
14945 + min_t(__u32, lifetime, MAX_RR_BINDING_LIFE),
14946 + seq, flags, bul_resend_exp, initdelay,
14947 + RESEND_EXP, initdelay,
14948 + maxackdelay, ops,
14950 + DEBUG(DBG_INFO, "couldn't update BUL for HoTi");
14954 + rr = bulentry->rr;
14955 + if (rr->rr_state&RR_WAITH)
14956 + mipv6_send_addr_test_init(home_addr, cn_addr, MIPV6_MH_HOTI,
14958 + if (ipv6_addr_cmp(home_addr, coa) && lifetime)
14959 + mipv6_send_addr_test_init(coa, cn_addr, MIPV6_MH_COTI, rr->cot_cookie);
14961 + bulentry->rr->rr_state &= ~RR_WAITC;
14969 + * Status codes for mipv6_ba_rcvd()
14971 +#define STATUS_UPDATE 0
14972 +#define STATUS_REMOVE 1
14975 + * mipv6_ba_rcvd - Update BUL for this Binding Acknowledgement
14976 + * @ifindex: interface BA came from
14977 + * @cnaddr: sender IPv6 address
14978 + * @home_addr: home address
14979 + * @sequence: sequence number
14980 + * @lifetime: lifetime granted by Home Agent in seconds
14981 + * @refresh: recommended resend interval
14982 + * @status: %STATUS_UPDATE (ack) or %STATUS_REMOVE (nack)
14984 + * This function must be called to notify the module of the receipt of
14985 + * a binding acknowledgement so that it can cease retransmitting the
14986 + * option. The caller must have validated the acknowledgement before calling
14987 + * this function. 'status' can be either STATUS_UPDATE in which case the
14988 + * binding acknowledgement is assumed to be valid and the corresponding
14989 + * binding update list entry is updated, or STATUS_REMOVE in which case
14990 + * the corresponding binding update list entry is removed (this can be
14991 + * used upon receiving a negative acknowledgement).
14992 + * Returns 0 if a matching binding update has been sent or non-zero if
14995 +static int mipv6_ba_rcvd(int ifindex, struct in6_addr *cnaddr,
14996 + struct in6_addr *home_addr,
14997 + u16 sequence, u32 lifetime,
14998 + u32 refresh, int status)
15000 + struct mipv6_bul_entry *bulentry;
15001 + unsigned long now = jiffies;
15002 + struct in6_addr coa;
15004 + DEBUG(DBG_INFO, "BA received with sequence number 0x%x, status: %d",
15005 + (int) sequence, status);
15007 + /* Find corresponding entry in binding update list. */
15008 + write_lock(&bul_lock);
15009 + if ((bulentry = mipv6_bul_get(cnaddr, home_addr)) == NULL) {
15010 + DEBUG(DBG_INFO, "- discarded, no entry in bul matches BA source address");
15011 + write_unlock(&bul_lock);
15015 + ipv6_addr_copy(&coa, &bulentry->coa);
15016 + if (status == SEQUENCE_NUMBER_OUT_OF_WINDOW) {
15017 + __u32 lifetime = mipv6_mn_get_bulifetime(&bulentry->home_addr,
15019 + bulentry->flags);
15020 + bulentry->seq = sequence;
15022 + mipv6_send_bu(&bulentry->home_addr, &bulentry->cn_addr,
15023 + &bulentry->coa, INITIAL_BINDACK_TIMEOUT,
15024 + MAX_BINDACK_TIMEOUT, 1, bulentry->flags,
15026 + write_unlock(&bul_lock);
15028 + } else if (status >= REASON_UNSPECIFIED) {
15030 + int at_home = MN_NOT_AT_HOME;
15031 + DEBUG(DBG_WARNING, "- NACK - BA status: %d, deleting bul entry", status);
15032 + if (bulentry->flags & MIPV6_BU_F_HOME) {
15033 + struct mn_info *minfo;
15034 + read_lock(&mn_info_lock);
15035 + minfo = mipv6_mninfo_get_by_home(home_addr);
15037 + spin_lock(&minfo->lock);
15038 + if (minfo->is_at_home != MN_NOT_AT_HOME)
15039 + minfo->is_at_home = MN_AT_HOME;
15040 + at_home = minfo->is_at_home;
15041 + minfo->has_home_reg = 0;
15042 + spin_unlock(&minfo->lock);
15044 + read_unlock(&mn_info_lock);
15045 + DEBUG(DBG_ERROR, "Home registration failed: BA status: %d, deleting bul entry", status);
15047 + write_unlock(&bul_lock);
15048 + err = mipv6_bul_delete(cnaddr, home_addr);
15049 + if (at_home == MN_AT_HOME) {
15050 + mipv6_mn_send_home_na(home_addr);
15051 + write_lock_bh(&bul_lock);
15052 + mipv6_bul_iterate(mn_cn_handoff, &coa);
15053 + write_unlock_bh(&bul_lock);
15057 + bulentry->state = ACK_OK;
15059 + if (bulentry->flags & MIPV6_BU_F_HOME && lifetime > 0) {
15060 + /* For home registrations: schedule a refresh binding update.
15061 + * Use the refresh interval given by home agent or 80%
15062 + * of lifetime, whichever is less.
15064 + * Adjust binding lifetime if 'granted' lifetime
15065 + * (lifetime value in received binding acknowledgement)
15066 + * is shorter than 'requested' lifetime (lifetime
15067 + * value sent in corresponding binding update).
15068 + * max((L_remain - (L_update - L_ack)), 0)
15070 + if (lifetime * HZ < (bulentry->expire - bulentry->lastsend)) {
15071 + bulentry->expire =
15072 + max_t(__u32, bulentry->expire -
15073 + ((bulentry->expire - bulentry->lastsend) -
15074 + lifetime * HZ), jiffies +
15075 + ERROR_DEF_LIFETIME * HZ);
15077 + if (refresh > lifetime || refresh == 0)
15078 + refresh = 4 * lifetime / 5;
15079 + DEBUG(DBG_INFO, "setting callback for expiration of"
15080 + " a Home Registration: lifetime:%d, refresh:%d",
15081 + lifetime, refresh);
15082 + bulentry->callback = bul_refresh;
15083 + bulentry->callback_time = now + refresh * HZ;
15084 + bulentry->expire = now + lifetime * HZ;
15085 + bulentry->lifetime = lifetime;
15086 + if (time_after_eq(jiffies, bulentry->expire)) {
15087 + /* Sanity check */
15088 + DEBUG(DBG_ERROR, "bul entry expire time in history - setting expire to %u secs",
15089 + ERROR_DEF_LIFETIME);
15090 + bulentry->expire = jiffies + ERROR_DEF_LIFETIME * HZ;
15092 + mipv6_mn_set_home_reg(home_addr, 1);
15093 + mipv6_bul_iterate(mn_cn_handoff, &coa);
15094 + } else if ((bulentry->flags & MIPV6_BU_F_HOME) && bulentry->lifetime == 0) {
15095 + write_unlock(&bul_lock);
15096 + DEBUG(DBG_INFO, "Got BA for deregistration BU");
15097 + mipv6_mn_set_home_reg(home_addr, 0);
15098 + mipv6_bul_delete(cnaddr, home_addr);
15099 + mipv6_mn_send_home_na(home_addr);
15101 + write_lock_bh(&bul_lock);
15102 + mipv6_bul_iterate(mn_cn_handoff, &coa);
15103 + write_unlock_bh(&bul_lock);
15107 + mipv6_bul_reschedule(bulentry);
15108 + write_unlock(&bul_lock);
15113 +static int mipv6_handle_mh_HC_test(struct sk_buff *skb,
15114 + struct in6_addr *saddr,
15115 + struct in6_addr *fcoa,
15116 + struct in6_addr *cn,
15117 + struct in6_addr *lcoa,
15118 + struct mipv6_mh *mh)
15121 + int msg_len = (mh->length+1) << 3;
15124 + struct mipv6_mh_addr_test *tm = (struct mipv6_mh_addr_test *)mh->data;
15125 + struct mipv6_bul_entry *bulentry;
15129 + if (msg_len > skb->len)
15132 + opt_len = msg_len - sizeof(*mh) - sizeof(*tm);
15134 + if (opt_len < 0) {
15135 + __u32 pos = (__u32)&mh->length - (__u32)skb->nh.raw;
15136 + icmpv6_send(skb, ICMPV6_PARAMPROB,
15137 + ICMPV6_HDR_FIELD, pos, skb->dev);
15139 + DEBUG(DBG_INFO, "Mobility Header length less than H/C Test");
15142 + if (fcoa || lcoa) {
15143 + DEBUG(DBG_INFO, "H/C Test has HAO or RTH2, dropped.");
15146 + write_lock(&bul_lock);
15148 + /* We need to get the home address, since CoT only has the CoA*/
15149 + if (mh->type == MIPV6_MH_COT) {
15150 + if ((bulentry = mipv6_bul_get_by_ccookie(cn, tm->init_cookie)) == NULL) {
15151 + DEBUG(DBG_ERROR, "has no BUL or RR state for "
15152 + "source:%x:%x:%x:%x:%x:%x:%x:%x",
15154 + write_unlock(&bul_lock);
15157 + } else { /* HoT has the home address */
15158 + if (((bulentry = mipv6_bul_get(cn, saddr)) == NULL) || !bulentry->rr) {
15159 + DEBUG(DBG_ERROR, "has no BUL or RR state for "
15160 + "source:%x:%x:%x:%x:%x:%x:%x:%x "
15161 + "dest:%x:%x:%x:%x:%x:%x:%x:%x",
15162 + NIPV6ADDR(cn), NIPV6ADDR(saddr));
15163 + write_unlock(&bul_lock);
15168 + switch (mh->type) {
15169 + case MIPV6_MH_HOT:
15170 + if ((bulentry->rr->rr_state & RR_WAITH) == 0) {
15171 + DEBUG(DBG_ERROR, "Not waiting for a Home Test message");
15175 + * Make sure no home cookies have been received yet.
15176 + * TODO: Check not being put in at this time since subsequent
15177 + * BU's after this time will have home cookie stored.
15180 + /* Check if the cookie received is the right one */
15181 + if (!mipv6_equal_cookies(tm->init_cookie,
15182 + bulentry->rr->hot_cookie)) {
15183 + /* Invalid cookie, might be an old cookie */
15184 + DEBUG(DBG_WARNING, "Received HoT cookie does not match stored cookie");
15187 + DEBUG(DBG_INFO, "Got Care-of Test message");
15188 + bulentry->rr->rr_state &= ~RR_WAITH;
15189 + memcpy(bulentry->rr->home_cookie, tm->kgen_token, MIPV6_COOKIE_LEN);
15190 + bulentry->rr->home_nonce_index = tm->nonce_index;
15191 + bulentry->rr->home_time = jiffies;
15195 + case MIPV6_MH_COT:
15196 + if ((bulentry->rr->rr_state & RR_WAITC) == 0) {
15197 + DEBUG(DBG_ERROR, "Not waiting for a Home Test message");
15201 + * Make sure no home cookies have been received yet.
15202 + * TODO: Check not being put in at this time since subsequent
15203 + * BU's at this time will have careof cookie stored.
15206 + /* Check if the cookie received is the right one */
15207 + if (!mipv6_equal_cookies(tm->init_cookie,
15208 + bulentry->rr->cot_cookie)) {
15209 + DEBUG(DBG_INFO, "Received CoT cookie does not match stored cookie");
15212 + bulentry->rr->rr_state &= ~RR_WAITC;
15213 + memcpy(bulentry->rr->careof_cookie, tm->kgen_token, MIPV6_COOKIE_LEN);
15214 + bulentry->rr->careof_nonce_index = tm->nonce_index;
15215 + bulentry->rr->careof_time = jiffies;
15219 + /* Impossible to get here */
15223 + if (bulentry->rr->rr_state == RR_DONE) {
15224 + if (bulentry->rr->kbu) /* First free any old keys */
15225 + kfree(bulentry->rr->kbu);
15226 + /* Store the session key to be used in BU's */
15227 + if (ipv6_addr_cmp(&bulentry->coa, &bulentry->home_addr) && bulentry->lifetime)
15228 + bulentry->rr->kbu = mipv6_rr_key_calc(bulentry->rr->home_cookie,
15229 + bulentry->rr->careof_cookie);
15231 + bulentry->rr->kbu = mipv6_rr_key_calc(bulentry->rr->home_cookie,
15233 + /* RR procedure is over, send a BU */
15234 + mipv6_send_RR_bu(bulentry);
15236 + write_unlock(&bul_lock);
15241 + * mipv6_handle_mh_brr - Binding Refresh Request handler
15242 + * @home: home address
15243 + * @coa: care-of address
15244 + * @cn: source of this packet
15245 + * @mh: pointer to the beginning of the Mobility Header
15247 + * Handles Binding Refresh Request. Packet and offset to option are
15248 + * passed. Returns 0 on success, otherwise negative.
15250 +static int mipv6_handle_mh_brr(struct sk_buff *skb,
15251 + struct in6_addr *home,
15252 + struct in6_addr *unused1,
15253 + struct in6_addr *cn,
15254 + struct in6_addr *unused2,
15255 + struct mipv6_mh *mh)
15257 + struct mipv6_mh_brr *brr = (struct mipv6_mh_brr *)mh->data;
15258 + struct mipv6_bul_entry *binding;
15259 + int msg_len = (mh->length+1) << 3;
15262 + if (msg_len > skb->len)
15265 + opt_len = msg_len - sizeof(*mh) - sizeof(*brr);
15267 + if (opt_len < 0) {
15268 + __u32 pos = (__u32)&mh->length - (__u32)skb->nh.raw;
15269 + icmpv6_send(skb, ICMPV6_PARAMPROB,
15270 + ICMPV6_HDR_FIELD, pos, skb->dev);
15272 + DEBUG(DBG_WARNING, "Mobility Header length less than BRR");
15273 + MIPV6_INC_STATS(n_brr_drop.invalid);
15277 + /* check we know src, else drop */
15278 + write_lock(&bul_lock);
15279 + if ((binding = mipv6_bul_get(cn, home)) == NULL) {
15280 + MIPV6_INC_STATS(n_brr_drop.misc);
15281 + write_unlock(&bul_lock);
15282 + return MH_UNKNOWN_CN;
15285 + MIPV6_INC_STATS(n_brr_rcvd);
15287 + if (opt_len > 0) {
15288 + struct mobopt opts;
15289 + memset(&opts, 0, sizeof(opts));
15290 + if (parse_mo_tlv(brr + 1, opt_len, &opts) < 0) {
15291 + write_unlock(&bul_lock);
15295 + * MIPV6_OPT_AUTH_DATA
15299 + /* must hold bul_lock (write) */
15300 + mipv6_RR_start(home, cn, &binding->coa, binding, binding->delay,
15301 + binding->maxdelay, binding->flags,
15302 + binding->lifetime, binding->ops);
15304 + write_unlock(&bul_lock);
15305 + /* MAY also decide to delete binding and send zero lifetime BU
15306 + with alt-coa set to home address */
15312 + * mipv6_handle_mh_ba - Binding Acknowledgement handler
15313 + * @src: source of this packet
15314 + * @coa: care-of address
15315 + * @home: home address
15316 + * @mh: pointer to the beginning of the Mobility Header
15319 +static int mipv6_handle_mh_ba(struct sk_buff *skb,
15320 + struct in6_addr *home,
15321 + struct in6_addr *coa,
15322 + struct in6_addr *src,
15323 + struct in6_addr *unused,
15324 + struct mipv6_mh *mh)
15326 + struct mipv6_mh_ba *ba = (struct mipv6_mh_ba *)mh->data;
15327 + struct mipv6_bul_entry *binding = NULL;
15328 + struct mobopt opts;
15329 + int msg_len = (mh->length+1) << 3;
15332 + int auth = 1, req_auth = 1, refresh = -1, ifindex = 0;
15333 + u32 lifetime, sequence;
15335 + if (msg_len > skb->len)
15338 + opt_len = msg_len - sizeof(*mh) - sizeof(*ba);
15340 + if (opt_len < 0) {
15341 + __u32 pos = (__u32)&mh->length - (__u32)skb->nh.raw;
15342 + icmpv6_send(skb, ICMPV6_PARAMPROB,
15343 + ICMPV6_HDR_FIELD, pos, skb->dev);
15345 + DEBUG(DBG_WARNING, "Mobility Header length less than BA");
15346 + MIPV6_INC_STATS(n_ba_drop.invalid);
15350 + lifetime = ntohs(ba->lifetime) << 2;
15351 + sequence = ntohs(ba->sequence);
15353 + if (opt_len > 0) {
15354 + memset(&opts, 0, sizeof(opts));
15355 + if (parse_mo_tlv(ba + 1, opt_len, &opts) < 0)
15358 + * MIPV6_OPT_AUTH_DATA, MIPV6_OPT_BR_ADVICE
15360 + if (opts.br_advice)
15361 + refresh = ntohs(opts.br_advice->refresh_interval);
15364 + if (ba->status >= EXPIRED_HOME_NONCE_INDEX &&
15365 + ba->status <= EXPIRED_NONCES)
15368 + write_lock(&bul_lock);
15369 + binding = mipv6_bul_get(src, home);
15371 + DEBUG(DBG_INFO, "No binding, BA dropped.");
15372 + write_unlock(&bul_lock);
15376 + if (opts.auth_data && binding->rr &&
15377 + (mipv6_auth_check(src, coa, (__u8 *)mh, msg_len,
15378 + opts.auth_data, binding->rr->kbu) == 0))
15381 + if (req_auth && binding->rr && !auth) {
15382 + DEBUG(DBG_INFO, "BA Authentication failed.");
15383 + MIPV6_INC_STATS(n_ba_drop.auth);
15384 + write_unlock(&bul_lock);
15385 + return MH_AUTH_FAILED;
15388 + if (ba->status == SEQUENCE_NUMBER_OUT_OF_WINDOW) {
15390 + "Sequence number out of window, setting seq to %d",
15392 + } else if (binding->seq != sequence) {
15393 + DEBUG(DBG_INFO, "BU/BA Sequence Number mismatch %d != %d",
15394 + binding->seq, sequence);
15395 + MIPV6_INC_STATS(n_ba_drop.invalid);
15396 + write_unlock(&bul_lock);
15397 + return MH_SEQUENCE_MISMATCH;
15399 + if (ba->status == EXPIRED_HOME_NONCE_INDEX || ba->status == EXPIRED_NONCES) {
15400 + if (binding->rr) {
15401 + /* Need to resend home test init to CN */
15402 + binding->rr->rr_state |= RR_WAITH;
15403 + mipv6_send_addr_test_init(&binding->home_addr,
15404 + &binding->cn_addr,
15406 + binding->rr->hot_cookie);
15407 + MIPV6_INC_STATS(n_ban_rcvd);
15409 + DEBUG(DBG_WARNING, "Got BA with status EXPIRED_HOME_NONCE_INDEX"
15410 + "for non-RR BU");
15411 + MIPV6_INC_STATS(n_ba_drop.invalid);
15413 + write_unlock(&bul_lock);
15416 + if (ba->status == EXPIRED_CAREOF_NONCE_INDEX || ba->status == EXPIRED_NONCES) {
15417 + if (binding->rr) {
15418 + /* Need to resend care-of test init to CN */
15419 + binding->rr->rr_state |= RR_WAITC;
15420 + mipv6_send_addr_test_init(&binding->coa,
15421 + &binding->cn_addr,
15423 + binding->rr->cot_cookie);
15424 + MIPV6_INC_STATS(n_ban_rcvd);
15426 + DEBUG(DBG_WARNING, "Got BA with status EXPIRED_HOME_CAREOF_INDEX"
15427 + "for non-RR BU");
15428 + MIPV6_INC_STATS(n_ba_drop.invalid);
15430 + write_unlock(&bul_lock);
15433 + write_unlock(&bul_lock);
15435 + if (ba->status >= REASON_UNSPECIFIED) {
15436 + DEBUG(DBG_INFO, "Binding Ack status : %d indicates error", ba->status);
15437 + mipv6_ba_rcvd(ifindex, src, home, sequence, lifetime,
15438 + refresh, ba->status);
15439 + MIPV6_INC_STATS(n_ban_rcvd);
15442 + MIPV6_INC_STATS(n_ba_rcvd);
15443 + if (mipv6_ba_rcvd(ifindex, src, home, ntohs(ba->sequence), lifetime,
15444 + refresh, ba->status)) {
15445 + DEBUG(DBG_WARNING, "mipv6_ba_rcvd failed");
15452 + * mipv6_handle_mh_be - Binding Error handler
15453 + * @cn: source of this packet
15454 + * @coa: care-of address
15455 + * @home: home address
15456 + * @mh: pointer to the beginning of the Mobility Header
15460 +static int mipv6_handle_mh_be(struct sk_buff *skb,
15461 + struct in6_addr *home,
15462 + struct in6_addr *coa,
15463 + struct in6_addr *cn,
15464 + struct in6_addr *unused,
15465 + struct mipv6_mh *mh)
15467 + struct mipv6_mh_be *be = (struct mipv6_mh_be *)mh->data;
15468 + int msg_len = (mh->length+1) << 3;
15470 + struct in6_addr *hoa;
15471 + struct bul_inval_args args;
15475 + if (msg_len > skb->len)
15478 + opt_len = msg_len - sizeof(*mh) - sizeof(*be);
15480 + if (opt_len < 0) {
15481 + __u32 pos = (__u32)&mh->length - (__u32)skb->nh.raw;
15482 + icmpv6_send(skb, ICMPV6_PARAMPROB,
15483 + ICMPV6_HDR_FIELD, pos, skb->dev);
15485 + DEBUG(DBG_WARNING, "Mobility Header length less than BE");
15486 + MIPV6_INC_STATS(n_be_drop.invalid);
15491 + if (!ipv6_addr_any(&be->home_addr))
15492 + hoa = &be->home_addr;
15496 + MIPV6_INC_STATS(n_be_rcvd);
15498 + args.all_rr_states = 0;
15502 + switch (be->status) {
15503 + case 1: /* Home Address Option used without a binding */
15504 + /* Get ULP information about CN-MN communication. If
15505 + nothing in progress, MUST delete. Otherwise MAY
15507 + args.all_rr_states = 1;
15508 + case 2: /* Received unknown MH type */
15509 + /* If not expecting ack, SHOULD ignore. If MH
15510 + extension in use, stop it. If not, stop RO for
15512 + write_lock(&bul_lock);
15513 + mipv6_bul_iterate(mn_bul_invalidate, &args);
15514 + write_unlock(&bul_lock);
15522 + * mipv6_bu_rate_limit() : Takes a bulentry, a COA and 'flags' to check
15523 + * whether BU being sent is for Home Registration or not.
15525 + * If the number of BU's sent is fewer than MAX_FAST_UPDATES, this BU
15526 + * is allowed to be sent at the MAX_UPDATE_RATE.
15527 + * If the number of BU's sent is greater than or equal to MAX_FAST_UPDATES,
15528 + * this BU is allowed to be sent at the SLOW_UPDATE_RATE.
15530 + * Assumption : This function is not re-entrant. and the caller holds the
15531 + * bulentry lock (by calling mipv6_bul_get()) to stop races with other
15532 + * CPU's executing this same function.
15534 + * Side-Effects. Either of the following could on success :
15535 + * 1. Sets consecutive_sends to 1 if the entry is a Home agent
15536 + * registration or the COA has changed.
15537 + * 2. Increments consecutive_sends if the number of BU's sent so
15538 + * far is less than MAX_FAST_UPDATES, and this BU is being sent
15539 + * atleast MAX_UPDATE_RATE after previous one.
15541 + * Return Value : 0 on Success, -1 on Failure
15543 +static int mipv6_bu_rate_limit(struct mipv6_bul_entry *bulentry,
15544 + struct in6_addr *coa, __u8 flags)
15546 + if ((flags & MIPV6_BU_F_HOME) || ipv6_addr_cmp(&bulentry->coa, coa)) {
15547 + /* Home Agent Registration or different COA - restart from 1 */
15548 + bulentry->consecutive_sends = 1;
15552 + if (bulentry->consecutive_sends < MAX_FAST_UPDATES) {
15553 + /* First MAX_FAST_UPDATES can be sent at MAX_UPDATE_RATE */
15554 + if (jiffies - bulentry->lastsend < MAX_UPDATE_RATE * HZ) {
15557 + bulentry->consecutive_sends ++;
15559 + /* Remaining updates SHOULD be sent at SLOW_UPDATE_RATE */
15560 + if (jiffies - bulentry->lastsend < SLOW_UPDATE_RATE * HZ) {
15563 + /* Don't inc 'consecutive_sends' to avoid overflow to zero */
15565 + /* OK to send a BU */
15570 + * mipv6_send_bu - send a Binding Update
15571 + * @saddr: source address for BU
15572 + * @daddr: destination address for BU
15573 + * @coa: care-of address for MN
15574 + * @initdelay: initial BA wait timeout
15575 + * @maxackdelay: maximum BA wait timeout
15576 + * @exp: exponention back off
15577 + * @flags: flags for BU
15578 + * @lifetime: granted lifetime for binding
15579 + * @ops: mobility options
15581 + * Send a binding update. 'flags' may contain any of %MIPV6_BU_F_ACK,
15582 + * %MIPV6_BU_F_HOME, %MIPV6_BU_F_ROUTER bitwise ORed. If
15583 + * %MIPV6_BU_F_ACK is included retransmission will be attempted until
15584 + * the update has been acknowledged. Retransmission is done if no
15585 + * acknowledgement is received within @initdelay seconds. @exp
15586 + * specifies whether to use exponential backoff (@exp != 0) or linear
15587 + * backoff (@exp == 0). For exponential backoff the time to wait for
15588 + * an acknowledgement is doubled on each retransmission until a delay
15589 + * of @maxackdelay, after which retransmission is no longer attempted.
15590 + * For linear backoff the delay is kept constant and @maxackdelay
15591 + * specifies the maximum number of retransmissions instead. If
15592 + * sub-options are present ops must contain all sub-options to be
15593 + * added. On a mobile node, use the mobile node's home address for
15594 + * @saddr. Returns 0 on success, non-zero on failure.
15596 + * Caller may not hold @bul_lock.
15598 +int mipv6_send_bu(struct in6_addr *saddr, struct in6_addr *daddr,
15599 + struct in6_addr *coa, u32 initdelay,
15600 + u32 maxackdelay, u8 exp, u8 flags, u32 lifetime,
15601 + struct mipv6_mh_opt *ops)
15606 + int (*callback)(struct mipv6_bul_entry *);
15607 + __u32 callback_time;
15608 + struct mipv6_bul_entry *bulentry;
15610 + /* First a sanity check: don't send BU to local addresses */
15611 + if(ipv6_chk_addr(daddr, NULL)) {
15612 + DEBUG(DBG_ERROR, "BUG: Trying to send BU to local address");
15615 + DEBUG(DBG_INFO, "Sending BU to CN %x:%x:%x:%x:%x:%x:%x:%x "
15616 + "for home address %x:%x:%x:%x:%x:%x:%x:%x",
15617 + NIPV6ADDR(daddr), NIPV6ADDR(saddr));
15619 + if ((bulentry = mipv6_bul_get(daddr, saddr)) != NULL) {
15620 + if (bulentry->state == ACK_ERROR) {
15622 + * Don't send any more BU's to nodes which don't
15623 + * understanding one.
15625 + DEBUG(DBG_INFO, "Not sending BU to node which doesn't"
15626 + " understand one");
15629 + if (mipv6_bu_rate_limit(bulentry, coa, flags) < 0) {
15630 + DEBUG(DBG_DATADUMP, "Limiting BU sent.");
15635 + switch (mipv6_rr_state(bulentry, saddr, coa, flags)) {
15636 + case INPROGRESS_RR:
15637 + /* We are already doing RR, don't do BU at this time, it is
15638 + * done automatically later */
15639 + DEBUG(DBG_INFO, "RR in progress not sending BU");
15643 + /* Just do RR and return, BU is done automatically later */
15644 + DEBUG(DBG_INFO, "starting RR" );
15645 + mipv6_RR_start(saddr, daddr, coa, bulentry, initdelay,
15646 + maxackdelay, flags, lifetime, ops);
15650 + DEBUG(DBG_DATADUMP, "No RR necessary" );
15656 + seq = bulentry->seq + 1;
15658 + /* Add to binding update list */
15660 + if (flags & MIPV6_BU_F_ACK) {
15661 + DEBUG(DBG_INFO, "Setting bul callback to bul_resend_exp");
15662 + /* Send using exponential backoff */
15663 + state = RESEND_EXP;
15664 + callback = bul_resend_exp;
15665 + callback_time = initdelay;
15667 + DEBUG(DBG_INFO, "Setting bul callback to bul_entry_expired");
15668 + /* No acknowledgement/resending required */
15669 + state = ACK_OK; /* pretend we got an ack */
15670 + callback = bul_entry_expired;
15671 + callback_time = lifetime;
15674 + /* BU only for the home address */
15675 + /* We must hold bul_lock (write) while calling add */
15676 + if ((bulentry = mipv6_bul_add(daddr, saddr, coa, lifetime, seq,
15677 + flags, callback, callback_time,
15678 + state, initdelay, maxackdelay, ops,
15679 + NULL)) == NULL) {
15680 + DEBUG(DBG_INFO, "couldn't update BUL");
15683 + ret = send_bu_msg(bulentry);
15688 +int __init mipv6_mh_mn_init(void)
15690 + mipv6_mh_register(MIPV6_MH_HOT, mipv6_handle_mh_HC_test);
15691 + mipv6_mh_register(MIPV6_MH_COT, mipv6_handle_mh_HC_test);
15692 + mipv6_mh_register(MIPV6_MH_BA, mipv6_handle_mh_ba);
15693 + mipv6_mh_register(MIPV6_MH_BRR, mipv6_handle_mh_brr);
15694 + mipv6_mh_register(MIPV6_MH_BE, mipv6_handle_mh_be);
15699 +void __exit mipv6_mh_mn_exit(void)
15701 + mipv6_mh_unregister(MIPV6_MH_HOT);
15702 + mipv6_mh_unregister(MIPV6_MH_COT);
15703 + mipv6_mh_unregister(MIPV6_MH_BA);
15704 + mipv6_mh_unregister(MIPV6_MH_BRR);
15705 + mipv6_mh_unregister(MIPV6_MH_BE);
15707 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/module_cn.c linux-2.4.25/net/ipv6/mobile_ip6/module_cn.c
15708 --- linux-2.4.25.old/net/ipv6/mobile_ip6/module_cn.c 1970-01-01 01:00:00.000000000 +0100
15709 +++ linux-2.4.25/net/ipv6/mobile_ip6/module_cn.c 2004-06-26 11:29:31.000000000 +0100
15712 + * Mobile IPv6 Common Module
15715 + * Sami Kivisaari <skivisaa@cc.hut.fi>
15716 + * Antti Tuominen <ajtuomin@tml.hut.fi>
15720 + * This program is free software; you can redistribute it and/or
15721 + * modify it under the terms of the GNU General Public License
15722 + * as published by the Free Software Foundation; either version
15723 + * 2 of the License, or (at your option) any later version.
15726 +#include <linux/config.h>
15727 +#include <linux/module.h>
15728 +#include <linux/init.h>
15730 +#ifdef CONFIG_SYSCTL
15731 +#include <linux/sysctl.h>
15732 +#endif /* CONFIG_SYSCTL */
15734 +#include <net/mipglue.h>
15736 +#include "bcache.h"
15737 +#include "mipv6_icmp.h"
15738 +#include "stats.h"
15739 +#include "mobhdr.h"
15740 +#include "exthdrs.h"
15742 +int mipv6_debug = 1;
15744 +#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
15745 +MODULE_AUTHOR("MIPL Team");
15746 +MODULE_DESCRIPTION("Mobile IPv6");
15747 +MODULE_LICENSE("GPL");
15748 +MODULE_PARM(mipv6_debug, "i");
15751 +#include "config.h"
15753 +struct mip6_func mip6_fn;
15754 +struct mip6_conf mip6node_cnf = {
15755 + capabilities: CAP_CN,
15756 + accept_ret_rout: 1,
15757 + max_rtr_reachable_time: 0,
15758 + eager_cell_switching: 0,
15759 + max_num_tunnels: 0,
15760 + min_num_tunnels: 0,
15761 + binding_refresh_advice: 0,
15767 +#define MIPV6_BCACHE_SIZE 128
15769 +/**********************************************************************
15771 + * MIPv6 CN Module Init / Cleanup
15773 + **********************************************************************/
15775 +#ifdef CONFIG_SYSCTL
15776 +/* Sysctl table */
15777 +ctl_table mipv6_mobility_table[] = {
15778 + {NET_IPV6_MOBILITY_DEBUG, "debuglevel",
15779 + &mipv6_debug, sizeof(int), 0644, NULL,
15781 + {NET_IPV6_MOBILITY_RETROUT, "accept_return_routability",
15782 + &mip6node_cnf.accept_ret_rout, sizeof(int), 0644, NULL,
15786 +ctl_table mipv6_table[] = {
15787 + {NET_IPV6_MOBILITY, "mobility", NULL, 0, 0555, mipv6_mobility_table},
15791 +static struct ctl_table_header *mipv6_sysctl_header;
15792 +static struct ctl_table mipv6_net_table[];
15793 +static struct ctl_table mipv6_root_table[];
15795 +ctl_table mipv6_net_table[] = {
15796 + {NET_IPV6, "ipv6", NULL, 0, 0555, mipv6_table},
15800 +ctl_table mipv6_root_table[] = {
15801 + {CTL_NET, "net", NULL, 0, 0555, mipv6_net_table},
15804 +#endif /* CONFIG_SYSCTL */
15806 +extern void mipv6_rr_init(void);
15808 +/* Initialize the module */
15809 +static int __init mip6_init(void)
15813 + printk(KERN_INFO "MIPL Mobile IPv6 for Linux Correspondent Node %s (%s)\n",
15814 + MIPLVERSION, MIPV6VERSION);
15816 +#ifdef CONFIG_IPV6_MOBILITY_DEBUG
15817 + printk(KERN_INFO "Debug-level: %d\n", mipv6_debug);
15820 + if ((err = mipv6_bcache_init(MIPV6_BCACHE_SIZE)) < 0)
15821 + goto bcache_fail;
15823 + if ((err = mipv6_icmpv6_init()) < 0)
15826 + if ((err = mipv6_stats_init()) < 0)
15830 +#ifdef CONFIG_SYSCTL
15831 + mipv6_sysctl_header = register_sysctl_table(mipv6_root_table, 0);
15834 + if ((err = mipv6_mh_common_init()) < 0)
15837 + MIPV6_SETCALL(mipv6_modify_txoptions, mipv6_modify_txoptions);
15839 + MIPV6_SETCALL(mipv6_handle_homeaddr, mipv6_handle_homeaddr);
15840 + MIPV6_SETCALL(mipv6_icmp_swap_addrs, mipv6_icmp_swap_addrs);
15845 +#ifdef CONFIG_SYSCTL
15846 + unregister_sysctl_table(mipv6_sysctl_header);
15848 + mipv6_stats_exit();
15850 + mipv6_icmpv6_exit();
15852 + mipv6_bcache_exit();
15856 +module_init(mip6_init);
15859 +/* Cleanup module */
15860 +static void __exit mip6_exit(void)
15862 + printk(KERN_INFO "mip6_base.o exiting.\n");
15863 +#ifdef CONFIG_SYSCTL
15864 + unregister_sysctl_table(mipv6_sysctl_header);
15867 + /* Invalidate all custom kernel hooks. No need to do this
15868 + separately for all hooks. */
15869 + mipv6_invalidate_calls();
15871 + mipv6_mh_common_exit();
15872 + mipv6_stats_exit();
15873 + mipv6_icmpv6_exit();
15874 + mipv6_bcache_exit();
15876 +module_exit(mip6_exit);
15877 +#endif /* MODULE */
15878 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/module_ha.c linux-2.4.25/net/ipv6/mobile_ip6/module_ha.c
15879 --- linux-2.4.25.old/net/ipv6/mobile_ip6/module_ha.c 1970-01-01 01:00:00.000000000 +0100
15880 +++ linux-2.4.25/net/ipv6/mobile_ip6/module_ha.c 2004-06-26 11:29:31.000000000 +0100
15883 + * Mobile IPv6 Home Agent Module
15886 + * Sami Kivisaari <skivisaa@cc.hut.fi>
15887 + * Antti Tuominen <ajtuomin@tml.hut.fi>
15891 + * This program is free software; you can redistribute it and/or
15892 + * modify it under the terms of the GNU General Public License
15893 + * as published by the Free Software Foundation; either version
15894 + * 2 of the License, or (at your option) any later version.
15897 +#include <linux/config.h>
15898 +#include <linux/module.h>
15899 +#include <linux/init.h>
15901 +#ifdef CONFIG_SYSCTL
15902 +#include <linux/sysctl.h>
15903 +#endif /* CONFIG_SYSCTL */
15905 +#include <net/mipglue.h>
15906 +#include <net/addrconf.h>
15908 +#include "mobhdr.h"
15909 +#include "tunnel_ha.h"
15911 +#include "halist.h"
15912 +#include "mipv6_icmp.h"
15913 +//#include "prefix.h"
15914 +#include "bcache.h"
15915 +#include "debug.h"
15917 +int mipv6_use_auth = 0;
15919 +#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
15920 +MODULE_AUTHOR("MIPL Team");
15921 +MODULE_DESCRIPTION("Mobile IPv6 Home Agent");
15922 +MODULE_LICENSE("GPL");
15925 +#include "config.h"
15927 +#define MIPV6_HALIST_SIZE 128
15928 +struct ha_info_opt {
15936 + * Called from ndisc.c's router_discovery.
15938 +static int mipv6_ha_ra_rcv(struct sk_buff *skb, struct ndisc_options *ndopts)
15940 + unsigned int ha_info_pref = 0, ha_info_lifetime;
15941 + int ifi = ((struct inet6_skb_parm *)skb->cb)->iif;
15942 + struct ra_msg *ra = (struct ra_msg *) skb->h.raw;
15943 + struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
15944 + struct in6_addr ll_addr;
15946 + struct in6_addr prefix;
15948 + struct hal *next;
15953 + ha_info_lifetime = ntohs(ra->icmph.icmp6_rt_lifetime);
15954 + ipv6_addr_copy(&ll_addr, saddr);
15956 + if (ndopts->nd_opts_hai) {
15957 + struct ha_info_opt *hai = (struct ha_info_opt *)ndopts->nd_opts_hai;
15958 + ha_info_pref = ntohs(hai->pref);
15959 + ha_info_lifetime = ntohs(hai->ltime);
15960 + DEBUG(DBG_DATADUMP,
15961 + "received home agent info with preference : %d and lifetime : %d",
15962 + ha_info_pref, ha_info_lifetime);
15964 + if (ndopts->nd_opts_pi) {
15965 + struct nd_opt_hdr *p;
15966 + for (p = ndopts->nd_opts_pi;
15968 + p = ndisc_next_option(p, ndopts->nd_opts_pi_end)) {
15969 + struct prefix_info *pinfo;
15971 + pinfo = (struct prefix_info *) p;
15973 + if (pinfo->router_address) {
15974 + DEBUG(DBG_DATADUMP, "Adding router address to "
15976 + /* If RA has H bit set and Prefix Info
15977 + * Option R bit set, queue this
15978 + * address to be added to Home Agents
15981 + if (ipv6_addr_type(&pinfo->prefix) &
15982 + IPV6_ADDR_LINKLOCAL)
15984 + if (!ra->icmph.icmp6_home_agent || !ha_info_lifetime) {
15985 + mipv6_halist_delete(&pinfo->prefix);
15989 + mipv6_halist_add(ifi, &pinfo->prefix,
15990 + pinfo->prefix_len, &ll_addr,
15991 + ha_info_pref, ha_info_lifetime);
15998 + return MIPV6_ADD_RTR;
16001 +/**********************************************************************
16003 + * MIPv6 Module Init / Cleanup
16005 + **********************************************************************/
16007 +#ifdef CONFIG_SYSCTL
16008 +/* Sysctl table */
16010 +mipv6_max_tnls_sysctl(ctl_table *, int, struct file *, void *, size_t *);
16013 +mipv6_min_tnls_sysctl(ctl_table *, int, struct file *, void *, size_t *);
16015 +int max_adv = ~(u16)0;
16017 +ctl_table mipv6_mobility_table[] = {
16018 + {NET_IPV6_MOBILITY_BINDING_REFRESH, "binding_refresh_advice",
16019 + &mip6node_cnf.binding_refresh_advice, sizeof(int), 0644, NULL,
16020 + &proc_dointvec_minmax, &sysctl_intvec, 0, &min_zero, &max_adv},
16022 + {NET_IPV6_MOBILITY_MAX_TNLS, "max_tnls", &mipv6_max_tnls, sizeof(int),
16023 + 0644, NULL, &mipv6_max_tnls_sysctl},
16024 + {NET_IPV6_MOBILITY_MIN_TNLS, "min_tnls", &mipv6_min_tnls, sizeof(int),
16025 + 0644, NULL, &mipv6_min_tnls_sysctl},
16028 +ctl_table mipv6_table[] = {
16029 + {NET_IPV6_MOBILITY, "mobility", NULL, 0, 0555, mipv6_mobility_table},
16033 +static struct ctl_table_header *mipv6_sysctl_header;
16034 +static struct ctl_table mipv6_net_table[];
16035 +static struct ctl_table mipv6_root_table[];
16037 +ctl_table mipv6_net_table[] = {
16038 + {NET_IPV6, "ipv6", NULL, 0, 0555, mipv6_table},
16042 +ctl_table mipv6_root_table[] = {
16043 + {CTL_NET, "net", NULL, 0, 0555, mipv6_net_table},
16046 +#endif /* CONFIG_SYSCTL */
16048 +extern void mipv6_check_dad(struct in6_addr *haddr);
16049 +extern void mipv6_dad_init(void);
16050 +extern void mipv6_dad_exit(void);
16051 +extern int mipv6_forward(struct sk_buff *);
16053 +/* Initialize the module */
16054 +static int __init mip6_ha_init(void)
16058 + printk(KERN_INFO "MIPL Mobile IPv6 for Linux Home Agent %s (%s)\n",
16059 + MIPLVERSION, MIPV6VERSION);
16060 + mip6node_cnf.capabilities = CAP_CN | CAP_HA;
16062 + mip6_fn.icmpv6_dhaad_rep_rcv = mipv6_icmpv6_no_rcv;
16063 + mip6_fn.icmpv6_dhaad_req_rcv = mipv6_icmpv6_rcv_dhaad_req;
16064 + mip6_fn.icmpv6_pfxadv_rcv = mipv6_icmpv6_no_rcv;
16065 + mip6_fn.icmpv6_pfxsol_rcv = mipv6_icmpv6_no_rcv;
16066 + mip6_fn.icmpv6_paramprob_rcv = mipv6_icmpv6_no_rcv;
16068 +#ifdef CONFIG_IPV6_MOBILITY_DEBUG
16069 + printk(KERN_INFO "Debug-level: %d\n", mipv6_debug);
16072 +#ifdef CONFIG_SYSCTL
16073 + mipv6_sysctl_header = register_sysctl_table(mipv6_root_table, 0);
16075 + mipv6_initialize_tunnel();
16077 + if ((err = mipv6_ha_init()) < 0)
16080 + MIPV6_SETCALL(mipv6_ra_rcv, mipv6_ha_ra_rcv);
16081 + MIPV6_SETCALL(mipv6_forward, mipv6_forward);
16082 + mipv6_dad_init();
16083 + MIPV6_SETCALL(mipv6_check_dad, mipv6_check_dad);
16085 + if ((err = mipv6_halist_init(MIPV6_HALIST_SIZE)) < 0)
16086 + goto halist_fail;
16088 +// mipv6_initialize_pfx_icmpv6();
16093 + mipv6_dad_exit();
16096 + mipv6_shutdown_tunnel();
16098 + mip6_fn.icmpv6_dhaad_rep_rcv = NULL;
16099 + mip6_fn.icmpv6_dhaad_req_rcv = NULL;
16100 + mip6_fn.icmpv6_pfxadv_rcv = NULL;
16101 + mip6_fn.icmpv6_pfxsol_rcv = NULL;
16102 + mip6_fn.icmpv6_paramprob_rcv = NULL;
16104 + MIPV6_RESETCALL(mipv6_ra_rcv);
16105 + MIPV6_RESETCALL(mipv6_forward);
16106 + MIPV6_RESETCALL(mipv6_check_dad);
16108 +#ifdef CONFIG_SYSCTL
16109 + unregister_sysctl_table(mipv6_sysctl_header);
16113 +module_init(mip6_ha_init);
16116 +/* Cleanup module */
16117 +static void __exit mip6_ha_exit(void)
16119 + printk(KERN_INFO "mip6_ha.o exiting.\n");
16120 + mip6node_cnf.capabilities &= ~(int)CAP_HA;
16122 + mipv6_bcache_cleanup(HOME_REGISTRATION);
16124 + MIPV6_RESETCALL(mipv6_ra_rcv);
16125 + MIPV6_RESETCALL(mipv6_forward);
16126 + MIPV6_RESETCALL(mipv6_check_dad);
16128 + mipv6_halist_exit();
16129 +// mipv6_shutdown_pfx_icmpv6();
16131 + mip6_fn.icmpv6_dhaad_rep_rcv = NULL;
16132 + mip6_fn.icmpv6_dhaad_req_rcv = NULL;
16133 + mip6_fn.icmpv6_pfxadv_rcv = NULL;
16134 + mip6_fn.icmpv6_pfxsol_rcv = NULL;
16135 + mip6_fn.icmpv6_paramprob_rcv = NULL;
16137 + mipv6_dad_exit();
16139 + mipv6_shutdown_tunnel();
16140 +#ifdef CONFIG_SYSCTL
16141 + unregister_sysctl_table(mipv6_sysctl_header);
16144 +module_exit(mip6_ha_exit);
16145 +#endif /* MODULE */
16146 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/module_mn.c linux-2.4.25/net/ipv6/mobile_ip6/module_mn.c
16147 --- linux-2.4.25.old/net/ipv6/mobile_ip6/module_mn.c 1970-01-01 01:00:00.000000000 +0100
16148 +++ linux-2.4.25/net/ipv6/mobile_ip6/module_mn.c 2004-06-26 11:29:31.000000000 +0100
16151 + * Mobile IPv6 Mobile Node Module
16154 + * Sami Kivisaari <skivisaa@cc.hut.fi>
16155 + * Antti Tuominen <ajtuomin@tml.hut.fi>
16159 + * This program is free software; you can redistribute it and/or
16160 + * modify it under the terms of the GNU General Public License
16161 + * as published by the Free Software Foundation; either version
16162 + * 2 of the License, or (at your option) any later version.
16165 +#include <linux/config.h>
16166 +#include <linux/module.h>
16167 +#include <linux/init.h>
16169 +#ifdef CONFIG_SYSCTL
16170 +#include <linux/sysctl.h>
16171 +#endif /* CONFIG_SYSCTL */
16173 +#include <net/mipglue.h>
16175 +extern int mipv6_debug;
16176 +int mipv6_use_auth = 0;
16178 +#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
16179 +MODULE_AUTHOR("MIPL Team");
16180 +MODULE_DESCRIPTION("Mobile IPv6 Mobile Node");
16181 +MODULE_LICENSE("GPL");
16182 +MODULE_PARM(mipv6_debug, "i");
16185 +#include "config.h"
16187 +#include "mobhdr.h"
16189 +#include "mipv6_icmp.h"
16190 +//#include "prefix.h"
16192 +/* TODO: These will go as soon as we get rid of the last two ioctls */
16193 +extern int mipv6_ioctl_mn_init(void);
16194 +extern void mipv6_ioctl_mn_exit(void);
16196 +/**********************************************************************
16198 + * MIPv6 Module Init / Cleanup
16200 + **********************************************************************/
16202 +#ifdef CONFIG_SYSCTL
16203 +/* Sysctl table */
16205 +extern int max_rtr_reach_time;
16206 +extern int eager_cell_switching;
16208 +static int max_reach = 1000;
16209 +static int min_reach = 1;
16210 +static int max_one = 1;
16211 +static int min_zero = 0;
16214 +mipv6_mdetect_mech_sysctl(ctl_table *, int, struct file *, void *, size_t *);
16217 +mipv6_router_reach_sysctl(ctl_table *, int, struct file *, void *, size_t *);
16219 +ctl_table mipv6_mobility_table[] = {
16220 + {NET_IPV6_MOBILITY_BU_F_LLADDR, "bu_flag_lladdr",
16221 + &mip6node_cnf.bu_lladdr, sizeof(int), 0644, NULL,
16222 + &proc_dointvec_minmax, &sysctl_intvec, 0, &min_zero, &max_one},
16223 + {NET_IPV6_MOBILITY_BU_F_KEYMGM, "bu_flag_keymgm",
16224 + &mip6node_cnf.bu_keymgm, sizeof(int), 0644, NULL,
16225 + &proc_dointvec_minmax, &sysctl_intvec, 0, &min_zero, &max_one},
16226 + {NET_IPV6_MOBILITY_BU_F_CN_ACK, "bu_flag_cn_ack",
16227 + &mip6node_cnf.bu_cn_ack, sizeof(int), 0644, NULL,
16228 + &proc_dointvec_minmax, &sysctl_intvec, 0, &min_zero, &max_one},
16230 + {NET_IPV6_MOBILITY_ROUTER_REACH, "max_router_reachable_time",
16231 + &max_rtr_reach_time, sizeof(int), 0644, NULL,
16232 + &proc_dointvec_minmax, &sysctl_intvec, 0, &min_reach, &max_reach},
16234 + {NET_IPV6_MOBILITY_MDETECT_MECHANISM, "eager_cell_switching",
16235 + &eager_cell_switching, sizeof(int), 0644, NULL,
16236 + &proc_dointvec_minmax, &sysctl_intvec, 0, &min_zero, &max_one},
16240 +ctl_table mipv6_table[] = {
16241 + {NET_IPV6_MOBILITY, "mobility", NULL, 0, 0555, mipv6_mobility_table},
16245 +static struct ctl_table_header *mipv6_sysctl_header;
16246 +static struct ctl_table mipv6_net_table[];
16247 +static struct ctl_table mipv6_root_table[];
16249 +ctl_table mipv6_net_table[] = {
16250 + {NET_IPV6, "ipv6", NULL, 0, 0555, mipv6_table},
16254 +ctl_table mipv6_root_table[] = {
16255 + {CTL_NET, "net", NULL, 0, 0555, mipv6_net_table},
16258 +#endif /* CONFIG_SYSCTL */
16260 +/* Initialize the module */
16261 +static int __init mip6_mn_init(void)
16265 + printk(KERN_INFO "MIPL Mobile IPv6 for Linux Mobile Node %s (%s)\n",
16266 + MIPLVERSION, MIPV6VERSION);
16267 + mip6node_cnf.capabilities = CAP_CN | CAP_MN;
16269 +#ifdef CONFIG_IPV6_MOBILITY_DEBUG
16270 + printk(KERN_INFO "Debug-level: %d\n", mipv6_debug);
16273 +#ifdef CONFIG_SYSCTL
16274 + mipv6_sysctl_header = register_sysctl_table(mipv6_root_table, 0);
16276 + if ((err = mipv6_mn_init()) < 0)
16279 + mipv6_mh_mn_init();
16281 + mip6_fn.icmpv6_dhaad_rep_rcv = mipv6_icmpv6_rcv_dhaad_rep;
16282 + mip6_fn.icmpv6_dhaad_req_rcv = mipv6_icmpv6_no_rcv;
16283 + mip6_fn.icmpv6_pfxadv_rcv = mipv6_icmpv6_no_rcv;
16284 + mip6_fn.icmpv6_pfxsol_rcv = mipv6_icmpv6_no_rcv;
16285 + mip6_fn.icmpv6_paramprob_rcv = mipv6_icmpv6_rcv_paramprob;
16287 +// mipv6_initialize_pfx_icmpv6();
16289 + if ((err = mipv6_ioctl_mn_init()) < 0)
16295 +// mipv6_shutdown_pfx_icmpv6();
16297 + mip6_fn.icmpv6_dhaad_rep_rcv = NULL;
16298 + mip6_fn.icmpv6_dhaad_req_rcv = NULL;
16299 + mip6_fn.icmpv6_pfxadv_rcv = NULL;
16300 + mip6_fn.icmpv6_pfxsol_rcv = NULL;
16301 + mip6_fn.icmpv6_paramprob_rcv = NULL;
16303 + mipv6_mh_mn_exit();
16306 +#ifdef CONFIG_SYSCTL
16307 + unregister_sysctl_table(mipv6_sysctl_header);
16311 +module_init(mip6_mn_init);
16314 +/* Cleanup module */
16315 +static void __exit mip6_mn_exit(void)
16317 + printk(KERN_INFO "mip6_mn.o exiting.\n");
16318 + mip6node_cnf.capabilities &= ~(int)CAP_MN;
16320 + mipv6_ioctl_mn_exit();
16321 +// mipv6_shutdown_pfx_icmpv6();
16323 + mip6_fn.icmpv6_dhaad_rep_rcv = NULL;
16324 + mip6_fn.icmpv6_dhaad_req_rcv = NULL;
16325 + mip6_fn.icmpv6_pfxadv_rcv = NULL;
16326 + mip6_fn.icmpv6_pfxsol_rcv = NULL;
16327 + mip6_fn.icmpv6_paramprob_rcv = NULL;
16331 +/* common cleanup */
16332 +#ifdef CONFIG_SYSCTL
16333 + unregister_sysctl_table(mipv6_sysctl_header);
16336 +module_exit(mip6_mn_exit);
16337 +#endif /* MODULE */
16338 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/multiaccess_ctl.c linux-2.4.25/net/ipv6/mobile_ip6/multiaccess_ctl.c
16339 --- linux-2.4.25.old/net/ipv6/mobile_ip6/multiaccess_ctl.c 1970-01-01 01:00:00.000000000 +0100
16340 +++ linux-2.4.25/net/ipv6/mobile_ip6/multiaccess_ctl.c 2004-06-26 11:29:31.000000000 +0100
16343 + * 2001 (c) Oy L M Ericsson Ab
16345 + * Author: NomadicLab / Ericsson Research <ipv6@nomadiclab.com>
16352 + * Vertical hand-off information manager
16355 +#include <linux/netdevice.h>
16356 +#include <linux/in6.h>
16357 +#include <linux/module.h>
16358 +#include <linux/init.h>
16359 +#include <linux/proc_fs.h>
16360 +#include <linux/string.h>
16361 +#include <linux/kernel.h>
16362 +#include <asm/io.h>
16363 +#include <asm/uaccess.h>
16364 +#include <linux/list.h>
16365 +#include "multiaccess_ctl.h"
16366 +#include "debug.h"
16369 + * Local variables
16371 +static LIST_HEAD(if_list);
16373 +/* Internal interface information list */
16374 +struct ma_if_info {
16375 + struct list_head list;
16376 + int interface_id;
16382 + * ma_ctl_get_preference - get preference value for interface
16383 + * @ifi: interface index
16385 + * Returns integer value preference for given interface.
16387 +int ma_ctl_get_preference(int ifi)
16389 + struct list_head *lh;
16390 + struct ma_if_info *info;
16393 + list_for_each(lh, &if_list) {
16394 + info = list_entry(lh, struct ma_if_info, list);
16395 + if (info->interface_id == ifi) {
16396 + pref = info->preference;
16403 + * ma_ctl_get_preference - get preference value for interface
16404 + * @ifi: interface index
16406 + * Returns integer value interface index for interface with highest preference.
16408 +int ma_ctl_get_preferred_if(void)
16410 + struct list_head *lh;
16411 + struct ma_if_info *info, *pref_if = NULL;
16413 + list_for_each(lh, &if_list) {
16414 + info = list_entry(lh, struct ma_if_info, list);
16415 + if (!pref_if || (info->preference > pref_if->preference)) {
16419 + if (pref_if) return pref_if->interface_id;
16423 + * ma_ctl_set_preference - set preference for interface
16424 + * @arg: ioctl args
16426 + * Sets preference of an existing interface (called by ioctl).
16428 +void ma_ctl_set_preference(unsigned long arg)
16430 + struct list_head *lh;
16431 + struct ma_if_info *info;
16432 + struct ma_if_uinfo uinfo;
16434 + memset(&uinfo, 0, sizeof(struct ma_if_uinfo));
16435 + if (copy_from_user(&uinfo, (struct ma_if_uinfo *)arg,
16436 + sizeof(struct ma_if_uinfo)) < 0) {
16437 + DEBUG(DBG_WARNING, "copy_from_user failed");
16441 + /* check if the interface exists */
16442 + list_for_each(lh, &if_list) {
16443 + info = list_entry(lh, struct ma_if_info, list);
16444 + if (info->interface_id == uinfo.interface_id) {
16445 + info->preference = uinfo.preference;
16452 + * ma_ctl_add_iface - add new interface to list
16453 + * @if_index: interface index
16455 + * Adds new interface entry to preference list. Preference is set to
16456 + * the same value as @if_index. Entry @status is set to
16457 + * %MA_IFACE_NOT_USED.
16459 +void ma_ctl_add_iface(int if_index)
16461 + struct list_head *lh;
16462 + struct ma_if_info *info;
16466 + /* check if the interface already exists */
16467 + list_for_each(lh, &if_list) {
16468 + info = list_entry(lh, struct ma_if_info, list);
16469 + if (info->interface_id == if_index) {
16470 + info->status = MA_IFACE_NOT_USED;
16471 + info->preference = if_index;
16476 + info = kmalloc(sizeof(struct ma_if_info), GFP_ATOMIC);
16477 + if (info == NULL) {
16478 + DEBUG(DBG_ERROR, "Out of memory");
16481 + memset(info, 0, sizeof(struct ma_if_info));
16482 + info->interface_id = if_index;
16483 + info->preference = if_index;
16484 + info->status = MA_IFACE_NOT_USED;
16485 + list_add(&info->list, &if_list);
16489 + * ma_ctl_del_iface - remove entry from the list
16490 + * @if_index: interface index
16492 + * Removes entry for interface @if_index from preference list.
16494 +int ma_ctl_del_iface(int if_index)
16496 + struct list_head *lh, *next;
16497 + struct ma_if_info *info;
16501 + /* if the iface exists, change availability to 0 */
16502 + list_for_each_safe(lh, next, &if_list) {
16503 + info = list_entry(lh, struct ma_if_info, list);
16504 + if (info->interface_id == if_index) {
16505 + list_del(&info->list);
16515 + * ma_ctl_upd_iface - update entry (and list)
16516 + * @if_index: interface to update
16517 + * @status: new status for interface
16518 + * @change_if_index: new interface
16520 + * Updates @if_index entry on preference list. Entry status is set to
16521 + * @status. If new @status is %MA_IFACE_CURRENT, updates list to have
16522 + * only one current device. If @status is %MA_IFACE_NOT_PRESENT,
16523 + * entry is deleted and further if entry had %MA_IFACE_CURRENT set,
16524 + * new current device is looked up and returned in @change_if_index.
16525 + * New preferred interface is also returned if current device changes
16526 + * to %MA_IFACE_NOT_USED. Returns 0 on success, otherwise negative.
16528 +int ma_ctl_upd_iface(int if_index, int status, int *change_if_index)
16530 + struct list_head *lh, *tmp;
16531 + struct ma_if_info *info, *pref = NULL;
16536 + *change_if_index = 0;
16538 + /* check if the interface exists */
16539 + list_for_each_safe(lh, tmp, &if_list) {
16540 + info = list_entry(lh, struct ma_if_info, list);
16541 + if (status == MA_IFACE_NOT_PRESENT) {
16542 + if (info->interface_id == if_index) {
16543 + list_del_init(&info->list);
16548 + } else if (status == MA_IFACE_CURRENT) {
16549 + if (info->interface_id == if_index) {
16550 + info->status |= MA_IFACE_CURRENT;
16553 + info->status |= MA_IFACE_NOT_USED;
16555 + } else if (status == MA_IFACE_NOT_USED) {
16556 + if (info->interface_id == if_index) {
16557 + if (info->status | MA_IFACE_CURRENT) {
16560 + info->status &= !MA_IFACE_CURRENT;
16561 + info->status |= MA_IFACE_NOT_USED;
16562 + info->status &= !MA_IFACE_HAS_ROUTER;
16565 + } else if (status == MA_IFACE_HAS_ROUTER) {
16566 + if (info->interface_id == if_index) {
16567 + info->status |= MA_IFACE_HAS_ROUTER;
16573 + if (status & (MA_IFACE_NOT_USED|MA_IFACE_NOT_PRESENT) && found) {
16574 + /* select new interface */
16575 + list_for_each(lh, &if_list) {
16576 + info = list_entry(lh, struct ma_if_info, list);
16577 + if (pref == NULL || ((info->preference > pref->preference) &&
16578 + info->status & MA_IFACE_HAS_ROUTER))
16582 + *change_if_index = pref->interface_id;
16583 + pref->status |= MA_IFACE_CURRENT;
16585 + *change_if_index = -1;
16590 + if (found) return 0;
16595 +static int if_proc_info(char *buffer, char **start, off_t offset,
16598 + struct list_head *lh;
16599 + struct ma_if_info *info;
16602 + list_for_each(lh, &if_list) {
16603 + info = list_entry(lh, struct ma_if_info, list);
16604 + len += sprintf(buffer + len, "%02d %010d %1d %1d\n",
16605 + info->interface_id, info->preference,
16606 + !!(info->status & MA_IFACE_HAS_ROUTER),
16607 + !!(info->status & MA_IFACE_CURRENT));
16610 + *start = buffer + offset;
16614 + if (len > length) len = length;
16620 +void ma_ctl_init(void)
16622 + proc_net_create("mip6_iface", 0, if_proc_info);
16625 +void ma_ctl_clean(void)
16627 + proc_net_remove("mip6_iface");
16629 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/multiaccess_ctl.h linux-2.4.25/net/ipv6/mobile_ip6/multiaccess_ctl.h
16630 --- linux-2.4.25.old/net/ipv6/mobile_ip6/multiaccess_ctl.h 1970-01-01 01:00:00.000000000 +0100
16631 +++ linux-2.4.25/net/ipv6/mobile_ip6/multiaccess_ctl.h 2004-06-26 11:29:31.000000000 +0100
16634 + * 2001 (c) Oy L M Ericsson Ab
16636 + * Author: NomadicLab / Ericsson Research <ipv6@nomadiclab.com>
16642 +#ifndef _MULTIACCESS_CTL_H
16643 +#define _MULTIACCESS_CTL_H
16646 +#define MA_IFACE_NOT_PRESENT 0x01
16647 +#define MA_IFACE_NOT_USED 0x02
16648 +#define MA_IFACE_HAS_ROUTER 0x04
16649 +#define MA_IFACE_CURRENT 0x10
16651 +struct ma_if_uinfo {
16652 + int interface_id;
16657 + * @ma_ctl_get_preferred_id: returns most preferred interface id
16659 +int ma_ctl_get_preferred_if(void);
16661 +/* @ma_ctl_get_preference: returns preference for an interface
16662 + * @name: name of the interface (dev->name)
16664 +int ma_ctl_get_preference(int ifi);
16667 + * Public function: ma_ctl_set_preference
16668 + * Description: Set preference of an existing interface (called by ioctl)
16671 +void ma_ctl_set_preference(unsigned long);
16674 + * Public function: ma_ctl_add_iface
16675 + * Description: Inform control module to insert a new interface
16676 + * Returns: 0 if success, any other number means an error
16678 +void ma_ctl_add_iface(int);
16681 + * Public function: ma_ctl_del_iface
16682 + * Description: Inform control module to remove an obsolete interface
16683 + * Returns: 0 if success, any other number means an error
16685 +int ma_ctl_del_iface(int);
16688 + * Public function: ma_ctl_upd_iface
16689 + * Description: Inform control module of status change.
16690 + * Returns: 0 if success, any other number means an error
16692 +int ma_ctl_upd_iface(int, int, int *);
16695 + * Public function: ma_ctl_init
16696 + * Description: XXX
16699 +void ma_ctl_init(void);
16702 + * Public function: ma_ctl_clean
16703 + * Description: XXX
16706 +void ma_ctl_clean(void);
16710 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/ndisc_ha.c linux-2.4.25/net/ipv6/mobile_ip6/ndisc_ha.c
16711 --- linux-2.4.25.old/net/ipv6/mobile_ip6/ndisc_ha.c 1970-01-01 01:00:00.000000000 +0100
16712 +++ linux-2.4.25/net/ipv6/mobile_ip6/ndisc_ha.c 2004-06-26 11:29:31.000000000 +0100
16715 + * Mobile IPv6 Duplicate Address Detection Functions
16718 + * Krishna Kumar <krkumar@us.ibm.com>
16722 + * This program is free software; you can redistribute it and/or
16723 + * modify it under the terms of the GNU General Public License
16724 + * as published by the Free Software Foundation; either version
16725 + * 2 of the License, or (at your option) any later version.
16729 +#include <linux/autoconf.h>
16730 +#include <linux/types.h>
16731 +#include <linux/init.h>
16732 +#include <linux/skbuff.h>
16733 +#include <linux/in6.h>
16734 +#include <net/ipv6.h>
16735 +#include <net/addrconf.h>
16736 +#include <net/mipv6.h>
16738 +#include "debug.h"
16739 +#include "bcache.h"
16740 +#include "ha.h" /* mipv6_generate_ll_addr */
16743 + * Binding Updates from MN are cached in this structure till DAD is performed.
16744 + * This structure is used to retrieve a pending Binding Update for the HA to
16745 + * reply to after performing DAD. The first cell is different from the rest as
16747 + * 1. The first cell is used to chain the remaining cells.
16748 + * 2. The timeout of the first cell is used to delete expired entries
16749 + * in the list of cells, while the timeout of the other cells are
16750 + * used for timing out a NS request so as to reply to a BU.
16751 + * 3. The only elements of the first cell that are used are :
16752 + * next, prev, and callback_timer.
16754 + * TODO : Don't we need to do pneigh_lookup on the Link Local address ?
16756 +struct mipv6_dad_cell {
16757 + /* Information needed for DAD management */
16758 + struct mipv6_dad_cell *next; /* Next element on the DAD list */
16759 + struct mipv6_dad_cell *prev; /* Prev element on the DAD list */
16760 + __u16 probes; /* Number of times to probe for addr */
16761 + __u16 flags; /* Entry flags - see below */
16762 + struct timer_list callback_timer; /* timeout for entry */
16764 + /* Information needed for performing DAD */
16765 + struct inet6_ifaddr *ifp;
16767 + struct in6_addr daddr;
16768 + struct in6_addr haddr; /* home address */
16769 + struct in6_addr ll_haddr; /* Link Local value of haddr */
16770 + struct in6_addr coa;
16771 + struct in6_addr rep_coa;
16772 + __u32 ba_lifetime;
16777 +/* Values for the 'flags' field in the mipv6_dad_cell */
16778 +#define DAD_INIT_ENTRY 0
16779 +#define DAD_DUPLICATE_ADDRESS 1
16780 +#define DAD_UNIQUE_ADDRESS 2
16782 +/* Head of the pending DAD list */
16783 +static struct mipv6_dad_cell dad_cell_head;
16785 +/* Lock to access the pending DAD list */
16786 +static rwlock_t dad_lock = RW_LOCK_UNLOCKED;
16788 +/* Timer routine which deletes 'expired' entries in the DAD list */
16789 +static void mipv6_dad_delete_old_entries(unsigned long unused)
16791 + struct mipv6_dad_cell *curr, *next;
16792 + unsigned long next_time = 0;
16794 + write_lock(&dad_lock);
16795 + curr = dad_cell_head.next;
16796 + while (curr != &dad_cell_head) {
16797 + next = curr->next;
16798 + if (curr->flags != DAD_INIT_ENTRY) {
16799 + if (curr->callback_timer.expires <= jiffies) {
16800 + /* Entry has expired, free it up. */
16801 + curr->next->prev = curr->prev;
16802 + curr->prev->next = curr->next;
16803 + in6_ifa_put(curr->ifp);
16805 + } else if (next_time <
16806 + curr->callback_timer.expires) {
16807 + next_time = curr->callback_timer.expires;
16812 + write_unlock(&dad_lock);
16815 + * Start another timer if more cells need to be removed at
16818 + dad_cell_head.callback_timer.expires = next_time;
16819 + add_timer(&dad_cell_head.callback_timer);
16824 + * Queue a timeout routine to clean up 'expired' DAD entries.
16826 +static void mipv6_start_dad_head_timer(struct mipv6_dad_cell *cell)
16828 + unsigned long expire = jiffies +
16829 + cell->ifp->idev->nd_parms->retrans_time * 10;
16831 + if (!timer_pending(&dad_cell_head.callback_timer) ||
16832 + expire < dad_cell_head.callback_timer.expires) {
16834 + * Add timer if none pending, or mod the timer if new
16835 + * cell needs to be expired before existing timer runs.
16837 + * We let the cell remain as long as possible, so that
16838 + * new BU's as part of retransmissions don't have to go
16839 + * through DAD before replying.
16841 + dad_cell_head.callback_timer.expires = expire;
16844 + * Keep the cell around for atleast some time to handle
16845 + * retransmissions or BU's due to fast MN movement. This
16846 + * is needed otherwise a previous timeout can delete all
16847 + * expired entries including this new one.
16849 + cell->callback_timer.expires = jiffies +
16850 + cell->ifp->idev->nd_parms->retrans_time * 5;
16851 + if (!timer_pending(&dad_cell_head.callback_timer)) {
16852 + add_timer(&dad_cell_head.callback_timer);
16854 + mod_timer(&dad_cell_head.callback_timer, expire);
16860 +/* Join solicited node MC address */
16861 +static inline void mipv6_join_sol_mc_addr(struct in6_addr *addr,
16862 + struct net_device *dev)
16864 + struct in6_addr maddr;
16866 + /* Join solicited node MC address */
16867 + addrconf_addr_solict_mult(addr, &maddr);
16868 + ipv6_dev_mc_inc(dev, &maddr);
16871 +/* Leave solicited node MC address */
16872 +static inline void mipv6_leave_sol_mc_addr(struct in6_addr *addr,
16873 + struct net_device *dev)
16875 + struct in6_addr maddr;
16877 + addrconf_addr_solict_mult(addr, &maddr);
16878 + ipv6_dev_mc_dec(dev, &maddr);
16882 +static inline void mipv6_dad_send_ns(struct inet6_ifaddr *ifp,
16883 + struct in6_addr *haddr)
16885 + struct in6_addr unspec;
16886 + struct in6_addr mcaddr;
16888 + ipv6_addr_set(&unspec, 0, 0, 0, 0);
16889 + addrconf_addr_solict_mult(haddr, &mcaddr);
16891 + /* addr is 'unspec' since we treat this address as transient */
16892 + ndisc_send_ns(ifp->idev->dev, NULL, haddr, &mcaddr, &unspec);
16896 + * Search for a home address in the list of pending DAD's. Called from
16897 + * Neighbor Advertisement
16898 + * Return values :
16899 + * -1 : No DAD entry found for this advertisement, or entry already
16900 + * finished processing.
16901 + * 0 : Entry found waiting for DAD to finish.
16903 +static int dad_search_haddr(struct in6_addr *ll_haddr,
16904 + struct in6_addr *daddr, struct in6_addr *haddr,
16905 + struct in6_addr *coa, struct in6_addr *rep_coa,
16906 + __u16 * seq, struct inet6_ifaddr **ifp)
16908 + struct mipv6_dad_cell *cell;
16910 + read_lock(&dad_lock);
16911 + cell = dad_cell_head.next;
16912 + while (cell != &dad_cell_head &&
16913 + ipv6_addr_cmp(&cell->ll_haddr, ll_haddr) &&
16914 + ipv6_addr_cmp(&cell->haddr, ll_haddr)) {
16915 + cell = cell->next;
16917 + if (cell == &dad_cell_head || cell->flags != DAD_INIT_ENTRY) {
16918 + /* Not found element, or element already finished processing */
16919 + if (cell != &dad_cell_head) {
16921 + * Set the state to DUPLICATE, even if it was UNIQUE
16922 + * earlier. It is not needed to setup timer via
16923 + * mipv6_start_dad_head_timer since this must have
16924 + * already been done.
16926 + cell->flags = DAD_DUPLICATE_ADDRESS;
16928 + read_unlock(&dad_lock);
16933 + * The NA found an unprocessed entry in the DAD list. Expire this
16934 + * entry since another node advertised this address. Caller should
16935 + * reject BU (DAD failed).
16937 + ipv6_addr_copy(daddr, &cell->daddr);
16938 + ipv6_addr_copy(haddr, &cell->haddr);
16939 + ipv6_addr_copy(coa, &cell->coa);
16940 + ipv6_addr_copy(rep_coa, &cell->rep_coa);
16941 + *seq = cell->sequence;
16942 + *ifp = cell->ifp;
16944 + if (del_timer(&cell->callback_timer) == 0) {
16945 + /* Timer already deleted, race with Timeout Handler */
16946 + /* No action needed */
16949 + cell->flags = DAD_DUPLICATE_ADDRESS;
16951 + /* Now leave this address to avoid future processing of NA's */
16952 + mipv6_leave_sol_mc_addr(&cell->ll_haddr, cell->ifp->idev->dev);
16953 + /* Leave also global address, if link local address was in use */
16954 + if (ipv6_addr_cmp(&cell->ll_haddr, &cell->haddr))
16955 + mipv6_leave_sol_mc_addr(&cell->haddr, cell->ifp->idev->dev);
16956 + /* Start dad_head timer to remove this entry */
16957 + mipv6_start_dad_head_timer(cell);
16959 + read_unlock(&dad_lock);
16964 +/* ENTRY routine called via Neighbor Advertisement */
16965 +void mipv6_check_dad(struct in6_addr *ll_haddr)
16967 + struct in6_addr daddr, haddr, coa, rep_coa;
16968 + struct inet6_ifaddr *ifp;
16971 + if (dad_search_haddr(ll_haddr, &daddr, &haddr, &coa, &rep_coa, &seq,
16974 + * Didn't find entry, or no action needed (the action has
16975 + * already been performed).
16981 + * A DAD cell was present, meaning that there is a pending BU
16982 + * request for 'haddr' - reject the BU.
16984 + mipv6_bu_finish(ifp, 0, DUPLICATE_ADDR_DETECT_FAIL,
16985 + &daddr, &haddr, &coa, &rep_coa, 0, seq, 0, NULL);
16990 + * Check if the passed 'cell' is in the list of pending DAD's. Called from
16991 + * the Timeout Handler.
16993 + * Assumes that the caller is holding the dad_lock in reader mode.
16995 +static int dad_search_cell(struct mipv6_dad_cell *cell)
16997 + struct mipv6_dad_cell *tmp;
16999 + tmp = dad_cell_head.next;
17000 + while (tmp != &dad_cell_head && tmp != cell) {
17003 + if (tmp == cell) {
17004 + if (cell->flags == DAD_INIT_ENTRY) {
17005 + /* Found valid entry */
17006 + if (--cell->probes == 0) {
17008 + * Retransmission's are over - return success.
17010 + cell->flags = DAD_UNIQUE_ADDRESS;
17013 + * Leave this address to avoid future
17014 + * processing of NA's.
17016 + mipv6_leave_sol_mc_addr(&cell->ll_haddr,
17017 + cell->ifp->idev->
17019 + if (ipv6_addr_cmp(&cell->ll_haddr, &cell->haddr))
17020 + mipv6_leave_sol_mc_addr(&cell->haddr,
17021 + cell->ifp->idev->dev);
17022 + /* start timeout to delete this cell. */
17023 + mipv6_start_dad_head_timer(cell);
17027 + * Retransmission not finished, send another NS and
17028 + * return failure.
17030 + mipv6_dad_send_ns(cell->ifp, &cell->ll_haddr);
17031 + if (ipv6_addr_cmp(&cell->ll_haddr, &cell->haddr))
17032 + mipv6_leave_sol_mc_addr(&cell->haddr,
17033 + cell->ifp->idev->dev);
17034 + cell->callback_timer.expires = jiffies +
17035 + cell->ifp->idev->nd_parms->retrans_time;
17036 + add_timer(&cell->callback_timer);
17039 + * This means that an NA was received before the
17040 + * timeout and when the state changed from
17041 + * DAD_INIT_ENTRY, the BU got failed as a result.
17042 + * There is nothing to be done.
17049 +/* ENTRY routine called via Timeout */
17050 +static void mipv6_dad_timeout(unsigned long arg)
17052 + __u8 ba_status = SUCCESS;
17053 + struct in6_addr daddr;
17054 + struct in6_addr haddr;
17055 + struct in6_addr coa;
17056 + struct in6_addr rep_coa;
17057 + struct inet6_ifaddr *ifp;
17059 + __u32 ba_lifetime;
17062 + struct mipv6_dad_cell *cell = (struct mipv6_dad_cell *) arg;
17065 + * If entry is not in the list, we have already sent BU Failure
17066 + * after getting a NA.
17068 + read_lock(&dad_lock);
17069 + if (dad_search_cell(cell) < 0) {
17071 + * 'cell' is no longer valid (may not be in the list or
17072 + * is already processed, due to NA processing), or NS
17073 + * retransmissions are not yet over.
17075 + read_unlock(&dad_lock);
17079 + /* This is the final Timeout. Send Bind Ack Success */
17082 + ifindex = cell->ifindex;
17083 + ba_lifetime = cell->ba_lifetime;
17084 + sequence = cell->sequence;
17085 + flags = cell->bu_flags;
17087 + ipv6_addr_copy(&daddr, &cell->daddr);
17088 + ipv6_addr_copy(&haddr, &cell->haddr);
17089 + ipv6_addr_copy(&coa, &cell->coa);
17090 + ipv6_addr_copy(&rep_coa, &cell->rep_coa);
17091 + read_unlock(&dad_lock);
17093 + /* Send BU Acknowledgement Success */
17094 + mipv6_bu_finish(ifp, ifindex, ba_status,
17095 + &daddr, &haddr, &coa, &rep_coa,
17096 + ba_lifetime, sequence, flags, NULL);
17101 + * Check if original home address exists in our DAD pending list, if so return
17104 + * Assumes that the caller is holding the dad_lock in writer mode.
17106 +static struct mipv6_dad_cell *mipv6_dad_get_cell(struct in6_addr *haddr)
17108 + struct mipv6_dad_cell *cell;
17110 + cell = dad_cell_head.next;
17111 + while (cell != &dad_cell_head
17112 + && ipv6_addr_cmp(&cell->haddr, haddr)) {
17113 + cell = cell->next;
17115 + if (cell == &dad_cell_head) {
17116 + /* Not found element */
17123 + * Save all parameters needed for doing a Bind Ack in the mipv6_dad_cell
17126 +static void mipv6_dad_save_cell(struct mipv6_dad_cell *cell,
17127 + struct inet6_ifaddr *ifp, int ifindex,
17128 + struct in6_addr *daddr,
17129 + struct in6_addr *haddr,
17130 + struct in6_addr *coa,
17131 + struct in6_addr *rep_coa,
17132 + __u32 ba_lifetime,
17133 + __u16 sequence, __u8 flags)
17135 + in6_ifa_hold(ifp);
17137 + cell->ifindex = ifindex;
17139 + ipv6_addr_copy(&cell->daddr, daddr);
17140 + ipv6_addr_copy(&cell->haddr, haddr);
17141 + ipv6_addr_copy(&cell->coa, coa);
17142 + ipv6_addr_copy(&cell->rep_coa, rep_coa);
17144 + /* Convert cell->ll_haddr to Link Local address */
17145 + if (flags & MIPV6_BU_F_LLADDR)
17146 + mipv6_generate_ll_addr(&cell->ll_haddr, haddr);
17148 + ipv6_addr_copy(&cell->ll_haddr, haddr);
17150 + cell->ba_lifetime = ba_lifetime;
17151 + cell->sequence = sequence;
17152 + cell->bu_flags = flags;
17156 + * Top level DAD routine for performing DAD.
17159 + * 0 : Don't need to do DAD.
17160 + * 1 : Need to do DAD.
17161 + * -n : Error, where 'n' is the reason for the error.
17163 + * Assumption : DAD process has been optimized by using cached values upto
17164 + * some time. However sometimes this can cause problems. Eg. when the first
17165 + * BU was received, DAD might have failed. Before the second BU arrived,
17166 + * the node using MN's home address might have stopped using it, but still
17167 + * we will return DAD_DUPLICATE_ADDRESS based on the first DAD's result. Or
17168 + * this can go the other way around. However, it is a very small possibility
17169 + * and thus optimization is turned on by default. It is possible to change
17170 + * this feature (needs a little code-rewriting in this routine), but
17171 + * currently DAD result is being cached for performance reasons.
17173 +int mipv6_dad_start(struct inet6_ifaddr *ifp, int ifindex,
17174 + struct in6_addr *daddr, struct in6_addr *haddr,
17175 + struct in6_addr *coa, struct in6_addr *rep_coa,
17176 + __u32 ba_lifetime, __u16 sequence, __u8 flags)
17179 + struct mipv6_dad_cell *cell;
17180 + struct mipv6_bce bc_entry;
17182 + if (ifp->idev->cnf.dad_transmits == 0) {
17183 + /* DAD is not configured on the HA, return SUCCESS */
17187 + if (mipv6_bcache_get(haddr, daddr, &bc_entry) == 0) {
17189 + * We already have an entry in our cache - don't need to
17190 + * do DAD as we are already defending this home address.
17195 + write_lock(&dad_lock);
17196 + if ((cell = mipv6_dad_get_cell(haddr)) != NULL) {
17198 + * An existing entry for BU was found in our cache due
17199 + * to retransmission of the BU or a new COA registration.
17201 + switch (cell->flags) {
17202 + case DAD_INIT_ENTRY:
17203 + /* Old entry is waiting for DAD to complete */
17205 + case DAD_UNIQUE_ADDRESS:
17206 + /* DAD is finished successfully - return success. */
17207 + write_unlock(&dad_lock);
17209 + case DAD_DUPLICATE_ADDRESS:
17211 + * DAD is finished and we got a NA while doing BU -
17212 + * return failure.
17214 + write_unlock(&dad_lock);
17215 + return -DUPLICATE_ADDR_DETECT_FAIL;
17217 + /* Unknown state - should never happen */
17218 + DEBUG(DBG_WARNING,
17219 + "cell entry in unknown state : %d",
17221 + write_unlock(&dad_lock);
17222 + return -REASON_UNSPECIFIED;
17226 + if ((cell = (struct mipv6_dad_cell *)
17227 + kmalloc(sizeof(struct mipv6_dad_cell), GFP_ATOMIC))
17229 + return -INSUFFICIENT_RESOURCES;
17234 + mipv6_dad_save_cell(cell, ifp, ifindex, daddr, haddr, coa, rep_coa,
17235 + ba_lifetime, sequence, flags);
17238 + cell->flags = DAD_INIT_ENTRY;
17239 + cell->probes = ifp->idev->cnf.dad_transmits;
17241 + /* Insert element on dad_cell_head list */
17242 + dad_cell_head.prev->next = cell;
17243 + cell->next = &dad_cell_head;
17244 + cell->prev = dad_cell_head.prev;
17245 + dad_cell_head.prev = cell;
17246 + write_unlock(&dad_lock);
17247 + if (flags & MIPV6_BU_F_LLADDR) {
17248 + /* join the solicited node MC of the global homeaddr.*/
17249 + mipv6_join_sol_mc_addr(&cell->haddr, ifp->idev->dev);
17251 + mipv6_dad_send_ns(ifp, &cell->haddr);
17253 + /* join the solicited node MC of the homeaddr. */
17254 + mipv6_join_sol_mc_addr(&cell->ll_haddr, ifp->idev->dev);
17257 + mipv6_dad_send_ns(ifp, &cell->ll_haddr);
17259 + /* Initialize timer for this cell to timeout the NS. */
17260 + init_timer(&cell->callback_timer);
17261 + cell->callback_timer.data = (unsigned long) cell;
17262 + cell->callback_timer.function = mipv6_dad_timeout;
17263 + cell->callback_timer.expires = jiffies +
17264 + ifp->idev->nd_parms->retrans_time;
17265 + add_timer(&cell->callback_timer);
17267 + write_unlock(&dad_lock);
17272 +void __init mipv6_dad_init(void)
17274 + dad_cell_head.next = dad_cell_head.prev = &dad_cell_head;
17275 + init_timer(&dad_cell_head.callback_timer);
17276 + dad_cell_head.callback_timer.data = 0;
17277 + dad_cell_head.callback_timer.function =
17278 + mipv6_dad_delete_old_entries;
17281 +void __exit mipv6_dad_exit(void)
17283 + struct mipv6_dad_cell *curr, *next;
17285 + write_lock_bh(&dad_lock);
17286 + del_timer(&dad_cell_head.callback_timer);
17288 + curr = dad_cell_head.next;
17289 + while (curr != &dad_cell_head) {
17290 + next = curr->next;
17291 + del_timer(&curr->callback_timer);
17292 + if (curr->flags == DAD_INIT_ENTRY) {
17294 + * We were in DAD_INIT state and listening to the
17295 + * solicited node MC address - need to stop that.
17297 + mipv6_leave_sol_mc_addr(&curr->ll_haddr,
17298 + curr->ifp->idev->dev);
17299 + if (ipv6_addr_cmp(&curr->ll_haddr, &curr->haddr))
17300 + mipv6_leave_sol_mc_addr(&curr->haddr,
17301 + curr->ifp->idev->dev);
17303 + in6_ifa_put(curr->ifp);
17307 + dad_cell_head.next = dad_cell_head.prev = &dad_cell_head;
17308 + write_unlock_bh(&dad_lock);
17310 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/prefix.c linux-2.4.25/net/ipv6/mobile_ip6/prefix.c
17311 --- linux-2.4.25.old/net/ipv6/mobile_ip6/prefix.c 1970-01-01 01:00:00.000000000 +0100
17312 +++ linux-2.4.25/net/ipv6/mobile_ip6/prefix.c 2004-06-26 11:29:31.000000000 +0100
17315 + * Prefix solicitation and advertisement
17318 + * Jaakko Laine <medved@iki.fi>
17322 + * This program is free software; you can redistribute it and/or
17323 + * modify it under the terms of the GNU General Public License
17324 + * as published by the Free Software Foundation; either version
17325 + * 2 of the License, or (at your option) any later version.
17328 +#include <linux/config.h>
17329 +#include <linux/icmpv6.h>
17330 +#include <linux/net.h>
17331 +#include <linux/spinlock.h>
17332 +#include <linux/timer.h>
17333 +#include <linux/netdevice.h>
17334 +#include <net/ipv6.h>
17335 +#include <net/addrconf.h>
17336 +#include <net/ip6_route.h>
17337 +#include <net/mipv6.h>
17339 +#include "mipv6_icmp.h"
17340 +#include "debug.h"
17341 +#include "sortedlist.h"
17342 +#include "prefix.h"
17343 +#include "config.h"
17345 +#define INFINITY 0xffffffff
17347 +struct timer_list pfx_timer;
17349 +struct list_head pfx_list;
17350 +rwlock_t pfx_list_lock = RW_LOCK_UNLOCKED;
17352 +int compare_pfx_list_entry(const void *data1, const void *data2,
17355 + struct pfx_list_entry *e1 = (struct pfx_list_entry *) data1;
17356 + struct pfx_list_entry *e2 = (struct pfx_list_entry *) data2;
17358 + return ((ipv6_addr_cmp(&e1->daddr, &e2->daddr) == 0)
17359 + && (e2->ifindex == -1 || e1->ifindex == e2->ifindex));
17363 + * mipv6_pfx_cancel_send - cancel pending items to daddr from saddr
17364 + * @daddr: Destination address
17365 + * @ifindex: pending items on this interface will be canceled
17367 + * if ifindex == -1, all items to daddr will be removed
17369 +void mipv6_pfx_cancel_send(struct in6_addr *daddr, int ifindex)
17371 + unsigned long tmp;
17372 + struct pfx_list_entry entry;
17376 + /* We'll just be comparing these parts... */
17377 + memcpy(&entry.daddr, daddr, sizeof(struct in6_addr));
17378 + entry.ifindex = ifindex;
17380 + write_lock_bh(&pfx_list_lock);
17382 + while (mipv6_slist_del_item(&pfx_list, &entry,
17383 + compare_pfx_list_entry) == 0)
17386 + if ((tmp = mipv6_slist_get_first_key(&pfx_list)))
17387 + mod_timer(&pfx_timer, tmp);
17389 + write_unlock_bh(&pfx_list_lock);
17393 + * mipv6_pfx_add_ha - add a new HA to send prefix solicitations to
17394 + * @daddr: address of HA
17395 + * @saddr: our address to use as source address
17396 + * @ifindex: interface index
17398 +void mipv6_pfx_add_ha(struct in6_addr *daddr, struct in6_addr *saddr,
17401 + unsigned long tmp;
17402 + struct pfx_list_entry entry;
17406 + memcpy(&entry.daddr, daddr, sizeof(struct in6_addr));
17407 + memcpy(&entry.saddr, saddr, sizeof(struct in6_addr));
17408 + entry.retries = 0;
17409 + entry.ifindex = ifindex;
17411 + write_lock_bh(&pfx_list_lock);
17412 + if (mipv6_slist_modify(&pfx_list, &entry, sizeof(struct pfx_list_entry),
17413 + jiffies + INITIAL_SOLICIT_TIMER * HZ,
17414 + compare_pfx_list_entry))
17415 + DEBUG(DBG_WARNING, "Cannot add new HA to pfx list");
17417 + if ((tmp = mipv6_slist_get_first_key(&pfx_list)))
17418 + mod_timer(&pfx_timer, tmp);
17419 + write_unlock_bh(&pfx_list_lock);
17422 +int mipv6_pfx_add_home(int ifindex, struct in6_addr *saddr,
17423 + struct in6_addr *daddr, unsigned long min_expire)
17425 + unsigned long tmp;
17427 + write_lock(&pfx_list_lock);
17429 + if (min_expire != INFINITY) {
17430 + unsigned long expire;
17431 + struct pfx_list_entry entry;
17433 + memcpy(&entry.daddr, saddr, sizeof(struct in6_addr));
17434 + memcpy(&entry.saddr, daddr, sizeof(struct in6_addr));
17435 + entry.retries = 0;
17436 + entry.ifindex = ifindex;
17438 + /* This is against the RFC 3775, but we need to set
17439 + * a minimum interval for a prefix solicitation.
17440 + * Otherwise a prefix solicitation storm will
17441 + * result if valid lifetime of the prefix is
17442 + * smaller than MAX_PFX_ADV_DELAY
17444 + min_expire -= MAX_PFX_ADV_DELAY;
17445 + min_expire = min_expire < MIN_PFX_SOL_DELAY ? MIN_PFX_SOL_DELAY : min_expire;
17447 + expire = jiffies + min_expire * HZ;
17449 + if (mipv6_slist_modify(&pfx_list, &entry,
17450 + sizeof(struct pfx_list_entry),
17452 + compare_pfx_list_entry) != 0)
17453 + DEBUG(DBG_WARNING, "Cannot add new entry to pfx_list");
17456 + if ((tmp = mipv6_slist_get_first_key(&pfx_list)))
17457 + mod_timer(&pfx_timer, tmp);
17459 + write_unlock(&pfx_list_lock);
17465 + * set_ha_pfx_list - manipulate pfx_list for HA when timer goes off
17466 + * @entry: pfx_list_entry that is due
17468 +static void set_ha_pfx_list(struct pfx_list_entry *entry)
17473 + * set_mn_pfx_list - manipulate pfx_list for MN when timer goes off
17474 + * @entry: pfx_list_entry that is due
17476 +static void set_mn_pfx_list(struct pfx_list_entry *entry)
17481 + * pfx_timer_handler - general timer handler
17484 + * calls set_ha_pfx_list and set_mn_pfx_list to do the thing when
17485 + * a timer goes off
17487 +static void pfx_timer_handler(unsigned long dummy)
17489 + unsigned long tmp;
17490 + struct pfx_list_entry *entry;
17494 + write_lock(&pfx_list_lock);
17495 + if (!(entry = mipv6_slist_get_first(&pfx_list)))
17498 + if (mip6node_cnf.capabilities & CAP_HA)
17499 + set_ha_pfx_list(entry);
17500 + if (mip6node_cnf.capabilities & CAP_MN)
17501 + set_mn_pfx_list(entry);
17502 + if ((tmp = mipv6_slist_get_first_key(&pfx_list)))
17503 + mod_timer(&pfx_timer, tmp);
17506 + write_unlock(&pfx_list_lock);
17509 +int mipv6_initialize_pfx_icmpv6(void)
17511 + INIT_LIST_HEAD(&pfx_list);
17513 + init_timer(&pfx_timer);
17514 + pfx_timer.function = pfx_timer_handler;
17519 +void mipv6_shutdown_pfx_icmpv6(void)
17521 + struct prefix_info *tmp;
17523 + if (timer_pending(&pfx_timer))
17524 + del_timer(&pfx_timer);
17526 + write_lock_bh(&pfx_list_lock);
17527 + while ((tmp = mipv6_slist_del_first(&pfx_list)))
17529 + write_unlock_bh(&pfx_list_lock);
17531 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/prefix.h linux-2.4.25/net/ipv6/mobile_ip6/prefix.h
17532 --- linux-2.4.25.old/net/ipv6/mobile_ip6/prefix.h 1970-01-01 01:00:00.000000000 +0100
17533 +++ linux-2.4.25/net/ipv6/mobile_ip6/prefix.h 2004-06-26 11:29:31.000000000 +0100
17536 + * MIPL Mobile IPv6 Prefix solicitation and advertisement
17540 + * This program is free software; you can redistribute it and/or
17541 + * modify it under the terms of the GNU General Public License
17542 + * as published by the Free Software Foundation; either version
17543 + * 2 of the License, or (at your option) any later version.
17549 +#include <net/addrconf.h>
17551 +struct pfx_list_entry {
17552 + struct in6_addr daddr;
17553 + struct in6_addr saddr;
17558 +extern struct list_head pfx_list;
17559 +extern rwlock_t pfx_list_lock;
17560 +extern struct timer_list pfx_timer;
17562 +int compare_pfx_list_entry(const void *data1, const void *data2,
17566 + * mipv6_pfx_cancel_send - cancel pending pfx_advs/sols to daddr
17567 + * @daddr: destination address
17568 + * @ifindex: pending items on this interface will be canceled
17570 + * if ifindex == -1, all items to daddr will be removed
17572 +void mipv6_pfx_cancel_send(struct in6_addr *daddr, int ifindex);
17575 + * mipv6_pfx_add_ha - add a new HA to send prefix solicitations to
17576 + * @daddr: address of HA
17577 + * @saddr: our address to use as source address
17578 + * @ifindex: interface index
17580 +void mipv6_pfx_add_ha(struct in6_addr *daddr, struct in6_addr *saddr,
17583 +void mipv6_pfxs_modified(struct prefix_info *pinfo, int ifindex);
17585 +int mipv6_pfx_add_home(int ifindex, struct in6_addr *daddr,
17586 + struct in6_addr *saddr, unsigned long min_expire);
17588 +int mipv6_initialize_pfx_icmpv6(void);
17589 +void mipv6_shutdown_pfx_icmpv6(void);
17592 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/prefix_ha.c linux-2.4.25/net/ipv6/mobile_ip6/prefix_ha.c
17593 --- linux-2.4.25.old/net/ipv6/mobile_ip6/prefix_ha.c 1970-01-01 01:00:00.000000000 +0100
17594 +++ linux-2.4.25/net/ipv6/mobile_ip6/prefix_ha.c 2004-06-26 11:29:31.000000000 +0100
17597 + * Prefix advertisement for Home Agent
17600 + * Jaakko Laine <medved@iki.fi>
17604 + * This program is free software; you can redistribute it and/or
17605 + * modify it under the terms of the GNU General Public License
17606 + * as published by the Free Software Foundation; either version
17607 + * 2 of the License, or (at your option) any later version.
17610 +#include <linux/config.h>
17611 +#include <linux/icmpv6.h>
17612 +#include <linux/net.h>
17613 +#include <linux/spinlock.h>
17614 +#include <linux/timer.h>
17615 +#include <linux/netdevice.h>
17616 +#include <net/ipv6.h>
17617 +#include <net/addrconf.h>
17618 +#include <net/ip6_route.h>
17619 +#include <net/mipv6.h>
17621 +#include "mipv6_icmp.h"
17622 +#include "debug.h"
17623 +#include "sortedlist.h"
17625 +#include "bcache.h"
17626 +#include "config.h"
17627 +#include "prefix.h"
17630 + * pfx_adv_iterator - modify pfx_list entries according to new prefix info
17631 + * @data: MN's home registration bcache_entry
17632 + * @args: new prefix info
17633 + * @sortkey: ignored
17635 +static int pfx_adv_iterator(void *data, void *args, unsigned long sortkey)
17637 + struct mipv6_bce *bc_entry = (struct mipv6_bce *) data;
17638 + struct prefix_info *pinfo = (struct prefix_info *) args;
17640 + if (mipv6_prefix_compare(&bc_entry->coa, &pinfo->prefix,
17641 + pinfo->prefix_len) == 0) {
17642 + struct pfx_list_entry pfx_entry;
17644 + memcpy(&pfx_entry.daddr, &bc_entry->coa,
17645 + sizeof(struct in6_addr));
17646 + memcpy(&pfx_entry.daddr, &bc_entry->our_addr,
17647 + sizeof(struct in6_addr));
17648 + pfx_entry.retries = 0;
17649 + pfx_entry.ifindex = bc_entry->ifindex;
17651 + mipv6_slist_modify(&pfx_list, &pfx_entry,
17652 + sizeof(struct pfx_list_entry),
17654 + net_random() % (MAX_PFX_ADV_DELAY * HZ),
17655 + compare_pfx_list_entry);
17661 +struct homereg_iterator_args {
17662 + struct list_head *head;
17666 +static int homereg_iterator(void *data, void *args, unsigned long *sortkey)
17668 + struct mipv6_bce *entry = (struct mipv6_bce *) data;
17669 + struct homereg_iterator_args *state =
17670 + (struct homereg_iterator_args *) args;
17672 + if (entry->type == HOME_REGISTRATION) {
17673 + mipv6_slist_add(state->head, entry,
17674 + sizeof(struct mipv6_bce),
17681 +static int mipv6_bcache_get_homeregs(struct list_head *head)
17683 + struct homereg_iterator_args args;
17688 + args.head = head;
17690 + mipv6_bcache_iterate(homereg_iterator, &args);
17691 + return args.count;
17695 + * mipv6_prefix_added - prefix was added to interface, act accordingly
17696 + * @pinfo: prefix_info that was added
17697 + * @ifindex: interface index
17699 +void mipv6_pfxs_modified(struct prefix_info *pinfo, int ifindex)
17702 + unsigned long tmp;
17703 + struct list_head home_regs;
17707 + INIT_LIST_HEAD(&home_regs);
17709 + if (!(count = mipv6_bcache_get_homeregs(&home_regs)))
17712 + write_lock_bh(&pfx_list_lock);
17713 + mipv6_slist_for_each(&home_regs, pinfo, pfx_adv_iterator);
17714 + if ((tmp = mipv6_slist_get_first_key(&pfx_list)))
17715 + mod_timer(&pfx_timer, tmp);
17716 + write_unlock_bh(&pfx_list_lock);
17718 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/rr_crypto.c linux-2.4.25/net/ipv6/mobile_ip6/rr_crypto.c
17719 --- linux-2.4.25.old/net/ipv6/mobile_ip6/rr_crypto.c 1970-01-01 01:00:00.000000000 +0100
17720 +++ linux-2.4.25/net/ipv6/mobile_ip6/rr_crypto.c 2004-06-26 11:29:31.000000000 +0100
17723 + * rr_cookie.c - Mobile IPv6 return routability crypto
17724 + * Author : Henrik Petander <henrik.petander@hut.fi>
17728 + * This program is free software; you can redistribute it and/or
17729 + * modify it under the terms of the GNU General Public License
17730 + * as published by the Free Software Foundation; either version
17731 + * 2 of the License, or (at your option) any later version.
17737 +#include <linux/kernel.h>
17738 +#include <linux/types.h>
17739 +#include <linux/spinlock.h>
17740 +#include <linux/sched.h>
17741 +#include <linux/timer.h>
17742 +#include <linux/in6.h>
17743 +#include <linux/init.h>
17744 +#include <linux/random.h>
17746 +#include <net/ipv6.h>
17748 +#include "debug.h"
17750 +#include "rr_crypto.h"
17754 +u8 k_CN[HMAC_SHA1_KEY_SIZE]; // secret key of CN
17756 +u16 curr_index = 0;
17758 +struct nonce_timestamp nonce_table[MAX_NONCES];
17759 +spinlock_t nonce_lock = SPIN_LOCK_UNLOCKED;
17760 +void update_nonces(void);
17762 +/** nonce_is_fresh - whether the nonce was generated recently
17764 + * @non_ts : table entry containing the nonce and a timestamp
17765 + * @interval : if nonce was generated within interval seconds it is fresh
17767 + * Returns 1 if the nonce is fresh, 0 otherwise.
17769 +static int nonce_is_fresh(struct nonce_timestamp *non_ts, unsigned long interval)
17771 + if (time_before(jiffies, non_ts->timestamp + interval * HZ) && !non_ts->invalid)
17775 +void mipv6_rr_invalidate_nonce(u16 nonce_ind)
17777 + spin_lock_bh(&nonce_lock);
17778 + if (nonce_ind > MAX_NONCES) {
17779 + spin_unlock_bh(&nonce_lock);
17782 + nonce_table[nonce_ind].invalid = 1;
17783 + spin_unlock_bh(&nonce_lock);
17785 +/* Returns a pointer to a new nonce */
17786 +struct mipv6_rr_nonce * mipv6_rr_get_new_nonce(void)
17788 + struct mipv6_rr_nonce *nce = kmalloc(sizeof(*nce), GFP_ATOMIC);
17792 + // Lock nonces here
17793 + spin_lock_bh(&nonce_lock);
17794 + // If nonce is not fresh create new one
17795 + if (!nonce_is_fresh(&nonce_table[curr_index], MIPV6_RR_NONCE_LIFETIME)) {
17796 + // increment the last nonce pointer and create new nonce
17799 + if (curr_index == MAX_NONCES)
17801 + // Get random data to fill the nonce data
17802 + get_random_bytes(nonce_table[curr_index].nonce.data, MIPV6_RR_NONCE_DATA_LENGTH);
17803 + // Fill the index field
17804 + nonce_table[curr_index].nonce.index = curr_index;
17805 + nonce_table[curr_index].invalid = 0;
17806 + nonce_table[curr_index].timestamp = jiffies;
17808 + spin_unlock_bh(&nonce_lock);
17809 + memcpy(nce, &nonce_table[curr_index].nonce, sizeof(*nce));
17813 +/** mipv6_rr_nonce_get_by_index - returns a nonce for index
17814 + * @nonce_ind : index of the nonce
17816 + * Returns a nonce or NULL if the nonce index was invalid or the nonce
17817 + * for the index was not fresh.
17819 +struct mipv6_rr_nonce * mipv6_rr_nonce_get_by_index(u16 nonce_ind)
17821 + struct mipv6_rr_nonce *nce = NULL;
17823 + spin_lock_bh(&nonce_lock);
17824 + if (nonce_ind >= MAX_NONCES) {
17825 + DEBUG(DBG_WARNING, "Nonce index field from BU invalid");
17827 + /* Here a double of the nonce_lifetime is used for freshness
17828 + * verification, since the nonces
17829 + * are not created in response to every initiator packet
17831 + } else if (nonce_is_fresh(&nonce_table[nonce_ind], 2 * MIPV6_RR_NONCE_LIFETIME)) {
17832 + nce = kmalloc(sizeof(*nce), GFP_ATOMIC);
17833 + memcpy(nce, &nonce_table[nonce_ind].nonce, sizeof(*nce));
17835 + spin_unlock_bh(&nonce_lock);
17840 +/* Fills rr test init cookies with random bytes */
17841 +void mipv6_rr_mn_cookie_create(u8 *cookie)
17843 + get_random_bytes(cookie, MIPV6_RR_COOKIE_LENGTH);
17846 +/** mipv6_rr_cookie_create - builds a home or care-of cookie
17848 + * @addr : the home or care-of address from HoTI or CoTI
17849 + * @ckie : memory where the cookie is copied to
17850 + * @nce : pointer to a nonce used for the calculation, nce is freed during the function
17853 +int mipv6_rr_cookie_create(struct in6_addr *addr, u8 **ckie,
17856 + struct ah_processing ah_proc;
17857 + u8 digest[HMAC_SHA1_HASH_LEN];
17858 + struct mipv6_rr_nonce *nce;
17860 + if ((nce = mipv6_rr_nonce_get_by_index(nonce_index))== NULL)
17863 + if (*ckie == NULL && (*ckie = kmalloc(MIPV6_RR_COOKIE_LENGTH,
17864 + GFP_ATOMIC)) == NULL) {
17868 + /* Calculate the full hmac-sha1 digest from address and nonce using the secret key of cn */
17870 + if (ah_hmac_sha1_init(&ah_proc, k_CN, HMAC_SHA1_KEY_SIZE) < 0) {
17871 + DEBUG(DBG_ERROR, "Hmac sha1 initialization failed");
17876 + ah_hmac_sha1_loop(&ah_proc, addr, sizeof(*addr));
17877 + ah_hmac_sha1_loop(&ah_proc, nce->data, MIPV6_RR_NONCE_DATA_LENGTH);
17878 + ah_hmac_sha1_result(&ah_proc, digest);
17881 + /* clean up nonce */
17884 + /* Copy first 64 bits of hash target to the cookie */
17885 + memcpy(*ckie, digest, MIPV6_RR_COOKIE_LENGTH);
17889 +/** mipv6_rr_key_calc - creates BU authentication key
17891 + * @hoc : Home Cookie
17892 + * @coc : Care-of Cookie
17894 + * Returns BU authentication key of length HMAC_SHA1_KEY_SIZE or NULL in error cases,
17895 + * caller needs to free the key.
17897 +u8 *mipv6_rr_key_calc(u8 *hoc, u8 *coc)
17900 + u8 *key_bu = kmalloc(HMAC_SHA1_KEY_SIZE, GFP_ATOMIC);
17904 + DEBUG(DBG_CRITICAL, "Memory allocation failed, could nort create BU authentication key");
17908 + /* Calculate the key from home and care-of cookies
17909 + * Kbu = sha1(home_cookie | care-of cookie)
17910 + * or KBu = sha1(home_cookie), if MN deregisters
17913 + sha1_compute(&c, hoc, MIPV6_RR_COOKIE_LENGTH);
17915 + sha1_compute(&c, coc, MIPV6_RR_COOKIE_LENGTH);
17916 + sha1_final(&c, key_bu);
17917 + DEBUG(DBG_RR, "Home and Care-of cookies used for calculating key ");
17918 + debug_print_buffer(DBG_RR, hoc, MIPV6_RR_COOKIE_LENGTH);
17920 + debug_print_buffer(DBG_RR, coc, MIPV6_RR_COOKIE_LENGTH);
17925 +void mipv6_rr_init(void)
17927 + get_random_bytes(k_CN, HMAC_SHA1_KEY_SIZE);
17928 + memset(nonce_table, 0, MAX_NONCES * sizeof(struct nonce_timestamp));
17931 +#ifdef TEST_MIPV6_RR_CRYPTO
17932 +void mipv6_test_rr(void)
17934 + struct mipv6_rr_nonce *nonce;
17935 + struct in6_addr a1, a2;
17937 + u8 *ckie1 = NULL, *ckie2 = NULL;
17938 + u8 *key_mn = NULL, *key_cn = NULL;
17941 + nonce = mipv6_rr_get_new_nonce();
17943 + printk("mipv6_rr_get_new_nonce() failed, at 1! \n");
17946 + mipv6_rr_cookie_create(&a1, &ckie1, nonce->index);
17947 + ind1 = nonce->index;
17950 + nonce = mipv6_rr_get_new_nonce();
17952 + printk("mipv6_rr_get_new_nonce() failed, at 2! \n");
17956 + mipv6_rr_cookie_create(&a2, &ckie2, nonce->index);
17957 + ind2 = nonce->index;
17958 + key_mn = mipv6_rr_key_calc(ckie1, ckie2);
17960 + /* Create home and coa cookies based on indices */
17961 + mipv6_rr_cookie_create(&a1, &ckie1, ind1);
17962 + mipv6_rr_cookie_create(&a2, &ckie2, ind2);
17963 + key_cn = mipv6_rr_key_calc(ckie1, ckie2);
17964 + if (!key_cn || !key_mn) {
17965 + printk("creation of secret key failed!\n");
17968 + if(memcmp(key_cn, key_mn, HMAC_SHA1_KEY_SIZE))
17969 + printk("mipv6_rr_key_calc produced different keys for MN and CN \n");
17971 + printk("mipv6_rr_crypto test OK\n");
17977 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/rr_crypto.h linux-2.4.25/net/ipv6/mobile_ip6/rr_crypto.h
17978 --- linux-2.4.25.old/net/ipv6/mobile_ip6/rr_crypto.h 1970-01-01 01:00:00.000000000 +0100
17979 +++ linux-2.4.25/net/ipv6/mobile_ip6/rr_crypto.h 2004-06-26 11:29:31.000000000 +0100
17982 + * MIPL Mobile IPv6 Return routability crypto prototypes
17986 + * This program is free software; you can redistribute it and/or
17987 + * modify it under the terms of the GNU General Public License
17988 + * as published by the Free Software Foundation; either version
17989 + * 2 of the License, or (at your option) any later version.
17992 +#ifndef _RR_CRYPTO
17993 +#define _RR_CRYPTO
17995 +#include <linux/in6.h>
17997 +/* Macros and data structures */
17999 +#define MIPV6_RR_NONCE_LIFETIME 60
18000 +#define MIPV6_RR_NONCE_DATA_LENGTH 8
18001 +#define MIPV6_RR_COOKIE_LENGTH 8
18002 +#define COOKIE_SIZE 8
18003 +#define MAX_NONCES 4
18004 +#define HMAC_SHA1_KEY_SIZE 20
18006 +struct mipv6_rr_nonce {
18008 + u_int8_t data[MIPV6_RR_NONCE_DATA_LENGTH];
18011 +struct nonce_timestamp {
18012 + struct mipv6_rr_nonce nonce;
18013 + unsigned long timestamp;
18014 + u_int8_t invalid;
18017 +/* Function definitions */
18019 +/* Return 1 if equal, 0 if not */
18020 +static __inline__ int mipv6_equal_cookies(u8 *c1, u8 *c2)
18022 + return (memcmp(c1, c2, MIPV6_RR_COOKIE_LENGTH) == 0);
18025 +/* Function declarations */
18027 +/* Create cookie for HoTi and CoTi */
18028 +extern void mipv6_rr_mn_cookie_create(u8 *cookie);
18030 +/* Create cookie for HoT and CoT */
18031 +extern int mipv6_rr_cookie_create(struct in6_addr *addr, u8 **ckie, u16 nonce_index);
18033 +/* Calculate return routability key from home and care-of cookies, key length is
18034 + * HMAC_SHA1_KEY_SIZE
18036 +extern u_int8_t *mipv6_rr_key_calc(u8 *hoc, u8 *coc);
18038 +extern struct mipv6_rr_nonce *mipv6_rr_get_new_nonce(void);
18040 +/* For avoiding replay attacks when MN deregisters */
18041 +extern void mipv6_rr_invalidate_nonce(u16 nonce_index);
18043 + * initializes the return routability crypto
18046 +void mipv6_rr_init(void);
18048 +#ifdef TEST_MIPV6_RR_CRYPTO
18049 +void mipv6_test_rr(void);
18050 +#endif /* TEST_MIPV6_RR_CRYPTO */
18052 +#endif /* RR_CRYPTO */
18053 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/sortedlist.c linux-2.4.25/net/ipv6/mobile_ip6/sortedlist.c
18054 --- linux-2.4.25.old/net/ipv6/mobile_ip6/sortedlist.c 1970-01-01 01:00:00.000000000 +0100
18055 +++ linux-2.4.25/net/ipv6/mobile_ip6/sortedlist.c 2004-06-26 11:29:31.000000000 +0100
18058 + * Sorted list - linked list with sortkey.
18061 + * Jaakko Laine <medved@iki.fi>
18065 + * This program is free software; you can redistribute it and/or
18066 + * modify it under the terms of the GNU General Public License
18067 + * as published by the Free Software Foundation; either version
18068 + * 2 of the License, or (at your option) any later version.
18071 +#include <linux/kernel.h>
18072 +#include <linux/types.h>
18073 +#include <linux/list.h>
18074 +#include <linux/slab.h>
18075 +#include <linux/spinlock.h>
18076 +#include <linux/string.h>
18078 +struct mipv6_sorted_list_entry {
18079 + struct list_head list;
18082 + unsigned long sortkey;
18086 + * compare - compares two arbitrary data items
18087 + * @data1: first data item
18088 + * @data2: second data item
18089 + * @datalen: length of data items in bits
18091 + * datalen is in bits!
18093 +int mipv6_bitwise_compare(const void *data1, const void *data2, int datalen)
18096 + __u8 * ptr1 = (__u8 *)data1;
18097 + __u8 * ptr2 = (__u8 *)data2;
18099 + for (; n>=0; n-=8, ptr1++, ptr2++) {
18101 + if (*ptr1 != *ptr2)
18104 + if ((*ptr1 ^ *ptr2) & ((~0) << (8 - n)))
18113 + * mipv6_slist_add - add an entry to sorted list
18114 + * @head: list_head of the sorted list
18115 + * @data: item to store
18116 + * @datalen: length of data (in bytes)
18117 + * @key: sortkey of item
18119 + * Allocates memory for entry and data
18121 +int mipv6_slist_add(struct list_head *head, void *data, int datalen,
18122 + unsigned long sortkey)
18124 + struct list_head *pos;
18125 + struct mipv6_sorted_list_entry *entry, *tmp, *next;
18127 + entry = kmalloc(sizeof(struct mipv6_sorted_list_entry), GFP_ATOMIC);
18132 + entry->data = kmalloc(datalen, GFP_ATOMIC);
18134 + if (!entry->data) {
18139 + memcpy(entry->data, data, datalen);
18140 + entry->datalen = datalen;
18141 + entry->sortkey = sortkey;
18143 + if ((pos = head->next) == head) {
18144 + list_add(&entry->list, head);
18148 + tmp = list_entry(pos, struct mipv6_sorted_list_entry, list);
18149 + if (entry->sortkey < tmp->sortkey) {
18150 + list_add(&entry->list, head);
18154 + for (; pos != head; pos = pos->next) {
18155 + tmp = list_entry(pos, struct mipv6_sorted_list_entry, list);
18156 + if (pos->next == head) {
18157 + list_add(&entry->list, &tmp->list);
18160 + next = list_entry(pos->next, struct mipv6_sorted_list_entry, list);
18161 + if (entry->sortkey >= tmp->sortkey && entry->sortkey < next->sortkey) {
18162 + list_add(&entry->list, &tmp->list);
18167 + /* never reached */
18172 + * mipv6_slist_get_first - get the first data item in the list
18173 + * @head: list_head of the sorted list
18175 + * Returns the actual data item, not copy, so don't kfree it
18177 +void *mipv6_slist_get_first(struct list_head *head)
18179 + struct mipv6_sorted_list_entry *entry;
18181 + if (list_empty(head))
18184 + entry = list_entry(head->next, struct mipv6_sorted_list_entry, list);
18185 + return entry->data;
18189 + * mipv6_slist_del_first - delete (and get) the first item in list
18190 + * @head: list_head of the sorted list
18192 + * Remember to kfree the item
18194 +void *mipv6_slist_del_first(struct list_head *head)
18197 + struct mipv6_sorted_list_entry *entry;
18199 + if (list_empty(head))
18202 + entry = list_entry(head->next, struct mipv6_sorted_list_entry, list);
18203 + tmp = entry->data;
18205 + list_del(head->next);
18212 + * mipv6_slist_del_item - delete entry
18213 + * @head: list_head of the sorted list
18214 + * @data: item to delete
18215 + * @compare: function used for comparing the data items
18217 + * compare function needs to have prototype
18218 + * int (*compare)(const void *data1, const void *data2, int datalen)
18220 +int mipv6_slist_del_item(struct list_head *head, void *data,
18221 + int (*compare)(const void *data1, const void *data2,
18224 + struct list_head *pos;
18225 + struct mipv6_sorted_list_entry *entry;
18227 + for(pos = head->next; pos != head; pos = pos->next) {
18228 + entry = list_entry(pos, struct mipv6_sorted_list_entry, list);
18229 + if (compare(data, entry->data, entry->datalen)) {
18231 + kfree(entry->data);
18241 + * mipv6_slist_get_first_key - get sortkey of the first item
18242 + * @head: list_head of the sorted list
18244 +unsigned long mipv6_slist_get_first_key(struct list_head *head)
18246 + struct mipv6_sorted_list_entry *entry;
18248 + if (list_empty(head))
18251 + entry = list_entry(head->next, struct mipv6_sorted_list_entry, list);
18252 + return entry->sortkey;
18256 + * mipv6_slist_get_key - get sortkey of the data item
18257 + * @head: list_head of the sorted list
18258 + * @data: the item to search for
18259 + * @compare: function used for comparing the data items
18261 + * compare function needs to have prototype
18262 + * int (*compare)(const void *data1, const void *data2, int datalen)
18264 +unsigned long mipv6_slist_get_key(struct list_head *head, void *data,
18265 + int (*compare)(const void *data1,
18266 + const void *data2,
18269 + struct list_head *pos;
18270 + struct mipv6_sorted_list_entry *entry;
18272 + for(pos = head->next; pos != head; pos = pos->next) {
18273 + entry = list_entry(pos, struct mipv6_sorted_list_entry, list);
18274 + if (compare(data, entry->data, entry->datalen))
18275 + return entry->sortkey;
18282 + * mipv6_slist_get_data - get the data item identified by sortkey
18283 + * @head: list_head of the sorted list
18284 + * @key: sortkey of the item
18286 + * Returns the actual data item, not copy, so don't kfree it
18288 +void *mipv6_slist_get_data(struct list_head *head, unsigned long sortkey)
18290 + struct list_head *pos;
18291 + struct mipv6_sorted_list_entry *entry;
18293 + list_for_each(pos, head) {
18294 + entry = list_entry(pos, struct mipv6_sorted_list_entry, list);
18295 + if (entry->sortkey == sortkey)
18296 + return entry->data;
18303 + * reorder_entry - move an entry to a new position according to sortkey
18304 + * @head: list_head of the sorted list
18305 + * @entry_pos: current place of the entry
18306 + * @key: new sortkey
18308 +static void reorder_entry(struct list_head *head, struct list_head *entry_pos,
18309 + unsigned long sortkey)
18311 + struct list_head *pos;
18312 + struct mipv6_sorted_list_entry *entry;
18314 + list_del(entry_pos);
18316 + for (pos = head->next; pos != head; pos = pos->next) {
18317 + entry = list_entry(pos, struct mipv6_sorted_list_entry, list);
18318 + if (sortkey >= entry->sortkey) {
18319 + list_add(entry_pos, &entry->list);
18324 + list_add(entry_pos, head);
18328 + * mipv6_slist_modify - modify data item
18329 + * @head: list_head of the sorted list
18330 + * @data: item, whose sortkey is to be modified
18331 + * @datalen: datalen in bytes
18332 + * @new_key: new sortkey
18333 + * @compare: function used for comparing the data items
18335 + * Compies the new data on top of the old one, if compare function returns
18336 + * true. If there's no matching entry, new one will be created.
18337 + * Compare function needs to have prototype
18338 + * int (*compare)(const void *data1, const void *data2, int datalen)
18340 +int mipv6_slist_modify(struct list_head *head, void *data, int datalen,
18341 + unsigned long new_key,
18342 + int (*compare)(const void *data1, const void *data2,
18345 + struct list_head *pos;
18346 + struct mipv6_sorted_list_entry *entry;
18348 + for (pos = head->next; pos != head; pos = pos->next) {
18349 + entry = list_entry(pos, struct mipv6_sorted_list_entry, list);
18350 + if (compare(data, entry->data, datalen)) {
18351 + memcpy(entry->data, data, datalen);
18352 + entry->sortkey = new_key;
18353 + reorder_entry(head, &entry->list, new_key);
18358 + return mipv6_slist_add(head, data, datalen, new_key);
18362 + * mipv6_slist_push_first - move the first entry to place indicated by new_key
18363 + * @head: list_head of the sorted list
18364 + * @new_key: new sortkey
18366 +int mipv6_slist_push_first(struct list_head *head, unsigned long new_key)
18368 + struct mipv6_sorted_list_entry *entry;
18370 + if (list_empty(head))
18373 + entry = list_entry(head->next, struct mipv6_sorted_list_entry, list);
18374 + entry->sortkey = new_key;
18376 + reorder_entry(head, head->next, new_key);
18381 + * mipv6_slist_for_each - apply func to every item in list
18382 + * @head: list_head of the sorted list
18383 + * @args: args to pass to func
18384 + * @func: function to use
18386 + * function must be of type
18387 + * int (*func)(void *data, void *args, unsigned long sortkey)
18388 + * List iteration will stop once func has been applied to every item
18389 + * or when func returns true
18391 +int mipv6_slist_for_each(struct list_head *head, void *args,
18392 + int (*func)(void *data, void *args,
18393 + unsigned long sortkey))
18395 + struct list_head *pos;
18396 + struct mipv6_sorted_list_entry *entry;
18398 + list_for_each(pos, head) {
18399 + entry = list_entry(pos, struct mipv6_sorted_list_entry, list);
18400 + if (func(entry->data, args, entry->sortkey))
18406 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/sortedlist.h linux-2.4.25/net/ipv6/mobile_ip6/sortedlist.h
18407 --- linux-2.4.25.old/net/ipv6/mobile_ip6/sortedlist.h 1970-01-01 01:00:00.000000000 +0100
18408 +++ linux-2.4.25/net/ipv6/mobile_ip6/sortedlist.h 2004-06-26 11:29:31.000000000 +0100
18411 + * Sorted list - linked list with sortkey
18415 + * This program is free software; you can redistribute it and/or
18416 + * modify it under the terms of the GNU General Public License
18417 + * as published by the Free Software Foundation; either version
18418 + * 2 of the License, or (at your option) any later version.
18422 + * compare - compares two arbitrary data items
18423 + * @data1: first data item
18424 + * @data2: second data item
18425 + * @datalen: length of data items in bits
18427 + * datalen is in bits!
18429 +int mipv6_bitwise_compare(const void *data1, const void *data2, int datalen);
18432 + * mipv6_slist_add - add an entry to sorted list
18433 + * @head: list_head of the sorted list
18434 + * @data: item to store
18435 + * @datalen: length of data (in bytes)
18436 + * @key: sortkey of item
18438 + * Allocates memory for entry and data
18440 +int mipv6_slist_add(struct list_head *head, void *data, int datalen,
18441 + unsigned long sortkey);
18444 + * mipv6_slist_get_first - get the first data item in the list
18445 + * @head: list_head of the sorted list
18447 + * Returns the actual data item, not copy, so don't kfree it
18449 +void *mipv6_slist_get_first(struct list_head *head);
18452 + * mipv6_slist_del_first - delete (and get) the first item in list
18453 + * @head: list_head of the sorted list
18455 + * Remember to kfree the item
18457 +void *mipv6_slist_del_first(struct list_head *head);
18460 + * mipv6_slist_del_item - delete entry
18461 + * @head: list_head of the sorted list
18462 + * @data: item to delete
18463 + * @compare: function used for comparing the data items
18465 + * compare function needs to have prototype
18466 + * int (*compare)(const void *data1, const void *data2, int datalen) where
18467 + * datalen is in bits
18469 +int mipv6_slist_del_item(struct list_head *head, void *data,
18470 + int (*compare)(const void *data1, const void *data2,
18474 + * mipv6_slist_get_first_key - get sortkey of the first item
18475 + * @head: list_head of the sorted list
18477 +unsigned long mipv6_slist_get_first_key(struct list_head *head);
18480 + * mipv6_slist_get_key - get sortkey of the data item
18481 + * @head: list_head of the sorted list
18482 + * @data: the item to search for
18483 + * @compare: function used for comparing the data items
18485 + * compare function needs to have prototype
18486 + * int (*compare)(const void *data1, const void *data2, int datalen) where
18487 + * datalen is in bits
18489 +unsigned long mipv6_slist_get_key(struct list_head *head, void *data,
18490 + int (*compare)(const void *data1,
18491 + const void *data2,
18495 + * mipv6_slist_get_data - get the data item identified by sortkey
18496 + * @head: list_head of the sorted list
18497 + * @key: sortkey of the item
18499 + * Returns the actual data item, not copy, so don't kfree it
18501 +void *mipv6_slist_get_data(struct list_head *head, unsigned long sortkey);
18504 + * mipv6_slist_modify - modify data item
18505 + * @head: list_head of the sorted list
18506 + * @data: item, whose sortkey is to be modified
18507 + * @datalen: datalen in bytes
18508 + * @new_key: new sortkey
18509 + * @compare: function used for comparing the data items
18511 + * Compies the new data on top of the old one, if compare function returns
18512 + * non-negative. If there's no matching entry, new one will be created.
18513 + * Compare function needs to have prototype
18514 + * int (*compare)(const void *data1, const void *data2, int datalen) where
18515 + * datalen is in bits.
18517 +int mipv6_slist_modify(struct list_head *head, void *data, int datalen,
18518 + unsigned long new_key,
18519 + int (*compare)(const void *data1, const void *data2,
18523 + * mipv6_slist_push_first - move the first entry to place indicated by new_key
18524 + * @head: list_head of the sorted list
18525 + * @new_key: new sortkey
18527 +int mipv6_slist_push_first(struct list_head *head, unsigned long new_key);
18530 + * mipv6_slist_for_each - apply func to every item in list
18531 + * @head: list_head of the sorted list
18532 + * @args: args to pass to func
18533 + * @func: function to use
18535 + * function must be of type
18536 + * int (*func)(void *data, void *args, unsigned long sortkey)
18537 + * List iteration will stop once func has been applied to every item
18538 + * or when func returns true
18540 +int mipv6_slist_for_each(struct list_head *head, void *args,
18541 + int (*func)(void *data, void *args,
18542 + unsigned long sortkey));
18543 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/stats.c linux-2.4.25/net/ipv6/mobile_ip6/stats.c
18544 --- linux-2.4.25.old/net/ipv6/mobile_ip6/stats.c 1970-01-01 01:00:00.000000000 +0100
18545 +++ linux-2.4.25/net/ipv6/mobile_ip6/stats.c 2004-06-26 11:29:32.000000000 +0100
18548 + * Statistics module
18551 + * Sami Kivisaari <skivisaa@cc.hut.fi>
18555 + * This program is free software; you can redistribute it and/or
18556 + * modify it under the terms of the GNU General Public License
18557 + * as published by the Free Software Foundation; either version
18558 + * 2 of the License, or (at your option) any later version.
18562 + * Venkata Jagana : SMP locking fix
18565 +#include <linux/config.h>
18566 +#include <linux/proc_fs.h>
18567 +#include "stats.h"
18569 +struct mipv6_statistics mipv6_stats;
18571 +static int proc_info_dump(
18572 + char *buffer, char **start,
18573 + off_t offset, int length)
18578 + } int_stats[] = {
18579 + {"NEncapsulations", &mipv6_stats.n_encapsulations},
18580 + {"NDecapsulations", &mipv6_stats.n_decapsulations},
18581 + {"NBindRefreshRqsRcvd", &mipv6_stats.n_brr_rcvd},
18582 + {"NHomeTestInitsRcvd", &mipv6_stats.n_hoti_rcvd},
18583 + {"NCareofTestInitsRcvd", &mipv6_stats.n_coti_rcvd},
18584 + {"NHomeTestRcvd", &mipv6_stats.n_hot_rcvd},
18585 + {"NCareofTestRcvd", &mipv6_stats.n_cot_rcvd},
18586 + {"NBindUpdatesRcvd", &mipv6_stats.n_bu_rcvd},
18587 + {"NBindAcksRcvd", &mipv6_stats.n_ba_rcvd},
18588 + {"NBindNAcksRcvd", &mipv6_stats.n_ban_rcvd},
18589 + {"NBindErrorsRcvd", &mipv6_stats.n_be_rcvd},
18590 + {"NBindRefreshRqsSent", &mipv6_stats.n_brr_sent},
18591 + {"NHomeTestInitsSent", &mipv6_stats.n_hoti_sent},
18592 + {"NCareofTestInitsSent", &mipv6_stats.n_coti_sent},
18593 + {"NHomeTestSent", &mipv6_stats.n_hot_sent},
18594 + {"NCareofTestSent", &mipv6_stats.n_cot_sent},
18595 + {"NBindUpdatesSent", &mipv6_stats.n_bu_sent},
18596 + {"NBindAcksSent", &mipv6_stats.n_ba_sent},
18597 + {"NBindNAcksSent", &mipv6_stats.n_ban_sent},
18598 + {"NBindErrorsSent", &mipv6_stats.n_be_sent},
18599 + {"NBindUpdatesDropAuth", &mipv6_stats.n_bu_drop.auth},
18600 + {"NBindUpdatesDropInvalid", &mipv6_stats.n_bu_drop.invalid},
18601 + {"NBindUpdatesDropMisc", &mipv6_stats.n_bu_drop.misc},
18602 + {"NBindAcksDropAuth", &mipv6_stats.n_bu_drop.auth},
18603 + {"NBindAcksDropInvalid", &mipv6_stats.n_bu_drop.invalid},
18604 + {"NBindAcksDropMisc", &mipv6_stats.n_bu_drop.misc},
18605 + {"NBindRqsDropAuth", &mipv6_stats.n_bu_drop.auth},
18606 + {"NBindRqsDropInvalid", &mipv6_stats.n_bu_drop.invalid},
18607 + {"NBindRqsDropMisc", &mipv6_stats.n_bu_drop.misc}
18612 + for(i=0; i<sizeof(int_stats) / sizeof(struct inf); i++) {
18613 + len += sprintf(buffer + len, "%s = %d\n",
18614 + int_stats[i].name, *int_stats[i].value);
18617 + *start = buffer + offset;
18621 + if(len > length) len = length;
18626 +int mipv6_stats_init(void)
18628 + memset(&mipv6_stats, 0, sizeof(struct mipv6_statistics));
18629 + proc_net_create("mip6_stat", 0, proc_info_dump);
18633 +void mipv6_stats_exit(void)
18635 + proc_net_remove("mip6_stat");
18637 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/stats.h linux-2.4.25/net/ipv6/mobile_ip6/stats.h
18638 --- linux-2.4.25.old/net/ipv6/mobile_ip6/stats.h 1970-01-01 01:00:00.000000000 +0100
18639 +++ linux-2.4.25/net/ipv6/mobile_ip6/stats.h 2004-06-26 11:29:32.000000000 +0100
18642 + * MIPL Mobile IPv6 Statistics header file
18646 + * This program is free software; you can redistribute it and/or
18647 + * modify it under the terms of the GNU General Public License
18648 + * as published by the Free Software Foundation; either version
18649 + * 2 of the License, or (at your option) any later version.
18655 +struct mipv6_drop {
18661 +struct mipv6_statistics {
18662 + int n_encapsulations;
18663 + int n_decapsulations;
18665 + int n_mh_in_error;
18666 + int n_mh_out_msg;
18667 + int n_mh_out_error;
18692 + struct mipv6_drop n_bu_drop;
18693 + struct mipv6_drop n_ba_drop;
18694 + struct mipv6_drop n_brr_drop;
18695 + struct mipv6_drop n_be_drop;
18696 + struct mipv6_drop n_ha_drop;
18699 +extern struct mipv6_statistics mipv6_stats;
18702 +/* atomic_t is max 24 bits long */
18703 +#define MIPV6_INC_STATS(X) atomic_inc((atomic_t *)&mipv6_stats.X);
18705 +#define MIPV6_INC_STATS(X) mipv6_stats.X++;
18708 +int mipv6_stats_init(void);
18709 +void mipv6_stats_exit(void);
18712 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/tunnel.h linux-2.4.25/net/ipv6/mobile_ip6/tunnel.h
18713 --- linux-2.4.25.old/net/ipv6/mobile_ip6/tunnel.h 1970-01-01 01:00:00.000000000 +0100
18714 +++ linux-2.4.25/net/ipv6/mobile_ip6/tunnel.h 2004-06-26 11:29:32.000000000 +0100
18717 + * MIPL Mobile IPv6 IP6-IP6 tunneling header file
18721 + * This program is free software; you can redistribute it and/or
18722 + * modify it under the terms of the GNU General Public License
18723 + * as published by the Free Software Foundation; either version
18724 + * 2 of the License, or (at your option) any later version.
18730 +#include <linux/in6.h>
18731 +#include <linux/if_arp.h>
18732 +#include <net/ipv6_tunnel.h>
18734 +static __inline__ int is_mip6_tnl(struct ip6_tnl *t)
18736 + return (t != NULL &&
18737 + t->parms.flags & IP6_TNL_F_KERNEL_DEV &&
18738 + t->parms.flags & IP6_TNL_F_MIP6_DEV);
18742 +static __inline__ int dev_is_mip6_tnl(struct net_device *dev)
18744 + struct ip6_tnl *t = (struct ip6_tnl *)dev->priv;
18745 + return (dev->type == ARPHRD_TUNNEL6 && is_mip6_tnl(t));
18751 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/tunnel_ha.c linux-2.4.25/net/ipv6/mobile_ip6/tunnel_ha.c
18752 --- linux-2.4.25.old/net/ipv6/mobile_ip6/tunnel_ha.c 1970-01-01 01:00:00.000000000 +0100
18753 +++ linux-2.4.25/net/ipv6/mobile_ip6/tunnel_ha.c 2004-06-26 11:29:32.000000000 +0100
18756 + * IPv6-IPv6 tunneling module
18759 + * Sami Kivisaari <skivisaa@cc.hut.fi>
18760 + * Ville Nuorvala <vnuorval@tml.hut.fi>
18764 + * This program is free software; you can redistribute it and/or
18765 + * modify it under the terms of the GNU General Public License
18766 + * as published by the Free Software Foundation; either version
18767 + * 2 of the License, or (at your option) any later version.
18771 +#include <linux/net.h>
18772 +#include <linux/skbuff.h>
18773 +#include <linux/ipv6.h>
18774 +#include <linux/net.h>
18775 +#include <linux/netdevice.h>
18776 +#include <linux/init.h>
18777 +#include <linux/route.h>
18778 +#include <linux/ipv6_route.h>
18780 +#ifdef CONFIG_SYSCTL
18781 +#include <linux/sysctl.h>
18782 +#endif /* CONFIG_SYSCTL */
18784 +#include <net/protocol.h>
18785 +#include <net/ipv6.h>
18786 +#include <net/ip6_route.h>
18787 +#include <net/dst.h>
18788 +#include <net/addrconf.h>
18790 +#include "tunnel.h"
18791 +#include "debug.h"
18792 +#include "stats.h"
18793 +#include "config.h"
18795 +#define MIPV6_TNL_MAX IP6_TNL_MAX
18796 +#define MIPV6_TNL_MIN 1
18798 +int mipv6_max_tnls = 3;
18799 +int mipv6_min_tnls = 1;
18801 +DECLARE_MUTEX(tnl_sem);
18803 +int mipv6_max_tnls_sysctl(ctl_table *ctl, int write, struct file *filp,
18804 + void *buffer, size_t *lenp)
18813 + int old_max_tnls = mipv6_max_tnls;
18814 + err = proc_dointvec(ctl, write, filp, buffer, lenp);
18817 + if (mipv6_max_tnls < mipv6_min_tnls ||
18818 + mipv6_max_tnls > MIPV6_TNL_MAX) {
18819 + mipv6_max_tnls = old_max_tnls;
18822 + if (mipv6_max_tnls < old_max_tnls) {
18823 + diff = old_max_tnls - mipv6_max_tnls;
18824 + ip6ip6_tnl_dec_max_kdev_count(diff);
18825 + } else if (mipv6_max_tnls > old_max_tnls) {
18826 + diff = mipv6_max_tnls - old_max_tnls;
18827 + ip6ip6_tnl_inc_max_kdev_count(diff);
18830 + err = proc_dointvec(ctl, write, filp, buffer, lenp);
18837 +int mipv6_min_tnls_sysctl(ctl_table *ctl, int write, struct file *filp,
18838 + void *buffer, size_t *lenp)
18847 + int old_min_tnls = mipv6_min_tnls;
18848 + err = proc_dointvec(ctl, write, filp, buffer, lenp);
18851 + if (mipv6_min_tnls > mipv6_max_tnls ||
18852 + mipv6_min_tnls < MIPV6_TNL_MIN) {
18853 + mipv6_min_tnls = old_min_tnls;
18856 + if (mipv6_min_tnls < old_min_tnls) {
18857 + diff = old_min_tnls - mipv6_min_tnls;
18858 + ip6ip6_tnl_dec_min_kdev_count(diff);
18859 + } else if (mipv6_min_tnls > old_min_tnls) {
18860 + diff = mipv6_min_tnls - old_min_tnls;
18861 + ip6ip6_tnl_inc_min_kdev_count(diff);
18864 + err = proc_dointvec(ctl, write, filp, buffer, lenp);
18871 +static __inline__ int mipv6_tnl_add(struct in6_addr *remote,
18872 + struct in6_addr *local)
18874 + struct ip6_tnl_parm p;
18879 + memset(&p, 0, sizeof(p));
18880 + p.proto = IPPROTO_IPV6;
18881 + ipv6_addr_copy(&p.laddr, local);
18882 + ipv6_addr_copy(&p.raddr, remote);
18883 + p.hop_limit = 255;
18884 + p.flags = (IP6_TNL_F_KERNEL_DEV | IP6_TNL_F_MIP6_DEV |
18885 + IP6_TNL_F_IGN_ENCAP_LIMIT);
18887 + ret = ip6ip6_kernel_tnl_add(&p);
18889 + DEBUG(DBG_INFO, "added tunnel from: "
18890 + "%x:%x:%x:%x:%x:%x:%x:%x to: %x:%x:%x:%x:%x:%x:%x:%x",
18891 + NIPV6ADDR(local), NIPV6ADDR(remote));
18893 + DEBUG(DBG_WARNING, "unable to add tunnel from: "
18894 + "%x:%x:%x:%x:%x:%x:%x:%x to: %x:%x:%x:%x:%x:%x:%x:%x",
18895 + NIPV6ADDR(local), NIPV6ADDR(remote));
18900 +static __inline__ int mipv6_tnl_del(struct in6_addr *remote,
18901 + struct in6_addr *local)
18903 + struct ip6_tnl *t = ip6ip6_tnl_lookup(remote, local);
18907 + if (t != NULL && (t->parms.flags & IP6_TNL_F_MIP6_DEV)) {
18908 + DEBUG(DBG_INFO, "deleting tunnel from: "
18909 + "%x:%x:%x:%x:%x:%x:%x:%x to: %x:%x:%x:%x:%x:%x:%x:%x",
18910 + NIPV6ADDR(local), NIPV6ADDR(remote));
18912 + return ip6ip6_kernel_tnl_del(t);
18917 +static int add_route_to_mn(struct in6_addr *coa, struct in6_addr *ha_addr,
18918 + struct in6_addr *home_addr)
18920 + struct in6_rtmsg rtmsg;
18922 + struct ip6_tnl *t = ip6ip6_tnl_lookup(coa, ha_addr);
18924 + if (!is_mip6_tnl(t)) {
18925 + DEBUG(DBG_CRITICAL,"Tunnel missing");
18929 + DEBUG(DBG_INFO, "adding route to: %x:%x:%x:%x:%x:%x:%x:%x via "
18930 + "tunnel device", NIPV6ADDR(home_addr));
18932 + memset(&rtmsg, 0, sizeof(rtmsg));
18933 + ipv6_addr_copy(&rtmsg.rtmsg_dst, home_addr);
18934 + rtmsg.rtmsg_dst_len = 128;
18935 + rtmsg.rtmsg_type = RTMSG_NEWROUTE;
18936 + rtmsg.rtmsg_flags = RTF_UP | RTF_NONEXTHOP | RTF_HOST | RTF_MOBILENODE;
18937 + rtmsg.rtmsg_ifindex = t->dev->ifindex;
18938 + rtmsg.rtmsg_metric = IP6_RT_PRIO_MIPV6;
18939 + if ((err = ip6_route_add(&rtmsg, NULL)) == -EEXIST) {
18945 +static void del_route_to_mn(struct in6_addr *coa, struct in6_addr *ha_addr,
18946 + struct in6_addr *home_addr)
18948 + struct ip6_tnl *t = ip6ip6_tnl_lookup(coa, ha_addr);
18952 + if (is_mip6_tnl(t)) {
18953 + struct in6_rtmsg rtmsg;
18955 + DEBUG(DBG_INFO, "deleting route to: %x:%x:%x:%x:%x:%x:%x:%x "
18956 + " via tunnel device", NIPV6ADDR(home_addr));
18958 + memset(&rtmsg, 0, sizeof(rtmsg));
18959 + ipv6_addr_copy(&rtmsg.rtmsg_dst, home_addr);
18960 + rtmsg.rtmsg_dst_len = 128;
18961 + rtmsg.rtmsg_ifindex = t->dev->ifindex;
18962 + rtmsg.rtmsg_metric = IP6_RT_PRIO_MIPV6;
18963 + ip6_route_del(&rtmsg, NULL);
18968 +int mipv6_add_tnl_to_mn(struct in6_addr *coa,
18969 + struct in6_addr *ha_addr,
18970 + struct in6_addr *home_addr)
18976 + ret = mipv6_tnl_add(coa, ha_addr);
18979 + int err = add_route_to_mn(coa, ha_addr, home_addr);
18981 + if (err != -ENODEV) {
18982 + mipv6_tnl_del(coa, ha_addr);
18990 +int mipv6_del_tnl_to_mn(struct in6_addr *coa,
18991 + struct in6_addr *ha_addr,
18992 + struct in6_addr *home_addr)
18995 + del_route_to_mn(coa, ha_addr, home_addr);
18996 + return mipv6_tnl_del(coa, ha_addr);
18999 +__init void mipv6_initialize_tunnel(void)
19002 + ip6ip6_tnl_inc_max_kdev_count(mipv6_max_tnls);
19003 + ip6ip6_tnl_inc_min_kdev_count(mipv6_min_tnls);
19005 + mip6_fn.bce_tnl_rt_add = add_route_to_mn;
19006 + mip6_fn.bce_tnl_rt_del = del_route_to_mn;
19009 +__exit void mipv6_shutdown_tunnel(void)
19011 + mip6_fn.bce_tnl_rt_del = NULL;
19012 + mip6_fn.bce_tnl_rt_add = NULL;
19014 + ip6ip6_tnl_dec_min_kdev_count(mipv6_min_tnls);
19015 + ip6ip6_tnl_dec_max_kdev_count(mipv6_max_tnls);
19019 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/tunnel_ha.h linux-2.4.25/net/ipv6/mobile_ip6/tunnel_ha.h
19020 --- linux-2.4.25.old/net/ipv6/mobile_ip6/tunnel_ha.h 1970-01-01 01:00:00.000000000 +0100
19021 +++ linux-2.4.25/net/ipv6/mobile_ip6/tunnel_ha.h 2004-06-26 11:29:32.000000000 +0100
19023 +#ifndef _TUNNEL_HA_H
19024 +#define _TUNNEL_HA_H
19026 +#include "tunnel.h"
19028 +extern int mipv6_max_tnls;
19029 +extern int mipv6_min_tnls;
19031 +extern void mipv6_initialize_tunnel(void);
19032 +extern void mipv6_shutdown_tunnel(void);
19034 +extern int mipv6_add_tnl_to_mn(struct in6_addr *coa,
19035 + struct in6_addr *ha_addr,
19036 + struct in6_addr *home_addr);
19038 +extern int mipv6_del_tnl_to_mn(struct in6_addr *coa,
19039 + struct in6_addr *ha_addr,
19040 + struct in6_addr *home_addr);
19043 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/tunnel_mn.c linux-2.4.25/net/ipv6/mobile_ip6/tunnel_mn.c
19044 --- linux-2.4.25.old/net/ipv6/mobile_ip6/tunnel_mn.c 1970-01-01 01:00:00.000000000 +0100
19045 +++ linux-2.4.25/net/ipv6/mobile_ip6/tunnel_mn.c 2004-06-26 11:29:32.000000000 +0100
19048 + * IPv6-IPv6 tunneling module
19051 + * Sami Kivisaari <skivisaa@cc.hut.fi>
19052 + * Ville Nuorvala <vnuorval@tml.hut.fi>
19056 + * This program is free software; you can redistribute it and/or
19057 + * modify it under the terms of the GNU General Public License
19058 + * as published by the Free Software Foundation; either version
19059 + * 2 of the License, or (at your option) any later version.
19063 +#include <linux/net.h>
19064 +#include <linux/skbuff.h>
19065 +#include <linux/ipv6.h>
19066 +#include <linux/net.h>
19067 +#include <linux/netdevice.h>
19068 +#include <linux/init.h>
19069 +#include <linux/route.h>
19070 +#include <linux/ipv6_route.h>
19072 +#ifdef CONFIG_SYSCTL
19073 +#include <linux/sysctl.h>
19074 +#endif /* CONFIG_SYSCTL */
19076 +#include <net/protocol.h>
19077 +#include <net/ipv6.h>
19078 +#include <net/ip6_route.h>
19079 +#include <net/dst.h>
19080 +#include <net/addrconf.h>
19082 +#include "tunnel.h"
19083 +#include "debug.h"
19084 +#include "stats.h"
19086 +static struct net_device *mn_ha_tdev;
19088 +static spinlock_t mn_ha_lock = SPIN_LOCK_UNLOCKED;
19090 +static __inline__ int add_reverse_route(struct in6_addr *ha_addr,
19091 + struct in6_addr *home_addr,
19092 + struct net_device *tdev)
19094 + struct in6_rtmsg rtmsg;
19099 + memset(&rtmsg, 0, sizeof(rtmsg));
19100 + rtmsg.rtmsg_type = RTMSG_NEWROUTE;
19101 + ipv6_addr_copy(&rtmsg.rtmsg_src, home_addr);
19102 + rtmsg.rtmsg_src_len = 128;
19103 + rtmsg.rtmsg_flags = RTF_UP | RTF_DEFAULT;
19104 + rtmsg.rtmsg_ifindex = tdev->ifindex;
19105 + rtmsg.rtmsg_metric = IP6_RT_PRIO_MIPV6;
19106 + if ((err = ip6_route_add(&rtmsg, NULL)) == -EEXIST) {
19112 +static __inline__ void del_reverse_route(struct in6_addr *ha_addr,
19113 + struct in6_addr *home_addr,
19114 + struct net_device *tdev)
19116 + struct in6_rtmsg rtmsg;
19118 + DEBUG(DBG_INFO, "removing reverse route via tunnel device");
19120 + memset(&rtmsg, 0, sizeof(rtmsg));
19121 + ipv6_addr_copy(&rtmsg.rtmsg_src, home_addr);
19122 + rtmsg.rtmsg_src_len = 128;
19123 + rtmsg.rtmsg_ifindex = tdev->ifindex;
19124 + rtmsg.rtmsg_metric = IP6_RT_PRIO_MIPV6;
19125 + ip6_route_del(&rtmsg, NULL);
19128 +int mipv6_add_tnl_to_ha(void)
19130 + struct ip6_tnl_parm p;
19131 + struct ip6_tnl *t;
19136 + memset(&p, 0, sizeof(p));
19137 + p.proto = IPPROTO_IPV6;
19138 + p.hop_limit = 255;
19139 + p.flags = (IP6_TNL_F_KERNEL_DEV | IP6_TNL_F_MIP6_DEV |
19140 + IP6_TNL_F_IGN_ENCAP_LIMIT);
19141 + strcpy(p.name, "mip6mnha1");
19144 + if ((err = ip6ip6_tnl_create(&p, &t))) {
19148 + spin_lock_bh(&mn_ha_lock);
19150 + if (!mn_ha_tdev) {
19151 + mn_ha_tdev = t->dev;
19152 + dev_hold(mn_ha_tdev);
19154 + spin_unlock_bh(&mn_ha_lock);
19155 + dev_open(t->dev);
19160 +int mipv6_mv_tnl_to_ha(struct in6_addr *ha_addr,
19161 + struct in6_addr *coa,
19162 + struct in6_addr *home_addr)
19164 + int err = -ENODEV;
19168 + spin_lock_bh(&mn_ha_lock);
19169 + if (mn_ha_tdev) {
19170 + struct ip6_tnl_parm p;
19171 + memset(&p, 0, sizeof(p));
19172 + p.proto = IPPROTO_IPV6;
19173 + ipv6_addr_copy(&p.laddr, coa);
19174 + ipv6_addr_copy(&p.raddr, ha_addr);
19175 + p.hop_limit = 255;
19176 + p.flags = (IP6_TNL_F_KERNEL_DEV | IP6_TNL_F_MIP6_DEV |
19177 + IP6_TNL_F_IGN_ENCAP_LIMIT);
19179 + ip6ip6_tnl_change((struct ip6_tnl *) mn_ha_tdev->priv, &p);
19180 + if (ipv6_addr_cmp(coa, home_addr)) {
19181 + err = add_reverse_route(ha_addr, home_addr,
19184 + del_reverse_route(ha_addr, home_addr, mn_ha_tdev);
19188 + spin_unlock_bh(&mn_ha_lock);
19192 +void mipv6_del_tnl_to_ha(void)
19194 + struct net_device *dev;
19199 + spin_lock_bh(&mn_ha_lock);
19200 + dev = mn_ha_tdev;
19201 + mn_ha_tdev = NULL;
19202 + spin_unlock_bh(&mn_ha_lock);
19204 + unregister_netdevice(dev);
19207 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/tunnel_mn.h linux-2.4.25/net/ipv6/mobile_ip6/tunnel_mn.h
19208 --- linux-2.4.25.old/net/ipv6/mobile_ip6/tunnel_mn.h 1970-01-01 01:00:00.000000000 +0100
19209 +++ linux-2.4.25/net/ipv6/mobile_ip6/tunnel_mn.h 2004-06-26 11:29:32.000000000 +0100
19211 +#ifndef _TUNNEL_MN_H
19212 +#define _TUNNEL_MN_H
19214 +#include "tunnel.h"
19216 +extern int mipv6_add_tnl_to_ha(void);
19218 +extern int mipv6_mv_tnl_to_ha(struct in6_addr *ha_addr,
19219 + struct in6_addr *coa,
19220 + struct in6_addr *home_addr);
19222 +extern int mipv6_del_tnl_to_ha(void);
19225 diff -uprN linux-2.4.25.old/net/ipv6/mobile_ip6/util.h linux-2.4.25/net/ipv6/mobile_ip6/util.h
19226 --- linux-2.4.25.old/net/ipv6/mobile_ip6/util.h 1970-01-01 01:00:00.000000000 +0100
19227 +++ linux-2.4.25/net/ipv6/mobile_ip6/util.h 2004-06-26 11:29:32.000000000 +0100
19230 + * MIPL Mobile IPv6 Utility functions
19234 + * This program is free software; you can redistribute it and/or
19235 + * modify it under the terms of the GNU General Public License
19236 + * as published by the Free Software Foundation; either version
19237 + * 2 of the License, or (at your option) any later version.
19243 +#include <linux/in6.h>
19244 +#include <asm/byteorder.h>
19247 + * mipv6_prefix_compare - Compare two IPv6 prefixes
19248 + * @addr: IPv6 address
19249 + * @prefix: IPv6 address
19250 + * @nprefix: number of bits to compare
19252 + * Perform prefix comparison bitwise for the @nprefix first bits
19253 + * Returns 1, if the prefixes are the same, 0 otherwise
19255 +static inline int mipv6_prefix_compare(const struct in6_addr *addr,
19256 + const struct in6_addr *prefix,
19257 + const unsigned int pfix_len)
19260 + unsigned int nprefix = pfix_len;
19262 + if (nprefix > 128)
19265 + for (i = 0; nprefix > 0; nprefix -= 32, i++) {
19266 + if (nprefix >= 32) {
19267 + if (addr->s6_addr32[i] != prefix->s6_addr32[i])
19270 + if (((addr->s6_addr32[i] ^ prefix->s6_addr32[i]) &
19271 + ((~0) << (32 - nprefix))) != 0)
19281 + * homeagent_anycast - Compute Home Agent anycast address
19282 + * @ac_addr: append home agent anycast suffix to passed prefix
19283 + * @prefix: prefix ha anycast address is generated from
19284 + * @plen: length of prefix in bits
19286 + * Calculate corresponding Home Agent Anycast Address (RFC2526) in a
19290 +mipv6_ha_anycast(struct in6_addr *ac_addr, struct in6_addr *prefix, int plen)
19292 + if (plen <= 0 || plen > 120) {
19293 + /* error, interface id should be minimum 8 bits */
19296 + ipv6_addr_copy(ac_addr, prefix);
19299 + ac_addr->s6_addr32[0] |= htonl((u32)(~0) >> plen);
19301 + ac_addr->s6_addr32[1] |= htonl((u32)(~0) >> (plen > 32 ? plen % 32 : 0));
19303 + ac_addr->s6_addr32[2] |= htonl((u32)(~0) >> (plen > 64 ? plen % 32 : 0));
19305 + ac_addr->s6_addr32[3] |= htonl((u32)(~0) >> (plen > 92 ? plen % 32 : 0));
19307 + /* RFC2526: for interface identifiers in EUI-64
19308 + * format, the universal/local bit in the interface
19309 + * identifier MUST be set to 0. */
19310 + if (plen == 64) {
19311 + ac_addr->s6_addr32[2] &= (int)htonl(0xfdffffff);
19313 + /* Mobile IPv6 Home-Agents anycast id (0x7e) */
19314 + ac_addr->s6_addr32[3] &= (int)htonl(0xfffffffe);
19319 +#endif /* _UTIL_H */
19320 diff -uprN linux-2.4.25.old/net/ipv6/ndisc.c linux-2.4.25/net/ipv6/ndisc.c
19321 --- linux-2.4.25.old/net/ipv6/ndisc.c 2003-11-28 18:26:21.000000000 +0000
19322 +++ linux-2.4.25/net/ipv6/ndisc.c 2004-06-26 11:29:32.000000000 +0100
19324 * and moved to net/core.
19325 * Pekka Savola : RFC2461 validation
19326 * YOSHIFUJI Hideaki @USAGI : Verify ND options properly
19327 + * Ville Nuorvala : RFC2461 fixes to proxy ND
19330 /* Set to 3 to get tracing... */
19332 #include <net/ip6_route.h>
19333 #include <net/addrconf.h>
19334 #include <net/icmp.h>
19335 +#include <net/mipglue.h>
19337 #include <net/checksum.h>
19338 #include <linux/proc_fs.h>
19339 @@ -187,6 +189,8 @@ struct ndisc_options *ndisc_parse_option
19340 case ND_OPT_TARGET_LL_ADDR:
19342 case ND_OPT_REDIRECT_HDR:
19343 + case ND_OPT_RTR_ADV_INTERVAL:
19344 + case ND_OPT_HOME_AGENT_INFO:
19345 if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) {
19346 ND_PRINTK2((KERN_WARNING
19347 "ndisc_parse_options(): duplicated ND6 option found: type=%d\n",
19348 @@ -372,8 +376,8 @@ ndisc_build_ll_hdr(struct sk_buff *skb,
19351 void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
19352 - struct in6_addr *daddr, struct in6_addr *solicited_addr,
19353 - int router, int solicited, int override, int inc_opt)
19354 + struct in6_addr *daddr, struct in6_addr *solicited_addr,
19355 + int router, int solicited, int override, int inc_opt)
19357 static struct in6_addr tmpaddr;
19358 struct inet6_ifaddr *ifp;
19359 @@ -766,7 +770,8 @@ void ndisc_recv_ns(struct sk_buff *skb)
19360 int addr_type = ipv6_addr_type(saddr);
19362 if (in6_dev && in6_dev->cnf.forwarding &&
19363 - (addr_type & IPV6_ADDR_UNICAST) &&
19364 + (addr_type & IPV6_ADDR_UNICAST ||
19365 + addr_type == IPV6_ADDR_ANY) &&
19366 pneigh_lookup(&nd_tbl, &msg->target, dev, 0)) {
19367 int inc = ipv6_addr_type(daddr)&IPV6_ADDR_MULTICAST;
19369 @@ -778,13 +783,21 @@ void ndisc_recv_ns(struct sk_buff *skb)
19370 nd_tbl.stats.rcv_probes_mcast++;
19372 nd_tbl.stats.rcv_probes_ucast++;
19374 - neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, dev);
19377 - ndisc_send_na(dev, neigh, saddr, &msg->target,
19379 - neigh_release(neigh);
19380 + if (addr_type & IPV6_ADDR_UNICAST) {
19381 + neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, dev);
19384 + ndisc_send_na(dev, neigh, saddr, &msg->target,
19386 + neigh_release(neigh);
19389 + /* the proxy should also protect against DAD */
19390 + struct in6_addr maddr;
19391 + ipv6_addr_all_nodes(&maddr);
19392 + ndisc_send_na(dev, NULL, &maddr, &msg->target,
19396 struct sk_buff *n = skb_clone(skb, GFP_ATOMIC);
19397 @@ -849,6 +862,9 @@ void ndisc_recv_na(struct sk_buff *skb)
19398 if (ifp->flags & IFA_F_TENTATIVE) {
19399 addrconf_dad_failure(ifp);
19401 + } else if (ndisc_mip_mn_ha_probe(ifp, lladdr)) {
19402 + in6_ifa_put(ifp);
19405 /* What should we make now? The advertisement
19406 is invalid, but ndisc specs say nothing
19407 @@ -887,6 +903,7 @@ void ndisc_recv_na(struct sk_buff *skb)
19408 msg->icmph.icmp6_override, 1);
19409 neigh_release(neigh);
19411 + ndisc_check_mipv6_dad(&msg->target);
19414 static void ndisc_router_discovery(struct sk_buff *skb)
19415 @@ -894,6 +911,7 @@ static void ndisc_router_discovery(struc
19416 struct ra_msg *ra_msg = (struct ra_msg *) skb->h.raw;
19417 struct neighbour *neigh;
19418 struct inet6_dev *in6_dev;
19420 struct rt6_info *rt;
19422 struct ndisc_options ndopts;
19423 @@ -923,10 +941,6 @@ static void ndisc_router_discovery(struc
19424 ND_PRINTK1("RA: can't find in6 device\n");
19427 - if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_ra) {
19428 - in6_dev_put(in6_dev);
19432 if (!ndisc_parse_options(opt, optlen, &ndopts)) {
19433 in6_dev_put(in6_dev);
19434 @@ -935,7 +949,12 @@ static void ndisc_router_discovery(struc
19435 "ICMP6 RA: invalid ND option, ignored.\n");
19438 + change_rtr = ndisc_mipv6_ra_rcv(skb, &ndopts);
19440 + if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_ra) {
19441 + in6_dev_put(in6_dev);
19444 if (in6_dev->if_flags & IF_RS_SENT) {
19446 * flag that an RA was received after an RS was sent
19447 @@ -963,8 +982,7 @@ static void ndisc_router_discovery(struc
19448 ip6_del_rt(rt, NULL);
19452 - if (rt == NULL && lifetime) {
19453 + if (rt == NULL && lifetime && change_rtr) {
19454 ND_PRINTK2("ndisc_rdisc: adding default router\n");
19456 rt = rt6_add_dflt_router(&skb->nh.ipv6h->saddr, skb->dev);
19457 @@ -1087,6 +1105,8 @@ out:
19459 dst_release(&rt->u.dst);
19460 in6_dev_put(in6_dev);
19462 + ndisc_mipv6_change_router(change_rtr);
19465 static void ndisc_redirect_rcv(struct sk_buff *skb)
19466 diff -uprN linux-2.4.25.old/net/ipv6/raw.c linux-2.4.25/net/ipv6/raw.c
19467 --- linux-2.4.25.old/net/ipv6/raw.c 2003-11-28 18:26:21.000000000 +0000
19468 +++ linux-2.4.25/net/ipv6/raw.c 2004-06-26 11:29:32.000000000 +0100
19470 #include <net/transp_v6.h>
19471 #include <net/udp.h>
19472 #include <net/inet_common.h>
19473 +#include <net/mipglue.h>
19475 #include <net/rawv6.h>
19477 @@ -636,6 +637,7 @@ static int rawv6_sendmsg(struct sock *sk
19481 + hdr.daddr = mipv6_get_fake_hdr_daddr(hdr.daddr, daddr);
19483 err = ip6_build_xmit(sk, rawv6_frag_cksum, &hdr, &fl, len,
19484 opt, hlimit, msg->msg_flags);
19485 diff -uprN linux-2.4.25.old/net/ipv6/route.c linux-2.4.25/net/ipv6/route.c
19486 --- linux-2.4.25.old/net/ipv6/route.c 2004-02-18 13:36:32.000000000 +0000
19487 +++ linux-2.4.25/net/ipv6/route.c 2004-06-26 11:29:32.000000000 +0100
19489 #include <net/addrconf.h>
19490 #include <net/tcp.h>
19491 #include <linux/rtnetlink.h>
19492 +#include <net/mipglue.h>
19494 #include <asm/uaccess.h>
19496 @@ -363,12 +364,8 @@ static struct rt6_info *rt6_cow(struct r
19497 rt->u.dst.flags |= DST_HOST;
19499 #ifdef CONFIG_IPV6_SUBTREES
19500 - if (rt->rt6i_src.plen && saddr) {
19501 - ipv6_addr_copy(&rt->rt6i_src.addr, saddr);
19502 - rt->rt6i_src.plen = 128;
19504 + rt->rt6i_src.plen = ort->rt6i_src.plen;
19507 rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway);
19509 dst_hold(&rt->u.dst);
19510 @@ -511,14 +508,19 @@ struct dst_entry * ip6_route_output(stru
19511 struct rt6_info *rt;
19514 + struct in6_addr *saddr;
19516 + if (ipv6_chk_addr(fl->nl_u.ip6_u.daddr, NULL))
19519 + saddr = fl->nl_u.ip6_u.saddr;
19521 strict = ipv6_addr_type(fl->nl_u.ip6_u.daddr) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL);
19524 read_lock_bh(&rt6_lock);
19526 - fn = fib6_lookup(&ip6_routing_table, fl->nl_u.ip6_u.daddr,
19527 - fl->nl_u.ip6_u.saddr);
19528 + fn = fib6_lookup(&ip6_routing_table, fl->nl_u.ip6_u.daddr, saddr);
19532 @@ -663,25 +665,6 @@ out:
19533 return (atomic_read(&ip6_dst_ops.entries) > ip6_rt_max_size);
19536 -/* Clean host part of a prefix. Not necessary in radix tree,
19537 - but results in cleaner routing tables.
19539 - Remove it only when all the things will work!
19542 -static void ipv6_addr_prefix(struct in6_addr *pfx,
19543 - const struct in6_addr *addr, int plen)
19545 - int b = plen&0x7;
19548 - memcpy(pfx->s6_addr, addr, o);
19550 - memset(pfx->s6_addr + o, 0, 16 - o);
19552 - pfx->s6_addr[o] = addr->s6_addr[o]&(0xff00 >> b);
19555 static int ipv6_get_mtu(struct net_device *dev)
19557 int mtu = IPV6_MIN_MTU;
19558 @@ -810,7 +793,7 @@ int ip6_route_add(struct in6_rtmsg *rtms
19559 if (!(gwa_type&IPV6_ADDR_UNICAST))
19562 - grt = rt6_lookup(gw_addr, NULL, rtmsg->rtmsg_ifindex, 1);
19563 + grt = rt6_lookup(gw_addr, &rtmsg->rtmsg_src, rtmsg->rtmsg_ifindex, 1);
19565 err = -EHOSTUNREACH;
19567 @@ -848,7 +831,15 @@ int ip6_route_add(struct in6_rtmsg *rtms
19572 +#ifdef USE_IPV6_MOBILITY
19573 + /* If destination is mobile node, add special skb->dst->input
19574 + * function for proxy ND.
19576 + if (rtmsg->rtmsg_flags & RTF_MOBILENODE) {
19577 + rt->u.dst.input = ip6_mipv6_forward;
19579 +#endif /* CONFIG_IPV6_MOBILITY */
19581 if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr))
19582 rt->rt6i_hoplimit = IPV6_DEFAULT_MCASTHOPS;
19584 @@ -936,7 +927,7 @@ void rt6_redirect(struct in6_addr *dest,
19585 struct rt6_info *rt, *nrt;
19587 /* Locate old route to this destination. */
19588 - rt = rt6_lookup(dest, NULL, neigh->dev->ifindex, 1);
19589 + rt = rt6_lookup(dest, saddr, neigh->dev->ifindex, 1);
19593 @@ -1003,6 +994,9 @@ source_ok:
19594 nrt = ip6_rt_copy(rt);
19597 +#ifdef CONFIG_IPV6_SUBTREES
19598 + nrt->rt6i_src.plen = rt->rt6i_src.plen;
19601 nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
19603 @@ -1104,6 +1098,9 @@ void rt6_pmtu_discovery(struct in6_addr
19604 nrt = ip6_rt_copy(rt);
19607 +#ifdef CONFIG_IPV6_SUBTREES
19608 + nrt->rt6i_src.plen = rt->rt6i_src.plen;
19610 ipv6_addr_copy(&nrt->rt6i_dst.addr, daddr);
19611 nrt->rt6i_dst.plen = 128;
19612 nrt->u.dst.flags |= DST_HOST;
19613 diff -uprN linux-2.4.25.old/net/ipv6/tcp_ipv6.c linux-2.4.25/net/ipv6/tcp_ipv6.c
19614 --- linux-2.4.25.old/net/ipv6/tcp_ipv6.c 2003-11-28 18:26:21.000000000 +0000
19615 +++ linux-2.4.25/net/ipv6/tcp_ipv6.c 2004-06-26 11:29:32.000000000 +0100
19617 #include <net/addrconf.h>
19618 #include <net/ip6_route.h>
19619 #include <net/inet_ecn.h>
19620 +#include <net/mipglue.h>
19622 #include <asm/uaccess.h>
19624 @@ -557,6 +558,7 @@ static int tcp_v6_connect(struct sock *s
19626 struct dst_entry *dst;
19631 if (addr_len < SIN6_LEN_RFC2133)
19632 @@ -660,7 +662,7 @@ static int tcp_v6_connect(struct sock *s
19634 fl.proto = IPPROTO_TCP;
19635 fl.fl6_dst = &np->daddr;
19636 - fl.fl6_src = saddr;
19637 + fl.fl6_src = saddr;
19638 fl.oif = sk->bound_dev_if;
19639 fl.uli_u.ports.dport = usin->sin6_port;
19640 fl.uli_u.ports.sport = sk->sport;
19641 @@ -669,31 +671,46 @@ static int tcp_v6_connect(struct sock *s
19642 struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
19643 fl.nl_u.ip6_u.daddr = rt0->addr;
19646 dst = ip6_route_output(sk, &fl);
19648 +#ifdef CONFIG_IPV6_SUBTREES
19649 + reroute = (saddr == NULL);
19651 if ((err = dst->error) != 0) {
19656 - ip6_dst_store(sk, dst, NULL);
19657 - sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM;
19660 + ip6_dst_store(sk, dst, NULL, NULL);
19661 + sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM;
19663 if (saddr == NULL) {
19664 err = ipv6_get_saddr(dst, &np->daddr, &saddr_buf);
19667 + dst_release(dst);
19671 saddr = &saddr_buf;
19672 + ipv6_addr_copy(&np->rcv_saddr, saddr);
19673 +#ifdef CONFIG_IPV6_SUBTREES
19674 + fl.fl6_src = saddr;
19675 + dst = ip6_route_output(sk, &fl);
19677 + if ((err = dst->error) != 0) {
19678 + dst_release(dst);
19681 + ip6_dst_store(sk, dst, NULL, NULL);
19682 + sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM;
19686 /* set the source address */
19687 - ipv6_addr_copy(&np->rcv_saddr, saddr);
19688 ipv6_addr_copy(&np->saddr, saddr);
19689 sk->rcv_saddr= LOOPBACK4_IPV6;
19691 - tp->ext_header_len = 0;
19692 + tp->ext_header_len = tcp_v6_get_mipv6_header_len();
19694 tp->ext_header_len = np->opt->opt_flen+np->opt->opt_nflen;
19695 tp->mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
19696 @@ -1338,7 +1355,7 @@ static struct sock * tcp_v6_syn_recv_soc
19700 - ip6_dst_store(newsk, dst, NULL);
19701 + ip6_dst_store(newsk, dst, NULL, NULL);
19702 sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM;
19704 newtp = &(newsk->tp_pinfo.af_tcp);
19705 @@ -1383,7 +1400,7 @@ static struct sock * tcp_v6_syn_recv_soc
19706 sock_kfree_s(sk, opt, opt->tot_len);
19709 - newtp->ext_header_len = 0;
19710 + newtp->ext_header_len = tcp_v6_get_mipv6_header_len();
19712 newtp->ext_header_len = np->opt->opt_nflen + np->opt->opt_flen;
19714 @@ -1710,7 +1727,7 @@ static int tcp_v6_rebuild_header(struct
19718 - ip6_dst_store(sk, dst, NULL);
19719 + ip6_dst_store(sk, dst, NULL, NULL);
19720 sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM;
19723 @@ -1749,7 +1766,7 @@ static int tcp_v6_xmit(struct sk_buff *s
19724 return -sk->err_soft;
19727 - ip6_dst_store(sk, dst, NULL);
19728 + ip6_dst_store(sk, dst, NULL, NULL);
19731 skb->dst = dst_clone(dst);
19732 diff -uprN linux-2.4.25.old/net/ipv6/udp.c linux-2.4.25/net/ipv6/udp.c
19733 --- linux-2.4.25.old/net/ipv6/udp.c 2004-02-18 13:36:32.000000000 +0000
19734 +++ linux-2.4.25/net/ipv6/udp.c 2004-06-26 11:29:32.000000000 +0100
19736 #include <net/ip.h>
19737 #include <net/udp.h>
19738 #include <net/inet_common.h>
19739 +#include <net/mipglue.h>
19741 #include <net/checksum.h>
19743 @@ -232,6 +233,7 @@ int udpv6_connect(struct sock *sk, struc
19744 struct ip6_flowlabel *flowlabel = NULL;
19749 if (usin->sin6_family == AF_INET) {
19750 if (__ipv6_only_sock(sk))
19751 @@ -331,7 +333,7 @@ ipv4_connected:
19753 fl.proto = IPPROTO_UDP;
19754 fl.fl6_dst = &np->daddr;
19755 - fl.fl6_src = &saddr;
19756 + fl.fl6_src = NULL;
19757 fl.oif = sk->bound_dev_if;
19758 fl.uli_u.ports.dport = sk->dport;
19759 fl.uli_u.ports.sport = sk->sport;
19760 @@ -348,29 +350,44 @@ ipv4_connected:
19761 struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
19762 fl.fl6_dst = rt0->addr;
19765 dst = ip6_route_output(sk, &fl);
19767 if ((err = dst->error) != 0) {
19769 fl6_sock_release(flowlabel);
19773 - ip6_dst_store(sk, dst, fl.fl6_dst);
19777 +#ifdef CONFIG_IPV6_SUBTREES
19778 + reroute = (fl.fl6_src == NULL);
19780 /* get the source adddress used in the apropriate device */
19782 err = ipv6_get_saddr(dst, daddr, &saddr);
19785 + dst_release(dst);
19788 - if(ipv6_addr_any(&np->saddr))
19789 +#ifdef CONFIG_IPV6_SUBTREES
19791 + fl.fl6_src = &saddr;
19792 + dst = ip6_route_output(sk, &fl);
19793 + if ((err = dst->error) != 0) {
19794 + dst_release(dst);
19795 + fl6_sock_release(flowlabel);
19800 + if(ipv6_addr_any(&np->saddr)) {
19801 ipv6_addr_copy(&np->saddr, &saddr);
19803 + fl.fl6_src = &np->saddr;
19805 if(ipv6_addr_any(&np->rcv_saddr)) {
19806 ipv6_addr_copy(&np->rcv_saddr, &saddr);
19807 sk->rcv_saddr = LOOPBACK4_IPV6;
19809 + ip6_dst_store(sk, dst, fl.fl6_dst,
19810 + fl.fl6_src == &np->saddr ? fl.fl6_src : NULL);
19811 sk->state = TCP_ESTABLISHED;
19813 fl6_sock_release(flowlabel);
19814 @@ -894,6 +911,7 @@ static int udpv6_sendmsg(struct sock *sk
19815 opt = fl6_merge_options(&opt_space, flowlabel, opt);
19816 if (opt && opt->srcrt)
19818 + udh.daddr = mipv6_get_fake_hdr_daddr(udh.daddr, daddr);
19820 udh.uh.source = sk->sport;
19821 udh.uh.len = len < 0x10000 ? htons(len) : 0;
19822 diff -uprN linux-2.4.25.old/net/netsyms.c linux-2.4.25/net/netsyms.c
19823 --- linux-2.4.25.old/net/netsyms.c 2003-11-28 18:26:21.000000000 +0000
19824 +++ linux-2.4.25/net/netsyms.c 2004-06-26 11:29:32.000000000 +0100
19825 @@ -190,6 +190,7 @@ EXPORT_SYMBOL(neigh_sysctl_register);
19827 EXPORT_SYMBOL(pneigh_lookup);
19828 EXPORT_SYMBOL(pneigh_enqueue);
19829 +EXPORT_SYMBOL(pneigh_delete);
19830 EXPORT_SYMBOL(neigh_destroy);
19831 EXPORT_SYMBOL(neigh_parms_alloc);
19832 EXPORT_SYMBOL(neigh_parms_release);