]> pilppa.org Git - familiar-h63xx-build.git/blob - org.handhelds.familiar/packages/linux/files/mipv6-1.1-v2.4.27.patch
OE tree imported from monotone branch org.openembedded.oz354fam083 at revision 8b12e3...
[familiar-h63xx-build.git] / org.handhelds.familiar / packages / linux / files / mipv6-1.1-v2.4.27.patch
1
2 #
3 # Patch managed by http://www.holgerschurig.de/patcher.html
4 #
5
6 --- linux-2.4.27/Documentation/Configure.help~mipv6-1.1-v2.4.26
7 +++ linux-2.4.27/Documentation/Configure.help
8 @@ -6308,6 +6308,57 @@
9  
10    It is safe to say N here for now.
11  
12 +IPv6: IPv6 over IPv6 Tunneling (EXPERIMENTAL)
13 +CONFIG_IPV6_TUNNEL
14 +  Experimental IP6-IP6 tunneling.  You must select this, if you want
15 +  to use CONFIG_IPV6_MOBILITY.  More information in MIPL Mobile IPv6
16 +  instructions.
17 +
18 +  If you don't want IP6-IP6 tunnels and Mobile IPv6, say N.
19 +
20 +IPv6: Mobility Support (EXPERIMENTAL)
21 +CONFIG_IPV6_MOBILITY
22 +  This is experimental support for the upcoming specification of
23 +  Mobile IPv6. Mobile IPv6 allows nodes to seamlessly move between
24 +  networks without changing their IP addresses, thus allowing them to
25 +  maintain upper layer connections (e.g. TCP).  Selecting this option
26 +  allows your computer to act as a Correspondent Node (CN).  A MIPv6
27 +  Mobile Node will be able to communicate with the CN and use route
28 +  optimization.
29 +
30 +  For more information and configuration details, see
31 +  http://www.mipl.mediapoli.com/.
32 +
33 +  If unsure, say N.
34 +
35 +MIPv6: Mobile Node Support
36 +CONFIG_IPV6_MOBILITY_MN
37 +  If you want your computer to be a MIPv6 Mobile Node (MN), select
38 +  this option.  You must configure MN using the userspace tools
39 +  available at http://www.mipl.mediapoli.com/download/mipv6-tools/.
40 +
41 +  If your computer is stationary, or you are unsure if you need this,
42 +  say N.  Note that you will need a properly configured MIPv6 Home
43 +  Agent to use any Mobile Nodes.
44 +
45 +MIPv6: Home Agent Support
46 +CONFIG_IPV6_MOBILITY_HA
47 +  If you want your router to serve as a MIPv6 Home Agent (HA), select
48 +  this option.  You must configure HA using the userspace tools
49 +  available at http://www.mipl.mediapoli.com/download/mipv6-tools/.
50 +
51 +  If your computer is not a router, or you are unsure if you need
52 +  this, say N.
53 +
54 +MIPv6: Debug messages
55 +CONFIG_IPV6_MOBILITY_DEBUG
56 +  MIPL Mobile IPv6 can produce a lot of debugging messages. There are
57 +  eight debug levels (0 through 7) and the level is controlled via
58 +  /proc/sys/net/ipv6/mobility/debuglevel. Since MIPL is still
59 +  experimental, you might want to say Y here.
60 +
61 +  Be sure to say Y and record debug messages when submitting a bug
62 +  report.
63  The SCTP Protocol (EXPERIMENTAL)
64  CONFIG_IP_SCTP
65    Stream Control Transmission Protocol
66 --- linux-2.4.27/Documentation/DocBook/Makefile~mipv6-1.1-v2.4.26
67 +++ linux-2.4.27/Documentation/DocBook/Makefile
68 @@ -2,7 +2,7 @@
69            kernel-api.sgml parportbook.sgml kernel-hacking.sgml \
70            kernel-locking.sgml via-audio.sgml mousedrivers.sgml sis900.sgml \
71            deviceiobook.sgml procfs-guide.sgml tulip-user.sgml \
72 -          journal-api.sgml libata.sgml
73 +          journal-api.sgml libata.sgml mip6-func.sgml
74  
75  PS     :=      $(patsubst %.sgml, %.ps, $(BOOKS))
76  PDF    :=      $(patsubst %.sgml, %.pdf, $(BOOKS))
77 @@ -96,6 +96,9 @@
78  procfs-guide.sgml:  procfs-guide.tmpl procfs_example.sgml
79         $(TOPDIR)/scripts/docgen < procfs-guide.tmpl >$@
80  
81 +mip6-func.sgml: mip6-func.tmpl
82 +       $(TOPDIR)/scripts/docgen <$< >$@
83 +
84  APISOURCES :=  $(TOPDIR)/drivers/media/video/videodev.c \
85                 $(TOPDIR)/arch/i386/kernel/irq.c \
86                 $(TOPDIR)/arch/i386/kernel/mca.c \
87 --- /dev/null
88 +++ linux-2.4.27/Documentation/DocBook/mip6-func.tmpl
89 @@ -0,0 +1,756 @@
90 +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
91 +<book id="LinuxMobileIPv6">
92 + <bookinfo>
93 +  <title>MIPL Mobile IPv6 Function Reference Guide</title>
94 +
95 +  <authorgroup>
96 +    <author>
97 +      <othername>MIPL Mobile IPv6 for Linux Team</othername>
98 +      <affiliation>
99 +       <orgname>Helsinki University of Technology</orgname>
100 +       <orgdiv>Telecommunications Software and Multimedia Lab</orgdiv>
101 +       <address>
102 +        <pob>PO BOX 9201</pob>
103 +       <postcode>FIN-02015 HUT</postcode>
104 +       <country>Finland</country>
105 +        <email>mipl@list.mipl.mediapoli.com</email>
106 +       </address>
107 +      </affiliation>
108 +     </author>
109 +  </authorgroup>
110 +
111 +  <copyright>
112 +   <year>2000-2001</year>
113 +   <holder>Helsinki University of Technology</holder>
114 +  </copyright>
115
116 +  <legalnotice>
117 +   <para>
118 +     Copyright (c) 2001, 2002 MIPL Mobile IPv6 for Linux Team.
119 +   </para>
120 +   <para>
121 +     Permission is granted to copy, distribute and/or modify this
122 +     document under the terms of the GNU Free Documentation License,
123 +     Version 1.1 published by the Free Software Foundation; with the
124 +     Invariant Sections being "Introduction", with the Front-Cover
125 +     Texts being "MIPL Mobile IPv6 Function Reference Guide", "MIPL
126 +     Mobile IPv6 for Linux Team" and "Helsinki University of
127 +     Technology".  A copy of the license is included in <xref
128 +     linkend="gfdl">.
129 +   </para>
130 +      
131 +  </legalnotice>
132 + </bookinfo>
133 +
134 +<toc></toc>
135 +
136 +  <preface id="intro">
137 +     <title>Introduction</title>
138 +
139 +     <para>
140 +       MIPL Mobile IPv6 for Linux is an implementation of Mobility
141 +       Support in IPv6 IETF mobile-ip working groups Internet-Draft
142 +       (draft-ietf-mobileip-ipv6).  This implementation has been
143 +       developed in the Telecommunications Software and Multimedia
144 +       Laboratory at Helsinki University of Technology.
145 +     </para>
146 +
147 +     <para>
148 +       MIPL is fully open source, licensed under the GNU General
149 +       Public License.  Latest source for MIPL can be downloaded from
150 +       the MIPL website at:
151 +     </para>
152 +     <programlisting>
153 +       http://www.mipl.mediapoli.com/.
154 +     </programlisting>
155 +     <para>
156 +       Developers and users interested in MIPL can subscribe to the
157 +       MIPL mailing list by sending e-mail to
158 +       <email>majordomo@list.mipl.mediapoli.com</email> with
159 +     </para>
160 +     <programlisting>
161 +       subscribe mipl
162 +     </programlisting>
163 +     <para>
164 +       in the body of the message.
165 +     </para>
166 +
167 +     <para>
168 +       This document is a reference guide to MIPL functions.  Intended
169 +       audience is developers wishing to contribute to the project.
170 +       Hopefully this document will make it easier and quicker to
171 +       understand and adopt the inner workings of MIPL Mobile IPv6.
172 +     </para>
173 +
174 +     <para>
175 +       MIPL Mobile IPv6 for Linux Team members (past and present):
176 +
177 +       <itemizedlist>
178 +        <listitem>
179 +       <address>
180 +       Sami Kivisaari <email>Sami.Kivisaari@hut.fi</email>
181 +       </address>
182 +        </listitem>
183 +        <listitem>
184 +       <address>
185 +       Niklas Kampe <email>Niklas.Kampe@hut.fi</email>
186 +       </address>
187 +        </listitem>
188 +        <listitem>
189 +       <address>
190 +       Juha Mynttinen <email>Juha.Mynttinen@hut.fi</email>
191 +       </address>
192 +        </listitem>
193 +        <listitem>
194 +       <address>
195 +       Toni Nykanen <email>Toni.Nykanen@iki.fi</email>
196 +       </address>
197 +        </listitem>
198 +        <listitem>
199 +       <address>
200 +       Henrik Petander <email>Henrik.Petander@hut.fi</email>
201 +       </address>
202 +        </listitem>
203 +        <listitem>
204 +       <address>
205 +       Antti Tuominen <email>ajtuomin@tml.hut.fi</email>
206 +       </address>
207 +        </listitem>
208 +       </itemizedlist>
209 +
210 +       <itemizedlist>
211 +        <listitem>
212 +       <address>
213 +       Marko Myllynen
214 +       </address>
215 +        </listitem>
216 +        <listitem>
217 +       <address>
218 +       Ville Nuorvala <email>vnuorval@tcs.hut.fi</email>
219 +       </address>
220 +        </listitem>
221 +        <listitem>
222 +       <address>
223 +       Jaakko Laine <email>Jaakko.Laine@hut.fi</email>
224 +       </address>
225 +        </listitem>
226 +       </itemizedlist>
227 +     </para>
228 +
229 +  </preface>
230 +
231 +  <chapter id="common">
232 +     <title>Common functions for all entities</title>
233 +
234 +     <sect1><title>Low-level functions</title>
235 +     <para>
236 +       These functions implement memory allocation used by others.
237 +       Hashlist functions implement a linked list with hash lookup,
238 +       which is used with Binding Update List, Binding Cache, Home
239 +       Agents List etc.
240 +     </para>
241 +!Inet/ipv6/mobile_ip6/mempool.h
242 +!Inet/ipv6/mobile_ip6/hashlist.h
243 +     </sect1>
244 +
245 +     <sect1><title>Debug functions</title>
246 +     <para>
247 +       Debug and utility functions.  These functions are available if
248 +       <constant>CONFIG_IPV6_MOBILITY_DEBUG</constant> is set.
249 +       Otherwise macros expand to no operation.
250 +     </para>
251 +!Inet/ipv6/mobile_ip6/debug.h
252 +!Inet/ipv6/mobile_ip6/mipv6.c
253 +     </sect1>
254 +
255 +     <sect1><title>Extension Header functions</title>
256 +     <para>
257 +       These functions create and handle extension headers that are
258 +       specific to MIPv6.
259 +     </para>
260 +!Inet/ipv6/mobile_ip6/exthdrs.c
261 +     </sect1>
262 +
263 +     <sect1><title>Mobility Header functions</title>
264 +     <para>
265 +       MIPv6 specifies a new protocol called Mobility Header.
266 +       Mobility Header has several message types.  Messages may also
267 +       carry Mobility Options.  These functions are used to create and
268 +       handle Mobility Headers and Mobility Options.
269 +     </para>
270 +!Inet/ipv6/mobile_ip6/sendopts.c
271 +!Inet/ipv6/mobile_ip6/mh_recv.c
272 +!Inet/ipv6/mobile_ip6/auth_subopt.c
273 +     </sect1>
274 +
275 +     <sect1><title>Binding Cache</title>
276 +     <para>
277 +       All Mobile IPv6 entities have a binding cache.  These functions
278 +       provide easy manipulation of the binding cache.
279 +     </para>
280 +!Inet/ipv6/mobile_ip6/bcache.c
281 +     </sect1>
282 +
283 +     <sect1><title>Security</title>
284 +
285 +     <para>
286 +       These functions are common authentication functions and
287 +       implement Draft 13 style IPSec AH support for Binding Updates.
288 +     </para>
289 +!Inet/ipv6/mobile_ip6/ah_algo.c
290 +!Inet/ipv6/mobile_ip6/sadb.c
291 +!Inet/ipv6/mobile_ip6/ah.c
292 +     </sect1>
293 +
294 +     <sect1><title>Utility functions</title>
295 +
296 +     <para>
297 +       These functions are general utility functions commonly used by
298 +       all entities.
299 +     </para>
300 +!Inet/ipv6/mobile_ip6/util.c
301 +     </sect1>
302 +
303 +  </chapter>
304 +
305 +  <chapter id="mn">
306 +     <title>Mobile Node functions</title>
307 +     <sect1><title>General functions</title>
308 +     <para>
309 +     </para>
310 +!Inet/ipv6/mobile_ip6/mn.c
311 +     </sect1>
312 +
313 +     <sect1><title>Binding Update List</title>
314 +     <para>
315 +       Mobile Node keeps track of sent binding updates in Binding
316 +       Update List.
317 +     </para>
318 +!Inet/ipv6/mobile_ip6/bul.c
319 +     </sect1>
320 +
321 +     <sect1><title>Movement detection</title>
322 +
323 +     <para>
324 +       These functions are used by the mobile node for movement
325 +       detection.
326 +     </para>
327 +!Inet/ipv6/mobile_ip6/mdetect.c
328 +     </sect1>
329 +  </chapter>
330 +
331 +  <chapter id="ha">
332 +     <title>Home Agent functions</title>
333 +     <sect1><title>General functions</title>
334 +     <para>
335 +     </para>
336 +!Inet/ipv6/mobile_ip6/ha.c
337 +     </sect1>
338 +
339 +     <sect1><title>Duplicate Address Detection functions</title>
340 +     <para>
341 +       Home Agent does Duplicate Address Detection for Mobile Nodes'
342 +       addresses.  These functions implement MIPv6 specific DAD
343 +       functionality.
344 +     </para>
345 +!Inet/ipv6/mobile_ip6/dad.c
346 +     </sect1>
347 +
348 +  </chapter>
349 +  <appendix id="gfdl">
350 +     <title>GNU Free Documentation License</title>
351 +
352 +     <para>
353 +       Version 1.1, March 2000
354 +     </para>
355 +
356 +     <programlisting>
357 +       Copyright (C) 2000  Free Software Foundation, Inc.
358 +       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
359 +       Everyone is permitted to copy and distribute verbatim copies
360 +       of this license document, but changing it is not allowed.
361 +     </programlisting>
362 +
363 +     <sect1><title>0. PREAMBLE</title>
364 +
365 +     <para>
366 +       The purpose of this License is to make a manual, textbook, or
367 +       other written document "free" in the sense of freedom: to
368 +       assure everyone the effective freedom to copy and redistribute
369 +       it, with or without modifying it, either commercially or
370 +       noncommercially. Secondarily, this License preserves for the
371 +       author and publisher a way to get credit for their work, while
372 +       not being considered responsible for modifications made by
373 +       others.
374 +     </para>
375 +
376 +     <para>
377 +       This License is a kind of "copyleft", which means that
378 +       derivative works of the document must themselves be free in the
379 +       same sense. It complements the GNU General Public License,
380 +       which is a copyleft license designed for free software.
381 +     </para>
382 +
383 +     <para>
384 +       We have designed this License in order to use it for manuals
385 +       for free software, because free software needs free
386 +       documentation: a free program should come with manuals
387 +       providing the same freedoms that the software does. But this
388 +       License is not limited to software manuals; it can be used for
389 +       any textual work, regardless of subject matter or whether it is
390 +       published as a printed book. We recommend this License
391 +       principally for works whose purpose is instruction or
392 +       reference.
393 +     </para>
394 +
395 +     </sect1>
396 +     <sect1><title>1. APPLICABILITY AND DEFINITIONS</title>
397 +
398 +     <para>
399 +       This License applies to any manual or other work that contains
400 +       a notice placed by the copyright holder saying it can be
401 +       distributed under the terms of this License. The "Document",
402 +       below, refers to any such manual or work. Any member of the
403 +       public is a licensee, and is addressed as "you".
404 +     </para>
405 +
406 +     <para>
407 +       A "Modified Version" of the Document means any work containing
408 +       the Document or a portion of it, either copied verbatim, or
409 +       with modifications and/or translated into another language.
410 +     </para>
411 +
412 +     <para>
413 +       A "Secondary Section" is a named appendix or a front-matter
414 +       section of the Document that deals exclusively with the
415 +       relationship of the publishers or authors of the Document to
416 +       the Document's overall subject (or to related matters) and
417 +       contains nothing that could fall directly within that overall
418 +       subject. (For example, if the Document is in part a textbook of
419 +       mathematics, a Secondary Section may not explain any
420 +       mathematics.) The relationship could be a matter of historical
421 +       connection with the subject or with related matters, or of
422 +       legal, commercial, philosophical, ethical or political position
423 +       regarding them.
424 +     </para>
425 +
426 +     <para>
427 +       The "Invariant Sections" are certain Secondary Sections whose
428 +       titles are designated, as being those of Invariant Sections, in
429 +       the notice that says that the Document is released under this
430 +       License.
431 +     </para>
432 +
433 +     <para>
434 +       The "Cover Texts" are certain short passages of text that are
435 +       listed, as Front-Cover Texts or Back-Cover Texts, in the notice
436 +       that says that the Document is released under this License.
437 +     </para>
438 +
439 +     <para>
440 +       A "Transparent" copy of the Document means a machine-readable
441 +       copy, represented in a format whose specification is available
442 +       to the general public, whose contents can be viewed and edited
443 +       directly and straightforwardly with generic text editors or
444 +       (for images composed of pixels) generic paint programs or (for
445 +       drawings) some widely available drawing editor, and that is
446 +       suitable for input to text formatters or for automatic
447 +       translation to a variety of formats suitable for input to text
448 +       formatters. A copy made in an otherwise Transparent file format
449 +       whose markup has been designed to thwart or discourage
450 +       subsequent modification by readers is not Transparent. A copy
451 +       that is not "Transparent" is called "Opaque".
452 +     </para>
453 +
454 +     <para>
455 +       Examples of suitable formats for Transparent copies include
456 +       plain ASCII without markup, Texinfo input format, LaTeX input
457 +       format, SGML or XML using a publicly available DTD, and
458 +       standard-conforming simple HTML designed for human
459 +       modification. Opaque formats include PostScript, PDF,
460 +       proprietary formats that can be read and edited only by
461 +       proprietary word processors, SGML or XML for which the DTD
462 +       and/or processing tools are not generally available, and the
463 +       machine-generated HTML produced by some word processors for
464 +       output purposes only.
465 +     </para>
466 +
467 +     <para>
468 +       The "Title Page" means, for a printed book, the title page
469 +       itself, plus such following pages as are needed to hold,
470 +       legibly, the material this License requires to appear in the
471 +       title page. For works in formats which do not have any title
472 +       page as such, "Title Page" means the text near the most
473 +       prominent appearance of the work's title, preceding the
474 +       beginning of the body of the text.
475 +     </para>
476 +
477 +     </sect1>
478 +     <sect1><title>2. VERBATIM COPYING</title>
479 +
480 +     <para>
481 +       You may copy and distribute the Document in any medium, either
482 +       commercially or noncommercially, provided that this License,
483 +       the copyright notices, and the license notice saying this
484 +       License applies to the Document are reproduced in all copies,
485 +       and that you add no other conditions whatsoever to those of
486 +       this License. You may not use technical measures to obstruct or
487 +       control the reading or further copying of the copies you make
488 +       or distribute. However, you may accept compensation in exchange
489 +       for copies. If you distribute a large enough number of copies
490 +       you must also follow the conditions in section 3.
491 +     </para>
492 +
493 +     <para>
494 +       You may also lend copies, under the same conditions stated
495 +       above, and you may publicly display copies.
496 +     </para>
497 +
498 +     </sect1>
499 +     <sect1><title>3. COPYING IN QUANTITY</title>
500 +
501 +     <para>
502 +       If you publish printed copies of the Document numbering more
503 +       than 100, and the Document's license notice requires Cover
504 +       Texts, you must enclose the copies in covers that carry,
505 +       clearly and legibly, all these Cover Texts: Front-Cover Texts
506 +       on the front cover, and Back-Cover Texts on the back
507 +       cover. Both covers must also clearly and legibly identify you
508 +       as the publisher of these copies. The front cover must present
509 +       the full title with all words of the title equally prominent
510 +       and visible. You may add other material on the covers in
511 +       addition. Copying with changes limited to the covers, as long
512 +       as they preserve the title of the Document and satisfy these
513 +       conditions, can be treated as verbatim copying in other
514 +       respects.
515 +     </para>
516 +
517 +     <para>
518 +       If the required texts for either cover are too voluminous to
519 +       fit legibly, you should put the first ones listed (as many as
520 +       fit reasonably) on the actual cover, and continue the rest onto
521 +       adjacent pages.
522 +     </para>
523 +
524 +     <para>
525 +       If you publish or distribute Opaque copies of the Document
526 +       numbering more than 100, you must either include a
527 +       machine-readable Transparent copy along with each Opaque copy,
528 +       or state in or with each Opaque copy a publicly-accessible
529 +       computer-network location containing a complete Transparent
530 +       copy of the Document, free of added material, which the general
531 +       network-using public has access to download anonymously at no
532 +       charge using public-standard network protocols. If you use the
533 +       latter option, you must take reasonably prudent steps, when you
534 +       begin distribution of Opaque copies in quantity, to ensure that
535 +       this Transparent copy will remain thus accessible at the stated
536 +       location until at least one year after the last time you
537 +       distribute an Opaque copy (directly or through your agents or
538 +       retailers) of that edition to the public.
539 +     </para>
540 +
541 +     <para>
542 +       It is requested, but not required, that you contact the authors
543 +       of the Document well before redistributing any large number of
544 +       copies, to give them a chance to provide you with an updated
545 +       version of the Document.
546 +     </para>
547 +
548 +     </sect1>
549 +     <sect1><title>4. MODIFICATIONS</title>
550 +
551 +     <para>
552 +       You may copy and distribute a Modified Version of the Document
553 +       under the conditions of sections 2 and 3 above, provided that
554 +       you release the Modified Version under precisely this License,
555 +       with the Modified Version filling the role of the Document,
556 +       thus licensing distribution and modification of the Modified
557 +       Version to whoever possesses a copy of it. In addition, you
558 +       must do these things in the Modified Version:
559 +     </para>
560 +
561 +     <para>
562 +      <itemizedlist spacing=compact>
563 +       <listitem>
564 +        <para>
565 +        A. Use in the Title Page (and on the covers, if any) a title
566 +        distinct from that of the Document, and from those of previous
567 +        versions (which should, if there were any, be listed in the
568 +        History section of the Document). You may use the same title
569 +        as a previous version if the original publisher of that
570 +        version gives permission.
571 +       </para>
572 +       </listitem>
573 +       <listitem>
574 +        <para>
575 +       B. List on the Title Page, as authors, one or more persons
576 +       or entities responsible for authorship of the modifications in
577 +       the Modified Version, together with at least five of the
578 +       principal authors of the Document (all of its principal
579 +       authors, if it has less than five).
580 +       </para>
581 +       </listitem>
582 +       <listitem>
583 +        <para>
584 +       C. State on the Title page the name of the publisher of the
585 +       Modified Version, as the publisher.
586 +       </para>
587 +       </listitem>
588 +       <listitem>
589 +        <para>
590 +       D. Preserve all the copyright notices of the Document.
591 +       </para>
592 +       </listitem>
593 +       <listitem>
594 +        <para>
595 +       E. Add an appropriate copyright notice for your
596 +       modifications adjacent to the other copyright notices.
597 +       </para>
598 +       </listitem>
599 +       <listitem>
600 +        <para>
601 +       F. Include, immediately after the copyright notices, a
602 +       license notice giving the public permission to use the
603 +       Modified Version under the terms of this License, in the form
604 +       shown in the Addendum below.
605 +       </para>
606 +       </listitem>
607 +       <listitem>
608 +        <para>
609 +       G. Preserve in that license notice the full lists of
610 +       Invariant Sections and required Cover Texts given in the
611 +       Document's license notice.
612 +       </para>
613 +       </listitem>
614 +       <listitem>
615 +        <para>
616 +       H. Include an unaltered copy of this License.
617 +       </para>
618 +       </listitem>
619 +       <listitem>
620 +        <para>
621 +       I. Preserve the section entitled "History", and its title,
622 +       and add to it an item stating at least the title, year, new
623 +       authors, and publisher of the Modified Version as given on the
624 +       Title Page. If there is no section entitled "History" in the
625 +       Document, create one stating the title, year, authors, and
626 +       publisher of the Document as given on its Title Page, then add
627 +       an item describing the Modified Version as stated in the
628 +       previous sentence.
629 +       </para>
630 +       </listitem>
631 +       <listitem>
632 +        <para>
633 +        J. Preserve the network location, if any, given in the
634 +        Document for public access to a Transparent copy of the
635 +        Document, and likewise the network locations given in the
636 +        Document for previous versions it was based on. These may be
637 +        placed in the "History" section. You may omit a network
638 +        location for a work that was published at least four years
639 +        before the Document itself, or if the original publisher of
640 +        the version it refers to gives permission.
641 +       </para>
642 +       </listitem>
643 +       <listitem>
644 +        <para>
645 +        K. In any section entitled "Acknowledgements" or
646 +        "Dedications", preserve the section's title, and preserve in
647 +        the section all the substance and tone of each of the
648 +        contributor acknowledgements and/or dedications given therein.
649 +       </para>
650 +       </listitem>
651 +       <listitem>
652 +        <para>
653 +       L. Preserve all the Invariant Sections of the Document,
654 +       unaltered in their text and in their titles. Section numbers
655 +       or the equivalent are not considered part of the section
656 +       titles.
657 +       </para>
658 +       </listitem>
659 +       <listitem>
660 +        <para>
661 +       M. Delete any section entitled "Endorsements". Such a
662 +       section may not be included in the Modified Version.
663 +       </para>
664 +       </listitem>
665 +       <listitem>
666 +        <para>
667 +       N. Do not retitle any existing section as "Endorsements" or
668 +       to conflict in title with any Invariant Section.
669 +       </para>
670 +       </listitem>
671 +      </itemizedlist>
672 +     </para>
673 +
674 +     <para>
675 +       If the Modified Version includes new front-matter sections or
676 +       appendices that qualify as Secondary Sections and contain no
677 +       material copied from the Document, you may at your option
678 +       designate some or all of these sections as invariant. To do
679 +       this, add their titles to the list of Invariant Sections in the
680 +       Modified Version's license notice. These titles must be
681 +       distinct from any other section titles.
682 +     </para>
683 +
684 +     <para>
685 +       You may add a section entitled "Endorsements", provided it
686 +       contains nothing but endorsements of your Modified Version by
687 +       various parties--for example, statements of peer review or that
688 +       the text has been approved by an organization as the
689 +       authoritative definition of a standard.
690 +     </para>
691 +
692 +     <para>
693 +       You may add a passage of up to five words as a Front-Cover
694 +       Text, and a passage of up to 25 words as a Back-Cover Text, to
695 +       the end of the list of Cover Texts in the Modified
696 +       Version. Only one passage of Front-Cover Text and one of
697 +       Back-Cover Text may be added by (or through arrangements made
698 +       by) any one entity. If the Document already includes a cover
699 +       text for the same cover, previously added by you or by
700 +       arrangement made by the same entity you are acting on behalf
701 +       of, you may not add another; but you may replace the old one,
702 +       on explicit permission from the previous publisher that added
703 +       the old one.
704 +     </para>
705 +
706 +     <para>
707 +       The author(s) and publisher(s) of the Document do not by this
708 +       License give permission to use their names for publicity for or
709 +       to assert or imply endorsement of any Modified Version.
710 +     </para>
711 +
712 +     </sect1>
713 +     <sect1><title>5. COMBINING DOCUMENTS</title>
714 +
715 +     <para>
716 +       You may combine the Document with other documents released
717 +       under this License, under the terms defined in section 4 above
718 +       for modified versions, provided that you include in the
719 +       combination all of the Invariant Sections of all of the
720 +       original documents, unmodified, and list them all as Invariant
721 +       Sections of your combined work in its license notice.
722 +     </para>
723 +
724 +     <para>
725 +       The combined work need only contain one copy of this License,
726 +       and multiple identical Invariant Sections may be replaced with
727 +       a single copy. If there are multiple Invariant Sections with
728 +       the same name but different contents, make the title of each
729 +       such section unique by adding at the end of it, in parentheses,
730 +       the name of the original author or publisher of that section if
731 +       known, or else a unique number. Make the same adjustment to the
732 +       section titles in the list of Invariant Sections in the license
733 +       notice of the combined work.
734 +     </para>
735 +
736 +     <para>
737 +       In the combination, you must combine any sections entitled
738 +       "History" in the various original documents, forming one
739 +       section entitled "History"; likewise combine any sections
740 +       entitled "Acknowledgements", and any sections entitled
741 +       "Dedications". You must delete all sections entitled
742 +       "Endorsements."
743 +     </para>
744 +
745 +     </sect1>
746 +     <sect1><title>6. COLLECTIONS OF DOCUMENTS</title>
747 +
748 +     <para>
749 +       You may make a collection consisting of the Document and other
750 +       documents released under this License, and replace the
751 +       individual copies of this License in the various documents with
752 +       a single copy that is included in the collection, provided that
753 +       you follow the rules of this License for verbatim copying of
754 +       each of the documents in all other respects.
755 +     </para>
756 +
757 +     <para>
758 +       You may extract a single document from such a collection, and
759 +       distribute it individually under this License, provided you
760 +       insert a copy of this License into the extracted document, and
761 +       follow this License in all other respects regarding verbatim
762 +       copying of that document.
763 +     </para>
764 +
765 +     </sect1>
766 +     <sect1><title>7. AGGREGATION WITH INDEPENDENT WORKS</title>
767 +
768 +     <para>
769 +       A compilation of the Document or its derivatives with other
770 +       separate and independent documents or works, in or on a volume
771 +       of a storage or distribution medium, does not as a whole count
772 +       as a Modified Version of the Document, provided no compilation
773 +       copyright is claimed for the compilation. Such a compilation is
774 +       called an "aggregate", and this License does not apply to the
775 +       other self-contained works thus compiled with the Document, on
776 +       account of their being thus compiled, if they are not
777 +       themselves derivative works of the Document.
778 +     </para>
779 +
780 +     <para>
781 +       If the Cover Text requirement of section 3 is applicable to
782 +       these copies of the Document, then if the Document is less than
783 +       one quarter of the entire aggregate, the Document's Cover Texts
784 +       may be placed on covers that surround only the Document within
785 +       the aggregate. Otherwise they must appear on covers around the
786 +       whole aggregate.
787 +     </para>
788 +
789 +     </sect1>
790 +     <sect1><title>8. TRANSLATION</title>
791 +
792 +     <para>
793 +       Translation is considered a kind of modification, so you may
794 +       distribute translations of the Document under the terms of
795 +       section 4. Replacing Invariant Sections with translations
796 +       requires special permission from their copyright holders, but
797 +       you may include translations of some or all Invariant Sections
798 +       in addition to the original versions of these Invariant
799 +       Sections. You may include a translation of this License
800 +       provided that you also include the original English version of
801 +       this License. In case of a disagreement between the translation
802 +       and the original English version of this License, the original
803 +       English version will prevail.
804 +     </para>
805 +
806 +     </sect1>
807 +     <sect1><title>9. TERMINATION</title>
808 +
809 +     <para>
810 +       You may not copy, modify, sublicense, or distribute the
811 +       Document except as expressly provided for under this
812 +       License. Any other attempt to copy, modify, sublicense or
813 +       distribute the Document is void, and will automatically
814 +       terminate your rights under this License. However, parties who
815 +       have received copies, or rights, from you under this License
816 +       will not have their licenses terminated so long as such parties
817 +       remain in full compliance.
818 +     </para>
819 +
820 +     </sect1>
821 +     <sect1><title>10. FUTURE REVISIONS OF THIS LICENSE</title>
822 +
823 +     <para>
824 +       The Free Software Foundation may publish new, revised versions
825 +       of the GNU Free Documentation License from time to time. Such
826 +       new versions will be similar in spirit to the present version,
827 +       but may differ in detail to address new problems or
828 +       concerns. See http://www.gnu.org/copyleft/.
829 +     </para>
830 +
831 +     <para>
832 +       Each version of the License is given a distinguishing version
833 +       number. If the Document specifies that a particular numbered
834 +       version of this License "or any later version" applies to it,
835 +       you have the option of following the terms and conditions
836 +       either of that specified version or of any later version that
837 +       has been published (not as a draft) by the Free Software
838 +       Foundation. If the Document does not specify a version number
839 +       of this License, you may choose any version ever published (not
840 +       as a draft) by the Free Software Foundation.
841 +     </para>
842 +
843 +     </sect1>
844 +  </appendix>
845 +</book>
846 --- linux-2.4.27/include/linux/icmpv6.h~mipv6-1.1-v2.4.26
847 +++ linux-2.4.27/include/linux/icmpv6.h
848 @@ -40,14 +40,16 @@
849                  struct icmpv6_nd_ra {
850                         __u8            hop_limit;
851  #if defined(__LITTLE_ENDIAN_BITFIELD)
852 -                       __u8            reserved:6,
853 +                       __u8            reserved:5,
854 +                                       home_agent:1,
855                                         other:1,
856                                         managed:1;
857  
858  #elif defined(__BIG_ENDIAN_BITFIELD)
859                         __u8            managed:1,
860                                         other:1,
861 -                                       reserved:6;
862 +                                       home_agent:1,
863 +                                       reserved:5;
864  #else
865  #error "Please fix <asm/byteorder.h>"
866  #endif
867 @@ -70,6 +72,7 @@
868  #define icmp6_addrconf_managed icmp6_dataun.u_nd_ra.managed
869  #define icmp6_addrconf_other   icmp6_dataun.u_nd_ra.other
870  #define icmp6_rt_lifetime      icmp6_dataun.u_nd_ra.rt_lifetime
871 +#define icmp6_home_agent       icmp6_dataun.u_nd_ra.home_agent
872  };
873  
874  
875 --- linux-2.4.27/include/linux/if_arp.h~mipv6-1.1-v2.4.26
876 +++ linux-2.4.27/include/linux/if_arp.h
877 @@ -59,7 +59,7 @@
878  #define ARPHRD_RAWHDLC 518             /* Raw HDLC                     */
879  
880  #define ARPHRD_TUNNEL  768             /* IPIP tunnel                  */
881 -#define ARPHRD_TUNNEL6 769             /* IPIP6 tunnel                 */
882 +#define ARPHRD_TUNNEL6 769             /* IP6IP6 tunnel                */
883  #define ARPHRD_FRAD    770             /* Frame Relay Access Device    */
884  #define ARPHRD_SKIP    771             /* SKIP vif                     */
885  #define ARPHRD_LOOPBACK        772             /* Loopback device              */
886 --- linux-2.4.27/include/linux/in6.h~mipv6-1.1-v2.4.26
887 +++ linux-2.4.27/include/linux/in6.h
888 @@ -142,6 +142,11 @@
889  #define IPV6_TLV_JUMBO         194
890  
891  /*
892 + *     Mobile IPv6 TLV options.
893 + */
894 +#define MIPV6_TLV_HOMEADDR     201
895 +
896 +/*
897   *     IPV6 socket options
898   */
899  
900 --- linux-2.4.27/include/linux/ipv6.h~mipv6-1.1-v2.4.26
901 +++ linux-2.4.27/include/linux/ipv6.h
902 @@ -29,6 +29,7 @@
903  
904  #define IPV6_SRCRT_STRICT      0x01    /* this hop must be a neighbor  */
905  #define IPV6_SRCRT_TYPE_0      0       /* IPv6 type 0 Routing Header   */
906 +#define IPV6_SRCRT_TYPE_2      2       /*      type 2 for Mobile IPv6  */
907  
908  /*
909   *     routing header
910 @@ -71,6 +72,19 @@
911         struct in6_addr         addr[0];
912  
913  #define rt0_type               rt_hdr.type
914 +
915 +};
916 +
917 +/*
918 + *     routing header type 2
919 + */
920 +
921 +struct rt2_hdr {
922 +       struct ipv6_rt_hdr      rt_hdr;
923 +       __u32                   reserved;
924 +       struct in6_addr         addr;
925 +
926 +#define rt2_type               rt_hdr.type;
927  };
928  
929  /*
930 @@ -156,12 +170,16 @@
931  struct inet6_skb_parm
932  {
933         int                     iif;
934 +       __u8                    mipv6_flags;
935         __u16                   ra;
936         __u16                   hop;
937         __u16                   auth;
938         __u16                   dst0;
939         __u16                   srcrt;
940 +       __u16                   srcrt2;
941 +       __u16                   hao;
942         __u16                   dst1;
943 +       struct in6_addr         hoa;
944  };
945  
946  #endif
947 --- linux-2.4.27/include/linux/ipv6_route.h~mipv6-1.1-v2.4.26
948 +++ linux-2.4.27/include/linux/ipv6_route.h
949 @@ -33,6 +33,7 @@
950  #define RTF_CACHE      0x01000000      /* cache entry                  */
951  #define RTF_FLOW       0x02000000      /* flow significant route       */
952  #define RTF_POLICY     0x04000000      /* policy route                 */
953 +#define RTF_MOBILENODE  0x10000000      /* for routing to Mobile Node   */
954  
955  #define RTF_LOCAL      0x80000000
956  
957 --- /dev/null
958 +++ linux-2.4.27/include/linux/ipv6_tunnel.h
959 @@ -0,0 +1,34 @@
960 +/*
961 + * $Id$
962 + */
963 +
964 +#ifndef _IPV6_TUNNEL_H
965 +#define _IPV6_TUNNEL_H
966 +
967 +#define IPV6_TLV_TNL_ENCAP_LIMIT 4
968 +#define IPV6_DEFAULT_TNL_ENCAP_LIMIT 4
969 +
970 +/* don't add encapsulation limit if one isn't present in inner packet */
971 +#define IP6_TNL_F_IGN_ENCAP_LIMIT 0x1
972 +/* copy the traffic class field from the inner packet */
973 +#define IP6_TNL_F_USE_ORIG_TCLASS 0x2
974 +/* copy the flowlabel from the inner packet */
975 +#define IP6_TNL_F_USE_ORIG_FLOWLABEL 0x4
976 +/* created and maintained from within the kernel */
977 +#define IP6_TNL_F_KERNEL_DEV 0x8
978 +/* being used for Mobile IPv6 */
979 +#define IP6_TNL_F_MIP6_DEV 0x10
980 +
981 +struct ip6_tnl_parm {
982 +       char name[IFNAMSIZ];    /* name of tunnel device */
983 +       int link;               /* ifindex of underlying L2 interface */
984 +       __u8 proto;             /* tunnel protocol */
985 +       __u8 encap_limit;       /* encapsulation limit for tunnel */
986 +       __u8 hop_limit;         /* hop limit for tunnel */
987 +       __u32 flowinfo;         /* traffic class and flowlabel for tunnel */
988 +       __u32 flags;            /* tunnel flags */
989 +       struct in6_addr laddr;  /* local tunnel end-point address */
990 +       struct in6_addr raddr;  /* remote tunnel end-point address */
991 +};
992 +
993 +#endif
994 --- linux-2.4.27/include/linux/rtnetlink.h~mipv6-1.1-v2.4.26
995 +++ linux-2.4.27/include/linux/rtnetlink.h
996 @@ -315,6 +315,7 @@
997         IFA_BROADCAST,
998         IFA_ANYCAST,
999         IFA_CACHEINFO,
1000 +       IFA_HOMEAGENT,
1001         __IFA_MAX
1002  };
1003  
1004 @@ -324,6 +325,7 @@
1005  
1006  #define IFA_F_SECONDARY                0x01
1007  
1008 +#define IFA_F_HOMEADDR         0x10
1009  #define IFA_F_DEPRECATED       0x20
1010  #define IFA_F_TENTATIVE                0x40
1011  #define IFA_F_PERMANENT                0x80
1012 --- linux-2.4.27/include/linux/skbuff.h~mipv6-1.1-v2.4.26
1013 +++ linux-2.4.27/include/linux/skbuff.h
1014 @@ -177,7 +177,7 @@
1015          * want to keep them across layers you have to do a skb_clone()
1016          * first. This is owned by whoever has the skb queued ATM.
1017          */ 
1018 -       char            cb[48];  
1019 +       char            cb[64];  
1020  
1021         unsigned int    len;                    /* Length of actual data                        */
1022         unsigned int    data_len;
1023 --- linux-2.4.27/include/linux/sysctl.h~mipv6-1.1-v2.4.26
1024 +++ linux-2.4.27/include/linux/sysctl.h
1025 @@ -404,6 +404,23 @@
1026         NET_IPV6_ICMP=19,
1027         NET_IPV6_BINDV6ONLY=20,
1028         NET_IPV6_MLD_MAX_MSF=25,
1029 +       NET_IPV6_MOBILITY=26
1030 +};
1031 +
1032 +/* /proc/sys/net/ipv6/mobility */
1033 +enum {
1034 +       NET_IPV6_MOBILITY_DEBUG=1,
1035 +       NET_IPV6_MOBILITY_TUNNEL_SITELOCAL=2,
1036 +       NET_IPV6_MOBILITY_ROUTER_SOLICITATION_MAX_SENDTIME=3,
1037 +       NET_IPV6_MOBILITY_ROUTER_REACH=4,
1038 +       NET_IPV6_MOBILITY_MDETECT_MECHANISM=5,
1039 +       NET_IPV6_MOBILITY_RETROUT=6,
1040 +       NET_IPV6_MOBILITY_MAX_TNLS=7,
1041 +       NET_IPV6_MOBILITY_MIN_TNLS=8,
1042 +       NET_IPV6_MOBILITY_BINDING_REFRESH=9,
1043 +       NET_IPV6_MOBILITY_BU_F_LLADDR=10,
1044 +       NET_IPV6_MOBILITY_BU_F_KEYMGM=11,
1045 +       NET_IPV6_MOBILITY_BU_F_CN_ACK=12
1046  };
1047  
1048  enum {
1049 --- linux-2.4.27/include/net/addrconf.h~mipv6-1.1-v2.4.26
1050 +++ linux-2.4.27/include/net/addrconf.h
1051 @@ -16,9 +16,11 @@
1052  #if defined(__BIG_ENDIAN_BITFIELD)
1053         __u8                    onlink : 1,
1054                                 autoconf : 1,
1055 -                               reserved : 6;
1056 +                               router_address : 1,
1057 +                               reserved : 5;
1058  #elif defined(__LITTLE_ENDIAN_BITFIELD)
1059 -       __u8                    reserved : 6,
1060 +       __u8                    reserved : 5,
1061 +                               router_address : 1,
1062                                 autoconf : 1,
1063                                 onlink : 1;
1064  #else
1065 @@ -55,6 +57,7 @@
1066                                               struct net_device *dev);
1067  extern struct inet6_ifaddr *   ipv6_get_ifaddr(struct in6_addr *addr,
1068                                                 struct net_device *dev);
1069 +extern void                    ipv6_del_addr(struct inet6_ifaddr *ifp);
1070  extern int                     ipv6_get_saddr(struct dst_entry *dst, 
1071                                                struct in6_addr *daddr,
1072                                                struct in6_addr *saddr);
1073 @@ -85,7 +88,9 @@
1074  extern void ipv6_mc_down(struct inet6_dev *idev);
1075  extern void ipv6_mc_init_dev(struct inet6_dev *idev);
1076  extern void ipv6_mc_destroy_dev(struct inet6_dev *idev);
1077 +extern void addrconf_dad_start(struct inet6_ifaddr *ifp, int flags);
1078  extern void addrconf_dad_failure(struct inet6_ifaddr *ifp);
1079 +extern void addrconf_dad_completed(struct inet6_ifaddr *ifp);
1080  
1081  extern int ipv6_chk_mcast_addr(struct net_device *dev, struct in6_addr *group,
1082                 struct in6_addr *src_addr);
1083 @@ -116,6 +121,9 @@
1084  extern int register_inet6addr_notifier(struct notifier_block *nb);
1085  extern int unregister_inet6addr_notifier(struct notifier_block *nb);
1086  
1087 +extern int ipv6_generate_eui64(u8 *eui, struct net_device *dev);
1088 +extern int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev);
1089 +
1090  static inline struct inet6_dev *
1091  __in6_dev_get(struct net_device *dev)
1092  {
1093 --- linux-2.4.27/include/net/ip6_route.h~mipv6-1.1-v2.4.26
1094 +++ linux-2.4.27/include/net/ip6_route.h
1095 @@ -2,6 +2,7 @@
1096  #define _NET_IP6_ROUTE_H
1097  
1098  #define IP6_RT_PRIO_FW         16
1099 +#define IP6_RT_PRIO_MIPV6              64
1100  #define IP6_RT_PRIO_USER       1024
1101  #define IP6_RT_PRIO_ADDRCONF   256
1102  #define IP6_RT_PRIO_KERN       512
1103 @@ -40,6 +41,9 @@
1104  
1105  extern int                     ip6_route_add(struct in6_rtmsg *rtmsg,
1106                                               struct nlmsghdr *);
1107 +
1108 +extern int                     ip6_route_del(struct in6_rtmsg *rtmsg,
1109 +                                             struct nlmsghdr *);
1110  extern int                     ip6_del_rt(struct rt6_info *,
1111                                            struct nlmsghdr *);
1112  
1113 @@ -99,7 +103,8 @@
1114   */
1115  
1116  static inline void ip6_dst_store(struct sock *sk, struct dst_entry *dst,
1117 -                                    struct in6_addr *daddr)
1118 +                                struct in6_addr *daddr, 
1119 +                                struct in6_addr *saddr)
1120  {
1121         struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
1122         struct rt6_info *rt = (struct rt6_info *) dst;
1123 @@ -107,6 +112,9 @@
1124         write_lock(&sk->dst_lock);
1125         __sk_dst_set(sk, dst);
1126         np->daddr_cache = daddr;
1127 +#ifdef CONFIG_IPV6_SUBTREES
1128 +       np->saddr_cache = saddr;
1129 +#endif
1130         np->dst_cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0;
1131         write_unlock(&sk->dst_lock);
1132  }
1133 --- linux-2.4.27/include/net/ipv6.h~mipv6-1.1-v2.4.26
1134 +++ linux-2.4.27/include/net/ipv6.h
1135 @@ -37,6 +37,7 @@
1136  #define NEXTHDR_ICMP           58      /* ICMP for IPv6. */
1137  #define NEXTHDR_NONE           59      /* No next header */
1138  #define NEXTHDR_DEST           60      /* Destination options header. */
1139 +#define NEXTHDR_MH             135     /* Mobility header, RFC 3775 */
1140  
1141  #define NEXTHDR_MAX            255
1142  
1143 @@ -146,9 +147,12 @@
1144         __u16                   opt_flen;       /* after fragment hdr */
1145         __u16                   opt_nflen;      /* before fragment hdr */
1146  
1147 +       __u8                    mipv6_flags;    /* flags set by MIPv6 */
1148 +
1149         struct ipv6_opt_hdr     *hopopt;
1150         struct ipv6_opt_hdr     *dst0opt;
1151 -       struct ipv6_rt_hdr      *srcrt; /* Routing Header */
1152 +       struct ipv6_rt_hdr      *srcrt; /* Routing Header Type 0 */
1153 +       struct ipv6_rt_hdr      *srcrt2; /* Routing Header Type 2 */
1154         struct ipv6_opt_hdr     *auth;
1155         struct ipv6_opt_hdr     *dst1opt;
1156  
1157 @@ -257,6 +261,38 @@
1158                  a->s6_addr32[2] | a->s6_addr32[3] ) == 0); 
1159  }
1160  
1161 +static inline void ipv6_addr_prefix(struct in6_addr *pfx,
1162 +                                   const struct in6_addr *addr, int plen)
1163 +{
1164 +       /* caller must guarantee 0 <= plen <= 128 */
1165 +       int o = plen >> 3,
1166 +           b = plen & 0x7;
1167 +
1168 +       memcpy(pfx->s6_addr, addr, o);
1169 +       if (b != 0) {
1170 +               pfx->s6_addr[o] = addr->s6_addr[o] & (0xff00 >> b);
1171 +               o++;
1172 +       }
1173 +       if (o < 16)
1174 +               memset(pfx->s6_addr + o, 0, 16 - o);
1175 +}
1176 +
1177 +static inline int ipv6_prefix_cmp(const struct in6_addr *p1,
1178 +                                 const struct in6_addr *p2, int plen)
1179 +{
1180 +       int b = plen&0x7;
1181 +       int o = plen>>3;
1182 +       int res = 0;
1183 +
1184 +       if (o > 0) 
1185 +               res = memcmp(&p1->s6_addr[0], &p2->s6_addr[0], o);
1186 +       if (res == 0 && b > 0) {
1187 +               __u8 m = (0xff00 >> b) & 0xff;
1188 +               res = (p1->s6_addr[o] & m) - (p2->s6_addr[o] & m);  
1189 +       }
1190 +       return res;
1191 +}
1192 +
1193  /*
1194   *     Prototypes exported by ipv6
1195   */
1196 --- /dev/null
1197 +++ linux-2.4.27/include/net/ipv6_tunnel.h
1198 @@ -0,0 +1,92 @@
1199 +/*
1200 + * $Id$
1201 + */
1202 +
1203 +#ifndef _NET_IPV6_TUNNEL_H
1204 +#define _NET_IPV6_TUNNEL_H
1205 +
1206 +#include <linux/ipv6.h>
1207 +#include <linux/netdevice.h>
1208 +#include <linux/ipv6_tunnel.h>
1209 +#include <linux/skbuff.h>
1210 +#include <asm/atomic.h>
1211 +
1212 +/* capable of sending packets */
1213 +#define IP6_TNL_F_CAP_XMIT 0x10000
1214 +/* capable of receiving packets */
1215 +#define IP6_TNL_F_CAP_RCV 0x20000
1216 +
1217 +#define IP6_TNL_MAX 128
1218 +
1219 +/* IPv6 tunnel */
1220 +
1221 +struct ip6_tnl {
1222 +       struct ip6_tnl *next;   /* next tunnel in list */
1223 +       struct net_device *dev; /* virtual device associated with tunnel */
1224 +       struct net_device_stats stat;   /* statistics for tunnel device */
1225 +       int recursion;          /* depth of hard_start_xmit recursion */
1226 +       struct ip6_tnl_parm parms;      /* tunnel configuration paramters */
1227 +       struct flowi fl;        /* flowi template for xmit */
1228 +       atomic_t refcnt;        /* nr of identical tunnels used by kernel */
1229 +       struct socket *sock;
1230 +};
1231 +
1232 +#define IP6_TNL_PRE_ENCAP 0
1233 +#define IP6_TNL_PRE_DECAP 1
1234 +#define IP6_TNL_MAXHOOKS 2
1235 +
1236 +#define IP6_TNL_DROP 0
1237 +#define IP6_TNL_ACCEPT 1
1238 +
1239 +typedef int ip6_tnl_hookfn(struct ip6_tnl *t, struct sk_buff *skb);
1240 +
1241 +struct ip6_tnl_hook_ops {
1242 +       struct list_head list;
1243 +       unsigned int hooknum;
1244 +       int priority;
1245 +       ip6_tnl_hookfn *hook;
1246 +};
1247 +
1248 +enum ip6_tnl_hook_priorities {
1249 +       IP6_TNL_PRI_FIRST = INT_MIN,
1250 +       IP6_TNL_PRI_LAST = INT_MAX
1251 +};
1252 +
1253 +/* Tunnel encapsulation limit destination sub-option */
1254 +
1255 +struct ipv6_tlv_tnl_enc_lim {
1256 +       __u8 type;              /* type-code for option         */
1257 +       __u8 length;            /* option length                */
1258 +       __u8 encap_limit;       /* tunnel encapsulation limit   */
1259 +} __attribute__ ((packed));
1260 +
1261 +#ifdef __KERNEL__
1262 +extern int ip6ip6_tnl_create(struct ip6_tnl_parm *p, struct ip6_tnl **pt);
1263 +
1264 +extern struct ip6_tnl *ip6ip6_tnl_lookup(struct in6_addr *remote,
1265 +                                        struct in6_addr *local);
1266 +
1267 +void ip6ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p);
1268 +
1269 +extern int ip6ip6_kernel_tnl_add(struct ip6_tnl_parm *p);
1270 +
1271 +extern int ip6ip6_kernel_tnl_del(struct ip6_tnl *t);
1272 +
1273 +extern unsigned int ip6ip6_tnl_inc_max_kdev_count(unsigned int n);
1274 +
1275 +extern unsigned int ip6ip6_tnl_dec_max_kdev_count(unsigned int n);
1276 +
1277 +extern unsigned int ip6ip6_tnl_inc_min_kdev_count(unsigned int n);
1278 +
1279 +extern unsigned int ip6ip6_tnl_dec_min_kdev_count(unsigned int n);
1280 +
1281 +extern void ip6ip6_tnl_register_hook(struct ip6_tnl_hook_ops *reg);
1282 +
1283 +extern void ip6ip6_tnl_unregister_hook(struct ip6_tnl_hook_ops *reg);
1284 +
1285 +#ifdef CONFIG_IPV6_TUNNEL
1286 +extern int __init ip6_tunnel_init(void);
1287 +extern void ip6_tunnel_cleanup(void);
1288 +#endif
1289 +#endif
1290 +#endif
1291 --- /dev/null
1292 +++ linux-2.4.27/include/net/mipglue.h
1293 @@ -0,0 +1,266 @@
1294 +/*
1295 + *     Glue for Mobility support integration to IPv6
1296 + *
1297 + *     Authors:
1298 + *     Antti Tuominen          <ajtuomin@cc.hut.fi>    
1299 + *
1300 + *     $Id$
1301 + *
1302 + *     This program is free software; you can redistribute it and/or
1303 + *      modify it under the terms of the GNU General Public License
1304 + *      as published by the Free Software Foundation; either version
1305 + *      2 of the License, or (at your option) any later version.
1306 + *
1307 + */
1308 +
1309 +#ifndef _NET_MIPGLUE_H
1310 +#define _NET_MIPGLUE_H
1311 +
1312 +#ifndef USE_IPV6_MOBILITY
1313 +#if defined(CONFIG_IPV6_MOBILITY) || defined(CONFIG_IPV6_MOBILITY_MODULE)
1314 +#define USE_IPV6_MOBILITY
1315 +#endif
1316 +#endif
1317 +
1318 +/* symbols to indicate whether destination options received should take
1319 + * effect or not (see exthdrs.c, procrcv.c)
1320 + */
1321 +#define MIPV6_DSTOPTS_ACCEPT 1
1322 +#define MIPV6_DSTOPTS_DISCARD 0
1323 +
1324 +#define MIPV6_IGN_RTR 0
1325 +#define MIPV6_ADD_RTR 1
1326 +#define MIPV6_CHG_RTR 2
1327 +
1328 +/* MIPV6: Approximate maximum for mobile IPv6 options and headers */
1329 +#define MIPV6_HEADERS 48
1330 +
1331 +#ifdef __KERNEL__
1332 +#include <net/mipv6.h>
1333 +#include <linux/slab.h>
1334 +#include <net/ipv6.h>
1335 +
1336 +struct sk_buff;
1337 +struct ndisc_options;
1338 +struct sock;
1339 +struct ipv6_txoptions;
1340 +struct flowi;
1341 +struct dst_entry;
1342 +struct in6_addr;
1343 +struct inet6_ifaddr;
1344 +
1345 +#ifdef USE_IPV6_MOBILITY
1346 +
1347 +/* calls a procedure from mipv6-module */
1348 +#define MIPV6_CALLPROC(X) if(mipv6_functions.X) mipv6_functions.X
1349 +
1350 +/* calls a function from mipv6-module, default-value if function not defined
1351 + */
1352 +#define MIPV6_CALLFUNC(X,Y) (!mipv6_functions.X)?(Y):mipv6_functions.X
1353 +
1354 +/* sets a handler-function to process a call */
1355 +#define MIPV6_SETCALL(X,Y) if(mipv6_functions.X) printk("mipv6: Warning, function assigned twice!\n"); \
1356 +                           mipv6_functions.X = Y
1357 +#define MIPV6_RESETCALL(X) mipv6_functions.X = NULL
1358 +
1359 +/* pointers to mipv6 callable functions */
1360 +struct mipv6_callable_functions {
1361 +       void (*mipv6_initialize_dstopt_rcv) (struct sk_buff *skb);
1362 +       int (*mipv6_finalize_dstopt_rcv) (int process);
1363 +       int (*mipv6_handle_homeaddr) (struct sk_buff *skb, int optoff);
1364 +       int (*mipv6_ra_rcv) (struct sk_buff *skb,
1365 +                            struct ndisc_options *ndopts);
1366 +       void (*mipv6_icmp_rcv) (struct sk_buff *skb);
1367 +       struct ipv6_txoptions * (*mipv6_modify_txoptions) (
1368 +               struct sock *sk,
1369 +               struct sk_buff *skb, 
1370 +               struct ipv6_txoptions *opt,
1371 +               struct flowi *fl,
1372 +               struct dst_entry **dst);
1373 +       void (*mipv6_set_home) (int ifindex, struct in6_addr *homeaddr,
1374 +                               int plen, struct in6_addr *homeagent, 
1375 +                               int plen2);
1376 +       void (*mipv6_get_home_address) (struct in6_addr *home_addr);
1377 +       void (*mipv6_get_care_of_address)(struct in6_addr *homeaddr, 
1378 +                                         struct in6_addr *coa);
1379 +       int (*mipv6_is_home_addr)(struct in6_addr *addr);
1380 +       void (*mipv6_change_router)(void);
1381 +       void (*mipv6_check_dad)(struct in6_addr *home_addr);      
1382 +       void (*mipv6_icmp_swap_addrs)(struct sk_buff *skb);
1383 +       int (*mipv6_forward)(struct sk_buff *skb);
1384 +       int (*mipv6_mn_ha_probe)(struct inet6_ifaddr *ifp, u8 *lladdr);
1385 +};
1386 +
1387 +extern struct mipv6_callable_functions mipv6_functions;
1388 +
1389 +extern void mipv6_invalidate_calls(void);
1390 +
1391 +extern int mipv6_handle_dstopt(struct sk_buff *skb, int optoff);
1392 +
1393 +static inline int
1394 +ndisc_mip_mn_ha_probe(struct inet6_ifaddr *ifp, u8 *lladdr)
1395 +{
1396 +       return MIPV6_CALLFUNC(mipv6_mn_ha_probe, 0)(ifp, lladdr);
1397 +}
1398 +
1399 +/* Must only be called for HA, no checks here */
1400 +static inline int ip6_mipv6_forward(struct sk_buff *skb)
1401 +{
1402 +       return MIPV6_CALLFUNC(mipv6_forward, 0)(skb);
1403 +}
1404 +
1405 +/* 
1406 + * Avoid adding new default routers if the old one is still in use 
1407 + */
1408 +
1409 +static inline int ndisc_mipv6_ra_rcv(struct sk_buff *skb,
1410 +                                    struct ndisc_options *ndopts)
1411 +{
1412 +       return MIPV6_CALLFUNC(mipv6_ra_rcv, MIPV6_ADD_RTR)(skb, ndopts);
1413 +}
1414 +
1415 +static inline int ipv6_chk_mip_home_addr(struct in6_addr *addr)
1416 +{
1417 +       return MIPV6_CALLFUNC(mipv6_is_home_addr, 0)(addr);
1418 +}
1419 +
1420 +static inline void ndisc_mipv6_change_router(int change_rtr)
1421 +{
1422 +       if (change_rtr == MIPV6_CHG_RTR)
1423 +               MIPV6_CALLPROC(mipv6_change_router)();
1424 +}
1425 +
1426 +static inline void ndisc_check_mipv6_dad(struct in6_addr *target)
1427 +{
1428 +       MIPV6_CALLPROC(mipv6_check_dad)(target);
1429 +}
1430 +
1431 +static inline void icmpv6_swap_mipv6_addrs(struct sk_buff *skb)
1432 +{
1433 +       MIPV6_CALLPROC(mipv6_icmp_swap_addrs)(skb);
1434 +}
1435 +
1436 +static inline void mipv6_icmp_rcv(struct sk_buff *skb)
1437 +{
1438 +       MIPV6_CALLPROC(mipv6_icmp_rcv)(skb);
1439 +}
1440 +
1441 +static inline int tcp_v6_get_mipv6_header_len(void)
1442 +{
1443 +       return MIPV6_HEADERS;
1444 +}
1445 +
1446 +static inline struct in6_addr *
1447 +mipv6_get_fake_hdr_daddr(struct in6_addr *hdaddr, struct in6_addr *daddr)
1448 +{
1449 +       return daddr;
1450 +}
1451 +
1452 +static inline void 
1453 +addrconf_set_mipv6_mn_home(int ifindex, struct in6_addr *homeaddr, int plen,
1454 +                          struct in6_addr *homeagent, int plen2)
1455 +{
1456 +       MIPV6_CALLPROC(mipv6_set_home)(ifindex, homeaddr, plen, homeagent, plen2);
1457 +}
1458 +
1459 +static inline void addrconf_get_mipv6_home_address(struct in6_addr *saddr)
1460 +{
1461 +       MIPV6_CALLPROC(mipv6_get_home_address)(saddr);
1462 +}
1463 +
1464 +static inline struct ipv6_txoptions *
1465 +ip6_add_mipv6_txoptions(struct sock *sk, struct sk_buff *skb, 
1466 +                       struct ipv6_txoptions *opt, struct flowi *fl,
1467 +                       struct dst_entry **dst)
1468 +{
1469 +       return MIPV6_CALLFUNC(mipv6_modify_txoptions, opt)(sk, skb, opt, fl, dst); 
1470 +
1471 +}
1472 +
1473 +static inline void
1474 +ip6_mark_mipv6_packet(struct ipv6_txoptions *txopt, struct sk_buff *skb)
1475 +{
1476 +       struct inet6_skb_parm *opt;
1477 +       if (txopt) {
1478 +               opt = (struct inet6_skb_parm *)skb->cb;
1479 +               opt->mipv6_flags = txopt->mipv6_flags;
1480 +       }
1481 +}
1482 +
1483 +static inline void 
1484 +ip6_free_mipv6_txoptions(struct ipv6_txoptions *opt,
1485 +                        struct ipv6_txoptions *orig_opt) 
1486 +{
1487 +       if (opt && opt != orig_opt)
1488 +               kfree(opt);
1489 +}
1490 +
1491 +#else /* USE_IPV6_MOBILITY */
1492 +
1493 +#define mipv6_handle_dstopt ip6_tlvopt_unknown
1494 +
1495 +static inline int
1496 +ndisc_mip_mn_ha_probe(struct inet6_ifaddr *ifp, u8 *lladdr)
1497 +{
1498 +       return 0;
1499 +}
1500 +
1501 +static inline int ip6_mipv6_forward(struct sk_buff *skb)
1502 +{
1503 +       return 0;
1504 +}
1505 +
1506 +static inline int ndisc_mipv6_ra_rcv(struct sk_buff *skb,
1507 +                                    struct ndisc_options *ndopts)
1508 +{
1509 +       return MIPV6_ADD_RTR;
1510 +}
1511 +
1512 +static inline int ipv6_chk_mip_home_addr(struct in6_addr *addr)
1513 +{
1514 +       return 0;
1515 +}
1516 +
1517 +static inline void ndisc_mipv6_change_router(int change_rtr) {}
1518 +
1519 +static inline void ndisc_check_mipv6_dad(struct in6_addr *target) {}
1520 +
1521 +static inline void icmpv6_swap_mipv6_addrs(struct sk_buff *skb) {}
1522 +
1523 +static inline void mipv6_icmp_rcv(struct sk_buff *skb) {}
1524 +
1525 +static inline int tcp_v6_get_mipv6_header_len(void)
1526 +{
1527 +       return 0;
1528 +}
1529 +
1530 +static inline struct in6_addr *
1531 +mipv6_get_fake_hdr_daddr(struct in6_addr *hdaddr, struct in6_addr *daddr)
1532 +{
1533 +       return hdaddr;
1534 +}
1535 +
1536 +static inline void 
1537 +addrconf_set_mipv6_mn_home(int ifindex, struct in6_addr *homeaddr, int plen,
1538 +                          struct in6_addr *homeagent, int plen2) {}
1539 +
1540 +static inline void addrconf_get_mipv6_home_address(struct in6_addr *saddr) {}
1541 +
1542 +static inline struct ipv6_txoptions *
1543 +ip6_add_mipv6_txoptions(struct sock *sk, struct sk_buff *skb,
1544 +                       struct ipv6_txoptions *opt, struct flowi *fl,
1545 +                       struct dst_entry **dst)
1546 +{
1547 +       return opt;
1548 +}
1549 +
1550 +static inline void
1551 +ip6_mark_mipv6_packet(struct ipv6_txoptions *txopt, struct sk_buff *skb) {}
1552 +
1553 +static inline void 
1554 +ip6_free_mipv6_txoptions(struct ipv6_txoptions *opt, 
1555 +                        struct ipv6_txoptions *orig_opt) {}
1556 +
1557 +#endif /* USE_IPV6_MOBILITY */
1558 +#endif /* __KERNEL__ */
1559 +#endif /* _NET_MIPGLUE_H */
1560 --- /dev/null
1561 +++ linux-2.4.27/include/net/mipv6.h
1562 @@ -0,0 +1,258 @@
1563 +/*
1564 + *     Mobile IPv6 header-file
1565 + *
1566 + *     Authors:
1567 + *     Sami Kivisaari          <skivisaa@cc.hut.fi>
1568 + *
1569 + *     $Id$
1570 + *
1571 + *     This program is free software; you can redistribute it and/or
1572 + *      modify it under the terms of the GNU General Public License
1573 + *      as published by the Free Software Foundation; either version
1574 + *      2 of the License, or (at your option) any later version.
1575 + *
1576 + */
1577 +
1578 +#ifndef _NET_MIPV6_H
1579 +#define _NET_MIPV6_H
1580 +
1581 +#include <linux/types.h>
1582 +#include <asm/byteorder.h>
1583 +#include <linux/in6.h>
1584 +
1585 +/*
1586 + *
1587 + * Mobile IPv6 Protocol constants
1588 + *
1589 + */
1590 +#define DHAAD_RETRIES                  4       /* transmissions        */
1591 +#define INITIAL_BINDACK_TIMEOUT                1       /* seconds              */
1592 +#define INITIAL_DHAAD_TIMEOUT          3       /* seconds              */
1593 +#define INITIAL_SOLICIT_TIMER          3       /* seconds              */
1594 +#define MAX_BINDACK_TIMEOUT            32      /* seconds              */
1595 +#define MAX_NONCE_LIFE                 240     /* seconds              */
1596 +#define MAX_TOKEN_LIFE                 210     /* seconds              */
1597 +#define MAX_RR_BINDING_LIFE            420     /* seconds              */
1598 +#define MAX_UPDATE_RATE                        3       /* 1/s (min delay=1s)   */
1599 +#define PREFIX_ADV_RETRIES             3       /* transmissions        */
1600 +#define PREFIX_ADV_TIMEOUT             3       /* seconds              */
1601 +
1602 +#define MAX_FAST_UPDATES               5       /* transmissions        */
1603 +#define MAX_PFX_ADV_DELAY              1000    /* seconds              */
1604 +#define SLOW_UPDATE_RATE               10      /* 1/10s (max delay=10s)*/
1605 +#define INITIAL_BINDACK_DAD_TIMEOUT    2       /* seconds              */
1606 +
1607 +/*
1608 + *
1609 + * Mobile IPv6 (RFC 3775) Protocol configuration variable defaults
1610 + *
1611 + */
1612 +#define DefHomeRtrAdvInterval          1000    /* seconds              */
1613 +#define DefMaxMobPfxAdvInterval                86400   /* seconds              */
1614 +#define DefMinDelayBetweenRAs          3       /* seconds (min 0.03)   */
1615 +#define DefMinMobPfxAdvInterval                600     /* seconds              */
1616 +#define DefInitialBindackTimeoutFirstReg       1.5 /* seconds          */
1617 +
1618 +/* This is not actually specified in the draft, but is needed to avoid
1619 + * prefix solicitation storm when valid lifetime of a prefix is smaller
1620 + * than MAX_PFX_ADV_DELAY
1621 + */
1622 +#define MIN_PFX_SOL_DELAY              5       /* seconds              */
1623 +
1624 +/* Mobile IPv6 ICMP types                */
1625 +/*
1626 + * Official numbers from RFC 3775
1627 + */
1628 +#define MIPV6_DHAAD_REQUEST            144
1629 +#define MIPV6_DHAAD_REPLY              145
1630 +#define MIPV6_PREFIX_SOLICIT           146
1631 +#define MIPV6_PREFIX_ADV               147
1632 +
1633 +/* Binding update flag codes              */
1634 +#define MIPV6_BU_F_ACK                 0x80
1635 +#define MIPV6_BU_F_HOME                        0x40
1636 +#define MIPV6_BU_F_LLADDR              0x20
1637 +#define MIPV6_BU_F_KEYMGM              0x10
1638 +
1639 +/* Binding ackknowledgment flag codes */
1640 +#define MIPV6_BA_F_KEYMGM              0x80
1641 +
1642 +/* Binding error status */
1643 +#define MIPV6_BE_HAO_WO_BINDING                1
1644 +#define MIPV6_BE_UNKNOWN_MH_TYPE       2
1645 +
1646 +/* Mobility Header */
1647 +struct mipv6_mh
1648 +{
1649 +       __u8    payload;                /* Payload Protocol             */
1650 +       __u8    length;                 /* MH Length                    */
1651 +       __u8    type;                   /* MH Type                      */
1652 +       __u8    reserved;               /* Reserved                     */
1653 +       __u16   checksum;               /* Checksum                     */
1654 +       __u8    data[0];                /* Message specific data        */
1655 +} __attribute__ ((packed));
1656 +
1657 +/* Mobility Header type */
1658 +#define IPPROTO_MOBILITY                135 /* RFC 3775*/                
1659 +/* Mobility Header Message Types */
1660 +
1661 +#define MIPV6_MH_BRR                   0
1662 +#define MIPV6_MH_HOTI                  1
1663 +#define MIPV6_MH_COTI                  2
1664 +#define MIPV6_MH_HOT                   3
1665 +#define MIPV6_MH_COT                   4
1666 +#define MIPV6_MH_BU                    5
1667 +#define MIPV6_MH_BA                    6
1668 +#define MIPV6_MH_BE                    7
1669 +
1670 +/*
1671 + * Status codes for Binding Acknowledgements
1672 + */
1673 +#define SUCCESS                                0
1674 +#define REASON_UNSPECIFIED             128
1675 +#define ADMINISTRATIVELY_PROHIBITED    129
1676 +#define INSUFFICIENT_RESOURCES         130
1677 +#define HOME_REGISTRATION_NOT_SUPPORTED        131
1678 +#define NOT_HOME_SUBNET                        132
1679 +#define NOT_HA_FOR_MN                  133
1680 +#define DUPLICATE_ADDR_DETECT_FAIL     134
1681 +#define SEQUENCE_NUMBER_OUT_OF_WINDOW  135
1682 +#define EXPIRED_HOME_NONCE_INDEX       136
1683 +#define EXPIRED_CAREOF_NONCE_INDEX     137
1684 +#define EXPIRED_NONCES                 138
1685 +#define REG_TYPE_CHANGE_FORBIDDEN       139
1686 +/*
1687 + * Values for mipv6_flags in struct inet6_skb_parm
1688 + */
1689 +
1690 +#define MIPV6_RCV_TUNNEL               0x1
1691 +#define MIPV6_SND_HAO                  0x2
1692 +#define MIPV6_SND_BU                    0x4
1693 +
1694 +/*
1695 + * Mobility Header Message structures
1696 + */
1697 +
1698 +struct mipv6_mh_brr
1699 +{
1700 +       __u16           reserved;
1701 +       /* Mobility options */
1702 +} __attribute__ ((packed));
1703 +
1704 +struct mipv6_mh_bu
1705 +{
1706 +       __u16           sequence;       /* sequence number of BU        */
1707 +       __u8            flags;          /* flags                        */
1708 +       __u8            reserved;       /* reserved bits                */
1709 +       __u16           lifetime;       /* lifetime of BU               */
1710 +       /* Mobility options */
1711 +} __attribute__ ((packed));
1712 +
1713 +struct mipv6_mh_ba
1714 +{
1715 +       __u8            status;         /* statuscode                   */
1716 +       __u8            reserved;       /* reserved bits                */
1717 +       __u16           sequence;       /* sequence number of BA        */
1718 +       __u16           lifetime;       /* lifetime in CN's bcache      */
1719 +       /* Mobility options */
1720 +} __attribute__ ((packed));
1721 +
1722 +struct mipv6_mh_be
1723 +{
1724 +       __u8            status;
1725 +       __u8            reserved;
1726 +       struct in6_addr home_addr;
1727 +       /* Mobility options */
1728 +} __attribute__ ((packed));
1729 +
1730 +struct mipv6_mh_addr_ti
1731 +{
1732 +       __u16           reserved;       /* Reserved                     */
1733 +       u_int8_t        init_cookie[8]; /* HoT/CoT Init Cookie          */
1734 +       /* Mobility options */
1735 +} __attribute__ ((packed));
1736 +
1737 +struct mipv6_mh_addr_test
1738 +{
1739 +       __u16           nonce_index;    /* Home/Care-of Nonce Index     */
1740 +       u_int8_t        init_cookie[8]; /* HoT/CoT Init Cookie          */
1741 +       u_int8_t        kgen_token[8];  /* Home/Care-of key generation token */
1742 +       /* Mobility options */
1743 +} __attribute__ ((packed));
1744 +
1745 +/*
1746 + * Mobility Options for various MH types.
1747 + */
1748 +#define MIPV6_OPT_PAD1                 0x00
1749 +#define MIPV6_OPT_PADN                 0x01
1750 +#define MIPV6_OPT_BIND_REFRESH_ADVICE  0x02
1751 +#define MIPV6_OPT_ALTERNATE_COA                0x03
1752 +#define MIPV6_OPT_NONCE_INDICES                0x04
1753 +#define MIPV6_OPT_AUTH_DATA            0x05
1754 +
1755 +#define MIPV6_SEQ_GT(x,y) \
1756 +        ((short int)(((__u16)(x)) - ((__u16)(y))) > 0)
1757 +
1758 +/*
1759 + * Mobility Option structures
1760 + */
1761 +
1762 +struct mipv6_mo
1763 +{
1764 +       __u8            type;
1765 +       __u8            length;
1766 +       __u8            value[0];       /* type specific data */
1767 +} __attribute__ ((packed));
1768 +
1769 +struct mipv6_mo_pad1
1770 +{
1771 +       __u8            type;
1772 +} __attribute__ ((packed));
1773 +
1774 +struct mipv6_mo_padn
1775 +{
1776 +       __u8            type;
1777 +       __u8            length;
1778 +       __u8            data[0];
1779 +} __attribute__ ((packed));
1780 +
1781 +struct mipv6_mo_alt_coa
1782 +{
1783 +       __u8            type;
1784 +       __u8            length;
1785 +       struct in6_addr addr;           /* alternate care-of-address    */
1786 +} __attribute__ ((packed));
1787 +
1788 +struct mipv6_mo_nonce_indices
1789 +{
1790 +       __u8            type;
1791 +       __u8            length;
1792 +       __u16           home_nonce_i;   /* Home Nonce Index             */
1793 +       __u16           careof_nonce_i; /* Careof Nonce Index           */
1794 +} __attribute__ ((packed)); 
1795 +
1796 +struct mipv6_mo_bauth_data
1797 +{
1798 +       __u8            type;
1799 +       __u8            length;
1800 +       __u8            data[0];
1801 +} __attribute__ ((packed)); 
1802 +
1803 +struct mipv6_mo_br_advice
1804 +{
1805 +       __u8            type;
1806 +       __u8            length;
1807 +       __u16           refresh_interval; /* Refresh Interval           */
1808 +} __attribute__ ((packed));
1809 +
1810 +/*
1811 + * Home Address Destination Option structure
1812 + */
1813 +struct mipv6_dstopt_homeaddr
1814 +{
1815 +       __u8            type;           /* type-code for option         */
1816 +       __u8            length;         /* option length                */
1817 +       struct in6_addr addr;           /* home address                 */
1818 +} __attribute__ ((packed));
1819 +
1820 +#endif /* _NET_MIPV6_H */
1821 --- linux-2.4.27/include/net/ndisc.h~mipv6-1.1-v2.4.26
1822 +++ linux-2.4.27/include/net/ndisc.h
1823 @@ -21,6 +21,10 @@
1824  #define ND_OPT_REDIRECT_HDR            4
1825  #define ND_OPT_MTU                     5
1826  
1827 +/* Mobile IPv6 specific ndisc options */ 
1828 +#define ND_OPT_RTR_ADV_INTERVAL                7 
1829 +#define ND_OPT_HOME_AGENT_INFO         8  
1830 +
1831  #define MAX_RTR_SOLICITATION_DELAY     HZ
1832  
1833  #define ND_REACHABLE_TIME              (30*HZ)
1834 @@ -57,7 +61,7 @@
1835  } __attribute__((__packed__));
1836  
1837  struct ndisc_options {
1838 -       struct nd_opt_hdr *nd_opt_array[7];
1839 +       struct nd_opt_hdr *nd_opt_array[10];
1840         struct nd_opt_hdr *nd_opt_piend;
1841  };
1842  
1843 @@ -67,6 +71,8 @@
1844  #define nd_opts_pi_end         nd_opt_piend
1845  #define nd_opts_rh             nd_opt_array[ND_OPT_REDIRECT_HDR]
1846  #define nd_opts_mtu            nd_opt_array[ND_OPT_MTU]
1847 +#define nd_opts_rai            nd_opt_array[ND_OPT_RTR_ADV_INTERVAL]
1848 +#define nd_opts_hai            nd_opt_array[ND_OPT_HOME_AGENT_INFO]
1849  
1850  extern struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur, struct nd_opt_hdr *end);
1851  extern struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len, struct ndisc_options *ndopts);
1852 @@ -83,6 +89,15 @@
1853                                               struct in6_addr *daddr,
1854                                               struct in6_addr *saddr);
1855  
1856 +extern void                    ndisc_send_na(struct net_device *dev,
1857 +                                             struct neighbour *neigh,
1858 +                                             struct in6_addr *daddr,
1859 +                                             struct in6_addr *solicited_addr,
1860 +                                             int router,
1861 +                                             int solicited,
1862 +                                             int override,
1863 +                                             int inc_opt);
1864 +
1865  extern void                    ndisc_send_rs(struct net_device *dev,
1866                                               struct in6_addr *saddr,
1867                                               struct in6_addr *daddr);
1868 --- linux-2.4.27/include/net/sock.h~mipv6-1.1-v2.4.26
1869 +++ linux-2.4.27/include/net/sock.h
1870 @@ -149,7 +149,9 @@
1871         struct in6_addr         rcv_saddr;
1872         struct in6_addr         daddr;
1873         struct in6_addr         *daddr_cache;
1874 -
1875 +#if defined(CONFIG_IPV6_SUBTREES)
1876 +       struct in6_addr         *saddr_cache;
1877 +#endif
1878         __u32                   flow_label;
1879         __u32                   frag_size;
1880         int                     hop_limit;
1881 --- linux-2.4.27/net/Makefile~mipv6-1.1-v2.4.26
1882 +++ linux-2.4.27/net/Makefile
1883 @@ -7,7 +7,7 @@
1884  
1885  O_TARGET :=    network.o
1886  
1887 -mod-subdirs := ipv4/netfilter ipv6/netfilter ipx irda bluetooth atm netlink sched core sctp 802
1888 +mod-subdirs := ipv4/netfilter ipv6/netfilter ipx irda bluetooth atm netlink sched core sctp 802 ipv6
1889  export-objs := netsyms.o
1890  
1891  subdir-y :=    core ethernet
1892 @@ -25,6 +25,7 @@
1893  ifneq ($(CONFIG_IPV6),n)
1894  ifneq ($(CONFIG_IPV6),)
1895  subdir-$(CONFIG_NETFILTER)     += ipv6/netfilter
1896 +subdir-$(CONFIG_IPV6_MOBILITY) += ipv6/mobile_ip6
1897  endif
1898  endif
1899  
1900 --- linux-2.4.27/net/core/neighbour.c~mipv6-1.1-v2.4.26
1901 +++ linux-2.4.27/net/core/neighbour.c
1902 @@ -386,7 +386,7 @@
1903         if (!creat)
1904                 return NULL;
1905  
1906 -       n = kmalloc(sizeof(*n) + key_len, GFP_KERNEL);
1907 +       n = kmalloc(sizeof(*n) + key_len, GFP_ATOMIC);
1908         if (n == NULL)
1909                 return NULL;
1910  
1911 --- linux-2.4.27/net/ipv6/Config.in~mipv6-1.1-v2.4.26
1912 +++ linux-2.4.27/net/ipv6/Config.in
1913 @@ -1,10 +1,16 @@
1914  #
1915  # IPv6 configuration
1916  # 
1917 -
1918 +bool '    IPv6: routing by source address (EXPERIMENTAL)' CONFIG_IPV6_SUBTREES
1919  #bool '    IPv6: flow policy support' CONFIG_RT6_POLICY
1920  #bool '    IPv6: firewall support' CONFIG_IPV6_FIREWALL
1921  
1922 +if [ "$CONFIG_IPV6" != "n" ]; then
1923 +       dep_tristate '    IPv6: IPv6 over IPv6 Tunneling (EXPERIMENTAL)' CONFIG_IPV6_TUNNEL $CONFIG_IPV6
1924 +fi
1925 +
1926 +source net/ipv6/mobile_ip6/Config.in
1927 +
1928  if [ "$CONFIG_NETFILTER" != "n" ]; then
1929     source net/ipv6/netfilter/Config.in
1930  fi
1931 --- linux-2.4.27/net/ipv6/Makefile~mipv6-1.1-v2.4.26
1932 +++ linux-2.4.27/net/ipv6/Makefile
1933 @@ -6,18 +6,28 @@
1934  # unless it's something special (ie not a .c file).
1935  #
1936  
1937 +export-objs := ipv6_syms.o ipv6_tunnel.o
1938  
1939 -O_TARGET := ipv6.o
1940 +#list-multi    := ipv6.o ipv6_tunnel.o
1941  
1942 -obj-y :=       af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o sit.o \
1943 -               route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o raw.o \
1944 -               protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \
1945 -               exthdrs.o sysctl_net_ipv6.o datagram.o proc.o \
1946 -               ip6_flowlabel.o ipv6_syms.o
1947 +ipv6-objs      := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o \
1948 +                  sit.o route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o \
1949 +                  raw.o protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \
1950 +                  exthdrs.o sysctl_net_ipv6.o datagram.o proc.o \
1951 +                  ip6_flowlabel.o ipv6_syms.o
1952  
1953 -export-objs := ipv6_syms.o
1954 +ifneq ($(CONFIG_IPV6_MOBILITY),n)
1955 +ifneq ($(CONFIG_IPV6_MOBILITY),)
1956 +ipv6-objs += mipglue.o
1957 +endif
1958 +endif
1959 +
1960 +obj-$(CONFIG_IPV6)  += ipv6.o
1961 +obj-$(CONFIG_IPV6_TUNNEL)  += ipv6_tunnel.o
1962 +
1963 +ipv6.o: $(ipv6-objs)
1964 +       $(LD) -r -o $@ $(ipv6-objs)
1965  
1966 -obj-m  := $(O_TARGET)
1967  
1968  #obj-$(CONFIG_IPV6_FIREWALL) += ip6_fw.o
1969  
1970 --- linux-2.4.27/net/ipv6/addrconf.c~mipv6-1.1-v2.4.26
1971 +++ linux-2.4.27/net/ipv6/addrconf.c
1972 @@ -68,6 +68,8 @@
1973  
1974  #include <asm/uaccess.h>
1975  
1976 +#include <net/mipglue.h>
1977 +
1978  #define IPV6_MAX_ADDRESSES 16
1979  
1980  /* Set to 3 to get tracing... */
1981 @@ -103,9 +105,9 @@
1982  
1983  static int addrconf_ifdown(struct net_device *dev, int how);
1984  
1985 -static void addrconf_dad_start(struct inet6_ifaddr *ifp, int flags);
1986 +void addrconf_dad_start(struct inet6_ifaddr *ifp, int flags);
1987  static void addrconf_dad_timer(unsigned long data);
1988 -static void addrconf_dad_completed(struct inet6_ifaddr *ifp);
1989 +void addrconf_dad_completed(struct inet6_ifaddr *ifp);
1990  static void addrconf_rs_timer(unsigned long data);
1991  static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa);
1992  
1993 @@ -330,38 +332,6 @@
1994         return idev;
1995  }
1996  
1997 -void ipv6_addr_prefix(struct in6_addr *prefix,
1998 -       struct in6_addr *addr, int prefix_len)
1999 -{
2000 -       unsigned long mask;
2001 -       int ncopy, nbits;
2002 -
2003 -       memset(prefix, 0, sizeof(*prefix));
2004 -
2005 -       if (prefix_len <= 0)
2006 -               return;
2007 -       if (prefix_len > 128)
2008 -               prefix_len = 128;
2009 -
2010 -       ncopy = prefix_len / 32;
2011 -       switch (ncopy) {
2012 -       case 4: prefix->s6_addr32[3] = addr->s6_addr32[3];
2013 -       case 3: prefix->s6_addr32[2] = addr->s6_addr32[2];
2014 -       case 2: prefix->s6_addr32[1] = addr->s6_addr32[1];
2015 -       case 1: prefix->s6_addr32[0] = addr->s6_addr32[0];
2016 -       case 0: break;
2017 -       }
2018 -       nbits = prefix_len % 32;
2019 -       if (nbits == 0)
2020 -               return;
2021 -
2022 -       mask = ~((1 << (32 - nbits)) - 1);
2023 -       mask = htonl(mask);
2024 -
2025 -       prefix->s6_addr32[ncopy] = addr->s6_addr32[ncopy] & mask;
2026 -}
2027 -
2028 -
2029  static void dev_forward_change(struct inet6_dev *idev)
2030  {
2031         struct net_device *dev;
2032 @@ -513,7 +483,7 @@
2033  
2034  /* This function wants to get referenced ifp and releases it before return */
2035  
2036 -static void ipv6_del_addr(struct inet6_ifaddr *ifp)
2037 +void ipv6_del_addr(struct inet6_ifaddr *ifp)
2038  {
2039         struct inet6_ifaddr *ifa, **ifap;
2040         struct inet6_dev *idev = ifp->idev;
2041 @@ -662,6 +632,12 @@
2042         if (match)
2043                 in6_ifa_put(match);
2044  
2045 +       /* The home address is always used as source address in
2046 +        * MIPL mobile IPv6
2047 +        */
2048 +       if (scope != IFA_HOST && scope != IFA_LINK)
2049 +               addrconf_get_mipv6_home_address(saddr);
2050 +
2051         return err;
2052  }
2053  
2054 @@ -815,7 +791,7 @@
2055  }
2056  
2057  
2058 -static int ipv6_generate_eui64(u8 *eui, struct net_device *dev)
2059 +int ipv6_generate_eui64(u8 *eui, struct net_device *dev)
2060  {
2061         switch (dev->type) {
2062         case ARPHRD_ETHER:
2063 @@ -840,7 +816,7 @@
2064         return -1;
2065  }
2066  
2067 -static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev)
2068 +int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev)
2069  {
2070         int err = -1;
2071         struct inet6_ifaddr *ifp;
2072 @@ -1407,6 +1383,24 @@
2073                 sit_route_add(dev);
2074  }
2075  
2076 +/**
2077 + * addrconf_ipv6_tunnel_config - configure IPv6 tunnel device
2078 + * @dev: tunnel device
2079 + **/
2080 +
2081 +static void addrconf_ipv6_tunnel_config(struct net_device *dev)
2082 +{
2083 +       struct inet6_dev *idev;
2084 +
2085 +       ASSERT_RTNL();
2086 +
2087 +       /* Assign inet6_dev structure to tunnel device */
2088 +       if ((idev = ipv6_find_idev(dev)) == NULL) {
2089 +               printk(KERN_DEBUG "init ipv6 tunnel: add_dev failed\n");
2090 +               return;
2091 +       }
2092 +}
2093 +
2094  
2095  int addrconf_notify(struct notifier_block *this, unsigned long event, 
2096                     void * data)
2097 @@ -1421,6 +1415,10 @@
2098                         addrconf_sit_config(dev);
2099                         break;
2100  
2101 +               case ARPHRD_TUNNEL6:
2102 +                       addrconf_ipv6_tunnel_config(dev);
2103 +                       break;
2104 +
2105                 case ARPHRD_LOOPBACK:
2106                         init_loopback(dev);
2107                         break;
2108 @@ -1602,7 +1600,7 @@
2109  /*
2110   *     Duplicate Address Detection
2111   */
2112 -static void addrconf_dad_start(struct inet6_ifaddr *ifp, int flags)
2113 +void addrconf_dad_start(struct inet6_ifaddr *ifp, int flags)
2114  {
2115         struct net_device *dev;
2116         unsigned long rand_num;
2117 @@ -1667,7 +1665,7 @@
2118         in6_ifa_put(ifp);
2119  }
2120  
2121 -static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
2122 +void addrconf_dad_completed(struct inet6_ifaddr *ifp)
2123  {
2124         struct net_device *     dev = ifp->idev->dev;
2125  
2126 @@ -1676,7 +1674,7 @@
2127          */
2128  
2129         ipv6_ifa_notify(RTM_NEWADDR, ifp);
2130 -
2131 +       notifier_call_chain(&inet6addr_chain,NETDEV_UP,ifp);
2132         /* If added prefix is link local and forwarding is off,
2133            start sending router solicitations.
2134          */
2135 @@ -1877,8 +1875,20 @@
2136         if (rta[IFA_LOCAL-1]) {
2137                 if (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx)))
2138                         return -EINVAL;
2139 +               if (ifm->ifa_flags & IFA_F_HOMEADDR && !rta[IFA_HOMEAGENT-1])
2140 +                       return -EINVAL;
2141                 pfx = RTA_DATA(rta[IFA_LOCAL-1]);
2142         }
2143 +       if (rta[IFA_HOMEAGENT-1]) {
2144 +               struct in6_addr *ha;
2145 +               if (pfx == NULL || !(ifm->ifa_flags & IFA_F_HOMEADDR))
2146 +                       return -EINVAL;
2147 +               if (RTA_PAYLOAD(rta[IFA_HOMEAGENT-1]) < sizeof(*ha))
2148 +                       return -EINVAL;
2149 +               ha = RTA_DATA(rta[IFA_HOMEAGENT-1]);
2150 +               addrconf_set_mipv6_mn_home(ifm->ifa_index, pfx, ifm->ifa_prefixlen,
2151 +                                          ha, ifm->ifa_prefixlen);
2152 +       }
2153         if (pfx == NULL)
2154                 return -EINVAL;
2155  
2156 --- linux-2.4.27/net/ipv6/af_inet6.c~mipv6-1.1-v2.4.26
2157 +++ linux-2.4.27/net/ipv6/af_inet6.c
2158 @@ -58,6 +58,9 @@
2159  #include <net/transp_v6.h>
2160  #include <net/ip6_route.h>
2161  #include <net/addrconf.h>
2162 +#ifdef CONFIG_IPV6_TUNNEL
2163 +#include <net/ipv6_tunnel.h>
2164 +#endif
2165  
2166  #include <asm/uaccess.h>
2167  #include <asm/system.h>
2168 @@ -646,6 +649,11 @@
2169         err = ndisc_init(&inet6_family_ops);
2170         if (err)
2171                 goto ndisc_fail;
2172 +#ifdef CONFIG_IPV6_TUNNEL
2173 +       err = ip6_tunnel_init();
2174 +       if (err)
2175 +               goto ip6_tunnel_fail;
2176 +#endif
2177         err = igmp6_init(&inet6_family_ops);
2178         if (err)
2179                 goto igmp_fail;
2180 @@ -698,6 +706,10 @@
2181  #endif
2182  igmp_fail:
2183         ndisc_cleanup();
2184 +#ifdef CONFIG_IPV6_TUNNEL
2185 +       ip6_tunnel_cleanup();
2186 +ip6_tunnel_fail:
2187 +#endif
2188  ndisc_fail:
2189         icmpv6_cleanup();
2190  icmp_fail:
2191 @@ -730,6 +742,9 @@
2192         ip6_route_cleanup();
2193         ipv6_packet_cleanup();
2194         igmp6_cleanup();
2195 +#ifdef CONFIG_IPV6_TUNNEL
2196 +       ip6_tunnel_cleanup();
2197 +#endif
2198         ndisc_cleanup();
2199         icmpv6_cleanup();
2200  #ifdef CONFIG_SYSCTL
2201 --- linux-2.4.27/net/ipv6/exthdrs.c~mipv6-1.1-v2.4.26
2202 +++ linux-2.4.27/net/ipv6/exthdrs.c
2203 @@ -41,6 +41,9 @@
2204  #include <net/ip6_route.h>
2205  #include <net/addrconf.h>
2206  
2207 +#include <net/mipglue.h>
2208 +#include <net/mipv6.h>
2209 +
2210  #include <asm/uaccess.h>
2211  
2212  /*
2213 @@ -160,7 +163,8 @@
2214   *****************************/
2215  
2216  struct tlvtype_proc tlvprocdestopt_lst[] = {
2217 -       /* No destination options are defined now */
2218 +       /* Mobility Support destination options */
2219 +       {MIPV6_TLV_HOMEADDR,    mipv6_handle_dstopt},
2220         {-1,                    NULL}
2221  };
2222  
2223 @@ -210,6 +214,7 @@
2224  
2225         struct ipv6_rt_hdr *hdr;
2226         struct rt0_hdr *rthdr;
2227 +       struct rt2_hdr *rt2hdr;
2228  
2229         if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
2230             !pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
2231 @@ -225,17 +230,25 @@
2232                 kfree_skb(skb);
2233                 return -1;
2234         }
2235 -
2236 +       /* Silently discard invalid packets containing RTH type 2 */ 
2237 +       if (hdr->type == IPV6_SRCRT_TYPE_2 && 
2238 +           (hdr->hdrlen != 2 || hdr->segments_left != 1)) {
2239 +               kfree_skb(skb);
2240 +               return -1;
2241 +       }
2242  looped_back:
2243         if (hdr->segments_left == 0) {
2244 -               opt->srcrt = skb->h.raw - skb->nh.raw;
2245 +               if (hdr->type == IPV6_SRCRT_TYPE_0)
2246 +                       opt->srcrt = skb->h.raw - skb->nh.raw;
2247 +               else if (hdr->type == IPV6_SRCRT_TYPE_2)
2248 +                       opt->srcrt2 = skb->h.raw - skb->nh.raw;
2249                 skb->h.raw += (hdr->hdrlen + 1) << 3;
2250                 opt->dst0 = opt->dst1;
2251                 opt->dst1 = 0;
2252                 return (&hdr->nexthdr) - skb->nh.raw;
2253         }
2254  
2255 -       if (hdr->type != IPV6_SRCRT_TYPE_0) {
2256 +       if (hdr->type != IPV6_SRCRT_TYPE_0 && hdr->type != IPV6_SRCRT_TYPE_2) {
2257                 icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw);
2258                 return -1;
2259         }
2260 @@ -275,9 +288,20 @@
2261  
2262         i = n - --hdr->segments_left;
2263  
2264 -       rthdr = (struct rt0_hdr *) hdr;
2265 -       addr = rthdr->addr;
2266 -       addr += i - 1;
2267 +       if (hdr->type == IPV6_SRCRT_TYPE_0) {
2268 +               rthdr = (struct rt0_hdr *) hdr;
2269 +               addr = rthdr->addr;
2270 +               addr += i - 1;
2271 +       } else {
2272 +               /* check that address is this node's home address */
2273 +               rt2hdr = (struct rt2_hdr *) hdr;
2274 +               addr = &rt2hdr->addr;
2275 +               if (!ipv6_chk_addr(addr, NULL) || 
2276 +                   !ipv6_chk_mip_home_addr(addr)) {
2277 +                       kfree_skb(skb);
2278 +                       return -1;
2279 +               }
2280 +       }
2281  
2282         addr_type = ipv6_addr_type(addr);
2283  
2284 @@ -330,6 +354,10 @@
2285     temporary (or permanent) backdoor.
2286     If listening socket set IPV6_RTHDR to 2, then we invert header.
2287                                                     --ANK (980729)
2288 +
2289 +   By the Mobile IPv6 specification Type 2 routing header MUST NOT be
2290 +   inverted.
2291 +                                                   --AJT (20020917)
2292   */
2293  
2294  struct ipv6_txoptions *
2295 @@ -352,6 +380,18 @@
2296         struct ipv6_txoptions *opt;
2297         int hdrlen = ipv6_optlen(hdr);
2298  
2299 +       if (hdr->type == IPV6_SRCRT_TYPE_2) {
2300 +               opt = sock_kmalloc(sk, sizeof(*opt) + hdrlen, GFP_ATOMIC);
2301 +               if (opt == NULL)
2302 +                       return NULL;
2303 +               memset(opt, 0, sizeof(*opt));
2304 +               opt->tot_len = sizeof(*opt) + hdrlen;
2305 +               opt->srcrt = (void*)(opt+1);
2306 +               opt->opt_nflen = hdrlen;
2307 +               memcpy(opt->srcrt, hdr, sizeof(struct rt2_hdr));
2308 +               return opt;
2309 +       }
2310 +
2311         if (hdr->segments_left ||
2312             hdr->type != IPV6_SRCRT_TYPE_0 ||
2313             hdr->hdrlen & 0x01)
2314 @@ -622,8 +662,18 @@
2315         if (opt) {
2316                 if (opt->dst0opt)
2317                         prev_hdr = ipv6_build_exthdr(skb, prev_hdr, NEXTHDR_DEST, opt->dst0opt);
2318 -               if (opt->srcrt)
2319 -                       prev_hdr = ipv6_build_rthdr(skb, prev_hdr, opt->srcrt, daddr);
2320 +               if (opt->srcrt) {
2321 +                       if (opt->srcrt2) {
2322 +                               struct in6_addr *rt2_hop = &((struct rt2_hdr *)opt->srcrt2)->addr;
2323 +                               prev_hdr = ipv6_build_rthdr(skb, prev_hdr, opt->srcrt, rt2_hop);
2324 +                       } else
2325 +                               prev_hdr = ipv6_build_rthdr(skb, prev_hdr, opt->srcrt, daddr);
2326 +               }
2327 +               if (opt->srcrt2) {
2328 +                       struct inet6_skb_parm *parm = (struct inet6_skb_parm *)skb->cb;
2329 +                       ipv6_addr_copy(&parm->hoa, daddr);
2330 +                       prev_hdr = ipv6_build_rthdr(skb, prev_hdr, opt->srcrt2, daddr);
2331 +               }
2332         }
2333         return prev_hdr;
2334  }
2335 @@ -684,6 +734,11 @@
2336                           u8 *proto,
2337                           struct in6_addr **daddr)
2338  {
2339 +       if (opt->srcrt2) {
2340 +               struct inet6_skb_parm *parm = (struct inet6_skb_parm *)skb->cb;
2341 +               ipv6_addr_copy(&parm->hoa, *daddr);
2342 +               ipv6_push_rthdr(skb, proto, opt->srcrt2, daddr);
2343 +       }
2344         if (opt->srcrt)
2345                 ipv6_push_rthdr(skb, proto, opt->srcrt, daddr);
2346         if (opt->dst0opt)
2347 @@ -719,6 +774,8 @@
2348                         *((char**)&opt2->auth) += dif;
2349                 if (opt2->srcrt)
2350                         *((char**)&opt2->srcrt) += dif;
2351 +               if (opt2->srcrt2)
2352 +                       *((char**)&opt2->srcrt2) += dif;
2353         }
2354         return opt2;
2355  }
2356 --- linux-2.4.27/net/ipv6/icmp.c~mipv6-1.1-v2.4.26
2357 +++ linux-2.4.27/net/ipv6/icmp.c
2358 @@ -61,6 +61,8 @@
2359  #include <net/addrconf.h>
2360  #include <net/icmp.h>
2361  
2362 +#include <net/mipglue.h>
2363 +
2364  #include <asm/uaccess.h>
2365  #include <asm/system.h>
2366  
2367 @@ -364,6 +366,8 @@
2368  
2369         msg.len = len;
2370  
2371 +       icmpv6_swap_mipv6_addrs(skb);
2372 +
2373         ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, len, NULL, -1,
2374                        MSG_DONTWAIT);
2375         if (type >= ICMPV6_DEST_UNREACH && type <= ICMPV6_PARAMPROB)
2376 @@ -562,13 +566,13 @@
2377                 rt6_pmtu_discovery(&orig_hdr->daddr, &orig_hdr->saddr, dev,
2378                                    ntohl(hdr->icmp6_mtu));
2379  
2380 -               /*
2381 -                *      Drop through to notify
2382 -                */
2383 +               icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
2384 +               break;
2385  
2386         case ICMPV6_DEST_UNREACH:
2387 -       case ICMPV6_TIME_EXCEED:
2388         case ICMPV6_PARAMPROB:
2389 +               mipv6_icmp_rcv(skb);
2390 +       case ICMPV6_TIME_EXCEED:
2391                 icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu);
2392                 break;
2393  
2394 @@ -598,6 +602,13 @@
2395         case ICMPV6_MLD2_REPORT:
2396                 break;
2397  
2398 +       case MIPV6_DHAAD_REQUEST:
2399 +       case MIPV6_DHAAD_REPLY:
2400 +       case MIPV6_PREFIX_SOLICIT:
2401 +       case MIPV6_PREFIX_ADV:
2402 +               mipv6_icmp_rcv(skb);
2403 +               break;
2404 +
2405         default:
2406                 if (net_ratelimit())
2407                         printk(KERN_DEBUG "icmpv6: msg of unkown type\n");
2408 --- linux-2.4.27/net/ipv6/ip6_fib.c~mipv6-1.1-v2.4.26
2409 +++ linux-2.4.27/net/ipv6/ip6_fib.c
2410 @@ -18,6 +18,7 @@
2411   *     Yuji SEKIYA @USAGI:     Support default route on router node;
2412   *                             remove ip6_null_entry from the top of
2413   *                             routing table.
2414 + *     Ville Nuorvala:         Fixes to source address based routing
2415   */
2416  #include <linux/config.h>
2417  #include <linux/errno.h>
2418 @@ -40,7 +41,6 @@
2419  #include <net/ip6_route.h>
2420  
2421  #define RT6_DEBUG 2
2422 -#undef CONFIG_IPV6_SUBTREES
2423  
2424  #if RT6_DEBUG >= 3
2425  #define RT6_TRACE(x...) printk(KERN_DEBUG x)
2426 @@ -500,6 +500,8 @@
2427                 mod_timer(&ip6_fib_timer, jiffies + ip6_rt_gc_interval);
2428  }
2429  
2430 +static struct rt6_info * fib6_find_prefix(struct fib6_node *fn);
2431 +
2432  /*
2433   *     Add routing information to the routing tree.
2434   *     <destination addr>/<source addr>
2435 @@ -508,17 +510,19 @@
2436  
2437  int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nlmsghdr *nlh)
2438  {
2439 -       struct fib6_node *fn;
2440 +       struct fib6_node *fn = root;
2441         int err = -ENOMEM;
2442  
2443 -       fn = fib6_add_1(root, &rt->rt6i_dst.addr, sizeof(struct in6_addr),
2444 -                       rt->rt6i_dst.plen, (u8*) &rt->rt6i_dst - (u8*) rt);
2445 +#ifdef CONFIG_IPV6_SUBTREES
2446 +       struct fib6_node *pn = NULL;
2447  
2448 +       fn = fib6_add_1(root, &rt->rt6i_src.addr, sizeof(struct in6_addr),
2449 +                       rt->rt6i_src.plen, (u8*) &rt->rt6i_src - (u8*) rt);
2450 +       
2451         if (fn == NULL)
2452                 goto out;
2453  
2454 -#ifdef CONFIG_IPV6_SUBTREES
2455 -       if (rt->rt6i_src.plen) {
2456 +       if (rt->rt6i_dst.plen) {
2457                 struct fib6_node *sn;
2458  
2459                 if (fn->subtree == NULL) {
2460 @@ -546,9 +550,9 @@
2461  
2462                         /* Now add the first leaf node to new subtree */
2463  
2464 -                       sn = fib6_add_1(sfn, &rt->rt6i_src.addr,
2465 -                                       sizeof(struct in6_addr), rt->rt6i_src.plen,
2466 -                                       (u8*) &rt->rt6i_src - (u8*) rt);
2467 +                       sn = fib6_add_1(sfn, &rt->rt6i_dst.addr,
2468 +                                       sizeof(struct in6_addr), rt->rt6i_dst.plen,
2469 +                                       (u8*) &rt->rt6i_dst - (u8*) rt);
2470  
2471                         if (sn == NULL) {
2472                                 /* If it is failed, discard just allocated
2473 @@ -562,21 +566,30 @@
2474                         /* Now link new subtree to main tree */
2475                         sfn->parent = fn;
2476                         fn->subtree = sfn;
2477 -                       if (fn->leaf == NULL) {
2478 -                               fn->leaf = rt;
2479 -                               atomic_inc(&rt->rt6i_ref);
2480 -                       }
2481                 } else {
2482 -                       sn = fib6_add_1(fn->subtree, &rt->rt6i_src.addr,
2483 -                                       sizeof(struct in6_addr), rt->rt6i_src.plen,
2484 -                                       (u8*) &rt->rt6i_src - (u8*) rt);
2485 +                       sn = fib6_add_1(fn->subtree, &rt->rt6i_dst.addr,
2486 +                                       sizeof(struct in6_addr), rt->rt6i_dst.plen,
2487 +                                       (u8*) &rt->rt6i_dst - (u8*) rt);
2488  
2489                         if (sn == NULL)
2490                                 goto st_failure;
2491                 }
2492  
2493 +               /* fib6_add_1 might have cleared the old leaf pointer */
2494 +               if (fn->leaf == NULL) {
2495 +                       fn->leaf = rt;
2496 +                       atomic_inc(&rt->rt6i_ref);
2497 +               }
2498 +
2499 +               pn = fn;
2500                 fn = sn;
2501         }
2502 +#else 
2503 +       fn = fib6_add_1(root, &rt->rt6i_dst.addr, sizeof(struct in6_addr),
2504 +                       rt->rt6i_dst.plen, (u8*) &rt->rt6i_dst - (u8*) rt);
2505 +
2506 +       if (fn == NULL)
2507 +               goto out;
2508  #endif
2509  
2510         err = fib6_add_rt2node(fn, rt, nlh);
2511 @@ -588,8 +601,30 @@
2512         }
2513  
2514  out:
2515 -       if (err)
2516 +       if (err) {
2517 +#ifdef CONFIG_IPV6_SUBTREES
2518 +
2519 +               /* If fib6_add_1 has cleared the old leaf pointer in the 
2520 +                  super-tree leaf node, we have to find a new one for it. 
2521 +                  
2522 +                  This situation will never arise in the sub-tree since 
2523 +                  the node will at least have the route that caused 
2524 +                  fib6_add_rt2node to fail.
2525 +               */
2526 +
2527 +               if (pn && !(pn->fn_flags & RTN_RTINFO)) {
2528 +                       pn->leaf = fib6_find_prefix(pn);
2529 +#if RT6_DEBUG >= 2
2530 +                       if (!pn->leaf) {
2531 +                               BUG_TRAP(pn->leaf);
2532 +                               pn->leaf = &ip6_null_entry;
2533 +                       }
2534 +#endif
2535 +                       atomic_inc(&pn->leaf->rt6i_ref);
2536 +               }
2537 +#endif
2538                 dst_free(&rt->u.dst);
2539 +       }
2540         return err;
2541  
2542  #ifdef CONFIG_IPV6_SUBTREES
2543 @@ -597,8 +632,8 @@
2544            is orphan. If it is, shoot it.
2545          */
2546  st_failure:
2547 -       if (fn && !(fn->fn_flags&RTN_RTINFO|RTN_ROOT))
2548 -               fib_repair_tree(fn);
2549 +       if (fn && !(fn->fn_flags & (RTN_RTINFO | RTN_ROOT)))
2550 +               fib6_repair_tree(fn);
2551         dst_free(&rt->u.dst);
2552         return err;
2553  #endif
2554 @@ -641,22 +676,28 @@
2555                 break;
2556         }
2557  
2558 -       while ((fn->fn_flags & RTN_ROOT) == 0) {
2559 +       for (;;) {
2560  #ifdef CONFIG_IPV6_SUBTREES
2561                 if (fn->subtree) {
2562 -                       struct fib6_node *st;
2563 -                       struct lookup_args *narg;
2564 -
2565 -                       narg = args + 1;
2566 -
2567 -                       if (narg->addr) {
2568 -                               st = fib6_lookup_1(fn->subtree, narg);
2569 +                       struct rt6key *key;
2570  
2571 -                               if (st && !(st->fn_flags & RTN_ROOT))
2572 -                                       return st;
2573 +                       key = (struct rt6key *) ((u8 *) fn->leaf +
2574 +                                                args->offset);
2575 +                       
2576 +                       if (addr_match(&key->addr, args->addr, key->plen)) {
2577 +                               struct fib6_node *st;
2578 +                               struct lookup_args *narg = args + 1;
2579 +                               if (!ipv6_addr_any(narg->addr)) {
2580 +                                       st = fib6_lookup_1(fn->subtree, narg);
2581 +                                       
2582 +                                       if (st && !(st->fn_flags & RTN_ROOT))
2583 +                                               return st;
2584 +                               } 
2585                         }
2586                 }
2587  #endif
2588 +               if (fn->fn_flags & RTN_ROOT)
2589 +                       break;
2590  
2591                 if (fn->fn_flags & RTN_RTINFO) {
2592                         struct rt6key *key;
2593 @@ -680,13 +721,22 @@
2594         struct lookup_args args[2];
2595         struct rt6_info *rt = NULL;
2596         struct fib6_node *fn;
2597 +#ifdef CONFIG_IPV6_SUBTREES
2598 +       struct in6_addr saddr_buf;
2599 +#endif
2600  
2601 +#ifdef CONFIG_IPV6_SUBTREES
2602 +       if (saddr == NULL) {
2603 +               memset(&saddr_buf, 0, sizeof(struct in6_addr));
2604 +               saddr = &saddr_buf;
2605 +       }
2606 +       args[0].offset = (u8*) &rt->rt6i_src - (u8*) rt;
2607 +       args[0].addr = saddr;
2608 +       args[1].offset = (u8*) &rt->rt6i_dst - (u8*) rt;
2609 +       args[1].addr = daddr;
2610 +#else 
2611         args[0].offset = (u8*) &rt->rt6i_dst - (u8*) rt;
2612         args[0].addr = daddr;
2613 -
2614 -#ifdef CONFIG_IPV6_SUBTREES
2615 -       args[1].offset = (u8*) &rt->rt6i_src - (u8*) rt;
2616 -       args[1].addr = saddr;
2617  #endif
2618  
2619         fn = fib6_lookup_1(root, args);
2620 @@ -739,19 +789,25 @@
2621  {
2622         struct rt6_info *rt = NULL;
2623         struct fib6_node *fn;
2624 -
2625 -       fn = fib6_locate_1(root, daddr, dst_len,
2626 -                          (u8*) &rt->rt6i_dst - (u8*) rt);
2627 -
2628  #ifdef CONFIG_IPV6_SUBTREES
2629 -       if (src_len) {
2630 -               BUG_TRAP(saddr!=NULL);
2631 -               if (fn == NULL)
2632 -                       fn = fn->subtree;
2633 +       struct in6_addr saddr_buf;
2634 +
2635 +       if (saddr == NULL) {
2636 +               memset(&saddr_buf, 0, sizeof(struct in6_addr));
2637 +               saddr = &saddr_buf;
2638 +       }
2639 +       fn = fib6_locate_1(root, saddr, src_len, 
2640 +                          (u8*) &rt->rt6i_src - (u8*) rt);
2641 +       if (dst_len) {
2642                 if (fn)
2643 -                       fn = fib6_locate_1(fn, saddr, src_len,
2644 -                                          (u8*) &rt->rt6i_src - (u8*) rt);
2645 +                       fn = fib6_locate_1(fn->subtree, daddr, dst_len,
2646 +                                          (u8*) &rt->rt6i_dst - (u8*) rt);
2647 +               else 
2648 +                       return NULL;
2649         }
2650 +#else
2651 +       fn = fib6_locate_1(root, daddr, dst_len,
2652 +                          (u8*) &rt->rt6i_dst - (u8*) rt);
2653  #endif
2654  
2655         if (fn && fn->fn_flags&RTN_RTINFO)
2656 @@ -939,7 +995,7 @@
2657                         }
2658                         fn = fn->parent;
2659                 }
2660 -               /* No more references are possiible at this point. */
2661 +               /* No more references are possible at this point. */
2662                 if (atomic_read(&rt->rt6i_ref) != 1) BUG();
2663         }
2664  
2665 --- linux-2.4.27/net/ipv6/ip6_input.c~mipv6-1.1-v2.4.26
2666 +++ linux-2.4.27/net/ipv6/ip6_input.c
2667 @@ -40,13 +40,42 @@
2668  #include <net/ip6_route.h>
2669  #include <net/addrconf.h>
2670  
2671 +static inline int ip6_proxy_chk(struct sk_buff *skb)
2672 +{
2673 +       struct ipv6hdr *hdr = skb->nh.ipv6h;
2674 +
2675 +       if (ipv6_addr_type(&hdr->daddr)&IPV6_ADDR_UNICAST &&
2676 +           pneigh_lookup(&nd_tbl, &hdr->daddr, skb->dev, 0)) {
2677 +               u8 nexthdr = hdr->nexthdr;
2678 +               int offset;
2679 +               struct icmp6hdr msg;
2680  
2681 +               if (ipv6_ext_hdr(nexthdr)) {
2682 +                       offset = ipv6_skip_exthdr(skb, sizeof(*hdr), &nexthdr, 
2683 +                                                 skb->len - sizeof(*hdr));
2684 +                       if (offset < 0)
2685 +                               return 0;
2686 +               } else
2687 +                       offset = sizeof(*hdr);
2688 +
2689 +               /* capture unicast NUD probes on behalf of the proxied node */
2690  
2691 +               if (nexthdr == IPPROTO_ICMPV6 &&
2692 +                   !skb_copy_bits(skb, offset, &msg, sizeof(msg)) &&
2693 +                   msg.icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) {
2694 +                       return 1;
2695 +               }
2696 +       }
2697 +       return 0;
2698 +}
2699
2700  static inline int ip6_rcv_finish( struct sk_buff *skb) 
2701  {
2702 -       if (skb->dst == NULL)
2703 -               ip6_route_input(skb);
2704 -
2705 +       if (skb->dst == NULL) {
2706 +               if (ip6_proxy_chk(skb)) 
2707 +                       return ip6_input(skb);
2708 +               ip6_route_input(skb);
2709 +       }
2710         return skb->dst->input(skb);
2711  }
2712  
2713 --- linux-2.4.27/net/ipv6/ip6_output.c~mipv6-1.1-v2.4.26
2714 +++ linux-2.4.27/net/ipv6/ip6_output.c
2715 @@ -50,6 +50,8 @@
2716  #include <net/rawv6.h>
2717  #include <net/icmp.h>
2718  
2719 +#include <net/mipglue.h>
2720 +
2721  static __inline__ void ipv6_select_ident(struct sk_buff *skb, struct frag_hdr *fhdr)
2722  {
2723         static u32 ipv6_fragmentation_id = 1;
2724 @@ -194,7 +196,14 @@
2725         u8  proto = fl->proto;
2726         int seg_len = skb->len;
2727         int hlimit;
2728 +       int retval;
2729 +       struct ipv6_txoptions *orig_opt = opt;
2730 +
2731 +       opt = ip6_add_mipv6_txoptions(sk, skb, orig_opt, fl, &dst);
2732  
2733 +       if(orig_opt && !opt)
2734 +               return -ENOMEM;
2735 +               
2736         if (opt) {
2737                 int head_room;
2738  
2739 @@ -209,8 +218,11 @@
2740                         struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room);
2741                         kfree_skb(skb);
2742                         skb = skb2;
2743 -                       if (skb == NULL)
2744 +                       if (skb == NULL) {
2745 +                               ip6_free_mipv6_txoptions(opt, orig_opt);
2746 +
2747                                 return -ENOBUFS;
2748 +                       }
2749                         if (sk)
2750                                 skb_set_owner_w(skb, sk);
2751                 }
2752 @@ -242,7 +254,10 @@
2753  
2754         if (skb->len <= dst->pmtu) {
2755                 IP6_INC_STATS(Ip6OutRequests);
2756 -               return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_maybe_reroute);
2757 +               ip6_mark_mipv6_packet(opt, skb);
2758 +               retval = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_maybe_reroute);
2759 +               ip6_free_mipv6_txoptions(opt, orig_opt);
2760 +               return retval; 
2761         }
2762  
2763         if (net_ratelimit())
2764 @@ -250,6 +265,9 @@
2765         skb->dev = dst->dev;
2766         icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst->pmtu, skb->dev);
2767         kfree_skb(skb);
2768 +
2769 +       ip6_free_mipv6_txoptions(opt, orig_opt);
2770 +
2771         return -EMSGSIZE;
2772  }
2773  
2774 @@ -473,6 +491,7 @@
2775  
2776                         IP6_INC_STATS(Ip6FragCreates);
2777                         IP6_INC_STATS(Ip6OutRequests);
2778 +                       ip6_mark_mipv6_packet(opt, skb);
2779                         err = NF_HOOK(PF_INET6,NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_maybe_reroute);
2780                         if (err) {
2781                                 kfree_skb(last_skb);
2782 @@ -499,6 +518,7 @@
2783         IP6_INC_STATS(Ip6FragCreates);
2784         IP6_INC_STATS(Ip6FragOKs);
2785         IP6_INC_STATS(Ip6OutRequests);
2786 +       ip6_mark_mipv6_packet(opt, last_skb);
2787         return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, last_skb, NULL,dst->dev, ip6_maybe_reroute);
2788  }
2789  
2790 @@ -509,26 +529,43 @@
2791         struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
2792         struct in6_addr *final_dst = NULL;
2793         struct dst_entry *dst;
2794 +       struct rt6_info *rt;
2795         int err = 0;
2796         unsigned int pktlength, jumbolen, mtu;
2797         struct in6_addr saddr;
2798 +       struct ipv6_txoptions *orig_opt = opt; 
2799 +#ifdef CONFIG_IPV6_SUBTREES
2800 +       struct dst_entry *org_dst;
2801 +#endif
2802 +
2803 +       opt = ip6_add_mipv6_txoptions(sk, NULL, orig_opt, fl, NULL);
2804 +
2805 +       if(orig_opt && !opt)
2806 +               return -ENOMEM;
2807  
2808         if (opt && opt->srcrt) {
2809                 struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
2810                 final_dst = fl->fl6_dst;
2811                 fl->fl6_dst = rt0->addr;
2812 -       }
2813 +       } else if (opt && opt->srcrt2) {
2814 +                struct rt2_hdr *rt2 = (struct rt2_hdr *) opt->srcrt2;
2815 +                final_dst = fl->fl6_dst;
2816 +                fl->fl6_dst = &rt2->addr;
2817 +        }
2818  
2819         if (!fl->oif && ipv6_addr_is_multicast(fl->nl_u.ip6_u.daddr))
2820                 fl->oif = np->mcast_oif;
2821  
2822         dst = __sk_dst_check(sk, np->dst_cookie);
2823 +#ifdef CONFIG_IPV6_SUBTREES
2824 +       org_dst = dst;
2825 +#endif
2826         if (dst) {
2827 -               struct rt6_info *rt = (struct rt6_info*)dst;
2828 +               rt = (struct rt6_info*)dst;
2829  
2830                         /* Yes, checking route validity in not connected
2831                            case is not very simple. Take into account,
2832 -                          that we do not support routing by source, TOS,
2833 +                          that we do not support routing by TOS,
2834                            and MSG_DONTROUTE            --ANK (980726)
2835  
2836                            1. If route was host route, check that
2837 @@ -548,6 +585,13 @@
2838                       ipv6_addr_cmp(fl->fl6_dst, &rt->rt6i_dst.addr))
2839                      && (np->daddr_cache == NULL ||
2840                          ipv6_addr_cmp(fl->fl6_dst, np->daddr_cache)))
2841 +#ifdef CONFIG_IPV6_SUBTREES
2842 +                   || (fl->fl6_src != NULL
2843 +                       && (rt->rt6i_src.plen != 128 ||
2844 +                           ipv6_addr_cmp(fl->fl6_src, &rt->rt6i_src.addr))
2845 +                       && (np->saddr_cache == NULL ||
2846 +                           ipv6_addr_cmp(fl->fl6_src, np->saddr_cache)))
2847 +#endif
2848                     || (fl->oif && fl->oif != dst->dev->ifindex)) {
2849                         dst = NULL;
2850                 } else
2851 @@ -560,21 +604,42 @@
2852         if (dst->error) {
2853                 IP6_INC_STATS(Ip6OutNoRoutes);
2854                 dst_release(dst);
2855 +               ip6_free_mipv6_txoptions(opt, orig_opt);
2856                 return -ENETUNREACH;
2857         }
2858  
2859         if (fl->fl6_src == NULL) {
2860                 err = ipv6_get_saddr(dst, fl->fl6_dst, &saddr);
2861 -
2862                 if (err) {
2863  #if IP6_DEBUG >= 2
2864                         printk(KERN_DEBUG "ip6_build_xmit: "
2865                                "no available source address\n");
2866  #endif
2867 +
2868 +#ifdef CONFIG_IPV6_SUBTREES
2869 +                       if (dst != org_dst) {
2870 +                               dst_release(dst);
2871 +                               dst = org_dst;
2872 +                       }
2873 +#endif         
2874                         goto out;
2875                 }
2876                 fl->fl6_src = &saddr;
2877         }
2878 +#ifdef CONFIG_IPV6_SUBTREES
2879 +       rt = (struct rt6_info*)dst;
2880 +       if (dst != org_dst || rt->rt6i_src.plen != 128 ||
2881 +           ipv6_addr_cmp(fl->fl6_src, &rt->rt6i_src.addr)) {
2882 +               dst_release(dst);
2883 +               dst = ip6_route_output(sk, fl);
2884 +               if (dst->error) {
2885 +                       IP6_INC_STATS(Ip6OutNoRoutes);
2886 +                       dst_release(dst);
2887 +                       ip6_free_mipv6_txoptions(opt, orig_opt);
2888 +                       return -ENETUNREACH;
2889 +               }
2890 +       }
2891 +#endif
2892         pktlength = length;
2893  
2894         if (hlimit < 0) {
2895 @@ -667,6 +732,7 @@
2896  
2897                 if (!err) {
2898                         IP6_INC_STATS(Ip6OutRequests);
2899 +                       ip6_mark_mipv6_packet(opt, skb);
2900                         err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_maybe_reroute);
2901                 } else {
2902                         err = -EFAULT;
2903 @@ -688,9 +754,14 @@
2904          *      cleanup
2905          */
2906  out:
2907 -       ip6_dst_store(sk, dst, fl->nl_u.ip6_u.daddr == &np->daddr ? &np->daddr : NULL);
2908 +       ip6_dst_store(sk, dst, 
2909 +                     fl->nl_u.ip6_u.daddr == &np->daddr ? &np->daddr : NULL,
2910 +                     fl->nl_u.ip6_u.saddr == &np->saddr ? &np->saddr : NULL);
2911         if (err > 0)
2912                 err = np->recverr ? net_xmit_errno(err) : 0;
2913 +
2914 +       ip6_free_mipv6_txoptions(opt, orig_opt);
2915 +
2916         return err;
2917  }
2918  
2919 @@ -769,6 +840,15 @@
2920                 return -ETIMEDOUT;
2921         }
2922  
2923 +       /* The proxying router can't forward traffic sent to a link-local
2924 +          address, so signal the sender and discard the packet. This
2925 +          behavior is required by the MIPv6 specification. */
2926 +
2927 +       if (ipv6_addr_type(&hdr->daddr) & IPV6_ADDR_LINKLOCAL && 
2928 +           skb->dev && pneigh_lookup(&nd_tbl, &hdr->daddr, skb->dev, 0)) {
2929 +               dst_link_failure(skb);
2930 +               goto drop;
2931 +       }
2932         /* IPv6 specs say nothing about it, but it is clear that we cannot
2933            send redirects to source routed frames.
2934          */
2935 --- linux-2.4.27/net/ipv6/ipv6_syms.c~mipv6-1.1-v2.4.26
2936 +++ linux-2.4.27/net/ipv6/ipv6_syms.c
2937 @@ -6,6 +6,8 @@
2938  #include <net/ipv6.h>
2939  #include <net/addrconf.h>
2940  #include <net/ip6_route.h>
2941 +#include <net/ndisc.h>
2942 +#include <net/mipglue.h>
2943  
2944  EXPORT_SYMBOL(ipv6_addr_type);
2945  EXPORT_SYMBOL(icmpv6_send);
2946 @@ -35,3 +37,47 @@
2947  EXPORT_SYMBOL(in6_dev_finish_destroy);
2948  EXPORT_SYMBOL(ipv6_skip_exthdr);
2949  
2950 +#if defined(CONFIG_IPV6_TUNNEL_MODULE) || defined(CONFIG_IPV6_MOBILITY_MODULE)
2951 +EXPORT_SYMBOL(ip6_build_xmit);
2952 +EXPORT_SYMBOL(rt6_lookup);
2953 +EXPORT_SYMBOL(ipv6_ext_hdr);
2954 +#endif
2955 +#ifdef CONFIG_IPV6_MOBILITY_MODULE
2956 +EXPORT_SYMBOL(mipv6_functions);
2957 +EXPORT_SYMBOL(mipv6_invalidate_calls);
2958 +#if defined(CONFIG_IPV6_MOBILITY_HA_MODULE) || defined(CONFIG_IPV6_MOBILITY_MN_MODULE)
2959 +EXPORT_SYMBOL(ip6_route_add);
2960 +EXPORT_SYMBOL(ip6_route_del);
2961 +EXPORT_SYMBOL(ipv6_get_lladdr);
2962 +EXPORT_SYMBOL(ipv6_get_ifaddr);
2963 +EXPORT_SYMBOL(nd_tbl);
2964 +EXPORT_SYMBOL(ndisc_send_ns);
2965 +EXPORT_SYMBOL(ndisc_send_na);
2966 +EXPORT_SYMBOL(ndisc_next_option);
2967 +EXPORT_SYMBOL(inet6_ifa_finish_destroy);
2968 +#endif
2969 +#ifdef CONFIG_IPV6_MOBILITY_HA_MODULE
2970 +EXPORT_SYMBOL(ipv6_dev_ac_dec);
2971 +EXPORT_SYMBOL(ipv6_dev_ac_inc);
2972 +EXPORT_SYMBOL(ipv6_dev_mc_dec);
2973 +EXPORT_SYMBOL(ipv6_dev_mc_inc);
2974 +EXPORT_SYMBOL(ip6_forward);
2975 +EXPORT_SYMBOL(ip6_input);
2976 +EXPORT_SYMBOL(ipv6_chk_acast_addr);
2977 +#endif
2978 +#ifdef CONFIG_IPV6_MOBILITY_MN_MODULE
2979 +#endif
2980 +EXPORT_SYMBOL(addrconf_add_ifaddr);
2981 +EXPORT_SYMBOL(addrconf_del_ifaddr);
2982 +EXPORT_SYMBOL(addrconf_dad_start);
2983 +EXPORT_SYMBOL(ip6_del_rt);
2984 +EXPORT_SYMBOL(ip6_routing_table);
2985 +EXPORT_SYMBOL(rt6_get_dflt_router);
2986 +EXPORT_SYMBOL(rt6_purge_dflt_routers);
2987 +EXPORT_SYMBOL(rt6_lock);
2988 +EXPORT_SYMBOL(ndisc_send_rs);
2989 +EXPORT_SYMBOL(fib6_clean_tree);
2990 +EXPORT_SYMBOL(ipv6_del_addr);
2991 +EXPORT_SYMBOL(ipv6_generate_eui64);
2992 +EXPORT_SYMBOL(ipv6_inherit_eui64);
2993 +#endif
2994 --- /dev/null
2995 +++ linux-2.4.27/net/ipv6/ipv6_tunnel.c
2996 @@ -0,0 +1,1604 @@
2997 +/*
2998 + *     IPv6 over IPv6 tunnel device
2999 + *     Linux INET6 implementation
3000 + *
3001 + *     Authors:
3002 + *     Ville Nuorvala          <vnuorval@tcs.hut.fi>   
3003 + *
3004 + *     $Id$
3005 + *
3006 + *      Based on:
3007 + *      linux/net/ipv6/sit.c
3008 + *
3009 + *      RFC 2473
3010 + *
3011 + *     This program is free software; you can redistribute it and/or
3012 + *      modify it under the terms of the GNU General Public License
3013 + *      as published by the Free Software Foundation; either version
3014 + *      2 of the License, or (at your option) any later version.
3015 + *
3016 + */
3017 +
3018 +#include <linux/config.h>
3019 +#include <linux/module.h>
3020 +#include <linux/errno.h>
3021 +#include <linux/types.h>
3022 +#include <linux/socket.h>
3023 +#include <linux/sockios.h>
3024 +#include <linux/if.h>
3025 +#include <linux/in.h>
3026 +#include <linux/ip.h>
3027 +#include <linux/if_tunnel.h>
3028 +#include <linux/net.h>
3029 +#include <linux/in6.h>
3030 +#include <linux/netdevice.h>
3031 +#include <linux/if_arp.h>
3032 +#include <linux/icmpv6.h>
3033 +#include <linux/init.h>
3034 +#include <linux/route.h>
3035 +#include <linux/rtnetlink.h>
3036 +#include <linux/tqueue.h>
3037 +
3038 +#include <asm/uaccess.h>
3039 +#include <asm/atomic.h>
3040 +
3041 +#include <net/sock.h>
3042 +#include <net/ipv6.h>
3043 +#include <net/protocol.h>
3044 +#include <net/ip6_route.h>
3045 +#include <net/addrconf.h>
3046 +#include <net/ipv6_tunnel.h>
3047 +
3048 +MODULE_AUTHOR("Ville Nuorvala");
3049 +MODULE_DESCRIPTION("IPv6-in-IPv6 tunnel");
3050 +MODULE_LICENSE("GPL");
3051 +
3052 +#define IPV6_TLV_TEL_DST_SIZE 8
3053 +
3054 +#ifdef IP6_TNL_DEBUG
3055 +#define IP6_TNL_TRACE(x...) printk(KERN_DEBUG "%s:" x "\n", __FUNCTION__)
3056 +#else
3057 +#define IP6_TNL_TRACE(x...) do {;} while(0)
3058 +#endif
3059 +
3060 +#define IPV6_TCLASS_MASK (IPV6_FLOWINFO_MASK & ~IPV6_FLOWLABEL_MASK)
3061 +
3062 +#define HASH_SIZE  32
3063 +
3064 +#define HASH(addr) (((addr)->s6_addr32[0] ^ (addr)->s6_addr32[1] ^ \
3065 +                    (addr)->s6_addr32[2] ^ (addr)->s6_addr32[3]) & \
3066 +                    (HASH_SIZE - 1))
3067 +
3068 +static int ip6ip6_fb_tnl_dev_init(struct net_device *dev);
3069 +static int ip6ip6_tnl_dev_init(struct net_device *dev);
3070 +
3071 +/* the IPv6 IPv6 tunnel fallback device */
3072 +static struct net_device ip6ip6_fb_tnl_dev = {
3073 +       name: "ip6tnl0",
3074 +       init: ip6ip6_fb_tnl_dev_init
3075 +};
3076 +
3077 +/* the IPv6 IPv6 fallback tunnel */
3078 +static struct ip6_tnl ip6ip6_fb_tnl = {
3079 +       dev: &ip6ip6_fb_tnl_dev,
3080 +       parms:{name: "ip6tnl0", proto: IPPROTO_IPV6}
3081 +};
3082 +
3083 +/* lists for storing tunnels in use */
3084 +static struct ip6_tnl *tnls_r_l[HASH_SIZE];
3085 +static struct ip6_tnl *tnls_wc[1];
3086 +static struct ip6_tnl **tnls[2] = { tnls_wc, tnls_r_l };
3087 +
3088 +/* list for unused cached kernel tunnels */
3089 +static struct ip6_tnl *tnls_kernel[1];
3090 +/* maximum number of cached kernel tunnels */
3091 +static unsigned int max_kdev_count = 0;
3092 +/* minimum number of cached kernel tunnels */
3093 +static unsigned int min_kdev_count = 0;
3094 +/* current number of cached kernel tunnels */
3095 +static unsigned int kdev_count = 0;
3096 +
3097 +/* lists for tunnel hook functions */
3098 +static struct list_head hooks[IP6_TNL_MAXHOOKS];
3099 +
3100 +/* locks for the different lists */
3101 +static rwlock_t ip6ip6_lock = RW_LOCK_UNLOCKED;
3102 +static rwlock_t ip6ip6_kernel_lock = RW_LOCK_UNLOCKED;
3103 +static rwlock_t ip6ip6_hook_lock = RW_LOCK_UNLOCKED;
3104 +
3105 +/* flag indicating if the module is being removed */
3106 +static int shutdown = 0;
3107 +
3108 +/**
3109 + * ip6ip6_tnl_lookup - fetch tunnel matching the end-point addresses
3110 + *   @remote: the address of the tunnel exit-point 
3111 + *   @local: the address of the tunnel entry-point 
3112 + *
3113 + * Return:  
3114 + *   tunnel matching given end-points if found,
3115 + *   else fallback tunnel if its device is up, 
3116 + *   else %NULL
3117 + **/
3118 +
3119 +struct ip6_tnl *
3120 +ip6ip6_tnl_lookup(struct in6_addr *remote, struct in6_addr *local)
3121 +{
3122 +       unsigned h0 = HASH(remote);
3123 +       unsigned h1 = HASH(local);
3124 +       struct ip6_tnl *t;
3125 +
3126 +       for (t = tnls_r_l[h0 ^ h1]; t; t = t->next) {
3127 +               if (!ipv6_addr_cmp(local, &t->parms.laddr) &&
3128 +                   !ipv6_addr_cmp(remote, &t->parms.raddr) &&
3129 +                   (t->dev->flags & IFF_UP))
3130 +                       return t;
3131 +       }
3132 +       if ((t = tnls_wc[0]) != NULL && (t->dev->flags & IFF_UP))
3133 +               return t;
3134 +
3135 +       return NULL;
3136 +}
3137 +
3138 +/**
3139 + * ip6ip6_bucket - get head of list matching given tunnel parameters
3140 + *   @p: parameters containing tunnel end-points 
3141 + *
3142 + * Description:
3143 + *   ip6ip6_bucket() returns the head of the list matching the 
3144 + *   &struct in6_addr entries laddr and raddr in @p.
3145 + *
3146 + * Return: head of IPv6 tunnel list 
3147 + **/
3148 +
3149 +static struct ip6_tnl **
3150 +ip6ip6_bucket(struct ip6_tnl_parm *p)
3151 +{
3152 +       struct in6_addr *remote = &p->raddr;
3153 +       struct in6_addr *local = &p->laddr;
3154 +       unsigned h = 0;
3155 +       int prio = 0;
3156 +
3157 +       if (!ipv6_addr_any(remote) || !ipv6_addr_any(local)) {
3158 +               prio = 1;
3159 +               h = HASH(remote) ^ HASH(local);
3160 +       }
3161 +       return &tnls[prio][h];
3162 +}
3163 +
3164 +/**
3165 + * ip6ip6_kernel_tnl_link - add new kernel tunnel to cache
3166 + *   @t: kernel tunnel
3167 + *
3168 + * Note:
3169 + *   %IP6_TNL_F_KERNEL_DEV is assumed to be raised in t->parms.flags. 
3170 + *   See the comments on ip6ip6_kernel_tnl_add() for more information.
3171 + **/
3172 +
3173 +static inline void
3174 +ip6ip6_kernel_tnl_link(struct ip6_tnl *t)
3175 +{
3176 +       write_lock_bh(&ip6ip6_kernel_lock);
3177 +       t->next = tnls_kernel[0];
3178 +       tnls_kernel[0] = t;
3179 +       kdev_count++;
3180 +       write_unlock_bh(&ip6ip6_kernel_lock);
3181 +}
3182 +
3183 +/**
3184 + * ip6ip6_kernel_tnl_unlink - remove first kernel tunnel from cache
3185 + *
3186 + * Return: first free kernel tunnel
3187 + *
3188 + * Note:
3189 + *   See the comments on ip6ip6_kernel_tnl_add() for more information.
3190 + **/
3191 +
3192 +static inline struct ip6_tnl *
3193 +ip6ip6_kernel_tnl_unlink(void)
3194 +{
3195 +       struct ip6_tnl *t;
3196 +
3197 +       write_lock_bh(&ip6ip6_kernel_lock);
3198 +       if ((t = tnls_kernel[0]) != NULL) {
3199 +               tnls_kernel[0] = t->next;
3200 +               kdev_count--;
3201 +       }
3202 +       write_unlock_bh(&ip6ip6_kernel_lock);
3203 +       return t;
3204 +}
3205 +
3206 +/**
3207 + * ip6ip6_tnl_link - add tunnel to hash table
3208 + *   @t: tunnel to be added
3209 + **/
3210 +
3211 +static void
3212 +ip6ip6_tnl_link(struct ip6_tnl *t)
3213 +{
3214 +       struct ip6_tnl **tp = ip6ip6_bucket(&t->parms);
3215 +
3216 +       write_lock_bh(&ip6ip6_lock);
3217 +       t->next = *tp;
3218 +       *tp = t;
3219 +       write_unlock_bh(&ip6ip6_lock);
3220 +}
3221 +
3222 +/**
3223 + * ip6ip6_tnl_unlink - remove tunnel from hash table
3224 + *   @t: tunnel to be removed
3225 + **/
3226 +
3227 +static void
3228 +ip6ip6_tnl_unlink(struct ip6_tnl *t)
3229 +{
3230 +       struct ip6_tnl **tp;
3231 +       
3232 +       write_lock_bh(&ip6ip6_lock);
3233 +       for (tp = ip6ip6_bucket(&t->parms); *tp; tp = &(*tp)->next) {
3234 +               if (t == *tp) {
3235 +                       *tp = t->next;
3236 +                       break;
3237 +               }
3238 +       }
3239 +       write_unlock_bh(&ip6ip6_lock);
3240 +}
3241 +
3242 +/**
3243 + * ip6ip6_tnl_create() - create a new tunnel
3244 + *   @p: tunnel parameters
3245 + *   @pt: pointer to new tunnel
3246 + *
3247 + * Description:
3248 + *   Create tunnel matching given parameters. New kernel managed devices are 
3249 + *   not put in the normal hash structure, but are instead cached for later
3250 + *   use.
3251 + * 
3252 + * Return: 
3253 + *   0 on success
3254 + **/
3255 +
3256 +
3257 +static int __ip6ip6_tnl_create(struct ip6_tnl_parm *p,
3258 +                              struct ip6_tnl **pt,
3259 +                              int kernel_list)
3260 +{
3261 +       struct net_device *dev;
3262 +       int err = -ENOBUFS;
3263 +       struct ip6_tnl *t;
3264 +
3265 +       MOD_INC_USE_COUNT;
3266 +       dev = kmalloc(sizeof (*dev) + sizeof (*t), GFP_KERNEL);
3267 +       if (!dev) {
3268 +               MOD_DEC_USE_COUNT;
3269 +               return err;
3270 +       }
3271 +       memset(dev, 0, sizeof (*dev) + sizeof (*t));
3272 +       dev->priv = (void *) (dev + 1);
3273 +       t = (struct ip6_tnl *) dev->priv;
3274 +       t->dev = dev;
3275 +       dev->init = ip6ip6_tnl_dev_init;
3276 +       dev->features |= NETIF_F_DYNALLOC;
3277 +       if (kernel_list) {
3278 +               memcpy(t->parms.name, p->name, IFNAMSIZ - 1);
3279 +               t->parms.proto = IPPROTO_IPV6;
3280 +               t->parms.flags = IP6_TNL_F_KERNEL_DEV;
3281 +       } else {
3282 +               memcpy(&t->parms, p, sizeof (*p));
3283 +       }
3284 +       t->parms.name[IFNAMSIZ - 1] = '\0';
3285 +       strcpy(dev->name, t->parms.name);
3286 +       if (!dev->name[0]) {
3287 +               int i;
3288 +               for (i = 0; i < IP6_TNL_MAX; i++) {
3289 +                       sprintf(dev->name, "ip6tnl%d", i);
3290 +                       if (__dev_get_by_name(dev->name) == NULL)
3291 +                               break;
3292 +               }
3293 +
3294 +               if (i == IP6_TNL_MAX) {
3295 +                       goto failed;
3296 +               }
3297 +               memcpy(t->parms.name, dev->name, IFNAMSIZ);
3298 +       }
3299 +       if ((err = register_netdevice(dev)) < 0) {
3300 +               goto failed;
3301 +       }
3302 +       dev_hold(dev);
3303 +       if (kernel_list) {
3304 +               ip6ip6_kernel_tnl_link(t);
3305 +       } else {
3306 +               ip6ip6_tnl_link(t);
3307 +       }
3308 +       *pt = t;
3309 +       return 0;
3310 +failed:
3311 +       kfree(dev);
3312 +       MOD_DEC_USE_COUNT;
3313 +       return err;
3314 +}
3315 +
3316 +
3317 +int ip6ip6_tnl_create(struct ip6_tnl_parm *p, struct ip6_tnl **pt)
3318 +{
3319 +       return __ip6ip6_tnl_create(p, pt, 0);
3320 +}
3321 +
3322 +
3323 +static void manage_kernel_tnls(void *foo);
3324 +
3325 +static struct tq_struct manager_task = {
3326 +       routine:manage_kernel_tnls,
3327 +       data:NULL
3328 +};
3329 +
3330 +/**
3331 + * manage_kernel_tnls() - create and destroy kernel tunnels
3332 + *
3333 + * Description:
3334 + *   manage_kernel_tnls() creates new kernel devices if there
3335 + *   are less than $min_kdev_count of them and deletes old ones if
3336 + *   there are less than $max_kdev_count of them in the cache
3337 + *
3338 + * Note:
3339 + *   Schedules itself to be run later in process context if called from 
3340 + *   interrupt. Therefore only works synchronously when called from process 
3341 + *   context.
3342 + **/
3343 +
3344 +static void
3345 +manage_kernel_tnls(void *foo)
3346 +{
3347 +       struct ip6_tnl *t = NULL;
3348 +       struct ip6_tnl_parm parm;
3349 +
3350 +       /* We can't do this processing in interrupt 
3351 +          context so schedule it for later */
3352 +       if (in_interrupt()) {
3353 +               read_lock(&ip6ip6_kernel_lock);
3354 +               if (!shutdown &&
3355 +                   (kdev_count < min_kdev_count ||
3356 +                    kdev_count > max_kdev_count)) {
3357 +                       schedule_task(&manager_task);
3358 +               }
3359 +               read_unlock(&ip6ip6_kernel_lock);
3360 +               return;
3361 +       }
3362 +
3363 +       rtnl_lock();
3364 +       read_lock_bh(&ip6ip6_kernel_lock);
3365 +       memset(&parm, 0, sizeof (parm));
3366 +       parm.flags = IP6_TNL_F_KERNEL_DEV;
3367 +       /* Create tunnels until there are at least min_kdev_count */
3368 +       while (kdev_count < min_kdev_count) {
3369 +               read_unlock_bh(&ip6ip6_kernel_lock);
3370 +               if (!__ip6ip6_tnl_create(&parm, &t, 1)) {
3371 +                       dev_open(t->dev);
3372 +               } else {
3373 +                       goto err;
3374 +               }
3375 +               read_lock_bh(&ip6ip6_kernel_lock);
3376 +       }
3377 +
3378 +       /* Destroy tunnels until there are at most max_kdev_count */
3379 +       while (kdev_count > max_kdev_count) {
3380 +               read_unlock_bh(&ip6ip6_kernel_lock);
3381 +               if ((t = ip6ip6_kernel_tnl_unlink()) != NULL) {
3382 +                       unregister_netdevice(t->dev);
3383 +               } else {
3384 +                       goto err;
3385 +               }
3386 +               read_lock_bh(&ip6ip6_kernel_lock);
3387 +       }
3388 +       read_unlock_bh(&ip6ip6_kernel_lock);
3389 +err:
3390 +       rtnl_unlock();
3391 +}
3392 +
3393 +/**
3394 + * ip6ip6_tnl_inc_max_kdev_count() - increase max kernel dev cache size
3395 + *   @n: size increase
3396 + * Description:
3397 + *   Increase the upper limit for the number of kernel devices allowed in the 
3398 + *   cache at any on time.
3399 + **/
3400 +
3401 +unsigned int
3402 +ip6ip6_tnl_inc_max_kdev_count(unsigned int n)
3403 +{
3404 +       write_lock_bh(&ip6ip6_kernel_lock);
3405 +       max_kdev_count += n;
3406 +       write_unlock_bh(&ip6ip6_kernel_lock);
3407 +       manage_kernel_tnls(NULL);
3408 +       return max_kdev_count;
3409 +}
3410 +
3411 +/**
3412 + * ip6ip6_tnl_dec_max_kdev_count() -  decrease max kernel dev cache size
3413 + *   @n: size decrement
3414 + * Description:
3415 + *   Decrease the upper limit for the number of kernel devices allowed in the 
3416 + *   cache at any on time.
3417 + **/
3418 +
3419 +unsigned int
3420 +ip6ip6_tnl_dec_max_kdev_count(unsigned int n)
3421 +{
3422 +       write_lock_bh(&ip6ip6_kernel_lock);
3423 +       max_kdev_count -= min(max_kdev_count, n);
3424 +       if (max_kdev_count < min_kdev_count)
3425 +               min_kdev_count = max_kdev_count;
3426 +       write_unlock_bh(&ip6ip6_kernel_lock);
3427 +       manage_kernel_tnls(NULL);
3428 +       return max_kdev_count;
3429 +}
3430 +
3431 +/**
3432 + * ip6ip6_tnl_inc_min_kdev_count() - increase min kernel dev cache size
3433 + *   @n: size increase
3434 + * Description:
3435 + *   Increase the lower limit for the number of kernel devices allowed in the 
3436 + *   cache at any on time.
3437 + **/
3438 +
3439 +unsigned int
3440 +ip6ip6_tnl_inc_min_kdev_count(unsigned int n)
3441 +{
3442 +       write_lock_bh(&ip6ip6_kernel_lock);
3443 +       min_kdev_count += n;
3444 +       if (min_kdev_count > max_kdev_count)
3445 +               max_kdev_count = min_kdev_count;
3446 +       write_unlock_bh(&ip6ip6_kernel_lock);
3447 +       manage_kernel_tnls(NULL);
3448 +       return min_kdev_count;
3449 +}
3450 +
3451 +/**
3452 + * ip6ip6_tnl_dec_min_kdev_count() -  decrease min kernel dev cache size
3453 + *   @n: size decrement
3454 + * Description:
3455 + *   Decrease the lower limit for the number of kernel devices allowed in the 
3456 + *   cache at any on time.
3457 + **/
3458 +
3459 +unsigned int
3460 +ip6ip6_tnl_dec_min_kdev_count(unsigned int n)
3461 +{
3462 +       write_lock_bh(&ip6ip6_kernel_lock);
3463 +       min_kdev_count -= min(min_kdev_count, n);
3464 +       write_unlock_bh(&ip6ip6_kernel_lock);
3465 +       manage_kernel_tnls(NULL);
3466 +       return min_kdev_count;
3467 +}
3468 +
3469 +/**
3470 + * ip6ip6_tnl_locate - find or create tunnel matching given parameters
3471 + *   @p: tunnel parameters 
3472 + *   @create: != 0 if allowed to create new tunnel if no match found
3473 + *
3474 + * Description:
3475 + *   ip6ip6_tnl_locate() first tries to locate an existing tunnel
3476 + *   based on @parms. If this is unsuccessful, but @create is set a new
3477 + *   tunnel device is created and registered for use.
3478 + *
3479 + * Return:
3480 + *   0 if tunnel located or created,
3481 + *   -EINVAL if parameters incorrect,
3482 + *   -ENODEV if no matching tunnel available
3483 + **/
3484 +
3485 +int ip6ip6_tnl_locate(struct ip6_tnl_parm *p, struct ip6_tnl **pt, int create)
3486 +{
3487 +       struct in6_addr *remote = &p->raddr;
3488 +       struct in6_addr *local = &p->laddr;
3489 +       struct ip6_tnl *t;
3490 +
3491 +       if (p->proto != IPPROTO_IPV6)
3492 +               return -EINVAL;
3493 +
3494 +       for (t = *ip6ip6_bucket(p); t; t = t->next) {
3495 +               if (!ipv6_addr_cmp(local, &t->parms.laddr) &&
3496 +                   !ipv6_addr_cmp(remote, &t->parms.raddr)) {
3497 +                       *pt = t;
3498 +                       return (create ? -EEXIST : 0);
3499 +               }
3500 +       }
3501 +       return ip6ip6_tnl_create(p, pt);
3502 +}
3503 +
3504 +/**
3505 + * ip6ip6_tnl_dev_destructor - tunnel device destructor
3506 + *   @dev: the device to be destroyed
3507 + **/
3508 +
3509 +static void
3510 +ip6ip6_tnl_dev_destructor(struct net_device *dev)
3511 +{
3512 +       if (dev != &ip6ip6_fb_tnl_dev) {
3513 +               MOD_DEC_USE_COUNT;
3514 +       }
3515 +}
3516 +
3517 +/**
3518 + * ip6ip6_tnl_dev_uninit - tunnel device uninitializer
3519 + *   @dev: the device to be destroyed
3520 + *   
3521 + * Description:
3522 + *   ip6ip6_tnl_dev_uninit() removes tunnel from its list
3523 + **/
3524 +
3525 +static void
3526 +ip6ip6_tnl_dev_uninit(struct net_device *dev)
3527 +{
3528 +       struct ip6_tnl *t = (struct ip6_tnl *) dev->priv;
3529 +
3530 +       if (dev == &ip6ip6_fb_tnl_dev) {
3531 +               write_lock_bh(&ip6ip6_lock);
3532 +               tnls_wc[0] = NULL;
3533 +               write_unlock_bh(&ip6ip6_lock);
3534 +       } else {
3535 +               ip6ip6_tnl_unlink(t);
3536 +       }
3537 +       sock_release(t->sock);
3538 +       dev_put(dev);
3539 +}
3540 +
3541 +/**
3542 + * parse_tvl_tnl_enc_lim - handle encapsulation limit option
3543 + *   @skb: received socket buffer
3544 + *
3545 + * Return: 
3546 + *   0 if none was found, 
3547 + *   else index to encapsulation limit
3548 + **/
3549 +
3550 +static __u16
3551 +parse_tlv_tnl_enc_lim(struct sk_buff *skb, __u8 * raw)
3552 +{
3553 +       struct ipv6hdr *ipv6h = (struct ipv6hdr *) raw;
3554 +       __u8 nexthdr = ipv6h->nexthdr;
3555 +       __u16 off = sizeof (*ipv6h);
3556 +
3557 +       while (ipv6_ext_hdr(nexthdr) && nexthdr != NEXTHDR_NONE) {
3558 +               __u16 optlen = 0;
3559 +               struct ipv6_opt_hdr *hdr;
3560 +               if (raw + off + sizeof (*hdr) > skb->data &&
3561 +                   !pskb_may_pull(skb, raw - skb->data + off + sizeof (*hdr)))
3562 +                       break;
3563 +
3564 +               hdr = (struct ipv6_opt_hdr *) (raw + off);
3565 +               if (nexthdr == NEXTHDR_FRAGMENT) {
3566 +                       struct frag_hdr *frag_hdr = (struct frag_hdr *) hdr;
3567 +                       if (frag_hdr->frag_off)
3568 +                               break;
3569 +                       optlen = 8;
3570 +               } else if (nexthdr == NEXTHDR_AUTH) {
3571 +                       optlen = (hdr->hdrlen + 2) << 2;
3572 +               } else {
3573 +                       optlen = ipv6_optlen(hdr);
3574 +               }
3575 +               if (nexthdr == NEXTHDR_DEST) {
3576 +                       __u16 i = off + 2;
3577 +                       while (1) {
3578 +                               struct ipv6_tlv_tnl_enc_lim *tel;
3579 +
3580 +                               /* No more room for encapsulation limit */
3581 +                               if (i + sizeof (*tel) > off + optlen)
3582 +                                       break;
3583 +
3584 +                               tel = (struct ipv6_tlv_tnl_enc_lim *) &raw[i];
3585 +                               /* return index of option if found and valid */
3586 +                               if (tel->type == IPV6_TLV_TNL_ENCAP_LIMIT &&
3587 +                                   tel->length == 1)
3588 +                                       return i;
3589 +                               /* else jump to next option */
3590 +                               if (tel->type)
3591 +                                       i += tel->length + 2;
3592 +                               else
3593 +                                       i++;
3594 +                       }
3595 +               }
3596 +               nexthdr = hdr->nexthdr;
3597 +               off += optlen;
3598 +       }
3599 +       return 0;
3600 +}
3601 +
3602 +/**
3603 + * ip6ip6_err - tunnel error handler
3604 + *
3605 + * Description:
3606 + *   ip6ip6_err() should handle errors in the tunnel according
3607 + *   to the specifications in RFC 2473.
3608 + **/
3609 +
3610 +void ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
3611 +                  int type, int code, int offset, __u32 info)
3612 +{
3613 +       struct ipv6hdr *ipv6h = (struct ipv6hdr *) skb->data;
3614 +       struct ip6_tnl *t;
3615 +       int rel_msg = 0;
3616 +       int rel_type = ICMPV6_DEST_UNREACH;
3617 +       int rel_code = ICMPV6_ADDR_UNREACH;
3618 +       __u32 rel_info = 0;
3619 +       __u16 len;
3620 +
3621 +       /* If the packet doesn't contain the original IPv6 header we are 
3622 +          in trouble since we might need the source address for furter 
3623 +          processing of the error. */
3624 +
3625 +       read_lock(&ip6ip6_lock);
3626 +       if ((t = ip6ip6_tnl_lookup(&ipv6h->daddr, &ipv6h->saddr)) == NULL)
3627 +               goto out;
3628 +
3629 +       switch (type) {
3630 +               __u32 teli;
3631 +               struct ipv6_tlv_tnl_enc_lim *tel;
3632 +               __u32 mtu;
3633 +       case ICMPV6_DEST_UNREACH:
3634 +               if (net_ratelimit())
3635 +                       printk(KERN_WARNING
3636 +                              "%s: Path to destination invalid "
3637 +                              "or inactive!\n", t->parms.name);
3638 +               rel_msg = 1;
3639 +               break;
3640 +       case ICMPV6_TIME_EXCEED:
3641 +               if (code == ICMPV6_EXC_HOPLIMIT) {
3642 +                       if (net_ratelimit())
3643 +                               printk(KERN_WARNING
3644 +                                      "%s: Too small hop limit or "
3645 +                                      "routing loop in tunnel!\n", 
3646 +                                      t->parms.name);
3647 +                       rel_msg = 1;
3648 +               }
3649 +               break;
3650 +       case ICMPV6_PARAMPROB:
3651 +               /* ignore if parameter problem not caused by a tunnel
3652 +                  encapsulation limit sub-option */
3653 +               if (code != ICMPV6_HDR_FIELD) {
3654 +                       break;
3655 +               }
3656 +               teli = parse_tlv_tnl_enc_lim(skb, skb->data);
3657 +
3658 +               if (teli && teli == ntohl(info) - 2) {
3659 +                       tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->data[teli];
3660 +                       if (tel->encap_limit == 0) {
3661 +                               if (net_ratelimit())
3662 +                                       printk(KERN_WARNING
3663 +                                              "%s: Too small encapsulation "
3664 +                                              "limit or routing loop in "
3665 +                                              "tunnel!\n", t->parms.name);
3666 +                               rel_msg = 1;
3667 +                       }
3668 +               }
3669 +               break;
3670 +       case ICMPV6_PKT_TOOBIG:
3671 +               mtu = ntohl(info) - offset;
3672 +               if (mtu < IPV6_MIN_MTU)
3673 +                       mtu = IPV6_MIN_MTU;
3674 +               t->dev->mtu = mtu;
3675 +
3676 +               if ((len = sizeof (*ipv6h) + ipv6h->payload_len) > mtu) {
3677 +                       rel_type = ICMPV6_PKT_TOOBIG;
3678 +                       rel_code = 0;
3679 +                       rel_info = mtu;
3680 +                       rel_msg = 1;
3681 +               }
3682 +               break;
3683 +       }
3684 +       if (rel_msg && pskb_may_pull(skb, offset + sizeof (*ipv6h))) {
3685 +               struct rt6_info *rt;
3686 +               struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
3687 +               if (!skb2)
3688 +                       goto out;
3689 +
3690 +               dst_release(skb2->dst);
3691 +               skb2->dst = NULL;
3692 +               skb_pull(skb2, offset);
3693 +               skb2->nh.raw = skb2->data;
3694 +
3695 +               /* Try to guess incoming interface */
3696 +               rt = rt6_lookup(&skb2->nh.ipv6h->saddr, NULL, 0, 0);
3697 +
3698 +               if (rt && rt->rt6i_dev)
3699 +                       skb2->dev = rt->rt6i_dev;
3700 +
3701 +               icmpv6_send(skb2, rel_type, rel_code, rel_info, skb2->dev);
3702 +
3703 +               if (rt)
3704 +                       dst_release(&rt->u.dst);
3705 +
3706 +               kfree_skb(skb2);
3707 +       }
3708 +out:
3709 +       read_unlock(&ip6ip6_lock);
3710 +}
3711 +
3712 +/**
3713 + * call_hooks - call ipv6 tunnel hooks
3714 + *   @hooknum: hook number, either %IP6_TNL_PRE_ENCAP, or 
3715 + *   %IP6_TNL_PRE_DECAP
3716 + *   @t: the current tunnel
3717 + *   @skb: the tunneled packet
3718 + *
3719 + * Description:
3720 + *   Pass packet to all the hook functions until %IP6_TNL_DROP
3721 + *
3722 + * Return:
3723 + *   %IP6_TNL_ACCEPT or %IP6_TNL_DROP
3724 + **/
3725 +
3726 +static inline int
3727 +call_hooks(unsigned int hooknum, struct ip6_tnl *t, struct sk_buff *skb)
3728 +{
3729 +       struct ip6_tnl_hook_ops *h;
3730 +       int accept = IP6_TNL_ACCEPT;
3731 +
3732 +       if (hooknum < IP6_TNL_MAXHOOKS) {
3733 +               struct list_head *i;
3734 +               read_lock(&ip6ip6_hook_lock);
3735 +               for (i = hooks[hooknum].next; i != &hooks[hooknum]; i = i->next) {
3736 +                       h = (struct ip6_tnl_hook_ops *) i;
3737 +
3738 +                       if (h->hook) {
3739 +                               accept = h->hook(t, skb);
3740 +
3741 +                               if (accept != IP6_TNL_ACCEPT)
3742 +                                       break;
3743 +                       }
3744 +               }
3745 +               read_unlock(&ip6ip6_hook_lock);
3746 +       }
3747 +       return accept;
3748 +}
3749 +
3750 +/**
3751 + * ip6ip6_rcv - decapsulate IPv6 packet and retransmit it locally
3752 + *   @skb: received socket buffer
3753 + *
3754 + * Return: 0
3755 + **/
3756 +
3757 +int ip6ip6_rcv(struct sk_buff *skb)
3758 +{
3759 +       struct ipv6hdr *ipv6h;
3760 +       struct ip6_tnl *t;
3761 +
3762 +       if (!pskb_may_pull(skb, sizeof (*ipv6h)))
3763 +               goto discard;
3764 +
3765 +       ipv6h = skb->nh.ipv6h;
3766 +
3767 +       read_lock(&ip6ip6_lock);
3768 +
3769 +       if ((t = ip6ip6_tnl_lookup(&ipv6h->saddr, &ipv6h->daddr)) != NULL) {
3770 +               if (!(t->parms.flags & IP6_TNL_F_CAP_RCV) ||
3771 +                   call_hooks(IP6_TNL_PRE_DECAP, t, skb) != IP6_TNL_ACCEPT) {
3772 +                       t->stat.rx_dropped++;
3773 +                       read_unlock(&ip6ip6_lock);
3774 +                       goto discard;
3775 +               }
3776 +               skb->mac.raw = skb->nh.raw;
3777 +               skb->nh.raw = skb->data;
3778 +               skb->protocol = htons(ETH_P_IPV6);
3779 +               skb->pkt_type = PACKET_HOST;
3780 +               memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
3781 +               skb->dev = t->dev;
3782 +               dst_release(skb->dst);
3783 +               skb->dst = NULL;
3784 +               t->stat.rx_packets++;
3785 +               t->stat.rx_bytes += skb->len;
3786 +               netif_rx(skb);
3787 +               read_unlock(&ip6ip6_lock);
3788 +               return 0;
3789 +       }
3790 +       read_unlock(&ip6ip6_lock);
3791 +       icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, skb->dev);
3792 +discard:
3793 +       kfree_skb(skb);
3794 +       return 0;
3795 +}
3796 +
3797 +static inline struct ipv6_txoptions *create_tel(__u8 encap_limit)
3798 +{
3799 +       struct ipv6_tlv_tnl_enc_lim *tel;
3800 +       struct ipv6_txoptions *opt;
3801 +       __u8 *raw;
3802 +
3803 +       int opt_len = sizeof(*opt) + IPV6_TLV_TEL_DST_SIZE;
3804 +
3805 +       if (!(opt = kmalloc(opt_len, GFP_ATOMIC))) {
3806 +               return NULL;
3807 +       }
3808 +       memset(opt, 0, opt_len);
3809 +       opt->tot_len = opt_len;
3810 +       opt->dst0opt = (struct ipv6_opt_hdr *) (opt + 1);
3811 +       opt->opt_nflen = 8;
3812 +
3813 +       tel = (struct ipv6_tlv_tnl_enc_lim *) (opt->dst0opt + 1);
3814 +       tel->type = IPV6_TLV_TNL_ENCAP_LIMIT;
3815 +       tel->length = 1;
3816 +       tel->encap_limit = encap_limit;
3817 +
3818 +       raw = (__u8 *) opt->dst0opt;
3819 +       raw[5] = IPV6_TLV_PADN;
3820 +       raw[6] = 1;
3821 +
3822 +       return opt;
3823 +}
3824 +
3825 +static int
3826 +ip6ip6_getfrag(const void *data, struct in6_addr *addr,
3827 +                 char *buff, unsigned int offset, unsigned int len)
3828 +{
3829 +       memcpy(buff, data + offset, len);
3830 +       return 0;
3831 +}
3832 +
3833 +/**
3834 + * ip6ip6_tnl_addr_conflict - compare packet addresses to tunnel's own
3835 + *   @t: the outgoing tunnel device
3836 + *   @hdr: IPv6 header from the incoming packet 
3837 + *
3838 + * Description:
3839 + *   Avoid trivial tunneling loop by checking that tunnel exit-point 
3840 + *   doesn't match source of incoming packet.
3841 + *
3842 + * Return: 
3843 + *   1 if conflict,
3844 + *   0 else
3845 + **/
3846 +
3847 +static inline int
3848 +ip6ip6_tnl_addr_conflict(struct ip6_tnl *t, struct ipv6hdr *hdr)
3849 +{
3850 +       return !ipv6_addr_cmp(&t->parms.raddr, &hdr->saddr);
3851 +}
3852 +
3853 +/**
3854 + * ip6ip6_tnl_xmit - encapsulate packet and send 
3855 + *   @skb: the outgoing socket buffer
3856 + *   @dev: the outgoing tunnel device 
3857 + *
3858 + * Description:
3859 + *   Build new header and do some sanity checks on the packet before sending
3860 + *   it to ip6_build_xmit().
3861 + *
3862 + * Return: 
3863 + *   0
3864 + **/
3865 +
3866 +int ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
3867 +{
3868 +       struct ip6_tnl *t = (struct ip6_tnl *) dev->priv;
3869 +       struct net_device_stats *stats = &t->stat;
3870 +       struct ipv6hdr *ipv6h = skb->nh.ipv6h;
3871 +       struct ipv6_txoptions *opt = NULL;
3872 +       int encap_limit = -1;
3873 +       __u16 offset;
3874 +       struct flowi fl;
3875 +       int err = 0;
3876 +       struct dst_entry *dst;
3877 +       struct sock *sk = t->sock->sk;
3878 +       struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
3879 +       int mtu;
3880 +
3881 +       if (t->recursion++) {
3882 +               stats->collisions++;
3883 +               goto tx_err;
3884 +       }
3885 +       if (skb->protocol != htons(ETH_P_IPV6) ||
3886 +           !(t->parms.flags & IP6_TNL_F_CAP_XMIT) ||
3887 +           ip6ip6_tnl_addr_conflict(t, ipv6h)) {
3888 +               goto tx_err;
3889 +       }
3890 +       if ((offset = parse_tlv_tnl_enc_lim(skb, skb->nh.raw)) > 0) {
3891 +               struct ipv6_tlv_tnl_enc_lim *tel;
3892 +               tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->nh.raw[offset];
3893 +               if (tel->encap_limit == 0) {
3894 +                       icmpv6_send(skb, ICMPV6_PARAMPROB,
3895 +                                   ICMPV6_HDR_FIELD, offset + 2, skb->dev);
3896 +                       goto tx_err;
3897 +               }
3898 +               encap_limit = tel->encap_limit - 1;
3899 +       } else if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) {
3900 +               encap_limit = t->parms.encap_limit;
3901 +       }
3902 +       if (call_hooks(IP6_TNL_PRE_ENCAP, t, skb) != IP6_TNL_ACCEPT)
3903 +               goto discard;
3904 +       memcpy(&fl, &t->fl, sizeof (fl));
3905 +
3906 +       if ((t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS))
3907 +               fl.fl6_flowlabel |= (*(__u32 *) ipv6h & IPV6_TCLASS_MASK);
3908 +       if ((t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL))
3909 +               fl.fl6_flowlabel |= (*(__u32 *) ipv6h & IPV6_FLOWLABEL_MASK);
3910 +
3911 +       if (encap_limit >= 0 && (opt = create_tel(encap_limit)) == NULL)
3912 +               goto tx_err;
3913 +
3914 +       dst = __sk_dst_check(sk, np->dst_cookie);
3915 +
3916 +       if (dst) {
3917 +               if (np->daddr_cache == NULL ||
3918 +                   ipv6_addr_cmp(fl.fl6_dst, np->daddr_cache) ||
3919 +#ifdef CONFIG_IPV6_SUBTREES
3920 +                   np->saddr_cache == NULL ||
3921 +                   ipv6_addr_cmp(fl.fl6_src, np->saddr_cache) ||
3922 +#endif
3923 +                   (fl.oif && fl.oif != dst->dev->ifindex)) {
3924 +                       dst = NULL;
3925 +               } else {
3926 +                       dst_hold(dst);
3927 +               }
3928 +       }
3929 +       if (dst == NULL) {
3930 +               dst = ip6_route_output(sk, &fl);
3931 +               if (dst->error) {
3932 +                       stats->tx_carrier_errors++;
3933 +                       dst_link_failure(skb);
3934 +                       goto tx_err_dst_release;
3935 +               }
3936 +               /* local routing loop */
3937 +               if (dst->dev == dev) {
3938 +                       stats->collisions++;
3939 +                       if (net_ratelimit())
3940 +                               printk(KERN_WARNING 
3941 +                                      "%s: Local routing loop detected!\n",
3942 +                                      t->parms.name);
3943 +                       goto tx_err_dst_release;
3944 +               }
3945 +       }
3946 +       mtu = dst->pmtu - sizeof (*ipv6h);
3947 +       if (opt) {
3948 +               mtu -= (opt->opt_nflen + opt->opt_flen);
3949 +       }
3950 +       if (mtu < IPV6_MIN_MTU)
3951 +               mtu = IPV6_MIN_MTU;
3952 +       if (skb->dst && mtu < skb->dst->pmtu) {
3953 +               struct rt6_info *rt = (struct rt6_info *) skb->dst;
3954 +               rt->rt6i_flags |= RTF_MODIFIED;
3955 +               rt->u.dst.pmtu = mtu;
3956 +       }
3957 +       if (skb->len > mtu) {
3958 +               icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev);
3959 +               goto tx_err_dst_release;
3960 +       }
3961 +       ip6_dst_store(sk, dst, &np->daddr, &np->saddr);
3962 +       err = ip6_build_xmit(sk, ip6ip6_getfrag, (void *) skb->nh.raw,
3963 +                            &fl, skb->len, opt, t->parms.hop_limit,
3964 +                            MSG_DONTWAIT);
3965 +
3966 +       if (err == NET_XMIT_SUCCESS || err == NET_XMIT_CN) {
3967 +               stats->tx_bytes += skb->len;
3968 +               stats->tx_packets++;
3969 +       } else {
3970 +               stats->tx_errors++;
3971 +               stats->tx_aborted_errors++;
3972 +       }
3973 +       if (opt)
3974 +               kfree(opt);
3975 +       kfree_skb(skb);
3976 +       t->recursion--;
3977 +       return 0;
3978 +tx_err_dst_release:
3979 +       dst_release(dst);
3980 +       if (opt)
3981 +               kfree(opt);
3982 +tx_err:
3983 +       stats->tx_errors++;
3984 +discard:
3985 +       stats->tx_dropped++;
3986 +       kfree_skb(skb);
3987 +       t->recursion--;
3988 +       return 0;
3989 +}
3990 +
3991 +static void ip6_tnl_set_cap(struct ip6_tnl *t)
3992 +{
3993 +       struct ip6_tnl_parm *p = &t->parms;
3994 +       struct in6_addr *laddr = &p->laddr;
3995 +       struct in6_addr *raddr = &p->raddr;
3996 +       int ltype = ipv6_addr_type(laddr);
3997 +       int rtype = ipv6_addr_type(raddr);
3998 +
3999 +       p->flags &= ~(IP6_TNL_F_CAP_XMIT|IP6_TNL_F_CAP_RCV);
4000 +
4001 +       if (ltype != IPV6_ADDR_ANY && rtype != IPV6_ADDR_ANY &&
4002 +           ((ltype|rtype) &
4003 +            (IPV6_ADDR_UNICAST|
4004 +             IPV6_ADDR_LOOPBACK|IPV6_ADDR_LINKLOCAL|
4005 +             IPV6_ADDR_MAPPED|IPV6_ADDR_RESERVED)) == IPV6_ADDR_UNICAST) {
4006 +               struct net_device *ldev = NULL;
4007 +               int l_ok = 1;
4008 +               int r_ok = 1;
4009 +
4010 +               if (p->link)
4011 +                       ldev = dev_get_by_index(p->link);
4012 +
4013 +               if ((ltype&IPV6_ADDR_UNICAST) && !ipv6_chk_addr(laddr, ldev))
4014 +                       l_ok = 0;
4015 +
4016 +               if ((rtype&IPV6_ADDR_UNICAST) && ipv6_chk_addr(raddr, NULL))
4017 +                       r_ok = 0;
4018 +
4019 +               if (l_ok && r_ok) {
4020 +                       if (ltype&IPV6_ADDR_UNICAST)
4021 +                               p->flags |= IP6_TNL_F_CAP_XMIT;
4022 +                       if (rtype&IPV6_ADDR_UNICAST)
4023 +                               p->flags |= IP6_TNL_F_CAP_RCV;
4024 +               }
4025 +               if (ldev)
4026 +                       dev_put(ldev);
4027 +       }
4028 +}
4029 +
4030 +static void ip6ip6_tnl_link_config(struct ip6_tnl *t)
4031 +{
4032 +       struct net_device *dev = t->dev;
4033 +       struct ip6_tnl_parm *p = &t->parms;
4034 +       struct flowi *fl = &t->fl;
4035 +
4036 +       /* Set up flowi template */
4037 +       fl->fl6_src = &p->laddr;
4038 +       fl->fl6_dst = &p->raddr;
4039 +       fl->oif = p->link;
4040 +       fl->fl6_flowlabel = 0;
4041 +
4042 +       if (!(p->flags&IP6_TNL_F_USE_ORIG_TCLASS))
4043 +               fl->fl6_flowlabel |= IPV6_TCLASS_MASK & htonl(p->flowinfo);
4044 +       if (!(p->flags&IP6_TNL_F_USE_ORIG_FLOWLABEL))
4045 +               fl->fl6_flowlabel |= IPV6_FLOWLABEL_MASK & htonl(p->flowinfo);
4046 +
4047 +       ip6_tnl_set_cap(t);
4048 +
4049 +       if (p->flags&IP6_TNL_F_CAP_XMIT && p->flags&IP6_TNL_F_CAP_RCV)
4050 +               dev->flags |= IFF_POINTOPOINT;
4051 +       else
4052 +               dev->flags &= ~IFF_POINTOPOINT;
4053 +
4054 +       if (p->flags & IP6_TNL_F_CAP_XMIT) {
4055 +               struct rt6_info *rt = rt6_lookup(&p->raddr, &p->laddr,
4056 +                                                p->link, 0);
4057 +               
4058 +               if (rt == NULL)
4059 +                       return;
4060 +               
4061 +               if (rt->rt6i_dev) {
4062 +                       dev->iflink = rt->rt6i_dev->ifindex;
4063 +
4064 +                       dev->hard_header_len = rt->rt6i_dev->hard_header_len +
4065 +                               sizeof (struct ipv6hdr);
4066 +
4067 +                       dev->mtu = rt->rt6i_dev->mtu - sizeof (struct ipv6hdr);
4068 +
4069 +                       if (dev->mtu < IPV6_MIN_MTU)
4070 +                               dev->mtu = IPV6_MIN_MTU;
4071 +               }
4072 +               dst_release(&rt->u.dst);
4073 +       }
4074 +}
4075 +
4076 +/**
4077 + * __ip6ip6_tnl_change - update the tunnel parameters
4078 + *   @t: tunnel to be changed
4079 + *   @p: tunnel configuration parameters
4080 + *
4081 + * Description:
4082 + *   __ip6ip6_tnl_change() updates the tunnel parameters
4083 + **/
4084 +
4085 +static void
4086 +__ip6ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p)
4087 +{
4088 +       ipv6_addr_copy(&t->parms.laddr, &p->laddr);
4089 +       ipv6_addr_copy(&t->parms.raddr, &p->raddr);
4090 +       t->parms.flags = p->flags;
4091 +       t->parms.hop_limit = p->hop_limit;
4092 +       t->parms.encap_limit = p->encap_limit;
4093 +       t->parms.flowinfo = p->flowinfo;
4094 +       ip6ip6_tnl_link_config(t);
4095 +}
4096 +
4097 +void ip6ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p)
4098 +{
4099 +       ip6ip6_tnl_unlink(t);
4100 +       __ip6ip6_tnl_change(t, p);
4101 +       ip6ip6_tnl_link(t);
4102 +}
4103 +
4104 +/**
4105 + * ip6ip6_kernel_tnl_add - configure and add kernel tunnel to hash 
4106 + *   @p: kernel tunnel configuration parameters
4107 + *
4108 + * Description:
4109 + *   ip6ip6_kernel_tnl_add() fetches an unused kernel tunnel configures
4110 + *   it according to @p and places it among the active tunnels.
4111 + * 
4112 + * Return:
4113 + *   number of references to tunnel on success,
4114 + *   %-EEXIST if there is already a device matching description
4115 + *   %-EINVAL if p->flags doesn't have %IP6_TNL_F_KERNEL_DEV raised,
4116 + *   %-ENODEV if there are no unused kernel tunnels available 
4117 + * 
4118 + * Note:
4119 + *   The code for creating, opening, closing and destroying network devices
4120 + *   must be called from process context, while the Mobile IP code, which 
4121 + *   needs the tunnel devices, unfortunately runs in interrupt context. 
4122 + *   
4123 + *   The devices must be created and opened in advance, then placed in a 
4124 + *   list where the kernel can fetch and ready them for use at a later time.
4125 + *
4126 + **/
4127 +
4128 +int
4129 +ip6ip6_kernel_tnl_add(struct ip6_tnl_parm *p)
4130 +{
4131 +       struct ip6_tnl *t;
4132 +
4133 +       if (!(p->flags & IP6_TNL_F_KERNEL_DEV))
4134 +               return -EINVAL;
4135 +       if ((t = ip6ip6_tnl_lookup(&p->raddr, &p->laddr)) != NULL &&
4136 +           t != &ip6ip6_fb_tnl) {
4137 +               /* Handle duplicate tunnels by incrementing 
4138 +                  reference count */
4139 +               atomic_inc(&t->refcnt);
4140 +               goto out;
4141 +       }
4142 +       if ((t = ip6ip6_kernel_tnl_unlink()) == NULL)
4143 +               return -ENODEV;
4144 +       __ip6ip6_tnl_change(t, p);
4145 +
4146 +       atomic_inc(&t->refcnt);
4147 +
4148 +       ip6ip6_tnl_link(t);
4149 +
4150 +       manage_kernel_tnls(NULL);
4151 +out:
4152 +       return atomic_read(&t->refcnt);
4153 +}
4154 +
4155 +/**
4156 + * ip6ip6_kernel_tnl_del - delete no longer needed kernel tunnel 
4157 + *   @t: kernel tunnel to be removed from hash
4158 + *
4159 + * Description:
4160 + *   ip6ip6_kernel_tnl_del() removes and deconfigures the tunnel @t
4161 + *   and places it among the unused kernel devices.
4162 + * 
4163 + * Return:
4164 + *   number of references on success,
4165 + *   %-EINVAL if p->flags doesn't have %IP6_TNL_F_KERNEL_DEV raised,
4166 + * 
4167 + * Note:
4168 + *   See the comments on ip6ip6_kernel_tnl_add() for more information.
4169 + **/
4170 +
4171 +int
4172 +ip6ip6_kernel_tnl_del(struct ip6_tnl *t)
4173 +{
4174 +       if (!t)
4175 +               return -ENODEV;
4176 +
4177 +       if (!(t->parms.flags & IP6_TNL_F_KERNEL_DEV))
4178 +               return -EINVAL;
4179 +
4180 +       if (atomic_dec_and_test(&t->refcnt)) {
4181 +               struct ip6_tnl_parm p;
4182 +               ip6ip6_tnl_unlink(t);
4183 +               memset(&p, 0, sizeof (p));
4184 +               p.flags = IP6_TNL_F_KERNEL_DEV;
4185 +
4186 +               __ip6ip6_tnl_change(t, &p);
4187 +
4188 +               ip6ip6_kernel_tnl_link(t);
4189 +
4190 +               manage_kernel_tnls(NULL);
4191 +       }
4192 +       return atomic_read(&t->refcnt);
4193 +}
4194 +
4195 +/**
4196 + * ip6ip6_tnl_ioctl - configure ipv6 tunnels from userspace 
4197 + *   @dev: virtual device associated with tunnel
4198 + *   @ifr: parameters passed from userspace
4199 + *   @cmd: command to be performed
4200 + *
4201 + * Description:
4202 + *   ip6ip6_tnl_ioctl() is used for managing IPv6 tunnels 
4203 + *   from userspace. 
4204 + *
4205 + *   The possible commands are the following:
4206 + *     %SIOCGETTUNNEL: get tunnel parameters for device
4207 + *     %SIOCADDTUNNEL: add tunnel matching given tunnel parameters
4208 + *     %SIOCCHGTUNNEL: change tunnel parameters to those given
4209 + *     %SIOCDELTUNNEL: delete tunnel
4210 + *
4211 + *   The fallback device "ip6tnl0", created during module 
4212 + *   initialization, can be used for creating other tunnel devices.
4213 + *
4214 + * Return:
4215 + *   0 on success,
4216 + *   %-EFAULT if unable to copy data to or from userspace,
4217 + *   %-EPERM if current process hasn't %CAP_NET_ADMIN set or attempting
4218 + *   to configure kernel devices from userspace, 
4219 + *   %-EINVAL if passed tunnel parameters are invalid,
4220 + *   %-EEXIST if changing a tunnel's parameters would cause a conflict
4221 + *   %-ENODEV if attempting to change or delete a nonexisting device
4222 + *
4223 + * Note:
4224 + *   See the comments on ip6ip6_kernel_tnl_add() for more information 
4225 + *   about kernel tunnels.
4226 + * **/
4227 +
4228 +static int
4229 +ip6ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
4230 +{
4231 +       int err = 0;
4232 +       int create;
4233 +       struct ip6_tnl_parm p;
4234 +       struct ip6_tnl *t = NULL;
4235 +
4236 +       MOD_INC_USE_COUNT;
4237 +
4238 +       switch (cmd) {
4239 +       case SIOCGETTUNNEL:
4240 +               if (dev == &ip6ip6_fb_tnl_dev) {
4241 +                       if (copy_from_user(&p,
4242 +                                          ifr->ifr_ifru.ifru_data,
4243 +                                          sizeof (p))) {
4244 +                               err = -EFAULT;
4245 +                               break;
4246 +                       }
4247 +                       if ((err = ip6ip6_tnl_locate(&p, &t, 0)) == -ENODEV)
4248 +                               t = (struct ip6_tnl *) dev->priv;
4249 +                       else if (err)
4250 +                               break;
4251 +               } else
4252 +                       t = (struct ip6_tnl *) dev->priv;
4253 +
4254 +               memcpy(&p, &t->parms, sizeof (p));
4255 +               if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof (p))) {
4256 +                       err = -EFAULT;
4257 +               }
4258 +               break;
4259 +       case SIOCADDTUNNEL:
4260 +       case SIOCCHGTUNNEL:
4261 +               err = -EPERM;
4262 +               create = (cmd == SIOCADDTUNNEL);
4263 +               if (!capable(CAP_NET_ADMIN))
4264 +                       break;
4265 +               if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p))) {
4266 +                       err = -EFAULT;
4267 +                       break;
4268 +               }
4269 +               if (p.flags & IP6_TNL_F_KERNEL_DEV) {
4270 +                       break;
4271 +               }
4272 +               if (!create && dev != &ip6ip6_fb_tnl_dev) {
4273 +                       t = (struct ip6_tnl *) dev->priv;
4274 +               }
4275 +               if (!t && (err = ip6ip6_tnl_locate(&p, &t, create))) {
4276 +                       break;
4277 +               }
4278 +               if (cmd == SIOCCHGTUNNEL) {
4279 +                       if (t->dev != dev) {
4280 +                               err = -EEXIST;
4281 +                               break;
4282 +                       }
4283 +                       if (t->parms.flags & IP6_TNL_F_KERNEL_DEV) {
4284 +                               err = -EPERM;
4285 +                               break;
4286 +                       }
4287 +                       ip6ip6_tnl_change(t, &p);
4288 +                       netdev_state_change(dev);
4289 +               }
4290 +               if (copy_to_user(ifr->ifr_ifru.ifru_data,
4291 +                                &t->parms, sizeof (p))) {
4292 +                       err = -EFAULT;
4293 +               } else {
4294 +                       err = 0;
4295 +               }
4296 +               break;
4297 +       case SIOCDELTUNNEL:
4298 +               err = -EPERM;
4299 +               if (!capable(CAP_NET_ADMIN))
4300 +                       break;
4301 +
4302 +               if (dev == &ip6ip6_fb_tnl_dev) {
4303 +                       if (copy_from_user(&p, ifr->ifr_ifru.ifru_data,
4304 +                                          sizeof (p))) {
4305 +                               err = -EFAULT;
4306 +                               break;
4307 +                       }
4308 +                       err = ip6ip6_tnl_locate(&p, &t, 0);
4309 +                       if (err)
4310 +                               break;
4311 +                       if (t == &ip6ip6_fb_tnl) {
4312 +                               err = -EPERM;
4313 +                               break;
4314 +                       }
4315 +               } else {
4316 +                       t = (struct ip6_tnl *) dev->priv;
4317 +               }
4318 +               if (t->parms.flags & IP6_TNL_F_KERNEL_DEV)
4319 +                       err = -EPERM;
4320 +               else
4321 +                       err = unregister_netdevice(t->dev);
4322 +               break;
4323 +       default:
4324 +               err = -EINVAL;
4325 +       }
4326 +       MOD_DEC_USE_COUNT;
4327 +       return err;
4328 +}
4329 +
4330 +/**
4331 + * ip6ip6_tnl_get_stats - return the stats for tunnel device 
4332 + *   @dev: virtual device associated with tunnel
4333 + *
4334 + * Return: stats for device
4335 + **/
4336 +
4337 +static struct net_device_stats *
4338 +ip6ip6_tnl_get_stats(struct net_device *dev)
4339 +{
4340 +       return &(((struct ip6_tnl *) dev->priv)->stat);
4341 +}
4342 +
4343 +/**
4344 + * ip6ip6_tnl_change_mtu - change mtu manually for tunnel device
4345 + *   @dev: virtual device associated with tunnel
4346 + *   @new_mtu: the new mtu
4347 + *
4348 + * Return:
4349 + *   0 on success,
4350 + *   %-EINVAL if mtu too small
4351 + **/
4352 +
4353 +static int
4354 +ip6ip6_tnl_change_mtu(struct net_device *dev, int new_mtu)
4355 +{
4356 +       if (new_mtu < IPV6_MIN_MTU) {
4357 +               return -EINVAL;
4358 +       }
4359 +       dev->mtu = new_mtu;
4360 +       return 0;
4361 +}
4362 +
4363 +/**
4364 + * ip6ip6_tnl_dev_init_gen - general initializer for all tunnel devices
4365 + *   @dev: virtual device associated with tunnel
4366 + *
4367 + * Description:
4368 + *   Set function pointers and initialize the &struct flowi template used
4369 + *   by the tunnel.
4370 + **/
4371 +
4372 +static int
4373 +ip6ip6_tnl_dev_init_gen(struct net_device *dev)
4374 +{
4375 +       struct ip6_tnl *t = (struct ip6_tnl *) dev->priv;
4376 +       struct flowi *fl = &t->fl;
4377 +       int err;
4378 +       struct sock *sk;
4379 +
4380 +       if ((err = sock_create(PF_INET6, SOCK_RAW, IPPROTO_IPV6, &t->sock))) {
4381 +               printk(KERN_ERR
4382 +                      "Failed to create IPv6 tunnel socket (err %d).\n", err);
4383 +               return err;
4384 +       }
4385 +       t->sock->inode->i_uid = 0;
4386 +       t->sock->inode->i_gid = 0;
4387 +
4388 +       sk = t->sock->sk;
4389 +       sk->allocation = GFP_ATOMIC;
4390 +       sk->net_pinfo.af_inet6.hop_limit = 254;
4391 +       sk->net_pinfo.af_inet6.mc_loop = 0;
4392 +       sk->prot->unhash(sk);
4393 +
4394 +       memset(fl, 0, sizeof (*fl));
4395 +       fl->proto = IPPROTO_IPV6;
4396 +
4397 +       dev->destructor = ip6ip6_tnl_dev_destructor;
4398 +       dev->uninit = ip6ip6_tnl_dev_uninit;
4399 +       dev->hard_start_xmit = ip6ip6_tnl_xmit;
4400 +       dev->get_stats = ip6ip6_tnl_get_stats;
4401 +       dev->do_ioctl = ip6ip6_tnl_ioctl;
4402 +       dev->change_mtu = ip6ip6_tnl_change_mtu;
4403 +
4404 +       dev->type = ARPHRD_TUNNEL6;
4405 +       dev->hard_header_len = LL_MAX_HEADER + sizeof (struct ipv6hdr);
4406 +       dev->mtu = ETH_DATA_LEN - sizeof (struct ipv6hdr);
4407 +       dev->flags |= IFF_NOARP;
4408 +       dev->iflink = 0;
4409 +       /* Hmm... MAX_ADDR_LEN is 8, so the ipv6 addresses can't be 
4410 +          copied to dev->dev_addr and dev->broadcast, like the ipv4
4411 +          addresses were in ipip.c, ip_gre.c and sit.c. */
4412 +       dev->addr_len = 0;
4413 +       return 0;
4414 +}
4415 +
4416 +/**
4417 + * ip6ip6_tnl_dev_init - initializer for all non fallback tunnel devices
4418 + *   @dev: virtual device associated with tunnel
4419 + **/
4420 +
4421 +static int
4422 +ip6ip6_tnl_dev_init(struct net_device *dev)
4423 +{
4424 +       struct ip6_tnl *t = (struct ip6_tnl *) dev->priv;
4425 +       ip6ip6_tnl_dev_init_gen(dev);
4426 +       ip6ip6_tnl_link_config(t);
4427 +       return 0;
4428 +}
4429 +
4430 +#ifdef MODULE
4431 +
4432 +/**
4433 + * ip6ip6_fb_tnl_open - function called when fallback device opened
4434 + *   @dev: fallback device
4435 + *
4436 + * Return: 0 
4437 + **/
4438 +
4439 +static int
4440 +ip6ip6_fb_tnl_open(struct net_device *dev)
4441 +{
4442 +       MOD_INC_USE_COUNT;
4443 +       return 0;
4444 +}
4445 +
4446 +/**
4447 + * ip6ip6_fb_tnl_close - function called when fallback device closed
4448 + *   @dev: fallback device
4449 + *
4450 + * Return: 0 
4451 + **/
4452 +
4453 +static int
4454 +ip6ip6_fb_tnl_close(struct net_device *dev)
4455 +{
4456 +       MOD_DEC_USE_COUNT;
4457 +       return 0;
4458 +}
4459 +#endif
4460 +
4461 +/**
4462 + * ip6ip6_fb_tnl_dev_init - initializer for fallback tunnel device
4463 + *   @dev: fallback device
4464 + *
4465 + * Return: 0
4466 + **/
4467 +
4468 +int __init
4469 +ip6ip6_fb_tnl_dev_init(struct net_device *dev)
4470 +{
4471 +       ip6ip6_tnl_dev_init_gen(dev);
4472 +#ifdef MODULE
4473 +       dev->open = ip6ip6_fb_tnl_open;
4474 +       dev->stop = ip6ip6_fb_tnl_close;
4475 +#endif
4476 +       dev_hold(dev);
4477 +       tnls_wc[0] = &ip6ip6_fb_tnl;
4478 +       return 0;
4479 +}
4480 +
4481 +/**
4482 + * ip6ip6_tnl_register_hook - add hook for processing of tunneled packets
4483 + *   @reg: hook function and its parameters
4484 + * 
4485 + * Description:
4486 + *   Add a netfilter like hook function for special handling of tunneled 
4487 + *   packets. The hook functions are called before encapsulation 
4488 + *   (%IP6_TNL_PRE_ENCAP) and before decapsulation 
4489 + *   (%IP6_TNL_PRE_DECAP). The possible return values by the hook 
4490 + *   functions are %IP6_TNL_DROP, %IP6_TNL_ACCEPT and 
4491 + *   %IP6_TNL_STOLEN (in case the hook function took care of the packet
4492 + *   and it doesn't have to be processed any further).
4493 + **/
4494 +
4495 +void
4496 +ip6ip6_tnl_register_hook(struct ip6_tnl_hook_ops *reg)
4497 +{
4498 +       if (reg->hooknum < IP6_TNL_MAXHOOKS) {
4499 +               struct list_head *i;
4500 +
4501 +               write_lock_bh(&ip6ip6_hook_lock);
4502 +               for (i = hooks[reg->hooknum].next;
4503 +                    i != &hooks[reg->hooknum]; i = i->next) {
4504 +                       if (reg->priority <
4505 +                           ((struct ip6_tnl_hook_ops *) i)->priority) {
4506 +                               break;
4507 +                       }
4508 +               }
4509 +               list_add(&reg->list, i->prev);
4510 +               write_unlock_bh(&ip6ip6_hook_lock);
4511 +       }
4512 +}
4513 +
4514 +/**
4515 + * ip6ip6_tnl_unregister_hook - remove tunnel hook
4516 + *   @reg: hook function and its parameters
4517 + **/
4518 +
4519 +void
4520 +ip6ip6_tnl_unregister_hook(struct ip6_tnl_hook_ops *reg)
4521 +{
4522 +       if (reg->hooknum < IP6_TNL_MAXHOOKS) {
4523 +               write_lock_bh(&ip6ip6_hook_lock);
4524 +               list_del(&reg->list);
4525 +               write_unlock_bh(&ip6ip6_hook_lock);
4526 +       }
4527 +}
4528 +
4529 +
4530 +/* the IPv6 over IPv6 protocol structure */
4531 +static struct inet6_protocol ip6ip6_protocol = {
4532 +       ip6ip6_rcv,             /* IPv6 handler         */
4533 +       ip6ip6_err,             /* IPv6 error control   */
4534 +       NULL,                   /* next                 */
4535 +       IPPROTO_IPV6,           /* protocol ID          */
4536 +       0,                      /* copy                 */
4537 +       NULL,                   /* data                 */
4538 +       "IPv6 over IPv6"        /* name                 */
4539 +};
4540 +
4541 +/**
4542 + * ip6_tunnel_init - register protocol and reserve needed resources
4543 + *
4544 + * Return: 0 on success
4545 + **/
4546 +
4547 +int __init ip6_tunnel_init(void)
4548 +{
4549 +       int i, err;
4550 +
4551 +       ip6ip6_fb_tnl_dev.priv = (void *) &ip6ip6_fb_tnl;
4552 +
4553 +       for (i = 0; i < IP6_TNL_MAXHOOKS; i++) {
4554 +               INIT_LIST_HEAD(&hooks[i]);
4555 +       }
4556 +       if ((err = register_netdev(&ip6ip6_fb_tnl_dev)))
4557 +               return err;
4558 +
4559 +       inet6_add_protocol(&ip6ip6_protocol);
4560 +       return 0;
4561 +}
4562 +
4563 +/**
4564 + * ip6_tunnel_cleanup - free resources and unregister protocol
4565 + **/
4566 +
4567 +void ip6_tunnel_cleanup(void)
4568 +{
4569 +       write_lock_bh(&ip6ip6_kernel_lock);
4570 +       shutdown = 1;
4571 +       write_unlock_bh(&ip6ip6_kernel_lock);
4572 +       flush_scheduled_tasks();
4573 +       manage_kernel_tnls(NULL);
4574 +       inet6_del_protocol(&ip6ip6_protocol);
4575 +       unregister_netdev(&ip6ip6_fb_tnl_dev);
4576 +}
4577 +
4578 +#ifdef MODULE
4579 +module_init(ip6_tunnel_init);
4580 +module_exit(ip6_tunnel_cleanup);
4581 +#endif
4582 +
4583 +#if defined(CONFIG_IPV6_MOBILITY_HA_MODULE) || defined(CONFIG_IPV6_MOBILITY_MN_MODULE)
4584 +EXPORT_SYMBOL(ip6ip6_tnl_register_hook);
4585 +EXPORT_SYMBOL(ip6ip6_tnl_unregister_hook);
4586 +#endif
4587 +#ifdef CONFIG_IPV6_MOBILITY_HA_MODULE
4588 +EXPORT_SYMBOL(ip6ip6_tnl_dec_max_kdev_count);
4589 +EXPORT_SYMBOL(ip6ip6_tnl_inc_max_kdev_count);
4590 +EXPORT_SYMBOL(ip6ip6_tnl_dec_min_kdev_count);
4591 +EXPORT_SYMBOL(ip6ip6_tnl_inc_min_kdev_count);
4592 +EXPORT_SYMBOL(ip6ip6_kernel_tnl_add);
4593 +EXPORT_SYMBOL(ip6ip6_kernel_tnl_del);
4594 +EXPORT_SYMBOL(ip6ip6_tnl_lookup);
4595 +#endif
4596 +#ifdef CONFIG_IPV6_MOBILITY_MN_MODULE
4597 +EXPORT_SYMBOL(ip6ip6_tnl_create);
4598 +EXPORT_SYMBOL(ip6ip6_tnl_change);
4599 +#endif
4600 +
4601 --- /dev/null
4602 +++ linux-2.4.27/net/ipv6/mipglue.c
4603 @@ -0,0 +1,63 @@
4604 +/*
4605 + *     Glue for Mobility support integration to IPv6
4606 + *
4607 + *     Authors:
4608 + *     Antti Tuominen          <ajtuomin@cc.hut.fi>    
4609 + *
4610 + *     $Id$
4611 + *
4612 + *     This program is free software; you can redistribute it and/or
4613 + *      modify it under the terms of the GNU General Public License
4614 + *      as published by the Free Software Foundation; either version
4615 + *      2 of the License, or (at your option) any later version.
4616 + *
4617 + */
4618 +
4619 +#include <linux/sched.h>
4620 +
4621 +#include <net/ipv6.h>
4622 +#include <net/addrconf.h>
4623 +#include <net/neighbour.h>
4624 +#include <net/mipglue.h>
4625 +
4626 +extern int ip6_tlvopt_unknown(struct sk_buff *skb, int optoff);
4627 +
4628 +/*  Initialize all zero  */
4629 +struct mipv6_callable_functions mipv6_functions = { NULL };
4630 +
4631 +/* Sets mipv6_functions struct to zero to invalidate all successive
4632 + * calls to mipv6 functions. Used on module unload. */
4633 +
4634 +void mipv6_invalidate_calls(void)
4635 +{
4636 +       memset(&mipv6_functions, 0, sizeof(mipv6_functions));
4637 +}
4638 +
4639 +
4640 +/* Selects correct handler for tlv encoded destination option. Called
4641 + * by ip6_parse_tlv. Checks if mipv6 calls are valid before calling. */
4642 +
4643 +int mipv6_handle_dstopt(struct sk_buff *skb, int optoff)
4644 +{
4645 +       int ret;
4646 +
4647 +        switch (skb->nh.raw[optoff]) {
4648 +       case MIPV6_TLV_HOMEADDR: 
4649 +               ret = MIPV6_CALLFUNC(mipv6_handle_homeaddr, 0)(skb, optoff);
4650 +               break;
4651 +       default:
4652 +               /* Should never happen */
4653 +               printk(KERN_ERR __FILE__ ": Invalid destination option code (%d)\n",
4654 +                      skb->nh.raw[optoff]);
4655 +               ret = 1;
4656 +               break;
4657 +       }
4658 +
4659 +       /* If mipv6 handlers are not valid, pass the packet to
4660 +         * ip6_tlvopt_unknown() for correct handling. */
4661 +       if (!ret)
4662 +               return ip6_tlvopt_unknown(skb, optoff);
4663 +
4664 +       return ret;
4665 +}
4666 +
4667 --- /dev/null
4668 +++ linux-2.4.27/net/ipv6/mobile_ip6/Config.in
4669 @@ -0,0 +1,12 @@
4670 +#
4671 +# Mobile IPv6 Configuration
4672 +#
4673 +dep_tristate '    IPv6: Mobility Support (Correspondent Node)' CONFIG_IPV6_MOBILITY $CONFIG_IPV6
4674 +if [ "$CONFIG_IPV6_IPV6_TUNNEL" != "n" ]; then
4675 +   dep_tristate '      MIPv6: Mobile Node Support' CONFIG_IPV6_MOBILITY_MN $CONFIG_IPV6_MOBILITY
4676 +
4677 +   dep_tristate '      MIPv6: Home Agent Support' CONFIG_IPV6_MOBILITY_HA $CONFIG_IPV6_MOBILITY
4678 +fi
4679 +if [ "$CONFIG_IPV6_MOBILITY" != "n" ]; then
4680 +   bool '      MIPv6: Debug messages' CONFIG_IPV6_MOBILITY_DEBUG
4681 +fi
4682 --- /dev/null
4683 +++ linux-2.4.27/net/ipv6/mobile_ip6/Makefile
4684 @@ -0,0 +1,35 @@
4685 +#
4686 +# Makefile for the MIPL Mobile IPv6 for Linux.
4687 +#
4688 +# Note! Dependencies are done automagically by 'make dep', which also
4689 +# removes any old dependencies. DON'T put your own dependencies here
4690 +# unless it's something special (ie not a .c file).
4691 +#
4692 +
4693 +
4694 +O_TARGET := mip6_base.o
4695 +
4696 +list-multi := mip6_ha.o mip6_mn.o
4697 +
4698 +obj-y := hashlist.o bcache.o mobhdr_common.o stats.o exthdrs.o \
4699 +       rr_crypto.o hmac.o auth_opt.o mipv6_icmp.o module_cn.o
4700 +
4701 +obj-m := $(O_TARGET)
4702 +
4703 +mip6_ha-objs := halist.o mipv6_icmp_ha.o tunnel_ha.o \
4704 +               ndisc_ha.o ha.o module_ha.o
4705 +
4706 +mip6_mn-objs := mipv6_icmp_mn.o ioctl_mn.o tunnel_mn.o \
4707 +               mdetect.o bul.o multiaccess_ctl.o mobhdr_mn.o mn.o \
4708 +               module_mn.o 
4709 +
4710 +obj-$(CONFIG_IPV6_MOBILITY_HA) += mip6_ha.o
4711 +obj-$(CONFIG_IPV6_MOBILITY_MN) += mip6_mn.o
4712 +
4713 +include $(TOPDIR)/Rules.make
4714 +
4715 +mip6_ha.o: $(mip6_ha-objs)
4716 +       $(LD) -r -o $@ $(mip6_ha-objs)
4717 +
4718 +mip6_mn.o: $(mip6_mn-objs)
4719 +       $(LD) -r -o $@ $(mip6_mn-objs)
4720 --- /dev/null
4721 +++ linux-2.4.27/net/ipv6/mobile_ip6/README
4722 @@ -0,0 +1,15 @@
4723 +MIPL Mobile IPv6 for Linux
4724 +
4725 +More information at http://www.mipl.mediapoli.com/.
4726 +
4727 +To join MIPL Mobile IPv6 for Linux mailing lists go to:
4728 +
4729 +       http://www.mipl.mediapoli.com/cgi-bin/mailman/listinfo
4730 +
4731 +Or send mail with subject "subscribe" for the general list to:
4732 +
4733 +       mipl-request@list.mipl.mediapoli.com
4734 +
4735 +or for the developer list to:
4736 +
4737 +       mipl-devel-request@list.mail.mediapoli.com
4738 --- /dev/null
4739 +++ linux-2.4.27/net/ipv6/mobile_ip6/auth_opt.c
4740 @@ -0,0 +1,121 @@
4741 +/*
4742 + *     MIPv6 Binding Authentication Data Option functions
4743 + *     
4744 + *      Authors: 
4745 + *      Henrik Petander         <lpetande@tml.hut.fi>
4746 + * 
4747 + *      $Id$
4748 + *
4749 + *      This program is free software; you can redistribute it and/or
4750 + *      modify it under the terms of the GNU General Public License
4751 + *      as published by the Free Software Foundation; either version
4752 + *      2 of the License, or (at your option) any later version.
4753 + */
4754 +
4755 +#include <linux/autoconf.h>
4756 +#include <linux/icmpv6.h>
4757 +#include <net/mipv6.h>
4758 +
4759 +#include "debug.h"
4760 +#include "hmac.h"
4761 +#include "mobhdr.h"
4762 +
4763 +#define DBG_KEY 5
4764 +
4765 +int mipv6_auth_build(struct in6_addr *cn_addr, struct in6_addr *coa, 
4766 +                    __u8 *mh, __u8 *aud_data, __u8 *k_bu)
4767 +{
4768 +       /* First look up the peer from sadb based on his address */ 
4769 +       struct ah_processing ahp;
4770 +
4771 +       /* Don't add any other options or this system is screwed */
4772 +
4773 +       __u8 buf[MAX_HASH_LENGTH];  
4774 +       
4775 +       
4776 +       if (!k_bu) {
4777 +               DEBUG(DBG_ERROR, "k_bu missing, aborting");
4778 +               return -1;
4779 +       }
4780 +       DEBUG(DBG_KEY, "Key for building authenticator:");
4781 +       debug_print_buffer(DBG_KEY, k_bu, HMAC_SHA1_KEY_SIZE);
4782 +
4783 +       if (ah_hmac_sha1_init(&ahp, k_bu,  HMAC_SHA1_KEY_SIZE) < 0) {
4784 +               DEBUG(DBG_ERROR, "Failed to initialize hmac sha1");
4785 +                return -1; 
4786 +        } 
4787 +
4788 +       DEBUG(DBG_KEY, "coa: ");
4789 +       debug_print_buffer(DBG_KEY, coa, 16);
4790 +       DEBUG(DBG_KEY, "cn_addr: ");
4791 +       debug_print_buffer(DBG_KEY, cn_addr, 16);
4792 +       DEBUG(DBG_KEY, "MH contents: ");
4793 +       debug_print_buffer(DBG_KEY, mh, aud_data - mh);
4794 +
4795 +       /* First the common part */
4796 +       ah_hmac_sha1_loop(&ahp, coa, sizeof(struct in6_addr));
4797 +       ah_hmac_sha1_loop(&ahp, cn_addr, sizeof(struct in6_addr));
4798 +       ah_hmac_sha1_loop(&ahp, mh, aud_data - mh);
4799 +       ah_hmac_sha1_result(&ahp, buf);
4800 +
4801 +       memcpy(aud_data, buf,  MIPV6_RR_MAC_LENGTH);
4802 +
4803 +       return 0;
4804 +}
4805 +
4806 +int mipv6_auth_check(struct in6_addr *cn_addr, struct in6_addr *coa,
4807 +                    __u8 *opt, __u8 optlen, 
4808 +                    struct mipv6_mo_bauth_data *aud, __u8 *k_bu)
4809 +{
4810 +       int ret = -1;
4811 +       struct ah_processing ahp;
4812 +       __u8 htarget[MAX_HASH_LENGTH];
4813 +
4814 +       /* Look up peer by home address */ 
4815 +       if (!k_bu) {
4816 +               DEBUG(DBG_ERROR, "k_bu missing, aborting"); 
4817 +               return -1;
4818 +       }
4819 +
4820 +       DEBUG(DBG_KEY, "Key for checking authenticator:");
4821 +       debug_print_buffer(DBG_KEY, k_bu, HMAC_SHA1_KEY_SIZE);
4822 +
4823 +       if (!aud || !coa) {
4824 +               DEBUG(DBG_INFO, "%s is NULL", aud ? "coa" : "aud");
4825 +               goto out;
4826 +       }
4827 +
4828 +       if (aud->length != MIPV6_RR_MAC_LENGTH) {
4829 +               DEBUG(DBG_ERROR,
4830 +                        ": Incorrect authentication option length %d", aud->length); 
4831 +               goto out; 
4832 +       }
4833 +       
4834 +       if (ah_hmac_sha1_init(&ahp, k_bu, HMAC_SHA1_KEY_SIZE) < 0) { 
4835 +                DEBUG(DBG_ERROR,
4836 +                        "internal error in initialization of authentication algorithm");
4837 +               goto out;
4838 +        } 
4839 +       DEBUG(DBG_KEY, "coa: ");
4840 +       debug_print_buffer(DBG_KEY, coa, 16);
4841 +       DEBUG(DBG_KEY, "cn_addr: ");
4842 +       debug_print_buffer(DBG_KEY, cn_addr, 16);
4843 +       DEBUG(DBG_KEY, "MH contents: ");
4844 +       debug_print_buffer(DBG_KEY, opt, (u8*) aud->data - opt);
4845 +
4846 +       ah_hmac_sha1_loop(&ahp, coa, sizeof(struct in6_addr));
4847 +       ah_hmac_sha1_loop(&ahp, cn_addr, sizeof(struct in6_addr));
4848 +
4849 +       /* 
4850 +        * Process MH + options till the start of the authenticator in
4851 +        * Auth. data option
4852 +        */
4853 +       ah_hmac_sha1_loop(&ahp, opt,  (u8 *)aud->data - opt);
4854 +       ah_hmac_sha1_result(&ahp, htarget);
4855 +       if (memcmp(htarget, aud->data, MIPV6_RR_MAC_LENGTH) == 0)
4856 +               ret = 0;
4857 +
4858 +       DEBUG(DBG_ERROR, "returning %d", ret);
4859 +out:   
4860 +       return ret;
4861 +}
4862 --- /dev/null
4863 +++ linux-2.4.27/net/ipv6/mobile_ip6/bcache.c
4864 @@ -0,0 +1,746 @@
4865 +/*
4866 + *      Binding Cache
4867 + *
4868 + *      Authors:
4869 + *      Juha Mynttinen            <jmynttin@cc.hut.fi>
4870 + *
4871 + *      $Id$
4872 + *
4873 + *      This program is free software; you can redistribute it and/or
4874 + *      modify it under the terms of the GNU General Public License
4875 + *      as published by the Free Software Foundation; either version
4876 + *      2 of the License, or (at your option) any later version.
4877 + */
4878 +
4879 +/*
4880 + *     Changes:
4881 + *
4882 + *     Nanno Langstraat        :       Timer code cleaned up, active socket
4883 + *                                     test rewritten
4884 + */
4885 +
4886 +#include <linux/autoconf.h>
4887 +#include <linux/sched.h>
4888 +#include <linux/timer.h>
4889 +#include <linux/in6.h>
4890 +#include <linux/init.h>
4891 +#include <linux/spinlock.h>
4892 +#include <linux/proc_fs.h>
4893 +#include <linux/ipv6_route.h>
4894 +#include <net/ipv6.h>
4895 +#include <net/addrconf.h>
4896 +#include <net/tcp.h>
4897 +#include <net/udp.h>
4898 +#include <net/ip6_route.h>
4899 +#include <net/mipv6.h>
4900 +
4901 +#include "bcache.h"
4902 +#include "hashlist.h"
4903 +#include "debug.h"
4904 +#include "mobhdr.h"
4905 +#include "tunnel.h"
4906 +#include "config.h"
4907 +
4908 +#define TIMERDELAY HZ/10
4909 +
4910 +struct mipv6_bcache {
4911 +       struct hashlist *entries;
4912 +       __u32 size;
4913 +       struct timer_list callback_timer;
4914 +};
4915 +
4916 +struct in6_addr_pair {
4917 +       struct in6_addr *a1;
4918 +       struct in6_addr *a2;
4919 +};
4920 +
4921 +static rwlock_t bcache_lock = RW_LOCK_UNLOCKED;
4922 +
4923 +static struct mipv6_bcache bcache;
4924 +
4925 +static int bcache_proc_info(char *buffer, char **start, off_t offset,
4926 +                           int length);
4927 +
4928 +#define MIPV6_BCACHE_HASHSIZE  32
4929 +
4930 +/* Moment of transmission of a BR, in seconds before bcache entry expiry */
4931 +#define BCACHE_BR_SEND_LEAD  3
4932 +
4933 +#define MIPV6_MAX_BRR 3 /* Send 3 BRRs before deleting BC entry */
4934 +#define MIPV6_BRR_RATE HZ /* Send BRRs once per second */
4935 +
4936 +/* 
4937 + * Internal functions.
4938 + */
4939 +
4940 +struct cache_entry_iterator_args {
4941 +       struct mipv6_bce **entry;
4942 +};
4943 +
4944 +static int find_first_cache_entry_iterator(void *data, void *args,
4945 +                                          unsigned long *lifetime)
4946 +{
4947 +       struct mipv6_bce *entry =
4948 +           (struct mipv6_bce *) data;
4949 +       struct cache_entry_iterator_args *state =
4950 +           (struct cache_entry_iterator_args *) args;
4951 +
4952 +       ASSERT(entry != NULL);
4953 +
4954 +       if (entry->type == CACHE_ENTRY) {
4955 +               *(state->entry) = entry;
4956 +               return ITERATOR_STOP;   /* stop iteration */
4957 +       } else {
4958 +               return ITERATOR_CONT;   /* continue iteration */
4959 +       }
4960 +}
4961 +
4962 +
4963 +/* 
4964 + * Get memory for a new bcache entry.  If bcache is full, a cache
4965 + * entry may be deleted to get space for a home registration, but not
4966 + * vice versa.
4967 + */
4968 +static struct mipv6_bce *mipv6_bce_alloc(__u8 type)
4969 +{
4970 +       struct mipv6_bce *entry;
4971 +       struct cache_entry_iterator_args args;
4972 +
4973 +       DEBUG_FUNC();
4974 +
4975 +       entry = (struct mipv6_bce *)
4976 +               hashlist_alloc(bcache.entries, SLAB_ATOMIC);
4977 +
4978 +       /* Cache replacement policy: always replace the CACHE_ENTRY
4979 +           closest to expiration.  Type HOME_REGISTRATION entry may
4980 +           never be deleted before expiration. */
4981 +       if (entry == NULL) {
4982 +               /* cache full, try to delete a CACHE_ENTRY */
4983 +               args.entry = &entry;
4984 +               hashlist_iterate(bcache.entries, &args,
4985 +                                find_first_cache_entry_iterator);
4986 +               if (entry == NULL)
4987 +                       return NULL;
4988 +               hashlist_delete(bcache.entries,
4989 +                               (struct hashlist_entry *)entry);
4990 +               entry = (struct mipv6_bce *)
4991 +                       hashlist_alloc(bcache.entries, SLAB_ATOMIC);
4992 +       }
4993 +       return entry;
4994 +}
4995 +
4996 +/*
4997 + * Frees entry's memory allocated with mipv6_bce_alloc
4998 + */
4999 +static void mipv6_bce_free(struct mipv6_bce *entry)
5000 +{
5001 +       hashlist_free(bcache.entries, (void *) entry);
5002 +}
5003 +
5004 +/*
5005 + * Removes all expired entries 
5006 + */
5007 +static void expire(void)
5008 +{
5009 +       struct mipv6_bce *entry;
5010 +       struct br_addrs {
5011 +               struct in6_addr daddr;
5012 +               struct in6_addr saddr;
5013 +               struct br_addrs *next;
5014 +       };
5015 +       struct br_addrs *br_info = NULL;
5016 +
5017 +       DEBUG_FUNC();
5018 +
5019 +       write_lock(&bcache_lock);
5020 +
5021 +       while ((entry = (struct mipv6_bce *)
5022 +               hashlist_get_first(bcache.entries)) != NULL) {
5023 +               struct rt6_info *rt;
5024 +               if (time_after_eq(jiffies, entry->callback_time)) {
5025 +
5026 +                       DEBUG(DBG_INFO, "an entry expired");
5027 +
5028 +                       if (entry->type & HOME_REGISTRATION) {
5029 +                               mip6_fn.proxy_del(&entry->home_addr, entry);
5030 +                       }
5031 +                       hashlist_delete(bcache.entries, (void *)entry);
5032 +                       mipv6_bce_free(entry);
5033 +                       entry = NULL;
5034 +               } else if (entry->br_callback_time != 0 &&
5035 +                          time_after_eq(jiffies, entry->br_callback_time) &&
5036 +                          entry->br_count < MIPV6_MAX_BRR &&
5037 +                          (rt = rt6_lookup(&entry->home_addr, &entry->our_addr, 0, 0)) != NULL){
5038 +                       /* Do we have a destination cache entry for the home address */
5039 +                       if (rt->rt6i_flags & RTF_CACHE) {
5040 +                               struct br_addrs *tmp;
5041 +                               tmp = br_info;
5042 +                               DEBUG(DBG_INFO,
5043 +                                     "bcache entry recently used. Sending BR.");
5044 +                               /* queue for sending */
5045 +                               br_info = kmalloc(sizeof(struct br_addrs),
5046 +                                                 GFP_ATOMIC);
5047 +                               if (br_info) {
5048 +                                       ipv6_addr_copy(&br_info->saddr,
5049 +                                                      &entry->our_addr);
5050 +                                       ipv6_addr_copy(&br_info->daddr,
5051 +                                                      &entry->home_addr);
5052 +                                       br_info->next = tmp;
5053 +                                       entry->last_br = jiffies;
5054 +                                       entry->br_callback_time = jiffies + MIPV6_BRR_RATE;
5055 +                                       entry->br_count++;
5056 +                               } else {
5057 +                                       br_info = tmp;
5058 +                                       DEBUG(DBG_ERROR, "Out of memory");
5059 +                               }
5060 +                               
5061 +                       } else
5062 +                               entry->br_callback_time = 0;    
5063 +                       dst_release(&rt->u.dst);
5064 +               } else {
5065 +                       entry->br_callback_time = 0;
5066 +                       break;
5067 +               }
5068 +       }
5069 +       write_unlock(&bcache_lock);
5070 +
5071 +       while (br_info) {
5072 +               struct br_addrs *tmp = br_info->next;
5073 +               if (mipv6_send_brr(&br_info->saddr, &br_info->daddr, NULL) < 0)
5074 +                       DEBUG(DBG_WARNING,
5075 +                             "BR send for %x:%x:%x:%x:%x:%x:%x:%x failed",
5076 +                             NIPV6ADDR(&br_info->daddr));
5077 +               kfree(br_info);
5078 +               br_info = tmp;
5079 +       }
5080 +}
5081 +
5082 +static void set_timer(void)
5083 +{
5084 +       struct mipv6_bce *entry;
5085 +       unsigned long callback_time;
5086 +
5087 +       DEBUG_FUNC();
5088 +
5089 +       entry = (struct mipv6_bce *)
5090 +               hashlist_get_first(bcache.entries);
5091 +       if (entry != NULL) {
5092 +               if (entry->br_callback_time > 0 && 
5093 +                   time_after(entry->br_callback_time, jiffies))
5094 +                       callback_time = entry->br_callback_time;
5095 +               else if (time_after(entry->callback_time, jiffies))
5096 +                       callback_time = entry->callback_time;
5097 +               else {
5098 +                       DEBUG(DBG_WARNING, 
5099 +                             "bcache timer attempted to schedule"
5100 +                             " for a historical jiffies count!");
5101 +                       callback_time = jiffies + TIMERDELAY;
5102 +               }
5103 +               
5104 +               DEBUG(DBG_INFO, "setting timer to now");
5105 +               mod_timer(&bcache.callback_timer, callback_time);
5106 +       } else {
5107 +               del_timer(&bcache.callback_timer);
5108 +               DEBUG(DBG_INFO, "BC empty, not setting a new timer");
5109 +       }
5110 +}
5111 +
5112 +/* 
5113 + * The function that is scheduled to do the callback functions. May be
5114 + * modified e.g to allow Binding Requests, now only calls expire() and
5115 + * schedules a new timer.
5116 + */
5117 +static void timer_handler(unsigned long dummy)
5118 +{
5119 +       expire();
5120 +       write_lock(&bcache_lock);
5121 +       set_timer();
5122 +       write_unlock(&bcache_lock);
5123 +}
5124 +
5125 +/*
5126 + * Interface functions visible to other modules
5127 + */
5128 +
5129 +/**
5130 + * mipv6_bcache_add - add Binding Cache entry
5131 + * @ifindex: interface index
5132 + * @our_addr: own address
5133 + * @home_addr_org: MN's home address
5134 + * @coa: MN's care-of address
5135 + * @lifetime: lifetime for this binding
5136 + * @prefix: prefix length
5137 + * @seq: sequence number
5138 + * @flags: flags received in BU
5139 + * @type: type of entry
5140 + *
5141 + * Adds an entry for this @home_addr_org in the Binding Cache.  If entry
5142 + * already exists, old entry is updated.  @type may be %CACHE_ENTRY or
5143 + * %HOME_REGISTRATION.
5144 + **/
5145 +int mipv6_bcache_add(int ifindex,
5146 +                    struct in6_addr *our_addr,
5147 +                    struct in6_addr *home_addr,
5148 +                    struct in6_addr *coa,
5149 +                    __u32 lifetime, __u16 seq, __u8 flags, __u8 type)
5150 +{
5151 +       struct mipv6_bce *entry;
5152 +       int update = 0;
5153 +       int create_tunnel = 0;
5154 +       unsigned long now = jiffies;
5155 +       struct in6_addr_pair hashkey;
5156 +       int ret = -1;
5157 +
5158 +       DEBUG_FUNC();
5159 +
5160 +       hashkey.a1 = home_addr;
5161 +       hashkey.a2 = our_addr;
5162 +
5163 +       write_lock(&bcache_lock);
5164 +
5165 +       if (type == HOME_REGISTRATION && !(mip6node_cnf.capabilities&CAP_HA))
5166 +               return 0;
5167 +
5168 +       if (unlikely(bcache.entries == NULL)) {
5169 +               ret = -ENOMEM;
5170 +               goto err;
5171 +       }
5172 +
5173 +       if ((entry = (struct mipv6_bce *)
5174 +            hashlist_get(bcache.entries, &hashkey)) != NULL) {
5175 +               /* if an entry for this home_addr exists (with smaller
5176 +                * seq than the new seq), update it by removing it
5177 +                * first
5178 +                */
5179 +               if (!MIPV6_SEQ_GT(seq, entry->seq)) {
5180 +                       DEBUG(DBG_INFO, "smaller seq than existing, not updating");
5181 +                       goto out;
5182 +               }
5183 +               DEBUG(DBG_INFO, "updating an existing entry");
5184 +               update = 1;
5185 +
5186 +               /* H-flag is already checked in BU handler. */
5187 +               /* XXX: Should we care about the other flags?*/
5188 +               if (flags != entry->flags) {
5189 +                       DEBUG(DBG_INFO, "entry/BU flag mismatch");
5190 +               }
5191 +
5192 +               if (type == HOME_REGISTRATION) {
5193 +                       create_tunnel = (ipv6_addr_cmp(&entry->coa, coa) ||
5194 +                                        entry->ifindex != ifindex);
5195 +               }
5196 +       } else {
5197 +               /* no entry for this home_addr, try to create a new entry */
5198 +               DEBUG(DBG_INFO, "creating a new entry");
5199 +               update = 0;
5200 +
5201 +               entry = mipv6_bce_alloc(type);
5202 +               if (entry == NULL) {
5203 +                       DEBUG(DBG_INFO, "cache full, entry not added");
5204 +                       goto err;
5205 +               }
5206 +
5207 +               create_tunnel = (type == HOME_REGISTRATION);
5208 +       }
5209 +
5210 +       if (create_tunnel) {
5211 +               if (update)
5212 +                       mip6_fn.proxy_del(&entry->home_addr, entry);
5213 +               if (mip6_fn.proxy_create(flags, ifindex, coa, our_addr, home_addr) < 0) {
5214 +                       goto err_proxy;
5215 +               }
5216 +       }
5217 +
5218 +       ipv6_addr_copy(&(entry->our_addr), our_addr);
5219 +       ipv6_addr_copy(&(entry->home_addr), home_addr);
5220 +       ipv6_addr_copy(&(entry->coa), coa);
5221 +       entry->ifindex = ifindex;
5222 +       entry->seq = seq;
5223 +       entry->type = type;
5224 +       entry->flags = flags;
5225 +       
5226 +       entry->last_br = 0;
5227 +       entry->destunr_count = 0;
5228 +       entry->callback_time = now + lifetime * HZ;
5229 +       if (entry->type & HOME_REGISTRATION)
5230 +               entry->br_callback_time = 0;
5231 +       else
5232 +               entry->br_callback_time = now +
5233 +                       (lifetime - BCACHE_BR_SEND_LEAD) * HZ;
5234 +       
5235 +       if (update) {
5236 +               DEBUG(DBG_INFO, "updating entry : %x", entry);
5237 +               hashlist_reposition(bcache.entries, (void *)entry, 
5238 +                                   entry->callback_time);
5239 +       } else {
5240 +               DEBUG(DBG_INFO, "adding entry: %x", entry);
5241 +               if ((hashlist_add(bcache.entries,
5242 +                                 &hashkey,
5243 +                                 entry->callback_time, entry)) < 0) {
5244 +                       
5245 +                       DEBUG(DBG_ERROR, "Hash add failed");
5246 +                       goto err_hashlist;
5247 +               }
5248 +       }
5249 +       
5250 +       set_timer();
5251 +       
5252 +out:
5253 +       write_unlock(&bcache_lock);
5254 +       return 0;
5255 +
5256 +err_hashlist:
5257 +       if (create_tunnel) {
5258 +               mip6_fn.proxy_del(home_addr, entry);
5259 +       }
5260 +err_proxy:
5261 +       if (update) {
5262 +               hashlist_delete(bcache.entries, (void *)entry);
5263 +       }
5264 +       mipv6_bce_free(entry);
5265 +err:
5266 +       write_unlock(&bcache_lock);
5267 +       return ret;
5268 +}
5269 +
5270 +int mipv6_bcache_icmp_err(struct in6_addr *home_addr,
5271 +                         struct in6_addr *our_addr, 
5272 +                         int destunr_count)
5273 +{
5274 +       struct mipv6_bce *entry;
5275 +       struct in6_addr_pair hashkey;
5276 +
5277 +       int ret = -ENOENT;
5278 +
5279 +       DEBUG_FUNC();
5280 +
5281 +       hashkey.a1 = home_addr;
5282 +       hashkey.a2 = our_addr;
5283 +
5284 +       write_lock(&bcache_lock);
5285 +       if (unlikely(bcache.entries == NULL)) {
5286 +               ret = -ENOMEM;
5287 +               goto err;
5288 +       }
5289 +
5290 +       if ((entry = (struct mipv6_bce *)
5291 +            hashlist_get(bcache.entries, &hashkey)) != NULL) {
5292 +               entry->last_destunr = jiffies;
5293 +               entry->destunr_count = destunr_count;
5294 +               ret = 0;
5295 +       }
5296 +err:
5297 +       write_unlock(&bcache_lock);
5298 +       return ret;
5299 +}
5300 +
5301 +
5302 +/**
5303 + * mipv6_bcache_delete - delete Binding Cache entry
5304 + * @home_addr: MN's home address
5305 + * @our_addr: our address
5306 + * @type: type of entry
5307 + *
5308 + * Deletes an entry associated with @home_addr from Binding Cache.
5309 + * Valid values for @type are %CACHE_ENTRY, %HOME_REGISTRATION and
5310 + * %ANY_ENTRY.  %ANY_ENTRY deletes any type of entry.
5311 + **/
5312 +int mipv6_bcache_delete(struct in6_addr *home_addr,
5313 +                       struct in6_addr *our_addr, __u8 type)
5314 +{
5315 +       struct mipv6_bce *entry;
5316 +       struct in6_addr_pair hashkey;
5317 +       int err = 0;
5318 +
5319 +       DEBUG_FUNC();
5320 +
5321 +       if (home_addr == NULL || our_addr == NULL) {
5322 +               DEBUG(DBG_INFO, "error in arguments");
5323 +               return -EINVAL;
5324 +       }
5325 +
5326 +       hashkey.a1 = home_addr;
5327 +       hashkey.a2 = our_addr;
5328 +
5329 +       write_lock(&bcache_lock);
5330 +
5331 +       if (unlikely(bcache.entries == NULL) ||
5332 +           (entry = (struct mipv6_bce *)
5333 +            hashlist_get(bcache.entries, &hashkey)) == NULL ||
5334 +           !(entry->type & type)) {
5335 +               DEBUG(DBG_INFO, "No matching entry found");
5336 +               err = -ENOENT;
5337 +               goto out;
5338 +       }
5339 +
5340 +       hashlist_delete(bcache.entries, (void *) entry);
5341 +       mipv6_bce_free(entry);
5342 +
5343 +       set_timer();
5344 +out:
5345 +       write_unlock(&bcache_lock);
5346 +       return err;
5347 +}
5348 +
5349 +/**
5350 + * mipv6_bcache_exists - check if entry exists
5351 + * @home_addr: home address to check
5352 + * @our_addr: our address
5353 + *
5354 + * Determines if a binding exists for @home_addr.  Returns type of the
5355 + * entry or negative if entry does not exist.
5356 + **/
5357 +int mipv6_bcache_exists(struct in6_addr *home_addr,
5358 +                       struct in6_addr *our_addr)
5359 +{
5360 +       struct mipv6_bce *entry;
5361 +       struct in6_addr_pair hashkey;
5362 +       int type = -ENOENT;
5363 +
5364 +       DEBUG_FUNC();
5365 +
5366 +       if (home_addr == NULL || our_addr == NULL)
5367 +               return -EINVAL;
5368 +
5369 +       hashkey.a1 = home_addr;
5370 +       hashkey.a2 = our_addr;
5371 +
5372 +       read_lock(&bcache_lock);
5373 +       if (likely(bcache.entries != NULL) &&
5374 +           (entry = (struct mipv6_bce *)
5375 +            hashlist_get(bcache.entries, &hashkey)) != NULL) {
5376 +               type = entry->type;
5377 +       }
5378 +       read_unlock(&bcache_lock);
5379 +
5380 +       return type;
5381 +}
5382 +
5383 +/**
5384 + * mipv6_bcache_get - get entry from Binding Cache
5385 + * @home_addr: home address to search
5386 + * @our_addr: our address
5387 + * @entry: pointer to buffer
5388 + *
5389 + * Gets a copy of Binding Cache entry for @home_addr. If entry 
5390 + * exists entry is copied to @entry and zero is returned.  
5391 + * Otherwise returns negative.
5392 + **/
5393 +int mipv6_bcache_get(struct in6_addr *home_addr,
5394 +                    struct in6_addr *our_addr,
5395 +                    struct mipv6_bce *entry)
5396 +{
5397 +       struct mipv6_bce *entry2;
5398 +       struct in6_addr_pair hashkey;
5399 +       int ret = -ENOENT;
5400 +
5401 +       DEBUG_FUNC();
5402 +
5403 +       if (home_addr == NULL || our_addr == NULL || entry == NULL)
5404 +               return -EINVAL;
5405 +
5406 +       hashkey.a1 = home_addr;
5407 +       hashkey.a2 = our_addr;
5408 +
5409 +       read_lock_bh(&bcache_lock);
5410 +
5411 +       entry2 = (struct mipv6_bce *)
5412 +               hashlist_get(bcache.entries, &hashkey);
5413 +       if (entry2 != NULL) {
5414 +               memcpy(entry, entry2, sizeof(struct mipv6_bce));
5415 +               ret = 0;
5416 +       }
5417 +       read_unlock_bh(&bcache_lock);
5418 +       return ret;
5419 +}
5420 +
5421 +int mipv6_bcache_iterate(hashlist_iterator_t func, void *args)
5422 +{
5423 +       int ret;
5424 +
5425 +       read_lock_bh(&bcache_lock);
5426 +       ret = hashlist_iterate(bcache.entries, args, func);
5427 +       read_unlock_bh(&bcache_lock);
5428 +
5429 +       return ret;
5430 +}
5431 +
5432 +/*
5433 + * Proc-filesystem functions
5434 + */
5435 +
5436 +#define BC_INFO_LEN 80
5437 +
5438 +struct procinfo_iterator_args {
5439 +       char *buffer;
5440 +       int offset;
5441 +       int length;
5442 +       int skip;
5443 +       int len;
5444 +};
5445 +
5446 +static int procinfo_iterator(void *data, void *args, unsigned long *pref)
5447 +{
5448 +       struct procinfo_iterator_args *arg =
5449 +           (struct procinfo_iterator_args *) args;
5450 +       struct mipv6_bce *entry =
5451 +           (struct mipv6_bce *) data;
5452 +
5453 +       ASSERT(entry != NULL);
5454 +
5455 +       if (arg->skip < arg->offset / BC_INFO_LEN) {
5456 +               arg->skip++;
5457 +               return ITERATOR_CONT;
5458 +       }
5459 +
5460 +       if (arg->len >= arg->length)
5461 +               return ITERATOR_CONT;
5462 +
5463 +       /* HoA CoA CallbackInSecs Type */
5464 +       arg->len += sprintf(arg->buffer + arg->len,
5465 +                           "%08x%08x%08x%08x %08x%08x%08x%08x %010lu %02d\n",
5466 +                           ntohl(entry->home_addr.s6_addr32[0]),
5467 +                           ntohl(entry->home_addr.s6_addr32[1]),
5468 +                           ntohl(entry->home_addr.s6_addr32[2]),
5469 +                           ntohl(entry->home_addr.s6_addr32[3]),
5470 +                           ntohl(entry->coa.s6_addr32[0]),
5471 +                           ntohl(entry->coa.s6_addr32[1]),
5472 +                           ntohl(entry->coa.s6_addr32[2]),
5473 +                           ntohl(entry->coa.s6_addr32[3]),
5474 +                           ((entry->callback_time) - jiffies) / HZ,
5475 +                           (int) entry->type);
5476 +
5477 +       return ITERATOR_CONT;
5478 +}
5479 +
5480 + /*
5481 +  * Callback function for proc filesystem.
5482 +  */
5483 +static int bcache_proc_info(char *buffer, char **start, off_t offset,
5484 +                           int length)
5485 +{
5486 +       struct procinfo_iterator_args args;
5487 +
5488 +       DEBUG_FUNC();
5489 +
5490 +       args.buffer = buffer;
5491 +       args.offset = offset;
5492 +       args.length = length;
5493 +       args.skip = 0;
5494 +       args.len = 0;
5495 +
5496 +       read_lock_bh(&bcache_lock);
5497 +       hashlist_iterate(bcache.entries, &args, procinfo_iterator);
5498 +       read_unlock_bh(&bcache_lock);
5499 +
5500 +       *start = buffer;
5501 +       if (offset)
5502 +               *start += offset % BC_INFO_LEN;
5503 +
5504 +       args.len -= offset % BC_INFO_LEN;
5505 +
5506 +       if (args.len > length)
5507 +               args.len = length;
5508 +       if (args.len < 0)
5509 +               args.len = 0;
5510 +
5511 +       return args.len;
5512 +}
5513 +
5514 +static int bcache_compare(void *data, void *hashkey)
5515 +{
5516 +       struct in6_addr_pair *p = (struct in6_addr_pair *) hashkey;
5517 +       struct mipv6_bce *e = (struct mipv6_bce *) data;
5518 +
5519 +       if (ipv6_addr_cmp(&e->home_addr, p->a1) == 0
5520 +           && ipv6_addr_cmp(&e->our_addr, p->a2) == 0)
5521 +               return 0;
5522 +       else
5523 +               return -1;
5524 +}
5525 +
5526 +static __u32 bcache_hash(void *hashkey)
5527 +{
5528 +       struct in6_addr_pair *p = (struct in6_addr_pair *) hashkey;
5529 +
5530 +       return p->a1->s6_addr32[0] ^ p->a1->s6_addr32[1] ^
5531 +               p->a2->s6_addr32[2] ^ p->a2->s6_addr32[3];
5532 +}
5533 +
5534 +/* 
5535 + * Initialization and shutdown functions
5536 + */
5537 +
5538 +int __init mipv6_bcache_init(__u32 size)
5539 +{
5540 +       if (size < 1) {
5541 +               DEBUG(DBG_ERROR, "Binding cache size must be at least 1");
5542 +               return -EINVAL;
5543 +       }
5544 +       bcache.entries = hashlist_create(MIPV6_BCACHE_HASHSIZE, size,
5545 +                                        sizeof(struct mipv6_bce),
5546 +                                        "mip6_bcache", NULL, NULL,
5547 +                                        bcache_compare, bcache_hash);
5548 +
5549 +       if (bcache.entries == NULL) {
5550 +               DEBUG(DBG_ERROR, "Failed to initialize hashlist");
5551 +               return -ENOMEM;
5552 +       }
5553 +
5554 +       init_timer(&bcache.callback_timer);
5555 +       bcache.callback_timer.data = 0;
5556 +       bcache.callback_timer.function = timer_handler;
5557 +       bcache.size = size;
5558 +
5559 +       proc_net_create("mip6_bcache", 0, bcache_proc_info);
5560 +
5561 +       DEBUG(DBG_INFO, "Binding cache initialized");
5562 +       return 0;
5563 +}
5564 +
5565 +static int 
5566 +bce_cleanup_iterator(void *rawentry, void *args, unsigned long *sortkey)
5567 +{
5568 +       int type = (int) args;
5569 +       struct mipv6_bce *entry = (struct mipv6_bce *) rawentry;
5570 +       if (entry->type == type) {
5571 +               if (entry->type & HOME_REGISTRATION) {
5572 +                       if (unlikely(mip6_fn.proxy_del == NULL))
5573 +                               DEBUG(DBG_ERROR, "proxy_del unitialized");
5574 +                       else
5575 +                               mip6_fn.proxy_del(&entry->home_addr, entry);
5576 +               }
5577 +               return ITERATOR_DELETE_ENTRY;
5578 +       }
5579 +       return ITERATOR_CONT;
5580 +
5581 +}
5582 +
5583 +void mipv6_bcache_cleanup(int type)
5584 +{
5585 +       write_lock_bh(&bcache_lock);
5586 +       hashlist_iterate(bcache.entries,(void *) type, bce_cleanup_iterator);
5587 +       write_unlock_bh(&bcache_lock);
5588 +}
5589 +
5590 +int __exit mipv6_bcache_exit(void)
5591 +{
5592 +       struct hashlist *entries;
5593 +
5594 +       DEBUG_FUNC();
5595 +
5596 +       proc_net_remove("mip6_bcache");
5597 +
5598 +       write_lock_bh(&bcache_lock);
5599 +       DEBUG(DBG_INFO, "Stopping the bcache timer");
5600 +       del_timer(&bcache.callback_timer);
5601 +       hashlist_iterate(bcache.entries,(void *)CACHE_ENTRY, 
5602 +                        bce_cleanup_iterator);
5603 +
5604 +       entries = bcache.entries;
5605 +       bcache.entries = NULL;
5606 +       write_unlock_bh(&bcache_lock);
5607 +
5608 +       hashlist_destroy(entries);
5609 +       return 0;
5610 +}
5611 --- /dev/null
5612 +++ linux-2.4.27/net/ipv6/mobile_ip6/bcache.h
5613 @@ -0,0 +1,72 @@
5614 +/*
5615 + *      MIPL Mobile IPv6 Binding Cache header file
5616 + *
5617 + *      $Id$
5618 + *
5619 + *      This program is free software; you can redistribute it and/or
5620 + *      modify it under the terms of the GNU General Public License
5621 + *      as published by the Free Software Foundation; either version
5622 + *      2 of the License, or (at your option) any later version.
5623 + */
5624 +
5625 +#ifndef _BCACHE_H
5626 +#define _BCACHE_H
5627 +
5628 +#include <linux/in6.h>
5629 +#include <linux/timer.h>
5630 +#include "hashlist.h"
5631 +
5632 +#define CACHE_ENTRY 1 /* this and HOME_REGISTRATION are the entry types */
5633 +#define HOME_REGISTRATION 2
5634 +#define ANY_ENTRY 3
5635 +
5636 +#define MIPV6_MAX_DESTUNREACH 5 /* Delete CN BCEs after 5 destination unreachables */
5637 +#define MIPV6_DEST_UNR_IVAL  10 /* What is the max interval of destination  
5638 +                                  unreacahable error messages for them to be persistent*/
5639 +
5640 +struct mipv6_bce {
5641 +       struct hashlist_entry e;
5642 +       int ifindex;                            /* Interface identifier */
5643 +       struct in6_addr our_addr;               /* our address (as seen by the MN) */
5644 +       struct in6_addr home_addr;              /* MN home address */
5645 +       struct in6_addr coa;                    /* MN care-of address */
5646 +       unsigned long callback_time;            /* time of expiration     (in jiffies) */
5647 +       unsigned long br_callback_time;         /* time for sending a BR  (in jiffies) */
5648 +       int (*callback_function)(struct mipv6_bce *entry);
5649 +       __u8 type;                              /* home registration */
5650 +       __u8 router;                            /* mn is router */
5651 +       __u8 flags;                             /* flags received in BU */
5652 +       __u16 seq;                              /* sequence number */
5653 +       unsigned long last_br;                  /* time when last BR sent */
5654 +       unsigned long last_destunr;             /* time when last ICMP destination unreachable received */
5655 +       int br_count;                           /* How many BRRs have sent */
5656 +       int destunr_count;                      /* Number of destination unreachables received */   
5657 +};
5658 +
5659 +int mipv6_bcache_add(int ifindex, struct in6_addr *our_addr, 
5660 +                    struct in6_addr *home_addr, struct in6_addr *coa,
5661 +                    __u32 lifetime, __u16 seq, __u8 flags, __u8 type);
5662 +
5663 +int mipv6_bcache_icmp_err(struct in6_addr *home_addr,
5664 +                         struct in6_addr *our_addr, 
5665 +                         int destunr_count);
5666 +
5667 +int mipv6_bcache_delete(struct in6_addr *home_addr, struct in6_addr *our_addr,
5668 +                       __u8 type);
5669 +
5670 +int mipv6_bcache_exists(struct in6_addr *home_addr,
5671 +                       struct in6_addr *our_addr);
5672 +
5673 +int mipv6_bcache_get(struct in6_addr *home_addr,
5674 +                    struct in6_addr *our_addr,
5675 +                    struct mipv6_bce *entry);
5676 +
5677 +int mipv6_bcache_iterate(int (*func)(void *, void *, unsigned long *), void *args);
5678 +
5679 +void mipv6_bcache_cleanup(int type);
5680 +
5681 +int mipv6_bcache_init(__u32 size);
5682 +
5683 +int mipv6_bcache_exit(void);
5684 +
5685 +#endif /* _BCACHE_H */
5686 --- /dev/null
5687 +++ linux-2.4.27/net/ipv6/mobile_ip6/bul.c
5688 @@ -0,0 +1,634 @@
5689 +/*
5690 + *      Binding update list
5691 + *
5692 + *      Authors:
5693 + *      Juha Mynttinen            <jmynttin@cc.hut.fi>
5694 + *
5695 + *      $Id$
5696 + *
5697 + *      This program is free software; you can redistribute it and/or
5698 + *      modify it under the terms of the GNU General Public License
5699 + *      as published by the Free Software Foundation; either version
5700 + *      2 of the License, or (at your option) any later version.
5701 + */
5702 +
5703 +/*
5704 + *     Changes:
5705 + *
5706 + *     Nanno Langstraat        :       Timer code cleaned up
5707 + */
5708 +
5709 +#include <linux/autoconf.h>
5710 +#include <linux/sched.h>
5711 +#include <linux/timer.h>
5712 +#include <linux/in6.h>
5713 +#include <linux/init.h>
5714 +#include <linux/spinlock.h>
5715 +#include <net/ipv6.h>
5716 +#include <net/mipv6.h>
5717 +#include <linux/proc_fs.h>
5718 +
5719 +#include "bul.h"
5720 +#include "debug.h"
5721 +#include "hashlist.h"
5722 +#include "tunnel_mn.h"
5723 +#include "mobhdr.h"
5724 +
5725 +#define MIPV6_BUL_HASHSIZE 32
5726 +
5727 +rwlock_t bul_lock = RW_LOCK_UNLOCKED;
5728 +
5729 +struct mipv6_bul {
5730 +       struct hashlist *entries;
5731 +       struct timer_list callback_timer;
5732 +};
5733 +
5734 +static struct mipv6_bul bul;
5735 +
5736 +struct in6_addr_pair {
5737 +       struct in6_addr *a1;
5738 +       struct in6_addr *a2;
5739 +};
5740 +
5741 +/**********************************************************************
5742 + *
5743 + * Private functions
5744 + *
5745 + **********************************************************************/
5746 +
5747 +static int bul_compare(void *data, void *hashkey)
5748 +{
5749 +       struct in6_addr_pair *p = (struct in6_addr_pair *)hashkey;
5750 +       struct mipv6_bul_entry *e = (struct mipv6_bul_entry *)data;
5751 +
5752 +       if (ipv6_addr_cmp(&e->cn_addr, p->a1) == 0
5753 +           && ipv6_addr_cmp(&e->home_addr, p->a2) == 0)
5754 +               return 0;
5755 +       else
5756 +               return -1;
5757 +}
5758 +
5759 +struct test_keys {
5760 +       struct in6_addr *addr;
5761 +       u8 *cookie;
5762 +};
5763 +
5764 +static int bul_compare_cookie(void *data, void *keys)
5765 +{
5766 +       struct test_keys *p = (struct test_keys *)keys;
5767 +       struct mipv6_bul_entry *e = (struct mipv6_bul_entry *)data;
5768 +
5769 +       if (ipv6_addr_cmp(&e->cn_addr, p->addr) == 0 && e->rr
5770 +           && memcmp(&e->rr->cot_cookie, p->cookie, 8) == 0)
5771 +               return 0;
5772 +       else
5773 +               return -1;
5774 +}
5775 +
5776 +static u32 bul_hash(void *hashkey)
5777 +{
5778 +       struct in6_addr_pair *p = (struct in6_addr_pair *)hashkey;
5779 +       
5780 +       return p->a1->s6_addr32[0] ^
5781 +               p->a1->s6_addr32[1] ^
5782 +               p->a1->s6_addr32[2] ^
5783 +               p->a1->s6_addr32[3];
5784 +}
5785 +
5786 +static int bul_proc_info(char *buffer, char **start, off_t offset,
5787 +                           int length);
5788 +
5789 +static struct mipv6_bul_entry *mipv6_bul_get_entry(void)
5790 +{
5791 +       DEBUG_FUNC();
5792 +       return ((struct mipv6_bul_entry *) 
5793 +               hashlist_alloc(bul.entries, SLAB_ATOMIC));
5794 +}
5795 +
5796 +static void mipv6_bul_entry_free(struct mipv6_bul_entry *entry)
5797 +{
5798 +       DEBUG_FUNC();           
5799 +
5800 +       if (entry->rr) {
5801 +               if (entry->rr->kbu)
5802 +                       kfree(entry->rr->kbu);
5803 +               kfree(entry->rr);
5804 +       }
5805 +       if (entry->ops)
5806 +               kfree(entry->ops);
5807 +       hashlist_free(bul.entries, (void *)entry);
5808 +}
5809 +
5810 +static __inline__ int del_bul_entry_tnl(struct mipv6_bul_entry *entry) 
5811 +{
5812 +       if (entry->flags & MIPV6_BU_F_HOME) {
5813 +               return mipv6_mv_tnl_to_ha(&entry->cn_addr, 
5814 +                                          &entry->coa,
5815 +                                          &entry->home_addr);
5816 +       }
5817 +       return 0;
5818 +}
5819 +
5820 +static void timer_update(void)
5821 +{
5822 +       struct mipv6_bul_entry *entry;
5823 +
5824 +       DEBUG_FUNC();
5825 +
5826 +       entry = hashlist_get_first(bul.entries);
5827 +
5828 +       while (entry && time_after_eq(jiffies, entry->callback_time)) {
5829 +               if (time_after_eq(jiffies, entry->expire) ||
5830 +                   entry->callback(entry) != 0) {
5831 +                       /*
5832 +                        * Either the entry has expired, or the callback
5833 +                        * indicated that it should be deleted.
5834 +                        */
5835 +                       hashlist_delete(bul.entries, (void *)entry);
5836 +                       
5837 +                       del_bul_entry_tnl(entry);
5838 +                       mipv6_bul_entry_free(entry);
5839 +                       DEBUG(DBG_INFO, "Entry deleted (was expired) from "
5840 +                             "binding update list");
5841 +               } else {
5842 +                       /* move entry to its right place in the hashlist */
5843 +                       DEBUG(DBG_INFO, "Rescheduling");
5844 +                       hashlist_reposition(bul.entries, (void *)entry,
5845 +                                           entry->callback_time);
5846 +               }
5847 +               entry = (struct mipv6_bul_entry *)
5848 +                       hashlist_get_first(bul.entries);
5849 +       }
5850 +
5851 +       if (entry == NULL) {
5852 +               DEBUG(DBG_INFO, "bul empty, not setting a new timer");
5853 +               del_timer(&bul.callback_timer);
5854 +       } else {
5855 +               mod_timer(&bul.callback_timer, entry->callback_time);
5856 +       }
5857 +}
5858 +
5859 +static void timer_handler(unsigned long dummy)
5860 +{
5861 +       DEBUG_FUNC();
5862 +
5863 +       write_lock(&bul_lock);
5864 +       timer_update();
5865 +       write_unlock(&bul_lock);
5866 +}
5867 +
5868 +/**********************************************************************
5869 + *
5870 + * Public interface functions
5871 + *
5872 + **********************************************************************/
5873 +
5874 +/**
5875 + * mipv6_bul_iterate - apply interator function to all entries
5876 + * @func: function to apply
5877 + * @args: extra arguments for iterator
5878 + *
5879 + * Applies @func for each entry in Binding Update List.  Extra
5880 + * arguments given in @args are also passed to the iterator function.
5881 + * Caller must hold @bul_lock.
5882 + **/
5883 +int mipv6_bul_iterate(hashlist_iterator_t func, void *args)
5884 +{
5885 +       DEBUG_FUNC();
5886 +
5887 +       return hashlist_iterate(bul.entries, args, func);
5888 +}
5889 +
5890 +/**
5891 + * mipv6_bul_exists - check if Binding Update List entry exists
5892 + * @cn: address to check
5893 + *
5894 + * Checks if Binding Update List has an entry for @cn.  Returns true
5895 + * if entry exists, false otherwise. Caller may not hold @bul_lock.
5896 + **/
5897 +int mipv6_bul_exists(struct in6_addr *cn, struct in6_addr *haddr)
5898 +{
5899 +       int exists;
5900 +       struct in6_addr_pair hashkey;
5901 +
5902 +       DEBUG_FUNC();
5903 +
5904 +       hashkey.a1 = cn;
5905 +       hashkey.a2 = haddr;
5906 +       
5907 +       read_lock_bh(&bul_lock);
5908 +
5909 +       if (unlikely(bul.entries == NULL))
5910 +               exists = 0;
5911 +       else
5912 +               exists = (hashlist_get(bul.entries, &hashkey) != NULL);
5913 +
5914 +       read_unlock_bh(&bul_lock);
5915 +       return exists;
5916 +}
5917 +
5918 +/**
5919 + * mipv6_bul_get - get Binding Update List entry
5920 + * @cn_addr: CN address to search
5921 + * @home_addr: home address to search
5922 + *
5923 + * Returns Binding Update List entry for @cn_addr if it exists.
5924 + * Otherwise returns %NULL.  Caller must hold @bul_lock.
5925 + **/
5926 +struct mipv6_bul_entry *mipv6_bul_get(struct in6_addr *cn_addr, 
5927 +                                     struct in6_addr *home_addr)
5928 +{
5929 +       struct mipv6_bul_entry *entry;
5930 +       struct in6_addr_pair hashkey;
5931 +       
5932 +       DEBUG_FUNC();
5933 +
5934 +       if (unlikely(bul.entries == NULL)) {
5935 +               return NULL;
5936 +       }
5937 +       hashkey.a1 = cn_addr;
5938 +       hashkey.a2 = home_addr;
5939 +
5940 +       entry = (struct mipv6_bul_entry *) 
5941 +               hashlist_get(bul.entries, &hashkey);
5942 +               
5943 +       return entry;
5944 +}
5945 +
5946 +struct mipv6_bul_entry *mipv6_bul_get_by_ccookie(
5947 +       struct in6_addr *cn_addr, u8 *cookie)
5948 +{
5949 +       struct test_keys key;
5950 +
5951 +       DEBUG_FUNC();
5952 +
5953 +       if (unlikely(bul.entries == NULL))
5954 +               return NULL;
5955 +       key.addr = cn_addr;
5956 +       key.cookie = cookie;
5957 +
5958 +       return (struct mipv6_bul_entry *) 
5959 +               hashlist_get_ex(bul.entries, &key,
5960 +                               bul_compare_cookie);
5961 +}
5962 +
5963 +/**
5964 + * mipv6_bul_reschedule - reschedule Binding Update List entry
5965 + * @entry: entry to reschedule
5966 + *
5967 + * Reschedules a Binding Update List entry.  Must be called after
5968 + * modifying entry lifetime.  Caller must hold @bul_lock (write).
5969 + **/
5970 +void mipv6_bul_reschedule(struct mipv6_bul_entry *entry)
5971 +{
5972 +       DEBUG_FUNC();
5973 +
5974 +       hashlist_reposition(bul.entries,
5975 +                           (void *)entry,
5976 +                           entry->callback_time);
5977 +       timer_update();
5978 +}
5979 +
5980 +/**
5981 + * mipv6_bul_add - add binding update to Binding Update List
5982 + * @cn_addr: IPv6 address where BU was sent
5983 + * @home_addr: Home address for this binding
5984 + * @coa: Care-of address for this binding
5985 + * @lifetime: expiration time of the binding in seconds
5986 + * @seq: sequence number of the BU
5987 + * @flags: %MIPV6_BU_F_* flags
5988 + * @callback: callback function called on expiration
5989 + * @callback_time: expiration time for callback
5990 + * @state: binding send state
5991 + * @delay: retransmission delay
5992 + * @maxdelay: retransmission maximum delay
5993 + * @ops: Mobility header options for BU
5994 + * @rr: Return routability information
5995 + *
5996 + * Adds a binding update sent to @cn_addr for @home_addr to the
5997 + * Binding Update List.  If entry already exists, it is updated.
5998 + * Entry is set to expire in @lifetime seconds.  Entry has a callback
5999 + * function @callback that is called at @callback_time.  Entry @state
6000 + * controls resending of this binding update and it can be set to
6001 + * %ACK_OK, %RESEND_EXP or %ACK_ERROR.  Returns a pointer to the newly
6002 + * created or updated entry.  Caller must hold @bul_lock (write).
6003 + **/
6004 +struct mipv6_bul_entry *mipv6_bul_add(
6005 +       struct in6_addr *cn_addr, struct in6_addr *home_addr,
6006 +       struct in6_addr *coa, 
6007 +       __u32 lifetime, __u16 seq, __u8 flags,
6008 +       int (*callback)(struct mipv6_bul_entry *entry),
6009 +       __u32 callback_time, 
6010 +       __u8 state, __u32 delay, __u32 maxdelay,
6011 +       struct mipv6_mh_opt *ops, 
6012 +       struct mipv6_rr_info *rr)
6013 +{
6014 +       struct mipv6_bul_entry *entry;
6015 +       int update = 0;
6016 +       struct in6_addr_pair hashkey;
6017 +
6018 +       DEBUG_FUNC();
6019 +
6020 +       if (unlikely(bul.entries == NULL))
6021 +               return NULL;
6022 +
6023 +       if (cn_addr == NULL || home_addr == NULL || coa == NULL || 
6024 +           lifetime < 0 || callback == NULL || callback_time < 0 || 
6025 +           (state != ACK_OK && state != RESEND_EXP && state != ACK_ERROR) ||
6026 +           delay < 0 || maxdelay < 0) {
6027 +               DEBUG(DBG_ERROR, "invalid arguments");
6028 +               return NULL;
6029 +       }
6030 +       DEBUG(DBG_INFO, "cn_addr: %x:%x:%x:%x:%x:%x:%x:%x, "
6031 +             "home_addr: %x:%x:%x:%x:%x:%x:%x:%x"
6032 +             "coaddr: %x:%x:%x:%x:%x:%x:%x:%x", NIPV6ADDR(cn_addr), 
6033 +              NIPV6ADDR(home_addr), NIPV6ADDR(coa));
6034 +       hashkey.a1 = cn_addr;
6035 +       hashkey.a2 = home_addr;
6036 +       
6037 +       /* 
6038 +        * decide whether to add a new entry or update existing, also
6039 +        * check if there's room for a new entry when adding a new
6040 +        * entry (latter is handled by mipv6_bul_get_entry() 
6041 +        */
6042 +       if ((entry = (struct mipv6_bul_entry *)
6043 +            hashlist_get(bul.entries, &hashkey)) != NULL) {
6044 +               /* if an entry for this cn_addr exists (with smaller
6045 +                * seq than the new entry's seq), update it */
6046 +               
6047 +               if (MIPV6_SEQ_GT(seq, entry->seq)) {
6048 +                       DEBUG(DBG_INFO, "updating an existing entry");
6049 +                       update = 1;
6050 +               } else {
6051 +                       DEBUG(DBG_INFO, "smaller seq than existing, not updating");
6052 +                       return NULL;
6053 +               }
6054 +       } else {
6055 +               entry = mipv6_bul_get_entry();
6056 +               if (entry == NULL) {
6057 +                       DEBUG(DBG_WARNING, "binding update list full, can't add!!!");
6058 +                       return NULL;
6059 +               }
6060 +               memset(entry, 0, sizeof(*entry));
6061 +               /* First BU send happens here, save count in the entry */
6062 +               entry->consecutive_sends = 1;
6063 +       }
6064 +
6065 +       if (!update) {
6066 +               ipv6_addr_copy(&(entry->cn_addr), cn_addr);
6067 +               ipv6_addr_copy(&(entry->home_addr), home_addr);
6068 +               entry->ops = ops;
6069 +       }
6070 +       /* Add Return Routability info to bul entry */
6071 +       if (rr) {
6072 +               if(entry->rr)
6073 +                       kfree(entry->rr); 
6074 +               entry->rr = rr;
6075 +       }
6076 +
6077 +       ipv6_addr_copy(&(entry->coa), coa);
6078 +       entry->lifetime = lifetime;
6079 +       if (lifetime)
6080 +               entry->expire = jiffies + lifetime * HZ;
6081 +       else if (flags & MIPV6_BU_F_ACK)
6082 +               entry->expire = jiffies + HOME_RESEND_EXPIRE * HZ;
6083 +       entry->seq = seq;
6084 +       entry->flags = flags;
6085 +       entry->lastsend = jiffies; /* current time = last use of the entry */
6086 +       entry->state = state;
6087 +       entry->delay = delay;
6088 +       entry->maxdelay = maxdelay;
6089 +       entry->callback_time = jiffies + callback_time * HZ;
6090 +       entry->callback = callback;
6091 +
6092 +       if (flags & MIPV6_BU_F_HOME && 
6093 +           mipv6_mv_tnl_to_ha(cn_addr, coa, home_addr)) {
6094 +               DEBUG(DBG_ERROR, "reconfiguration of the tunnel failed");
6095 +       }
6096 +       if (update) {
6097 +               DEBUG(DBG_INFO, "updating entry: %x", entry);
6098 +               hashlist_reposition(bul.entries, (void *)entry,
6099 +                                   entry->callback_time);
6100 +       } else {
6101 +               DEBUG(DBG_INFO, "adding entry: %x", entry);
6102 +
6103 +               hashkey.a1 = &entry->cn_addr;
6104 +               hashkey.a2 = &entry->home_addr;
6105 +
6106 +               if ((hashlist_add(bul.entries, &hashkey,
6107 +                                 entry->callback_time,
6108 +                                 entry)) < 0) {
6109 +                       DEBUG(DBG_ERROR, "Hash add failed");
6110 +                       mipv6_bul_entry_free(entry);                    
6111 +                       return NULL;
6112 +               }
6113 +       }
6114 +       timer_update(); 
6115 +
6116 +       return entry;
6117 +}
6118 +
6119 +/**
6120 + * mipv6_bul_delete - delete Binding Update List entry
6121 + * @cn_addr: address for entry to delete
6122 + *
6123 + * Deletes the entry for @cn_addr from the Binding Update List.
6124 + * Returns zero if entry was deleted succesfully, otherwise returns
6125 + * negative.  Caller may not hold @bul_lock.
6126 + **/
6127 +int mipv6_bul_delete(struct in6_addr *cn_addr, struct in6_addr *home_addr)
6128 +{
6129 +       struct mipv6_bul_entry *entry;
6130 +       struct in6_addr_pair hashkey;
6131 +
6132 +       DEBUG_FUNC();
6133 +
6134 +       hashkey.a1 = cn_addr;
6135 +       hashkey.a2 = home_addr;
6136 +
6137 +       write_lock(&bul_lock);
6138 +
6139 +       if (unlikely(bul.entries == NULL) ||  
6140 +           (entry = (struct mipv6_bul_entry *)
6141 +            hashlist_get(bul.entries, &hashkey)) == NULL) {
6142 +               write_unlock(&bul_lock);
6143 +               DEBUG(DBG_INFO, "No such entry");
6144 +               return -ENOENT;
6145 +       }
6146 +
6147 +       hashlist_delete(bul.entries, (void *)entry);
6148 +
6149 +       del_bul_entry_tnl(entry);
6150 +
6151 +       mipv6_bul_entry_free(entry);
6152 +       timer_update();
6153 +       write_unlock(&bul_lock);
6154 +
6155 +       DEBUG(DBG_INFO, "Binding update list entry deleted");
6156 +
6157 +       return 0;
6158 +}
6159 +
6160 +/**********************************************************************
6161 + *
6162 + * Proc interface functions
6163 + *
6164 + **********************************************************************/
6165 +
6166 +#define BUL_INFO_LEN 152
6167 +
6168 +struct procinfo_iterator_args {
6169 +       char *buffer;
6170 +       int offset;
6171 +       int length;
6172 +       int skip;
6173 +       int len;
6174 +};
6175 +
6176 +static int procinfo_iterator(void *data, void *args,
6177 +                            unsigned long *sortkey)
6178 +{
6179 +       struct procinfo_iterator_args *arg =
6180 +               (struct procinfo_iterator_args *)args;
6181 +       struct mipv6_bul_entry *entry =
6182 +               (struct mipv6_bul_entry *)data;
6183 +       unsigned long callback_seconds;
6184 +
6185 +       DEBUG_FUNC();
6186 +
6187 +       if (entry == NULL) return ITERATOR_ERR;
6188 +
6189 +       if (time_after(jiffies, entry->callback_time))
6190 +               callback_seconds = 0;
6191 +       else
6192 +               callback_seconds = (entry->callback_time - jiffies) / HZ;
6193 +
6194 +       if (arg->skip < arg->offset / BUL_INFO_LEN) {
6195 +               arg->skip++;
6196 +               return ITERATOR_CONT;
6197 +       }
6198 +
6199 +       if (arg->len >= arg->length)
6200 +               return ITERATOR_CONT;
6201 +
6202 +       /* CN HoA CoA ExpInSecs SeqNum State Delay MaxDelay CallbackInSecs */
6203 +       arg->len += sprintf(arg->buffer + arg->len,
6204 +                           "%08x%08x%08x%08x %08x%08x%08x%08x %08x%08x%08x%08x\n"
6205 +                           "%010lu %05d %02d %010d %010d %010lu\n",
6206 +                           ntohl(entry->cn_addr.s6_addr32[0]),
6207 +                           ntohl(entry->cn_addr.s6_addr32[1]),
6208 +                           ntohl(entry->cn_addr.s6_addr32[2]),
6209 +                           ntohl(entry->cn_addr.s6_addr32[3]),
6210 +                           ntohl(entry->home_addr.s6_addr32[0]),
6211 +                           ntohl(entry->home_addr.s6_addr32[1]),
6212 +                           ntohl(entry->home_addr.s6_addr32[2]),
6213 +                           ntohl(entry->home_addr.s6_addr32[3]),
6214 +                           ntohl(entry->coa.s6_addr32[0]),
6215 +                           ntohl(entry->coa.s6_addr32[1]),
6216 +                           ntohl(entry->coa.s6_addr32[2]),
6217 +                           ntohl(entry->coa.s6_addr32[3]),
6218 +                           (entry->expire - jiffies) / HZ,
6219 +                           entry->seq, entry->state, entry->delay, 
6220 +                           entry->maxdelay, callback_seconds);
6221 +
6222 +       return ITERATOR_CONT;
6223 +}
6224 +
6225 +
6226 +/*
6227 + * Callback function for proc filesystem.
6228 + */
6229 +static int bul_proc_info(char *buffer, char **start, off_t offset,
6230 +                            int length)
6231 +{
6232 +       struct procinfo_iterator_args args;
6233 +
6234 +       DEBUG_FUNC();
6235 +
6236 +       args.buffer = buffer;
6237 +       args.offset = offset;
6238 +       args.length = length;
6239 +       args.skip = 0;
6240 +       args.len = 0;
6241 +
6242 +       read_lock_bh(&bul_lock);
6243 +       hashlist_iterate(bul.entries, &args, procinfo_iterator);
6244 +       read_unlock_bh(&bul_lock);
6245 +
6246 +       *start = buffer;
6247 +       if (offset)
6248 +               *start += offset % BUL_INFO_LEN;
6249 +
6250 +       args.len -= offset % BUL_INFO_LEN;
6251 +
6252 +       if (args.len > length)
6253 +               args.len = length;
6254 +       if (args.len < 0)
6255 +               args.len = 0;
6256 +       
6257 +       return args.len;
6258 +}
6259 +
6260 +/**********************************************************************
6261 + *
6262 + * Code module init/fini functions
6263 + *
6264 + **********************************************************************/
6265 +
6266 +int __init mipv6_bul_init(__u32 size)
6267 +{
6268 +       DEBUG_FUNC();
6269 +
6270 +       if (size < 1) {
6271 +               DEBUG(DBG_CRITICAL, 
6272 +                     "Binding update list size must be at least 1");
6273 +               return -EINVAL;
6274 +       }
6275 +       bul.entries = hashlist_create(MIPV6_BUL_HASHSIZE, size, 
6276 +                                      sizeof(struct mipv6_bul_entry),
6277 +                                      "mip6_bul", NULL, NULL,
6278 +                                      bul_compare, bul_hash);
6279 +
6280 +       if (bul.entries == NULL) {
6281 +               DEBUG(DBG_CRITICAL, "Couldn't allocate memory for "
6282 +                     "hashlist when creating a binding update list");
6283 +               return -ENOMEM;
6284 +       }
6285 +       init_timer(&bul.callback_timer);
6286 +       bul.callback_timer.data = 0;
6287 +       bul.callback_timer.function = timer_handler;
6288 +       proc_net_create("mip6_bul", 0, bul_proc_info);
6289 +       DEBUG(DBG_INFO, "Binding update list initialized");
6290 +       return 0;
6291 +}
6292 +
6293 +void __exit mipv6_bul_exit()
6294 +{
6295 +       struct mipv6_bul_entry *entry;
6296 +       struct hashlist *entries;
6297 +
6298 +       DEBUG_FUNC();
6299 +
6300 +       proc_net_remove("mip6_bul");
6301 +
6302 +       write_lock_bh(&bul_lock);
6303 +
6304 +       DEBUG(DBG_INFO, "Stopping the bul timer");
6305 +       del_timer(&bul.callback_timer);
6306 +
6307 +       while ((entry = (struct mipv6_bul_entry *) 
6308 +               hashlist_get_first(bul.entries)) != NULL) {
6309 +               hashlist_delete(bul.entries, (void *)entry);
6310 +               
6311 +               del_bul_entry_tnl(entry);
6312 +               
6313 +               mipv6_bul_entry_free(entry);
6314 +       }
6315 +       entries = bul.entries;
6316 +       bul.entries = NULL;
6317 +       write_unlock_bh(&bul_lock); 
6318 +
6319 +       hashlist_destroy(entries);
6320 +
6321 +       DEBUG(DBG_INFO, "binding update list destroyed");
6322 +}
6323 --- /dev/null
6324 +++ linux-2.4.27/net/ipv6/mobile_ip6/bul.h
6325 @@ -0,0 +1,91 @@
6326 +/*
6327 + *      MIPL Mobile IPv6 Binding Update List header file
6328 + *
6329 + *      $Id$
6330 + *
6331 + *      This program is free software; you can redistribute it and/or
6332 + *      modify it under the terms of the GNU General Public License
6333 + *      as published by the Free Software Foundation; either version
6334 + *      2 of the License, or (at your option) any later version.
6335 + */
6336 +
6337 +#ifndef _BUL_H
6338 +#define _BUL_H
6339 +
6340 +#include "hashlist.h"
6341 +
6342 +#define ACK_OK          0x01
6343 +#define RESEND_EXP      0x02
6344 +#define ACK_ERROR       0x04
6345 +
6346 +#define HOME_RESEND_EXPIRE 3600
6347 +#define MIPV6_COOKIE_LEN 8
6348 +struct mipv6_rr_info {
6349 +       /* RR information */
6350 +       u16 rr_state;                /* State of the RR */
6351 +       u16 rr_flags;                /* Flags for the RR */
6352 +       u8 hot_cookie[MIPV6_COOKIE_LEN];    /* HoT Cookie */
6353 +       u8 cot_cookie[MIPV6_COOKIE_LEN];    /* CoT Cookie */
6354 +       u8 home_cookie[MIPV6_COOKIE_LEN];   /* Home Cookie */
6355 +       u8 careof_cookie[MIPV6_COOKIE_LEN]; /* Careof Cookie */
6356 +       u32 lastsend_hoti;            /* When HoTI was last sent (jiffies) */
6357 +       u32 lastsend_coti;            /* When CoTI was last sent (jiffies) */
6358 +       u32 home_time;                /* when Care-of cookie was received */
6359 +       u32 careof_time;              /* when Home cookie was received */
6360 +       int home_nonce_index;         /* Home cookie nonce index */
6361 +       int careof_nonce_index;       /* Care-of cookie nonce index */
6362 +       u8 *kbu;                      /* Binding authentication key */
6363 +};
6364 +struct mipv6_bul_entry {
6365 +       struct hashlist_entry e;
6366 +       struct in6_addr cn_addr;        /* CN to which BU was sent */
6367 +       struct in6_addr home_addr;      /* home address of this binding */
6368 +       struct in6_addr coa;            /* care-of address of the sent BU */
6369 +
6370 +       unsigned long expire;           /* entry's expiration time (jiffies) */ 
6371 +       __u32 lifetime;                 /* lifetime sent in this BU */
6372 +       __u32 lastsend;                 /* last time when BU sent (jiffies) */
6373 +       __u32 consecutive_sends;        /* Number of consecutive BU's sent */
6374 +       __u16 seq;                      /* sequence number of the latest BU */
6375 +       __u8 flags;                     /* BU send flags */
6376 +       __u8 state;                     /* resend state */
6377 +       __u32 initdelay;                /* initial ack wait */
6378 +       __u32 delay;                    /* current ack wait */
6379 +       __u32 maxdelay;                 /* maximum ack wait */
6380 +
6381 +       struct mipv6_rr_info *rr;
6382 +       struct mipv6_mh_opt *ops;       /* saved option values */
6383 +
6384 +       unsigned long callback_time;
6385 +       int (*callback)(struct mipv6_bul_entry *entry);
6386 +};
6387 +
6388 +extern rwlock_t bul_lock;
6389 +
6390 +int mipv6_bul_init(__u32 size);
6391 +
6392 +void mipv6_bul_exit(void);
6393 +
6394 +struct mipv6_bul_entry *mipv6_bul_add(
6395 +       struct in6_addr *cn_addr, struct in6_addr *home_addr,
6396 +       struct in6_addr *coa, __u32 lifetime, __u16 seq, __u8 flags,
6397 +       int (*callback)(struct mipv6_bul_entry *entry), __u32 callback_time,
6398 +       __u8 state, __u32 delay, __u32 maxdelay, struct mipv6_mh_opt *ops,
6399 +       struct mipv6_rr_info *rr);
6400 +
6401 +int mipv6_bul_delete(struct in6_addr *cn_addr, struct in6_addr *home_addr);
6402 +
6403 +int mipv6_bul_exists(struct in6_addr *cnaddr, struct in6_addr *home_addr);
6404 +
6405 +struct mipv6_bul_entry *mipv6_bul_get(struct in6_addr *cnaddr,
6406 +                                     struct in6_addr *home_addr);
6407 +struct mipv6_bul_entry *mipv6_bul_get_by_ccookie(struct in6_addr *cn_addr,
6408 +                                                u8 *cookie);
6409 +
6410 +int bul_entry_expired(struct mipv6_bul_entry *bulentry);
6411 +
6412 +void mipv6_bul_reschedule(struct mipv6_bul_entry *entry);
6413 +
6414 +int mipv6_bul_iterate(int (*func)(void *, void *, unsigned long *), void *args);
6415 +
6416 +#endif /* BUL_H */
6417 --- /dev/null
6418 +++ linux-2.4.27/net/ipv6/mobile_ip6/config.h
6419 @@ -0,0 +1,72 @@
6420 +/*
6421 + * Configuration parameters
6422 + *
6423 + * $Id$
6424 + */
6425 +
6426 +#define MIPV6VERSION "D24"
6427 +#define MIPLVERSION "v1.0"
6428 +
6429 +#define CAP_CN 0x01
6430 +#define CAP_HA 0x02
6431 +#define CAP_MN 0x04
6432 +
6433 +struct mip6_conf {
6434 +       int capabilities;
6435 +       int debug_level;
6436 +       int accept_ret_rout;
6437 +       int max_rtr_reachable_time;
6438 +       int eager_cell_switching;
6439 +       int max_num_tunnels;
6440 +       int min_num_tunnels;
6441 +       int binding_refresh_advice;
6442 +       int bu_lladdr;
6443 +       int bu_keymgm;
6444 +       int bu_cn_ack;
6445 +};
6446 +
6447 +extern struct mip6_conf mip6node_cnf;
6448 +
6449 +struct mipv6_bce;
6450 +
6451 +struct mip6_func {
6452 +       void (*bce_home_add) (int ifindex, struct in6_addr *daddr, 
6453 +                             struct in6_addr *haddr, struct in6_addr *coa,
6454 +                             struct in6_addr *rep_coa, __u32 lifetime, 
6455 +                             __u16 sequence, __u8 flags, __u8 *k_bu);
6456 +       void (*bce_cache_add) (int ifindex, struct in6_addr *daddr,
6457 +                              struct in6_addr *haddr, struct in6_addr *coa,
6458 +                              struct in6_addr *rep_coa, __u32 lifetime,
6459 +                              __u16 sequence, __u8 flags, __u8 *k_bu);
6460 +       void (*bce_home_del) (struct in6_addr *daddr, struct in6_addr *haddr, 
6461 +                             struct in6_addr *coa, struct in6_addr *rep_coa,
6462 +                             __u16 sequence, __u8 flags,
6463 +                             __u8 *k_bu);
6464 +       void (*bce_cache_del) (struct in6_addr *daddr, struct in6_addr *haddr, 
6465 +                              struct in6_addr *coa, struct in6_addr *rep_coa,
6466 +                              __u16 sequence, __u8 flags,
6467 +                              __u8 *k_bu);
6468 +       
6469 +       int (*bce_tnl_rt_add) (struct in6_addr *coa, 
6470 +                              struct in6_addr *ha_addr, 
6471 +                              struct in6_addr *home_addr);
6472 +
6473 +       void (*bce_tnl_rt_del) (struct in6_addr *coa, 
6474 +                               struct in6_addr *ha_addr, 
6475 +                               struct in6_addr *home_addr);
6476 +
6477 +       void (*proxy_del) (struct in6_addr *home_addr, struct mipv6_bce *entry);
6478 +       int (*proxy_create) (int flags, int ifindex, struct in6_addr *coa,
6479 +                            struct in6_addr *our_addr, struct in6_addr *home_addr);
6480 +
6481 +       int (*icmpv6_dhaad_rep_rcv) (struct sk_buff *skb);
6482 +       int (*icmpv6_dhaad_req_rcv) (struct sk_buff *skb);
6483 +       int (*icmpv6_pfxadv_rcv) (struct sk_buff *skb);
6484 +       int (*icmpv6_pfxsol_rcv) (struct sk_buff *skb);
6485 +       int (*icmpv6_paramprob_rcv) (struct sk_buff *skb);
6486 +
6487 +       int (*mn_use_hao) (struct in6_addr *daddr, struct in6_addr *saddr);
6488 +       void (*mn_check_tunneled_packet) (struct sk_buff *skb);
6489 +};
6490 +
6491 +extern struct mip6_func mip6_fn;
6492 --- /dev/null
6493 +++ linux-2.4.27/net/ipv6/mobile_ip6/debug.h
6494 @@ -0,0 +1,112 @@
6495 +/*
6496 + *      MIPL Mobile IPv6 Debugging macros and functions
6497 + *
6498 + *      $Id$
6499 + *
6500 + *      This program is free software; you can redistribute it and/or
6501 + *      modify it under the terms of the GNU General Public License
6502 + *      as published by the Free Software Foundation; either version
6503 + *      2 of the License, or (at your option) any later version.
6504 + */
6505 +
6506 +#ifndef _DEBUG_H
6507 +#define _DEBUG_H
6508 +
6509 +#include <linux/autoconf.h>
6510 +
6511 +/* priorities for different debug conditions */
6512 +
6513 +#define DBG_CRITICAL   0 /* unrecoverable error                     */
6514 +#define DBG_ERROR      1 /* error (recoverable)                     */
6515 +#define DBG_WARNING    2 /* unusual situation but not a real error  */
6516 +#define DBG_INFO       3 /* generally useful information            */
6517 +#define DBG_EXTRA      4 /* extra information                       */
6518 +#define DBG_FUNC_ENTRY 6 /* use to indicate function entry and exit */
6519 +#define DBG_DATADUMP   7 /* packet dumps, etc. lots of flood        */
6520 +
6521 +/**
6522 + * NIPV6ADDR - macro for IPv6 addresses
6523 + * @addr: Network byte order IPv6 address
6524 + *
6525 + * Macro for printing IPv6 addresses.  Used in conjunction with
6526 + * printk() or derivatives (such as DEBUG macro).
6527 + **/
6528 +#define NIPV6ADDR(addr) \
6529 +        ntohs(((u16 *)addr)[0]), \
6530 +        ntohs(((u16 *)addr)[1]), \
6531 +        ntohs(((u16 *)addr)[2]), \
6532 +        ntohs(((u16 *)addr)[3]), \
6533 +        ntohs(((u16 *)addr)[4]), \
6534 +        ntohs(((u16 *)addr)[5]), \
6535 +        ntohs(((u16 *)addr)[6]), \
6536 +        ntohs(((u16 *)addr)[7])
6537 +
6538 +#ifdef CONFIG_IPV6_MOBILITY_DEBUG
6539 +extern int mipv6_debug;
6540 +
6541 +/**
6542 + * debug_print - print debug message
6543 + * @debug_level: message priority
6544 + * @fname: calling function's name
6545 + * @fmt: printf-style formatting string
6546 + *
6547 + * Prints a debug message to system log if @debug_level is less or
6548 + * equal to @mipv6_debug.  Should always be called using DEBUG()
6549 + * macro, not directly.
6550 + **/
6551 +static void debug_print(int debug_level, const char *fname, const char* fmt, ...)
6552 +{
6553 +       char s[1024];
6554 +       va_list args;
6555
6556 +       if (mipv6_debug < debug_level)
6557 +               return;
6558
6559 +       va_start(args, fmt);
6560 +       vsprintf(s, fmt, args);
6561 +       printk("mip6[%s]: %s\n", fname, s);
6562 +       va_end(args);
6563 +}
6564 +
6565 +/**
6566 + * debug_print_buffer - print arbitrary buffer to system log
6567 + * @debug_level: message priority
6568 + * @data: pointer to buffer
6569 + * @len: number of bytes to print
6570 + *
6571 + * Prints @len bytes from buffer @data to system log.  @debug_level
6572 + * tells on which debug level message gets printed.  For
6573 + * debug_print_buffer() priority %DBG_DATADUMP should be used.
6574 + **/
6575 +#define debug_print_buffer(debug_level,data,len) { \
6576 +       if (mipv6_debug >= debug_level) { \
6577 +       int i; \
6578 +       for (i=0; i<len; i++) { \
6579 +               if (i%16 == 0) printk("\n%04x: ", i); \
6580 +               printk("%02x ", ((unsigned char *)data)[i]); \
6581 +       } \
6582 +       printk("\n\n"); \
6583 +       } \
6584 +}
6585 +
6586 +#define DEBUG(x,y,z...) debug_print(x,__FUNCTION__,y,##z)
6587 +#define DEBUG_FUNC() \
6588 +DEBUG(DBG_FUNC_ENTRY, "%s(%d)/%s: ", __FILE__,__LINE__,__FUNCTION__)
6589 +
6590 +#else
6591 +#define DEBUG(x,y,z...)
6592 +#define DEBUG_FUNC()
6593 +#define debug_print_buffer(x,y,z)
6594 +#endif
6595 +
6596 +#undef ASSERT
6597 +#define ASSERT(expression) { \
6598 +        if (!(expression)) { \
6599 +                (void)printk(KERN_ERR \
6600 +                 "Assertion \"%s\" failed: file \"%s\", function \"%s\", line %d\n", \
6601 +                 #expression, __FILE__, __FUNCTION__, __LINE__); \
6602 +               BUG(); \
6603 +        } \
6604 +}
6605 +
6606 +#endif /* _DEBUG_H */
6607 --- /dev/null
6608 +++ linux-2.4.27/net/ipv6/mobile_ip6/exthdrs.c
6609 @@ -0,0 +1,394 @@
6610 +/*
6611 + *     Extension Header handling and adding code
6612 + *
6613 + *     Authors:
6614 + *     Sami Kivisaari          <skivisaa@cc.hut.fi>    
6615 + *
6616 + *     $Id$
6617 + *
6618 + *     This program is free software; you can redistribute it and/or
6619 + *      modify it under the terms of the GNU General Public License
6620 + *      as published by the Free Software Foundation; either version
6621 + *      2 of the License, or (at your option) any later version.
6622 + */
6623 +
6624 +#include <linux/types.h>
6625 +#include <linux/slab.h>
6626 +
6627 +#include <net/ipv6.h>
6628 +#include <net/ip6_route.h>
6629 +#include <net/addrconf.h>
6630 +#include <net/mipv6.h>
6631 +
6632 +#include "debug.h"
6633 +#include "stats.h"
6634 +#include "mobhdr.h"
6635 +#include "bcache.h"
6636 +#include "config.h"
6637 +
6638 +/**
6639 + * mipv6_append_home_addr - Add Home Address Option
6640 + * @opt: buffer for Home Address Option
6641 + * @offset: offset from beginning of @opt
6642 + * @addr: address for HAO
6643 + *
6644 + * Adds a Home Address Option to a packet.  Option is stored in
6645 + * @offset from beginning of @opt.  The option is created but the
6646 + * original source address in IPv6 header is left intact.  The source
6647 + * address will be changed from home address to CoA after the checksum
6648 + * has been calculated in getfrag.  Padding is done automatically, and
6649 + * @opt must have allocated space for both actual option and pad.
6650 + * Returns offset from @opt to end of options.
6651 + **/
6652 +int mipv6_append_home_addr(__u8 *opt, int offset, struct in6_addr *addr)
6653 +{
6654 +       int pad;
6655 +       struct mipv6_dstopt_homeaddr *ho;
6656 +
6657 +       DEBUG(DBG_DATADUMP, "HAO: %x:%x:%x:%x:%x:%x:%x:%x",
6658 +             NIPV6ADDR(addr));
6659 +
6660 +       pad = (6 - offset) & 7;
6661 +       mipv6_add_pad(opt + offset, pad);
6662 +
6663 +       ho = (struct mipv6_dstopt_homeaddr *)(opt + offset + pad);
6664 +       ho->type = MIPV6_TLV_HOMEADDR;
6665 +       ho->length = sizeof(*ho) - 2;
6666 +       ipv6_addr_copy(&ho->addr, addr); 
6667 +
6668 +       return offset + pad + sizeof(*ho);
6669 +}
6670 +static inline int check_hao_validity(struct mipv6_dstopt_homeaddr *haopt, 
6671 +                                    u8 *dst1, 
6672 +                                    struct in6_addr *saddr, 
6673 +                                    struct in6_addr *daddr)
6674 +{
6675 +       int addr_type = ipv6_addr_type(&haopt->addr);
6676 +       struct mipv6_bce bc_entry;
6677 +       
6678 +       if (addr_type & IPV6_ADDR_LINKLOCAL || 
6679 +           !(addr_type & IPV6_ADDR_UNICAST)) {
6680 +               DEBUG(DBG_INFO, "HAO with link local or non-unicast HoA, "
6681 +                     "not sending BE to "
6682 +                     "home address " 
6683 +                     "%x:%x:%x:%x:%x:%x:%x:%x ",
6684 +                     "care-of  address %x:%x:%x:%x:%x:%x:%x:%x",
6685 +                     NIPV6ADDR(&haopt->addr),
6686 +                     NIPV6ADDR(saddr));
6687 +               return -EINVAL;
6688 +       } else if (dst1[0] != IPPROTO_MOBILITY && 
6689 +           (mipv6_bcache_get(&haopt->addr, 
6690 +                             daddr, &bc_entry) != 0 ||
6691 +            ipv6_addr_cmp(saddr, &bc_entry.coa))) {
6692 +               DEBUG(DBG_INFO, "HAO without binding or incorrect CoA, "
6693 +                     "sending BE code 1: "
6694 +                     "home address %x:%x:%x:%x:%x:%x:%x:%x",
6695 +                     "to care-of address %x:%x:%x:%x:%x:%x:%x:%x",
6696 +                     NIPV6ADDR(&haopt->addr),
6697 +                     NIPV6ADDR(saddr));
6698 +               return -ENOENT;
6699 +       }
6700 +       return 0;
6701 +}
6702 +/**
6703 + * mipv6_handle_homeaddr - Home Address Destination Option handler
6704 + * @skb: packet buffer
6705 + * @optoff: offset to where option begins
6706 + *
6707 + * Handles Home Address Option in IPv6 Destination Option header.
6708 + * Packet and offset to option are passed.  If HAO is used without
6709 + * binding, sends a Binding Error code 1.  When sending BE, notify bit
6710 + * is cleared to prevent IPv6 error handling from sending ICMP
6711 + * Parameter Problem.  Returns 1 on success, otherwise zero.
6712 + **/
6713 +int mipv6_handle_homeaddr(struct sk_buff *skb, int optoff)
6714 +{
6715 +       struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
6716 +       struct in6_addr coaddr;
6717 +       struct inet6_skb_parm *opt = (struct inet6_skb_parm *) skb->cb;
6718 +       struct mipv6_dstopt_homeaddr *haopt =
6719 +           (struct mipv6_dstopt_homeaddr *) &skb->nh.raw[optoff];
6720 +       u8 *dst1;
6721 +       int err;
6722 +
6723 +       DEBUG_FUNC();
6724 +       
6725 +       if (haopt->length != sizeof(*haopt) - 2) {
6726 +               DEBUG(DBG_WARNING, "HAO has invalid length");
6727 +               MIPV6_INC_STATS(n_ha_drop.invalid);
6728 +               return 0;
6729 +       }
6730 +       dst1 = (u8 *)skb->h.raw;
6731 +       err = check_hao_validity(haopt, dst1, saddr, &skb->nh.ipv6h->daddr);
6732 +
6733 +       if (err) {
6734 +               haopt->type &= ~(0x80); /* clear notify bit */
6735 +               if (err == -ENOENT)
6736 +                       mipv6_send_be(&skb->nh.ipv6h->daddr, saddr,
6737 +                                     &haopt->addr, MIPV6_BE_HAO_WO_BINDING);
6738 +               MIPV6_INC_STATS(n_ha_drop.misc);
6739 +               return 0;
6740 +       }
6741 +       ipv6_addr_copy(&coaddr, saddr);
6742 +       ipv6_addr_copy(saddr, &haopt->addr);
6743 +       ipv6_addr_copy(&haopt->addr, &coaddr);
6744 +       opt->hao = optoff;
6745 +       if (mip6_fn.mn_check_tunneled_packet != NULL)
6746 +               mip6_fn.mn_check_tunneled_packet(skb);
6747 +
6748 +       MIPV6_INC_STATS(n_ha_rcvd);
6749 +       return 1;
6750 +}
6751 +
6752 +/**
6753 + * mipv6_icmp_swap_addrs - Switch HAO and src and RT2 and dest for ICMP errors
6754 + * @skb: packet buffer
6755 + *
6756 + * Reset the source address and the Home Address option in skb before
6757 + * appending it to an ICMP error message, so original packet appears
6758 + * in the error message rather than mangled.
6759 + **/
6760 +void mipv6_icmp_swap_addrs(struct sk_buff *skb)
6761 +{
6762 +       struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
6763 +       struct in6_addr tmp;
6764 +       struct in6_addr *hoa;
6765 +       DEBUG_FUNC();
6766 +       if (opt->srcrt2) {
6767 +               struct rt2_hdr *rt2;
6768 +               rt2 = (struct rt2_hdr *)(skb->nh.raw + opt->srcrt2);
6769 +               hoa = &rt2->addr;
6770 +
6771 +               ipv6_addr_copy(&tmp, hoa);
6772 +               ipv6_addr_copy(hoa, &skb->nh.ipv6h->daddr);
6773 +               ipv6_addr_copy(&skb->nh.ipv6h->daddr, &tmp);
6774 +               rt2->rt_hdr.segments_left++;
6775 +               skb->nh.ipv6h->hop_limit++;
6776 +       }
6777 +       if (opt->hao) {
6778 +               struct mipv6_dstopt_homeaddr *hao;
6779 +               hao = (struct mipv6_dstopt_homeaddr *)(skb->nh.raw + opt->hao);
6780 +               hoa = &hao->addr;
6781 +
6782 +               ipv6_addr_copy(&tmp, hoa);
6783 +               ipv6_addr_copy(hoa, &skb->nh.ipv6h->saddr);
6784 +               ipv6_addr_copy(&skb->nh.ipv6h->saddr, &tmp);
6785 +       }
6786 +}
6787 +
6788 +/**
6789 + * mipv6_append_rt2hdr - Add Type 2 Routing Header
6790 + * @rt: buffer for new routing header
6791 + * @addr: intermediate hop address
6792 + *
6793 + * Adds a Routing Header Type 2 in a packet.  Stores newly created
6794 + * routing header in buffer @rt.  Type 2 RT only carries one address,
6795 + * so there is no need to process old routing header.  @rt must have
6796 + * allocated space for 24 bytes.
6797 + **/
6798 +void mipv6_append_rt2hdr(struct ipv6_rt_hdr *rt, struct in6_addr *addr)
6799 +{
6800 +       struct rt2_hdr *rt2 = (struct rt2_hdr *)rt;
6801 +
6802 +        DEBUG(DBG_DATADUMP, "RT2: %x:%x:%x:%x:%x:%x:%x:%x",
6803 +             NIPV6ADDR(addr));
6804 +
6805 +       if (ipv6_addr_type(addr) == IPV6_ADDR_MULTICAST) {
6806 +               DEBUG(DBG_ERROR, "destination address not unicast");
6807 +               return;
6808 +       }
6809 +
6810 +       memset(rt2, 0, sizeof(*rt2));
6811 +       rt2->rt_hdr.type = 2;
6812 +       rt2->rt_hdr.hdrlen = 2;
6813 +       rt2->rt_hdr.segments_left = 1;
6814 +       ipv6_addr_copy(&rt2->addr, addr);
6815 +}
6816 +
6817 +/**
6818 + * mipv6_append_dst1opts - Add Destination Option (1) Headers
6819 + * @dst1opt: buffer for new destination options
6820 + * @saddr: address for Home Address Option
6821 + * @old_dst1opt: old destination options
6822 + * @len: length of options
6823 + *
6824 + * Adds Destination Option (1) Header to a packet.  New options are
6825 + * stored in @dst1opt.  If old destination options exist, they are
6826 + * copied from @old_dst1opt.  Only Home Address Option is destination
6827 + * option.  @dstopt must have allocated space for @len bytes.  @len
6828 + * includes Destination Option Header (2 bytes), Home Address Option
6829 + * (18 bytes) and possible HAO pad (8n+6).
6830 + **/
6831 +/*
6832 + * ISSUE: Home Address Destination Option should really be added to a
6833 + * new destination option header specified in Mobile IPv6 spec which
6834 + * should be placed after routing header(s), but before fragmentation
6835 + * header.  Putting HAO in DO1 works for now, but support for the new
6836 + * placement should be added to the IPv6 stack.
6837 + */
6838 +void 
6839 +mipv6_append_dst1opts(struct ipv6_opt_hdr *dst1opt, struct in6_addr *saddr,
6840 +                     struct ipv6_opt_hdr *old_dst1opt, int len)
6841 +{
6842 +       int offset;
6843 +
6844 +       if (old_dst1opt) {
6845 +               memcpy(dst1opt, old_dst1opt, ipv6_optlen(old_dst1opt));
6846 +               offset = ipv6_optlen(old_dst1opt);
6847 +       } else {
6848 +               offset = sizeof (*dst1opt);
6849 +       }
6850 +       dst1opt->hdrlen = (len >> 3) - 1;
6851 +       mipv6_append_home_addr((__u8 *) dst1opt, offset, saddr);
6852 +}
6853 +
6854 +/**
6855 + * mipv6_modify_txoptions - Modify outgoing packets
6856 + * @sk: socket
6857 + * @skb: packet buffer for outgoing packet
6858 + * @old_opt: transmit options
6859 + * @fl: packet flow structure
6860 + * @dst: pointer to destination cache entry
6861 + *
6862 + * Adds Home Address Option (for MN packets, when not at home) and
6863 + * Routing Header Type 2 (for CN packets when sending to an MN) to
6864 + * data packets.  Old extension headers are copied from @old_opt (if
6865 + * any).  Extension headers are _explicitly_ added for packets with
6866 + * Mobility Header.  Returns the new header structure, or old if no
6867 + * changes.
6868 + **/
6869 +struct ipv6_txoptions *
6870 +mipv6_modify_txoptions(struct sock *sk, struct sk_buff *skb, 
6871 +                      struct ipv6_txoptions *old_opt, struct flowi *fl, 
6872 +                      struct dst_entry **dst)
6873 +{      
6874 +       struct ipv6_opt_hdr *old_hopopt = NULL;
6875 +       struct ipv6_opt_hdr *old_dst1opt = NULL;
6876 +       struct ipv6_rt_hdr *old_srcrt = NULL;
6877 +
6878 +       int srcrtlen = 0, dst1len = 0;
6879 +       int tot_len, use_hao = 0;
6880 +       struct ipv6_txoptions *opt;
6881 +       struct mipv6_bce bc_entry;
6882 +       struct in6_addr tmpaddr, *saddr, *daddr, coaddr;
6883 +       __u8 *opt_ptr;
6884 +
6885 +       DEBUG_FUNC();
6886 +
6887 +       if (fl->proto == IPPROTO_MOBILITY) return old_opt;
6888 +       /*
6889 +        * we have to be prepared to the fact that saddr might not be present,
6890 +        * if that is the case, we acquire saddr just as kernel does.
6891 +        */
6892 +       saddr = fl ? fl->fl6_src : NULL;
6893 +       daddr = fl ? fl->fl6_dst : NULL;
6894 +
6895 +       if (daddr == NULL)
6896 +               return old_opt;
6897 +       if (saddr == NULL) {
6898 +               int err = ipv6_get_saddr(NULL, daddr, &tmpaddr);
6899 +               if (err)
6900 +                       return old_opt;
6901 +               else
6902 +                       saddr = &tmpaddr;
6903 +       }
6904 +
6905 +       DEBUG(DBG_DATADUMP,
6906 +             "dest. address of packet: %x:%x:%x:%x:%x:%x:%x:%x",
6907 +             NIPV6ADDR(daddr));
6908 +       DEBUG(DBG_DATADUMP, " and src. address: %x:%x:%x:%x:%x:%x:%x:%x", 
6909 +             NIPV6ADDR(saddr));
6910 +
6911 +       if (old_opt) {
6912 +               old_hopopt = old_opt->hopopt;
6913 +               old_dst1opt = old_opt->dst1opt;
6914 +               old_srcrt = old_opt->srcrt;
6915 +       } 
6916 +
6917 +       if (mip6_fn.mn_use_hao != NULL)
6918 +               use_hao = mip6_fn.mn_use_hao(daddr, saddr);
6919 +
6920 +       if (use_hao) {
6921 +               if (old_dst1opt)
6922 +                       dst1len = ipv6_optlen(old_dst1opt);
6923 +               dst1len += sizeof(struct mipv6_dstopt_homeaddr) +
6924 +                       ((6 - dst1len) & 7); /* padding */
6925 +       }
6926 +
6927 +       if (mipv6_bcache_get(daddr, saddr, &bc_entry) == 0)
6928 +               srcrtlen = sizeof(struct rt2_hdr);
6929 +
6930 +       if ((tot_len = srcrtlen + dst1len) == 0) { 
6931 +               return old_opt;
6932 +       }
6933 +
6934 +       tot_len += sizeof(*opt);
6935 +
6936 +       if (!(opt = kmalloc(tot_len, GFP_ATOMIC))) {
6937 +               return NULL;
6938 +       }
6939 +       memset(opt, 0, tot_len);
6940 +       opt->tot_len = tot_len;
6941 +       opt_ptr = (__u8 *) (opt + 1);
6942 +       
6943 +       if (old_srcrt) {
6944 +               opt->srcrt = old_srcrt;
6945 +               opt->opt_nflen += ipv6_optlen(old_srcrt);
6946 +       }
6947 +
6948 +       if (srcrtlen) {
6949 +               DEBUG(DBG_DATADUMP, "Binding exists. Adding routing header");
6950 +
6951 +               opt->srcrt2 = (struct ipv6_rt_hdr *) opt_ptr;
6952 +               opt->opt_nflen += srcrtlen;
6953 +               opt_ptr += srcrtlen;
6954 +               
6955 +               /*
6956 +                * Append care-of-address to routing header (original
6957 +                * destination address is home address, the first
6958 +                * source route segment gets put to the destination
6959 +                * address and the home address gets to the last
6960 +                * segment of source route (just as it should)) 
6961 +                */
6962 +
6963 +               ipv6_addr_copy(&coaddr, &bc_entry.coa);
6964 +
6965 +               mipv6_append_rt2hdr(opt->srcrt2, &coaddr);
6966 +
6967 +               /*
6968 +                * reroute output (we have to do this in case of TCP
6969 +                 * segment) unless a routing header of type 0 is also added
6970 +                */
6971 +               if (dst && !opt->srcrt) {
6972 +                       struct in6_addr *tmp = fl->fl6_dst;
6973 +                       fl->fl6_dst = &coaddr;
6974 +
6975 +                       dst_release(*dst);
6976 +                       *dst = ip6_route_output(sk, fl);
6977 +                       if (skb)
6978 +                               skb->dst = *dst;
6979 +                       fl->fl6_dst = tmp;
6980 +
6981 +                       DEBUG(DBG_DATADUMP, "Rerouted outgoing packet");
6982 +               }
6983 +       }
6984 +
6985 +       /* Only home address option is inserted to first dst opt header */
6986 +       if (dst1len) {
6987 +               opt->dst1opt = (struct ipv6_opt_hdr *) opt_ptr;
6988 +               opt->opt_flen += dst1len;
6989 +               opt_ptr += dst1len;
6990 +               mipv6_append_dst1opts(opt->dst1opt, saddr, 
6991 +                                     old_dst1opt, dst1len);
6992 +               opt->mipv6_flags = MIPV6_SND_HAO;
6993 +       } else if (old_dst1opt) {
6994 +               opt->dst1opt = old_dst1opt;
6995 +               opt->opt_flen += ipv6_optlen(old_dst1opt);
6996 +       }
6997 +       if (old_hopopt) {
6998 +               opt->hopopt = old_hopopt;
6999 +               opt->opt_nflen += ipv6_optlen(old_hopopt);
7000 +       }       
7001 +       
7002 +       return opt;
7003 +}
7004 --- /dev/null
7005 +++ linux-2.4.27/net/ipv6/mobile_ip6/exthdrs.h
7006 @@ -0,0 +1,47 @@
7007 +/*
7008 + *     MIPL Mobile IPv6 Extension Headers header file
7009 + *
7010 + *     $Id$
7011 + *
7012 + *     This program is free software; you can redistribute it and/or
7013 + *      modify it under the terms of the GNU General Public License
7014 + *      as published by the Free Software Foundation; either version
7015 + *      2 of the License, or (at your option) any later version.
7016 + */
7017 +
7018 +#ifndef _MIPV6_EXTHDRS_H
7019 +#define _MIPV6_EXTHDRS_H
7020 +
7021 +struct in6_addr;
7022 +struct sk_buff;
7023 +struct ipv6_rt_hdr;
7024 +struct ipv6_opt_hdr;
7025 +struct ipv6_txoptions;
7026 +struct flowi;
7027 +struct dst_entry;
7028 +/*
7029 + * Home Address Destination Option function prototypes
7030 + */
7031 +int mipv6_append_home_addr(__u8 *opt, int offset, struct in6_addr *addr);
7032 +
7033 +int mipv6_handle_homeaddr(struct sk_buff *skb, int optoff);
7034 +
7035 +void mipv6_icmp_swap_addrs(struct sk_buff *skb);
7036 +
7037 +/*
7038 + * Creates a routing header of type 2.
7039 + */
7040 +void mipv6_append_rt2hdr(struct ipv6_rt_hdr *srcrt, struct in6_addr *addr);
7041 +
7042 +/* Function to add the first destination option header, which may
7043 + * include a home address option.  
7044 + */
7045 +void mipv6_append_dst1opts(struct ipv6_opt_hdr *dst1opt, struct in6_addr *saddr,
7046 +                          struct ipv6_opt_hdr *old_dst1opt, int len);
7047 +
7048 +struct ipv6_txoptions *mipv6_modify_txoptions(
7049 +       struct sock *sk, struct sk_buff *skb,
7050 +       struct ipv6_txoptions *old_opt, struct flowi *fl,
7051 +       struct dst_entry **dst);
7052 +
7053 +#endif /* _MIPV6_EXTHDRS_H */
7054 --- /dev/null
7055 +++ linux-2.4.27/net/ipv6/mobile_ip6/ha.c
7056 @@ -0,0 +1,553 @@
7057 +/*
7058 + *      Home-agent functionality
7059 + *
7060 + *      Authors:
7061 + *      Sami Kivisaari           <skivisaa@cc.hut.fi>
7062 + *      Henrik Petander          <lpetande@cc.hut.fi>
7063 + *
7064 + *      $Id$
7065 + *
7066 + *      This program is free software; you can redistribute it and/or
7067 + *      modify it under the terms of the GNU General Public License
7068 + *      as published by the Free Software Foundation; either version
7069 + *      2 of the License, or (at your option) any later version.
7070 + *   
7071 + *      Changes: Venkata Jagana,
7072 + *               Krishna Kumar     : Statistics fix
7073 + *               Masahide Nakamura : Use of mipv6_forward  
7074 + *     
7075 + */
7076 +
7077 +#include <linux/autoconf.h>
7078 +#include <linux/net.h>
7079 +#include <linux/skbuff.h>
7080 +#include <linux/if_ether.h>
7081 +#include <linux/netdevice.h>
7082 +#include <linux/in6.h>
7083 +#include <linux/init.h>
7084 +#include <linux/netfilter.h>
7085 +#include <linux/netfilter_ipv6.h>
7086 +#ifdef CONFIG_SYSCTL
7087 +#include <linux/sysctl.h>
7088 +#endif
7089 +
7090 +#include <net/neighbour.h>
7091 +#include <net/ipv6.h>
7092 +#include <net/ip6_fib.h>
7093 +#include <net/ip6_route.h>
7094 +#include <net/ndisc.h>
7095 +#include <net/addrconf.h>
7096 +#include <net/neighbour.h>
7097 +
7098 +#include "tunnel_ha.h"
7099 +#include "bcache.h"
7100 +#include "stats.h"
7101 +#include "debug.h"
7102 +#include "util.h"
7103 +#include "ha.h"
7104 +#include "config.h"
7105 +#include "mobhdr.h"
7106 +
7107 +static int mipv6_ha_tunnel_sitelocal = 0;
7108 +
7109 +#ifdef CONFIG_SYSCTL
7110 +
7111 +static struct ctl_table_header *mipv6_ha_sysctl_header;
7112 +
7113 +static struct mipv6_ha_sysctl_table
7114 +{
7115 +       struct ctl_table_header *sysctl_header;
7116 +       ctl_table mipv6_vars[3];
7117 +       ctl_table mipv6_mobility_table[2];
7118 +       ctl_table mipv6_proto_table[2];
7119 +       ctl_table mipv6_root_table[2];
7120 +} mipv6_ha_sysctl = {
7121 +       NULL,
7122 +
7123 +        {{NET_IPV6_MOBILITY_TUNNEL_SITELOCAL, "tunnel_sitelocal",
7124 +         &mipv6_ha_tunnel_sitelocal, sizeof(int), 0644, NULL, 
7125 +         &proc_dointvec},
7126 +        {0}},
7127 +
7128 +       {{NET_IPV6_MOBILITY, "mobility", NULL, 0, 0555, 
7129 +         mipv6_ha_sysctl.mipv6_vars}, {0}},
7130 +       {{NET_IPV6, "ipv6", NULL, 0, 0555, 
7131 +         mipv6_ha_sysctl.mipv6_mobility_table}, {0}},
7132 +       {{CTL_NET, "net", NULL, 0, 0555, 
7133 +         mipv6_ha_sysctl.mipv6_proto_table}, {0}}
7134 +};
7135 +
7136 +#endif /* CONFIG_SYSCTL */
7137 +
7138 +
7139 +/*  this is defined in kernel IPv6 module (sockglue.c)  */
7140 +extern struct packet_type ipv6_packet_type;
7141 +
7142 +/* mipv6_forward: Intercept NS packets destined to home address of MN */
7143 +int mipv6_forward(struct sk_buff *skb)
7144 +{
7145 +       struct ipv6hdr *ipv6h;
7146 +       struct in6_addr *daddr, *saddr;
7147 +       __u8 nexthdr;
7148 +       int nhoff;
7149 +       
7150 +       if (skb == NULL) return  0;
7151 +       
7152 +       ipv6h = skb->nh.ipv6h;
7153 +       daddr = &ipv6h->daddr;
7154 +       saddr = &ipv6h->saddr;
7155 +
7156 +       nexthdr = ipv6h->nexthdr;
7157 +       nhoff = sizeof(*ipv6h);
7158 +   
7159 +       if (ipv6_ext_hdr(nexthdr))
7160 +               nhoff = ipv6_skip_exthdr(skb, nhoff, &nexthdr,
7161 +                                        skb->len - sizeof(*ipv6h));
7162 +       
7163 +       /* Do not to forward Neighbor Solicitation to Home Address of MN */
7164 +       if (nexthdr == IPPROTO_ICMPV6) {
7165 +               struct icmp6hdr *icmp6h;
7166 +               int dest_type;
7167 +               
7168 +               if (nhoff < 0 || !pskb_may_pull(skb, nhoff + 
7169 +                                               sizeof(struct icmp6hdr))) {
7170 +                       kfree_skb(skb);
7171 +                       return 0;
7172 +                   }
7173 +               
7174 +               dest_type = ipv6_addr_type(daddr);
7175 +               icmp6h = (struct icmp6hdr *)&skb->nh.raw[nhoff];
7176 +               
7177 +               /* Intercepts NS to HoA of MN */
7178 +
7179 +               if ((icmp6h->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) ||
7180 +                   ((dest_type & IPV6_ADDR_MULTICAST) &&
7181 +                    (icmp6h->icmp6_type == NDISC_ROUTER_ADVERTISEMENT))) {
7182 +                       ip6_input(skb);
7183 +               } else {
7184 +                       ip6_forward(skb);
7185 +               }
7186 +       } else {
7187 +               ip6_forward(skb);
7188 +       }
7189 +       return 0;
7190 +}
7191 +
7192 +
7193 +/**
7194 + * mipv6_proxy_nd_rem - stop acting as a proxy for @home_address
7195 + * @home_addr: address to remove
7196 + * @ha_addr: home agent's address on home link
7197 + * @linklocal: link-local compatibility bit
7198 + *
7199 + * When Home Agent acts as a proxy for an address it must leave the
7200 + * solicited node multicast group for that address and stop responding 
7201 + * to neighbour solicitations.  
7202 + **/
7203 +static int mipv6_proxy_nd_rem(struct in6_addr *home_addr,
7204 +                             int ifindex, int linklocal)
7205 +{
7206 +        /* When MN returns home HA leaves the solicited mcast groups
7207 +         * for MNs home addresses 
7208 +        */
7209 +       int err;
7210 +       struct net_device *dev;
7211 +       
7212 +       DEBUG_FUNC();
7213 +       
7214 +        if ((dev = dev_get_by_index(ifindex)) == NULL) {
7215 +               DEBUG(DBG_ERROR, "couldn't get dev");
7216 +               return -ENODEV;
7217 +       }
7218 +#if 1  /* TEST */
7219 +       /* Remove link-local entry */
7220 +       if (linklocal) {
7221 +               struct in6_addr ll_addr;
7222 +               mipv6_generate_ll_addr(&ll_addr, home_addr);
7223 +               if ((err = pneigh_delete(&nd_tbl, &ll_addr, dev)) < 0) {
7224 +                       DEBUG(DBG_INFO,
7225 +                             "peigh_delete failed for "
7226 +                             "%x:%x:%x:%x:%x:%x:%x:%x",
7227 +                             NIPV6ADDR(&ll_addr));     
7228 +               }
7229 +       }
7230 +#endif
7231 +       /* Remove global (or site-local) entry */
7232 +       if ((err = pneigh_delete(&nd_tbl, home_addr, dev)) < 0) {
7233 +               DEBUG(DBG_INFO,
7234 +                     "peigh_delete failed for " 
7235 +                     "%x:%x:%x:%x:%x:%x:%x:%x",
7236 +                     NIPV6ADDR(home_addr));
7237 +       }
7238 +       dev_put(dev);
7239 +       return err;
7240 +}
7241 +
7242 +/**
7243 + * mipv6_proxy_nd - join multicast group for this address
7244 + * @home_addr: address to defend
7245 + * @ha_addr: home agent's address on home link
7246 + * @linklocal: link-local compatibility bit
7247 + *
7248 + * While Mobile Node is away from home, Home Agent acts as a proxy for
7249 + * @home_address. HA responds to neighbour solicitations for  @home_address 
7250 + * thus getting all packets destined to home address of MN. 
7251 + **/
7252 +static int mipv6_proxy_nd(struct in6_addr *home_addr, 
7253 +                         int ifindex, int linklocal)
7254 +{  
7255 +       /* The HA sends a proxy ndisc_na message to all hosts on MN's
7256 +        * home subnet by sending a neighbor advertisement with the
7257 +        * home address or all addresses of the mobile node if the
7258 +        * prefix is not 0. The addresses are formed by combining the
7259 +        * suffix or the host part of the address with each subnet
7260 +        * prefix that exists in the home subnet 
7261 +        */
7262 +       
7263 +        /* Since no previous entry for MN exists a proxy_nd advertisement
7264 +        * is sent to all nodes link local multicast address
7265 +        */     
7266 +       int err = -1;
7267 +
7268 +       struct net_device *dev;
7269 +       struct in6_addr na_saddr;
7270 +       struct in6_addr ll_addr;
7271 +       struct pneigh_entry *ll_pneigh;
7272 +       struct in6_addr mcdest;
7273 +       int send_ll_na = 0;
7274 +       int inc_opt = 1;
7275 +       int solicited = 0;
7276 +       int override = 1;
7277 +       
7278 +       DEBUG_FUNC();
7279 +       
7280 +       if ((dev = dev_get_by_index(ifindex)) == NULL) {
7281 +               DEBUG(DBG_ERROR, "couldn't get dev");
7282 +               return -ENODEV;
7283 +       }
7284 +       
7285 +       if (!pneigh_lookup(&nd_tbl, home_addr, dev, 1)) {
7286 +               DEBUG(DBG_INFO,
7287 +                     "peigh_lookup failed for "
7288 +                     "%x:%x:%x:%x:%x:%x:%x:%x",
7289 +                     NIPV6ADDR(home_addr));
7290 +               goto free_dev;
7291 +       }
7292 +#if 1 /* TEST */
7293 +       if (linklocal) {
7294 +               mipv6_generate_ll_addr(&ll_addr, home_addr);
7295 +               
7296 +               if ((ll_pneigh = pneigh_lookup(&nd_tbl, &ll_addr, 
7297 +                                              dev, 1)) == NULL) {
7298 +                       DEBUG(DBG_INFO,
7299 +                             "peigh_lookup failed for "
7300 +                             "%x:%x:%x:%x:%x:%x:%x:%x",
7301 +                             NIPV6ADDR(&ll_addr));
7302 +                       pneigh_delete(&nd_tbl, home_addr, dev);
7303 +                       goto free_dev;
7304 +               } else {
7305 +                       send_ll_na = 1;
7306 +               }
7307 +       } else {
7308 +               ll_pneigh = NULL;
7309 +       }
7310 +#endif 
7311 +       /* Proxy neighbor advertisement of MN's home address 
7312 +        * to all nodes solicited multicast address 
7313 +        */
7314 +       if (!ipv6_get_lladdr(dev, &na_saddr)) { 
7315 +               ipv6_addr_all_nodes(&mcdest); 
7316 +               ndisc_send_na(dev, NULL, &mcdest, home_addr, 0, 
7317 +                             solicited, override, inc_opt);
7318 +#if 1 /* TEST */
7319 +               if (send_ll_na) {
7320 +                       ndisc_send_na(dev, NULL, &mcdest, &ll_addr, 
7321 +                                     0, solicited, override, inc_opt);
7322 +               }
7323 +#endif
7324 +               err = 0;
7325 +       } else {
7326 +               DEBUG(DBG_ERROR, "failed to get link local address for sending proxy NA");
7327 +       }
7328 +free_dev:
7329 +       dev_put(dev);
7330 +       return err;
7331 +       
7332 +}
7333 +
7334 +struct inet6_ifaddr *is_on_link_ipv6_address(struct in6_addr *mn_haddr,
7335 +                                            struct in6_addr *ha_addr)
7336 +{
7337 +       struct inet6_ifaddr *ifp;
7338 +       struct inet6_dev *in6_dev;
7339 +       struct inet6_ifaddr *oifp = NULL;
7340 +
7341 +       if ((ifp = ipv6_get_ifaddr(ha_addr, 0)) == NULL)
7342 +               return NULL;
7343 +
7344 +       if ((in6_dev = ifp->idev) != NULL) {
7345 +               in6_dev_hold(in6_dev);
7346 +               oifp = in6_dev->addr_list;
7347 +               while (oifp != NULL) {
7348 +                       spin_lock(&oifp->lock);
7349 +                       if (mipv6_prefix_compare(&oifp->addr, mn_haddr,
7350 +                                                oifp->prefix_len) &&
7351 +                           !(oifp->flags & IFA_F_TENTATIVE)) {
7352 +                               spin_unlock(&oifp->lock);
7353 +                               DEBUG(DBG_INFO, "Home Addr Opt: on-link");
7354 +                               in6_ifa_hold(oifp);
7355 +                               break;
7356 +                       }
7357 +                       spin_unlock(&oifp->lock);
7358 +                       oifp = oifp->if_next;
7359 +               }
7360 +               in6_dev_put(in6_dev);
7361 +       }
7362 +       in6_ifa_put(ifp);
7363 +/*      DEBUG(DBG_WARNING, "Home Addr Opt NOT on-link"); */
7364 +       return oifp;
7365 +
7366 +}
7367 +
7368 +/*
7369 + * Lifetime checks. ifp->valid_lft >= ifp->prefered_lft always (see addrconf.c)
7370 + * Returned value is in seconds.
7371 + */
7372 +
7373 +static __u32 get_min_lifetime(struct inet6_ifaddr *ifp, __u32 lifetime)
7374 +{
7375 +       __u32 rem_lifetime = 0;
7376 +       unsigned long now = jiffies;
7377 +
7378 +       if (ifp->valid_lft == 0) {
7379 +               rem_lifetime = lifetime;
7380 +       } else {
7381 +               __u32 valid_lft_left =
7382 +                   ifp->valid_lft - ((now - ifp->tstamp) / HZ);
7383 +               rem_lifetime =
7384 +                   min_t(unsigned long, valid_lft_left, lifetime);
7385 +       }
7386 +
7387 +       return rem_lifetime;
7388 +}
7389 +
7390 +#define MAX_LIFETIME 1000
7391 +
7392 +/**
7393 + * mipv6_lifetime_check - check maximum lifetime is not exceeded
7394 + * @lifetime: lifetime to check
7395 + *
7396 + * Checks @lifetime does not exceed %MAX_LIFETIME.  Returns @lifetime
7397 + * if not exceeded, otherwise returns %MAX_LIFETIME.
7398 + **/
7399 +static int mipv6_lifetime_check(int lifetime)
7400 +{
7401 +       return (lifetime > MAX_LIFETIME) ? MAX_LIFETIME : lifetime;
7402 +}
7403 +
7404 +/* Generic routine handling finish of BU processing */
7405 +void mipv6_bu_finish(struct inet6_ifaddr *ifp, int ifindex, __u8 ba_status,
7406 +                    struct in6_addr *daddr, struct in6_addr *haddr,
7407 +                    struct in6_addr *coa, struct in6_addr *rep_coa,
7408 +                    __u32 ba_lifetime, __u16 sequence, __u8 flags, __u8 *k_bu)
7409 +{
7410 +       int err;
7411 +
7412 +       if (ba_status >= REASON_UNSPECIFIED) {
7413 +               /* DAD failed */
7414 +               goto out;
7415 +       }
7416 +       
7417 +       ba_lifetime = get_min_lifetime(ifp, ba_lifetime);
7418 +       ba_lifetime = mipv6_lifetime_check(ba_lifetime);
7419 +
7420 +       if ((err = mipv6_bcache_add(ifindex, daddr, haddr, coa, 
7421 +                                   ba_lifetime, sequence, flags,
7422 +                                   HOME_REGISTRATION)) != 0 ) {
7423 +               DEBUG(DBG_WARNING, "home reg failed.");
7424 +
7425 +               if (err == -ENOMEDIUM)
7426 +                       return;
7427 +
7428 +               ba_status = INSUFFICIENT_RESOURCES;
7429 +       } else {
7430 +               DEBUG(DBG_INFO, "home reg succeeded.");
7431 +       }
7432 +
7433 +       DEBUG(DBG_DATADUMP, "home_addr: %x:%x:%x:%x:%x:%x:%x:%x",
7434 +             NIPV6ADDR(haddr));
7435 +       DEBUG(DBG_DATADUMP, "coa: %x:%x:%x:%x:%x:%x:%x:%x",
7436 +             NIPV6ADDR(coa));
7437 +       DEBUG(DBG_DATADUMP, "lifet:%d, seq:%d", ba_lifetime, sequence);
7438 +out:
7439 +       mipv6_send_ba(daddr, haddr, coa, rep_coa, ba_status, sequence,
7440 +                     ba_lifetime, k_bu);
7441 +}
7442 +
7443 +static int ha_proxy_create(int flags, int ifindex, struct in6_addr *coa,
7444 +                          struct in6_addr *our_addr, struct in6_addr *home_addr)
7445 +{
7446 +       int ret;
7447 +
7448 +       if ((ret = mipv6_add_tnl_to_mn(coa, our_addr, home_addr)) <= 0) {
7449 +               if (ret != -ENOMEDIUM) {
7450 +                       DEBUG(DBG_ERROR, "unable to configure tunnel to MN!");
7451 +               }
7452 +               return -1;
7453 +       }
7454 +       if (mipv6_proxy_nd(home_addr, ifindex, 
7455 +                          flags & MIPV6_BU_F_LLADDR) != 0) {
7456 +               DEBUG(DBG_ERROR, "mipv6_proxy_nd failed!");
7457 +               mipv6_del_tnl_to_mn(coa, our_addr, home_addr);
7458 +               return -2;
7459 +       }
7460 +       return 0;
7461 +}
7462 +
7463 +static void ha_proxy_del(struct in6_addr *home_addr, struct mipv6_bce *entry)
7464 +{
7465 +       if (mipv6_proxy_nd_rem(&entry->home_addr, entry->ifindex,
7466 +                              entry->flags & MIPV6_BU_F_LLADDR) == 0) {
7467 +               DEBUG(DBG_INFO, "proxy_nd succ");
7468 +       } else {
7469 +               DEBUG(DBG_INFO, "proxy_nd fail");
7470 +       }
7471 +       mipv6_del_tnl_to_mn(&entry->coa, &entry->our_addr, home_addr);
7472 +}
7473 +
7474 +static void bc_home_add(int ifindex, 
7475 +                       struct in6_addr *daddr, struct in6_addr *haddr, 
7476 +                       struct in6_addr *coa, struct in6_addr *rep_coa,
7477 +                       __u32 lifetime, __u16 sequence, __u8 flags, 
7478 +                       __u8 *k_bu)
7479 +{
7480 +       struct inet6_ifaddr *ifp = NULL;
7481 +       __u8 ba_status = SUCCESS;
7482 +
7483 +       DEBUG_FUNC();
7484 +
7485 +       ifp = is_on_link_ipv6_address(haddr, daddr);
7486 +
7487 +       if (ifp == NULL) {
7488 +               ba_status = NOT_HOME_SUBNET;
7489 +       } else if (((ipv6_addr_type(haddr) & IPV6_ADDR_SITELOCAL) ||
7490 +                   (ipv6_addr_type(coa) & IPV6_ADDR_SITELOCAL))
7491 +                  && !mipv6_ha_tunnel_sitelocal) {
7492 +               /* Site-local home or care-of addresses are not 
7493 +                  accepted by default */
7494 +               ba_status = ADMINISTRATIVELY_PROHIBITED;
7495 +       } else {
7496 +               int ret;
7497 +
7498 +               ifindex = ifp->idev->dev->ifindex;
7499 +
7500 +               if ((ret = mipv6_dad_start(ifp, ifindex, daddr, 
7501 +                                          haddr, coa, rep_coa, lifetime,
7502 +                                          sequence, flags)) < 0) {
7503 +                       /* An error occurred */
7504 +                       ba_status = -ret;
7505 +               } else if (ret) {
7506 +                       /* DAD is needed to be performed. */
7507 +                       in6_ifa_put(ifp);
7508 +                       return;
7509 +               }
7510 +       }
7511 +
7512 +       mipv6_bu_finish(ifp, ifindex, ba_status, daddr, haddr, coa, 
7513 +                       rep_coa, lifetime, sequence, flags, k_bu);
7514 +       if (ifp)
7515 +               in6_ifa_put(ifp);
7516 +}
7517 +
7518 +static void bc_home_delete(struct in6_addr *daddr, struct in6_addr *haddr, 
7519 +                          struct in6_addr *coa, struct in6_addr *rep_coa, 
7520 +                          __u16 sequence, __u8 flags, __u8 *k_bu)
7521 +{
7522 +       __u8 status = SUCCESS;
7523 +       struct mipv6_bce bce;
7524 +
7525 +       /* Primary Care-of Address Deregistration */
7526 +       if (mipv6_bcache_get(haddr, daddr, &bce) < 0) {
7527 +               DEBUG(DBG_INFO, "entry is not in cache");
7528 +               status = NOT_HA_FOR_MN;
7529 +       } else {
7530 +               ha_proxy_del(&bce.home_addr, &bce);
7531 +               mipv6_bcache_delete(haddr, daddr, HOME_REGISTRATION);
7532 +       }
7533 +       mipv6_send_ba(daddr, haddr, coa, rep_coa, status, sequence, 0, k_bu);
7534 +}
7535 +
7536 +extern int mipv6_ra_rcv_ptr(struct sk_buff *skb, struct icmp6hdr *msg);
7537 +
7538 +
7539 +static int
7540 +mipv6_ha_tnl_xmit_stats_hook(struct ip6_tnl *t, struct sk_buff *skb)
7541 +{
7542 +       DEBUG_FUNC();
7543 +       if (is_mip6_tnl(t))
7544 +               MIPV6_INC_STATS(n_encapsulations);
7545 +       return IP6_TNL_ACCEPT;
7546 +}
7547 +
7548 +static struct ip6_tnl_hook_ops mipv6_ha_tnl_xmit_stats_ops = {
7549 +       {NULL, NULL},
7550 +       IP6_TNL_PRE_ENCAP,
7551 +       IP6_TNL_PRI_LAST,
7552 +       mipv6_ha_tnl_xmit_stats_hook
7553 +};
7554 +
7555 +static int
7556 +mipv6_ha_tnl_rcv_stats_hook(struct ip6_tnl *t, struct sk_buff *skb)
7557 +{
7558 +       DEBUG_FUNC();
7559 +       if (is_mip6_tnl(t))
7560 +               MIPV6_INC_STATS(n_decapsulations);
7561 +       return IP6_TNL_ACCEPT;
7562 +}
7563 +
7564 +static struct ip6_tnl_hook_ops mipv6_ha_tnl_rcv_stats_ops = {
7565 +       {NULL, NULL},
7566 +       IP6_TNL_PRE_DECAP,
7567 +       IP6_TNL_PRI_LAST,
7568 +       mipv6_ha_tnl_rcv_stats_hook
7569 +};
7570 +
7571 +static struct mip6_func old;
7572 +
7573 +int __init mipv6_ha_init(void)
7574 +{
7575 +       DEBUG_FUNC();
7576 +       
7577 +#ifdef CONFIG_SYSCTL
7578 +       if (!(mipv6_ha_sysctl_header = 
7579 +             register_sysctl_table(mipv6_ha_sysctl.mipv6_root_table, 0)))
7580 +               printk(KERN_ERR "Failed to register sysctl handlers!");
7581 +#endif
7582 +       memcpy(&old, &mip6_fn, sizeof(struct mip6_func));
7583 +       mip6_fn.bce_home_add = bc_home_add;
7584 +       mip6_fn.bce_home_del = bc_home_delete;
7585 +       mip6_fn.proxy_del = ha_proxy_del;
7586 +       mip6_fn.proxy_create = ha_proxy_create;
7587 +       /*  register packet interception hooks  */
7588 +       ip6ip6_tnl_register_hook(&mipv6_ha_tnl_xmit_stats_ops);
7589 +       ip6ip6_tnl_register_hook(&mipv6_ha_tnl_rcv_stats_ops);
7590 +       return 0;
7591 +}
7592 +
7593 +void __exit mipv6_ha_exit(void)
7594 +{
7595 +       DEBUG_FUNC();
7596 +
7597 +#ifdef CONFIG_SYSCTL
7598 +       unregister_sysctl_table(mipv6_ha_sysctl_header);
7599 +#endif
7600 +
7601 +       /*  remove packet interception hooks  */
7602 +       ip6ip6_tnl_unregister_hook(&mipv6_ha_tnl_rcv_stats_ops);
7603 +       ip6ip6_tnl_unregister_hook(&mipv6_ha_tnl_xmit_stats_ops);
7604 +
7605 +       mip6_fn.bce_home_add = old.bce_home_add;
7606 +       mip6_fn.bce_home_del = old.bce_home_del;
7607 +       mip6_fn.proxy_del = old.proxy_del;
7608 +       mip6_fn.proxy_create = old.proxy_create;
7609 +}
7610 --- /dev/null
7611 +++ linux-2.4.27/net/ipv6/mobile_ip6/ha.h
7612 @@ -0,0 +1,39 @@
7613 +/*
7614 + *      MIPL Mobile IPv6 Home Agent header file
7615 + *
7616 + *      $Id$
7617 + *
7618 + *      This program is free software; you can redistribute it and/or
7619 + *      modify it under the terms of the GNU General Public License
7620 + *      as published by the Free Software Foundation; either version
7621 + *      2 of the License, or (at your option) any later version.
7622 + */
7623 +
7624 +#ifndef _HA_H
7625 +#define _HA_H
7626 +
7627 +int mipv6_ha_init(void);
7628 +void mipv6_ha_exit(void);
7629 +
7630 +int mipv6_dad_start(struct inet6_ifaddr *ifp, int ifindex,
7631 +                   struct in6_addr *daddr, struct in6_addr *haddr,
7632 +                   struct in6_addr *coa, struct in6_addr *rep_coa,
7633 +                   __u32 ba_lifetime, __u16 sequence, __u8 flags);
7634 +
7635 +void mipv6_bu_finish(struct inet6_ifaddr *ifp, int ifindex, 
7636 +                    __u8 ba_status, struct in6_addr *daddr,
7637 +                    struct in6_addr *haddr, struct in6_addr *coa, 
7638 +                    struct in6_addr *rep_coa, __u32 ba_lifetime,
7639 +                    __u16 sequence, __u8 flags, __u8 *k_bu);
7640 +
7641 +
7642 +static __inline__ void mipv6_generate_ll_addr(struct in6_addr *ll_addr,
7643 +                                             struct in6_addr *addr)
7644 +{
7645 +       ll_addr->s6_addr32[0] = htonl(0xfe800000);
7646 +       ll_addr->s6_addr32[1] = 0;
7647 +       ll_addr->s6_addr32[2] = addr->s6_addr32[2];
7648 +       ll_addr->s6_addr32[3] = addr->s6_addr32[3];
7649 +}
7650 +
7651 +#endif
7652 --- /dev/null
7653 +++ linux-2.4.27/net/ipv6/mobile_ip6/halist.c
7654 @@ -0,0 +1,507 @@
7655 +/*
7656 + *      Home Agents List
7657 + *
7658 + *      Authors:
7659 + *      Antti Tuominen          <ajtuomin@tml.hut.fi>
7660 + *
7661 + *      $Id$
7662 + *
7663 + *      This program is free software; you can redistribute it and/or
7664 + *      modify it under the terms of the GNU General Public License
7665 + *      as published by the Free Software Foundation; either version
7666 + *      2 of the License, or (at your option) any later version.
7667 + *
7668 + */
7669 +
7670 +#define PREF_BASE 0xffff /* MAX value for u16 field in RA */
7671 +
7672 +#include <linux/autoconf.h>
7673 +#include <linux/sched.h>
7674 +#include <linux/timer.h>
7675 +#include <linux/proc_fs.h>
7676 +#include <linux/init.h>
7677 +#include <net/ipv6.h>
7678 +#include <net/addrconf.h>
7679 +
7680 +#include "hashlist.h"
7681 +#include "util.h"
7682 +#include "debug.h"
7683 +
7684 +struct mipv6_halist {
7685 +       struct hashlist *entries;
7686 +       struct timer_list expire_timer;
7687 +};
7688 +
7689 +static rwlock_t home_agents_lock = RW_LOCK_UNLOCKED;
7690 +
7691 +static struct mipv6_halist home_agents;
7692 +
7693 +struct mipv6_halist_entry {
7694 +       struct hashlist_entry e;
7695 +       int ifindex;                     /* Link identifier             */
7696 +       struct in6_addr link_local_addr; /* HA's link-local address     */
7697 +       struct in6_addr global_addr;     /* HA's Global address         */
7698 +       int plen;
7699 +       long preference;                 /* The preference for this HA  */
7700 +       unsigned long expire;            /* expiration time (jiffies)   */
7701 +};
7702 +
7703 +static inline void mipv6_ha_ac_add(struct in6_addr *ll_addr, int ifindex,
7704 +                                  struct in6_addr *glob_addr, int plen)
7705 +{
7706 +       struct net_device *dev;
7707 +
7708 +       if ((dev = __dev_get_by_index(ifindex)) && ipv6_chk_addr(ll_addr, dev)) {
7709 +               struct in6_addr addr;
7710 +               mipv6_ha_anycast(&addr, glob_addr, plen);
7711 +               ipv6_dev_ac_inc(dev, &addr);
7712 +       }
7713 +}
7714 +
7715 +static inline void mipv6_ha_ac_del(struct in6_addr *ll_addr, int ifindex,
7716 +                                  struct in6_addr *glob_addr, int plen)
7717 +{
7718 +       struct net_device *dev;
7719 +
7720 +       if ((dev = __dev_get_by_index(ifindex)) && ipv6_chk_addr(ll_addr, dev)) {
7721 +               struct in6_addr addr;
7722 +               mipv6_ha_anycast(&addr, glob_addr, plen);
7723 +               ipv6_dev_ac_dec(dev, &addr);
7724 +       }
7725 +}
7726 +
7727 +struct preflist_iterator_args {
7728 +       int count;
7729 +       int requested;
7730 +       int ifindex;
7731 +       struct in6_addr *list;
7732 +};
7733 +
7734 +static int preflist_iterator(void *data, void *args,
7735 +                            unsigned long *pref)
7736 +{
7737 +       struct preflist_iterator_args *state =
7738 +               (struct preflist_iterator_args *)args;
7739 +       struct mipv6_halist_entry *entry =
7740 +               (struct mipv6_halist_entry *)data;
7741 +       struct in6_addr *newaddr =
7742 +               (struct in6_addr *)state->list + state->count;
7743 +
7744 +       if (state->count >= state->requested)
7745 +               return ITERATOR_STOP;
7746 +
7747 +       if (time_after(jiffies, entry->expire)) {
7748 +               if (!ipv6_addr_any(&entry->link_local_addr)) {
7749 +                       mipv6_ha_ac_del(&entry->link_local_addr, 
7750 +                                       entry->ifindex, 
7751 +                                       &entry->global_addr, entry->plen);
7752 +               }
7753 +               DEBUG(DBG_INFO, "preflist_iterator: Deleting entry with address %x:%x:%x:%x:%x:%x:%x:%x to list", NIPV6ADDR(&entry->global_addr));
7754 +               return ITERATOR_DELETE_ENTRY;
7755 +       }
7756 +       if (state->ifindex != entry->ifindex)
7757 +               return ITERATOR_CONT;
7758 +
7759 +       ipv6_addr_copy(newaddr, &entry->global_addr);
7760 +       DEBUG(DBG_INFO, "preflist_iterator: adding new entry with address %x:%x:%x:%x:%x:%x:%x:%x to list", NIPV6ADDR(&entry->global_addr));
7761 +       state->count++;
7762 +
7763 +       return ITERATOR_CONT;
7764 +}
7765 +
7766 +static int gc_iterator(void *data, void *args,
7767 +                      unsigned long *pref)
7768 +{
7769 +       struct mipv6_halist_entry *entry =
7770 +               (struct mipv6_halist_entry *)data;
7771 +
7772 +       int *type = (int *)args;
7773 +
7774 +       if (*type == 1 || time_after(jiffies, entry->expire)) {
7775 +               if (!ipv6_addr_any(&entry->link_local_addr)) {
7776 +                       mipv6_ha_ac_del(&entry->link_local_addr, 
7777 +                                       entry->ifindex, 
7778 +                                       &entry->global_addr, entry->plen);
7779 +               }
7780 +               return ITERATOR_DELETE_ENTRY;
7781 +       }
7782 +
7783 +       return ITERATOR_CONT;
7784 +}
7785 +
7786 +static int mipv6_halist_gc(int type)
7787 +{
7788 +       DEBUG_FUNC();
7789 +       hashlist_iterate(home_agents.entries, &type, gc_iterator);
7790 +       return 0;
7791 +}
7792 +
7793 +static void mipv6_halist_expire(unsigned long dummy)
7794 +{
7795 +       DEBUG_FUNC();
7796 +
7797 +       write_lock(&home_agents_lock);
7798 +       mipv6_halist_gc(0);
7799 +       write_unlock(&home_agents_lock);
7800 +}
7801 +
7802 +
7803 +static struct mipv6_halist_entry *mipv6_halist_new_entry(void)
7804 +{
7805 +       struct mipv6_halist_entry *entry;
7806 +
7807 +       DEBUG_FUNC();
7808 +
7809 +       entry = hashlist_alloc(home_agents.entries, SLAB_ATOMIC);
7810 +
7811 +       return entry;
7812 +}
7813 +
7814 +
7815 +
7816 +/**
7817 + * mipv6_halist_add - Add new home agent to the Home Agents List
7818 + * @ifindex: interface identifier
7819 + * @glob_addr: home agent's global address
7820 + * @ll_addr: home agent's link-local address
7821 + * @pref: relative preference for this home agent
7822 + * @lifetime: lifetime for the entry
7823 + *
7824 + * Adds new home agent to the Home Agents List.  The list is interface
7825 + * specific and @ifindex tells through which interface the home agent
7826 + * was heard.  Returns zero on success and negative on failure.
7827 + **/
7828 +
7829 +int mipv6_halist_add(int ifindex, struct in6_addr *glob_addr, int plen,
7830 +                    struct in6_addr *ll_addr, unsigned int pref, __u32 lifetime)
7831 +{
7832 +       int update = 0, ret = 0;
7833 +       unsigned int mpref;
7834 +       struct mipv6_halist_entry *entry = NULL;
7835 +
7836 +       DEBUG_FUNC();
7837 +
7838 +       write_lock(&home_agents_lock);
7839 +
7840 +       if (glob_addr == NULL || lifetime <= 0) {
7841 +               DEBUG(DBG_WARNING, "invalid arguments");
7842 +               ret = -EINVAL;
7843 +               goto out;
7844 +       }
7845 +       mpref = PREF_BASE - pref;
7846 +       if ((entry = (struct mipv6_halist_entry *)
7847 +            hashlist_get(home_agents.entries, glob_addr)) != NULL) {
7848 +               if (entry->ifindex == ifindex) {
7849 +                       DEBUG(DBG_DATADUMP, "updating old entry with address %x:%x:%x:%x:%x:%x:%x:%x", NIPV6ADDR(glob_addr));
7850 +                       update = 1;
7851 +               } else {
7852 +                       DEBUG(DBG_INFO, "halist_add : adding new entry with address %x:%x:%x:%x:%x:%x:%x:%x", NIPV6ADDR(glob_addr));
7853 +                       update = 0;
7854 +               }
7855 +       }
7856 +       if (update) {
7857 +               entry->expire = jiffies + lifetime * HZ;
7858 +               if (entry->preference != mpref) {
7859 +                       entry->preference = mpref;
7860 +                       ret = hashlist_reposition(home_agents.entries, 
7861 +                                                 (void *)entry, mpref);
7862 +               }
7863 +       } else {
7864 +               entry = mipv6_halist_new_entry();
7865 +               if (entry == NULL) {
7866 +                       DEBUG(DBG_INFO, "list full");
7867 +                       ret = -ENOMEM;
7868 +                       goto out;
7869 +               }
7870 +               entry->ifindex = ifindex;
7871 +               if (ll_addr) {
7872 +                       ipv6_addr_copy(&entry->link_local_addr, ll_addr);
7873 +                       mipv6_ha_ac_add(ll_addr, ifindex, glob_addr, plen);
7874 +               } else
7875 +                       ipv6_addr_set(&entry->link_local_addr, 0, 0, 0, 0);
7876 +
7877 +               ipv6_addr_copy(&entry->global_addr, glob_addr);
7878 +               entry->plen = plen;
7879 +               entry->preference = mpref;
7880 +               entry->expire = jiffies + lifetime * HZ;
7881 +               ret = hashlist_add(home_agents.entries, glob_addr, mpref, 
7882 +                                  entry);
7883 +       }
7884 +out:
7885 +       write_unlock(&home_agents_lock);
7886 +       return ret;
7887 +}
7888 +
7889 +/**
7890 + * mipv6_halist_delete - delete home agent from Home Agents List
7891 + * @glob_addr: home agent's global address
7892 + *
7893 + * Deletes entry for home agent @glob_addr from the Home Agent List.
7894 + **/
7895 +int mipv6_halist_delete(struct in6_addr *glob_addr)
7896 +{
7897 +       struct hashlist_entry *e;
7898 +       struct mipv6_halist_entry *entry;
7899 +       DEBUG_FUNC();
7900 +
7901 +       if (glob_addr == NULL) {
7902 +               DEBUG(DBG_WARNING, "invalid glob addr");
7903 +               return -EINVAL;
7904 +       }
7905 +       write_lock(&home_agents_lock);
7906 +       if ((e = hashlist_get(home_agents.entries, glob_addr)) == NULL) {
7907 +               write_unlock(&home_agents_lock);
7908 +               return -ENOENT;
7909 +       }
7910 +       hashlist_delete(home_agents.entries, e);
7911 +       entry = (struct mipv6_halist_entry *)e;
7912 +       if (!ipv6_addr_any(&entry->link_local_addr)) {
7913 +               mipv6_ha_ac_del(&entry->link_local_addr, entry->ifindex, 
7914 +                               &entry->global_addr, entry->plen);
7915 +       }
7916 +       hashlist_free(home_agents.entries, e);
7917 +       write_unlock(&home_agents_lock);
7918 +       return 0;
7919 +}
7920 +
7921 +/**
7922 + * mipv6_ha_get_pref_list - Get list of preferred home agents
7923 + * @ifindex: interface identifier
7924 + * @addrs: pointer to a buffer to store the list
7925 + * @max: maximum number of home agents to return
7926 + *
7927 + * Creates a list of @max preferred (or all known if less than @max)
7928 + * home agents.  Home Agents List is interface specific so you must
7929 + * supply @ifindex.  Stores list in addrs and returns number of home
7930 + * agents stored.  On failure, returns a negative value.
7931 + **/
7932 +int mipv6_ha_get_pref_list(int ifindex, struct in6_addr **addrs, int max)
7933 +{
7934 +       struct preflist_iterator_args args;
7935 +
7936 +       DEBUG_FUNC();
7937 +       if (max <= 0) {
7938 +               *addrs = NULL;
7939 +               return 0;
7940 +       }
7941 +
7942 +       args.count = 0;
7943 +       args.requested = max;
7944 +       args.ifindex = ifindex;
7945 +       args.list = kmalloc(max * sizeof(struct in6_addr), GFP_ATOMIC);
7946 +
7947 +       if (args.list == NULL) return -ENOMEM;
7948 +
7949 +       read_lock(&home_agents_lock);
7950 +       hashlist_iterate(home_agents.entries, &args, preflist_iterator);
7951 +       read_unlock(&home_agents_lock);
7952 +
7953 +       if (args.count >= 0) {
7954 +               *addrs = args.list;
7955 +       } else {
7956 +               kfree(args.list);
7957 +               *addrs = NULL;
7958 +       }
7959 +
7960 +       return args.count;
7961 +}
7962 +
7963 +struct getaddr_iterator_args {
7964 +       struct net_device *dev;
7965 +       struct in6_addr *addr;
7966 +};
7967 +
7968 +static int getaddr_iterator(void *data, void *args,
7969 +            unsigned long *pref)
7970 +{
7971 +       struct mipv6_halist_entry *entry =
7972 +               (struct mipv6_halist_entry *)data;
7973 +       struct getaddr_iterator_args *state =
7974 +               (struct getaddr_iterator_args *)args;
7975 +
7976 +       if (entry->ifindex != state->dev->ifindex)
7977 +               return ITERATOR_CONT;
7978 +
7979 +       if (ipv6_chk_addr(&entry->global_addr, state->dev)) {
7980 +               ipv6_addr_copy(state->addr, &entry->global_addr);
7981 +               return ITERATOR_STOP;
7982 +       }
7983 +       return ITERATOR_CONT;
7984 +}
7985 +
7986 +/*
7987 + * Get Home Agent Address for given interface.  If node is not serving
7988 + * as a HA for this interface returns negative error value.
7989 + */
7990 +int mipv6_ha_get_addr(int ifindex, struct in6_addr *addr)
7991 +{
7992 +       struct getaddr_iterator_args args;
7993 +       struct net_device *dev;
7994 +
7995 +       if (ifindex <= 0)
7996 +               return -EINVAL;
7997 +
7998 +       if ((dev = dev_get_by_index(ifindex)) == NULL)
7999 +               return -ENODEV;
8000 +
8001 +       memset(addr, 0, sizeof(struct in6_addr));
8002 +       args.dev = dev;
8003 +       args.addr = addr;
8004 +       read_lock(&home_agents_lock);
8005 +       hashlist_iterate(home_agents.entries, &args, getaddr_iterator);
8006 +       read_unlock(&home_agents_lock);
8007 +       dev_put(dev);
8008 +
8009 +       if (ipv6_addr_any(addr))
8010 +               return -ENOENT;
8011 +       
8012 +       return 0;
8013 +}
8014 +
8015 +#define HALIST_INFO_LEN 81
8016 +
8017 +struct procinfo_iterator_args {
8018 +       char *buffer;
8019 +       int offset;
8020 +       int length;
8021 +       int skip;
8022 +       int len;
8023 +};
8024 +
8025 +static int procinfo_iterator(void *data, void *args,
8026 +                            unsigned long *pref)
8027 +{
8028 +       struct procinfo_iterator_args *arg =
8029 +               (struct procinfo_iterator_args *)args;
8030 +       struct mipv6_halist_entry *entry =
8031 +               (struct mipv6_halist_entry *)data;
8032 +       unsigned long int expire;
8033 +
8034 +       DEBUG_FUNC();
8035 +
8036 +       if (entry == NULL) return ITERATOR_ERR;
8037 +
8038 +       if (time_after(jiffies, entry->expire)) {
8039 +               if (!ipv6_addr_any(&entry->link_local_addr)) {
8040 +                       mipv6_ha_ac_del(&entry->link_local_addr, 
8041 +                                       entry->ifindex, 
8042 +                                       &entry->global_addr, entry->plen);
8043 +               }
8044 +               return ITERATOR_DELETE_ENTRY;
8045 +       }
8046 +       if (arg->skip < arg->offset / HALIST_INFO_LEN) {
8047 +               arg->skip++;
8048 +               return ITERATOR_CONT;
8049 +       }
8050 +
8051 +       if (arg->len >= arg->length)
8052 +               return ITERATOR_CONT;
8053 +
8054 +       expire = (entry->expire - jiffies) / HZ;
8055 +
8056 +       arg->len += sprintf(arg->buffer + arg->len, 
8057 +                           "%02d %08x%08x%08x%08x %08x%08x%08x%08x %05ld %05ld\n",
8058 +                           entry->ifindex,
8059 +                           ntohl(entry->global_addr.s6_addr32[0]),
8060 +                           ntohl(entry->global_addr.s6_addr32[1]),
8061 +                           ntohl(entry->global_addr.s6_addr32[2]),
8062 +                           ntohl(entry->global_addr.s6_addr32[3]),
8063 +                           ntohl(entry->link_local_addr.s6_addr32[0]),
8064 +                           ntohl(entry->link_local_addr.s6_addr32[1]),
8065 +                           ntohl(entry->link_local_addr.s6_addr32[2]),
8066 +                           ntohl(entry->link_local_addr.s6_addr32[3]),
8067 +                           -(entry->preference - PREF_BASE), expire);
8068 +
8069 +       return ITERATOR_CONT;
8070 +}
8071 +
8072 +static int halist_proc_info(char *buffer, char **start, off_t offset,
8073 +                            int length)
8074 +{
8075 +       struct procinfo_iterator_args args;
8076 +
8077 +       DEBUG_FUNC();
8078 +
8079 +       args.buffer = buffer;
8080 +       args.offset = offset;
8081 +       args.length = length;
8082 +       args.skip = 0;
8083 +       args.len = 0;
8084 +
8085 +       read_lock_bh(&home_agents_lock);
8086 +       hashlist_iterate(home_agents.entries, &args, procinfo_iterator);
8087 +       read_unlock_bh(&home_agents_lock);
8088 +
8089 +       *start = buffer;
8090 +       if (offset)
8091 +               *start += offset % HALIST_INFO_LEN;
8092 +
8093 +       args.len -= offset % HALIST_INFO_LEN;
8094 +
8095 +       if (args.len > length)
8096 +               args.len = length;
8097 +       if (args.len < 0)
8098 +               args.len = 0;
8099 +       
8100 +       return args.len;
8101 +}
8102 +
8103 +static int halist_compare(void *data, void *hashkey)
8104 +{
8105 +       struct mipv6_halist_entry *e = (struct mipv6_halist_entry *)data;
8106 +       struct in6_addr *key = (struct in6_addr *)hashkey;
8107 +
8108 +       return ipv6_addr_cmp(&e->global_addr, key);
8109 +}
8110 +
8111 +static __u32 halist_hash(void *hashkey)
8112 +{
8113 +       struct in6_addr *key = (struct in6_addr *)hashkey;
8114 +       __u32 hash;
8115 +
8116 +       hash = key->s6_addr32[0] ^
8117 +                key->s6_addr32[1] ^
8118 +                key->s6_addr32[2] ^
8119 +                key->s6_addr32[3];
8120 +
8121 +       return hash;
8122 +}
8123 +
8124 +int __init mipv6_halist_init(__u32 size)
8125 +{
8126 +       DEBUG_FUNC();
8127 +
8128 +       if (size <= 0) {
8129 +               DEBUG(DBG_ERROR, "size must be at least 1");
8130 +               return -EINVAL;
8131 +       }
8132 +       init_timer(&home_agents.expire_timer);
8133 +       home_agents.expire_timer.data = 0;
8134 +       home_agents.expire_timer.function = mipv6_halist_expire;
8135 +       home_agents_lock = RW_LOCK_UNLOCKED;
8136 +
8137 +       home_agents.entries = hashlist_create(16, size, sizeof(struct mipv6_halist_entry),
8138 +                                              "mip6_halist", NULL, NULL,
8139 +                                              halist_compare, halist_hash);
8140 +
8141 +       if (home_agents.entries == NULL) {
8142 +               DEBUG(DBG_ERROR, "Failed to initialize hashlist");
8143 +               return -ENOMEM;
8144 +       }
8145 +
8146 +       proc_net_create("mip6_home_agents", 0, halist_proc_info);
8147 +       DEBUG(DBG_INFO, "Home Agents List initialized");
8148 +       return 0;
8149 +}
8150 +
8151 +void __exit mipv6_halist_exit(void)
8152 +{
8153 +       DEBUG_FUNC();
8154 +       proc_net_remove("mip6_home_agents");
8155 +       write_lock_bh(&home_agents_lock);
8156 +       DEBUG(DBG_INFO, "Stopping the halist timer");
8157 +       del_timer(&home_agents.expire_timer);
8158 +       mipv6_halist_gc(1);
8159 +       write_unlock_bh(&home_agents_lock);
8160 +       hashlist_destroy(home_agents.entries);
8161 +}
8162 --- /dev/null
8163 +++ linux-2.4.27/net/ipv6/mobile_ip6/halist.h
8164 @@ -0,0 +1,28 @@
8165 +/*
8166 + *      MIPL Mobile IPv6 Home Agents List header file      
8167 + *
8168 + *      $Id$
8169 + *
8170 + *      This program is free software; you can redistribute it and/or
8171 + *      modify it under the terms of the GNU General Public License
8172 + *      as published by the Free Software Foundation; either version
8173 + *      2 of the License, or (at your option) any later version.
8174 + */
8175 +
8176 +#ifndef _HALIST_H
8177 +#define _HALIST_H
8178 +
8179 +int mipv6_halist_init(__u32 size);
8180 +
8181 +void mipv6_halist_exit(void);
8182 +
8183 +int mipv6_halist_add(int ifindex, struct in6_addr *glob_addr, int plen,
8184 +                    struct in6_addr *ll_addr, unsigned int pref, __u32 lifetime);
8185 +
8186 +int mipv6_halist_delete(struct in6_addr *glob_addr);
8187 +
8188 +int mipv6_ha_get_pref_list(int ifindex, struct in6_addr **addrs, int max);
8189 +
8190 +int mipv6_ha_get_addr(int ifindex, struct in6_addr *addr);
8191 +
8192 +#endif /* _HALIST_H */
8193 --- /dev/null
8194 +++ linux-2.4.27/net/ipv6/mobile_ip6/hashlist.c
8195 @@ -0,0 +1,351 @@
8196 +/*
8197 + *     Generic hashtable with chaining.  Supports secodary sort order
8198 + *     with doubly linked-list.
8199 + *
8200 + *     Authors:
8201 + *     Sami Kivisaari          <skivisaa@cc.hut.fi>
8202 + *     Antti Tuominen          <ajtuomin@tml.hut.fi>
8203 + *
8204 + *     $Id: s.hashlist.c 1.21 02/10/07 19:31:52+03:00 antti@traci.mipl.mediapoli.com $
8205 + *
8206 + *     This program is free software; you can redistribute it and/or
8207 + *     modify it under the terms of the GNU General Public License as
8208 + *     published by the Free Software Foundation; either version 2 of
8209 + *     the License, or (at your option) any later version.
8210 + */
8211 +
8212 +#include <linux/slab.h>
8213 +#include "hashlist.h"
8214 +#include "debug.h"
8215 +
8216 +struct hashlist {
8217 +       int count;              /* entry count  */
8218 +       int maxcount;           /* max entries  */
8219 +       __u32 bucketnum;        /* hash buckets */
8220 +
8221 +       kmem_cache_t *kmem;
8222 +
8223 +       struct list_head *hashtable;
8224 +       struct list_head sortedlist;
8225 +
8226 +       int (*compare)(void *data, void *hashkey);
8227 +       __u32 (*hash_function)(void *hashkey);
8228 +};
8229 +
8230 +/**
8231 + * hashlist_create - Create new hashlist
8232 + * @bucketnum: number of hash buckets
8233 + * @maxentries: maximum number of entries (0 = no limit)
8234 + * @size: entry size in bytes
8235 + * @name: name for kmem_cache_t
8236 + * @ctor: kmem_cache_t constructor
8237 + * @dtor: kmem_cache_t destructor
8238 + * @compare: compare function for key
8239 + * @hash_function: hash function
8240 + *
8241 + * Creates a hashlist structure with @max_entries entries of @size
8242 + * bytes.  User must supply @hash_function and @compare function for
8243 + * the hashlist.  User can also supply @ctor and @dtor for kmem_cache.
8244 + **/
8245 +struct hashlist *hashlist_create(int bucketnum, int max_entries, size_t size,
8246 +                                char *name,
8247 +                                void (*ctor)(void *, kmem_cache_t *, unsigned long),
8248 +                                void (*dtor)(void *, kmem_cache_t *, unsigned long),
8249 +                                int (*compare)(void *data, void *hashkey),
8250 +                                __u32 (*hash_function)(void *hashkey))
8251 +{
8252 +       int i;
8253 +       struct hashlist *hl;
8254 +
8255 +       if (!compare || !hash_function)
8256 +               goto hlfailed;
8257 +
8258 +       hl = kmalloc(sizeof(struct hashlist), GFP_ATOMIC);
8259 +       if (!hl) goto hlfailed;
8260 +
8261 +       hl->kmem = kmem_cache_create(name, size, 0, 0, ctor, dtor);
8262 +       if (!hl->kmem) goto poolfailed;
8263 +
8264 +       hl->hashtable = kmalloc(
8265 +               sizeof(struct list_head) * bucketnum, GFP_ATOMIC);
8266 +       if (!hl->hashtable) goto hashfailed;
8267 +
8268 +       for (i = 0; i < bucketnum; i++)
8269 +               INIT_LIST_HEAD(&hl->hashtable[i]);
8270 +
8271 +       INIT_LIST_HEAD(&hl->sortedlist);
8272 +
8273 +       hl->maxcount = max_entries;
8274 +       hl->count = 0;
8275 +       hl->bucketnum = bucketnum;
8276 +       hl->compare = compare;
8277 +       hl->hash_function = hash_function;
8278 +
8279 +       return hl;
8280 +
8281 +hashfailed:
8282 +       kmem_cache_destroy(hl->kmem);
8283 +       hl->kmem = NULL;
8284 +
8285 +poolfailed:
8286 +       kfree(hl);
8287 +
8288 +hlfailed:
8289 +       DEBUG(DBG_ERROR, "could not create hashlist");
8290 +
8291 +       return NULL;    
8292 +}
8293 +
8294 +/**
8295 + * hashlist_destroy - Destroy hashlist
8296 + * @hashlist: hashlist to destroy
8297 + *
8298 + * Frees all memory allocated for a hashlist.
8299 + **/
8300 +void hashlist_destroy(struct hashlist *hashlist)
8301 +{
8302 +       DEBUG_FUNC();
8303 +
8304 +       if (hashlist == NULL) return;
8305 +
8306 +       if (hashlist->hashtable) {
8307 +               kfree(hashlist->hashtable);
8308 +               hashlist->hashtable = NULL;
8309 +       }
8310 +
8311 +       if (hashlist->kmem) {
8312 +               kmem_cache_destroy(hashlist->kmem);
8313 +               hashlist->kmem = NULL;
8314 +       }
8315 +
8316 +       kfree(hashlist);
8317 +
8318 +       return;
8319 +}
8320 +
8321 +/*
8322 + * Insert a chain of entries to hashlist into correct order.  The
8323 + * entries are assumed to have valid hashkeys.  We use time_after_eq
8324 + * for comparing, since it handles wrap-around correctly, and the
8325 + * sortkey is usually jiffies.
8326 + */
8327 +static void sorted_insert(struct list_head *lh, struct hashlist_entry *he)
8328 +{
8329 +       struct list_head *p;
8330 +       struct hashlist_entry *hlp = NULL;
8331 +       unsigned long sortkey = he->sortkey;
8332 +
8333 +       if (list_empty(lh)) {
8334 +               list_add(&he->sorted, lh);
8335 +               return;
8336 +       }
8337 +       
8338 +       list_for_each(p, lh) {
8339 +               hlp = list_entry(p, typeof(*hlp), sorted);
8340 +               if (time_after_eq(hlp->sortkey, sortkey)) {
8341 +                       list_add(&he->sorted, hlp->sorted.prev);
8342 +                       return;
8343 +               }
8344 +       }
8345 +       list_add(&he->sorted, &hlp->sorted);
8346 +}
8347 +
8348 +/**
8349 + * hashlist_iterate - Apply function for all elements in a hash list
8350 + * @hashlist: pointer to hashlist
8351 + * @args: data to pass to the function
8352 + * @func: pointer to a function
8353 + *
8354 + * Apply arbitrary function @func to all elements in a hash list.
8355 + * @func must be a pointer to a function with the following prototype:
8356 + * int func(void *entry, void *arg, struct in6_addr *hashkey, unsigned
8357 + * long *sortkey).  Function must return %ITERATOR_STOP,
8358 + * %ITERATOR_CONT or %ITERATOR_DELETE_ENTRY.  %ITERATOR_STOP stops
8359 + * iterator and returns last return value from the function.
8360 + * %ITERATOR_CONT continues with iteration.  %ITERATOR_DELETE_ENTRY
8361 + * deletes current entry from the hashlist.  If function changes
8362 + * hashlist element's sortkey, iterator automatically schedules
8363 + * element to be reinserted after all elements have been processed.
8364 + */
8365 +int hashlist_iterate(
8366 +       struct hashlist *hashlist, void *args,
8367 +       hashlist_iterator_t func)
8368 +{
8369 +       int res = ITERATOR_CONT;
8370 +       unsigned long skey;
8371 +       struct list_head *p, *n, repos;
8372 +       struct hashlist_entry *he;
8373 +
8374 +       DEBUG_FUNC();
8375 +       INIT_LIST_HEAD(&repos);
8376 +
8377 +       list_for_each_safe(p, n, &hashlist->sortedlist) {
8378 +               he = list_entry(p, typeof(*he), sorted);
8379 +               if (res == ITERATOR_STOP)
8380 +                       break;
8381 +               skey = he->sortkey;
8382 +               res = func(he, args, &he->sortkey);
8383 +               if (res == ITERATOR_DELETE_ENTRY) {
8384 +                       hashlist_delete(hashlist, he);
8385 +                       hashlist_free(hashlist, he);
8386 +               } else if (skey != he->sortkey) {
8387 +                       /* iterator changed the sortkey, schedule for
8388 +                        * repositioning */
8389 +                       list_move(&he->sorted, &repos);
8390 +               }
8391 +       }
8392 +       list_for_each_safe(p, n, &repos) {      
8393 +               he = list_entry(p, typeof(*he), sorted);
8394 +               sorted_insert(&hashlist->sortedlist, he);
8395 +       }
8396 +       return res;
8397 +}
8398 +
8399 +/**
8400 + * hashlist_alloc - Allocate memory for a hashlist entry
8401 + * @hashlist: hashlist for allocated entry
8402 + * @size: size of entry in bytes
8403 + *
8404 + * Allocates @size bytes memory from @hashlist->kmem.
8405 + **/
8406 +void *hashlist_alloc(struct hashlist *hashlist, int type)
8407 +{
8408 +       if (hashlist == NULL) return NULL;
8409 +       return kmem_cache_alloc(hashlist->kmem, type);
8410 +}
8411 +
8412 +/**
8413 + * hashlist_free - Free hashlist entry
8414 + * @hashlist: hashlist where @he is
8415 + * @he: entry to free
8416 + *
8417 + * Frees an allocated hashlist entry.
8418 + **/
8419 +void hashlist_free(struct hashlist *hashlist, struct hashlist_entry *he)
8420 +{
8421 +       kmem_cache_free(hashlist->kmem, he);
8422 +}
8423 +
8424 +/**
8425 + * hashlist_add - Add element to hashlist
8426 + * @hashlist: pointer to hashlist
8427 + * @hashkey: hashkey for the element
8428 + * @sortkey: key for sorting
8429 + * @data: element data
8430 + *
8431 + * Add element to hashlist.  Hashlist is also sorted in a linked list
8432 + * by @sortkey.
8433 + */
8434 +int hashlist_add(struct hashlist *hashlist, void *hashkey,
8435 +                unsigned long sortkey, void *entry)
8436 +{
8437 +       struct hashlist_entry *he = (struct hashlist_entry *)entry;
8438 +       unsigned int hash;
8439 +
8440 +       if (hashlist->count >= hashlist->maxcount)
8441 +               return -1;
8442 +
8443 +       hashlist->count++;
8444 +
8445 +       /*  link the entry to sorted order  */ 
8446 +       he->sortkey = sortkey;
8447 +       sorted_insert(&hashlist->sortedlist, he);
8448 +
8449 +       /*  hash the entry  */
8450 +       hash = hashlist->hash_function(hashkey) % hashlist->bucketnum;
8451 +       list_add(&he->hashlist, &hashlist->hashtable[hash]);
8452 +
8453 +       return 0;
8454 +}
8455 +
8456 +/**
8457 + * hashlist_get_ex - Get element from hashlist
8458 + * @hashlist: hashlist
8459 + * @hashkey: hashkey of the desired entry
8460 + *
8461 + * Lookup entry with @hashkey from the hash table using @compare
8462 + * function for entry comparison.  Returns entry on success, otherwise
8463 + * %NULL.
8464 + **/
8465 +struct hashlist_entry *hashlist_get_ex(
8466 +       struct hashlist *hashlist, void *hashkey,
8467 +       int (*compare)(void *data, void *hashkey))
8468 +{
8469 +       struct list_head *p, *bkt;
8470 +       __u32 hash;
8471 +
8472 +       hash = hashlist->hash_function(hashkey) % hashlist->bucketnum;
8473 +       bkt = &hashlist->hashtable[hash];
8474 +
8475 +       /*  scan the entries within the same hashbucket  */
8476 +       list_for_each(p, bkt) {
8477 +               struct hashlist_entry *he = list_entry(p, typeof(*he), 
8478 +                                                      hashlist);
8479 +               if (compare(he, hashkey) == 0)
8480 +                       return he;
8481 +       }
8482 +
8483 +       return NULL;
8484 +}
8485 +
8486 +/**
8487 + * hashlist_get - Get element from hashlist
8488 + * @hashlist: hashlist
8489 + * @hashkey: hashkey of the desired entry
8490 + *
8491 + * Lookup entry with @hashkey from the hash table.  Returns entry on
8492 + * success, otherwise %NULL.
8493 + **/
8494 +struct hashlist_entry *hashlist_get(struct hashlist *hashlist, void *hashkey)
8495 +{
8496 +       return hashlist_get_ex(hashlist, hashkey, hashlist->compare);
8497 +}
8498 +
8499 +/**
8500 + * hashlist_reposition - set entry to new position in the list
8501 + * @hashlist: hashlist
8502 + * @he: entry to reposition
8503 + * @sortkey: new sortkey of the entry
8504 + *
8505 + * If secondary order sortkey changes, entry must be repositioned in
8506 + * the sorted list.
8507 + **/
8508 +int hashlist_reposition(struct hashlist *hashlist, struct hashlist_entry *he,
8509 +                       unsigned long sortkey)
8510 +{
8511 +       list_del(&he->sorted);
8512 +       he->sortkey = sortkey;
8513 +       sorted_insert(&hashlist->sortedlist, he);
8514 +
8515 +       return 0;
8516 +}
8517 +
8518 +/**
8519 + * hashlist_delete - Delete entry from hashlist
8520 + * @hashlist: hashlist where entry is
8521 + * @he: entry to delete
8522 + *
8523 + * Deletes an entry from the hashlist and sorted list.
8524 + **/
8525 +void hashlist_delete(struct hashlist *hashlist,
8526 +                    struct hashlist_entry *he)
8527 +{
8528 +       list_del_init(&he->hashlist);
8529 +       list_del_init(&he->sorted);
8530 +
8531 +       hashlist->count--;
8532 +}
8533 +
8534 +/**
8535 + * hashlist_get_first - Get first item from sorted list
8536 + * @hashlist: pointer to hashlist
8537 + *
8538 + * Returns first item in the secondary sort order.
8539 + **/
8540 +void * hashlist_get_first(struct hashlist *hashlist)
8541 +{
8542 +       if (list_empty(&hashlist->sortedlist))
8543 +               return NULL;
8544 +       
8545 +       return list_entry(hashlist->sortedlist.next, struct hashlist_entry, sorted);
8546 +}
8547 --- /dev/null
8548 +++ linux-2.4.27/net/ipv6/mobile_ip6/hashlist.h
8549 @@ -0,0 +1,63 @@
8550 +/*
8551 + *     MIPL Mobile IPv6 Hashlist header file
8552 + *
8553 + *     $Id$
8554 + *
8555 + *     This program is free software; you can redistribute it and/or
8556 + *      modify it under the terms of the GNU General Public License
8557 + *      as published by the Free Software Foundation; either version
8558 + *      2 of the License, or (at your option) any later version.
8559 + */
8560 +
8561 +#ifndef _HASHLIST_H
8562 +#define _HASHLIST_H
8563 +
8564 +#define ITERATOR_ERR -1
8565 +#define ITERATOR_CONT 0
8566 +#define ITERATOR_STOP 1
8567 +#define ITERATOR_DELETE_ENTRY 2
8568 +
8569 +struct kmem_cache_t;
8570 +
8571 +struct hashlist_entry {
8572 +       unsigned long sortkey;
8573 +       struct list_head sorted;
8574 +       struct list_head hashlist;
8575 +};
8576 +
8577 +struct hashlist * hashlist_create(
8578 +       int bucketnum, int max_entries, size_t size, char *name,
8579 +       void (*ctor)(void *, kmem_cache_t *, unsigned long),
8580 +       void (*dtor)(void *, kmem_cache_t *, unsigned long),
8581 +       int (*compare)(void *data, void *hashkey),
8582 +       __u32 (*hash_function)(void *hashkey));
8583 +
8584 +void hashlist_destroy(struct hashlist *hashlist);
8585 +
8586 +void *hashlist_alloc(struct hashlist *hashlist, int type);
8587 +
8588 +void hashlist_free(struct hashlist *hashlist, struct hashlist_entry *he);
8589 +
8590 +struct hashlist_entry *hashlist_get(struct hashlist *hashlist, void *hashkey);
8591 +
8592 +struct hashlist_entry *hashlist_get_ex(
8593 +       struct hashlist *hashlist, void *hashkey,
8594 +       int (*compare)(void *data, void *hashkey));
8595 +
8596 +int hashlist_add(struct hashlist *hashlist, void *hashkey,
8597 +                unsigned long sortkey, void *data);
8598 +
8599 +void hashlist_delete(struct hashlist *hashlist, struct hashlist_entry *he);
8600 +
8601 +/* iterator function */
8602 +typedef int (*hashlist_iterator_t)(void *, void *, unsigned long *);
8603 +
8604 +int hashlist_iterate(struct hashlist *hashlist, void *args,
8605 +                    hashlist_iterator_t func);
8606 +
8607 +void * hashlist_get_first(struct hashlist *hashlist);
8608 +
8609 +int hashlist_reposition(struct hashlist *hashlist, struct hashlist_entry *he,
8610 +                       unsigned long sortkey);
8611 +
8612 +#endif
8613 --- /dev/null
8614 +++ linux-2.4.27/net/ipv6/mobile_ip6/hmac.c
8615 @@ -0,0 +1,658 @@
8616 +/*     Authentication algorithms       
8617 + *     
8618 + *      Authors: 
8619 + *       Alexis Olivereau              <Alexis.Olivereau@crm.mot.com>
8620 + * 
8621 + *      $Id$
8622 + *
8623 + *      This program is free software; you can redistribute it and/or
8624 + *      modify it under the terms of the GNU General Public License
8625 + *      as published by the Free Software Foundation; either version
8626 + *      2 of the License, or (at your option) any later version.
8627 + *
8628 + *      Changes: 
8629 + *      Henrik Petander     :     Cleaned up unused parts
8630 + *
8631 + */
8632 +
8633 +#include <linux/sched.h>
8634 +#include <linux/tty.h>
8635 +#include <linux/types.h>
8636 +#include <linux/slab.h>
8637 +#include <linux/in6.h>
8638 +
8639 +#include "hmac.h"
8640 +#define LROLL(x, s) (((x) << (s)) | ((x) >> (32 - (s))))
8641 +
8642 +/* MD5 */
8643 +#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
8644 +#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
8645 +#define H(x, y, z) ((x) ^ (y) ^ (z))
8646 +#define I(x, y, z) ((y) ^ ((x) | ~(z)))
8647 +
8648 +#define FF(a, b, c, d, m, s, t) { \
8649 + (a) += F ((b), (c), (d)) + (m) + (t); \
8650 + (a) = LROLL((a), (s)); \
8651 + (a) += (b); \
8652 + }
8653 +#define GG(a, b, c, d, m, s, t) { \
8654 + (a) += G ((b), (c), (d)) + (m) + (t); \
8655 + (a) = LROLL((a), (s)); \
8656 + (a) += (b); \
8657 + }
8658 +#define HH(a, b, c, d, m, s, t) { \
8659 + (a) += H ((b), (c), (d)) + (m) + (t); \
8660 + (a) = LROLL((a), (s)); \
8661 + (a) += (b); \
8662 + }
8663 +#define II(a, b, c, d, m, s, t) { \
8664 + (a) += I ((b), (c), (d)) + (m) + (t); \
8665 + (a) = LROLL((a), (s)); \
8666 + (a) += (b); \
8667 + }
8668 +
8669 +#define s11  7
8670 +#define s12 12
8671 +#define s13 17
8672 +#define s14 22
8673 +#define s21  5
8674 +#define s22  9
8675 +#define s23 14
8676 +#define s24 20
8677 +#define s31  4
8678 +#define s32 11
8679 +#define s33 16
8680 +#define s34 23
8681 +#define s41  6
8682 +#define s42 10
8683 +#define s43 15
8684 +#define s44 21
8685 +
8686 +/* SHA-1 */
8687 +#define f(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
8688 +#define g(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
8689 +#define h(x, y, z) ((x) ^ (y) ^ (z))
8690 +
8691 +#define K1 0x5a827999
8692 +#define K2 0x6ed9eba1
8693 +#define K3 0x8f1bbcdc
8694 +#define K4 0xca62c1d6
8695 +
8696 +int ah_hmac_md5_init(struct ah_processing *ahp, u_int8_t *key, u_int32_t key_len)
8697 +{
8698 +       int i;
8699 +       int key_up4;
8700 +       uint32_t ipad = 0x36363636;
8701 +       uint8_t extkey[64];
8702 +
8703 +       ahp->key_auth = key;
8704 +       ahp->key_auth_len = key_len;
8705 +       ahp->context = (void *) kmalloc(sizeof(MD5_CTX), GFP_ATOMIC);
8706 +       if (ahp->context == NULL)
8707 +               return -1;
8708 +       md5_init((MD5_CTX *) ahp->context);
8709 +       if ((64 * sizeof(uint8_t)) < ahp->key_auth_len) {
8710 +               printk("buffer overflow!");
8711 +               return -1;
8712 +       }
8713 +       memcpy(extkey, ahp->key_auth, ahp->key_auth_len);
8714 +       if (ahp->key_auth_len % 4) {
8715 +               memset(extkey + ahp->key_auth_len, 0,
8716 +                      4 - (ahp->key_auth_len % 4));
8717 +       }
8718 +       key_up4 = ((ahp->key_auth_len + 0x3) & 0xFFFFFFFC) / 4;
8719 +
8720 +       for (i = 0; i < key_up4; i++)
8721 +               ((uint32_t *) extkey)[i] = ((uint32_t *) extkey)[i] ^ ipad;
8722 +       for (i = key_up4; i < 16; i++)
8723 +               ((uint32_t *) extkey)[i] = ipad;
8724 +
8725 +       md5_compute((MD5_CTX *) ahp->context, extkey, 64);
8726 +       return 0;
8727 +}
8728 +
8729 +void ah_hmac_md5_loop(struct ah_processing *ahp, void *str, uint32_t len)
8730 +{
8731 +       md5_compute((MD5_CTX *) ahp->context, str, len);
8732 +}
8733 +
8734 +void ah_hmac_md5_result(struct ah_processing *ahp, char *digest)
8735 +{
8736 +       uint8_t inner[HMAC_MD5_HASH_LEN];
8737 +       int i;
8738 +       int key_up4;
8739 +       uint32_t opad = 0x5c5c5c5c;
8740 +       uint8_t extkey[64];
8741 +
8742 +       md5_final((MD5_CTX *) ahp->context, inner);
8743 +       md5_init((MD5_CTX *) ahp->context);
8744 +
8745 +       memcpy(extkey, ahp->key_auth, ahp->key_auth_len);
8746 +       if (ahp->key_auth_len % 4) {
8747 +               memset(extkey + ahp->key_auth_len, 0,
8748 +                      4 - (ahp->key_auth_len % 4));
8749 +       }
8750 +       key_up4 = ((ahp->key_auth_len + 0x3) & 0xFFFFFFFC) / 4;
8751 +
8752 +       for (i = 0; i < key_up4; i++)
8753 +               ((uint32_t *) extkey)[i] = ((uint32_t *) extkey)[i] ^ opad;
8754 +       for (i = key_up4; i < 16; i++)
8755 +               ((uint32_t *) extkey)[i] = opad;
8756 +
8757 +       md5_compute((MD5_CTX *) ahp->context, extkey, 64);
8758 +       md5_compute((MD5_CTX *) ahp->context, inner, HMAC_MD5_HASH_LEN);
8759 +
8760 +       md5_final((MD5_CTX *) ahp->context, digest);
8761 +
8762 +       kfree(ahp->context);
8763 +}
8764 +
8765 +int ah_hmac_sha1_init(struct ah_processing *ahp, u_int8_t *key, u_int32_t key_len)
8766 +{
8767 +       int i;
8768 +       int key_up4;
8769 +       uint32_t ipad = 0x36363636;
8770 +       uint8_t extkey[64];
8771 +
8772 +       ahp->key_auth = key;
8773 +       ahp->key_auth_len = key_len;
8774 +
8775 +       ahp->context = (void *) kmalloc(sizeof(SHA1_CTX), GFP_ATOMIC);
8776 +       //if (ahp->context == NULL)
8777 +       //      return -1;
8778 +
8779 +       sha1_init((SHA1_CTX *) ahp->context);
8780 +
8781 +       memcpy(extkey, ahp->key_auth, ahp->key_auth_len);
8782 +       if (ahp->key_auth_len % 4) {
8783 +               memset(extkey + ahp->key_auth_len, 0,
8784 +                      4 - (ahp->key_auth_len % 4));
8785 +       }
8786 +       key_up4 = ((ahp->key_auth_len + 0x3) & 0xFFFFFFFC) / 4;
8787 +
8788 +       for (i = 0; i < key_up4; i++)
8789 +               ((uint32_t *) extkey)[i] = ((uint32_t *) extkey)[i] ^ ipad;
8790 +       for (i = key_up4; i < 16; i++)
8791 +               ((uint32_t *) extkey)[i] = ipad;
8792 +
8793 +       sha1_compute((SHA1_CTX *) ahp->context, extkey, 64);
8794 +       return 0;
8795 +}
8796 +
8797 +void ah_hmac_sha1_loop(struct ah_processing *ahp, void *str, uint32_t len)
8798 +{
8799 +       if (!ahp)
8800 +               return;
8801 +       sha1_compute((SHA1_CTX *) ahp->context, str, len);
8802 +}
8803 +
8804 +void ah_hmac_sha1_result(struct ah_processing *ahp, char *digest)
8805 +{
8806 +       uint8_t inner[HMAC_SHA1_HASH_LEN];
8807 +       int i;
8808 +       int key_up4;
8809 +       uint32_t opad = 0x5c5c5c5c;
8810 +       uint8_t extkey[64];
8811 +
8812 +       if (!ahp)
8813 +               return;
8814 +       sha1_final((SHA1_CTX *) ahp->context, inner);
8815 +       sha1_init((SHA1_CTX *) ahp->context);
8816 +
8817 +       memcpy(extkey, ahp->key_auth, ahp->key_auth_len);
8818 +       if (ahp->key_auth_len % 4) {
8819 +               memset(extkey + ahp->key_auth_len, 0,
8820 +                      4 - (ahp->key_auth_len % 4));
8821 +       }
8822 +       key_up4 = ((ahp->key_auth_len + 0x3) & 0xFFFFFFFC) / 4;
8823 +
8824 +       for (i = 0; i < key_up4; i++)
8825 +               ((uint32_t *) extkey)[i] = ((uint32_t *) extkey)[i] ^ opad;
8826 +       for (i = key_up4; i < 16; i++)
8827 +               ((uint32_t *) extkey)[i] = opad;
8828 +
8829 +       sha1_compute((SHA1_CTX *) ahp->context, extkey, 64);
8830 +       sha1_compute((SHA1_CTX *) ahp->context, inner,
8831 +                    HMAC_SHA1_HASH_LEN);
8832 +
8833 +       sha1_final((SHA1_CTX *) ahp->context, digest);
8834 +
8835 +       kfree(ahp->context);
8836 +}
8837 +
8838 +void md5_init(MD5_CTX * ctx)
8839 +{
8840 +       ctx->A = 0x67452301;
8841 +       ctx->B = 0xefcdab89;
8842 +       ctx->C = 0x98badcfe;
8843 +       ctx->D = 0x10325476;
8844 +       ctx->buf_cur = ctx->buf;
8845 +       ctx->bitlen[0] = ctx->bitlen[1] = 0;
8846 +       memset(ctx->buf, 0, 64);
8847 +}
8848 +
8849 +void md5_over_block(MD5_CTX * ctx, uint8_t * data)
8850 +{
8851 +       uint32_t M[16];
8852 +       uint32_t a = ctx->A;
8853 +       uint32_t b = ctx->B;
8854 +       uint32_t c = ctx->C;
8855 +       uint32_t d = ctx->D;
8856 +
8857 +       create_M_blocks(M, data);
8858 +
8859 +       /* Round 1 */
8860 +       FF(a, b, c, d, M[0], s11, 0xd76aa478);  /*  1 */
8861 +       FF(d, a, b, c, M[1], s12, 0xe8c7b756);  /*  2 */
8862 +       FF(c, d, a, b, M[2], s13, 0x242070db);  /*  3 */
8863 +       FF(b, c, d, a, M[3], s14, 0xc1bdceee);  /*  4 */
8864 +       FF(a, b, c, d, M[4], s11, 0xf57c0faf);  /*  5 */
8865 +       FF(d, a, b, c, M[5], s12, 0x4787c62a);  /*  6 */
8866 +       FF(c, d, a, b, M[6], s13, 0xa8304613);  /*  7 */
8867 +       FF(b, c, d, a, M[7], s14, 0xfd469501);  /*  8 */
8868 +       FF(a, b, c, d, M[8], s11, 0x698098d8);  /*  9 */
8869 +       FF(d, a, b, c, M[9], s12, 0x8b44f7af);  /* 10 */
8870 +       FF(c, d, a, b, M[10], s13, 0xffff5bb1); /* 11 */
8871 +       FF(b, c, d, a, M[11], s14, 0x895cd7be); /* 12 */
8872 +       FF(a, b, c, d, M[12], s11, 0x6b901122); /* 13 */
8873 +       FF(d, a, b, c, M[13], s12, 0xfd987193); /* 14 */
8874 +       FF(c, d, a, b, M[14], s13, 0xa679438e); /* 15 */
8875 +       FF(b, c, d, a, M[15], s14, 0x49b40821); /* 16 */
8876 +
8877 +       /* Round 2 */
8878 +       GG(a, b, c, d, M[1], s21, 0xf61e2562);  /* 17 */
8879 +       GG(d, a, b, c, M[6], s22, 0xc040b340);  /* 18 */
8880 +       GG(c, d, a, b, M[11], s23, 0x265e5a51); /* 19 */
8881 +       GG(b, c, d, a, M[0], s24, 0xe9b6c7aa);  /* 20 */
8882 +       GG(a, b, c, d, M[5], s21, 0xd62f105d);  /* 21 */
8883 +       GG(d, a, b, c, M[10], s22, 0x02441453); /* 22 */
8884 +       GG(c, d, a, b, M[15], s23, 0xd8a1e681); /* 23 */
8885 +       GG(b, c, d, a, M[4], s24, 0xe7d3fbc8);  /* 24 */
8886 +       GG(a, b, c, d, M[9], s21, 0x21e1cde6);  /* 25 */
8887 +       GG(d, a, b, c, M[14], s22, 0xc33707d6); /* 26 */
8888 +       GG(c, d, a, b, M[3], s23, 0xf4d50d87);  /* 27 */
8889 +       GG(b, c, d, a, M[8], s24, 0x455a14ed);  /* 28 */
8890 +       GG(a, b, c, d, M[13], s21, 0xa9e3e905); /* 29 */
8891 +       GG(d, a, b, c, M[2], s22, 0xfcefa3f8);  /* 30 */
8892 +       GG(c, d, a, b, M[7], s23, 0x676f02d9);  /* 31 */
8893 +       GG(b, c, d, a, M[12], s24, 0x8d2a4c8a); /* 32 */
8894 +
8895 +       /* Round 3 */
8896 +       HH(a, b, c, d, M[5], s31, 0xfffa3942);  /* 33 */
8897 +       HH(d, a, b, c, M[8], s32, 0x8771f681);  /* 34 */
8898 +       HH(c, d, a, b, M[11], s33, 0x6d9d6122); /* 35 */
8899 +       HH(b, c, d, a, M[14], s34, 0xfde5380c); /* 36 */
8900 +       HH(a, b, c, d, M[1], s31, 0xa4beea44);  /* 37 */
8901 +       HH(d, a, b, c, M[4], s32, 0x4bdecfa9);  /* 38 */
8902 +       HH(c, d, a, b, M[7], s33, 0xf6bb4b60);  /* 39 */
8903 +       HH(b, c, d, a, M[10], s34, 0xbebfbc70); /* 40 */
8904 +       HH(a, b, c, d, M[13], s31, 0x289b7ec6); /* 41 */
8905 +       HH(d, a, b, c, M[0], s32, 0xeaa127fa);  /* 42 */
8906 +       HH(c, d, a, b, M[3], s33, 0xd4ef3085);  /* 43 */
8907 +       HH(b, c, d, a, M[6], s34, 0x4881d05);   /* 44 */
8908 +       HH(a, b, c, d, M[9], s31, 0xd9d4d039);  /* 45 */
8909 +       HH(d, a, b, c, M[12], s32, 0xe6db99e5); /* 46 */
8910 +       HH(c, d, a, b, M[15], s33, 0x1fa27cf8); /* 47 */
8911 +       HH(b, c, d, a, M[2], s34, 0xc4ac5665);  /* 48 */
8912 +
8913 +       /* Round 4 */
8914 +       II(a, b, c, d, M[0], s41, 0xf4292244);  /* 49 */
8915 +       II(d, a, b, c, M[7], s42, 0x432aff97);  /* 50 */
8916 +       II(c, d, a, b, M[14], s43, 0xab9423a7); /* 51 */
8917 +       II(b, c, d, a, M[5], s44, 0xfc93a039);  /* 52 */
8918 +       II(a, b, c, d, M[12], s41, 0x655b59c3); /* 53 */
8919 +       II(d, a, b, c, M[3], s42, 0x8f0ccc92);  /* 54 */
8920 +       II(c, d, a, b, M[10], s43, 0xffeff47d); /* 55 */
8921 +       II(b, c, d, a, M[1], s44, 0x85845dd1);  /* 56 */
8922 +       II(a, b, c, d, M[8], s41, 0x6fa87e4f);  /* 57 */
8923 +       II(d, a, b, c, M[15], s42, 0xfe2ce6e0); /* 58 */
8924 +       II(c, d, a, b, M[6], s43, 0xa3014314);  /* 59 */
8925 +       II(b, c, d, a, M[13], s44, 0x4e0811a1); /* 60 */
8926 +       II(a, b, c, d, M[4], s41, 0xf7537e82);  /* 61 */
8927 +       II(d, a, b, c, M[11], s42, 0xbd3af235); /* 62 */
8928 +       II(c, d, a, b, M[2], s43, 0x2ad7d2bb);  /* 63 */
8929 +       II(b, c, d, a, M[9], s44, 0xeb86d391);  /* 64 */
8930 +
8931 +       ctx->A += a;
8932 +       ctx->B += b;
8933 +       ctx->C += c;
8934 +       ctx->D += d;
8935 +}
8936 +
8937 +void create_M_blocks(uint32_t * M, uint8_t * data)
8938 +{
8939 +#ifdef HAVE_LITTLE_ENDIAN
8940 +       memcpy((uint8_t *) M, data, 64);
8941 +#endif                         /* HAVE_LITTLE_ENDIAN */
8942 +
8943 +#ifdef HAVE_BIG_ENDIAN
8944 +       int i;
8945 +       for (i = 0; i < 16; i++, data += 4) {
8946 +               ((uint8_t *) (&M[i]))[0] = data[3];
8947 +               ((uint8_t *) (&M[i]))[1] = data[2];
8948 +               ((uint8_t *) (&M[i]))[2] = data[1];
8949 +               ((uint8_t *) (&M[i]))[3] = data[0];
8950 +       }
8951 +#endif                         /* HAVE_BIG_ENDIAN */
8952 +}
8953 +
8954 +void md5_compute(MD5_CTX * ctx, uint8_t * data, uint32_t len)
8955 +{
8956 +       uint8_t pos = ((ctx->bitlen[0] >> 3) & 0x3f);
8957 +
8958 +       /* First we update the bit length */
8959 +       if ((ctx->bitlen[0] += (len << 3)) < (len << 3))
8960 +               ctx->bitlen[1]++;
8961 +       ctx->bitlen[1] += (len >> 29);  /* len is expressed in bytes */
8962 +
8963 +       if (pos) {
8964 +               /* Buffer is not empty */
8965 +               if (64 - pos >= len) {
8966 +                       memcpy(ctx->buf_cur, data, len);
8967 +                       ctx->buf_cur += len;
8968 +                       pos += len;
8969 +                       if (pos == 64) {
8970 +                               /* The current block is over */
8971 +                               md5_over_block(ctx, ctx->buf);
8972 +                               ctx->buf_cur = ctx->buf;
8973 +                       }
8974 +                       return;
8975 +               } else {
8976 +                       memcpy(ctx->buf_cur, data, 64 - pos);
8977 +                       md5_over_block(ctx, ctx->buf);
8978 +                       len -= (64 - pos);
8979 +                       data += (64 - pos);
8980 +                       ctx->buf_cur = ctx->buf;
8981 +               }
8982 +       }
8983 +       while (len >= 64) {
8984 +               md5_over_block(ctx, data);
8985 +               len -= 64;
8986 +               data += 64;
8987 +       }
8988 +       if (len) {
8989 +               memcpy(ctx->buf_cur, data, len);
8990 +               ctx->buf_cur += len;
8991 +       }
8992 +}
8993 +
8994 +void md5_final(MD5_CTX * ctx, uint8_t * digest)
8995 +{
8996 +       uint32_t rem_size;
8997 +       uint8_t *buf_cur = ctx->buf_cur;
8998 +       int i;
8999 +
9000 +       rem_size = 64 - ((ctx->bitlen[0] >> 3) & 0x3f);
9001 +       *(buf_cur++) = 0x80;
9002 +
9003 +       if (rem_size > 8 + 1) {
9004 +               /* We have enough room in the current block */
9005 +               for (i = 0; i < rem_size - 8 - 1; i++) {
9006 +                       *(buf_cur++) = 0;
9007 +               }
9008 +       } else {
9009 +               /* We do not have enough room and need therefore to add a new
9010 +                  64-byte block */
9011 +               for (i = 0; i < rem_size - 1; i++) {
9012 +                       *(buf_cur++) = 0;
9013 +               }
9014 +               md5_over_block(ctx, ctx->buf);
9015 +
9016 +               buf_cur = ctx->buf;
9017 +               for (i = 0; i < 64 - 8; i++) {
9018 +                       *(buf_cur++) = 0;
9019 +               }
9020 +       }
9021 +#ifdef HAVE_LITTLE_ENDIAN
9022 +       memcpy(buf_cur, (uint8_t *) ctx->bitlen, 8);
9023 +#endif                         /* HAVE_LITTLE_ENDIAN */
9024 +
9025 +#ifdef HAVE_BIG_ENDIAN
9026 +       *(buf_cur++) = (ctx->bitlen[0] >> 24) & 0xff;
9027 +       *(buf_cur++) = (ctx->bitlen[0] >> 16) & 0xff;
9028 +       *(buf_cur++) = (ctx->bitlen[0] >> 8) & 0xff;
9029 +       *(buf_cur++) = (ctx->bitlen[0] >> 0) & 0xff;
9030 +       *(buf_cur++) = (ctx->bitlen[1] >> 24) & 0xff;
9031 +       *(buf_cur++) = (ctx->bitlen[1] >> 16) & 0xff;
9032 +       *(buf_cur++) = (ctx->bitlen[1] >> 8) & 0xff;
9033 +       *(buf_cur++) = (ctx->bitlen[1] >> 0) & 0xff;
9034 +#endif                         /* HAVE_BIG_ENDIAN */
9035 +
9036 +       md5_over_block(ctx, ctx->buf);
9037 +
9038 +#ifdef HAVE_LITTLE_ENDIAN
9039 +       memcpy(digest + 0, (uint8_t *) (&(ctx->A)), sizeof(uint32_t));
9040 +       memcpy(digest + 4, (uint8_t *) (&(ctx->B)), sizeof(uint32_t));
9041 +       memcpy(digest + 8, (uint8_t *) (&(ctx->C)), sizeof(uint32_t));
9042 +       memcpy(digest + 12, (uint8_t *) (&(ctx->D)), sizeof(uint32_t));
9043 +#endif                         /* HAVE_LITTLE_ENDIAN */
9044 +
9045 +#ifdef HAVE_BIG_ENDIAN
9046 +       digest[0] = ((ctx->A) >> 24) & 0xff;
9047 +       digest[1] = ((ctx->A) >> 16) & 0xff;
9048 +       digest[2] = ((ctx->A) >> 8) & 0xff;
9049 +       digest[3] = ((ctx->A) >> 0) & 0xff;
9050 +       digest[4] = ((ctx->B) >> 24) & 0xff;
9051 +       digest[5] = ((ctx->B) >> 16) & 0xff;
9052 +       digest[6] = ((ctx->B) >> 8) & 0xff;
9053 +       digest[7] = ((ctx->B) >> 0) & 0xff;
9054 +       digest[8] = ((ctx->C) >> 24) & 0xff;
9055 +       digest[9] = ((ctx->C) >> 16) & 0xff;
9056 +       digest[10] = ((ctx->C) >> 8) & 0xff;
9057 +       digest[11] = ((ctx->C) >> 0) & 0xff;
9058 +       digest[12] = ((ctx->D) >> 24) & 0xff;
9059 +       digest[13] = ((ctx->D) >> 16) & 0xff;
9060 +       digest[14] = ((ctx->D) >> 8) & 0xff;
9061 +       digest[15] = ((ctx->D) >> 0) & 0xff;
9062 +#endif                         /* HAVE_BIG_ENDIAN */
9063 +}
9064 +
9065 +void sha1_init(SHA1_CTX * ctx)
9066 +{
9067 +       ctx->A = 0x67452301;
9068 +       ctx->B = 0xefcdab89;
9069 +       ctx->C = 0x98badcfe;
9070 +       ctx->D = 0x10325476;
9071 +       ctx->E = 0xc3d2e1f0;
9072 +       ctx->buf_cur = ctx->buf;
9073 +       ctx->bitlen[0] = ctx->bitlen[1] = 0;
9074 +       memset(ctx->buf, 0, 64);
9075 +}
9076 +
9077 +void sha1_over_block(SHA1_CTX * ctx, uint8_t * data)
9078 +{
9079 +       int i;
9080 +       uint32_t W[80];
9081 +       uint32_t a = ctx->A;
9082 +       uint32_t b = ctx->B;
9083 +       uint32_t c = ctx->C;
9084 +       uint32_t d = ctx->D;
9085 +       uint32_t e = ctx->E;
9086 +       uint32_t temp;
9087 +
9088 +       create_W_blocks(W, data);
9089 +
9090 +       /* Round 1 */
9091 +       for (i = 0; i < 20; i++) {
9092 +               temp = LROLL(a, 5) + f(b, c, d) + e + W[i] + K1;
9093 +               e = d;
9094 +               d = c;
9095 +               c = LROLL(b, 30);
9096 +               b = a;
9097 +               a = temp;
9098 +       }
9099 +
9100 +       /* Round 2 */
9101 +       for (i = 20; i < 40; i++) {
9102 +               temp = LROLL(a, 5) + h(b, c, d) + e + W[i] + K2;
9103 +               e = d;
9104 +               d = c;
9105 +               c = LROLL(b, 30);
9106 +               b = a;
9107 +               a = temp;
9108 +       }
9109 +
9110 +       /* Round 3 */
9111 +       for (i = 40; i < 60; i++) {
9112 +               temp = LROLL(a, 5) + g(b, c, d) + e + W[i] + K3;
9113 +               e = d;
9114 +               d = c;
9115 +               c = LROLL(b, 30);
9116 +               b = a;
9117 +               a = temp;
9118 +       }
9119 +
9120 +       /* Round 4 */
9121 +       for (i = 60; i < 80; i++) {
9122 +               temp = LROLL(a, 5) + h(b, c, d) + e + W[i] + K4;
9123 +               e = d;
9124 +               d = c;
9125 +               c = LROLL(b, 30);
9126 +               b = a;
9127 +               a = temp;
9128 +       }
9129 +
9130 +       ctx->A += a;
9131 +       ctx->B += b;
9132 +       ctx->C += c;
9133 +       ctx->D += d;
9134 +       ctx->E += e;
9135 +}
9136 +
9137 +void create_W_blocks(uint32_t * W, uint8_t * data)
9138 +{
9139 +       int i;
9140 +
9141 +#ifdef HAVE_BIG_ENDIAN
9142 +       memcpy((uint8_t *) W, data, 64);
9143 +#endif                         /* HAVE_BIG_ENDIAN */
9144 +
9145 +#ifdef HAVE_LITTLE_ENDIAN
9146 +       for (i = 0; i < 16; i++, data += 4) {
9147 +               ((uint8_t *) (&W[i]))[0] = data[3];
9148 +               ((uint8_t *) (&W[i]))[1] = data[2];
9149 +               ((uint8_t *) (&W[i]))[2] = data[1];
9150 +               ((uint8_t *) (&W[i]))[3] = data[0];
9151 +       }
9152 +#endif                         /* HAVE_LITTLE_ENDIAN */
9153 +       for (i = 16; i < 80; i++) {
9154 +               W[i] = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16];
9155 +               W[i] = LROLL(W[i], 1);
9156 +       }
9157 +}
9158 +
9159 +void sha1_compute(SHA1_CTX * ctx, uint8_t * data, uint32_t len)
9160 +{
9161 +       uint8_t pos = ((ctx->bitlen[0] >> 3) & 0x3f);
9162 +
9163 +       /* First we update the bit length */
9164 +       if ((ctx->bitlen[0] += (len << 3)) < (len << 3))
9165 +               ctx->bitlen[1]++;
9166 +       ctx->bitlen[1] += (len >> 29);  /* len is expressed in bytes */
9167 +
9168 +       if (pos) {
9169 +               /* Buffer is not empty */
9170 +               if (64 - pos >= len) {
9171 +                       memcpy(ctx->buf_cur, data, len);
9172 +                       ctx->buf_cur += len;
9173 +                       pos += len;
9174 +                       if (pos == 64) {
9175 +                               /* The current block is over */
9176 +                               sha1_over_block(ctx, ctx->buf);
9177 +                               ctx->buf_cur = ctx->buf;
9178 +                       }
9179 +                       return;
9180 +               } else {
9181 +                       memcpy(ctx->buf_cur, data, 64 - pos);
9182 +                       sha1_over_block(ctx, ctx->buf);
9183 +                       len -= (64 - pos);
9184 +                       data += (64 - pos);
9185 +                       ctx->buf_cur = ctx->buf;
9186 +               }
9187 +       }
9188 +       while (len >= 64) {
9189 +               sha1_over_block(ctx, data);
9190 +               len -= 64;
9191 +               data += 64;
9192 +       }
9193 +       if (len) {
9194 +               memcpy(ctx->buf_cur, data, len);
9195 +               ctx->buf_cur += len;
9196 +       }
9197 +}
9198 +
9199 +void sha1_final(SHA1_CTX * ctx, uint8_t * digest)
9200 +{
9201 +       uint32_t rem_size;
9202 +       uint8_t *buf_cur = ctx->buf_cur;
9203 +       int i;
9204 +
9205 +       rem_size = 64 - ((ctx->bitlen[0] >> 3) & 0x3f);
9206 +       *(buf_cur++) = 0x80;
9207 +
9208 +       if (rem_size > 8 + 1) {
9209 +               /* We have enough room in the current block */
9210 +               for (i = 0; i < rem_size - 8 - 1; i++) {
9211 +                       *(buf_cur++) = 0;
9212 +               }
9213 +       } else {
9214 +               /* We do not have enough room and need therefore to add a new
9215 +                  64-byte block */
9216 +               for (i = 0; i < rem_size - 1; i++) {
9217 +                       *(buf_cur++) = 0;
9218 +               }
9219 +               sha1_over_block(ctx, ctx->buf);
9220 +
9221 +               buf_cur = ctx->buf;
9222 +               for (i = 0; i < 64 - 8; i++) {
9223 +                       *(buf_cur++) = 0;
9224 +               }
9225 +       }
9226 +#ifdef HAVE_BIG_ENDIAN
9227 +       memcpy(buf_cur, (uint8_t *) ctx->bitlen, 8);
9228 +#endif                         /* HAVE_BIG_ENDIAN */
9229 +
9230 +#ifdef HAVE_LITTLE_ENDIAN
9231 +       *(buf_cur++) = (ctx->bitlen[1] >> 24) & 0xff;
9232 +       *(buf_cur++) = (ctx->bitlen[1] >> 16) & 0xff;
9233 +       *(buf_cur++) = (ctx->bitlen[1] >> 8) & 0xff;
9234 +       *(buf_cur++) = (ctx->bitlen[1] >> 0) & 0xff;
9235 +       *(buf_cur++) = (ctx->bitlen[0] >> 24) & 0xff;
9236 +       *(buf_cur++) = (ctx->bitlen[0] >> 16) & 0xff;
9237 +       *(buf_cur++) = (ctx->bitlen[0] >> 8) & 0xff;
9238 +       *(buf_cur++) = (ctx->bitlen[0] >> 0) & 0xff;
9239 +#endif                         /* HAVE_LITTLE_ENDIAN */
9240 +
9241 +       sha1_over_block(ctx, ctx->buf);
9242 +
9243 +#ifdef HAVE_BIG_ENDIAN
9244 +       memcpy(digest + 0, (uint8_t *) (&(ctx->A)), sizeof(uint32_t));
9245 +       memcpy(digest + 4, (uint8_t *) (&(ctx->B)), sizeof(uint32_t));
9246 +       memcpy(digest + 8, (uint8_t *) (&(ctx->C)), sizeof(uint32_t));
9247 +       memcpy(digest + 12, (uint8_t *) (&(ctx->D)), sizeof(uint32_t));
9248 +       memcpy(digest + 16, (uint8_t *) (&(ctx->E)), sizeof(uint32_t));
9249 +#endif                         /* HAVE_BIG_ENDIAN */
9250 +
9251 +#ifdef HAVE_LITTLE_ENDIAN
9252 +       digest[0] = ((ctx->A) >> 24) & 0xff;
9253 +       digest[1] = ((ctx->A) >> 16) & 0xff;
9254 +       digest[2] = ((ctx->A) >> 8) & 0xff;
9255 +       digest[3] = ((ctx->A) >> 0) & 0xff;
9256 +       digest[4] = ((ctx->B) >> 24) & 0xff;
9257 +       digest[5] = ((ctx->B) >> 16) & 0xff;
9258 +       digest[6] = ((ctx->B) >> 8) & 0xff;
9259 +       digest[7] = ((ctx->B) >> 0) & 0xff;
9260 +       digest[8] = ((ctx->C) >> 24) & 0xff;
9261 +       digest[9] = ((ctx->C) >> 16) & 0xff;
9262 +       digest[10] = ((ctx->C) >> 8) & 0xff;
9263 +       digest[11] = ((ctx->C) >> 0) & 0xff;
9264 +       digest[12] = ((ctx->D) >> 24) & 0xff;
9265 +       digest[13] = ((ctx->D) >> 16) & 0xff;
9266 +       digest[14] = ((ctx->D) >> 8) & 0xff;
9267 +       digest[15] = ((ctx->D) >> 0) & 0xff;
9268 +       digest[16] = ((ctx->E) >> 24) & 0xff;
9269 +       digest[17] = ((ctx->E) >> 16) & 0xff;
9270 +       digest[18] = ((ctx->E) >> 8) & 0xff;
9271 +       digest[19] = ((ctx->E) >> 0) & 0xff;
9272 +#endif                         /* HAVE_LITTLE_ENDIAN */
9273 +}
9274 --- /dev/null
9275 +++ linux-2.4.27/net/ipv6/mobile_ip6/hmac.h
9276 @@ -0,0 +1,94 @@
9277 +/*
9278 + *      MIPL Mobile IPv6 Message authentication algorithms        
9279 + * 
9280 + *      $Id$
9281 + *
9282 + *      This program is free software; you can redistribute it and/or
9283 + *      modify it under the terms of the GNU General Public License
9284 + *      as published by the Free Software Foundation; either version
9285 + *      2 of the License, or (at your option) any later version.
9286 + */
9287 +
9288 +#ifndef _HMAC_H
9289 +#define _HMAC_H
9290 +
9291 +#include <linux/types.h>
9292 +#include <linux/in6.h>
9293 +
9294 +#define HAVE_LITTLE_ENDIAN
9295 +
9296 +#define NO_EXPIRY 1  /* For sec_as */
9297 +
9298 +#define ALG_AUTH_NONE           0
9299 +#define ALG_AUTH_HMAC_MD5       1
9300 +#define ALG_AUTH_HMAC_SHA1      2
9301 +
9302 +struct sec_as;
9303 +struct ah_processing {
9304 +       void *context;
9305 +       struct sec_as *sas;
9306 +       u_int8_t *key_auth;
9307 +       u_int32_t key_auth_len;
9308 +};
9309 +
9310 +struct antireplay {
9311 +       u_int32_t count;
9312 +       u_int32_t bitmap; 
9313 +};
9314 +
9315 +typedef struct {
9316 +  u_int32_t A, B, C, D;
9317 +  u_int32_t bitlen[2];
9318 +  u_int8_t* buf_cur;
9319 +  u_int8_t buf[64];
9320 +} MD5_CTX;
9321 +
9322 +typedef struct {
9323 +  u_int32_t A, B, C, D, E;
9324 +  u_int32_t bitlen[2];
9325 +  u_int8_t* buf_cur;
9326 +  u_int8_t buf[64];
9327 +} SHA1_CTX;
9328 +
9329 +
9330 +
9331 +int ah_hmac_md5_init (struct ah_processing *ahp, u_int8_t *key, u_int32_t key_len);
9332 +void ah_hmac_md5_loop(struct ah_processing*, void*, u_int32_t);
9333 +void ah_hmac_md5_result(struct ah_processing*, char*);
9334 +int ah_hmac_sha1_init(struct ah_processing*, u_int8_t *key, u_int32_t key_len);
9335 +void ah_hmac_sha1_loop(struct ah_processing*, void*, u_int32_t);
9336 +void ah_hmac_sha1_result(struct ah_processing*, char*);
9337 +
9338 +
9339 +#define AH_HDR_LEN 12   /* # of bytes for Next Header, Payload Length,
9340 +                           RESERVED, Security Parameters Index and
9341 +
9342 +                           Sequence Number Field */
9343 +
9344 +void md5_init(MD5_CTX *ctx);
9345 +void md5_over_block(MD5_CTX *ctx, u_int8_t* data);
9346 +void create_M_blocks(u_int32_t* M, u_int8_t* data);
9347 +void md5_compute(MD5_CTX *ctx, u_int8_t* data, u_int32_t len);
9348 +void md5_final(MD5_CTX *ctx, u_int8_t* digest);
9349 +
9350 +void sha1_init(SHA1_CTX *ctx);
9351 +void sha1_over_block(SHA1_CTX *ctx, u_int8_t* data);
9352 +void create_W_blocks(u_int32_t* W, u_int8_t* data);
9353 +void sha1_compute(SHA1_CTX *ctx, u_int8_t* data, u_int32_t len);
9354 +void sha1_final(SHA1_CTX *ctx, u_int8_t* digest);
9355 +
9356 +struct mipv6_acq {
9357 +       struct in6_addr coa;
9358 +       struct in6_addr haddr;
9359 +       struct in6_addr peer;
9360 +       u_int32_t spi;
9361 +};
9362 +#define MIPV6_MAX_AUTH_DATA 20
9363 +
9364 +#define HMAC_MD5_HASH_LEN   16
9365 +#define HMAC_SHA1_HASH_LEN  20
9366 +#define HMAC_SHA1_KEY_SIZE  20
9367 +#define HMAC_MD5_ICV_LEN   12 /* RFC 2403 */
9368 +#define HMAC_SHA1_ICV_LEN  12 /* RFC 2404 */
9369 +
9370 +#endif /* _HMAC_H */
9371 --- /dev/null
9372 +++ linux-2.4.27/net/ipv6/mobile_ip6/ioctl_mn.c
9373 @@ -0,0 +1,142 @@
9374 +/*
9375 + *     Mobile Node IOCTL Control device
9376 + *
9377 + *     Authors:
9378 + *     Henrik Petander         <lpetande@tml.hut.fi>
9379 + *
9380 + *     $Id$
9381 + *
9382 + *     This program is free software; you can redistribute it and/or
9383 + *      modify it under the terms of the GNU General Public License
9384 + *      as published by the Free Software Foundation; either version
9385 + *      2 of the License, or (at your option) any later version.
9386 + */
9387 +
9388 +#include <linux/config.h>
9389 +#include <linux/module.h>
9390 +#include <linux/fs.h>
9391 +#include <linux/poll.h>
9392 +#include <linux/ioctl.h> 
9393 +#include <net/ipv6.h>
9394 +#include <asm/uaccess.h>
9395 +
9396 +#include "debug.h"
9397 +#include "mdetect.h"
9398 +#include "multiaccess_ctl.h"
9399 +
9400 +/* Reserved for local / experimental use */
9401 +#define MAJOR_NUM 0xf9
9402 +
9403 +/* Get Care-of address information for Mobile Node */
9404 +#define IOCTL_GET_CAREOFADDR _IOWR(MAJOR_NUM, 9, void *)
9405 +
9406 +#define MA_IOCTL_SET_IFACE_PREFERENCE _IOR (MAJOR_NUM, 13, void *)
9407 +
9408 +/* The name of the device file */
9409 +#define CTLFILE "mipv6_dev"
9410 +
9411 +static int inuse = 0;
9412 +
9413 +static int mipv6_open(struct inode *inode, struct file *file)
9414 +{
9415 +       DEBUG(DBG_INFO, "(%p)\n", file);
9416 +
9417 +       if (inuse)
9418 +               return -EBUSY;
9419 +
9420 +       inuse++;
9421 +
9422 +       MOD_INC_USE_COUNT;
9423 +
9424 +       return 0;
9425 +}
9426 +
9427 +static int mipv6_close(struct inode *inode, struct file *file)
9428 +{
9429 +       DEBUG(DBG_INFO, "(%p,%p)\n", inode, file);
9430 +       inuse--;
9431 +
9432 +       MOD_DEC_USE_COUNT;
9433 +
9434 +       return 0;
9435 +}
9436 +
9437 +int mipv6_ioctl(struct inode *inode, struct file *file, 
9438 +               unsigned int ioctl_num, /* The number of the ioctl */
9439 +               unsigned long arg)      /* The parameter to it */
9440 +{
9441 +       struct in6_addr careofaddr;
9442 +
9443 +       /* Switch according to the ioctl called */
9444 +       switch (ioctl_num) {
9445 +       case IOCTL_GET_CAREOFADDR:
9446 +               DEBUG(DBG_DATADUMP, "IOCTL_GET_CAREOFADDR");
9447 +               /* First get home address from user and then look up 
9448 +                * the care-of address and return it
9449 +                */
9450 +               if (copy_from_user(&careofaddr, (struct in6_addr *)arg, 
9451 +                                  sizeof(struct in6_addr)) < 0) {
9452 +                       DEBUG(DBG_WARNING, "Copy from user failed");
9453 +                       return -EFAULT;
9454 +               }
9455 +               mipv6_get_care_of_address(&careofaddr, &careofaddr);
9456 +               if (copy_to_user((struct in6_addr *)arg, &careofaddr,
9457 +                                sizeof(struct in6_addr)) < 0) {
9458 +                       DEBUG(DBG_WARNING, "copy_to_user failed");
9459 +                       return -EFAULT;
9460 +               }
9461 +               break;
9462 +       case MA_IOCTL_SET_IFACE_PREFERENCE:
9463 +               DEBUG(DBG_INFO, "MA_IOCTL_SET_IFACE_PREFERENCE");
9464 +               ma_ctl_set_preference(arg);
9465 +               break;
9466 +
9467 +       default:
9468 +               DEBUG(DBG_WARNING, "Unknown ioctl cmd (%d)", ioctl_num);
9469 +               return -ENOENT;
9470 +       }
9471 +       return 0;
9472 +}
9473 +
9474 +struct file_operations Fops = {
9475 +       owner: THIS_MODULE,
9476 +       read: NULL,
9477 +       write: NULL,
9478 +       poll: NULL,
9479 +       ioctl: mipv6_ioctl,
9480 +       open: mipv6_open,
9481 +       release: mipv6_close
9482 +};
9483 +
9484 +
9485 +/* Initialize the module - Register the character device */
9486 +int mipv6_ioctl_mn_init(void)
9487 +{
9488 +       int ret_val;
9489 +
9490 +       /* Register the character device (atleast try) */
9491 +       ret_val = register_chrdev(MAJOR_NUM, CTLFILE, &Fops);
9492 +
9493 +       /* Negative values signify an error */
9494 +       if (ret_val < 0) {
9495 +               DEBUG(DBG_ERROR, "failed registering char device (err=%d)",
9496 +                     ret_val);
9497 +               return ret_val;
9498 +       }
9499 +
9500 +       DEBUG(DBG_INFO, "Device number %x, success", MAJOR_NUM);
9501 +       return 0;
9502 +}
9503 +
9504 +
9505 +/* Cleanup - unregister the appropriate file from /proc */
9506 +void mipv6_ioctl_mn_exit(void)
9507 +{
9508 +       int ret;
9509 +       /* Unregister the device */
9510 +       ret = unregister_chrdev(MAJOR_NUM, CTLFILE);
9511 +
9512 +       /* If there's an error, report it */
9513 +       if (ret < 0)
9514 +               DEBUG(DBG_ERROR, "errorcode: %d\n", ret);
9515 +}
9516 --- /dev/null
9517 +++ linux-2.4.27/net/ipv6/mobile_ip6/mdetect.c
9518 @@ -0,0 +1,1153 @@
9519 +/*
9520 + *      Movement Detection Module
9521 + *
9522 + *      Authors:
9523 + *      Henrik Petander                <lpetande@cc.hut.fi>
9524 + *
9525 + *      $Id$
9526 + *
9527 + *      This program is free software; you can redistribute it and/or
9528 + *      modify it under the terms of the GNU General Public License
9529 + *      as published by the Free Software Foundation; either version
9530 + *      2 of the License, or (at your option) any later version.
9531 + *
9532 + *      Handles the L3 movement detection of mobile node and also
9533 + *      changing of its routes.
9534 + *  
9535 + */
9536 +
9537 +/*
9538 + *     Changes:
9539 + *
9540 + *     Nanno Langstraat        :       Locking fixes
9541 + *      Venkata Jagana          :       Locking fix
9542 + */
9543 +
9544 +#include <linux/autoconf.h>
9545 +#include <linux/errno.h>
9546 +#include <linux/init.h>
9547 +#include <linux/if_arp.h>
9548 +#include <linux/route.h>
9549 +#include <net/ipv6.h>
9550 +#include <net/ip6_route.h>
9551 +#include <net/addrconf.h>
9552 +#include <net/mipglue.h>
9553 +#ifdef CONFIG_SYSCTL
9554 +#include <linux/sysctl.h>
9555 +#endif /* CONFIG_SYSCTL */
9556 +
9557 +#include "util.h"
9558 +#include "mdetect.h"
9559 +#include "mn.h"
9560 +#include "debug.h"
9561 +#include "multiaccess_ctl.h"
9562 +
9563 +#define START 0
9564 +#define CONTINUE 1
9565 +#define OK 2
9566 +#define DEBUG_MDETECT 7
9567 +
9568 +#define DEF_RTR_POLL_IVAL 5 /* In seconds */
9569 +
9570 +#define NO_RTR 0
9571 +#define RTR_SUSPECT 1
9572 +#define CURR_RTR_OK 2
9573 +
9574 +#define RA_RCVD 0
9575 +#define NA_RCVD 1
9576 +#define TIMEOUT 2
9577 +
9578 +#define MIPV6_MDF_NONE 0x0
9579 +#define MIPV6_MDF_HAS_RTR_PREV 0x1
9580 +
9581 +#define ROUTER_REACHABLE 1
9582 +#define RADV_MISSED 2
9583 +#define NOT_REACHABLE 3
9584 +
9585 +/* R_TIME_OUT paramater is used to make the decision when to change the 
9586 + * default  router, if the current one is unreachable. 2s is pretty aggressive 
9587 + * and may result in hopping between two routers. OTOH a small value enhances 
9588 + * the  performance
9589 + */
9590 +#define R_TIME_OUT 30*HZ
9591 +
9592 +/* maximum RA interval for router unreachability detection */
9593 +#define MAX_RADV_INTERVAL 6*HZ  /* 6000 ms... */
9594 +
9595 +/* Threshold for exponential resending of router solicitations */
9596 +#define RS_RESEND_LINEAR 10*HZ
9597 +
9598 +#define EAGER_CELL_SWITCHING 1
9599 +#define LAZY_CELL_SWITCHING 0
9600 +#define RESPECT_DAD 1
9601 +
9602 +#define ROUTER_ADDRESS 0x20
9603 +
9604 +/* RA flags */
9605 +#define ND_RA_FLAG_MANAGED  0x80
9606 +#define ND_RA_FLAG_OTHER    0x40
9607 +#define ND_RA_FLAG_HA       0x20
9608 +
9609 +/* DAD flags for global and link local addresses */
9610 +
9611 +#define COA_TENTATIVE       0x10
9612 +#define LLADDR_TENTATIVE    0x01
9613 +
9614 +struct router {
9615 +       struct list_head list;
9616 +       struct in6_addr ll_addr;
9617 +       struct in6_addr raddr; /* Also contains prefix */
9618 +       __u8 link_addr[MAX_ADDR_LEN]; /* link layer address */
9619 +       __u8 link_addr_len;
9620 +       __u8 state;
9621 +       __u8 is_current;
9622 +       __u8 reachable;
9623 +       int ifindex;
9624 +       int pfix_len; /* Length of the network prefix */
9625 +       unsigned long lifetime; /* from ra */
9626 +       __u32 last_ns_sent; 
9627 +       __u32 last_ra_rcvd;
9628 +       __u32 interval; /* ra interval in milliseconds, 0 if not set */ 
9629 +       int glob_addr; /*Whether raddr contains also routers global address*/
9630 +       __u8 flags; /* RA flags, for example ha */
9631 +        struct in6_addr CoA;     /* care-off address used with this router */
9632 +       int extra_addr_route;
9633 +};
9634 +
9635 +/* dad could also be RESPECT_DAD for duplicate address detection of
9636 +   new care-of addresses */
9637 +static int dad = 0;
9638 +
9639 +/* Only one choice, nothing else implemented */
9640 +int max_rtr_reach_time = DEF_RTR_POLL_IVAL;
9641 +
9642 +
9643 +int eager_cell_switching = EAGER_CELL_SWITCHING; /* Can be set to 0 via proc */  
9644 +static spinlock_t router_lock; 
9645 +static spinlock_t ho_lock;
9646 +
9647 +static void coa_timer_handler(unsigned long arg);
9648 +static void timer_handler(unsigned long foo);
9649 +static struct router *curr_router = NULL, *next_router = NULL;
9650 +static struct timer_list r_timer = { function: timer_handler };
9651 +static struct timer_list coa_timer = { function: coa_timer_handler };
9652 +#define MAX_ROUTERS 1000
9653 +static LIST_HEAD(rtr_list);
9654 +static int num_routers = 0;
9655 +static struct handoff *_ho = NULL;
9656 +/*
9657 + * Functions for handling the default router list, which movement
9658 + * detection uses for avoiding loops etc.
9659 + */
9660 +
9661 +/* TODO: Send NS to router after MAX interval has passed from last RA */
9662 +static int mipv6_router_state(struct router *rtr) {
9663 +       if (rtr->interval) {
9664 +               if (time_before(jiffies, (rtr->last_ra_rcvd + (rtr->interval * HZ) / 1000)))
9665 +                       return ROUTER_REACHABLE;
9666 +               else
9667 +                       return NOT_REACHABLE;
9668 +       }
9669 +       else
9670 +               if (time_after(jiffies, rtr->last_ra_rcvd + (rtr->lifetime * HZ)))
9671 +                       return NOT_REACHABLE;
9672 +       return ROUTER_REACHABLE;
9673 +}
9674 +
9675 +/* searches for a specific router or any router that is reachable, 
9676 + * if address is NULL. Also deletes obsolete routers.
9677 + */
9678 +static void mipv6_router_gc(void)
9679 +{
9680 +       struct router *curr = NULL;
9681 +       struct list_head *lh, *lh_tmp;
9682 +
9683 +       DEBUG_FUNC();
9684 +
9685 +       list_for_each_safe(lh, lh_tmp, &rtr_list) {
9686 +               curr =  list_entry(lh, struct router, list);
9687 +               if (mipv6_router_state(curr) == NOT_REACHABLE && !curr->is_current) {
9688 +                       num_routers--;
9689 +                       list_del_init(&curr->list);
9690 +                       DEBUG(DBG_DATADUMP, "Deleting unreachable router  %x:%x:%x:%x:%x:%x:%x:%x", 
9691 +                             NIPV6ADDR(&curr->raddr));
9692 +                       kfree(curr);
9693 +               }
9694 +               else {
9695 +                       DEBUG(DBG_DATADUMP, "NOT Deleting router  %x:%x:%x:%x:%x:%x:%x:%x", 
9696 +                             NIPV6ADDR(&curr->raddr));
9697 +               }
9698 +       }
9699 +}
9700 +
9701 +static struct router *mipv6_rtr_get(struct in6_addr *search_addr)
9702 +{
9703 +       struct router *rtr = NULL;
9704 +       struct list_head *lh;
9705 +
9706 +       DEBUG_FUNC();
9707 +
9708 +       if (search_addr == NULL)
9709 +               return NULL;
9710 +       list_for_each(lh, &rtr_list) {
9711 +               rtr = list_entry(lh, struct router, list);
9712 +               if(!ipv6_addr_cmp(search_addr, &rtr->raddr)) {
9713 +                       return rtr;
9714 +               }
9715 +       }
9716 +       return NULL;
9717 +}
9718 +
9719 +/*
9720 + * Adds router to list
9721 + */
9722 +static struct router *mipv6_rtr_add(struct router *nrt)
9723 +{
9724 +
9725 +       struct router *rptr;
9726 +
9727 +       DEBUG_FUNC();
9728 +
9729 +       /* check if someone is trying DoS attack, or we just have some
9730 +           memory leaks... */
9731 +       if (num_routers > MAX_ROUTERS) {
9732 +               DEBUG(DBG_CRITICAL, 
9733 +                     "failed to add new router, MAX_ROUTERS exceeded");
9734 +               return NULL;
9735 +       }
9736 +       
9737 +       rptr = kmalloc(sizeof(struct router), GFP_ATOMIC);
9738 +       if (rptr) {
9739 +               memcpy(rptr, nrt, sizeof(struct router));
9740 +               list_add(&rptr->list, &rtr_list);
9741 +               num_routers++;
9742 +       }
9743 +       DEBUG(DBG_INFO, "Adding router: %x:%x:%x:%x:%x:%x:%x:%x, "
9744 +             "lifetime : %d sec, adv.interval: %d millisec", 
9745 +             NIPV6ADDR(&rptr->raddr), rptr->lifetime, rptr->interval);
9746 +
9747 +       DEBUG(DBG_INFO, "num_routers after addition: %d", num_routers);
9748 +       return rptr;
9749 +}
9750 +
9751 +/* Cleans up the list */
9752 +static void list_free(struct router **curr_router_p)
9753 +{
9754 +       struct router *tmp;
9755 +       struct list_head *lh, *lh_tmp;
9756 +
9757 +       DEBUG_FUNC();
9758 +
9759 +       DEBUG(DBG_INFO, "Freeing the router list");
9760 +       /* set curr_router->prev_router and curr_router NULL */
9761 +       *curr_router_p = NULL;
9762 +       list_for_each_safe(lh, lh_tmp, &rtr_list) {
9763 +               tmp = list_entry(lh, struct router, list);
9764 +               DEBUG(DBG_INFO, "%x:%x:%x:%x:%x:%x:%x:%x",
9765 +                     NIPV6ADDR(&tmp->ll_addr));
9766 +               list_del(&tmp->list);
9767 +               kfree(tmp);
9768 +               num_routers--;
9769 +       }
9770 +}
9771 +
9772 +int rs_state = START;
9773 +
9774 +/* Sends router solicitations to all valid devices 
9775 + * source  = link local address (of sending interface)
9776 + * dstaddr = all routers multicast address
9777 + * Solicitations are sent at an exponentially decreasing rate
9778 + *
9779 + * TODO: send solicitation first at a normal rate (from ipv6) and
9780 + *       after that use the exponentially increasing intervals 
9781 + */
9782 +static int rs_send(void)
9783 +{
9784 +       struct net_device *dev;
9785 +       struct in6_addr raddr, lladdr;
9786 +       struct inet6_dev *in6_dev = NULL;
9787 +       static int num_rs;
9788 +
9789 +       if (rs_state == START) {
9790 +               num_rs = 0;
9791 +               rs_state = CONTINUE;
9792 +       } else if (num_rs++ > MAX_RTR_SOLICITATIONS)
9793 +               return HZ;
9794 +
9795 +       ipv6_addr_all_routers(&raddr);
9796 +       read_lock(&dev_base_lock); 
9797 +
9798 +       /*  Send router solicitations to all interfaces  */
9799 +       for (dev = dev_base; dev; dev = dev->next) {
9800 +               if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ETHER) {
9801 +                       DEBUG(DBG_DATADUMP, "Sending RS to device %s", 
9802 +                             dev->name);
9803 +                       if (!ipv6_get_lladdr(dev, &lladdr)) {
9804 +                               ndisc_send_rs(dev, &lladdr, &raddr);
9805 +                               in6_dev = in6_dev_get(dev);
9806 +                               in6_dev->if_flags |= IF_RS_SENT;
9807 +                               in6_dev_put(in6_dev);
9808 +                       } else {
9809 +                               DEBUG(DBG_DATADUMP, "%s: device doesn't have link-local address!\n", dev->name);
9810 +                               continue;
9811 +                       }
9812 +               }
9813 +               
9814 +       }
9815 +       read_unlock(&dev_base_lock);
9816 +       return RTR_SOLICITATION_INTERVAL;
9817 +}
9818 +
9819 +/* Create a new CoA for MN and also add a route to it if it is still tentative 
9820 +   to allow MN to get packets to the address immediately
9821 + */
9822 +static int form_coa(struct in6_addr *coa, struct in6_addr *pfix, 
9823 +                   int plen, int ifindex)
9824 +{
9825 +       struct net_device *dev;
9826 +       struct inet6_dev *in6_dev;
9827 +       int ret = 0;
9828 +
9829 +       if ((dev = dev_get_by_index(ifindex)) == NULL) {
9830 +               DEBUG(DBG_WARNING, "Device is not present");
9831 +               return -1;
9832 +       }
9833 +       if ((in6_dev = in6_dev_get(dev)) == NULL) {
9834 +               DEBUG(DBG_WARNING, "inet6_dev is not present");
9835 +               dev_put(dev);
9836 +               return -1;
9837 +       }
9838 +       coa->s6_addr32[0] = pfix->s6_addr32[0];
9839 +       coa->s6_addr32[1] = pfix->s6_addr32[1];
9840 +
9841 +       if (ipv6_generate_eui64(coa->s6_addr + 8, dev) &&
9842 +           ipv6_inherit_eui64(coa->s6_addr + 8, in6_dev)) {
9843 +               in6_dev_put(in6_dev);
9844 +               dev_put(dev);
9845 +               return -1;
9846 +       }
9847 +       if (ipv6_chk_addr(coa, dev) == 0) { 
9848 +               DEBUG(DBG_WARNING, "care-of address still tentative");
9849 +               ret = 1;
9850 +       }
9851 +       DEBUG(DBG_INFO, "Formed new CoA:  %x:%x:%x:%x:%x:%x:%x:%x",
9852 +             NIPV6ADDR(coa));
9853 +       
9854 +       in6_dev_put(in6_dev);
9855 +       dev_put(dev);
9856 +       return ret;
9857 +}
9858 +
9859 +static inline int rtr_is_gw(struct router *rtr, struct rt6_info *rt) 
9860 +{
9861 +       return ((rt->rt6i_flags & RTF_GATEWAY) && 
9862 +               !ipv6_addr_cmp(&rt->rt6i_gateway, &rtr->ll_addr));
9863 +}
9864 +
9865 +static inline int is_prefix_route(struct router *rtr, struct rt6_info *rt) 
9866 +{
9867 +       return (!(rt->rt6i_flags & RTF_GATEWAY) &&
9868 +               mipv6_prefix_compare(&rt->rt6i_dst.addr, &rtr->raddr, 
9869 +                                    rtr->pfix_len));
9870 +}
9871 +
9872 +/*
9873 + * Function that determines whether given rt6_info should be destroyed
9874 + * (negative => destroy rt6_info, zero or positive => do nothing) 
9875 + */
9876 +static int mn_route_cleaner(struct rt6_info *rt, void *arg)
9877 +{
9878 +       int type;
9879 +
9880 +       struct router *rtr = (struct router *)arg;
9881 +
9882 +       int ret = -1;
9883 +
9884 +       DEBUG_FUNC();
9885 +       
9886 +       if (!rt || !rtr) {
9887 +               DEBUG(DBG_ERROR, "mn_route_cleaner: rt or rtr NULL");
9888 +               return 0;
9889 +       }
9890 +
9891 +       /* Do not delete routes to local addresses or to multicast
9892 +        * addresses, since we need them to get router advertisements
9893 +        * etc. Multicast addresses are more tricky, but we don't
9894 +        * delete them in any case. The routing mechanism is not optimal for 
9895 +        * multihoming.   
9896 +        *
9897 +        * Also keep all new prefix routes, gateway routes through rtr and
9898 +        * all remaining default routes (including those used for reverse
9899 +        * tunneling)
9900 +        */
9901 +       type = ipv6_addr_type(&rt->rt6i_dst.addr);
9902 +       
9903 +       if ((type & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL)) ||
9904 +           rt->rt6i_dev == &loopback_dev || rtr_is_gw(rtr, rt) ||
9905 +           is_prefix_route(rtr, rt) || (rt->rt6i_flags & RTF_DEFAULT))  
9906 +               ret = 0;
9907 +       
9908 +       /*   delete all others */
9909 +
9910 +       if (rt->rt6i_dev != &loopback_dev) {
9911 +               DEBUG(DEBUG_MDETECT, 
9912 +                     "%s route:\n"
9913 +                     "dev: %s,\n"
9914 +                     "gw: %x:%x:%x:%x:%x:%x:%x:%x,\n"
9915 +                     "flags: %x,\n"
9916 +                     "metric: %d,\n"
9917 +                     "src: %x:%x:%x:%x:%x:%x:%x:%x,\n"
9918 +                     "dst: %x:%x:%x:%x:%x:%x:%x:%x,\n"
9919 +                     "plen: %d\n",
9920 +                     (ret ? "Deleting" : "Keeping"),
9921 +                     rt->rt6i_dev->name,              
9922 +                     NIPV6ADDR(&rt->rt6i_gateway),            
9923 +                     rt->rt6i_flags,
9924 +                     rt->rt6i_metric,
9925 +                     NIPV6ADDR(&rt->rt6i_src.addr),
9926 +                     NIPV6ADDR(&rt->rt6i_dst.addr),
9927 +                     rt->rt6i_dst.plen);
9928 +       }
9929 +       return ret;
9930 +}
9931 +
9932 +/* 
9933 + * Deletes old routes 
9934 + */
9935 +static __inline__ void delete_routes(struct router *rtr)
9936 +{
9937 +       DEBUG_FUNC();
9938 +
9939 +       /* Routing table is locked to ensure that nobody uses its */  
9940 +       write_lock_bh(&rt6_lock);
9941 +       DEBUG(DBG_INFO, "mipv6: Purging routes");
9942 +       /*  TODO: Does not prune, should it?  */
9943 +       fib6_clean_tree(&ip6_routing_table, 
9944 +                       mn_route_cleaner, 0, rtr);
9945 +       write_unlock_bh(&rt6_lock);
9946 +
9947 +}
9948 +
9949 +
9950 +static __inline__ void delete_coas(struct router *rtr)
9951 +{
9952 +       struct net_device *dev;
9953 +       struct inet6_dev *idev;
9954 +       struct inet6_ifaddr *ifa;
9955 +
9956 +       dev = dev_get_by_index(rtr->ifindex);
9957 +       if (!dev)
9958 +               return;
9959 +
9960 +       idev = in6_dev_get(dev);
9961 +       
9962 +       if (idev) {
9963 +               read_lock_bh(&idev->lock);
9964 +               ifa = idev->addr_list;
9965 +               while (ifa) {
9966 +                       int keep; 
9967 +                       spin_lock(&ifa->lock);
9968 +                       
9969 +                       keep = (ifa->flags&(IFA_F_PERMANENT|IFA_F_HOMEADDR) ||
9970 +                               !ipv6_addr_cmp(&ifa->addr, &rtr->CoA));
9971 +                       
9972 +                       spin_unlock(&ifa->lock);
9973 +                       
9974 +                       if (keep)
9975 +                               ifa = ifa->if_next;
9976 +                       else {
9977 +                               in6_ifa_hold(ifa);
9978 +                               read_unlock_bh(&idev->lock);
9979 +                               
9980 +                               ipv6_del_addr(ifa);
9981 +                               
9982 +                               read_lock_bh(&idev->lock);
9983 +                               ifa = idev->addr_list;
9984 +                       }
9985 +               }
9986 +               read_unlock_bh(&idev->lock);
9987 +               in6_dev_put(idev);
9988 +       }
9989 +       dev_put(dev);
9990 +}
9991 +
9992 +int next_mdet_state[3][3] = {{CURR_RTR_OK, NO_RTR, NO_RTR},
9993 +                            {CURR_RTR_OK, CURR_RTR_OK, NO_RTR},
9994 +                            {CURR_RTR_OK, CURR_RTR_OK, RTR_SUSPECT}};
9995
9996 +char *states[3] = {"NO_RTR", "RTR_SUSPECT", "CURR_RTR_OK"};
9997 +char *events[3] = {"RA_RCVD", "NA_RCVD", "TIMEOUT"};
9998 +
9999 +/* State transitions
10000 + * NO_RTR, RA_RCVD -> CURR_RTR_OK
10001 + * NO_RTR, NA_RCVD -> NO_RTR
10002 + * NO_RTR, TIMEOUT -> NO_RTR
10003 +
10004 + * RTR_SUSPECT, RA_RCVD -> CURR_RTR_OK
10005 + * RTR_SUSPECT, NA_RCVD -> CURR_RTR_OK
10006 + * RTR_SUSPECT, TIMEOUT -> NO_RTR
10007 +
10008 + * CURR_RTR_OK, RA_RCVD -> CURR_RTR_OK
10009 + * CURR_RTR_OK, NA_RCVD -> CURR_RTR_OK
10010 + * CURR_RTR_OK, TIMEOUT -> RTR_SUSPECT
10011 + */
10012 +static int _curr_state = NO_RTR;
10013 +
10014 +#if 0
10015 +static int get_mdet_state(void){
10016 +       int state;
10017 +       spin_lock_bh(&router_lock); 
10018 +       state = _curr_state;
10019 +       spin_unlock_bh(&router_lock);
10020 +       return state;
10021 +}
10022 +#endif
10023 +
10024 +/* Needs to be called with router_lock locked */
10025 +static int mdet_statemachine(int event)
10026 +{
10027 +       
10028 +       if (event > 2 || _curr_state > 2) {
10029 +              DEBUG(DBG_ERROR, "Got illegal event or curr_state");
10030 +              return -1;
10031 +       }
10032 +
10033 +       DEBUG(DBG_DATADUMP, "Got event %s and curr_state is %s", 
10034 +             events[event], states[_curr_state]); 
10035 +       
10036 +       _curr_state = next_mdet_state[_curr_state][event];
10037 +       DEBUG(DBG_DATADUMP, "Next state is %s", states[_curr_state]);
10038 +       return _curr_state;
10039 +}
10040 +
10041 +static void mipv6_do_ll_dad(int ifindex)
10042 +{
10043 +       struct net_device *dev = dev_get_by_index(ifindex);
10044 +       if (dev) {
10045 +               struct in6_addr lladdr;
10046 +               struct inet6_ifaddr *ifa;
10047 +               if (!ipv6_get_lladdr(dev, &lladdr) &&
10048 +                   (ifa = ipv6_get_ifaddr(&lladdr, dev)) != NULL) {
10049 +                       spin_lock_bh(&ifa->lock);
10050 +                       if (!(ifa->flags & IFA_F_TENTATIVE)) {
10051 +                               ifa->flags |= IFA_F_TENTATIVE;
10052 +                               spin_unlock_bh(&ifa->lock);
10053 +                               addrconf_dad_start(ifa, 0);
10054 +                       } else
10055 +                               spin_unlock_bh(&ifa->lock);
10056 +
10057 +               }
10058 +               dev_put(dev);
10059 +       }
10060 +}
10061 +/* 
10062 + * Changes the router, called from ndisc.c if mipv6_router_event 
10063 + * returns true.
10064 + */
10065 +
10066 +static void mipv6_change_router(void)
10067 +{
10068 +       struct in6_addr coa;
10069 +       int ret, ifindex;
10070 +       
10071 +       DEBUG_FUNC(); 
10072 +
10073 +       
10074 +       if (next_router == NULL) 
10075 +               return;
10076 +       
10077 +       spin_lock(&router_lock);
10078 +
10079 +
10080 +       if (curr_router != NULL && 
10081 +           !ipv6_addr_cmp(&curr_router->ll_addr, &next_router->ll_addr)) {
10082 +               DEBUG(DBG_INFO,"Trying to handoff from: "
10083 +                     "%x:%x:%x:%x:%x:%x:%x:%x",
10084 +                     NIPV6ADDR(&curr_router->ll_addr));
10085 +               DEBUG(DBG_INFO,"Trying to handoff to: "
10086 +                     "%x:%x:%x:%x:%x:%x:%x:%x",
10087 +                     NIPV6ADDR(&next_router->ll_addr));
10088 +               next_router = NULL; /* Let's not leave dangling pointers */
10089 +               spin_unlock(&router_lock);
10090 +               return;
10091 +        }
10092 +       ret = form_coa(&next_router->CoA, &next_router->raddr, 
10093 +                      next_router->pfix_len, next_router->ifindex);
10094 +       if (ret < 0) {
10095 +               DEBUG(DBG_ERROR, "handoff: Creation of coa failed");
10096 +               spin_unlock(&router_lock);
10097 +               return;
10098 +       } else if (ret > 0)
10099 +               next_router->flags |= COA_TENTATIVE;
10100 +
10101 +       mdet_statemachine(RA_RCVD); /* TODO: What if DAD fails... */
10102 +       if (next_router->interval)
10103 +               mod_timer(&r_timer, jiffies + 
10104 +                         (next_router->interval * HZ)/1000);
10105 +       else
10106 +               mod_timer(&r_timer, jiffies + max_rtr_reach_time * HZ);
10107 +       
10108 +
10109 +       if (ret == 0) {
10110 +               ipv6_addr_copy(&coa, &next_router->CoA);
10111 +               ifindex = next_router->ifindex;
10112 +               spin_unlock(&router_lock);
10113 +               mipv6_mdet_finalize_ho(&coa, ifindex);
10114 +               return;
10115 +       }
10116 +       spin_unlock(&router_lock);
10117 +
10118 +}
10119 +static unsigned long ns_send(void)
10120 +{
10121 +       struct neighbour *neigh;
10122 +       struct net_device *dev;
10123 +       struct in6_addr *raddr;
10124 +
10125 +       DEBUG(DBG_DATADUMP, "Sending Neighbour solicitation to default router to verify its reachability");
10126 +       if (!curr_router) 
10127 +               return HZ;
10128 +       if ((dev = dev_get_by_index(curr_router->ifindex)) == NULL)
10129 +               return HZ;
10130 +       if ((neigh = ndisc_get_neigh(dev, &curr_router->ll_addr)) == NULL) {
10131 +               dev_put(dev);
10132 +               return HZ;
10133 +       }
10134 +       if (curr_router->glob_addr)
10135 +               raddr = &curr_router->raddr;
10136 +       else 
10137 +               raddr = &curr_router->ll_addr;
10138 +
10139 +       curr_router->last_ns_sent = jiffies;
10140 +       ndisc_send_ns(dev, neigh, raddr, raddr, NULL);  
10141 +
10142 +       neigh_release(neigh);
10143 +       dev_put(dev);
10144 +       return HZ/5; /* Wait 200ms for a reply */
10145 +}
10146 +
10147 +static int na_rcvd(void)
10148 +{      
10149 +       int neigh_ok = 0;
10150 +       struct neighbour *neigh;
10151 +       struct net_device *dev;
10152 +
10153 +       if (!curr_router) 
10154 +               return 0;
10155 +       if ((dev = dev_get_by_index(curr_router->ifindex)) == NULL)
10156 +               return 0;
10157 +       if ((neigh = ndisc_get_neigh(dev, &curr_router->ll_addr)) == NULL) {
10158 +               dev_put(dev);
10159 +               return 0;
10160 +       }
10161 +       if (neigh->flags & NTF_ROUTER && 
10162 +           (time_after(neigh->confirmed, curr_router->last_ns_sent) || 
10163 +            neigh->confirmed == curr_router->last_ns_sent)) {
10164 +               neigh_ok = 1;
10165 +               DEBUG(DBG_DATADUMP, "Mdetect event: NA rcvd from curr rtr");
10166 +       } else
10167 +               DEBUG(DBG_DATADUMP, "Mdetect event: NA NOT rcvd from curr rtr within time limit");
10168 +       neigh_release(neigh);
10169 +       dev_put(dev);
10170 +       return neigh_ok;
10171 +}
10172 +
10173 +static void coa_timer_handler(unsigned long dummy)
10174 +{
10175 +
10176 +       spin_lock_bh(&ho_lock);
10177 +       if (_ho) {
10178 +               DEBUG(DBG_INFO, "Starting handoff after DAD");
10179 +               mipv6_mobile_node_moved(_ho);
10180 +               kfree(_ho);
10181 +               _ho = NULL;
10182 +       }
10183 +       spin_unlock_bh(&ho_lock);
10184 +}
10185 +static void timer_handler(unsigned long foo)
10186 +{
10187 +       unsigned long timeout;
10188 +       int state;
10189 +       spin_lock_bh(&router_lock);
10190 +       
10191 +       if (_curr_state != NO_RTR)
10192 +               rs_state = START;
10193 +
10194 +       if (_curr_state == RTR_SUSPECT && na_rcvd()) {
10195 +               state = mdet_statemachine(NA_RCVD);
10196 +               timeout = curr_router->interval ? curr_router->interval : max_rtr_reach_time * HZ;
10197 +       } else { 
10198 +               state =  mdet_statemachine(TIMEOUT);
10199 +               if (state == NO_RTR)
10200 +                       timeout = rs_send();
10201 +               else  /* RTR_SUSPECT */
10202 +                       timeout = ns_send();
10203 +       }
10204 +       if (!timeout)
10205 +               timeout = HZ;
10206 +
10207 +       mipv6_router_gc();
10208 +       mod_timer(&r_timer, jiffies + timeout);
10209 +       spin_unlock_bh(&router_lock);
10210 +}
10211 +
10212 +/**
10213 + * mipv6_get_care_of_address - get node's care-of primary address
10214 + * @homeaddr: one of node's home addresses
10215 + * @coaddr: buffer to store care-of address
10216 + *
10217 + * Stores the current care-of address in the @coaddr, assumes
10218 + * addresses in EUI-64 format.  Since node might have several home
10219 + * addresses caller MUST supply @homeaddr.  If node is at home
10220 + * @homeaddr is stored in @coaddr.  Returns 0 on success, otherwise a
10221 + * negative value.
10222 + **/
10223 +int mipv6_get_care_of_address(
10224 +       struct in6_addr *homeaddr, struct in6_addr *coaddr)
10225 +{
10226 +       
10227 +       DEBUG_FUNC();
10228 +
10229 +       if (homeaddr == NULL)
10230 +               return -1;
10231 +       spin_lock_bh(&router_lock);
10232 +       if (curr_router == NULL || mipv6_mn_is_at_home(homeaddr) || 
10233 +           mipv6_prefix_compare(homeaddr, &curr_router->raddr, 64) || 
10234 +           curr_router->flags&COA_TENTATIVE) {
10235 +               DEBUG(DBG_INFO,
10236 +                     "mipv6_get_care_of_address: returning home address");
10237 +               ipv6_addr_copy(coaddr, homeaddr);
10238 +               spin_unlock_bh(&router_lock);
10239 +               return 0;
10240 +
10241 +       }
10242 +
10243 +       /* At home or address check failure probably due to dad wait */
10244 +       if (mipv6_prefix_compare(&curr_router->raddr, homeaddr, 
10245 +                                curr_router->pfix_len) 
10246 +                                || (dad == RESPECT_DAD && 
10247 +                                    (ipv6_chk_addr(coaddr, NULL) == 0))) { 
10248 +               ipv6_addr_copy(coaddr, homeaddr);
10249 +       } else { 
10250 +               ipv6_addr_copy(coaddr, &curr_router->CoA);
10251 +       }
10252 +
10253 +       spin_unlock_bh(&router_lock);
10254 +       return 0;
10255 +}
10256 +
10257 +int mipv6_mdet_del_if(int ifindex)
10258 +{
10259 +       struct router *curr = NULL;
10260 +       struct list_head *lh, *lh_tmp;
10261 +
10262 +       spin_lock_bh(&router_lock);
10263 +       list_for_each_safe(lh, lh_tmp, &rtr_list) {
10264 +               curr =  list_entry(lh, struct router, list);
10265 +               if (curr->ifindex == ifindex) {
10266 +                       num_routers--;
10267 +                       list_del_init(&curr->list);
10268 +                       DEBUG(DBG_DATADUMP, "Deleting router  %x:%x:%x:%x:%x:%x:%x:%x on interface %d", 
10269 +                             NIPV6ADDR(&curr->raddr), ifindex);
10270 +                       if (curr_router == curr)
10271 +                               curr_router = NULL;
10272 +                       kfree(curr);
10273 +               }
10274 +       }
10275 +       spin_unlock_bh(&router_lock);
10276 +       return 0;
10277 +}
10278 +
10279 +void mipv6_mdet_retrigger_ho(void)
10280 +{
10281 +       struct handoff ho;
10282 +
10283 +       spin_lock_bh(&router_lock);
10284 +       if (curr_router != NULL) {
10285 +               ho.coa = &curr_router->CoA;
10286 +               ho.plen = curr_router->pfix_len;
10287 +               ho.ifindex = curr_router->ifindex;
10288 +               ipv6_addr_copy(&ho.rtr_addr, &curr_router->raddr);
10289 +               ho.home_address = (curr_router->glob_addr && 
10290 +                                  curr_router->flags&ND_RA_FLAG_HA);
10291 +       }
10292 +       spin_unlock_bh(&router_lock);
10293 +       mipv6_mobile_node_moved(&ho);
10294 +}
10295 +
10296 +void mipv6_mdet_set_curr_rtr_reachable(int reachable)
10297 +{
10298 +       spin_lock_bh(&router_lock);
10299 +       if (curr_router != NULL) {
10300 +               curr_router->reachable = reachable;
10301 +       }
10302 +       spin_unlock_bh(&router_lock);
10303 +
10304 +}
10305 +
10306 +int mipv6_mdet_finalize_ho(const struct in6_addr *coa, const int ifindex)
10307 +{
10308 +       int dummy;
10309 +       struct handoff ho;
10310 +       struct router *tmp;
10311 +       struct net_device *dev; 
10312 +       struct in6_addr ll_addr;
10313 +
10314 +       spin_lock_bh(&router_lock);
10315 +
10316 +       if (!next_router) {
10317 +               spin_unlock_bh(&router_lock);
10318 +               return 0;
10319 +       }
10320 +
10321 +       dev = dev_get_by_index(next_router->ifindex);
10322 +
10323 +       if (ipv6_get_lladdr(dev, &ll_addr) == 0) {
10324 +               if (ipv6_addr_cmp(&ll_addr, coa) == 0)
10325 +                       DEBUG(DBG_INFO, "DAD for link local address completed");
10326 +               next_router->flags &= ~LLADDR_TENTATIVE;
10327 +       }
10328 +
10329 +       dev_put(dev);
10330 +
10331 +       if (mipv6_prefix_compare(coa, &next_router->CoA, 
10332 +                                next_router->pfix_len)) {
10333 +               DEBUG(DBG_INFO, "DAD for Care-of address completed");
10334 +               next_router->flags &= ~COA_TENTATIVE;
10335 +       }
10336 +       if (!(next_router->flags&LLADDR_TENTATIVE) && !(next_router->flags&COA_TENTATIVE)) {
10337 +               DEBUG(DBG_INFO, "%s: Proceeding with handoff after DAD\n", __FUNCTION__);
10338 +               tmp = curr_router;
10339 +               curr_router = next_router;
10340 +               curr_router->is_current = 1;
10341 +               next_router = NULL; 
10342 +               curr_router->flags &= ~COA_TENTATIVE; 
10343 +               delete_routes(curr_router);
10344 +               delete_coas(curr_router);
10345 +               if (tmp) {
10346 +                       struct net_device *dev_old = dev_get_by_index(tmp->ifindex);
10347 +                       struct rt6_info *rt = NULL;
10348 +                       if (dev_old) {
10349 +                               rt = rt6_get_dflt_router(&tmp->ll_addr, dev_old);
10350 +                               dev_put(dev_old);
10351 +                       }
10352 +                       if (rt)
10353 +                               ip6_del_rt(rt, NULL);
10354 +                       tmp->is_current = 0;
10355 +               }
10356 +
10357 +               ma_ctl_upd_iface(curr_router->ifindex, MA_IFACE_CURRENT, &dummy);
10358 +               ma_ctl_upd_iface(curr_router->ifindex, MA_IFACE_CURRENT, &dummy);
10359 +
10360 +
10361 +               ho.coa = &curr_router->CoA;
10362 +               ho.plen = curr_router->pfix_len;
10363 +               ho.ifindex = curr_router->ifindex;
10364 +               ipv6_addr_copy(&ho.rtr_addr, &curr_router->raddr);
10365 +               ho.home_address = (curr_router->glob_addr && 
10366 +                                   curr_router->flags&ND_RA_FLAG_HA);
10367 +               
10368 +               spin_unlock_bh(&router_lock);
10369 +               mipv6_mobile_node_moved(&ho);
10370 +       } else 
10371 +               spin_unlock_bh(&router_lock);
10372 +       return 0;
10373 +}
10374 +/* Decides whether router candidate is the same router as current rtr
10375 + * based on prefix / global addresses of the routers and their link local 
10376 + * addresses 
10377 + */
10378 +static int is_current_rtr(struct router *nrt, struct router *crt)
10379 +{
10380 +       DEBUG_FUNC();
10381 +       
10382 +       DEBUG(DEBUG_MDETECT, "Current router: "
10383 +             "%x:%x:%x:%x:%x:%x:%x:%x and", NIPV6ADDR(&crt->raddr));
10384 +       DEBUG(DEBUG_MDETECT, "Candidate router: "
10385 +             "%x:%x:%x:%x:%x:%x:%x:%x", NIPV6ADDR(&nrt->raddr));
10386 +
10387 +       return (!ipv6_addr_cmp(&nrt->raddr,&crt->raddr) && 
10388 +               !ipv6_addr_cmp(&nrt->ll_addr, &crt->ll_addr));
10389 +}
10390 +
10391 +/* 
10392 + * Change next router to nrtr
10393 + * Returns 1, if router has been changed.
10394 + */ 
10395 +
10396 +static int change_next_rtr(struct router *nrtr, struct router *ortr)
10397 +{
10398 +       int changed = 0;
10399 +       DEBUG_FUNC();
10400 +
10401 +       if (!next_router || ipv6_addr_cmp(&nrtr->raddr, &next_router->raddr)) {
10402 +               changed = 1;
10403 +       }
10404 +       next_router = nrtr;
10405 +       return changed;
10406 +}
10407 +static int clean_ncache(struct router *nrt, struct router *ort, int same_if)
10408 +{
10409 +       struct net_device *ortdev;
10410 +       DEBUG_FUNC();
10411 +
10412 +       /* Always call ifdown after a handoff to ensure proper routing */
10413 +       
10414 +       if (!ort) 
10415 +               return 0;
10416 +       if ((ortdev = dev_get_by_index(ort->ifindex)) == NULL) {
10417 +               DEBUG(DBG_WARNING, "Device is not present");
10418 +               return -1;
10419 +       }
10420 +       neigh_ifdown(&nd_tbl, ortdev);
10421 +       dev_put(ortdev);        
10422 +       return 0;
10423 +}
10424 +
10425 +static int mdet_get_if_preference(int ifi)
10426 +{
10427 +       int pref = 0;
10428 +
10429 +       DEBUG_FUNC();
10430 +
10431 +       pref = ma_ctl_get_preference(ifi);
10432 +
10433 +       DEBUG(DEBUG_MDETECT, "ifi: %d preference %d", ifi, pref);
10434 +
10435 +       return pref;
10436 +}
10437 +
10438 +/*
10439 + * Called from mipv6_mn_ra_rcv to determine whether to do a handoff. 
10440 + */
10441 +static int mipv6_router_event(struct router *rptr)
10442 +{
10443 +       struct router *nrt = NULL;
10444 +       int new_router = 0, same_if = 1;
10445 +       int oldstate = _curr_state;
10446 +       int addrtype = ipv6_addr_type(&rptr->raddr);
10447 +
10448 +       DEBUG_FUNC();
10449 +
10450 +       if (rptr->lifetime == 0)
10451 +               return MIPV6_IGN_RTR;
10452 +       DEBUG(DEBUG_MDETECT, "Received a RA from router: "
10453 +             "%x:%x:%x:%x:%x:%x:%x:%x", NIPV6ADDR(&rptr->raddr));
10454 +       spin_lock(&router_lock);
10455 +       
10456 +       /* Add or update router entry */
10457 +       if ((nrt = mipv6_rtr_get(&rptr->raddr)) == NULL) {
10458 +               if (addrtype == IPV6_ADDR_ANY || (nrt = mipv6_rtr_add(rptr)) == NULL) {
10459 +                               spin_unlock(&router_lock);
10460 +                               return MIPV6_IGN_RTR;
10461 +               }
10462 +               DEBUG(DBG_INFO, "Router not on list,adding it to the list"); 
10463 +               new_router = 1;
10464 +       }
10465 +       nrt->last_ra_rcvd = jiffies;
10466 +       nrt->state = ROUTER_REACHABLE;
10467 +       nrt->interval = rptr->interval;
10468 +       nrt->lifetime = rptr->lifetime;
10469 +       nrt->ifindex = rptr->ifindex;
10470 +       nrt->flags = rptr->flags;
10471 +       nrt->glob_addr = rptr->glob_addr;
10472 +
10473 +       /* Whether from current router */
10474 +       if (curr_router && curr_router->reachable && 
10475 +           is_current_rtr(nrt, curr_router)) {
10476 +               if (nrt->interval)
10477 +                       mod_timer(&r_timer, jiffies + (nrt->interval * HZ)/1000);
10478 +               else
10479 +                       mod_timer(&r_timer, jiffies + max_rtr_reach_time * HZ);
10480 +               mdet_statemachine(RA_RCVD);
10481 +               spin_unlock(&router_lock);
10482 +               return MIPV6_ADD_RTR;
10483 +       } else if (oldstate == NO_RTR) {
10484 +               rt6_purge_dflt_routers(0); /* For multiple interface case */
10485 +               DEBUG(DBG_INFO, "No router or router not reachable, switching to new one");   
10486 +               goto handoff;
10487 +       }
10488 +       if (!curr_router) { 
10489 +               /* Startup */
10490 +               goto handoff;
10491 +       }
10492 +       /* Router behind same interface as current one ?*/
10493 +       same_if = (nrt->ifindex == curr_router->ifindex);
10494 +       /* Switch to new router behind same interface if eager cell 
10495 +        *  switching is used or if the interface is preferred
10496 +        */
10497 +       if ((new_router && eager_cell_switching && same_if) ||
10498 +           (mdet_get_if_preference(nrt->ifindex) > 
10499 +            mdet_get_if_preference(curr_router->ifindex))) {
10500 +               DEBUG(DBG_INFO, "Switching to new router.");
10501 +               goto handoff;
10502 +       }
10503 +       
10504 +       /* No handoff, don't add default route */
10505 +       DEBUG(DEBUG_MDETECT, "Ignoring RA");
10506 +       spin_unlock(&router_lock);
10507 +       return MIPV6_IGN_RTR;
10508 +handoff:
10509 +       clean_ncache(nrt, curr_router, same_if);
10510 +       nrt->reachable = 1;
10511 +       if (same_if && change_next_rtr(nrt, curr_router)) {
10512 +               mipv6_do_ll_dad(nrt->ifindex);
10513 +               nrt->flags |= LLADDR_TENTATIVE;
10514 +       }
10515 +       spin_unlock(&router_lock);
10516 +
10517 +       return MIPV6_CHG_RTR;
10518 +}      
10519 +
10520 +/* 
10521 + * Called from ndisc.c's router_discovery.
10522 + */
10523 +
10524 +static inline int ret_to_ha(struct in6_addr *addr)
10525 +{
10526 +       int res = 0;
10527 +       struct mn_info *minfo;
10528 +       read_lock(&mn_info_lock);
10529 +       minfo = mipv6_mninfo_get_by_ha(addr);
10530 +       if (minfo != NULL) {
10531 +               spin_lock(&minfo->lock);
10532 +               if (minfo->has_home_reg) {
10533 +                       res = 1;
10534 +               }
10535 +               spin_unlock(&minfo->lock);
10536 +       }
10537 +       read_unlock(&mn_info_lock);
10538 +       return res;
10539 +}
10540 +
10541 +static int mipv6_mn_ra_rcv(struct sk_buff *skb, struct ndisc_options *ndopts)
10542 +{
10543 +       int ifi = ((struct inet6_skb_parm *)skb->cb)->iif;
10544 +       struct ra_msg *ra = (struct ra_msg *) skb->h.raw;
10545 +       struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
10546 +       struct router nrt;
10547 +       struct in6_addr *ha = NULL;
10548 +       u8 *lladdr = NULL;
10549 +       int res;
10550 +       DEBUG_FUNC();
10551 +
10552 +       memset(&nrt, 0, sizeof(struct router));
10553 +
10554 +       if (ra->icmph.icmp6_home_agent) {
10555 +               nrt.flags |= ND_RA_FLAG_HA;
10556 +               DEBUG(DBG_DATADUMP, "RA has ND_RA_FLAG_HA up");
10557 +       }
10558 +
10559 +       if (ra->icmph.icmp6_addrconf_managed) {
10560 +               nrt.flags |= ND_RA_FLAG_MANAGED;
10561 +               DEBUG(DBG_DATADUMP, "RA has ND_RA_FLAG_MANAGED up");
10562 +       }
10563 +
10564 +       if (ra->icmph.icmp6_addrconf_other) {
10565 +               nrt.flags |= ND_RA_FLAG_OTHER;
10566 +               DEBUG(DBG_DATADUMP, "RA has ND_RA_FLAG_OTHER up");
10567 +       }
10568 +
10569 +       ipv6_addr_copy(&nrt.ll_addr, saddr);
10570 +       nrt.ifindex = ifi;
10571 +       nrt.lifetime = ntohs(ra->icmph.icmp6_rt_lifetime);
10572 +
10573 +       if (ndopts->nd_opts_src_lladdr) {
10574 +               lladdr = (u8 *) ndopts->nd_opts_src_lladdr+2;
10575 +               nrt.link_addr_len = skb->dev->addr_len;
10576 +               memcpy(nrt.link_addr, lladdr, nrt.link_addr_len);
10577 +       }
10578 +       if (ndopts->nd_opts_pi) {
10579 +               struct nd_opt_hdr *p;
10580 +               for (p = ndopts->nd_opts_pi;
10581 +                    p;
10582 +                    p = ndisc_next_option(p, ndopts->nd_opts_pi_end)) {
10583 +                       struct prefix_info *pinfo;
10584 +                       int update = 0;
10585 +
10586 +                       pinfo = (struct prefix_info *) p;
10587 +
10588 +                       if (!pinfo->autoconf)
10589 +                               continue;
10590 +
10591 +                       if ((pinfo->router_address && 
10592 +                            (update = ret_to_ha(&pinfo->prefix))) ||
10593 +                           ipv6_addr_type(&nrt.raddr) != IPV6_ADDR_UNICAST) {
10594 +                               ipv6_addr_copy(&nrt.raddr, &pinfo->prefix);
10595 +                               nrt.pfix_len = pinfo->prefix_len;
10596 +                               if (pinfo->router_address)
10597 +                                       nrt.glob_addr = 1;
10598 +                               else
10599 +                                       nrt.glob_addr = 0;
10600 +                               if (update)
10601 +                                       ha = &pinfo->prefix;
10602 +                               DEBUG(DBG_DATADUMP, "Address of the received "
10603 +                                     "prefix info option: %x:%x:%x:%x:%x:%x:%x:%x", 
10604 +                                     NIPV6ADDR(&nrt.raddr));
10605 +                               DEBUG(DBG_DATADUMP, "the length of the prefix is %d", 
10606 +                                     nrt.pfix_len);
10607 +                       }
10608 +               }
10609 +       }
10610 +       if (ndopts->nd_opts_rai) {                      
10611 +               nrt.interval = ntohl(*(__u32 *)(ndopts->nd_opts_rai+4));
10612 +               DEBUG(DBG_DATADUMP, 
10613 +                     "received router interval option with interval : %d ",
10614 +                     nrt.interval / HZ);
10615 +
10616 +               if (nrt.interval > MAX_RADV_INTERVAL) {
10617 +                       nrt.interval = 0;
10618 +                       DEBUG(DBG_DATADUMP, "but we are using: %d, "
10619 +                             "because interval>MAX_RADV_INTERVAL",
10620 +                             nrt.interval / HZ);
10621 +               }
10622 +       }
10623 +
10624 +       res = mipv6_router_event(&nrt);
10625 +       
10626 +       if (ha && lladdr) {
10627 +               mipv6_mn_ha_nd_update(__dev_get_by_index(ifi), ha, lladdr);
10628 +       }
10629 +       return res;
10630 +}
10631 +
10632 +int __init mipv6_initialize_mdetect(void)
10633 +{
10634 +
10635 +       DEBUG_FUNC();
10636 +
10637 +       spin_lock_init(&router_lock);
10638 +       spin_lock_init(&ho_lock);
10639 +       init_timer(&coa_timer);
10640 +       init_timer(&r_timer);
10641 +       r_timer.expires = jiffies + HZ;
10642 +       add_timer(&r_timer);
10643 +
10644 +       /* Actual HO, also deletes old routes after the addition of new ones 
10645 +          in ndisc */
10646 +       MIPV6_SETCALL(mipv6_change_router, mipv6_change_router);
10647 +
10648 +       MIPV6_SETCALL(mipv6_ra_rcv, mipv6_mn_ra_rcv);
10649 +
10650 +       return 0;
10651 +}
10652 +
10653 +int __exit mipv6_shutdown_mdetect()
10654 +{
10655 +
10656 +       DEBUG_FUNC();
10657 +
10658 +       MIPV6_RESETCALL(mipv6_ra_rcv);
10659 +       MIPV6_RESETCALL(mipv6_change_router);
10660 +       spin_lock_bh(&router_lock);
10661 +       spin_lock(&ho_lock);
10662 +       del_timer(&coa_timer);
10663 +       del_timer(&r_timer);
10664 +       /* Free the memory allocated by router list */
10665 +       list_free(&curr_router);
10666 +       if (_ho)
10667 +               kfree(_ho);
10668 +       spin_unlock(&ho_lock);
10669 +       spin_unlock_bh(&router_lock);
10670 +       return 0;
10671 +}
10672 --- /dev/null
10673 +++ linux-2.4.27/net/ipv6/mobile_ip6/mdetect.h
10674 @@ -0,0 +1,37 @@
10675 +/*
10676 + *      MIPL Mobile IPv6 Movement detection module header file
10677 + *
10678 + *      $Id$
10679 + *
10680 + *      This program is free software; you can redistribute it and/or
10681 + *      modify it under the terms of the GNU General Public License
10682 + *      as published by the Free Software Foundation; either version
10683 + *      2 of the License, or (at your option) any later version.
10684 + */
10685 +
10686 +#ifndef _MDETECT_H
10687 +#define _MDETECT_H
10688 +
10689 +struct handoff {
10690 +       int home_address; /* Is the coa a home address */
10691 +       int ifindex;
10692 +       int plen;
10693 +       struct in6_addr *coa;
10694 +       struct in6_addr rtr_addr; /* Prefix or rtr address if coa is home address */
10695 +};
10696 +
10697 +int mipv6_initialize_mdetect(void);
10698 +
10699 +int mipv6_shutdown_mdetect(void);
10700 +
10701 +int mipv6_get_care_of_address(struct in6_addr *homeaddr, struct in6_addr *coa);
10702 +
10703 +int mipv6_mdet_del_if(int ifindex);
10704 +
10705 +int mipv6_mdet_finalize_ho(const struct in6_addr *coa, const int ifindex);
10706 +
10707 +void mipv6_mdet_retrigger_ho(void);
10708 +
10709 +void mipv6_mdet_set_curr_rtr_reachable(int reachable);
10710 +
10711 +#endif /* _MDETECT_H */
10712 --- /dev/null
10713 +++ linux-2.4.27/net/ipv6/mobile_ip6/mipv6_icmp.c
10714 @@ -0,0 +1,342 @@
10715 +/**
10716 + * Generic icmp routines
10717 + *
10718 + * Authors:
10719 + * Jaakko Laine <medved@iki.fi>,
10720 + * Ville Nuorvala <vnuorval@tcs.hut.fi> 
10721 + *
10722 + * $Id$
10723 + *
10724 + * This program is free software; you can redistribute it and/or
10725 + * modify it under the terms of the GNU General Public License
10726 + * as published by the Free Software Foundation; either version
10727 + * 2 of the License, or (at your option) any later version.
10728 + */
10729 +
10730 +#include <linux/config.h>
10731 +#include <linux/icmpv6.h>
10732 +#include <net/checksum.h>
10733 +#include <net/ipv6.h>
10734 +#include <net/ip6_route.h>
10735 +#include <net/mipv6.h>
10736 +#include <net/mipglue.h>
10737 +
10738 +#include "debug.h"
10739 +#include "bcache.h"
10740 +#include "mipv6_icmp.h"
10741 +#include "config.h"
10742 +
10743 +struct mipv6_icmpv6_msg {
10744 +       struct icmp6hdr icmph;
10745 +       __u8 *data;
10746 +       struct in6_addr *daddr;
10747 +       int len;
10748 +       __u32 csum;
10749 +};
10750 +
10751 +#define MIPV6_ICMP_HOP_LIMIT 64
10752 +
10753 +static struct socket *mipv6_icmpv6_socket = NULL;
10754 +static __u16 identifier = 0;
10755 +
10756 +int mipv6_icmpv6_no_rcv(struct sk_buff *skb)
10757 +{
10758 +       return 0;
10759 +}
10760 +
10761 +static int mipv6_icmpv6_xmit_holder = -1;
10762 +
10763 +static int mipv6_icmpv6_xmit_lock_bh(void)
10764 +{
10765 +       if (!spin_trylock(&mipv6_icmpv6_socket->sk->lock.slock)) {
10766 +               if (mipv6_icmpv6_xmit_holder == smp_processor_id())
10767 +                       return -EAGAIN;
10768 +               spin_lock(&mipv6_icmpv6_socket->sk->lock.slock);
10769 +       }
10770 +       mipv6_icmpv6_xmit_holder = smp_processor_id();
10771 +       return 0;
10772 +}
10773 +
10774 +static __inline__ int mipv6_icmpv6_xmit_lock(void)
10775 +{
10776 +       int ret;
10777 +       local_bh_disable();
10778 +       ret = mipv6_icmpv6_xmit_lock_bh();
10779 +       if (ret)
10780 +               local_bh_enable();
10781 +       return ret;
10782 +}
10783 +
10784 +static void mipv6_icmpv6_xmit_unlock_bh(void)
10785 +{
10786 +       mipv6_icmpv6_xmit_holder = -1;
10787 +       spin_unlock(&mipv6_icmpv6_socket->sk->lock.slock);
10788 +}
10789 +
10790 +static __inline__ void mipv6_icmpv6_xmit_unlock(void)
10791 +{
10792 +       mipv6_icmpv6_xmit_unlock_bh();
10793 +       local_bh_enable();
10794 +}
10795 +
10796 +
10797 +/**
10798 + * mipv6_icmpv6_dest_unreach - Destination Unreachable ICMP error message handler
10799 + * @skb: buffer containing ICMP error message
10800 + *
10801 + * Special Mobile IPv6 ICMP handling.  If Correspondent Node receives
10802 + * persistent ICMP Destination Unreachable messages for a destination
10803 + * in its Binding Cache, the binding should be deleted.  See draft
10804 + * section 8.8.
10805 + **/
10806 +static int mipv6_icmpv6_rcv_dest_unreach(struct sk_buff *skb)
10807 +{
10808 +       struct icmp6hdr *icmph = (struct icmp6hdr *) skb->h.raw;
10809 +       struct ipv6hdr *ipv6h = (struct ipv6hdr *) (icmph + 1);
10810 +       int left = (skb->tail - skb->h.raw) - sizeof(*icmph)- sizeof(ipv6h);
10811 +       struct ipv6_opt_hdr *eh;
10812 +       struct rt2_hdr *rt2h = NULL;
10813 +       struct in6_addr *daddr = &ipv6h->daddr;
10814 +       struct in6_addr *saddr = &ipv6h->saddr;
10815 +       int hdrlen, nexthdr = ipv6h->nexthdr;
10816 +       struct mipv6_bce bce;
10817 +       DEBUG_FUNC();
10818 +
10819 +       eh = (struct ipv6_opt_hdr *) (ipv6h + 1);
10820 +
10821 +       while (left > 0) {
10822 +               if (nexthdr != NEXTHDR_HOP && nexthdr != NEXTHDR_DEST && 
10823 +                   nexthdr != NEXTHDR_ROUTING)
10824 +                       return 0;
10825 +
10826 +               hdrlen = ipv6_optlen(eh);
10827 +               if (hdrlen > left)
10828 +                       return 0;
10829 +
10830 +               if (nexthdr == NEXTHDR_ROUTING) {
10831 +                       struct ipv6_rt_hdr *rth = (struct ipv6_rt_hdr *) eh;
10832 +
10833 +                       if (rth->type == IPV6_SRCRT_TYPE_2) {
10834 +                               if (hdrlen != sizeof(struct rt2_hdr))
10835 +                                       return 0;
10836 +
10837 +                               rt2h = (struct rt2_hdr *) rth;
10838 +
10839 +                               if (rt2h->rt_hdr.segments_left > 0)
10840 +                                       daddr = &rt2h->addr;
10841 +                               break;
10842 +                       }
10843 +               }
10844 +               /* check for home address option in case this node is a MN */
10845 +               if (nexthdr == NEXTHDR_DEST) {
10846 +                       __u8 *raw = (__u8 *) eh;
10847 +                       __u16 i = 2;
10848 +                       while (1) {
10849 +                               struct mipv6_dstopt_homeaddr *hao;
10850 +                               
10851 +                               if (i + sizeof (*hao) > hdrlen)
10852 +                                       break;
10853 +                               
10854 +                               hao = (struct mipv6_dstopt_homeaddr *) &raw[i];
10855 +                               
10856 +                               if (hao->type == MIPV6_TLV_HOMEADDR &&
10857 +                                   hao->length == sizeof(struct in6_addr)) {
10858 +                                       saddr = &hao->addr;
10859 +                                       break;
10860 +                               }
10861 +                               if (hao->type)
10862 +                                       i += hao->length + 2;
10863 +                               else
10864 +                                       i++;
10865 +                       }
10866 +                       
10867 +               }
10868 +               nexthdr = eh->nexthdr;
10869 +               eh = (struct ipv6_opt_hdr *) ((u8 *) eh + hdrlen);
10870 +               left -= hdrlen;
10871 +       }
10872 +       if (rt2h == NULL) return 0;
10873 +
10874 +       if (mipv6_bcache_get(daddr, saddr, &bce) == 0 && !(bce.flags&HOME_REGISTRATION)) {
10875 +               /* A primitive algorithm for detecting persistent ICMP destination unreachable messages */
10876 +               if (bce.destunr_count &&
10877 +                   time_after(jiffies, 
10878 +                              bce.last_destunr + MIPV6_DEST_UNR_IVAL*HZ)) 
10879 +                       bce.destunr_count = 0;
10880 +
10881 +               bce.destunr_count++;
10882 +
10883 +               mipv6_bcache_icmp_err(daddr, saddr, bce.destunr_count);
10884 +
10885 +               if (bce.destunr_count > MIPV6_MAX_DESTUNREACH && mipv6_bcache_delete(daddr, saddr, CACHE_ENTRY) == 0) {
10886 +                       DEBUG(DBG_INFO, "Deleted bcache entry "
10887 +                             "%x:%x:%x:%x:%x:%x:%x:%x "
10888 +                             "%x:%x:%x:%x:%x:%x:%x:%x (reason: "
10889 +                             "%d dest unreachables) ",
10890 +                             NIPV6ADDR(daddr), NIPV6ADDR(saddr), bce.destunr_count);
10891 +               }
10892 +       }
10893 +       return 0;
10894 +}
10895 +
10896 +static int mipv6_icmpv6_getfrag(const void *data, struct in6_addr *saddr, 
10897 +                               char *buff, unsigned int offset, 
10898 +                               unsigned int len)
10899 +{
10900 +       struct mipv6_icmpv6_msg *msg = (struct mipv6_icmpv6_msg *) data;
10901 +       struct icmp6hdr *icmph;
10902 +       __u32 csum;
10903 +
10904 +       if (offset) {
10905 +               msg->csum = csum_partial_copy_nocheck(msg->data + offset -
10906 +                                                     sizeof(*icmph), buff,
10907 +                                                     len, msg->csum);
10908 +               return 0;
10909 +       }
10910 +       
10911 +       csum = csum_partial_copy_nocheck((__u8 *) &msg->icmph, buff,
10912 +                                        sizeof(*icmph), msg->csum);
10913 +       
10914 +       csum = csum_partial_copy_nocheck(msg->data, buff + sizeof(*icmph),
10915 +                                        len - sizeof(*icmph), csum);
10916 +       
10917 +       icmph = (struct icmp6hdr *) buff;
10918 +       
10919 +       icmph->icmp6_cksum = csum_ipv6_magic(saddr, msg->daddr, msg->len,
10920 +                                            IPPROTO_ICMPV6, csum);
10921 +       return 0; 
10922 +}
10923 +
10924 +/**
10925 + * mipv6_icmpv6_send - generic icmpv6 message send
10926 + * @daddr: destination address
10927 + * @saddr: source address
10928 + * @type: icmp type
10929 + * @code: icmp code
10930 + * @id: packet identifier. If null, uses internal counter to get new id
10931 + * @data: packet data
10932 + * @datalen: length of data in bytes
10933 + */
10934 +void mipv6_icmpv6_send(struct in6_addr *daddr, struct in6_addr *saddr, int type,
10935 +                      int code, __u16 *id, __u16 flags, void *data, int datalen)
10936 +{
10937 +       struct sock *sk = mipv6_icmpv6_socket->sk;
10938 +       struct flowi fl;
10939 +       struct mipv6_icmpv6_msg msg;
10940 +
10941 +       DEBUG_FUNC();
10942 +
10943 +       fl.proto = IPPROTO_ICMPV6;
10944 +       fl.fl6_dst = daddr;
10945 +       fl.fl6_src = saddr;
10946 +       fl.fl6_flowlabel = 0;
10947 +       fl.uli_u.icmpt.type = type;
10948 +       fl.uli_u.icmpt.code = code;
10949 +
10950 +       msg.icmph.icmp6_type = type;
10951 +       msg.icmph.icmp6_code = code;
10952 +       msg.icmph.icmp6_cksum = 0;
10953 +
10954 +       if (id)
10955 +               msg.icmph.icmp6_identifier = htons(*id);
10956 +       else
10957 +               msg.icmph.icmp6_identifier = htons(identifier++);
10958 +
10959 +       msg.icmph.icmp6_sequence = htons(flags);
10960 +       msg.data = data;
10961 +       msg.csum = 0;
10962 +       msg.len = datalen + sizeof(struct icmp6hdr);
10963 +       msg.daddr = daddr;
10964 +
10965 +       if (mipv6_icmpv6_xmit_lock())
10966 +               return;
10967 +
10968 +       ip6_build_xmit(sk, mipv6_icmpv6_getfrag, &msg, &fl, msg.len, NULL, -1,
10969 +                      MSG_DONTWAIT);
10970 +
10971 +       ICMP6_INC_STATS_BH(Icmp6OutMsgs);
10972 +       mipv6_icmpv6_xmit_unlock();
10973 +}
10974 +
10975 +/**
10976 + * icmp6_rcv - ICMPv6 receive and multiplex
10977 + * @skb: buffer containing ICMP message
10978 + *
10979 + * Generic ICMPv6 receive function to multiplex messages to approriate
10980 + * handlers.  Only used for ICMP messages with special handling in
10981 + * Mobile IPv6.
10982 + **/
10983 +static void icmp6_rcv(struct sk_buff *skb)
10984 +{
10985 +       struct icmp6hdr *hdr;
10986 +
10987 +       if (skb_is_nonlinear(skb) &&
10988 +           skb_linearize(skb, GFP_ATOMIC) != 0) {
10989 +               kfree_skb(skb);
10990 +               return;
10991 +       }
10992 +       __skb_push(skb, skb->data-skb->h.raw);
10993 +
10994 +       hdr = (struct icmp6hdr *) skb->h.raw;
10995 +
10996 +       switch (hdr->icmp6_type) {
10997 +       case ICMPV6_DEST_UNREACH:
10998 +               mipv6_icmpv6_rcv_dest_unreach(skb);
10999 +               break;
11000 +
11001 +       case ICMPV6_PARAMPROB:
11002 +               mip6_fn.icmpv6_paramprob_rcv(skb);
11003 +               break;
11004 +
11005 +       case MIPV6_DHAAD_REPLY:
11006 +               mip6_fn.icmpv6_dhaad_rep_rcv(skb);
11007 +               break;
11008 +
11009 +       case MIPV6_PREFIX_ADV:
11010 +               mip6_fn.icmpv6_pfxadv_rcv(skb);
11011 +               break;
11012 +
11013 +       case MIPV6_DHAAD_REQUEST:
11014 +               mip6_fn.icmpv6_dhaad_req_rcv(skb);
11015 +               break;
11016 +
11017 +       case MIPV6_PREFIX_SOLICIT:
11018 +               mip6_fn.icmpv6_pfxsol_rcv(skb);
11019 +               break;
11020 +       }
11021 +}
11022 +
11023 +int mipv6_icmpv6_init(void)
11024 +{
11025 +       struct sock *sk;
11026 +       int err;
11027 +
11028 +       if ((mipv6_icmpv6_socket = sock_alloc()) == NULL) {
11029 +               DEBUG(DBG_ERROR, "Cannot allocate mipv6_icmpv6_socket");
11030 +               return -1;
11031 +       }
11032 +       mipv6_icmpv6_socket->type = SOCK_RAW;
11033 +
11034 +       if ((err = sock_create(PF_INET6, SOCK_RAW, IPPROTO_ICMP, 
11035 +                              &mipv6_icmpv6_socket)) < 0) {
11036 +               DEBUG(DBG_ERROR, "Cannot initialize mipv6_icmpv6_socket");
11037 +               sock_release(mipv6_icmpv6_socket);
11038 +               mipv6_icmpv6_socket = NULL; /* For safety */
11039 +               return err;
11040 +       }
11041 +       sk = mipv6_icmpv6_socket->sk;
11042 +       sk->allocation = GFP_ATOMIC;
11043 +       sk->prot->unhash(sk);
11044 +
11045 +       /* Register our ICMP handler */
11046 +       MIPV6_SETCALL(mipv6_icmp_rcv, icmp6_rcv);
11047 +       return 0;
11048 +}
11049 +
11050 +void mipv6_icmpv6_exit(void)
11051 +{
11052 +       MIPV6_RESETCALL(mipv6_icmp_rcv);
11053 +       if (mipv6_icmpv6_socket)
11054 +               sock_release(mipv6_icmpv6_socket);
11055 +       mipv6_icmpv6_socket = NULL; /* For safety */
11056 +}
11057 --- /dev/null
11058 +++ linux-2.4.27/net/ipv6/mobile_ip6/mipv6_icmp.h
11059 @@ -0,0 +1,43 @@
11060 +/*
11061 + *      MIPL Mobile IPv6 ICMP send and receive prototypes
11062 + *
11063 + *      $Id$
11064 + *
11065 + *      This program is free software; you can redistribute it and/or
11066 + *      modify it under the terms of the GNU General Public License
11067 + *      as published by the Free Software Foundation; either version
11068 + *      2 of the License, or (at your option) any later version.
11069 + */
11070 +
11071 +#ifndef _MIPV6_ICMP
11072 +#define _MIPV6_ICMP
11073 +
11074 +#include <linux/config.h>
11075 +#include <linux/in6.h>
11076 +
11077 +void mipv6_icmpv6_send(struct in6_addr *daddr, struct in6_addr *saddr,
11078 +                      int type, int code, __u16 *id, __u16 flags,
11079 +                      void *data, int datalen);
11080 +
11081 +void mipv6_icmpv6_send_dhaad_req(struct in6_addr *home_addr, int plen, __u16 dhaad_id);
11082 +
11083 +void mipv6_icmpv6_send_dhaad_rep(int ifindex, __u16 id, struct in6_addr *daddr);
11084 +/* No handling */
11085 +int mipv6_icmpv6_no_rcv(struct sk_buff *skb);
11086 +
11087 +/* Receive DHAAD Reply message */
11088 +int mipv6_icmpv6_rcv_dhaad_rep(struct sk_buff *skb);
11089 +/* Receive Parameter Problem message */
11090 +int mipv6_icmpv6_rcv_paramprob(struct sk_buff *skb);
11091 +/* Receive prefix advertisements */
11092 +int mipv6_icmpv6_rcv_pfx_adv(struct sk_buff *skb);
11093 +
11094 +/* Receive DHAAD Request message */
11095 +int mipv6_icmpv6_rcv_dhaad_req(struct sk_buff *skb);
11096 +/* Receive prefix solicitations */
11097 +int mipv6_icmpv6_rcv_pfx_sol(struct sk_buff *skb);
11098 +
11099 +int mipv6_icmpv6_init(void);
11100 +void mipv6_icmpv6_exit(void);
11101 +
11102 +#endif
11103 --- /dev/null
11104 +++ linux-2.4.27/net/ipv6/mobile_ip6/mipv6_icmp_ha.c
11105 @@ -0,0 +1,158 @@
11106 +/*
11107 + *     Home Agent specific ICMP routines
11108 + *
11109 + *     Authors:
11110 + *     Antti Tuominen  <ajtuomin@tml.hut.fi>
11111 + *     Jaakko Laine    <medved@iki.fi>
11112 + *
11113 + *      $Id$
11114 + *
11115 + *      This program is free software; you can redistribute it and/or
11116 + *      modify it under the terms of the GNU General Public License
11117 + *      as published by the Free Software Foundation; either version
11118 + *      2 of the License, or (at your option) any later version.
11119 + */
11120 +
11121 +#include <linux/autoconf.h>
11122 +#include <linux/sched.h>
11123 +#include <net/ipv6.h>
11124 +#include <net/addrconf.h>
11125 +#include <net/ip6_route.h>
11126 +#include <net/mipv6.h>
11127 +
11128 +#include "halist.h"
11129 +#include "debug.h"
11130 +#include "mipv6_icmp.h"
11131 +//#include "prefix.h"
11132 +
11133 +/* Is this the easiest way of checking on 
11134 + *  which interface an anycast address is ?
11135 + */
11136 +static int find_ac_dev(struct in6_addr *addr)
11137 +{
11138 +       int ifindex = 0;
11139 +       struct net_device *dev;
11140 +       read_lock(&dev_base_lock);
11141 +       for (dev=dev_base; dev; dev=dev->next) {
11142 +               if (ipv6_chk_acast_addr(dev, addr)) {
11143 +                       ifindex = dev->ifindex;
11144 +                       break;
11145 +               }
11146 +       }
11147 +       read_unlock(&dev_base_lock);
11148 +       return ifindex;
11149 +}
11150 +
11151 +/**
11152 + * mipv6_icmpv6_send_dhaad_rep - Reply to DHAAD Request
11153 + * @ifindex: index of interface request was received from
11154 + * @id: request's identification number
11155 + * @daddr: requester's IPv6 address
11156 + *
11157 + * When Home Agent receives Dynamic Home Agent Address Discovery
11158 + * request, it replies with a list of home agents available on the
11159 + * home link.
11160 + */
11161 +void mipv6_icmpv6_send_dhaad_rep(int ifindex, __u16 id, struct in6_addr *daddr)
11162 +{
11163 +       __u8 *data = NULL;
11164 +       struct in6_addr home, *ha_addrs = NULL;
11165 +       int addr_count, max_addrs, size = 0;
11166 +
11167 +       if (daddr == NULL)
11168 +               return;
11169 +
11170 +       if (mipv6_ha_get_addr(ifindex, &home) < 0) {
11171 +               DEBUG(DBG_INFO, "Not Home Agent in this interface");
11172 +               return;
11173 +       }
11174 +
11175 +       /* We send all available HA addresses, not exceeding a maximum
11176 +        * number we can fit in a packet with minimum IPv6 MTU (to
11177 +        * avoid fragmentation).
11178 +        */
11179 +       max_addrs = 76;
11180 +       addr_count = mipv6_ha_get_pref_list(ifindex, &ha_addrs, max_addrs);
11181 +
11182 +       if (addr_count < 0) return;
11183 +
11184 +       if (addr_count != 0 && ha_addrs == NULL) {
11185 +               DEBUG(DBG_ERROR, "addr_count = %d but return no addresses", 
11186 +                     addr_count);
11187 +               return;
11188 +       }
11189 +       data = (u8 *)ha_addrs;
11190 +
11191 +       size = addr_count * sizeof(struct in6_addr);
11192 +
11193 +       mipv6_icmpv6_send(daddr, &home, MIPV6_DHAAD_REPLY, 
11194 +                         0, &id, 0, data, size);
11195 +       if (ha_addrs) {
11196 +               data = NULL;
11197 +               kfree(ha_addrs);
11198 +       }
11199 +}
11200 +
11201 +/** 
11202 + * mipv6_icmpv6_dhaad_req - Home Agent Address Discovery Request ICMP handler
11203 + * @skb: buffer containing ICMP information message
11204 + *
11205 + * Special Mobile IPv6 ICMP message.  Handles Dynamic Home Agent
11206 + * Address Discovery Request messages.
11207 + **/
11208 +int mipv6_icmpv6_rcv_dhaad_req(struct sk_buff *skb)
11209 +{
11210 +       struct icmp6hdr *phdr = (struct icmp6hdr *) skb->h.raw;
11211 +       struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
11212 +       struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
11213 +       __u16 identifier;
11214 +       int ifindex = 0;
11215 +
11216 +       DEBUG_FUNC();
11217 +
11218 +       /* Invalid packet checks. */
11219 +       if (phdr->icmp6_code != 0)
11220 +               return 0;
11221 +
11222 +       identifier = ntohs(phdr->icmp6_identifier);
11223 +
11224 +       /* 
11225 +        * Make sure we have the right ifindex (if the
11226 +        * req came through another interface. 
11227 +        */
11228 +       ifindex = find_ac_dev(daddr);
11229 +       if (ifindex == 0) { 
11230 +               DEBUG(DBG_WARNING, "received dhaad request to anycast address %x:%x:%x:%x:%x:%x:%x:%x"
11231 +                     " on which prefix we are not HA",
11232 +                     NIPV6ADDR(daddr));
11233 +               return 0;
11234 +       }
11235 +
11236 +       /*
11237 +        * send reply with list
11238 +        */
11239 +       mipv6_icmpv6_send_dhaad_rep(ifindex, identifier, saddr);
11240 +       return 1;
11241 +}
11242 +#if 0
11243 +/**
11244 + * mipv6_icmpv6_handle_pfx_sol - handle prefix solicitations
11245 + * @skb: sk_buff including the icmp6 message
11246 + */
11247 +int mipv6_icmpv6_rcv_pfx_sol(struct sk_buff *skb)
11248 +{
11249 +       struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
11250 +       struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
11251 +       struct inet6_ifaddr *ifp;
11252 +
11253 +       DEBUG_FUNC();
11254 +
11255 +       if (!(ifp = ipv6_get_ifaddr(daddr, NULL)))
11256 +               return -1;
11257 +
11258 +       in6_ifa_put(ifp);
11259 +       mipv6_pfx_cancel_send(saddr, -1);
11260 +
11261 +       return 0;
11262 +}
11263 +#endif
11264 --- /dev/null
11265 +++ linux-2.4.27/net/ipv6/mobile_ip6/mipv6_icmp_mn.c
11266 @@ -0,0 +1,273 @@
11267 +/*
11268 + *     Mobile Node specific ICMP routines
11269 + *
11270 + *     Authors:
11271 + *     Antti Tuominen  <ajtuomin@tml.hut.fi>
11272 + *     Jaakko Laine    <medved@iki.fi>
11273 + *
11274 + *      $Id$
11275 + *
11276 + *      This program is free software; you can redistribute it and/or
11277 + *      modify it under the terms of the GNU General Public License
11278 + *      as published by the Free Software Foundation; either version
11279 + *      2 of the License, or (at your option) any later version.
11280 + */
11281 +
11282 +#include <linux/sched.h>
11283 +#include <net/ipv6.h>
11284 +#include <net/ip6_route.h>
11285 +#include <net/addrconf.h>
11286 +#include <net/mipv6.h>
11287 +
11288 +#include "mn.h"
11289 +#include "bul.h"
11290 +#include "mdetect.h"
11291 +#include "debug.h"
11292 +#include "mipv6_icmp.h"
11293 +#include "util.h"
11294 +//#include "prefix.h"
11295 +
11296 +#define INFINITY 0xffffffff
11297 +
11298 +/**
11299 + * mipv6_icmpv6_paramprob - Parameter Problem ICMP error message handler
11300 + * @skb: buffer containing ICMP error message
11301 + *
11302 + * Special Mobile IPv6 ICMP handling.  If Mobile Node receives ICMP
11303 + * Parameter Problem message when using a Home Address Option,
11304 + * offending node should be logged and error message dropped.  If
11305 + * error is received because of a Binding Update, offending node
11306 + * should be recorded in Binding Update List and no more Binding
11307 + * Updates should be sent to this destination.  See RFC 3775 section
11308 + * 10.15.
11309 + **/
11310 +int mipv6_icmpv6_rcv_paramprob(struct sk_buff *skb)
11311 +{
11312 +       struct icmp6hdr *phdr = (struct icmp6hdr *) skb->h.raw;
11313 +       struct in6_addr *saddr = skb ? &skb->nh.ipv6h->saddr : NULL;
11314 +       struct in6_addr *daddr = skb ? &skb->nh.ipv6h->daddr : NULL;
11315 +       struct ipv6hdr *hdr = (struct ipv6hdr *) (phdr + 1);
11316 +       int ulen = (skb->tail - (unsigned char *) (phdr + 1));
11317 +
11318 +       int errptr;
11319 +       __u8 *off_octet;
11320 +
11321 +       DEBUG_FUNC();
11322 +
11323 +       /* We only handle code 1 & 2 messages. */
11324 +       if (phdr->icmp6_code != ICMPV6_UNK_NEXTHDR &&
11325 +           phdr->icmp6_code != ICMPV6_UNK_OPTION)
11326 +               return 0;
11327 +
11328 +       /* Find offending octet in the original packet. */
11329 +       errptr = ntohl(phdr->icmp6_pointer);
11330 +
11331 +       /* There is not enough of the original packet left to figure
11332 +        * out what went wrong. Bail out. */
11333 +       if (ulen <= errptr)
11334 +               return 0;
11335 +
11336 +       off_octet = ((__u8 *) hdr + errptr);
11337 +       DEBUG(DBG_INFO, "Parameter problem: offending octet %d [0x%2x]",
11338 +             errptr, *off_octet);
11339 +
11340 +       /* If CN did not understand Mobility Header, set BUL entry to
11341 +        * ACK_ERROR so no further BUs are sumbitted to this CN. */
11342 +       if (phdr->icmp6_code == ICMPV6_UNK_NEXTHDR &&
11343 +           *off_octet == IPPROTO_MOBILITY) {
11344 +               struct bul_inval_args args;
11345 +               args.all_rr_states = 1;
11346 +               args.cn = saddr;
11347 +               args.mn = daddr;
11348 +               write_lock(&bul_lock);
11349 +               mipv6_bul_iterate(mn_bul_invalidate, &args);
11350 +               write_unlock(&bul_lock);
11351 +       }
11352 +
11353 +       /* If CN did not understand Home Address Option, we log an
11354 +        * error and discard the error message. */
11355 +       if (phdr->icmp6_code == ICMPV6_UNK_OPTION &&
11356 +           *off_octet == MIPV6_TLV_HOMEADDR) {
11357 +               DEBUG(DBG_WARNING, "Correspondent node does not "
11358 +                     "implement Home Address Option receipt.");
11359 +               return 1;
11360 +       }
11361 +       return 0;
11362 +}
11363 +
11364 +/**
11365 + * mipv6_mn_dhaad_send_req - Send DHAAD Request to home network
11366 + * @home_addr: address to do DHAAD for
11367 + * @plen: prefix length for @home_addr
11368 + *
11369 + * Send Dynamic Home Agent Address Discovery Request to the Home
11370 + * Agents anycast address in the nodes home network.
11371 + **/
11372 +void 
11373 +mipv6_icmpv6_send_dhaad_req(struct in6_addr *home_addr, int plen, __u16 dhaad_id)
11374 +{
11375 +       struct in6_addr ha_anycast;
11376 +       struct in6_addr careofaddr;
11377 +       
11378 +       if (mipv6_get_care_of_address(home_addr, &careofaddr) < 0) {
11379 +               DEBUG(DBG_WARNING, "Could not get node's Care-of Address");
11380 +               return;
11381 +       }
11382 +
11383 +       if (mipv6_ha_anycast(&ha_anycast, home_addr, plen) < 0) {
11384 +               DEBUG(DBG_WARNING, 
11385 +                     "Could not get Home Agent Anycast address for home address %x:%x.%x:%x:%x:%x:%x:%x/%d",
11386 +                     NIPV6ADDR(home_addr), plen);
11387 +               return;
11388 +       }
11389 +
11390 +       mipv6_icmpv6_send(&ha_anycast, &careofaddr, MIPV6_DHAAD_REQUEST, 0, 
11391 +                         &dhaad_id, 0, NULL, 0);
11392 +
11393 +}
11394 +
11395 +/** 
11396 + * mipv6_icmpv6_dhaad_rep - Home Agent Address Discovery Reply ICMP handler
11397 + * @skb: buffer containing ICMP information message
11398 + *
11399 + * Special Mobile IPv6 ICMP message.  Handles Dynamic Home Agent
11400 + * Address Discovery Reply messages.
11401 + **/
11402 +int mipv6_icmpv6_rcv_dhaad_rep(struct sk_buff *skb)
11403 +{
11404 +       struct icmp6hdr *phdr = (struct icmp6hdr *) skb->h.raw;
11405 +       struct in6_addr *address;
11406 +       struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
11407 +       __u16 identifier;
11408 +       int ulen = (skb->tail - (unsigned char *) ((__u32 *) phdr + 2));
11409 +       int i;
11410 +       struct in6_addr home_addr, coa;
11411 +       struct in6_addr *first_ha = NULL;
11412 +       struct mn_info *minfo;
11413 +       int n_addr = ulen / sizeof(struct in6_addr);
11414 +
11415 +       DEBUG_FUNC();
11416 +
11417 +       /* Invalid packet checks. */
11418 +       if (ulen % sizeof(struct in6_addr) != 0)
11419 +               return 0;
11420 +
11421 +       if (phdr->icmp6_code != 0)
11422 +               return 0;
11423 +
11424 +       identifier = ntohs(phdr->icmp6_identifier);
11425 +       if (ulen > 0) {
11426 +               address = (struct in6_addr *) ((__u32 *) phdr + 2);
11427 +       } else {
11428 +               address = saddr;
11429 +               n_addr = 1;
11430 +       }
11431 +
11432 +       /* receive list of home agent addresses
11433 +        * add to home agents list
11434 +        */
11435 +       DEBUG(DBG_INFO, "DHAAD: got %d home agents", n_addr);
11436 +
11437 +       first_ha = address;
11438 +
11439 +       /* lookup H@ with identifier */
11440 +       read_lock(&mn_info_lock);
11441 +       minfo = mipv6_mninfo_get_by_id(identifier);
11442 +       if (!minfo) {
11443 +               read_unlock(&mn_info_lock);
11444 +               DEBUG(DBG_INFO, "no mninfo with id %d", 
11445 +                     identifier);
11446 +               return 0;
11447 +       }
11448 +       spin_lock(&minfo->lock);
11449 +
11450 +       /* Logic:
11451 +        * 1. if old HA on list, prefer it
11452 +        * 2. otherwise first HA on list prefered
11453 +        */
11454 +       for (i = 0; i < n_addr; i++) {
11455 +               DEBUG(DBG_INFO, "HA[%d] %x:%x:%x:%x:%x:%x:%x:%x",
11456 +                     i, NIPV6ADDR(address));
11457 +               if (ipv6_addr_cmp(&minfo->ha, address) == 0) {
11458 +                       spin_unlock(&minfo->lock);
11459 +                       read_unlock(&mn_info_lock);
11460 +                       return 0;
11461 +               }
11462 +               address++;
11463 +       }
11464 +       ipv6_addr_copy(&minfo->ha, first_ha);
11465 +       spin_unlock(&minfo->lock);
11466 +       ipv6_addr_copy(&home_addr, &minfo->home_addr);
11467 +       read_unlock(&mn_info_lock);
11468 +
11469 +       mipv6_get_care_of_address(&home_addr, &coa);
11470 +       init_home_registration(&home_addr, &coa);
11471 +
11472 +       return 1;
11473 +}
11474 +#if 0
11475 +/**
11476 + * mipv6_icmpv6_handle_pfx_adv - handle prefix advertisements
11477 + * @skb: sk_buff including the icmp6 message
11478 + */
11479 +int mipv6_icmpv6_rcv_pfx_adv(struct sk_buff *skb)
11480 +{
11481 +       struct icmp6hdr *hdr = (struct icmp6hdr *) skb->h.raw;
11482 +       struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
11483 +       struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
11484 +       __u8 *opt = (__u8 *) (hdr + 1);
11485 +       int optlen = (skb->tail - opt);
11486 +       unsigned long min_expire = INFINITY;
11487 +       struct inet6_skb_parm *parm = (struct inet6_skb_parm *) skb->cb;
11488 +
11489 +       DEBUG_FUNC();
11490 +
11491 +       while (optlen > 0) {
11492 +               int len = opt[1] << 3;
11493 +               if (len == 0)
11494 +                       goto set_timer;
11495 +
11496 +               if (opt[0] == ND_OPT_PREFIX_INFO) {
11497 +                       int ifindex;
11498 +                       unsigned long expire;
11499 +                       struct prefix_info *pinfo =
11500 +                               (struct prefix_info *) opt;
11501 +                       struct net_device *dev;
11502 +                       struct mn_info *mninfo;
11503 +
11504 +                       read_lock(&mn_info_lock);
11505 +                       mninfo = mipv6_mninfo_get_by_ha(saddr);
11506 +                       if (mninfo == NULL) {
11507 +                               ifindex = 0;
11508 +                       } else {
11509 +                               spin_lock(&mninfo->lock);
11510 +                               ifindex = mninfo->ifindex;
11511 +                               spin_unlock(&mninfo->lock);
11512 +                               mninfo = NULL;
11513 +                       }
11514 +                       read_unlock(&mn_info_lock);
11515 +
11516 +                       if (!(dev = dev_get_by_index(ifindex))) {
11517 +                               DEBUG(DBG_WARNING, "Cannot find device by index %d", parm->iif);
11518 +                               goto nextopt;
11519 +                       }
11520 +
11521 +                       expire = ntohl(pinfo->valid);
11522 +                       expire = expire == 0 ? INFINITY : expire;
11523 +
11524 +                       min_expire = expire < min_expire ? expire : min_expire;
11525 +
11526 +                       dev_put(dev);
11527 +               }
11528 +
11529 +nextopt:
11530 +               optlen -= len;
11531 +               opt += len;
11532 +       }
11533 +
11534 +set_timer:
11535 +
11536 +       mipv6_pfx_add_home(parm->iif, saddr, daddr, min_expire);
11537 +       return 0;
11538 +}
11539 +#endif
11540 --- /dev/null
11541 +++ linux-2.4.27/net/ipv6/mobile_ip6/mn.c
11542 @@ -0,0 +1,1521 @@
11543 +/*
11544 + *      Mobile-node functionality
11545 + *
11546 + *      Authors:
11547 + *      Sami Kivisaari          <skivisaa@cc.hut.fi>
11548 + *
11549 + *      $Id$
11550 + *
11551 + *      This program is free software; you can redistribute it and/or
11552 + *      modify it under the terms of the GNU General Public License
11553 + *      as published by the Free Software Foundation; either version
11554 + *      2 of the License, or (at your option) any later version.
11555 + *
11556 + */
11557 +
11558 +#include <linux/autoconf.h>
11559 +#include <linux/sched.h>
11560 +#include <linux/ipv6.h>
11561 +#include <linux/net.h>
11562 +#include <linux/init.h>
11563 +#include <linux/skbuff.h>
11564 +#include <linux/rtnetlink.h>
11565 +#include <linux/if_arp.h>
11566 +#include <linux/ipsec.h>
11567 +#include <linux/notifier.h>
11568 +#include <linux/list.h>
11569 +#include <linux/route.h>
11570 +#include <linux/netfilter.h>
11571 +#include <linux/netfilter_ipv6.h>
11572 +#include <linux/tqueue.h>
11573 +#include <linux/proc_fs.h>
11574 +
11575 +#include <asm/uaccess.h>
11576 +
11577 +#include <net/ipv6.h>
11578 +#include <net/addrconf.h>
11579 +#include <net/neighbour.h>
11580 +#include <net/ndisc.h>
11581 +#include <net/ip6_route.h>
11582 +#include <net/mipglue.h>
11583 +
11584 +#include "util.h"
11585 +#include "mdetect.h"
11586 +#include "bul.h"
11587 +#include "mobhdr.h"
11588 +#include "debug.h"
11589 +#include "mn.h"
11590 +#include "mipv6_icmp.h"
11591 +#include "multiaccess_ctl.h"
11592 +//#include "prefix.h"
11593 +#include "tunnel_mn.h"
11594 +#include "stats.h"
11595 +#include "config.h"
11596 +
11597 +#define MIPV6_BUL_SIZE 128
11598 +
11599 +static LIST_HEAD(mn_info_list);
11600 +
11601 +/* Lock for list of MN infos */
11602 +rwlock_t mn_info_lock = RW_LOCK_UNLOCKED;
11603 +
11604 +static spinlock_t ifrh_lock = SPIN_LOCK_UNLOCKED;
11605 +
11606 +struct ifr_holder {
11607 +       struct list_head list;
11608 +       struct in6_ifreq ifr;
11609 +       int old_ifi;
11610 +       struct handoff *ho;
11611 +};
11612 +
11613 +LIST_HEAD(ifrh_list);
11614 +
11615 +static struct tq_struct mv_home_addr_task;
11616 +
11617 +/* Determines whether manually configured home addresses are preferred as 
11618 + * source addresses over dynamically configured ones
11619 + */
11620 +int mipv6_use_preconfigured_hoaddr = 1; 
11621 +
11622 +/* Determines whether home addresses, which are at home are preferred as 
11623 + * source addresses over other home addresses
11624 + */
11625 +int mipv6_use_topol_corr_hoaddr = 0;
11626 +
11627 +static spinlock_t icmpv6_id_lock = SPIN_LOCK_UNLOCKED;
11628 +static __u16 icmpv6_id = 0;
11629 +
11630 +static inline __u16 mipv6_get_dhaad_id(void)
11631 +{
11632 +       __u16 ret;
11633 +       spin_lock_bh(&icmpv6_id_lock);
11634 +       ret = ++icmpv6_id;
11635 +       spin_unlock_bh(&icmpv6_id_lock);
11636 +       return ret;
11637 +}
11638 +
11639 +/** 
11640 + * mipv6_mninfo_get_by_home - Returns mn_info for a home address
11641 + * @haddr: home address of MN
11642 + *
11643 + * Returns mn_info on success %NULL otherwise.  Caller MUST hold
11644 + * @mn_info_lock (read or write).
11645 + **/
11646 +struct mn_info *mipv6_mninfo_get_by_home(struct in6_addr *haddr)
11647 +{
11648 +       struct list_head *lh;
11649 +       struct mn_info *minfo;
11650 +
11651 +       DEBUG_FUNC();
11652 +
11653 +       if (!haddr)
11654 +               return NULL;
11655 +
11656 +       list_for_each(lh, &mn_info_list) {
11657 +               minfo = list_entry(lh, struct mn_info, list);
11658 +               spin_lock(&minfo->lock);
11659 +               if (!ipv6_addr_cmp(&minfo->home_addr, haddr)) {
11660 +                       spin_unlock(&minfo->lock);
11661 +                       return minfo;
11662 +               }
11663 +               spin_unlock(&minfo->lock);
11664 +       }
11665 +       return NULL;
11666 +}
11667 +
11668 +/**
11669 + * mipv6_mninfo_get_by_ha - Lookup mn_info with Home Agent address
11670 + * @home_agent: Home Agent address
11671 + *
11672 + * Searches for a mn_info entry with @ha set to @home_agent.  You MUST
11673 + * hold @mn_info_lock when calling this function.  Returns pointer to
11674 + * mn_info entry or %NULL on failure.
11675 + **/
11676 +struct mn_info *mipv6_mninfo_get_by_ha(struct in6_addr *home_agent)
11677 +{
11678 +       struct list_head *lh;
11679 +       struct mn_info *minfo;
11680 +
11681 +       if (!home_agent)
11682 +               return NULL;
11683 +
11684 +       list_for_each(lh, &mn_info_list) {
11685 +               minfo = list_entry(lh, struct mn_info, list);
11686 +               spin_lock(&minfo->lock);
11687 +               if (!ipv6_addr_cmp(&minfo->ha, home_agent)) {
11688 +                       spin_unlock(&minfo->lock);
11689 +                       return minfo;
11690 +               }
11691 +               spin_unlock(&minfo->lock);
11692 +       }
11693 +       return NULL;
11694 +}
11695 +
11696 +/**
11697 + * mipv6_mninfo_get_by_id - Lookup mn_info with id
11698 + * @id: DHAAD identifier
11699 + *
11700 + * Searches for a mn_info entry with @dhaad_id set to @id.  You MUST
11701 + * hold @mn_info_lock when calling this function.  Returns pointer to
11702 + * mn_info entry or %NULL on failure.
11703 + **/
11704 +struct mn_info *mipv6_mninfo_get_by_id(unsigned short id)
11705 +{
11706 +       struct list_head *lh;
11707 +       struct mn_info *minfo = 0;
11708 +
11709 +       list_for_each(lh, &mn_info_list) {
11710 +               minfo = list_entry(lh, struct mn_info, list);
11711 +               spin_lock(&minfo->lock);
11712 +               if (minfo->dhaad_id == id) {
11713 +                       spin_unlock(&minfo->lock);
11714 +                       return minfo;
11715 +               }
11716 +               spin_unlock(&minfo->lock);
11717 +       }
11718 +       return NULL;
11719 +}
11720 +
11721 +/** 
11722 + * mipv6_mninfo_add - Adds a new home info for MN
11723 + * @ifindex: Interface for home address
11724 + * @home_addr:  Home address of MN, must be set
11725 + * @plen: prefix length of the home address, must be set
11726 + * @isathome : home address at home
11727 + * @lifetime: lifetime of the home address, 0 is infinite
11728 + * @ha: home agent for the home address
11729 + * @ha_plen: prefix length of home agent's address, can be zero 
11730 + * @ha_lifetime: Lifetime of the home address, 0 is infinite
11731 + *
11732 + * The function adds a new home info entry for MN, allowing it to
11733 + * register the home address with the home agent.  Starts home
11734 + * registration process.  If @ha is %ADDRANY, DHAAD is performed to
11735 + * find a home agent.  Returns 0 on success, a negative value
11736 + * otherwise.  Caller MUST NOT hold @mn_info_lock or
11737 + * @addrconf_hash_lock.
11738 + **/
11739 +void mipv6_mninfo_add(int ifindex, struct in6_addr *home_addr, int plen, 
11740 +                     int isathome, unsigned long lifetime, struct in6_addr *ha, 
11741 +                     int ha_plen, unsigned long ha_lifetime, int man_conf)
11742 +{
11743 +       struct mn_info *minfo;
11744 +       struct in6_addr coa;
11745 +
11746 +       DEBUG_FUNC();
11747 +
11748 +       write_lock_bh(&mn_info_lock);
11749 +       if ((minfo = mipv6_mninfo_get_by_home(home_addr)) != NULL){ 
11750 +             DEBUG(1, "MN info already exists");
11751 +             write_unlock_bh(&mn_info_lock);
11752 +             return;
11753 +       }
11754 +       minfo = kmalloc(sizeof(struct mn_info), GFP_ATOMIC);
11755 +       if (!minfo) {
11756 +              write_unlock_bh(&mn_info_lock);
11757 +              return;
11758 +       }
11759 +       memset(minfo, 0, sizeof(struct mn_info));
11760 +       spin_lock_init(&minfo->lock);
11761 +
11762 +       
11763 +       ipv6_addr_copy(&minfo->home_addr, home_addr);
11764 +
11765 +       if (ha)
11766 +               ipv6_addr_copy(&minfo->ha, ha);
11767 +       if (ha_plen < 128 && ha_plen > 0)
11768 +               minfo->home_plen = ha_plen; 
11769 +       else minfo->home_plen = 64;
11770 +
11771 +       minfo->ifindex_user = ifindex; /* Ifindex for tunnel interface */
11772 +       minfo->ifindex = ifindex; /* Interface on which home address is currently conf'd */
11773 +       /* TODO: we should get home address lifetime from somewhere */
11774 +       /* minfo->home_addr_expires = jiffies + lifetime * HZ; */
11775 +
11776 +       /* manual configuration flag cannot be unset by dynamic updates 
11777 +        *  from prefix advertisements
11778 +        */
11779 +       if (!minfo->man_conf) minfo->man_conf = man_conf; 
11780 +       minfo->is_at_home = isathome;
11781 +
11782 +       list_add(&minfo->list, &mn_info_list);
11783 +       write_unlock_bh(&mn_info_lock);
11784 +
11785 +       if (mipv6_get_care_of_address(home_addr, &coa) == 0) 
11786 +               init_home_registration(home_addr, &coa);
11787 +}
11788 +
11789 +/**
11790 + * mipv6_mninfo_del - Delete home info for MN 
11791 + * @home_addr : Home address or prefix 
11792 + * @del_dyn_only : Delete only dynamically created home entries 
11793 + *
11794 + * Deletes every mn_info entry that matches the first plen bits of
11795 + * @home_addr.  Returns number of deleted entries on success and a
11796 + * negative value otherwise.  Caller MUST NOT hold @mn_info_lock.
11797 + **/
11798 +int mipv6_mninfo_del(struct in6_addr *home_addr, int del_dyn_only)
11799 +{
11800 +       struct list_head *lh, *next;
11801 +       struct mn_info *minfo;
11802 +       int ret = -1;
11803 +       if (!home_addr)
11804 +               return -1;
11805 +
11806 +       write_lock(&mn_info_lock);
11807 +
11808 +       list_for_each_safe(lh, next, &mn_info_list) {
11809 +               minfo = list_entry(lh, struct mn_info, list);
11810 +               if (ipv6_addr_cmp(&minfo->home_addr, home_addr) == 0
11811 +                   && ((!minfo->man_conf && del_dyn_only) || !del_dyn_only)){
11812 +                       list_del(&minfo->list);
11813 +                       kfree(minfo);
11814 +                       ret++;
11815 +               }
11816 +       }
11817 +       write_unlock(&mn_info_lock);
11818 +       return ret;
11819 +}
11820 +
11821 +void mipv6_mn_set_home(int ifindex, struct in6_addr *homeaddr, int plen,
11822 +                      struct in6_addr *homeagent, int ha_plen)
11823 +{
11824 +       mipv6_mninfo_add(ifindex, homeaddr, plen, 0, 0, 
11825 +                        homeagent, ha_plen, 0, 1);
11826 +}
11827 +
11828 +static int skip_dad(struct in6_addr *addr)
11829 +{
11830 +       struct mn_info *minfo;
11831 +       int ret = 0;
11832 +
11833 +       if (addr == NULL) {
11834 +               DEBUG(DBG_CRITICAL, "Null argument");
11835 +               return 0;
11836 +       }
11837 +       read_lock_bh(&mn_info_lock);
11838 +       if ((minfo = mipv6_mninfo_get_by_home(addr)) != NULL) {
11839 +               if ((minfo->is_at_home != MN_NOT_AT_HOME) && (minfo->has_home_reg))
11840 +                       ret = 1;
11841 +               DEBUG(DBG_INFO, "minfo->is_at_home = %d, minfo->has_home_reg = %d",
11842 +                     minfo->is_at_home, minfo->has_home_reg);
11843 +       }
11844 +       read_unlock_bh(&mn_info_lock);
11845 +       
11846 +       return ret;
11847 +}
11848 +/**
11849 + * mipv6_mn_is_home_addr - Determines if addr is node's home address
11850 + * @addr: IPv6 address
11851 + *
11852 + * Returns 1 if addr is node's home address.  Otherwise returns zero.
11853 + **/
11854 +int mipv6_mn_is_home_addr(struct in6_addr *addr)
11855 +{
11856 +       int ret = 0;
11857 +
11858 +       if (addr == NULL) {
11859 +               DEBUG(DBG_CRITICAL, "Null argument");
11860 +               return -1;
11861 +       }
11862 +       read_lock_bh(&mn_info_lock);
11863 +       if (mipv6_mninfo_get_by_home(addr))
11864 +               ret = 1;
11865 +       read_unlock_bh(&mn_info_lock);
11866 +
11867 +       return (ret);
11868 +}
11869 +
11870 +/** 
11871 + * mipv6_mn_is_at_home - determine if node is home for a home address
11872 + * @home_addr : home address of MN
11873 + *
11874 + * Returns 1 if home address in question is in the home network, 0
11875 + * otherwise.  Caller MUST NOT not hold @mn_info_lock.
11876 + **/ 
11877 +int mipv6_mn_is_at_home(struct in6_addr *home_addr)
11878 +{
11879 +       struct mn_info *minfo;
11880 +       int ret = 0;
11881 +       read_lock_bh(&mn_info_lock);
11882 +       if ((minfo = mipv6_mninfo_get_by_home(home_addr)) != NULL) {
11883 +               spin_lock(&minfo->lock);
11884 +               ret = (minfo->is_at_home == MN_AT_HOME);
11885 +               spin_unlock(&minfo->lock);
11886 +       }
11887 +       read_unlock_bh(&mn_info_lock);
11888 +       return ret;
11889 +}      
11890 +void mipv6_mn_set_home_reg(struct in6_addr *home_addr, int has_home_reg)
11891 +{
11892 +       struct mn_info *minfo;
11893 +       read_lock_bh(&mn_info_lock);
11894 +
11895 +       if ((minfo = mipv6_mninfo_get_by_home(home_addr)) != NULL) {
11896 +               spin_lock(&minfo->lock);
11897 +               minfo->has_home_reg = has_home_reg;
11898 +               spin_unlock(&minfo->lock);
11899 +       }
11900 +       read_unlock_bh(&mn_info_lock);
11901 +}      
11902 +
11903 +static int mn_inet6addr_event(
11904 +       struct notifier_block *nb, unsigned long event, void *ptr)
11905 +{
11906 +       struct inet6_ifaddr *ifp = (struct inet6_ifaddr *)ptr;
11907 +
11908 +       switch (event) {
11909 +       case NETDEV_UP:
11910 +               /* Is address a valid coa ?*/
11911 +               if (!(ifp->flags & IFA_F_TENTATIVE))
11912 +                       mipv6_mdet_finalize_ho(&ifp->addr, 
11913 +                                              ifp->idev->dev->ifindex);
11914 +               else if(skip_dad(&ifp->addr))
11915 +                       ifp->flags &= ~IFA_F_TENTATIVE;
11916 +               break;
11917 +       case NETDEV_DOWN:       
11918 +#if 0
11919 +               /* This is useless with manually configured home 
11920 +                  addresses, which will not expire
11921 +               */
11922 +               mipv6_mninfo_del(&ifp->addr, 0);
11923 +#endif
11924 +         break;
11925 +
11926 +       }
11927 +
11928 +       return NOTIFY_DONE;
11929 +}
11930 +
11931 +struct notifier_block mipv6_mn_inet6addr_notifier = {
11932 +       mn_inet6addr_event,
11933 +       NULL,
11934 +       0 /* check if using zero is ok */
11935 +};
11936 +
11937 +static void mipv6_get_saddr_hook(struct in6_addr *homeaddr)
11938 +{
11939 +       int found = 0, reiter = 0;
11940 +       struct list_head *lh;
11941 +       struct mn_info *minfo = NULL;
11942 +       struct in6_addr coa;
11943 +
11944 +       read_lock_bh(&mn_info_lock);
11945 +restart:
11946 +       list_for_each(lh, &mn_info_list) {
11947 +               minfo = list_entry(lh, struct mn_info, list);
11948 +               if ((ipv6_addr_scope(homeaddr) != ipv6_addr_scope(&minfo->home_addr)) 
11949 +                   || ipv6_chk_addr(&minfo->home_addr, NULL) == 0)
11950 +                       continue; 
11951 +
11952 +               spin_lock(&minfo->lock);
11953 +               if (minfo->is_at_home == MN_AT_HOME || minfo->has_home_reg) {
11954 +                       if ((mipv6_use_topol_corr_hoaddr && 
11955 +                            minfo->is_at_home == MN_AT_HOME) || 
11956 +                           (mipv6_use_preconfigured_hoaddr && 
11957 +                            minfo->man_conf) ||
11958 +                           (!(mipv6_use_preconfigured_hoaddr || 
11959 +                              mipv6_use_topol_corr_hoaddr) || reiter)) {
11960 +                               spin_unlock(&minfo->lock);
11961 +                               ipv6_addr_copy(homeaddr, &minfo->home_addr);
11962 +                               found = 1;
11963 +                               break;
11964 +                       }
11965 +               }
11966 +               spin_unlock(&minfo->lock);
11967 +       }
11968 +       if (!found && !reiter) {
11969 +               reiter = 1;
11970 +               goto restart;
11971 +       }
11972 +
11973 +       if (!found && minfo && 
11974 +           !mipv6_get_care_of_address(&minfo->home_addr, &coa)) {
11975 +               ipv6_addr_copy(homeaddr, &coa); 
11976 +       }
11977 +       read_unlock_bh(&mn_info_lock);
11978 +
11979 +       DEBUG(DBG_DATADUMP, "Source address selection:  %x:%x:%x:%x:%x:%x:%x:%x", 
11980 +             NIPV6ADDR(homeaddr));
11981 +       return;
11982 +}
11983 +
11984 +static void mv_home_addr(void *arg)
11985 +{
11986 +       mm_segment_t oldfs;
11987 +       int err = 0, new_if = 0;
11988 +       struct list_head *lh, *next;
11989 +       struct ifr_holder *ifrh;
11990 +       LIST_HEAD(list);
11991 +       
11992 +       DEBUG(DBG_INFO, "mipv6 move home address task");
11993 +
11994 +       spin_lock_bh(&ifrh_lock);
11995 +       list_splice_init(&ifrh_list, &list);
11996 +       spin_unlock_bh(&ifrh_lock);
11997 +       
11998 +       oldfs = get_fs(); set_fs(KERNEL_DS);
11999 +       list_for_each_safe(lh, next, &list) {
12000 +               ifrh = list_entry(lh, struct ifr_holder, list);
12001 +               if (ifrh->old_ifi) {
12002 +                       new_if = ifrh->ifr.ifr6_ifindex;
12003 +                       ifrh->ifr.ifr6_ifindex = ifrh->old_ifi;
12004 +                       err = addrconf_del_ifaddr(&ifrh->ifr); 
12005 +                       ifrh->ifr.ifr6_ifindex = new_if;
12006 +                       if (err < 0)
12007 +                               DEBUG(DBG_WARNING, "removal of home address %x:%x:%x:%x:%x:%x:%x:%x from" 
12008 +                                     " old interface %d failed with status %d", 
12009 +                                     NIPV6ADDR(&ifrh->ifr.ifr6_addr), ifrh->old_ifi, err);             
12010 +               }
12011 +               if(!err) {
12012 +                       err = addrconf_add_ifaddr(&ifrh->ifr);
12013 +               }
12014 +               if (ifrh->ho) {
12015 +                       DEBUG(DBG_INFO, "Calling mobile_node moved after moving home address to new if");
12016 +                       mipv6_mobile_node_moved(ifrh->ho);
12017 +               }
12018 +               list_del(&ifrh->list);
12019 +               kfree(ifrh);
12020 +       }
12021 +       set_fs(oldfs);
12022 +
12023 +       if (err < 0)
12024 +               DEBUG(DBG_WARNING, "adding of home address to a new interface %d failed %d", new_if, err);
12025 +       else {
12026 +               DEBUG(DBG_WARNING, "adding of home address to a new interface OK");
12027 +       }
12028 +}
12029 +
12030 +struct dhaad_halist {
12031 +       struct list_head list;
12032 +       struct in6_addr addr;
12033 +       int retry;
12034 +};
12035 +
12036 +/* clear all has from candidate list.  do this when a new dhaad reply
12037 + * is received. */
12038 +int mipv6_mn_flush_ha_candidate(struct list_head *ha)
12039 +{
12040 +       struct list_head *p, *tmp;
12041 +       struct dhaad_halist *e;
12042 +
12043 +       list_for_each_safe(p, tmp, ha) {
12044 +               e = list_entry(p, struct dhaad_halist, list);
12045 +               list_del(p);
12046 +               kfree(e);
12047 +               e = NULL;
12048 +       }
12049 +       return 0;
12050 +}
12051 +
12052 +/* add new ha to candidates. only done when dhaad reply is received. */
12053 +int mipv6_mn_add_ha_candidate(struct list_head *ha, struct in6_addr *addr)
12054 +{
12055 +       struct dhaad_halist *e;
12056 +
12057 +       e = kmalloc(sizeof(*e), GFP_ATOMIC);
12058 +       memset(e, 0, sizeof(*e));
12059 +       ipv6_addr_copy(&e->addr, addr);
12060 +
12061 +       list_add_tail(&e->list, ha);
12062 +       return 0;
12063 +}
12064 +
12065 +#define MAX_RETRIES_PER_HA 3
12066 +
12067 +/* get next ha candidate.  this is done when dhaad reply has been
12068 + * received and we want to register with the best available ha. */
12069 +int mipv6_mn_get_ha_candidate(struct list_head *ha, struct in6_addr *addr)
12070 +{
12071 +       struct list_head *p;
12072 +
12073 +       list_for_each(p, ha) {
12074 +               struct dhaad_halist *e;
12075 +               e = list_entry(p, typeof(*e), list);
12076 +               if (e->retry >= 0 && e->retry < MAX_RETRIES_PER_HA) {
12077 +                       ipv6_addr_copy(addr, &e->addr);
12078 +                       return 0;
12079 +               }
12080 +       }
12081 +       return -1;
12082 +}
12083 +
12084 +/* change candidate status.  if registration with ha fails, we
12085 + * increase retry for ha candidate.  if retry is >= 3 we set it to -1
12086 + * (failed), do get_ha_candidate() again */
12087 +int mipv6_mn_try_ha_candidate(struct list_head *ha, struct in6_addr *addr)
12088 +{
12089 +       struct list_head *p;
12090 +
12091 +       list_for_each(p, ha) {
12092 +               struct dhaad_halist *e;
12093 +               e = list_entry(p, typeof(*e), list);
12094 +               if (ipv6_addr_cmp(addr, &e->addr) == 0) {
12095 +                       if (e->retry >= MAX_RETRIES_PER_HA) e->retry = -1;
12096 +                       else if (e->retry >= 0) e->retry++;
12097 +                       return 0;
12098 +               }
12099 +       }
12100 +       return -1;
12101 +}
12102 +
12103 +/**
12104 + * mipv6_mn_get_bulifetime - Get lifetime for a binding update
12105 + * @home_addr: home address for BU 
12106 + * @coa: care-of address for BU
12107 + * @flags: flags used for BU 
12108 + *
12109 + * Returns maximum lifetime for BUs determined by the lifetime of
12110 + * care-of address and the lifetime of home address.
12111 + **/
12112 +__u32 mipv6_mn_get_bulifetime(struct in6_addr *home_addr, struct in6_addr *coa,
12113 +                             __u8 flags)
12114 +{
12115 +       struct inet6_ifaddr *ifp_hoa, *ifp_coa;
12116 +       __u32 lifetime = (flags & MIPV6_BU_F_HOME ? 
12117 +                         HA_BU_DEF_LIFETIME : CN_BU_DEF_LIFETIME); 
12118 +
12119 +       ifp_hoa = ipv6_get_ifaddr(home_addr, NULL);
12120 +       if(!ifp_hoa) {
12121 +               DEBUG(DBG_INFO, "home address missing");
12122 +               return 0;
12123 +       }
12124 +       if (!(ifp_hoa->flags & IFA_F_PERMANENT)){
12125 +               if (ifp_hoa->valid_lft)
12126 +                       lifetime = min_t(__u32, lifetime, ifp_hoa->valid_lft);
12127 +               else
12128 +                       DEBUG(DBG_ERROR, "Zero lifetime for home address");
12129 +       }
12130 +       in6_ifa_put(ifp_hoa);
12131 +
12132 +       ifp_coa = ipv6_get_ifaddr(coa, NULL);
12133 +       if (!ifp_coa) { 
12134 +               DEBUG(DBG_INFO, "care-of address missing");
12135 +               return 0;
12136 +       }
12137 +       if (!(ifp_coa->flags & IFA_F_PERMANENT)) {
12138 +               if(ifp_coa->valid_lft)
12139 +                       lifetime = min_t(__u32, lifetime, ifp_coa->valid_lft);
12140 +               else
12141 +                       DEBUG(DBG_ERROR, 
12142 +                             "Zero lifetime for care-of address");
12143 +       }
12144 +       in6_ifa_put(ifp_coa);
12145 +
12146 +       DEBUG(DBG_INFO, "Lifetime for binding is %ld", lifetime);
12147 +       return lifetime;
12148 +}
12149 +
12150 +static int 
12151 +mipv6_mn_tnl_rcv_send_bu_hook(struct ip6_tnl *t, struct sk_buff *skb)
12152 +{
12153 +       struct ipv6hdr *inner;
12154 +       struct ipv6hdr *outer = skb->nh.ipv6h; 
12155 +       struct mn_info *minfo = NULL;
12156 +       __u32 lifetime;
12157 +       __u8 user_flags = 0;
12158 +
12159 +       DEBUG_FUNC();
12160 +
12161 +       if (!is_mip6_tnl(t))
12162 +               return IP6_TNL_ACCEPT;
12163 +
12164 +       if (!mip6node_cnf.accept_ret_rout) {
12165 +               DEBUG(DBG_INFO, "Return routability administratively disabled" 
12166 +                     " not doing route optimization");
12167 +               return IP6_TNL_ACCEPT;
12168 +       }
12169 +       if (!pskb_may_pull(skb, skb->h.raw-skb->data+sizeof(*inner)))
12170 +               return IP6_TNL_DROP;
12171 +
12172 +       inner = (struct ipv6hdr *)skb->h.raw;
12173 +       
12174 +       read_lock(&mn_info_lock);
12175 +       minfo = mipv6_mninfo_get_by_home(&inner->daddr);
12176 +
12177 +       if (!minfo) {
12178 +               DEBUG(DBG_WARNING, "MN info missing");
12179 +               read_unlock(&mn_info_lock);
12180 +               return IP6_TNL_ACCEPT;
12181 +       }
12182 +       DEBUG(DBG_DATADUMP, "MIPV6 MN: Received a tunneled IPv6 packet"
12183 +             " to %x:%x:%x:%x:%x:%x:%x:%x,"
12184 +             " from %x:%x:%x:%x:%x:%x:%x:%x with\n tunnel header"
12185 +             "daddr: %x:%x:%x:%x:%x:%x:%x:%x,"
12186 +             "saddr: %x:%x:%x:%x:%x:%x:%x:%x", 
12187 +              NIPV6ADDR(&inner->daddr), NIPV6ADDR(&inner->saddr),
12188 +              NIPV6ADDR(&outer->daddr), NIPV6ADDR(&outer->saddr));
12189 +       
12190 +       spin_lock(&minfo->lock);
12191 +
12192 +       /* We don't send bus in response to all tunneled packets */
12193 +
12194 +        if (!ipv6_addr_cmp(&minfo->ha, &inner->saddr)) {
12195 +               spin_unlock(&minfo->lock);
12196 +               read_unlock(&mn_info_lock);
12197 +                DEBUG(DBG_ERROR, "HA BUG: Received a tunneled packet "
12198 +                     "originally sent by home agent, not sending BU");
12199 +               return IP6_TNL_ACCEPT;
12200 +        }
12201 +       spin_unlock(&minfo->lock);
12202 +       read_unlock(&mn_info_lock);
12203 +
12204 +       DEBUG(DBG_DATADUMP, "Sending BU to correspondent node");
12205 +
12206 +       user_flags |= mip6node_cnf.bu_cn_ack ? MIPV6_BU_F_ACK : 0;
12207 +
12208 +       if (inner->nexthdr != IPPROTO_DSTOPTS && 
12209 +           inner->nexthdr != IPPROTO_MOBILITY) {
12210 +               struct in6_addr coa;
12211 +               /* Don't start RR when receiving ICMP error messages */
12212 +               if (inner->nexthdr == IPPROTO_ICMPV6) {
12213 +                       int ptr = (u8*)(inner+1) - skb->data;
12214 +                       u8 type;
12215 +
12216 +                       if (skb_copy_bits(skb,
12217 +                                         ptr+offsetof(struct icmp6hdr,
12218 +                                                      icmp6_type),
12219 +                                         &type, 1)
12220 +                           || !(type & ICMPV6_INFOMSG_MASK)) {
12221 +                               return IP6_TNL_ACCEPT;
12222 +                       }
12223 +               }
12224 +               lifetime = mipv6_mn_get_bulifetime(&inner->daddr,
12225 +                                                  &outer->daddr, 0); 
12226 +               if (lifetime && 
12227 +                   !mipv6_get_care_of_address(&inner->daddr, &coa)) {
12228 +                       write_lock(&bul_lock);
12229 +                       mipv6_send_bu(&inner->daddr, &inner->saddr, &coa,
12230 +                                     INITIAL_BINDACK_TIMEOUT,
12231 +                                     MAX_BINDACK_TIMEOUT, 1, 
12232 +                                     user_flags,
12233 +                                     lifetime, NULL);
12234 +                       write_unlock(&bul_lock);
12235 +               }
12236 +       }
12237 +       DEBUG(DBG_DATADUMP, "setting rcv_tunnel flag in skb");
12238 +       skb->security |= MIPV6_RCV_TUNNEL;
12239 +       return IP6_TNL_ACCEPT;
12240 +}
12241 +
12242 +static struct ip6_tnl_hook_ops mipv6_mn_tnl_rcv_send_bu_ops = {
12243 +       {NULL, NULL}, 
12244 +       IP6_TNL_PRE_DECAP,
12245 +       IP6_TNL_PRI_FIRST,
12246 +       mipv6_mn_tnl_rcv_send_bu_hook
12247 +};
12248 +
12249 +static int
12250 +mipv6_mn_tnl_xmit_stats_hook(struct ip6_tnl *t, struct sk_buff *skb)
12251 +{
12252 +       DEBUG_FUNC();
12253 +       if (is_mip6_tnl(t))
12254 +               MIPV6_INC_STATS(n_encapsulations);
12255 +       return IP6_TNL_ACCEPT;
12256 +}
12257 +
12258 +static struct ip6_tnl_hook_ops mipv6_mn_tnl_xmit_stats_ops = {
12259 +       {NULL, NULL},
12260 +       IP6_TNL_PRE_ENCAP,
12261 +       IP6_TNL_PRI_LAST,
12262 +       mipv6_mn_tnl_xmit_stats_hook
12263 +};
12264 +
12265 +static int
12266 +mipv6_mn_tnl_rcv_stats_hook(struct ip6_tnl *t, struct sk_buff *skb)
12267 +{
12268 +       DEBUG_FUNC();   
12269 +       if (is_mip6_tnl(t))
12270 +               MIPV6_INC_STATS(n_decapsulations);
12271 +       return IP6_TNL_ACCEPT;
12272 +}
12273 +
12274 +static struct ip6_tnl_hook_ops mipv6_mn_tnl_rcv_stats_ops = {
12275 +       {NULL, NULL},
12276 +       IP6_TNL_PRE_DECAP,
12277 +       IP6_TNL_PRI_LAST,
12278 +       mipv6_mn_tnl_rcv_stats_hook
12279 +};
12280 +
12281 +static void mn_check_tunneled_packet(struct sk_buff *skb)
12282 +{
12283 +       DEBUG_FUNC();
12284 +       /* If tunnel flag was set */
12285 +       if (skb->security & MIPV6_RCV_TUNNEL) {
12286 +               struct in6_addr coa; 
12287 +               __u32 lifetime;
12288 +               __u8 user_flags = 0;
12289 +               int ptr = (u8*)(skb->nh.ipv6h+1) - skb->data;
12290 +               int len = skb->len - ptr;
12291 +               __u8 nexthdr = skb->nh.ipv6h->nexthdr;
12292 +
12293 +               if (len < 0)
12294 +                       return;
12295 +
12296 +               ptr = ipv6_skip_exthdr(skb, ptr, &nexthdr, len);
12297 +               if (ptr < 0)
12298 +                       return;
12299 +
12300 +               if (!mip6node_cnf.accept_ret_rout) {
12301 +                       DEBUG(DBG_INFO, "Return routability administratively disabled");
12302 +                       return;
12303 +               }
12304 +               if (nexthdr == IPPROTO_MOBILITY)
12305 +                       return;
12306 +             
12307 +               /* Don't start RR when receiving ICMP error messages */
12308 +               if (nexthdr == IPPROTO_ICMPV6) {
12309 +                       u8 type;
12310 +
12311 +                       if (skb_copy_bits(skb,
12312 +                                         ptr+offsetof(struct icmp6hdr,
12313 +                                                      icmp6_type),
12314 +                                         &type, 1)
12315 +                           || !(type & ICMPV6_INFOMSG_MASK)) {
12316 +                               return;
12317 +                       }
12318 +               }
12319 +               user_flags |= mip6node_cnf.bu_cn_ack ? MIPV6_BU_F_ACK : 0;
12320 +               mipv6_get_care_of_address(&skb->nh.ipv6h->daddr, &coa);
12321 +               lifetime = mipv6_mn_get_bulifetime(&skb->nh.ipv6h->daddr,
12322 +                                                        &coa, 0); 
12323 +
12324 +               DEBUG(DBG_WARNING, "packet to address %x:%x:%x:%x:%x:%x:%x:%x"
12325 +                     "was tunneled. Sending BU to CN" 
12326 +                     "%x:%x:%x:%x:%x:%x:%x:%x", 
12327 +                     NIPV6ADDR(&skb->nh.ipv6h->daddr),
12328 +                     NIPV6ADDR(&skb->nh.ipv6h->saddr)); 
12329 +               /* This should work also with home address option */
12330 +               
12331 +               write_lock(&bul_lock);
12332 +               mipv6_send_bu(&skb->nh.ipv6h->daddr, &skb->nh.ipv6h->saddr, 
12333 +                             &coa, INITIAL_BINDACK_TIMEOUT,
12334 +                             MAX_BINDACK_TIMEOUT, 1, user_flags,
12335 +                             lifetime, NULL);
12336 +               write_unlock(&bul_lock);
12337 +       }
12338 +}
12339 +
12340 +static int sched_mv_home_addr_task(struct in6_addr *haddr, int plen_new, 
12341 +                                  int newif, int oldif, struct handoff *ho)
12342 +{
12343 +       int alloc_size;
12344 +       struct ifr_holder *ifrh;
12345 +
12346 +       alloc_size = sizeof(*ifrh) + (ho ? sizeof(*ho): 0);
12347 +       if ((ifrh = kmalloc(alloc_size, GFP_ATOMIC)) == NULL) {
12348 +               DEBUG(DBG_ERROR, "Out of memory");
12349 +               return -1;
12350 +       } 
12351 +       if (ho) {
12352 +               ifrh->ho = (struct handoff *)((struct ifr_holder *)(ifrh + 1));
12353 +               memcpy(ifrh->ho, ho, sizeof(*ho));
12354 +       } else 
12355 +               ifrh->ho = NULL;
12356 +
12357 +       /* must queue task to avoid deadlock with rtnl */
12358 +       ifrh->ifr.ifr6_ifindex = newif;
12359 +       ifrh->ifr.ifr6_prefixlen = plen_new;
12360 +       ipv6_addr_copy(&ifrh->ifr.ifr6_addr, haddr);
12361 +       ifrh->old_ifi = oldif;
12362 +       
12363 +       spin_lock_bh(&ifrh_lock);
12364 +       list_add_tail(&ifrh->list, &ifrh_list);
12365 +       spin_unlock_bh(&ifrh_lock);
12366 +
12367 +       schedule_task(&mv_home_addr_task);
12368 +
12369 +       return 0;
12370 +}
12371 +
12372 +static void send_ret_home_ns(struct in6_addr *ha_addr, 
12373 +                            struct in6_addr *home_addr,
12374 +                            int ifindex)
12375 +{
12376 +       struct in6_addr nil;
12377 +       struct in6_addr mcaddr;
12378 +       struct net_device *dev = dev_get_by_index(ifindex);
12379 +       if (!dev)
12380 +               return;
12381 +       memset(&nil, 0, sizeof(nil));
12382 +       addrconf_addr_solict_mult(home_addr, &mcaddr);
12383 +       ndisc_send_ns(dev, NULL, home_addr, &mcaddr, &nil); 
12384 +       dev_put(dev);
12385 +}
12386 +
12387 +static inline int ha_is_reachable(int ifindex, struct in6_addr *ha)
12388 +{
12389 +       struct net_device *dev;
12390 +       int reachable = 0;
12391 +
12392 +       dev = dev_get_by_index(ifindex);
12393 +       if (dev) {
12394 +               struct neighbour *neigh;
12395 +               if ((neigh = ndisc_get_neigh(dev, ha)) != NULL) {
12396 +                       read_lock_bh(&neigh->lock);
12397 +                       if (neigh->nud_state&NUD_VALID)
12398 +                               reachable = 1;
12399 +                       read_unlock_bh(&neigh->lock);
12400 +                       neigh_release(neigh);
12401 +               }
12402 +               dev_put(dev);
12403 +       }
12404 +       return reachable;
12405 +}
12406 +
12407 +static int mn_ha_handoff(struct handoff *ho)
12408 +{
12409 +       struct list_head *lh;
12410 +       struct mn_info *minfo;
12411 +       struct in6_addr *coa= ho->coa;
12412 +       int wait_mv_home = 0; 
12413 +
12414 +       read_lock_bh(&mn_info_lock);
12415 +       list_for_each(lh, &mn_info_list) {
12416 +               __u8 has_home_reg;
12417 +               int ifindex;
12418 +               struct in6_addr ha;
12419 +               __u8 athome;
12420 +               __u32 lifetime;
12421 +               struct mipv6_bul_entry *entry = NULL;
12422 +               
12423 +               minfo = list_entry(lh, struct mn_info, list);
12424 +               spin_lock(&minfo->lock);
12425 +               has_home_reg = minfo->has_home_reg;
12426 +               ifindex = minfo->ifindex;
12427 +               ipv6_addr_copy(&ha, &minfo->ha);
12428 +               
12429 +               if (mipv6_prefix_compare(&ho->rtr_addr, &minfo->home_addr,
12430 +                                        ho->plen)) {
12431 +                       if (minfo->has_home_reg)
12432 +                               athome = minfo->is_at_home = MN_RETURNING_HOME;
12433 +                       else
12434 +                               athome = minfo->is_at_home = MN_AT_HOME;
12435 +                       coa = &minfo->home_addr;
12436 +
12437 +                       spin_unlock(&minfo->lock);
12438 +#if 0                  
12439 +                       /* Cancel prefix solicitation, rtr is our HA */
12440 +                       mipv6_pfx_cancel_send(&ho->rtr_addr, ifindex);
12441 +#endif                 
12442 +                       minfo->ifindex = ho->ifindex;
12443 +
12444 +                       if (minfo->has_home_reg && 
12445 +                           !ha_is_reachable(ho->ifindex, &minfo->ha)) {
12446 +                               send_ret_home_ns(&minfo->ha,
12447 +                                                &minfo->home_addr, 
12448 +                                                ho->ifindex);
12449 +                               mipv6_mdet_set_curr_rtr_reachable(0);
12450 +                               wait_mv_home++;
12451 +                       }
12452 +                       if (ifindex != ho->ifindex){
12453 +                               wait_mv_home++;
12454 +                               DEBUG(DBG_INFO, 
12455 +                                     "Moving home address back to "
12456 +                                     "the home interface");
12457 +                               sched_mv_home_addr_task(&minfo->home_addr, 
12458 +                                                       128,
12459 +                                                       ho->ifindex, 
12460 +                                                       ifindex, ho);
12461 +                       }
12462 +                       if (!has_home_reg || wait_mv_home)
12463 +                               continue;
12464 +                       
12465 +                       lifetime = 0;
12466 +
12467 +               } else {
12468 +                       athome = minfo->is_at_home = MN_NOT_AT_HOME;
12469 +                       if (minfo->ifindex_user != minfo->ifindex) {
12470 +                               DEBUG(DBG_INFO, "Scheduling home address move to virtual interface");
12471 +                               sched_mv_home_addr_task(&minfo->home_addr, 
12472 +                                                       128,
12473 +                                                       minfo->ifindex_user, 
12474 +                                                       minfo->ifindex, ho); /* Is minfo->ifindex correct */
12475 +                               
12476 +                               wait_mv_home++;
12477 +                       }
12478 +                       minfo->ifindex = minfo->ifindex_user;
12479 +                       spin_unlock(&minfo->lock);
12480 +                       if (wait_mv_home)
12481 +                               continue;
12482 +                       if (!has_home_reg &&
12483 +                           init_home_registration(&minfo->home_addr, 
12484 +                                                  ho->coa)) {
12485 +                               continue;
12486 +                       }
12487 +                       lifetime = mipv6_mn_get_bulifetime(&minfo->home_addr, 
12488 +                                                          ho->coa,
12489 +                                                          MIPV6_BU_F_HOME);
12490 +                       
12491 +               }
12492 +               write_lock(&bul_lock);
12493 +               if (!(entry = mipv6_bul_get(&ha, &minfo->home_addr)) ||
12494 +                   !(entry->flags & MIPV6_BU_F_HOME)) {
12495 +                       DEBUG(DBG_ERROR, 
12496 +                             "Unable to find home registration for "
12497 +                             "home address: %x:%x:%x:%x:%x:%x:%x:%x!\n",
12498 +                             NIPV6ADDR(&minfo->home_addr));
12499 +                       write_unlock(&bul_lock);
12500 +                       continue;
12501 +               }
12502 +               DEBUG(DBG_INFO, "Sending home de ? %d registration for "
12503 +                     "home address: %x:%x:%x:%x:%x:%x:%x:%x\n" 
12504 +                     "to home agent %x:%x:%x:%x:%x:%x:%x:%x, "
12505 +                     "with lifetime %ld", 
12506 +                     (athome != MN_NOT_AT_HOME),  
12507 +                     NIPV6ADDR(&entry->home_addr), 
12508 +                     NIPV6ADDR(&entry->cn_addr), lifetime);
12509 +               mipv6_send_bu(&entry->home_addr, &entry->cn_addr, 
12510 +                             coa, INITIAL_BINDACK_TIMEOUT, 
12511 +                             MAX_BINDACK_TIMEOUT, 1, entry->flags, 
12512 +                             lifetime, NULL);
12513 +               write_unlock(&bul_lock);
12514 +
12515 +       }
12516 +       read_unlock_bh(&mn_info_lock);
12517 +       return wait_mv_home;
12518 +}
12519 +/**
12520 + * mn_cn_handoff - called for every bul entry to send BU to CN
12521 + * @rawentry: bul entry
12522 + * @args: handoff event
12523 + * @sortkey:
12524 + *
12525 + * Since MN can have many home addresses and home networks, every BUL
12526 + * entry needs to be checked
12527 + **/
12528 +int mn_cn_handoff(void *rawentry, void *args, unsigned long *sortkey)
12529 +{
12530 +       struct mipv6_bul_entry *entry = (struct mipv6_bul_entry *)rawentry;
12531 +       struct in6_addr *coa = (struct in6_addr *)args;
12532 +
12533 +       DEBUG_FUNC();
12534 +
12535 +       /* Home registrations already handled by mn_ha_handoff */
12536 +       if (entry->flags & MIPV6_BU_F_HOME)
12537 +               return ITERATOR_CONT;
12538 +
12539 +       /* BUL is locked by mipv6_mobile_node_moved which calls us 
12540 +          through mipv6_bul_iterate */
12541 +
12542 +       if (mipv6_prefix_compare(coa, 
12543 +                                &entry->home_addr,
12544 +                                64)) {
12545 +               mipv6_send_bu(&entry->home_addr, &entry->cn_addr, 
12546 +                             &entry->home_addr, INITIAL_BINDACK_TIMEOUT, 
12547 +                             MAX_BINDACK_TIMEOUT, 1, entry->flags, 0, 
12548 +                             NULL);
12549 +       } else {
12550 +               u32 lifetime = mipv6_mn_get_bulifetime(&entry->home_addr, 
12551 +                                                      coa,
12552 +                                                      entry->flags);
12553 +               mipv6_send_bu(&entry->home_addr, &entry->cn_addr,
12554 +                              coa, INITIAL_BINDACK_TIMEOUT,
12555 +                             MAX_BINDACK_TIMEOUT, 1, entry->flags,
12556 +                             lifetime, NULL);
12557 +       }
12558 +       return ITERATOR_CONT;
12559 +}
12560 +
12561 +
12562 +int mn_bul_invalidate(void *rawentry, void *args, unsigned long *sortkey)
12563 +{
12564 +       struct mipv6_bul_entry *bul = (struct mipv6_bul_entry *)rawentry;
12565 +       struct bul_inval_args *arg = (struct bul_inval_args *)args;
12566 +
12567 +       DEBUG_FUNC();
12568 +
12569 +       if (!ipv6_addr_cmp(arg->cn, &bul->cn_addr) &&
12570 +           (!ipv6_addr_cmp(arg->mn, &bul->home_addr) ||
12571 +            !ipv6_addr_cmp(arg->mn, &bul->coa))) {
12572 +               if (arg->all_rr_states || !bul->rr ||
12573 +                   (bul->rr->rr_state != RR_INIT && 
12574 +                    bul->rr->rr_state != RR_DONE)) {
12575 +                       bul->state = ACK_ERROR;
12576 +                       bul->callback = bul_entry_expired;
12577 +                       bul->callback_time = jiffies +
12578 +                               DUMB_CN_BU_LIFETIME * HZ;
12579 +                       bul->expire = bul->callback_time;
12580 +                       DEBUG(DBG_INFO, "BUL entry set to ACK_ERROR");
12581 +                       mipv6_bul_reschedule(bul);
12582 +               }
12583 +       }
12584 +       return ITERATOR_CONT;
12585 +}
12586 +/**
12587 + * init_home_registration - start Home Registration process
12588 + * @home_addr: home address
12589 + * @coa: care-of address
12590 + *
12591 + * Checks whether we have a Home Agent address for this home address.
12592 + * If not starts Dynamic Home Agent Address Discovery.  Otherwise
12593 + * tries to register with home agent if not already registered.
12594 + * Returns 1, if home registration process is started and 0 otherwise
12595 + **/
12596 +int init_home_registration(struct in6_addr *home_addr, struct in6_addr *coa)
12597 +{
12598 +       struct mn_info *hinfo;
12599 +       struct in6_addr ha;
12600 +       __u8 man_conf;
12601 +       int ifindex;
12602 +       __u32 lifetime;
12603 +       __u8 user_flags = 0, flags;
12604 +
12605 +       DEBUG_FUNC();
12606 +
12607 +       read_lock_bh(&mn_info_lock);
12608 +        if ((hinfo = mipv6_mninfo_get_by_home(home_addr)) == NULL) {
12609 +                DEBUG(DBG_ERROR, "No mn_info found for address: "
12610 +                     "%x:%x:%x:%x:%x:%x:%x:%x",
12611 +                     NIPV6ADDR(home_addr));
12612 +               read_unlock_bh(&mn_info_lock);
12613 +                return -ENOENT;
12614 +        }
12615 +       spin_lock(&hinfo->lock);
12616 +       if (mipv6_prefix_compare(&hinfo->home_addr, coa, hinfo->home_plen)) { 
12617 +               spin_unlock(&hinfo->lock);
12618 +               read_unlock_bh(&mn_info_lock);
12619 +               DEBUG(DBG_INFO, "Adding home address, MN at home");
12620 +               return 1;
12621 +       }
12622 +        if (ipv6_addr_any(&hinfo->ha)) {
12623 +                int dhaad_id = mipv6_get_dhaad_id();
12624 +                hinfo->dhaad_id = dhaad_id;
12625 +               spin_unlock(&hinfo->lock);
12626 +                mipv6_icmpv6_send_dhaad_req(home_addr, hinfo->home_plen, dhaad_id);
12627 +               read_unlock_bh(&mn_info_lock);
12628 +                DEBUG(DBG_INFO,
12629 +                     "Home Agent address not set, initiating DHAAD");
12630 +                return 1;
12631 +        }
12632 +        ipv6_addr_copy(&ha, &hinfo->ha);
12633 +        man_conf = hinfo->man_conf;
12634 +        ifindex = hinfo->ifindex;
12635 +       spin_unlock(&hinfo->lock);
12636 +       read_unlock_bh(&mn_info_lock);
12637 +#if 0  
12638 +       if (man_conf)
12639 +               mipv6_pfx_add_ha(&ha, coa, ifindex);
12640 +#endif 
12641 +       if (mipv6_bul_exists(&ha, home_addr)) {
12642 +               DEBUG(DBG_INFO, "BU already sent to HA");
12643 +               return 0;
12644 +       }
12645 +       /* user flags received through sysctl */
12646 +       user_flags |= mip6node_cnf.bu_lladdr ? MIPV6_BU_F_LLADDR : 0;
12647 +       user_flags |= mip6node_cnf.bu_keymgm ? MIPV6_BU_F_KEYMGM : 0;
12648 +
12649 +       flags = MIPV6_BU_F_HOME | MIPV6_BU_F_ACK | user_flags;
12650 +
12651 +       lifetime = mipv6_mn_get_bulifetime(home_addr, coa, flags);
12652 +
12653 +       DEBUG(DBG_INFO, "Sending initial home registration for "
12654 +             "home address: %x:%x:%x:%x:%x:%x:%x:%x\n" 
12655 +             "to home agent %x:%x:%x:%x:%x:%x:%x:%x, "
12656 +             "with lifetime %ld, prefixlength %d",   
12657 +             NIPV6ADDR(home_addr), NIPV6ADDR(&ha), lifetime, 0);
12658 +
12659 +       write_lock_bh(&bul_lock);
12660 +       mipv6_send_bu(home_addr, &ha, coa, INITIAL_BINDACK_DAD_TIMEOUT,
12661 +                     MAX_BINDACK_TIMEOUT, 1, flags, lifetime, NULL);
12662 +       write_unlock_bh(&bul_lock);
12663 +
12664 +       return 1;
12665 +}
12666 +
12667 +/**
12668 + * mipv6_mobile_node_moved - Send BUs to all HAs and CNs
12669 + * @ho: handoff structure contains the new and previous routers
12670 + *
12671 + * Event for handoff.  Sends BUs everyone on Binding Update List.
12672 + **/
12673 +int mipv6_mobile_node_moved(struct handoff *ho)
12674 +{
12675 +#if 0
12676 +       int bu_to_prev_router = 1;
12677 +#endif
12678 +       int dummy;
12679 +
12680 +       DEBUG_FUNC();
12681 +
12682 +       ma_ctl_upd_iface(ho->ifindex, 
12683 +                        MA_IFACE_CURRENT | MA_IFACE_HAS_ROUTER, &dummy);
12684 +
12685 +       /* First send BU to HA, then to all other nodes that are on BU list */
12686 +       if (mn_ha_handoff(ho) != 0)
12687 +               return 0; /* Wait for move home address task */
12688 +#if 0   
12689 +       /* Add current care-of address to mn_info list, if current router acts 
12690 +          as a HA.*/ 
12691 +
12692 +       if (ho->home_address && bu_to_prev_router) 
12693 +               mipv6_mninfo_add(ho->coa, ho->plen, 
12694 +                                MN_AT_HOME, 0, &ho->rtr_addr, 
12695 +                                ho->plen, ROUTER_BU_DEF_LIFETIME,
12696 +                                0);
12697 +                                 
12698 +#endif
12699 +       return 0;               
12700 +}
12701 +
12702 +/**
12703 + * mipv6_mn_send_home_na - send NA when returning home
12704 + * @haddr: home address to advertise
12705 + *
12706 + * After returning home, MN must advertise all its valid addresses in
12707 + * home link to all nodes.
12708 + **/
12709 +void mipv6_mn_send_home_na(struct in6_addr *haddr)
12710 +{
12711 +       struct net_device *dev = NULL;
12712 +       struct in6_addr mc_allnodes;
12713 +       struct mn_info *hinfo = NULL;
12714
12715 +       read_lock(&mn_info_lock);
12716 +       hinfo = mipv6_mninfo_get_by_home(haddr);
12717 +       if (!hinfo) {
12718 +               read_unlock(&mn_info_lock);
12719 +               return;
12720 +       }
12721 +       spin_lock(&hinfo->lock);
12722 +       hinfo->is_at_home = MN_AT_HOME;
12723 +       dev = dev_get_by_index(hinfo->ifindex);
12724 +       spin_unlock(&hinfo->lock);
12725 +       read_unlock(&mn_info_lock);
12726 +       if (dev == NULL) {
12727 +               DEBUG(DBG_ERROR, "Send home_na: device not found.");
12728 +               return;
12729 +       }
12730 +       
12731 +       ipv6_addr_all_nodes(&mc_allnodes);
12732 +       ndisc_send_na(dev, NULL, &mc_allnodes, haddr, 0, 0, 1, 1);
12733 +       dev_put(dev);
12734 +}
12735 +
12736 +static int mn_use_hao(struct in6_addr *daddr, struct in6_addr *saddr)
12737 +{
12738 +       struct mipv6_bul_entry *entry;
12739 +       struct mn_info *minfo = NULL;
12740 +       int add_ha = 0;
12741 +
12742 +       read_lock_bh(&mn_info_lock);
12743 +       minfo = mipv6_mninfo_get_by_home(saddr);
12744 +       if (minfo && minfo->is_at_home != MN_AT_HOME) {
12745 +               read_lock_bh(&bul_lock);
12746 +               if ((entry = mipv6_bul_get(daddr, saddr)) == NULL) {
12747 +                       read_unlock_bh(&bul_lock);
12748 +                       read_unlock_bh(&mn_info_lock);
12749 +                       return add_ha;
12750 +               }
12751 +               add_ha = (entry->state != ACK_ERROR &&
12752 +                         (!entry->rr || entry->rr->rr_state == RR_DONE || 
12753 +                          entry->flags & MIPV6_BU_F_HOME));
12754 +               read_unlock_bh(&bul_lock);
12755 +       }
12756 +       read_unlock_bh(&mn_info_lock);
12757 +       return add_ha;
12758 +}
12759 +
12760 +static int 
12761 +mn_dev_event(struct notifier_block *nb, unsigned long event, void *ptr)
12762 +{
12763 +       struct net_device *dev = ptr;
12764 +       struct list_head *lh;
12765 +       struct mn_info *minfo;
12766 +       int newif = 0;
12767 +
12768 +       /* here are probably the events we need to worry about */
12769 +       switch (event) {
12770 +       case NETDEV_UP:
12771 +               DEBUG(DBG_DATADUMP, "New netdevice %s registered.", dev->name);
12772 +               if (dev->type != ARPHRD_LOOPBACK && !dev_is_mip6_tnl(dev)) 
12773 +                       ma_ctl_add_iface(dev->ifindex);
12774 +                       
12775 +               break;
12776 +       case NETDEV_GOING_DOWN:
12777 +               DEBUG(DBG_DATADUMP, "Netdevice %s disappeared.", dev->name);
12778 +               /* 
12779 +                * Go through mn_info list and move all home addresses on the
12780 +                * netdev going down to a new device. This will make it 
12781 +                 * practically impossible for the home address to return home,
12782 +                * but allow MN to retain its connections using the address.
12783 +                */
12784 +
12785 +               read_lock_bh(&mn_info_lock);
12786 +               list_for_each(lh, &mn_info_list) {
12787 +                       minfo = list_entry(lh, struct mn_info, list);
12788 +                       spin_lock(&minfo->lock);
12789 +                       if (minfo->ifindex == dev->ifindex) {
12790 +                               if (sched_mv_home_addr_task(&minfo->home_addr, 128, 
12791 +                                                           minfo->ifindex_user, 
12792 +                                                           0, NULL) < 0) {
12793 +                                       minfo->ifindex = 0;
12794 +                                       spin_unlock(&minfo->lock);
12795 +                                       read_unlock_bh(&mn_info_lock);
12796 +                                       return NOTIFY_DONE;
12797 +                               } else { 
12798 +                                       minfo->ifindex = minfo->ifindex_user;
12799 +                                       if (minfo->is_at_home) {
12800 +                                               minfo->is_at_home = 0;
12801 +
12802 +                                       }
12803 +                                       newif = minfo->ifindex_user;
12804 +                               }
12805 +                       }
12806 +                       spin_unlock(&minfo->lock);                              
12807 +               }
12808 +               
12809 +               read_unlock_bh(&mn_info_lock);
12810 +       }
12811 +       ma_ctl_upd_iface(dev->ifindex, MA_IFACE_NOT_PRESENT, &newif);
12812 +       mipv6_mdet_del_if(dev->ifindex);
12813 +
12814 +       return NOTIFY_DONE;
12815 +}
12816 +
12817 +struct notifier_block mipv6_mn_dev_notifier = {
12818 +       mn_dev_event,
12819 +       NULL,
12820 +       0 /* check if using zero is ok */
12821 +};
12822 +
12823 +static void deprecate_addr(struct mn_info *minfo)
12824 +{
12825 +       /*
12826 +        * Lookup address from IPv6 address list and set deprecated flag
12827 +        */
12828 +       
12829 +}
12830 +
12831 +/*
12832 + * Required because we can only modify addresses after the packet is
12833 + * constructed.  We otherwise mess with higher level protocol
12834 + * pseudoheaders. With strict protocol layering life would be SO much
12835 + * easier!  
12836 + */
12837 +static unsigned int modify_xmit_addrs(unsigned int hooknum,
12838 +                                     struct sk_buff **pskb,
12839 +                                     const struct net_device *in,
12840 +                                     const struct net_device *out,
12841 +                                     int (*okfn) (struct sk_buff *))
12842 +{
12843 +       struct sk_buff *skb = *pskb;
12844 +
12845 +       DEBUG_FUNC();
12846 +       
12847 +       if (skb) {
12848 +               struct ipv6hdr *hdr = skb->nh.ipv6h;
12849 +               struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
12850 +               struct mipv6_bul_entry *bule;
12851 +               struct in6_addr *daddr;
12852 +
12853 +               if (!ipv6_addr_any(&opt->hoa))
12854 +                       daddr = &opt->hoa;
12855 +               else
12856 +                       daddr = &hdr->daddr;
12857 +
12858 +               /* We don't consult bul when sending a BU to avoid deadlock, since
12859 +                * BUL is already locked. 
12860 +                */
12861 +               
12862 +
12863 +               if (opt->mipv6_flags & MIPV6_SND_HAO && 
12864 +                   !(opt->mipv6_flags & MIPV6_SND_BU)) {
12865 +                       write_lock(&bul_lock);
12866 +                       bule = mipv6_bul_get(daddr, &hdr->saddr);
12867 +                       if (!bule) {
12868 +                               write_unlock(&bul_lock);
12869 +                               return NF_ACCEPT;
12870 +                       }
12871 +                       if (!bule->rr || bule->rr->rr_state == RR_DONE || 
12872 +                           bule->flags & MIPV6_BU_F_HOME) {
12873 +                               DEBUG(DBG_DATADUMP, 
12874 +                                     "Replace source address with CoA and reroute");
12875 +                               ipv6_addr_copy(&hdr->saddr, &bule->coa);
12876 +                               skb->nfcache |= NFC_ALTERED;
12877 +                       }
12878 +                       write_unlock(&bul_lock);
12879 +               } else if (opt->mipv6_flags & MIPV6_SND_HAO) {
12880 +                       mipv6_get_care_of_address(&hdr->saddr, &hdr->saddr);
12881 +                       skb->nfcache |= NFC_ALTERED;
12882 +               }
12883 +       }
12884 +       return NF_ACCEPT;
12885 +}
12886 +
12887 +/* We set a netfilter hook so that we can modify outgoing packet's
12888 + * source addresses 
12889 + */
12890 +struct nf_hook_ops addr_modify_hook_ops = {
12891 +       {NULL, NULL},           /* List head, no predecessor, no successor */
12892 +       modify_xmit_addrs,
12893 +       PF_INET6,
12894 +       NF_IP6_LOCAL_OUT,
12895 +       NF_IP6_PRI_FIRST        /* Should be of EXTREMELY high priority since we
12896 +                                * do not want to mess with IPSec (possibly
12897 +                                * implemented as packet filter)
12898 +                                */
12899 +};
12900 +
12901 +#define MN_INFO_LEN 77
12902 +
12903 +static int mn_proc_info(char *buffer, char **start, off_t offset,
12904 +                       int length)
12905 +{
12906 +       struct list_head *p;
12907 +       struct mn_info *minfo;
12908 +       int len = 0, skip = 0;
12909 +
12910 +       DEBUG_FUNC();
12911 +
12912 +       read_lock_bh(&mn_info_lock);
12913 +       list_for_each(p, &mn_info_list) {
12914 +               if (len < offset / MN_INFO_LEN) {
12915 +                       skip++;
12916 +                       continue;
12917 +               }
12918 +               if (len >= length)
12919 +                       break;
12920 +               minfo = list_entry(p, struct mn_info, list);
12921 +               spin_lock(&minfo->lock);
12922 +               len += sprintf(buffer + len, "%02d %08x%08x%08x%08x %02x "
12923 +                              "%08x%08x%08x%08x %d %d\n",
12924 +                              minfo->ifindex,
12925 +                              ntohl(minfo->home_addr.s6_addr32[0]),
12926 +                              ntohl(minfo->home_addr.s6_addr32[1]),
12927 +                              ntohl(minfo->home_addr.s6_addr32[2]),
12928 +                              ntohl(minfo->home_addr.s6_addr32[3]),
12929 +                              minfo->home_plen,
12930 +                              ntohl(minfo->ha.s6_addr32[0]),
12931 +                              ntohl(minfo->ha.s6_addr32[1]),
12932 +                              ntohl(minfo->ha.s6_addr32[2]),
12933 +                              ntohl(minfo->ha.s6_addr32[3]),
12934 +                              minfo->is_at_home, minfo->has_home_reg);
12935 +               spin_unlock(&minfo->lock);
12936 +       }
12937 +       read_unlock_bh(&mn_info_lock);
12938 +
12939 +       *start = buffer;
12940 +       if (offset)
12941 +               *start += offset % MN_INFO_LEN;
12942 +
12943 +       len -= offset % MN_INFO_LEN;
12944 +
12945 +       if (len > length)
12946 +               len = length;
12947 +       if (len < 0)
12948 +               len = 0;
12949 +       
12950 +       return len;
12951 +}
12952 +
12953 +int mipv6_mn_ha_nd_update(struct net_device *dev,
12954 +                         struct in6_addr *ha, u8 *lladdr)
12955 +{
12956 +       int valid = 0;
12957 +       struct neighbour *neigh;
12958 +       if ((neigh = ndisc_get_neigh(dev, ha))) {
12959 +               read_lock(&neigh->lock);
12960 +               valid = neigh->nud_state & NUD_VALID;
12961 +               read_unlock(&neigh->lock);
12962 +               if (!valid && lladdr)
12963 +                       neigh_update(neigh, lladdr, NUD_REACHABLE, 0, 1);
12964 +               neigh_release(neigh);
12965 +       }
12966 +       return valid;
12967 +}
12968 +
12969 +int mipv6_mn_ha_probe(struct inet6_ifaddr *ifp, u8 *lladdr)
12970 +{
12971 +       struct mn_info *minfo;
12972 +
12973 +       if (!(minfo = mipv6_mninfo_get_by_home(&ifp->addr)) ||
12974 +           ipv6_addr_any(&minfo->ha))
12975 +               return 0;
12976 +
12977 +       if (mipv6_mn_ha_nd_update(ifp->idev->dev, &minfo->ha, lladdr))
12978 +               mipv6_mdet_retrigger_ho();
12979 +       return 1;
12980 +}
12981 +
12982 +int __init mipv6_mn_init(void)
12983 +{
12984 +       struct net_device *dev;
12985 +
12986 +       DEBUG_FUNC();
12987 +
12988 +       if (mipv6_add_tnl_to_ha())
12989 +               return -ENODEV;
12990 +
12991 +       mipv6_bul_init(MIPV6_BUL_SIZE);
12992 +       mip6_fn.mn_use_hao = mn_use_hao;
12993 +       mip6_fn.mn_check_tunneled_packet = mn_check_tunneled_packet;
12994 +       INIT_TQUEUE(&mv_home_addr_task, mv_home_addr, NULL);
12995 +
12996 +       ma_ctl_init();
12997 +       for (dev = dev_base; dev; dev = dev->next) {
12998 +               if (dev->flags & IFF_UP && 
12999 +                   dev->type != ARPHRD_LOOPBACK && !dev_is_mip6_tnl(dev)) {
13000 +                       ma_ctl_add_iface(dev->ifindex);
13001 +               }
13002 +       } 
13003 +       DEBUG(DBG_INFO, "Multiaccess support initialized");
13004 +
13005 +       register_netdevice_notifier(&mipv6_mn_dev_notifier);
13006 +       register_inet6addr_notifier(&mipv6_mn_inet6addr_notifier);
13007 +
13008 +       ip6ip6_tnl_register_hook(&mipv6_mn_tnl_rcv_send_bu_ops);
13009 +       ip6ip6_tnl_register_hook(&mipv6_mn_tnl_xmit_stats_ops);
13010 +       ip6ip6_tnl_register_hook(&mipv6_mn_tnl_rcv_stats_ops);
13011 +
13012 +       MIPV6_SETCALL(mipv6_set_home, mipv6_mn_set_home);
13013 +
13014 +       mipv6_initialize_mdetect();
13015 +
13016 +       /* COA to home transformation hook */
13017 +       MIPV6_SETCALL(mipv6_get_home_address, mipv6_get_saddr_hook);
13018 +       MIPV6_SETCALL(mipv6_mn_ha_probe, mipv6_mn_ha_probe);
13019 +       MIPV6_SETCALL(mipv6_is_home_addr, mipv6_mn_is_home_addr);
13020 +       proc_net_create("mip6_mninfo", 0, mn_proc_info);
13021 +       /* Set packet modification hook (source addresses) */
13022 +       nf_register_hook(&addr_modify_hook_ops);
13023 +
13024 +       return 0;
13025 +}
13026 +
13027 +void __exit mipv6_mn_exit(void)
13028 +{
13029 +       struct list_head *lh, *tmp;
13030 +       struct mn_info *minfo;
13031 +       DEBUG_FUNC();
13032 +       
13033 +       mip6_fn.mn_use_hao = NULL;
13034 +       mip6_fn.mn_check_tunneled_packet = NULL;
13035 +       
13036 +       MIPV6_RESETCALL(mipv6_set_home);
13037 +       MIPV6_RESETCALL(mipv6_get_home_address);
13038 +       MIPV6_RESETCALL(mipv6_mn_ha_probe);
13039 +       MIPV6_RESETCALL(mipv6_is_home_addr);
13040 +       nf_unregister_hook(&addr_modify_hook_ops);
13041 +       proc_net_remove("mip6_mninfo");
13042 +       mipv6_shutdown_mdetect();
13043 +       ip6ip6_tnl_unregister_hook(&mipv6_mn_tnl_rcv_stats_ops);
13044 +       ip6ip6_tnl_unregister_hook(&mipv6_mn_tnl_xmit_stats_ops);
13045 +       ip6ip6_tnl_unregister_hook(&mipv6_mn_tnl_rcv_send_bu_ops);
13046 +       ma_ctl_clean();
13047 +
13048 +       unregister_inet6addr_notifier(&mipv6_mn_inet6addr_notifier);
13049 +       unregister_netdevice_notifier(&mipv6_mn_dev_notifier);
13050 +       write_lock_bh(&mn_info_lock);
13051 +
13052 +       list_for_each_safe(lh, tmp, &mn_info_list) {
13053 +               minfo = list_entry(lh, struct mn_info, list);
13054 +               if (minfo->is_at_home == MN_NOT_AT_HOME) 
13055 +                       deprecate_addr(minfo);
13056 +               list_del(&minfo->list);
13057 +               kfree(minfo);
13058 +       }
13059 +       write_unlock_bh(&mn_info_lock);
13060 +       mipv6_bul_exit();
13061 +       flush_scheduled_tasks();
13062 +       mipv6_del_tnl_to_ha();
13063 +}
13064 --- /dev/null
13065 +++ linux-2.4.27/net/ipv6/mobile_ip6/mn.h
13066 @@ -0,0 +1,96 @@
13067 +/*
13068 + *      MIPL Mobile IPv6 Mobile Node header file
13069 + *
13070 + *      $Id$
13071 + *
13072 + *      This program is free software; you can redistribute it and/or
13073 + *      modify it under the terms of the GNU General Public License
13074 + *      as published by the Free Software Foundation; either version
13075 + *      2 of the License, or (at your option) any later version.
13076 + */
13077 +
13078 +#ifndef _MN_H
13079 +#define _MN_H
13080 +
13081 +#include <linux/in6.h>
13082 +
13083 +/* constants for sending of BUs*/
13084 +#define HA_BU_DEF_LIFETIME 10000
13085 +#define CN_BU_DEF_LIFETIME 420 /* Max lifetime for RR bindings from RFC 3775 */
13086 +#define DUMB_CN_BU_LIFETIME 600 /* BUL entry lifetime in case of dumb CN */
13087 +#define ROUTER_BU_DEF_LIFETIME 30 /* For packet forwarding from previous coa */
13088 +#define ERROR_DEF_LIFETIME DUMB_CN_BU_LIFETIME
13089 +
13090 +extern rwlock_t mn_info_lock;
13091 +
13092 +#define MN_NOT_AT_HOME 0
13093 +#define MN_RETURNING_HOME 1
13094 +#define MN_AT_HOME 2
13095 +
13096 +/*
13097 + * Mobile Node information record
13098 + */
13099 +struct mn_info {
13100 +       struct in6_addr home_addr;
13101 +       struct in6_addr ha;
13102 +       __u8 home_plen;
13103 +       __u8 is_at_home;
13104 +       __u8 has_home_reg;
13105 +       __u8 man_conf;
13106 +       int ifindex;
13107 +       int ifindex_user; 
13108 +       unsigned long home_addr_expires;
13109 +       unsigned short dhaad_id;
13110 +       struct list_head list;
13111 +       spinlock_t lock;
13112 +};
13113 +
13114 +/* prototypes for interface functions */
13115 +int mipv6_mn_init(void);
13116 +void mipv6_mn_exit(void);
13117 +
13118 +struct handoff;
13119 +
13120 +/* Interface to movement detection */
13121 +int mipv6_mobile_node_moved(struct handoff *ho);
13122 +
13123 +void mipv6_mn_send_home_na(struct in6_addr *haddr);
13124 +/* Init home reg. with coa */
13125 +int init_home_registration(struct in6_addr *home_addr, struct in6_addr *coa);
13126 +
13127 +/* mn_info functions that require locking by caller */
13128 +struct mn_info *mipv6_mninfo_get_by_home(struct in6_addr *haddr);
13129 +
13130 +struct mn_info *mipv6_mninfo_get_by_ha(struct in6_addr *home_agent);
13131 +
13132 +struct mn_info *mipv6_mninfo_get_by_id(unsigned short id);
13133 +
13134 +/* "safe" mn_info functions */
13135 +void mipv6_mninfo_add(int ifindex, struct in6_addr *home_addr, int plen, 
13136 +                     int isathome, unsigned long lifetime, struct in6_addr *ha, 
13137 +                     int ha_plen, unsigned long ha_lifetime, int man_conf);
13138 +
13139 +int mipv6_mninfo_del(struct in6_addr *home_addr, int del_dyn_only);
13140 +
13141 +void mipv6_mn_set_home_reg(struct in6_addr *home_addr, int has_home_reg);
13142 +
13143 +int mipv6_mn_is_at_home(struct in6_addr *addr);
13144 +
13145 +int mipv6_mn_is_home_addr(struct in6_addr *addr);
13146 +
13147 +__u32 mipv6_mn_get_bulifetime(struct in6_addr *home_addr, 
13148 +                             struct in6_addr *coa, __u8 flags);
13149 +int mn_cn_handoff(void *rawentry, void *args, unsigned long *sortkey);
13150 +
13151 +int mipv6_mn_ha_nd_update(struct net_device *dev,
13152 +                         struct in6_addr *ha, u8 *lladdr);
13153 +
13154 +struct bul_inval_args {
13155 +       int all_rr_states;
13156 +       struct in6_addr *cn;
13157 +       struct in6_addr *mn;
13158 +};
13159 +
13160 +int mn_bul_invalidate(void *rawentry, void *args, unsigned long *sortkey);
13161 +
13162 +#endif /* _MN_H */
13163 --- /dev/null
13164 +++ linux-2.4.27/net/ipv6/mobile_ip6/mobhdr.h
13165 @@ -0,0 +1,101 @@
13166 +/*
13167 + *      MIPL Mobile IPv6 Mobility Header send and receive
13168 + *
13169 + *      $Id$
13170 + *
13171 + *      This program is free software; you can redistribute it and/or
13172 + *      modify it under the terms of the GNU General Public License
13173 + *      as published by the Free Software Foundation; either version
13174 + *      2 of the License, or (at your option) any later version.
13175 + */
13176 +
13177 +#ifndef _MOBHDR_H
13178 +#define _MOBHDR_H
13179 +
13180 +#include <net/mipv6.h>
13181 +
13182 +/* RR states for mipv6_send_bu() */
13183 +#define RR_INIT                        0x00
13184 +#define RR_WAITH               0x01
13185 +#define RR_WAITC               0x02
13186 +#define RR_WAITHC              0x13
13187 +#define RR_DONE                        0x10
13188 +
13189 +#define MH_UNKNOWN_CN 1
13190 +#define MH_AUTH_FAILED 2
13191 +#define MH_SEQUENCE_MISMATCH 3
13192 +
13193 +struct mipv6_bul_entry;
13194 +struct sk_buff;
13195 +
13196 +int mipv6_mh_common_init(void);
13197 +void mipv6_mh_common_exit(void);
13198 +int mipv6_mh_mn_init(void);
13199 +void mipv6_mh_mn_exit(void);
13200 +
13201 +struct mipv6_mh_opt {
13202 +       struct mipv6_mo_alt_coa         *alt_coa;
13203 +       struct mipv6_mo_nonce_indices   *nonce_indices;
13204 +       struct mipv6_mo_bauth_data      *auth_data;
13205 +       struct mipv6_mo_br_advice       *br_advice;
13206 +       int freelen;
13207 +       int totlen;
13208 +       u8 *next_free;
13209 +       u8 data[0];
13210 +};
13211 +
13212 +struct mobopt {
13213 +       struct mipv6_mo_alt_coa         *alt_coa;
13214 +       struct mipv6_mo_nonce_indices   *nonce_indices;
13215 +       struct mipv6_mo_bauth_data      *auth_data;
13216 +       struct mipv6_mo_br_advice       *br_advice;
13217 +};
13218 +
13219 +struct mipv6_mh_opt *alloc_mh_opts(int totlen);
13220 +int append_mh_opt(struct mipv6_mh_opt *ops, u8 type, u8 len, void *data);
13221 +int parse_mo_tlv(void *mos, int len, struct mobopt *opts);
13222 +int mipv6_add_pad(u8 *data, int n);
13223 +
13224 +struct mipv6_auth_parm {
13225 +       struct in6_addr *coa;
13226 +       struct in6_addr *cn_addr;
13227 +       __u8 *k_bu;
13228 +};
13229 +
13230 +int send_mh(struct in6_addr *daddr, struct in6_addr *saddr, 
13231 +           u8 msg_type, u8 msg_len, u8 *msg,
13232 +           struct in6_addr *hao_addr, struct in6_addr *rth_addr,
13233 +           struct mipv6_mh_opt *ops, struct mipv6_auth_parm *parm);
13234 +
13235 +int mipv6_mh_register(int type, int (*func)(struct sk_buff *,
13236 +       struct in6_addr *, struct in6_addr *, 
13237 +       struct in6_addr *, struct in6_addr *, struct mipv6_mh *));
13238 +
13239 +void mipv6_mh_unregister(int type);
13240 +
13241 +int mipv6_send_brr(struct in6_addr *saddr, struct in6_addr *daddr,
13242 +                  struct mipv6_mh_opt *ops);
13243 +
13244 +int mipv6_send_bu(struct in6_addr *saddr, struct in6_addr *daddr, 
13245 +                 struct in6_addr *coa, __u32 initdelay, 
13246 +                 __u32 maxackdelay, __u8 exp, __u8 flags,
13247 +                 __u32 lifetime, struct mipv6_mh_opt *ops);
13248 +
13249 +int mipv6_send_be(struct in6_addr *saddr, struct in6_addr *daddr, 
13250 +                 struct in6_addr *home, __u8 status);
13251 +
13252 +int mipv6_send_ba(struct in6_addr *saddr, struct in6_addr *daddr, 
13253 +                 struct in6_addr *auth_coa, struct in6_addr *rep_coa,
13254 +                 u8 status, u16 sequence, u32 lifetime, u8 *k_bu);
13255 +
13256 +/* Binding Authentication Data Option routines */
13257 +#define MAX_HASH_LENGTH 20
13258 +#define MIPV6_RR_MAC_LENGTH 12
13259 +
13260 +int mipv6_auth_build(struct in6_addr *cn_addr, struct in6_addr *coa, 
13261 +                    __u8 *opt, __u8 *aud_data, __u8 *k_bu);
13262 +
13263 +int mipv6_auth_check(struct in6_addr *cn_addr, struct in6_addr *coa, 
13264 +                    __u8 *opt, __u8 optlen, struct mipv6_mo_bauth_data *aud, 
13265 +                    __u8 *k_bu);
13266 +#endif /* _MOBHDR_H */
13267 --- /dev/null
13268 +++ linux-2.4.27/net/ipv6/mobile_ip6/mobhdr_common.c
13269 @@ -0,0 +1,1210 @@
13270 +/*
13271 + *     Mobile IPv6 Mobility Header Common Functions
13272 + *
13273 + *     Authors:
13274 + *     Antti Tuominen <ajtuomin@tml.hut.fi>
13275 + *
13276 + *      $Id: s.mh_recv.c 1.159 02/10/16 15:01:29+03:00 antti@traci.mipl.mediapoli.com $
13277 + *
13278 + *      This program is free software; you can redistribute it and/or
13279 + *      modify it under the terms of the GNU General Public License
13280 + *      as published by the Free Software Foundation; either version
13281 + *      2 of the License, or (at your option) any later version.
13282 + *
13283 + */
13284 +
13285 +#include <linux/autoconf.h>
13286 +#include <linux/types.h>
13287 +#include <linux/in6.h>
13288 +#include <linux/skbuff.h>
13289 +#include <linux/ipsec.h>
13290 +#include <linux/init.h>
13291 +#include <net/ipv6.h>
13292 +#include <net/ip6_route.h>
13293 +#include <net/addrconf.h>
13294 +#include <net/mipv6.h>
13295 +#include <net/checksum.h>
13296 +#include <net/protocol.h>
13297 +
13298 +#include "stats.h"
13299 +#include "debug.h"
13300 +#include "mobhdr.h"
13301 +#include "bcache.h"
13302 +
13303 +#include "rr_crypto.h"
13304 +#include "exthdrs.h"
13305 +#include "config.h"
13306 +
13307 +#define MIPV6_MH_MAX MIPV6_MH_BE
13308 +struct mh_proto {
13309 +       int     (*func) (struct sk_buff *,
13310 +                        struct in6_addr *, struct in6_addr *, 
13311 +                        struct in6_addr *, struct in6_addr *, 
13312 +                        struct mipv6_mh *);
13313 +};
13314 +
13315 +static struct mh_proto mh_rcv[MIPV6_MH_MAX];
13316 +
13317 +int mipv6_mh_register(int type, int (*func)(struct sk_buff *,
13318 +       struct in6_addr *, struct in6_addr *, 
13319 +       struct in6_addr *, struct in6_addr *, struct mipv6_mh *))
13320 +{
13321 +       if (mh_rcv[type].func != NULL)
13322 +               return -1;
13323 +
13324 +       mh_rcv[type].func = func;
13325 +
13326 +       return 0;
13327 +}
13328 +
13329 +void mipv6_mh_unregister(int type)
13330 +{
13331 +       if (type < 0 || type > MIPV6_MH_MAX)
13332 +               return;
13333 +
13334 +       mh_rcv[type].func = NULL;
13335 +}
13336 +
13337 +struct socket *mipv6_mh_socket = NULL;
13338 +
13339 +/* TODO: Fix fragmentation */
13340 +static int dstopts_getfrag(
13341 +       const void *data, struct in6_addr *addr,
13342 +       char *buff, unsigned int offset, unsigned int len)
13343 +{
13344 +       memcpy(buff, data + offset, len);
13345 +       return 0;
13346 +}
13347 +
13348 +struct mipv6_mh_opt *alloc_mh_opts(int totlen)
13349 +{
13350 +       struct mipv6_mh_opt *ops;
13351 +
13352 +       ops = kmalloc(sizeof(*ops) + totlen, GFP_ATOMIC);
13353 +       if (ops == NULL)
13354 +               return NULL;
13355 +
13356 +       memset(ops, 0, sizeof(*ops));
13357 +       ops->next_free = ops->data;
13358 +       ops->freelen = totlen;
13359 +
13360 +       return ops;
13361 +}
13362 +
13363 +int append_mh_opt(struct mipv6_mh_opt *ops, u8 type, u8 len, void *data)
13364 +{
13365 +       struct mipv6_mo *mo;
13366 +
13367 +       if (ops->next_free == NULL) {
13368 +               DEBUG(DBG_ERROR, "No free room for option");
13369 +               return -ENOMEM;
13370 +       }
13371 +       if (ops->freelen < len + 2) {
13372 +               DEBUG(DBG_ERROR, "No free room for option");
13373 +               return -ENOMEM;
13374 +       }
13375 +       else {
13376 +               ops->freelen -= (len + 2);
13377 +               ops->totlen += (len + 2);
13378 +       }
13379 +
13380 +       mo = (struct mipv6_mo *)ops->next_free;
13381 +       mo->type = type;
13382 +       mo->length = len;
13383 +
13384 +       switch (type) {
13385 +       case MIPV6_OPT_ALTERNATE_COA:
13386 +               ops->alt_coa = (struct mipv6_mo_alt_coa *)mo;
13387 +               ipv6_addr_copy(&ops->alt_coa->addr, (struct in6_addr *)data);
13388 +               break;
13389 +       case MIPV6_OPT_NONCE_INDICES:
13390 +               DEBUG(DBG_INFO, "Added nonce indices pointer");
13391 +               ops->nonce_indices = (struct mipv6_mo_nonce_indices *)mo;
13392 +               ops->nonce_indices->home_nonce_i = *(__u16 *)data;
13393 +               ops->nonce_indices->careof_nonce_i = *((__u16 *)data + 1);
13394 +               break;
13395 +       case MIPV6_OPT_AUTH_DATA:
13396 +               DEBUG(DBG_INFO, "Added opt auth_data pointer");
13397 +               ops->auth_data = (struct mipv6_mo_bauth_data *)mo;
13398 +               break;
13399 +       case MIPV6_OPT_BIND_REFRESH_ADVICE:
13400 +               ops->br_advice = (struct mipv6_mo_br_advice *)mo;
13401 +               ops->br_advice->refresh_interval = htons(*(u16 *)data);
13402 +               break;
13403 +       default:
13404 +               DEBUG(DBG_ERROR, "Unknow option type");
13405 +               break;
13406 +       }
13407 +
13408 +       if (ops->freelen == 0)
13409 +               ops->next_free = NULL;
13410 +       else
13411 +               ops->next_free += (len + 2);
13412 +
13413 +       return 0;
13414 +}
13415 +
13416 +/*
13417 + * Calculates required padding with xn + y requirement with offset
13418 + */
13419 +static inline int optpad(int xn, int y, int offset)
13420 +{
13421 +       return ((y - offset) & (xn - 1));
13422 +}
13423 +
13424 +static int option_pad(int type, int offset)
13425 +{
13426 +       if (type == MIPV6_OPT_ALTERNATE_COA)
13427 +               return optpad(8, 6, offset); /* 8n + 6 */
13428 +       if (type == MIPV6_OPT_BIND_REFRESH_ADVICE ||
13429 +           type == MIPV6_OPT_NONCE_INDICES)
13430 +               return optpad(2, 0, offset); /* 2n */
13431 +       return 0;
13432 +}
13433 +
13434 +/*
13435 + * Add Pad1 or PadN option to data
13436 + */
13437 +int mipv6_add_pad(u8 *data, int n)
13438 +{
13439 +       struct mipv6_mo_padn *padn;
13440 +
13441 +       if (n <= 0) return 0;
13442 +       if (n == 1) {
13443 +               *data = MIPV6_OPT_PAD1;
13444 +               return 1;
13445 +       }
13446 +       padn = (struct mipv6_mo_padn *)data;
13447 +       padn->type = MIPV6_OPT_PADN;
13448 +       padn->length = n - 2;
13449 +       memset(padn->data, 0, n - 2);
13450 +       return n;
13451 +}
13452 +
13453 +/*
13454 + * Write options to mobility header buffer
13455 + */
13456 +static int prepare_mh_opts(u8 *optdata, int off, struct mipv6_mh_opt *ops)
13457 +{
13458 +       u8 *nextopt = optdata;
13459 +       int offset = off, pad = 0;
13460 +
13461 +       if (ops == NULL) {
13462 +               nextopt = NULL;
13463 +               return -1;
13464 +       }
13465 +
13466 +       if (ops->alt_coa) {
13467 +               pad = option_pad(MIPV6_OPT_ALTERNATE_COA, offset);
13468 +               nextopt += mipv6_add_pad(nextopt, pad);
13469 +               memcpy(nextopt, ops->alt_coa, sizeof(struct mipv6_mo_alt_coa));
13470 +               nextopt += sizeof(struct mipv6_mo_alt_coa);
13471 +               offset += pad + sizeof(struct mipv6_mo_alt_coa);
13472 +       }
13473 +
13474 +       if (ops->br_advice) {
13475 +               pad = option_pad(MIPV6_OPT_BIND_REFRESH_ADVICE, offset);
13476 +               nextopt += mipv6_add_pad(nextopt, pad);
13477 +               memcpy(nextopt, ops->br_advice, sizeof(struct mipv6_mo_br_advice));
13478 +               nextopt += sizeof(struct mipv6_mo_br_advice);
13479 +               offset += pad + sizeof(struct mipv6_mo_br_advice);
13480 +       }
13481 +
13482 +       if (ops->nonce_indices) {
13483 +               pad = option_pad(MIPV6_OPT_NONCE_INDICES, offset);
13484 +               nextopt += mipv6_add_pad(nextopt, pad);
13485 +               memcpy(nextopt, ops->nonce_indices, sizeof(struct mipv6_mo_nonce_indices));
13486 +               nextopt += sizeof(struct mipv6_mo_nonce_indices);
13487 +               offset += pad + sizeof(struct mipv6_mo_nonce_indices);
13488 +       }
13489 +
13490 +       if (ops->auth_data) {
13491 +               /* This option should always be the last.  Header
13492 +                * length must be a multiple of 8 octects, so we pad
13493 +                * if necessary. */
13494 +               pad = optpad(8, 0, offset + ops->auth_data->length + 2);
13495 +               nextopt += mipv6_add_pad(nextopt, pad);
13496 +               memcpy(nextopt, ops->auth_data, ops->auth_data->length + 2);
13497 +               nextopt += ops->auth_data->length + 2;
13498 +       }
13499 +       nextopt = NULL;
13500 +
13501 +       return 0;
13502 +}
13503 +
13504 +static int calculate_mh_opts(struct mipv6_mh_opt *ops, int mh_len)
13505 +{
13506 +       int offset = mh_len;
13507 +
13508 +       if (ops == NULL)
13509 +               return 0;
13510 +
13511 +       if (ops->alt_coa)
13512 +               offset += sizeof(struct mipv6_mo_alt_coa)
13513 +                       + option_pad(MIPV6_OPT_ALTERNATE_COA, offset);
13514 +
13515 +       if (ops->br_advice)
13516 +               offset += sizeof(struct mipv6_mo_br_advice)
13517 +                       + option_pad(MIPV6_OPT_BIND_REFRESH_ADVICE, offset);
13518 +
13519 +       if (ops->nonce_indices)
13520 +               offset += sizeof(struct mipv6_mo_nonce_indices)
13521 +                       + option_pad(MIPV6_OPT_NONCE_INDICES, offset);
13522 +
13523 +       if (ops->auth_data) /* no alignment */
13524 +               offset += ops->auth_data->length + 2;
13525 +
13526 +       return offset - mh_len;
13527 +}
13528 +
13529 +/*
13530 + *
13531 + * Mobility Header Message send functions
13532 + *
13533 + */
13534 +
13535 +/**
13536 + * send_mh - builds and sends a MH msg
13537 + *
13538 + * @daddr: destination address for packet
13539 + * @saddr: source address for packet
13540 + * @msg_type: type of MH
13541 + * @msg_len: message length
13542 + * @msg: MH type specific data
13543 + * @hao_addr: home address for home address option
13544 + * @rth_addr: routing header address
13545 + * @ops: mobility options
13546 + * @parm: auth data
13547 + *
13548 + * Builds MH, appends the type specific msg data to the header and
13549 + * sends the packet with a home address option, if a home address was
13550 + * given. Returns 0, if everything succeeded and a negative error code
13551 + * otherwise.
13552 + **/
13553 +int send_mh(struct in6_addr *daddr, 
13554 +           struct in6_addr *saddr, 
13555 +           u8 msg_type, u8 msg_len, u8 *msg,
13556 +           struct in6_addr *hao_addr,
13557 +           struct in6_addr *rth_addr,
13558 +           struct mipv6_mh_opt *ops,
13559 +           struct mipv6_auth_parm *parm)
13560 +{
13561 +       struct flowi fl;
13562 +       struct mipv6_mh *mh; 
13563 +       struct sock *sk = mipv6_mh_socket->sk;
13564 +       struct ipv6_txoptions *txopt = NULL;
13565 +       int tot_len = sizeof(struct mipv6_mh) + msg_len;
13566 +       int padded_len = 0, txopt_len = 0;
13567 +
13568 +       DEBUG_FUNC();
13569 +       /* Add length of options */
13570 +       tot_len += calculate_mh_opts(ops, tot_len);
13571 +       /* Needs to be a multiple of 8 octets */
13572 +       padded_len = tot_len + optpad(8, 0, tot_len);
13573 +
13574 +       mh = sock_kmalloc(sk, padded_len, GFP_ATOMIC);
13575 +       if (!mh) {
13576 +               DEBUG(DBG_ERROR, "memory allocation failed");
13577 +               return -ENOMEM;
13578 +       }
13579 +
13580 +       memset(&fl, 0, sizeof(fl)); 
13581 +       fl.proto = IPPROTO_MOBILITY;
13582 +       fl.fl6_dst = daddr;
13583 +       fl.fl6_src = saddr;
13584 +       fl.fl6_flowlabel = 0;
13585 +       fl.oif = sk->bound_dev_if;
13586 +
13587 +       if (hao_addr || rth_addr) {
13588 +               __u8 *opt_ptr;
13589 +
13590 +               if (hao_addr)
13591 +                       txopt_len += sizeof(struct mipv6_dstopt_homeaddr) + 6;
13592 +               if (rth_addr)
13593 +                       txopt_len += sizeof(struct rt2_hdr);
13594 +
13595 +               txopt_len += sizeof(*txopt);
13596 +               txopt = sock_kmalloc(sk, txopt_len, GFP_ATOMIC);
13597 +               if (txopt == NULL) {
13598 +                       DEBUG(DBG_ERROR, "No socket space left");
13599 +                       sock_kfree_s(sk, mh, padded_len);
13600 +                       return -ENOMEM;
13601 +               }
13602 +               memset(txopt, 0, txopt_len);
13603 +               txopt->tot_len = txopt_len;
13604 +               opt_ptr = (__u8 *) (txopt + 1);
13605 +               if (hao_addr) {
13606 +                       int holen = sizeof(struct mipv6_dstopt_homeaddr) + 6;
13607 +                       txopt->dst1opt = (struct ipv6_opt_hdr *) opt_ptr;
13608 +                       txopt->opt_flen += holen;
13609 +                       opt_ptr += holen;
13610 +                       mipv6_append_dst1opts(txopt->dst1opt, saddr, 
13611 +                                             NULL, holen);
13612 +                       txopt->mipv6_flags = MIPV6_SND_HAO | MIPV6_SND_BU;
13613 +               }
13614 +               if (rth_addr) {
13615 +                       int rtlen = sizeof(struct rt2_hdr);
13616 +                       txopt->srcrt2 = (struct ipv6_rt_hdr *) opt_ptr;
13617 +                       txopt->opt_nflen += rtlen;
13618 +                       opt_ptr += rtlen;
13619 +                       mipv6_append_rt2hdr(txopt->srcrt2, rth_addr);
13620 +               }
13621 +       }
13622 +
13623 +       /* Fill in the fields of MH */
13624 +       mh->payload = NEXTHDR_NONE;
13625 +       mh->length = (padded_len >> 3) - 1;     /* Units of 8 octets - 1 */
13626 +       mh->type = msg_type;
13627 +       mh->reserved = 0;
13628 +       mh->checksum = 0;
13629 +
13630 +       memcpy(mh->data, msg, msg_len);
13631 +       prepare_mh_opts(mh->data + msg_len, msg_len + sizeof(*mh), ops);
13632 +       /* If BAD is present, this is already done. */
13633 +       mipv6_add_pad((u8 *)mh + tot_len, padded_len - tot_len);
13634 +       
13635 +       if (parm && parm->k_bu && ops && ops->auth_data) {
13636 +               /* Calculate the position of the authorization data before adding checksum*/
13637 +               mipv6_auth_build(parm->cn_addr, parm->coa, (__u8 *)mh, 
13638 +                                (__u8 *)mh + padded_len - MIPV6_RR_MAC_LENGTH, parm->k_bu);
13639 +       }
13640 +       /* Calculate the MH checksum */
13641 +       mh->checksum = csum_ipv6_magic(fl.fl6_src, fl.fl6_dst, 
13642 +                                      padded_len, IPPROTO_MOBILITY,
13643 +                                      csum_partial((char *)mh, padded_len, 0));
13644 +       ip6_build_xmit(sk, dstopts_getfrag, mh, &fl, padded_len, txopt, 255,
13645 +                      MSG_DONTWAIT);
13646 +       /* dst cache must be cleared so RR messages can be routed through 
13647 +          different interfaces */
13648 +       sk_dst_reset(sk);
13649 +
13650 +       if (txopt_len)
13651 +               sock_kfree_s(sk, txopt, txopt_len);
13652 +       sock_kfree_s(sk, mh, padded_len);
13653 +       return 0;
13654 +}
13655 +
13656 +/**
13657 + * mipv6_send_brr - send a Binding Refresh Request 
13658 + * @saddr: source address for BRR
13659 + * @daddr: destination address for BRR
13660 + * @ops: mobility options
13661 + *
13662 + * Sends a binding request.  On a mobile node, use the mobile node's
13663 + * home address for @saddr.  Returns 0 on success, negative on
13664 + * failure.
13665 + **/
13666 +int mipv6_send_brr(struct in6_addr *saddr, struct in6_addr *daddr,
13667 +                  struct mipv6_mh_opt *ops)
13668 +{
13669 +       struct mipv6_mh_brr br;
13670 +
13671 +       memset(&br, 0, sizeof(br));
13672 +       /* We don't need to explicitly add a RH to brr, since it will be 
13673 +        * included automatically, if a BCE exists 
13674 +        */
13675 +       MIPV6_INC_STATS(n_brr_sent);
13676 +       return send_mh(daddr, saddr, MIPV6_MH_BRR, sizeof(br), (u8 *)&br,
13677 +                      NULL, NULL, ops, NULL);
13678 +}
13679 +
13680 +/**
13681 + * mipv6_send_ba - send a Binding Acknowledgement 
13682 + * @saddr: source address for BA
13683 + * @daddr: destination address for BA 
13684 + * @reply_coa: destination care-of address of MN
13685 + * @auth_coa: care-of address of MN used for authentication
13686 + * @status: status field value
13687 + * @sequence: sequence number from BU
13688 + * @lifetime: granted lifetime for binding in seconds
13689 + * @ops: mobility options
13690 + *
13691 + * Send a binding acknowledgement.  On a mobile node, use the mobile
13692 + * node's home address for saddr.  Returns 0 on success, non-zero on
13693 + * failure.
13694 + **/
13695 +int mipv6_send_ba(struct in6_addr *saddr, struct in6_addr *daddr, 
13696 +                 struct in6_addr *auth_coa, struct in6_addr *rep_coa,
13697 +                 u8 status, u16 sequence, u32 lifetime, u8 *k_bu)
13698 +{
13699 +       struct mipv6_mh_ba ba;
13700 +       struct mipv6_auth_parm parm;
13701 +       struct mipv6_mh_opt *ops = NULL; 
13702 +       int ops_len = 0, ret = 0;
13703 +       struct mipv6_bce bc_entry;
13704 +       int coming_home = 0;
13705 +       int bypass_tnl = 0;
13706 +
13707 +       memset(&ba, 0, sizeof(ba));
13708 +       
13709 +       ba.status = status;
13710 +       ba.sequence = htons(sequence);
13711 +       ba.lifetime = htons(lifetime >> 2);
13712 +       
13713 +       DEBUG(DBG_INFO, "sending a status %d BA %s authenticator to MN \n"
13714 +             "%x:%x:%x:%x:%x:%x:%x:%x  at care of address \n" 
13715 +             "%x:%x:%x:%x:%x:%x:%x:%x : with lifetime %d and \n" 
13716 +             " sequence number %d",
13717 +             status, k_bu ? "with" : "without", 
13718 +             NIPV6ADDR(daddr), NIPV6ADDR(auth_coa), lifetime, sequence);
13719 +
13720 +       memset(&parm, 0, sizeof(parm));
13721 +       parm.coa = auth_coa;
13722 +       parm.cn_addr = saddr;
13723 +
13724 +       if (k_bu) {
13725 +               ops_len += sizeof(struct mipv6_mo_bauth_data) + 
13726 +                       MIPV6_RR_MAC_LENGTH;
13727 +               parm.k_bu = k_bu;
13728 +       }
13729 +
13730 +       if (mip6node_cnf.binding_refresh_advice) {
13731 +               ops_len += sizeof(struct mipv6_mo_br_advice);
13732 +       }
13733 +       if (ops_len) {
13734 +               ops = alloc_mh_opts(ops_len);
13735 +               if (ops == NULL) {
13736 +                       DEBUG(DBG_WARNING, "Out of memory");
13737 +                       return -ENOMEM;
13738 +               }
13739 +               if (mip6node_cnf.binding_refresh_advice > 0) {
13740 +                       if (append_mh_opt(ops, MIPV6_OPT_BIND_REFRESH_ADVICE, 2,
13741 +                                         &mip6node_cnf.binding_refresh_advice) < 0) {
13742 +                               DEBUG(DBG_WARNING, "Adding BRA failed");
13743 +                               if (ops)
13744 +                                       kfree(ops);
13745 +                               return -ENOMEM;
13746 +                       }
13747 +               }
13748 +               if (k_bu) {
13749 +                       if (append_mh_opt(ops, MIPV6_OPT_AUTH_DATA,
13750 +                                         MIPV6_RR_MAC_LENGTH, NULL) < 0) {
13751 +                               DEBUG(DBG_WARNING, "Adding BAD failed");
13752 +                               if (ops)
13753 +                                       kfree(ops);
13754 +                               return -ENOMEM;
13755 +                       }
13756 +               }
13757 +       }
13758 +       coming_home = !ipv6_addr_cmp(rep_coa, daddr);
13759 +
13760 +       bypass_tnl = (coming_home &&
13761 +                     !mipv6_bcache_get(daddr, saddr, &bc_entry) &&
13762 +                     bc_entry.flags&MIPV6_BU_F_HOME && 
13763 +                     status >= 128);
13764 +
13765 +       if (bypass_tnl && mip6_fn.bce_tnl_rt_del)
13766 +               mip6_fn.bce_tnl_rt_del(&bc_entry.coa,
13767 +                                      &bc_entry.our_addr,
13768 +                                      &bc_entry.home_addr);
13769 +
13770 +       if (coming_home)
13771 +               ret = send_mh(daddr, saddr, MIPV6_MH_BA, sizeof(ba), (u8 *)&ba,
13772 +                             NULL, NULL, ops, &parm);
13773 +       else
13774 +               ret = send_mh(daddr, saddr, MIPV6_MH_BA, sizeof(ba), (u8 *)&ba,
13775 +                             NULL, rep_coa, ops, &parm);
13776 +
13777 +       if (bypass_tnl && mip6_fn.bce_tnl_rt_add)
13778 +               mip6_fn.bce_tnl_rt_add(&bc_entry.coa,
13779 +                                      &bc_entry.our_addr,
13780 +                                      &bc_entry.home_addr);
13781 +       
13782 +       if (ret == 0) {
13783 +               if (status < 128) {
13784 +                       MIPV6_INC_STATS(n_ba_sent);
13785 +               } else {
13786 +                       MIPV6_INC_STATS(n_ban_sent);
13787 +               }
13788 +       }
13789 +
13790 +       if (ops)
13791 +               kfree(ops);
13792 +
13793 +       return 0;
13794 +}
13795 +
13796 +/**
13797 + * mipv6_send_be - send a Binding Error message
13798 + * @saddr: source address for BE
13799 + * @daddr: destination address for BE
13800 + * @home: Home Address in offending packet (if any)
13801 + *
13802 + * Sends a binding error.  On a mobile node, use the mobile node's
13803 + * home address for @saddr.  Returns 0 on success, negative on
13804 + * failure.
13805 + **/
13806 +int mipv6_send_be(struct in6_addr *saddr, struct in6_addr *daddr, 
13807 +                 struct in6_addr *home, __u8 status)
13808 +{
13809 +       struct mipv6_mh_be be;
13810 +       int ret = 0;
13811 +       struct mipv6_bce bc_entry;
13812 +       int bypass_tnl = 0;
13813 +
13814 +       if (ipv6_addr_is_multicast(daddr))
13815 +               return -EINVAL;
13816 +
13817 +       memset(&be, 0, sizeof(be));
13818 +       be.status = status;
13819 +       if (home)
13820 +               ipv6_addr_copy(&be.home_addr, home);
13821 +
13822 +       if (mipv6_bcache_get(daddr, saddr, &bc_entry) == 0 &&
13823 +           bc_entry.flags&MIPV6_BU_F_HOME)
13824 +               bypass_tnl = 1;
13825 +
13826 +       if (bypass_tnl && mip6_fn.bce_tnl_rt_del)
13827 +               mip6_fn.bce_tnl_rt_del(&bc_entry.coa,
13828 +                                      &bc_entry.our_addr,
13829 +                                      &bc_entry.home_addr);
13830 +
13831 +       ret = send_mh(daddr, saddr, MIPV6_MH_BE, sizeof(be), (u8 *)&be,
13832 +                     NULL, NULL, NULL, NULL);
13833 +       
13834 +       if (bypass_tnl && mip6_fn.bce_tnl_rt_add)
13835 +               mip6_fn.bce_tnl_rt_add(&bc_entry.coa,
13836 +                                      &bc_entry.our_addr,
13837 +                                      &bc_entry.home_addr);
13838 +
13839 +       if (ret == 0)
13840 +               MIPV6_INC_STATS(n_be_sent);
13841 +
13842 +       return ret;
13843 +}
13844 +
13845 +/**
13846 + * mipv6_send_addr_test - send a HoT or CoT message
13847 + * @saddr: source address
13848 + * @daddr: destination address
13849 + * @msg_type: HoT or CoT message
13850 + * @init: HoTI or CoTI message
13851 + *
13852 + * Send a reply to HoTI or CoTI message. 
13853 + **/
13854 +static int mipv6_send_addr_test(struct in6_addr *saddr,
13855 +                               struct in6_addr *daddr,
13856 +                               int msg_type,
13857 +                               struct mipv6_mh_addr_ti *init)
13858 +{
13859 +       u_int8_t                        *kgen_token = NULL;
13860 +       struct mipv6_mh_addr_test       addr_test;      
13861 +       struct mipv6_rr_nonce           *nonce;
13862 +       struct mipv6_mh_opt *ops = NULL;
13863 +       int ret = 0;
13864 +
13865 +       DEBUG_FUNC();
13866 +
13867 +       if ((nonce = mipv6_rr_get_new_nonce())== NULL) {
13868 +               DEBUG(DBG_WARNING, "Nonce creation failed");
13869 +               return 0;
13870 +       } 
13871 +       if (mipv6_rr_cookie_create(daddr, &kgen_token, nonce->index)) {
13872 +               DEBUG(DBG_WARNING, "No cookie");
13873 +               return 0;
13874 +       }
13875 +
13876 +       addr_test.nonce_index = nonce->index;
13877 +       memcpy(addr_test.init_cookie, init->init_cookie,
13878 +                       MIPV6_RR_COOKIE_LENGTH);
13879 +       memcpy(addr_test.kgen_token, kgen_token,
13880 +                       MIPV6_RR_COOKIE_LENGTH);
13881 +
13882 +       /* No options defined */
13883 +       ret = send_mh(daddr, saddr, msg_type, sizeof(addr_test),
13884 +                     (u8 *)&addr_test, NULL, NULL, ops, NULL);
13885 +
13886 +       if (ret == 0) {
13887 +               if (msg_type == MIPV6_MH_HOT) {
13888 +                       MIPV6_INC_STATS(n_hot_sent);
13889 +               } else {
13890 +                       MIPV6_INC_STATS(n_cot_sent);
13891 +               }
13892 +       }
13893 +
13894 +       return 0;
13895 +}
13896 +
13897 +static void bc_cache_add(int ifindex, struct in6_addr *daddr,
13898 +                        struct in6_addr *haddr, struct in6_addr *coa,
13899 +                        struct in6_addr *rep_coa, __u32 lifetime,
13900 +                        __u16 sequence, __u8 flags, __u8 *k_bu)
13901 +{
13902 +       __u8 ba_status = SUCCESS;
13903 +
13904 +       if (lifetime >  MAX_RR_BINDING_LIFE)
13905 +               lifetime = MAX_RR_BINDING_LIFE;
13906 +
13907 +       if (mipv6_bcache_add(ifindex, daddr, haddr, coa, lifetime,
13908 +                            sequence, flags, CACHE_ENTRY) != 0) {
13909 +               DEBUG(DBG_ERROR, "binding failed.");
13910 +               ba_status = INSUFFICIENT_RESOURCES;
13911 +       } 
13912 +
13913 +       if (flags & MIPV6_BU_F_ACK) {
13914 +               DEBUG(DBG_INFO, "sending ack (code=%d)", ba_status);
13915 +               mipv6_send_ba(daddr, haddr, coa, rep_coa, ba_status, sequence,
13916 +                             lifetime, k_bu);
13917 +       }
13918 +}
13919 +
13920 +static void bc_cn_home_add(int ifindex, struct in6_addr *daddr, 
13921 +                          struct in6_addr *haddr, struct in6_addr *coa,
13922 +                          struct in6_addr *rep_coa, __u32 lifetime,
13923 +                          __u16 sequence, __u8 flags, __u8 *k_bu)
13924 +{
13925 +       mipv6_send_ba(daddr, haddr, coa, rep_coa,
13926 +                     HOME_REGISTRATION_NOT_SUPPORTED,
13927 +                     sequence, lifetime, k_bu);
13928 +}
13929 +
13930 +static void bc_cache_delete(struct in6_addr *daddr, struct in6_addr *haddr, 
13931 +                           struct in6_addr *coa, struct in6_addr *rep_coa,
13932 +                           __u16 sequence, __u8 flags,
13933 +                           __u8 *k_bu)
13934 +{
13935 +       __u8 status = SUCCESS;
13936 +
13937 +       /* Cached Care-of Address Deregistration */
13938 +       if (mipv6_bcache_exists(haddr, daddr) == CACHE_ENTRY) {
13939 +               mipv6_bcache_delete(haddr, daddr, CACHE_ENTRY);
13940 +       } else {
13941 +               DEBUG(DBG_INFO, "entry is not in cache");
13942 +               status = REASON_UNSPECIFIED;
13943 +       }
13944 +       if (flags & MIPV6_BU_F_ACK) {
13945 +               mipv6_send_ba(daddr, haddr, coa, rep_coa, status, sequence, 
13946 +                             0, k_bu);
13947 +       }
13948 +}
13949 +
13950 +static void bc_cn_home_delete(struct in6_addr *daddr, struct in6_addr *haddr, 
13951 +                             struct in6_addr *coa, struct in6_addr *rep_coa,
13952 +                             __u16 sequence, __u8 flags,
13953 +                             __u8 *k_bu)
13954 +{
13955 +}
13956 +
13957 +/**
13958 + * parse_mo_tlv - Parse TLV-encoded Mobility Options
13959 + * @mos: pointer to Mobility Options
13960 + * @len: total length of options
13961 + * @opts: structure to store option pointers
13962 + *
13963 + * Parses Mobility Options passed in @mos.  Stores pointers in @opts
13964 + * to all valid mobility options found in @mos.  Unknown options and
13965 + * padding (%MIPV6_OPT_PAD1 and %MIPV6_OPT_PADN) is ignored and
13966 + * skipped.
13967 + **/
13968 +int parse_mo_tlv(void *mos, int len, struct mobopt *opts)
13969 +{
13970 +       struct mipv6_mo *curr = (struct mipv6_mo *)mos;
13971 +       int left = len;
13972 +
13973 +       while (left > 0) {
13974 +               int optlen = 0;
13975 +               if (curr->type == MIPV6_OPT_PAD1)
13976 +                       optlen = 1;
13977 +               else
13978 +                       optlen = 2 + curr->length;
13979 +
13980 +               if (optlen > left)
13981 +                       goto bad;
13982 +
13983 +               switch (curr->type) {
13984 +               case MIPV6_OPT_PAD1:
13985 +                       DEBUG(DBG_DATADUMP, "MIPV6_OPT_PAD1 at %x", curr);
13986 +                       break;
13987 +               case MIPV6_OPT_PADN:
13988 +                       DEBUG(DBG_DATADUMP, "MIPV6_OPT_PADN at %x", curr);
13989 +                       break;
13990 +               case MIPV6_OPT_ALTERNATE_COA:
13991 +                       DEBUG(DBG_DATADUMP, "MIPV6_OPT_ACOA at %x", curr);
13992 +                       opts->alt_coa = (struct mipv6_mo_alt_coa *)curr;
13993 +                       break;
13994 +               case MIPV6_OPT_NONCE_INDICES:
13995 +                       DEBUG(DBG_DATADUMP, "MIPV6_OPT_NONCE_INDICES at %x", curr);
13996 +                       opts->nonce_indices = 
13997 +                               (struct mipv6_mo_nonce_indices *)curr;
13998 +                       break;
13999 +               case MIPV6_OPT_AUTH_DATA:
14000 +                       DEBUG(DBG_DATADUMP, "MIPV6_OPT_AUTH_DATA at %x", curr);
14001 +                       opts->auth_data = (struct mipv6_mo_bauth_data *)curr;
14002 +                       break;
14003 +               case MIPV6_OPT_BIND_REFRESH_ADVICE:
14004 +                       DEBUG(DBG_DATADUMP, "MIPV6_OPT_BIND_REFRESH_ADVICE at %x", curr);
14005 +                       opts->br_advice = (struct mipv6_mo_br_advice *)curr;
14006 +                       break;
14007 +               default:
14008 +                       DEBUG(DBG_INFO, "MO Unknown option type %d at %x, ignoring.",
14009 +                              curr->type, curr);
14010 +                       /* unknown mobility option, ignore and skip */
14011 +               }
14012 +
14013 +               (u8 *)curr += optlen;
14014 +               left -= optlen;
14015 +       }
14016 +
14017 +       if (left == 0)
14018 +               return 0;
14019 + bad:
14020 +       return -1;
14021 +}
14022 +
14023 +/*
14024 + *
14025 + * Mobility Header Message handlers
14026 + *
14027 + */
14028 +
14029 +static int mipv6_handle_mh_testinit(struct sk_buff *skb,
14030 +                                   struct in6_addr *cn,
14031 +                                   struct in6_addr *lcoa,
14032 +                                   struct in6_addr *saddr,
14033 +                                   struct in6_addr *fcoa,
14034 +                                   struct mipv6_mh *mh)
14035 +{
14036 +       struct mipv6_mh_addr_ti *ti = (struct mipv6_mh_addr_ti *)mh->data;
14037 +       int msg_len = (mh->length+1) << 3;
14038 +       int opt_len;
14039 +       DEBUG_FUNC();
14040 +
14041 +       if (msg_len > skb->len)
14042 +               return -1;
14043 +
14044 +       opt_len = msg_len - sizeof(*mh) - sizeof(*ti);
14045 +
14046 +       if (opt_len < 0) {
14047 +               __u32 pos = (__u32)&mh->length - (__u32)skb->nh.raw;
14048 +               icmpv6_send(skb, ICMPV6_PARAMPROB,
14049 +                           ICMPV6_HDR_FIELD, pos, skb->dev);
14050 +
14051 +               DEBUG(DBG_INFO, "Mobility Header length less than H/C TestInit");
14052 +               return -1;
14053 +       }
14054 +       if (!mip6node_cnf.accept_ret_rout) {
14055 +               DEBUG(DBG_INFO, "Return routability administratively disabled");
14056 +               return -1;
14057 +       }
14058 +       if (lcoa || fcoa) {
14059 +               DEBUG(DBG_INFO, "H/C TestInit has HAO or RTH2, dropped.");
14060 +               return -1;
14061 +       }
14062 +
14063 +       if (mh->type == MIPV6_MH_HOTI) {
14064 +               MIPV6_INC_STATS(n_hoti_rcvd);
14065 +               return mipv6_send_addr_test(cn, saddr, MIPV6_MH_HOT, ti);
14066 +       } else if (mh->type == MIPV6_MH_COTI) {
14067 +               MIPV6_INC_STATS(n_coti_rcvd);
14068 +               return mipv6_send_addr_test(cn, saddr, MIPV6_MH_COT, ti);
14069 +       } else 
14070 +               return -1; /* Impossible to get here */
14071 +}
14072 +
14073 +/**
14074 + * mipv6_handle_mh_bu - Binding Update handler
14075 + * @src: care-of address of sender
14076 + * @dst: our address
14077 + * @haddr: home address of sender
14078 + * @mh: pointer to the beginning of the Mobility Header
14079 + *
14080 + * Handles Binding Update. Packet and offset to option are passed.
14081 + * Returns 0 on success, otherwise negative.
14082 + **/
14083 +static int mipv6_handle_mh_bu(struct sk_buff *skb,
14084 +                             struct in6_addr *dst,
14085 +                             struct in6_addr *unused,
14086 +                             struct in6_addr *haddr, 
14087 +                             struct in6_addr *coaddr,
14088 +                             struct mipv6_mh *mh)
14089 +{
14090 +       struct mipv6_mh_bu *bu = (struct mipv6_mh_bu *)mh->data;
14091 +       int msg_len = (mh->length+1) << 3;
14092 +       int opt_len;
14093 +       int auth = 0;
14094 +       int dereg; /* Is this deregistration? */ 
14095 +       int addr_type;
14096 +
14097 +       struct mipv6_bce bc_entry;
14098 +       struct in6_addr *coa, *reply_coa;
14099 +       __u8 *key_bu = NULL; /* RR BU authentication key */
14100 +       __u8 flags = bu->flags;
14101 +       __u16 sequence;
14102 +       __u32 lifetime;
14103 +       __u16 nonce_ind = (__u16) -1; 
14104 +
14105 +       if (msg_len > skb->len)
14106 +               return -1;
14107 +
14108 +       opt_len = msg_len - sizeof(*mh) - sizeof(*bu);
14109 +
14110 +       if (opt_len < 0) {
14111 +               __u32 pos = (__u32)&mh->length - (__u32)skb->nh.raw;
14112 +               icmpv6_send(skb, ICMPV6_PARAMPROB,
14113 +                           ICMPV6_HDR_FIELD, pos, skb->dev);
14114 +
14115 +               DEBUG(DBG_INFO, "Mobility Header length less than BU");
14116 +               MIPV6_INC_STATS(n_bu_drop.invalid);
14117 +               return -1;
14118 +       }
14119 +
14120 +       addr_type = ipv6_addr_type(haddr);
14121 +       if (addr_type&IPV6_ADDR_LINKLOCAL || !(addr_type&IPV6_ADDR_UNICAST))
14122 +               return -EINVAL;
14123 +
14124 +       /* If HAO not present, CoA == HAddr */
14125 +       if (coaddr == NULL) 
14126 +               coa = haddr;
14127 +       else {
14128 +               coa = coaddr;
14129 +               addr_type = ipv6_addr_type(coa);
14130 +               if (addr_type&IPV6_ADDR_LINKLOCAL ||
14131 +                   !(addr_type&IPV6_ADDR_UNICAST))
14132 +                       return -EINVAL;
14133 +       }
14134 +       reply_coa = coa;
14135 +
14136 +       sequence = ntohs(bu->sequence);
14137 +       if (bu->lifetime == 0xffff)
14138 +               lifetime = 0xffffffff;
14139 +       else
14140 +               lifetime = ntohs(bu->lifetime) << 2;
14141 +
14142 +       dereg = (ipv6_addr_cmp(haddr, coa) == 0 || lifetime == 0);
14143 +
14144 +       if (opt_len > 0) {
14145 +               struct mobopt opts;
14146 +               memset(&opts, 0, sizeof(opts));
14147 +               if (parse_mo_tlv(bu + 1, opt_len, &opts) < 0) {
14148 +                       MIPV6_INC_STATS(n_bu_drop.invalid);
14149 +                       return -1;
14150 +               }
14151 +               /*
14152 +                * MIPV6_OPT_AUTH_DATA, MIPV6_OPT_NONCE_INDICES, 
14153 +                * MIPV6_OPT_ALT_COA
14154 +                */
14155 +               if (opts.alt_coa) {
14156 +                       coa = &opts.alt_coa->addr;
14157 +                       dereg = (ipv6_addr_cmp(haddr, coa) == 0 || lifetime == 0);
14158 +               }
14159 +               addr_type = ipv6_addr_type(coa);
14160 +               if (addr_type&IPV6_ADDR_LINKLOCAL || 
14161 +                   !(addr_type&IPV6_ADDR_UNICAST))
14162 +                       return -EINVAL;
14163 +
14164 +               if (flags & MIPV6_BU_F_HOME) {
14165 +                       if (opts.nonce_indices)
14166 +                               return -1;
14167 +               } else {
14168 +                       u8 ba_status = 0;
14169 +                       u8 *h_ckie  = NULL, *c_ckie = NULL; /* Home and care-of cookies */
14170 +
14171 +                       /* BUs to CN MUST include authorization data and nonce indices options */
14172 +                       if (!opts.auth_data || !opts.nonce_indices) {
14173 +                               DEBUG(DBG_WARNING,
14174 +                                     "Route optimization BU without authorization material, aborting processing");
14175 +                               return MH_AUTH_FAILED;
14176 +                       }
14177 +                       if (mipv6_rr_cookie_create(
14178 +                                   haddr, &h_ckie, opts.nonce_indices->home_nonce_i) < 0) {
14179 +                               DEBUG(DBG_WARNING,
14180 +                                     "mipv6_rr_cookie_create failed for home cookie");
14181 +                               ba_status = EXPIRED_HOME_NONCE_INDEX;
14182 +                       }
14183 +                       nonce_ind = opts.nonce_indices->home_nonce_i;
14184 +                       /* Don't create the care-of cookie, if MN deregisters */
14185 +                       if (!dereg && mipv6_rr_cookie_create(
14186 +                                   coa, &c_ckie,
14187 +                                   opts.nonce_indices->careof_nonce_i) < 0) {
14188 +                               DEBUG(DBG_WARNING,
14189 +                                     "mipv6_rr_cookie_create failed for coa cookie");
14190 +                               if (ba_status == 0)
14191 +                                       ba_status = EXPIRED_CAREOF_NONCE_INDEX;
14192 +                               else
14193 +                                       ba_status = EXPIRED_NONCES;
14194 +                       }
14195 +                       if (ba_status == 0) {
14196 +                               if (dereg)
14197 +                                       key_bu = mipv6_rr_key_calc(h_ckie, NULL);
14198 +                               else
14199 +                                       key_bu = mipv6_rr_key_calc(h_ckie, c_ckie);            
14200 +                               mh->checksum = 0;/* TODO: Don't mangle the packet */
14201 +                               if (key_bu && mipv6_auth_check(
14202 +                                       dst, coa, (__u8 *)mh,  msg_len + sizeof(*mh), opts.auth_data, key_bu) == 0) {
14203 +                                       DEBUG(DBG_INFO, "mipv6_auth_check OK for BU");
14204 +                                       auth = 1;
14205 +                               } else {
14206 +                                       DEBUG(DBG_WARNING, 
14207 +                                             "BU Authentication failed");
14208 +                               }
14209 +                       }
14210 +                       if (h_ckie)
14211 +                               kfree(h_ckie);
14212 +                       if (c_ckie)
14213 +                               kfree(c_ckie);
14214 +                       if (ba_status != 0) {
14215 +                               MIPV6_INC_STATS(n_bu_drop.auth);
14216 +                               mipv6_send_ba(dst, haddr, coa,
14217 +                                             reply_coa, ba_status,
14218 +                                             sequence, 0, NULL);
14219 +                               goto out;
14220 +                       }
14221 +               }
14222 +
14223 +       }
14224 +       /* Require authorization option for RO, home reg is protected by IPsec */
14225 +       if (!(flags & MIPV6_BU_F_HOME) && !auth) {
14226 +               MIPV6_INC_STATS(n_bu_drop.auth);
14227 +               if (key_bu)
14228 +                       kfree(key_bu);
14229 +               return MH_AUTH_FAILED;
14230 +       }
14231 +
14232 +       if (mipv6_bcache_get(haddr, dst, &bc_entry) == 0) {
14233 +               if ((bc_entry.flags&MIPV6_BU_F_HOME) != 
14234 +                   (flags&MIPV6_BU_F_HOME)) {
14235 +                       DEBUG(DBG_INFO,
14236 +                             "Registration type change. Sending BA REG_TYPE_CHANGE_FORBIDDEN");
14237 +                       mipv6_send_ba(dst, haddr, coa, reply_coa,
14238 +                                     REG_TYPE_CHANGE_FORBIDDEN,
14239 +                                     sequence, lifetime, key_bu);
14240 +                       goto out;
14241 +               }
14242 +               if (!MIPV6_SEQ_GT(sequence, bc_entry.seq)) {
14243 +                       DEBUG(DBG_INFO,
14244 +                             "Sequence number mismatch. Sending BA SEQUENCE_NUMBER_OUT_OF_WINDOW");
14245 +                       mipv6_send_ba(dst, haddr, coa, reply_coa,
14246 +                                     SEQUENCE_NUMBER_OUT_OF_WINDOW,
14247 +                                     bc_entry.seq, lifetime, key_bu);
14248 +                       goto out;
14249 +               }
14250 +       }
14251 +
14252 +       if (!dereg) {
14253 +               int ifindex;
14254 +               struct rt6_info *rt;
14255 +
14256 +               /* Avoid looping binding cache entries */
14257 +               if (mipv6_bcache_get(coa, dst, &bc_entry) == 0) {
14258 +                       DEBUG(DBG_WARNING, "Looped BU, dropping the packet");
14259 +                       goto out;
14260 +               }
14261 +               DEBUG(DBG_INFO, "calling bu_add.");
14262 +               if ((rt = rt6_lookup(haddr, dst, 0, 0)) != NULL) {
14263 +                       ifindex = rt->rt6i_dev->ifindex;
14264 +                       dst_release(&rt->u.dst);
14265 +               } else {
14266 +                       /*
14267 +                        * Can't process the BU since the right interface is 
14268 +                        * not found.
14269 +                        */
14270 +                       DEBUG(DBG_WARNING, "No route entry found for handling "
14271 +                             "a BU request, (using 0 as index)");
14272 +                       ifindex = 0;
14273 +               }
14274 +               if (flags & MIPV6_BU_F_HOME)
14275 +                       mip6_fn.bce_home_add(ifindex, dst, haddr, coa, 
14276 +                                            reply_coa, lifetime, sequence,
14277 +                                            flags, key_bu);
14278 +               else
14279 +                       mip6_fn.bce_cache_add(ifindex, dst, haddr, coa, 
14280 +                                             reply_coa, lifetime, sequence,
14281 +                                             flags, key_bu);
14282 +       } else {
14283 +               DEBUG(DBG_INFO, "calling BCE delete.");
14284 +
14285 +               if (flags & MIPV6_BU_F_HOME)
14286 +                       mip6_fn.bce_home_del(dst, haddr, coa, reply_coa,
14287 +                                            sequence, flags, key_bu);
14288 +               else {
14289 +                       mipv6_rr_invalidate_nonce(nonce_ind);
14290 +                       mip6_fn.bce_cache_del(dst, haddr, coa, reply_coa, 
14291 +                                             sequence, flags, key_bu);
14292 +               }
14293 +       }
14294 + out:
14295 +       MIPV6_INC_STATS(n_bu_rcvd);
14296 +       if (key_bu)
14297 +               kfree(key_bu);
14298 +       return 0;
14299 +}
14300 +
14301 +static int mipv6_mh_rcv(struct sk_buff *skb)
14302 +{
14303 +       struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
14304 +       struct mipv6_mh *mh;
14305 +       struct in6_addr *lhome, *fhome, *lcoa = NULL, *fcoa = NULL;
14306 +       int ret = 0;
14307 +
14308 +       fhome = &skb->nh.ipv6h->saddr;
14309 +       lhome = &skb->nh.ipv6h->daddr;
14310 +
14311 +       if (opt->hao != 0) {
14312 +               struct mipv6_dstopt_homeaddr *hao;
14313 +               hao = (struct mipv6_dstopt_homeaddr *)(skb->nh.raw + opt->hao);
14314 +               fcoa = &hao->addr;
14315 +       }
14316 +
14317 +       if (opt->srcrt2 != 0) {
14318 +               struct rt2_hdr *rt2;
14319 +               rt2 = (struct rt2_hdr *)((u8 *)skb->nh.raw + opt->srcrt2);
14320 +               lcoa = &rt2->addr;
14321 +       }
14322 +
14323 +       /* Verify checksum is correct */
14324 +       if (skb->ip_summed == CHECKSUM_HW) {
14325 +               skb->ip_summed = CHECKSUM_UNNECESSARY;
14326 +               if (csum_ipv6_magic(fhome, lhome, skb->len, IPPROTO_MOBILITY,
14327 +                                   skb->csum)) {
14328 +                       if (net_ratelimit())
14329 +                               printk(KERN_WARNING "MIPv6 MH hw checksum failed\n");
14330 +                       skb->ip_summed = CHECKSUM_NONE;
14331 +               }
14332 +       }
14333 +       if (skb->ip_summed == CHECKSUM_NONE) {
14334 +               if (csum_ipv6_magic(fhome, lhome, skb->len, IPPROTO_MOBILITY,
14335 +                                   skb_checksum(skb, 0, skb->len, 0))) {
14336 +                       if (net_ratelimit())
14337 +                               printk(KERN_WARNING "MIPv6 MH checksum failed\n");
14338 +                       goto bad;
14339 +               }
14340 +       }
14341 +
14342 +       if (!pskb_may_pull(skb, skb->h.raw-skb->data+sizeof(*mh)) ||
14343 +           !pskb_may_pull(skb, 
14344 +                          skb->h.raw-skb->data+((skb->h.raw[1]+1)<<3))) {
14345 +               DEBUG(DBG_INFO, "MIPv6 MH invalid length");
14346 +               kfree_skb(skb);
14347 +               return 0;
14348 +       }
14349 +
14350 +       mh = (struct mipv6_mh *) skb->h.raw;
14351 +
14352 +       /* Verify there are no more headers after the MH */
14353 +       if (mh->payload != NEXTHDR_NONE) {
14354 +               __u32 pos = (__u32)&mh->payload - (__u32)skb->nh.raw;
14355 +               icmpv6_send(skb, ICMPV6_PARAMPROB,
14356 +                           ICMPV6_HDR_FIELD, pos, skb->dev);
14357 +
14358 +               DEBUG(DBG_INFO, "MIPv6 MH error");
14359 +               goto bad;
14360 +       }
14361 +
14362 +       if (mh->type > MIPV6_MH_MAX) {
14363 +               /* send binding error */
14364 +               printk("Invalid mobility header type (%d)\n", mh->type);
14365 +               mipv6_send_be(lhome, fcoa ? fcoa : fhome,
14366 +                             fcoa ? fhome : NULL, 
14367 +                             MIPV6_BE_UNKNOWN_MH_TYPE);
14368 +               goto bad;
14369 +       }
14370 +       if (mh_rcv[mh->type].func != NULL) {
14371 +               ret = mh_rcv[mh->type].func(skb, lhome, lcoa, fhome, fcoa, mh);
14372 +       } else {
14373 +               DEBUG(DBG_INFO, "No handler for MH Type %d", mh->type);
14374 +               goto bad;
14375 +       }
14376 +
14377 +       kfree_skb(skb);
14378 +       return 0;
14379 +
14380 +bad:
14381 +       MIPV6_INC_STATS(n_mh_in_error);
14382 +       kfree_skb(skb);
14383 +       return 0;
14384 +
14385 +}
14386 +
14387 +#if LINUX_VERSION_CODE >= 0x2052a
14388 +struct inet6_protocol mipv6_mh_protocol =
14389 +{
14390 +       mipv6_mh_rcv,           /* handler              */
14391 +       NULL                    /* error control        */
14392 +};
14393 +#else
14394 +struct inet6_protocol mipv6_mh_protocol = 
14395 +{
14396 +       mipv6_mh_rcv,           /* handler              */
14397 +       NULL,                   /* error control        */
14398 +       NULL,                   /* next                 */
14399 +       IPPROTO_MOBILITY,       /* protocol ID          */
14400 +       0,                      /* copy                 */
14401 +       NULL,                   /* data                 */
14402 +       "MIPv6 MH"              /* name                 */
14403 +};
14404 +#endif
14405 +
14406 +/*
14407 + *
14408 + * Code module init/exit functions
14409 + *
14410 + */
14411 +
14412 +int __init mipv6_mh_common_init(void)
14413 +{
14414 +       struct sock *sk;
14415 +       int err;
14416 +
14417 +       mip6_fn.bce_home_add = bc_cn_home_add;
14418 +       mip6_fn.bce_cache_add = bc_cache_add;
14419 +       mip6_fn.bce_home_del = bc_cn_home_delete;
14420 +       mip6_fn.bce_cache_del = bc_cache_delete;
14421 +
14422 +       mipv6_mh_socket = sock_alloc();
14423 +       if (mipv6_mh_socket == NULL) {
14424 +               printk(KERN_ERR
14425 +                      "Failed to create the MIP6 MH control socket.\n");
14426 +               return -1;
14427 +       }
14428 +       mipv6_mh_socket->type = SOCK_RAW;
14429 +
14430 +       if ((err = sock_create(PF_INET6, SOCK_RAW, IPPROTO_MOBILITY, 
14431 +                              &mipv6_mh_socket)) < 0) {
14432 +               printk(KERN_ERR
14433 +                      "Failed to initialize the MIP6 MH control socket (err %d).\n",
14434 +                      err);
14435 +               sock_release(mipv6_mh_socket);
14436 +               mipv6_mh_socket = NULL; /* for safety */
14437 +               return err;
14438 +       }
14439 +
14440 +       sk = mipv6_mh_socket->sk;
14441 +       sk->allocation = GFP_ATOMIC;
14442 +       sk->sndbuf = 64 * 1024 + sizeof(struct sk_buff);
14443 +       sk->prot->unhash(sk);
14444 +
14445 +       memset(&mh_rcv, 0, sizeof(mh_rcv));
14446 +       mh_rcv[MIPV6_MH_HOTI].func = mipv6_handle_mh_testinit;
14447 +       mh_rcv[MIPV6_MH_COTI].func = mipv6_handle_mh_testinit;
14448 +       mh_rcv[MIPV6_MH_BU].func =  mipv6_handle_mh_bu;
14449 +
14450 +#if LINUX_VERSION_CODE >= 0x2052a
14451 +       if (inet6_add_protocol(&mipv6_mh_protocol, IPPROTO_MOBILITY) < 0) {
14452 +               printk(KERN_ERR "Failed to register MOBILITY protocol\n");
14453 +               sock_release(mipv6_mh_socket);
14454 +               mipv6_mh_socket = NULL;
14455 +               return -EAGAIN;
14456 +       }
14457 +#else
14458 +       inet6_add_protocol(&mipv6_mh_protocol);
14459 +#endif
14460 +       /* To disable the use of dst_cache, 
14461 +        *  which slows down the sending of BUs ??
14462 +        */
14463 +       sk->dst_cache=NULL; 
14464 +
14465 +       return 0;
14466 +}
14467 +
14468 +void __exit mipv6_mh_common_exit(void)
14469 +{
14470 +       if (mipv6_mh_socket) sock_release(mipv6_mh_socket);
14471 +       mipv6_mh_socket = NULL; /* For safety. */
14472 +
14473 +#if LINUX_VERSION_CODE >= 0x2052a
14474 +       inet6_del_protocol(&mipv6_mh_protocol, IPPROTO_MOBILITY);
14475 +#else
14476 +       inet6_del_protocol(&mipv6_mh_protocol);
14477 +#endif
14478 +       memset(&mh_rcv, 0, sizeof(mh_rcv));
14479 +}
14480 --- /dev/null
14481 +++ linux-2.4.27/net/ipv6/mobile_ip6/mobhdr_mn.c
14482 @@ -0,0 +1,1155 @@
14483 +/*
14484 + *     Mobile IPv6 Mobility Header Functions for Mobile Node
14485 + *
14486 + *     Authors:
14487 + *     Antti Tuominen  <ajtuomin@tml.hut.fi>
14488 + *     Niklas Kämpe    <nhkampe@cc.hut.fi>
14489 + *     Henrik Petander <henrik.petander@hut.fi>
14490 + *
14491 + *     $Id:$
14492 + *
14493 + *     This program is free software; you can redistribute it and/or
14494 + *     modify it under the terms of the GNU General Public License as
14495 + *     published by the Free Software Foundation; either version 2 of
14496 + *     the License, or (at your option) any later version.
14497 + *
14498 + */
14499 +
14500 +#include <linux/types.h>
14501 +#include <linux/sched.h>
14502 +#include <linux/init.h>
14503 +#include <net/ipv6.h>
14504 +#include <net/addrconf.h>
14505 +#include <net/mipv6.h>
14506 +
14507 +#include "mobhdr.h"
14508 +#include "mn.h"
14509 +#include "bul.h"
14510 +#include "rr_crypto.h"
14511 +#include "debug.h"
14512 +#include "util.h"
14513 +#include "stats.h"
14514 +
14515 +int rr_configured = 1;
14516 +
14517 +/* Return value of mipv6_rr_state() */
14518 +#define NO_RR                  0
14519 +#define DO_RR                  1
14520 +#define RR_FOR_COA             2
14521 +#define INPROGRESS_RR          3
14522 +
14523 +/** 
14524 + * send_bu_msg - sends a Binding Update 
14525 + * @bulentry : BUL entry with the information for building a BU
14526 + *
14527 + * Function builds a BU msg based on the contents of a bul entry.
14528 + * Does not change the bul entry.
14529 + **/
14530 +static int send_bu_msg(struct mipv6_bul_entry *binding)
14531 +{ 
14532 +       int auth = 0; /* Use auth */
14533 +       int ret = 0;
14534 +       struct mipv6_auth_parm parm;
14535 +       struct mipv6_mh_bu bu;
14536 +
14537 +       if (!binding) {
14538 +               DEBUG(DBG_ERROR, "called with a null bul entry");
14539 +               return -1;
14540 +       }
14541 +       
14542 +       memset(&parm, 0, sizeof(parm));
14543 +       if (mipv6_prefix_compare(&binding->coa, &binding->home_addr, 64))
14544 +               parm.coa = &binding->home_addr;
14545 +       else
14546 +               parm.coa = &binding->coa;
14547 +       parm.cn_addr = &binding->cn_addr;
14548 +
14549 +       if (binding->rr && binding->rr->kbu) {
14550 +               DEBUG(DBG_INFO, "Binding with key");
14551 +               auth = 1;
14552 +               parm.k_bu = binding->rr->kbu;
14553 +       }
14554 +       memset(&bu, 0, sizeof(bu));
14555 +       bu.flags = binding->flags;
14556 +       bu.sequence = htons(binding->seq);
14557 +       bu.lifetime = htons(binding->lifetime >> 2);
14558 +       bu.reserved = 0;
14559 +
14560 +       ret = send_mh(&binding->cn_addr, &binding->home_addr,
14561 +                     MIPV6_MH_BU, sizeof(bu), (u8 *)&bu, 
14562 +                     &binding->home_addr, NULL, 
14563 +                     binding->ops, &parm);
14564 +
14565 +       if (ret == 0)
14566 +               MIPV6_INC_STATS(n_bu_sent);
14567 +
14568 +       return ret;
14569 +}
14570 +
14571 +/**
14572 + * mipv6_send_addr_test_init - send a HoTI or CoTI message
14573 + * @saddr: source address for H/CoTI
14574 + * @daddr: destination address for H/CoTI
14575 + * @msg_type: Identifies whether HoTI or CoTI
14576 + * @init_cookie: the HoTi or CoTi init cookie
14577 + *
14578 + * The message will be retransmitted till we get a HoT or CoT message, since 
14579 + * our caller (mipv6_RR_start) has entered this message in the BUL with
14580 + * exponential backoff retramission set.
14581 + */
14582 +static int mipv6_send_addr_test_init(struct in6_addr *saddr,
14583 +                                    struct in6_addr *daddr,
14584 +                                    u8 msg_type,
14585 +                                    u8 *init_cookie)
14586 +{
14587 +       struct mipv6_mh_addr_ti ti;
14588 +       struct mipv6_mh_opt *ops = NULL;
14589 +       int ret = 0;
14590 +
14591 +       /* Set reserved and copy the cookie from address test init msg */
14592 +       ti.reserved = 0;
14593 +       mipv6_rr_mn_cookie_create(init_cookie);
14594 +       memcpy(ti.init_cookie, init_cookie, MIPV6_RR_COOKIE_LENGTH);
14595 +
14596 +       ret = send_mh(daddr, saddr, msg_type, sizeof(ti), (u8 *)&ti,
14597 +                     NULL, NULL, ops, NULL);
14598 +       if (ret == 0) {
14599 +               if (msg_type == MIPV6_MH_HOTI) {
14600 +                       MIPV6_INC_STATS(n_hoti_sent);
14601 +               } else {
14602 +                       MIPV6_INC_STATS(n_coti_sent);
14603 +               }
14604 +       }
14605 +
14606 +       return ret;
14607 +}
14608 +
14609 +/*
14610 + *
14611 + * Callback handlers for binding update list
14612 + *
14613 + */
14614 +
14615 +/* Return value 0 means keep entry, non-zero means discard entry. */
14616 +
14617 +/* Callback for BUs not requiring acknowledgement
14618 + */
14619 +int bul_entry_expired(struct mipv6_bul_entry *bulentry)
14620 +{
14621 +       /* Lifetime expired, delete entry. */
14622 +       DEBUG(DBG_INFO, "bul entry 0x%p lifetime expired, deleting entry", 
14623 +             bulentry);
14624 +       return 1;
14625 +}
14626 +
14627 +/* Callback for BUs requiring acknowledgement with exponential resending
14628 + * scheme */
14629 +static int bul_resend_exp(struct mipv6_bul_entry *bulentry)
14630 +{
14631 +       unsigned long now = jiffies;
14632 +       
14633 +       DEBUG(DBG_INFO, "(0x%x) resending bu", (int) bulentry);
14634 +
14635 +       
14636 +       /* If sending a de-registration, do not care about the
14637 +        * lifetime value, as de-registrations are normally sent with
14638 +        * a zero lifetime value. If the entry is a home entry get the 
14639 +        * current lifetime. 
14640 +        */
14641 +
14642 +       if (bulentry->lifetime != 0) {
14643 +               bulentry->lifetime = mipv6_mn_get_bulifetime(
14644 +                       &bulentry->home_addr, &bulentry->coa, bulentry->flags);
14645 +
14646 +               bulentry->expire = now + bulentry->lifetime * HZ;
14647 +       } else {
14648 +               bulentry->expire = now + HOME_RESEND_EXPIRE * HZ; 
14649 +       }
14650 +       if (bulentry->rr) {
14651 +               /* Redo RR, if cookies have expired */
14652 +               if (time_after(jiffies, bulentry->rr->home_time + MAX_TOKEN_LIFE * HZ)) 
14653 +                       bulentry->rr->rr_state |= RR_WAITH;
14654 +               if (time_after(jiffies, bulentry->rr->careof_time + MAX_NONCE_LIFE * HZ)) 
14655 +                       bulentry->rr->rr_state |= RR_WAITC;
14656 +
14657 +               if (bulentry->rr->rr_state & RR_WAITH) {
14658 +                       /* Resend HoTI directly */
14659 +                       mipv6_send_addr_test_init(&bulentry->home_addr, 
14660 +                                                 &bulentry->cn_addr, MIPV6_MH_HOTI,
14661 +                                                 bulentry->rr->hot_cookie);
14662 +               }
14663 +               if (bulentry->rr->rr_state & RR_WAITC) {
14664 +                               /* Resend CoTI directly */
14665 +                               mipv6_send_addr_test_init(&bulentry->coa, 
14666 +                                                         &bulentry->cn_addr, MIPV6_MH_COTI,
14667 +                                                         bulentry->rr->cot_cookie);
14668 +                       }
14669 +               goto out;
14670 +       }
14671 +       
14672 +       bulentry->seq++;
14673 +
14674 +       if (send_bu_msg(bulentry) < 0)
14675 +               DEBUG(DBG_ERROR, "Resending of BU failed");
14676 +
14677 +out:
14678 +       /* Schedule next retransmission */
14679 +       if (bulentry->delay < bulentry->maxdelay) {
14680 +               bulentry->delay = 2 * bulentry->delay;
14681 +               if (bulentry->delay > bulentry->maxdelay) {
14682 +                       /* can happen if maxdelay is not power(mindelay, 2) */
14683 +                       bulentry->delay = bulentry->maxdelay;
14684 +               }
14685 +       } else if (bulentry->flags & MIPV6_BU_F_HOME) {
14686 +               /* Home registration - continue sending BU at maxdelay rate */
14687 +               DEBUG(DBG_INFO, "Sending BU to HA after max ack wait time "
14688 +                     "reached(0x%x)", (int) bulentry);
14689 +               bulentry->delay = bulentry->maxdelay;
14690 +       } else if (!(bulentry->flags & MIPV6_BU_F_HOME)) {
14691 +               /* Failed to get BA from a CN */
14692 +               bulentry->callback_time = now;
14693 +               return -1;
14694 +       }
14695 +       
14696 +       bulentry->callback_time = now + bulentry->delay * HZ;
14697 +       return 0;
14698 +}
14699 +
14700 +
14701 +
14702 +/* Callback for sending a registration refresh BU
14703 + */
14704 +static int bul_refresh(struct mipv6_bul_entry *bulentry)
14705 +{
14706 +       unsigned long now = jiffies;
14707 +       
14708 +       /* Refresh interval passed, send new BU */
14709 +       DEBUG(DBG_INFO, "bul entry 0x%x refresh interval passed, sending new BU", (int) bulentry);
14710 +       if (bulentry->lifetime == 0)
14711 +               return 0;
14712 +
14713 +       /* Set new maximum lifetime and expiration time */
14714 +       bulentry->lifetime = mipv6_mn_get_bulifetime(&bulentry->home_addr, 
14715 +                                                    &bulentry->coa, 
14716 +                                                    bulentry->flags);
14717 +       bulentry->expire = now + bulentry->lifetime * HZ;
14718 +       bulentry->seq++;
14719 +       /* Send update */
14720 +       if (send_bu_msg(bulentry) < 0)
14721 +               DEBUG(DBG_ERROR, "Resending of BU failed");
14722 +       
14723 +       if (time_after_eq(now, bulentry->expire)) {
14724 +               /* Sanity check */
14725 +               DEBUG(DBG_ERROR, "bul entry expire time in history - setting expire to %u secs", ERROR_DEF_LIFETIME);
14726 +               bulentry->lifetime = ERROR_DEF_LIFETIME;
14727 +               bulentry->expire = now + ERROR_DEF_LIFETIME*HZ;
14728 +       }
14729 +
14730 +       /* Set up retransmission */
14731 +       bulentry->state = RESEND_EXP;
14732 +       bulentry->callback = bul_resend_exp;
14733 +       bulentry->callback_time = now + INITIAL_BINDACK_TIMEOUT*HZ;
14734 +       bulentry->delay = INITIAL_BINDACK_TIMEOUT;
14735 +       bulentry->maxdelay = MAX_BINDACK_TIMEOUT;
14736 +
14737 +       return 0;
14738 +}
14739 +
14740 +static int mipv6_send_RR_bu(struct mipv6_bul_entry *bulentry)
14741 +{
14742 +       int ret;
14743 +       int ops_len = 0;
14744 +       u16 nonces[2];
14745 +
14746 +       DEBUG(DBG_INFO, "Sending BU to CN  %x:%x:%x:%x:%x:%x:%x:%x "
14747 +             "for home address %x:%x:%x:%x:%x:%x:%x:%x", 
14748 +             NIPV6ADDR(&bulentry->cn_addr), NIPV6ADDR(&bulentry->home_addr));
14749 +       nonces[0] = bulentry->rr->home_nonce_index;
14750 +       nonces[1] = bulentry->rr->careof_nonce_index;
14751 +       ops_len = sizeof(struct mipv6_mo_bauth_data) + MIPV6_RR_MAC_LENGTH + 
14752 +                       sizeof(struct mipv6_mo_nonce_indices);
14753 +       if (bulentry->ops) {
14754 +               DEBUG(DBG_WARNING, "Bul entry had existing mobility options, freeing them");
14755 +               kfree(bulentry->ops);
14756 +       }
14757 +       bulentry->ops = alloc_mh_opts(ops_len);
14758 +
14759 +       if (!bulentry->ops)
14760 +               return -ENOMEM;
14761 +       if (append_mh_opt(bulentry->ops, MIPV6_OPT_NONCE_INDICES, 
14762 +                         sizeof(struct mipv6_mo_nonce_indices) - 2, nonces) < 0)
14763 +               return -ENOMEM;
14764 +
14765 +       if (append_mh_opt(bulentry->ops, MIPV6_OPT_AUTH_DATA,
14766 +                         MIPV6_RR_MAC_LENGTH, NULL) < 0)
14767 +               return -ENOMEM;
14768 +       /* RR procedure is over, send a BU */
14769 +       if (!(bulentry->flags & MIPV6_BU_F_ACK)) {
14770 +               DEBUG(DBG_INFO, "Setting bul callback to bul_entry_expired");
14771 +               bulentry->state = ACK_OK;
14772 +               bulentry->callback = bul_entry_expired;
14773 +               bulentry->callback_time = jiffies + HZ * bulentry->lifetime;
14774 +               bulentry->expire = jiffies + HZ *  bulentry->lifetime;
14775 +       }
14776 +       else {
14777 +               bulentry->callback_time = jiffies + HZ;
14778 +               bulentry->expire = jiffies + HZ *  bulentry->lifetime;
14779 +       }
14780 +
14781 +       ret  = send_bu_msg(bulentry);
14782 +       mipv6_bul_reschedule(bulentry);
14783 +       return ret;
14784 +}
14785 +
14786 +static int mipv6_rr_state(struct mipv6_bul_entry *bul, struct in6_addr *saddr,
14787 +                         struct in6_addr *coa, __u8 flags)
14788 +{
14789 +       if (!rr_configured)
14790 +               return NO_RR;
14791 +               if (flags & MIPV6_BU_F_HOME) {
14792 +               /* We don't need RR, this is a Home Registration */
14793 +               return NO_RR;
14794 +       }
14795 +       if (!bul || !bul->rr) {
14796 +               /* First time BU to CN, need RR */
14797 +               return DO_RR;
14798 +       }
14799 +
14800 +       switch (bul->rr->rr_state) {
14801 +       case RR_INIT:
14802 +               /* Need RR if first BU to CN */
14803 +               return DO_RR;
14804 +       case RR_DONE:
14805 +               /* If MN moves to a new coa, do RR for it */
14806 +               if (!ipv6_addr_cmp(&bul->coa, coa))  
14807 +                       return NO_RR; 
14808 +               else
14809 +                       return DO_RR;
14810 +       default:
14811 +               /*
14812 +                * We are in the middle of RR, the HoTI and CoTI have been
14813 +                * sent. But we haven't got HoT and CoT from the CN, so
14814 +                * don't do anything more at this time.
14815 +                */
14816 +               return INPROGRESS_RR;
14817 +       }
14818 +}
14819 +
14820 +/**
14821 + * mipv6_RR_start - Start Return Routability procedure
14822 + * @home_addr: home address
14823 + * @cn_addr: correspondent address
14824 + * @coa: care-of address
14825 + * @entry: binding update list entry (if any)
14826 + * @initdelay: initial ack timeout
14827 + * @maxackdelay: maximum ack timeout
14828 + * @flags: flags
14829 + * @lifetime: lifetime of binding
14830 + * @ops: mobility options
14831 + *
14832 + * Caller must hold @bul_lock (write).
14833 + **/
14834 +static int mipv6_RR_start(struct in6_addr *home_addr, struct in6_addr *cn_addr,
14835 +                         struct in6_addr *coa, struct mipv6_bul_entry *entry,
14836 +                         __u32 initdelay, __u32 maxackdelay, __u8 flags, 
14837 +                         __u32 lifetime, struct mipv6_mh_opt *ops)
14838 +{
14839 +       int ret = -1;
14840 +       struct mipv6_bul_entry *bulentry = entry;
14841 +       struct mipv6_rr_info *rr = NULL;
14842 +       int seq = 0;
14843 +       DEBUG_FUNC();
14844 +       
14845 +       /* Do RR procedure only for care-of address after handoff, 
14846 +          if home cookie is still valid */
14847 +       if (bulentry && bulentry->rr) {
14848 +               if (time_before(jiffies, bulentry->rr->home_time + MAX_NONCE_LIFE * HZ) &&
14849 +                   lifetime && !(ipv6_addr_cmp(home_addr, coa) == 0)) { 
14850 +                       mipv6_rr_mn_cookie_create(bulentry->rr->cot_cookie); 
14851 +                       DEBUG(DBG_INFO, "Bul entry and rr info exist, only doing RR for CoA");
14852 +                       ipv6_addr_copy(&bulentry->coa, coa);
14853 +                       bulentry->rr->rr_state |= RR_WAITC;
14854 +               } else if (!lifetime) { /* Send only HoTi when returning home */
14855 +                       mipv6_rr_mn_cookie_create(bulentry->rr->hot_cookie); 
14856 +                       DEBUG(DBG_INFO, "Bul entry and rr info exist, only doing RR for HoA");
14857 +                       ipv6_addr_copy(&bulentry->coa, coa); /* Home address as CoA */
14858 +                       bulentry->rr->rr_state |= RR_WAITH;
14859 +               }
14860 +       } else {
14861 +               DEBUG(DBG_INFO, "Doing RR for both HoA and CoA");
14862 +               rr = kmalloc(sizeof(*rr), GFP_ATOMIC);
14863 +               memset(rr, 0, sizeof(*rr));
14864 +               rr->rr_state = RR_WAITHC;
14865 +       } 
14866 +       if (bulentry) {
14867 +               if (bulentry->state == ACK_ERROR)
14868 +                       goto out;
14869 +               seq = bulentry->seq + 1;
14870 +       } else
14871 +               seq = 0;
14872 +       /* Save the info in the BUL to retransmit the BU after RR is done */
14873 +       /* Caller must hold bul_lock (write) since we don't */
14874 +       
14875 +       if ((bulentry = mipv6_bul_add(cn_addr, home_addr, coa, 
14876 +                                     min_t(__u32, lifetime, MAX_RR_BINDING_LIFE),
14877 +                                     seq, flags, bul_resend_exp, initdelay, 
14878 +                                     RESEND_EXP, initdelay, 
14879 +                                     maxackdelay, ops, 
14880 +                                     rr)) == NULL) {
14881 +               DEBUG(DBG_INFO, "couldn't update BUL for HoTi");
14882 +               goto out;
14883 +       }
14884 +
14885 +       rr = bulentry->rr; 
14886 +       if (rr->rr_state&RR_WAITH)
14887 +               mipv6_send_addr_test_init(home_addr, cn_addr, MIPV6_MH_HOTI, 
14888 +                                         rr->hot_cookie);
14889 +       if (ipv6_addr_cmp(home_addr, coa) && lifetime) 
14890 +               mipv6_send_addr_test_init(coa, cn_addr, MIPV6_MH_COTI, rr->cot_cookie);
14891 +       else {
14892 +               bulentry->rr->rr_state &= ~RR_WAITC;
14893 +       }
14894 +       ret = 0;
14895 +out:
14896 +       return ret;
14897 +}
14898 +
14899 +/*
14900 + * Status codes for mipv6_ba_rcvd()
14901 + */
14902 +#define STATUS_UPDATE 0
14903 +#define STATUS_REMOVE 1
14904 +
14905 +/**
14906 + * mipv6_ba_rcvd - Update BUL for this Binding Acknowledgement
14907 + * @ifindex: interface BA came from
14908 + * @cnaddr: sender IPv6 address
14909 + * @home_addr: home address
14910 + * @sequence: sequence number
14911 + * @lifetime: lifetime granted by Home Agent in seconds
14912 + * @refresh: recommended resend interval
14913 + * @status: %STATUS_UPDATE (ack) or %STATUS_REMOVE (nack)
14914 + *
14915 + * This function must be called to notify the module of the receipt of
14916 + * a binding acknowledgement so that it can cease retransmitting the
14917 + * option. The caller must have validated the acknowledgement before calling
14918 + * this function. 'status' can be either STATUS_UPDATE in which case the
14919 + * binding acknowledgement is assumed to be valid and the corresponding
14920 + * binding update list entry is updated, or STATUS_REMOVE in which case
14921 + * the corresponding binding update list entry is removed (this can be
14922 + * used upon receiving a negative acknowledgement).
14923 + * Returns 0 if a matching binding update has been sent or non-zero if
14924 + * not.
14925 + */
14926 +static int mipv6_ba_rcvd(int ifindex, struct in6_addr *cnaddr, 
14927 +                        struct in6_addr *home_addr, 
14928 +                        u16 sequence, u32 lifetime, 
14929 +                        u32 refresh, int status)
14930 +{
14931 +       struct mipv6_bul_entry *bulentry;
14932 +       unsigned long now = jiffies;
14933 +       struct in6_addr coa;
14934 +
14935 +       DEBUG(DBG_INFO, "BA received with sequence number 0x%x, status: %d",
14936 +             (int) sequence, status);
14937 +
14938 +       /* Find corresponding entry in binding update list. */
14939 +       write_lock(&bul_lock);
14940 +       if ((bulentry = mipv6_bul_get(cnaddr, home_addr)) == NULL) {
14941 +               DEBUG(DBG_INFO, "- discarded, no entry in bul matches BA source address");
14942 +               write_unlock(&bul_lock);
14943 +               return -1;
14944 +       }
14945 +       
14946 +       ipv6_addr_copy(&coa, &bulentry->coa); 
14947 +       if (status == SEQUENCE_NUMBER_OUT_OF_WINDOW) {
14948 +               __u32 lifetime = mipv6_mn_get_bulifetime(&bulentry->home_addr, 
14949 +                                                        &bulentry->coa, 
14950 +                                                        bulentry->flags);
14951 +               bulentry->seq = sequence;
14952 +
14953 +               mipv6_send_bu(&bulentry->home_addr, &bulentry->cn_addr, 
14954 +                             &bulentry->coa, INITIAL_BINDACK_TIMEOUT,
14955 +                             MAX_BINDACK_TIMEOUT, 1, bulentry->flags,
14956 +                             lifetime, NULL);
14957 +               write_unlock(&bul_lock);
14958 +               return 0;
14959 +       } else if (status >= REASON_UNSPECIFIED) {
14960 +               int err;
14961 +               int at_home = MN_NOT_AT_HOME;
14962 +               DEBUG(DBG_WARNING, "- NACK - BA status:  %d, deleting bul entry", status);
14963 +               if (bulentry->flags & MIPV6_BU_F_HOME) {
14964 +                       struct mn_info *minfo;
14965 +                       read_lock(&mn_info_lock);
14966 +                       minfo = mipv6_mninfo_get_by_home(home_addr);
14967 +                       if (minfo) {
14968 +                               spin_lock(&minfo->lock);
14969 +                               if (minfo->is_at_home != MN_NOT_AT_HOME)
14970 +                                       minfo->is_at_home = MN_AT_HOME;
14971 +                               at_home = minfo->is_at_home;
14972 +                               minfo->has_home_reg = 0;
14973 +                               spin_unlock(&minfo->lock);
14974 +                       }
14975 +                       read_unlock(&mn_info_lock);
14976 +                       DEBUG(DBG_ERROR, "Home registration failed: BA status:  %d, deleting bul entry", status);
14977 +               }
14978 +               write_unlock(&bul_lock);
14979 +               err = mipv6_bul_delete(cnaddr, home_addr);
14980 +               if (at_home == MN_AT_HOME) {
14981 +                       mipv6_mn_send_home_na(home_addr);
14982 +                       write_lock_bh(&bul_lock);
14983 +                       mipv6_bul_iterate(mn_cn_handoff, &coa);
14984 +                       write_unlock_bh(&bul_lock);
14985 +               }
14986 +               return err;
14987 +       }
14988 +       bulentry->state = ACK_OK;
14989 +
14990 +       if (bulentry->flags & MIPV6_BU_F_HOME && lifetime > 0) {
14991 +               /* For home registrations: schedule a refresh binding update.
14992 +                * Use the refresh interval given by home agent or 80%
14993 +                * of lifetime, whichever is less.
14994 +                *
14995 +                * Adjust binding lifetime if 'granted' lifetime
14996 +                * (lifetime value in received binding acknowledgement)
14997 +                * is shorter than 'requested' lifetime (lifetime
14998 +                * value sent in corresponding binding update).
14999 +                * max((L_remain - (L_update - L_ack)), 0)
15000 +                */
15001 +               if (lifetime * HZ < (bulentry->expire - bulentry->lastsend)) {
15002 +                       bulentry->expire = 
15003 +                               max_t(__u32, bulentry->expire - 
15004 +                                     ((bulentry->expire - bulentry->lastsend) - 
15005 +                                      lifetime * HZ), jiffies + 
15006 +                                     ERROR_DEF_LIFETIME * HZ);
15007 +               }
15008 +               if (refresh > lifetime || refresh == 0)
15009 +                       refresh = 4 * lifetime / 5;
15010 +                       DEBUG(DBG_INFO, "setting callback for expiration of"
15011 +                             " a Home Registration: lifetime:%d, refresh:%d",
15012 +                             lifetime, refresh);
15013 +               bulentry->callback = bul_refresh;
15014 +               bulentry->callback_time = now + refresh * HZ;
15015 +               bulentry->expire = now + lifetime * HZ;
15016 +               bulentry->lifetime = lifetime;
15017 +               if (time_after_eq(jiffies, bulentry->expire)) {
15018 +                       /* Sanity check */
15019 +                       DEBUG(DBG_ERROR, "bul entry expire time in history - setting expire to %u secs",
15020 +                             ERROR_DEF_LIFETIME);
15021 +                       bulentry->expire = jiffies + ERROR_DEF_LIFETIME * HZ;
15022 +               }
15023 +               mipv6_mn_set_home_reg(home_addr, 1);
15024 +               mipv6_bul_iterate(mn_cn_handoff, &coa);
15025 +       } else if ((bulentry->flags & MIPV6_BU_F_HOME) && bulentry->lifetime == 0) {
15026 +               write_unlock(&bul_lock);
15027 +               DEBUG(DBG_INFO, "Got BA for deregistration BU");
15028 +               mipv6_mn_set_home_reg(home_addr, 0);
15029 +               mipv6_bul_delete(cnaddr, home_addr);
15030 +               mipv6_mn_send_home_na(home_addr);
15031 +
15032 +               write_lock_bh(&bul_lock);
15033 +               mipv6_bul_iterate(mn_cn_handoff, &coa);
15034 +               write_unlock_bh(&bul_lock);
15035 +               return 0;
15036 +       }
15037 +
15038 +       mipv6_bul_reschedule(bulentry);
15039 +       write_unlock(&bul_lock);
15040 +
15041 +       return 0;
15042 +}
15043 +
15044 +static int mipv6_handle_mh_HC_test(struct sk_buff *skb,
15045 +                                  struct in6_addr *saddr,
15046 +                                  struct in6_addr *fcoa,
15047 +                                  struct in6_addr *cn,
15048 +                                  struct in6_addr *lcoa,
15049 +                                  struct mipv6_mh *mh)
15050 +{
15051 +       int ret = 0;
15052 +       int msg_len = (mh->length+1) << 3;
15053 +       int opt_len;
15054 +
15055 +       struct mipv6_mh_addr_test *tm = (struct mipv6_mh_addr_test *)mh->data;
15056 +       struct mipv6_bul_entry *bulentry;
15057 +
15058 +       DEBUG_FUNC();
15059 +
15060 +       if (msg_len > skb->len)
15061 +               return -1;
15062 +
15063 +       opt_len = msg_len - sizeof(*mh) - sizeof(*tm);
15064 +
15065 +       if (opt_len < 0) {
15066 +               __u32 pos = (__u32)&mh->length - (__u32)skb->nh.raw;
15067 +               icmpv6_send(skb, ICMPV6_PARAMPROB,
15068 +                           ICMPV6_HDR_FIELD, pos, skb->dev);
15069 +
15070 +               DEBUG(DBG_INFO, "Mobility Header length less than H/C Test");
15071 +               return -1;
15072 +       }
15073 +       if (fcoa || lcoa) {
15074 +               DEBUG(DBG_INFO, "H/C Test has HAO or RTH2, dropped.");
15075 +               return -1;
15076 +       }
15077 +       write_lock(&bul_lock);
15078 +
15079 +       /* We need to get the home address, since CoT only has the CoA*/
15080 +       if (mh->type == MIPV6_MH_COT) {
15081 +               if ((bulentry = mipv6_bul_get_by_ccookie(cn, tm->init_cookie)) == NULL) {
15082 +                       DEBUG(DBG_ERROR, "has no BUL or RR state for "
15083 +                             "source:%x:%x:%x:%x:%x:%x:%x:%x",
15084 +                             NIPV6ADDR(cn));
15085 +                       write_unlock(&bul_lock);
15086 +                       return -1;
15087 +               }
15088 +       } else { /* HoT has the home address */
15089 +               if (((bulentry = mipv6_bul_get(cn, saddr)) == NULL) || !bulentry->rr) {
15090 +                       DEBUG(DBG_ERROR, "has no BUL or RR state for "
15091 +                             "source:%x:%x:%x:%x:%x:%x:%x:%x "
15092 +                             "dest:%x:%x:%x:%x:%x:%x:%x:%x",
15093 +                             NIPV6ADDR(cn), NIPV6ADDR(saddr));
15094 +                       write_unlock(&bul_lock);
15095 +                       return -1;
15096 +               }
15097 +       }
15098 +
15099 +       switch (mh->type) {
15100 +       case MIPV6_MH_HOT:
15101 +               if ((bulentry->rr->rr_state & RR_WAITH) == 0) {
15102 +                       DEBUG(DBG_ERROR, "Not waiting for a Home Test message");
15103 +                       goto out;
15104 +               }
15105 +               /*
15106 +                * Make sure no home cookies have been received yet.
15107 +                * TODO: Check not being put in at this time since subsequent
15108 +                * BU's after this time will have home cookie stored.
15109 +                */
15110 +       
15111 +               /* Check if the cookie received is the right one */
15112 +               if (!mipv6_equal_cookies(tm->init_cookie,
15113 +                                        bulentry->rr->hot_cookie)) {
15114 +                       /* Invalid cookie, might be an old cookie */
15115 +                       DEBUG(DBG_WARNING, "Received HoT cookie does not match stored cookie");
15116 +                       goto out;
15117 +               }
15118 +               DEBUG(DBG_INFO, "Got Care-of Test message");
15119 +               bulentry->rr->rr_state &= ~RR_WAITH;
15120 +               memcpy(bulentry->rr->home_cookie, tm->kgen_token, MIPV6_COOKIE_LEN);
15121 +               bulentry->rr->home_nonce_index = tm->nonce_index;
15122 +               bulentry->rr->home_time = jiffies;
15123 +               ret = 1;
15124 +               break;
15125 +
15126 +       case MIPV6_MH_COT:
15127 +               if ((bulentry->rr->rr_state & RR_WAITC) == 0) {
15128 +                       DEBUG(DBG_ERROR, "Not waiting for a Home Test message");
15129 +                       goto out;
15130 +               }
15131 +               /*
15132 +                * Make sure no home cookies have been received yet.
15133 +                * TODO: Check not being put in at this time since subsequent
15134 +                * BU's at this time will have careof cookie stored.
15135 +                */
15136 +       
15137 +               /* Check if the cookie received is the right one */
15138 +               if (!mipv6_equal_cookies(tm->init_cookie,
15139 +                                        bulentry->rr->cot_cookie)) {
15140 +                       DEBUG(DBG_INFO, "Received CoT cookie does not match stored cookie");
15141 +                       goto out;
15142 +               }
15143 +               bulentry->rr->rr_state &= ~RR_WAITC;
15144 +               memcpy(bulentry->rr->careof_cookie, tm->kgen_token, MIPV6_COOKIE_LEN);
15145 +               bulentry->rr->careof_nonce_index = tm->nonce_index;
15146 +               bulentry->rr->careof_time = jiffies;
15147 +               ret = 1;
15148 +               break;
15149 +       default:
15150 +               /* Impossible to get here */
15151 +               break;
15152 +       }
15153 +out:
15154 +       if (bulentry->rr->rr_state == RR_DONE) {
15155 +               if (bulentry->rr->kbu) /* First free any old keys */
15156 +                       kfree(bulentry->rr->kbu);
15157 +               /* Store the session key to be used in BU's */
15158 +               if (ipv6_addr_cmp(&bulentry->coa, &bulentry->home_addr) && bulentry->lifetime)
15159 +                       bulentry->rr->kbu = mipv6_rr_key_calc(bulentry->rr->home_cookie,
15160 +                                                             bulentry->rr->careof_cookie);
15161 +               else 
15162 +                       bulentry->rr->kbu = mipv6_rr_key_calc(bulentry->rr->home_cookie,
15163 +                                                             NULL);
15164 +               /* RR procedure is over, send a BU */
15165 +               mipv6_send_RR_bu(bulentry);
15166 +       }
15167 +       write_unlock(&bul_lock);
15168 +       return ret;
15169 +}
15170 +
15171 +/**
15172 + * mipv6_handle_mh_brr - Binding Refresh Request handler
15173 + * @home: home address
15174 + * @coa: care-of address
15175 + * @cn: source of this packet
15176 + * @mh: pointer to the beginning of the Mobility Header
15177 + *
15178 + * Handles Binding Refresh Request.  Packet and offset to option are
15179 + * passed.  Returns 0 on success, otherwise negative.
15180 + **/
15181 +static int mipv6_handle_mh_brr(struct sk_buff *skb,
15182 +                              struct in6_addr *home,
15183 +                              struct in6_addr *unused1,
15184 +                              struct in6_addr *cn,
15185 +                              struct in6_addr *unused2,
15186 +                              struct mipv6_mh *mh)
15187 +{
15188 +       struct mipv6_mh_brr *brr = (struct mipv6_mh_brr *)mh->data;
15189 +       struct mipv6_bul_entry *binding;
15190 +       int msg_len = (mh->length+1) << 3;
15191 +       int opt_len;
15192 +
15193 +       if (msg_len > skb->len)
15194 +               return -1;
15195 +
15196 +       opt_len = msg_len - sizeof(*mh) - sizeof(*brr);
15197 +
15198 +       if (opt_len < 0) {
15199 +               __u32 pos = (__u32)&mh->length - (__u32)skb->nh.raw;
15200 +               icmpv6_send(skb, ICMPV6_PARAMPROB,
15201 +                           ICMPV6_HDR_FIELD, pos, skb->dev);
15202 +
15203 +               DEBUG(DBG_WARNING, "Mobility Header length less than BRR");
15204 +               MIPV6_INC_STATS(n_brr_drop.invalid);
15205 +               return -1;
15206 +       }
15207 +
15208 +       /* check we know src, else drop */
15209 +       write_lock(&bul_lock);
15210 +       if ((binding = mipv6_bul_get(cn, home)) == NULL) {
15211 +               MIPV6_INC_STATS(n_brr_drop.misc);
15212 +               write_unlock(&bul_lock);
15213 +               return MH_UNKNOWN_CN;
15214 +       }
15215 +
15216 +       MIPV6_INC_STATS(n_brr_rcvd);
15217 +
15218 +       if (opt_len > 0) {
15219 +               struct mobopt opts;
15220 +               memset(&opts, 0, sizeof(opts));
15221 +               if (parse_mo_tlv(brr + 1, opt_len, &opts) < 0) {
15222 +                       write_unlock(&bul_lock);
15223 +                       return -1;
15224 +               }
15225 +               /*
15226 +                * MIPV6_OPT_AUTH_DATA
15227 +                */
15228 +       }
15229 +
15230 +       /* must hold bul_lock (write) */
15231 +       mipv6_RR_start(home, cn, &binding->coa, binding, binding->delay, 
15232 +                      binding->maxdelay, binding->flags,
15233 +                      binding->lifetime, binding->ops);
15234 +
15235 +       write_unlock(&bul_lock);
15236 +       /* MAY also decide to delete binding and send zero lifetime BU
15237 +           with alt-coa set to home address */
15238 +
15239 +       return 0;
15240 +}
15241 +
15242 +/**
15243 + * mipv6_handle_mh_ba - Binding Acknowledgement handler
15244 + * @src: source of this packet
15245 + * @coa: care-of address
15246 + * @home: home address
15247 + * @mh: pointer to the beginning of the Mobility Header
15248 + *
15249 + **/
15250 +static int mipv6_handle_mh_ba(struct sk_buff *skb,
15251 +                             struct in6_addr *home,
15252 +                             struct in6_addr *coa,
15253 +                             struct in6_addr *src,
15254 +                             struct in6_addr *unused,
15255 +                             struct mipv6_mh *mh)
15256 +{
15257 +       struct mipv6_mh_ba *ba = (struct mipv6_mh_ba *)mh->data;
15258 +       struct mipv6_bul_entry *binding = NULL;
15259 +       struct mobopt opts;
15260 +       int msg_len = (mh->length+1) << 3;
15261 +       int opt_len;
15262 +
15263 +       int auth = 1, req_auth = 1, refresh = -1, ifindex = 0;
15264 +       u32 lifetime, sequence;
15265 +
15266 +       if (msg_len > skb->len)
15267 +               return -1;
15268 +
15269 +       opt_len = msg_len - sizeof(*mh) - sizeof(*ba);
15270 +
15271 +       if (opt_len < 0) {
15272 +               __u32 pos = (__u32)&mh->length - (__u32)skb->nh.raw;
15273 +               icmpv6_send(skb, ICMPV6_PARAMPROB,
15274 +                           ICMPV6_HDR_FIELD, pos, skb->dev);
15275 +
15276 +               DEBUG(DBG_WARNING, "Mobility Header length less than BA");
15277 +               MIPV6_INC_STATS(n_ba_drop.invalid);
15278 +               return -1;
15279 +       }
15280 +
15281 +       lifetime = ntohs(ba->lifetime) << 2;
15282 +       sequence = ntohs(ba->sequence);
15283 +
15284 +       if (opt_len > 0) {
15285 +               memset(&opts, 0, sizeof(opts));
15286 +               if (parse_mo_tlv(ba + 1, opt_len, &opts) < 0)
15287 +                       return -1;
15288 +               /*
15289 +                * MIPV6_OPT_AUTH_DATA, MIPV6_OPT_BR_ADVICE
15290 +                */
15291 +               if (opts.br_advice)
15292 +                       refresh = ntohs(opts.br_advice->refresh_interval);
15293 +       }
15294 +
15295 +       if (ba->status >= EXPIRED_HOME_NONCE_INDEX && 
15296 +           ba->status <= EXPIRED_NONCES) 
15297 +               req_auth = 0;
15298 +       
15299 +       write_lock(&bul_lock);
15300 +       binding = mipv6_bul_get(src, home);
15301 +       if (!binding) {
15302 +               DEBUG(DBG_INFO, "No binding, BA dropped.");
15303 +               write_unlock(&bul_lock);
15304 +               return -1;
15305 +       }
15306 +
15307 +       if (opts.auth_data && binding->rr && 
15308 +           (mipv6_auth_check(src, coa, (__u8 *)mh, msg_len, 
15309 +                             opts.auth_data, binding->rr->kbu) == 0))
15310 +               auth = 1;
15311 +
15312 +       if (req_auth && binding->rr && !auth) {
15313 +               DEBUG(DBG_INFO, "BA Authentication failed.");
15314 +               MIPV6_INC_STATS(n_ba_drop.auth);
15315 +               write_unlock(&bul_lock);
15316 +               return MH_AUTH_FAILED;
15317 +       }
15318 +
15319 +       if (ba->status == SEQUENCE_NUMBER_OUT_OF_WINDOW) {
15320 +               DEBUG(DBG_INFO,
15321 +                     "Sequence number out of window, setting seq to %d",
15322 +                     sequence);
15323 +       } else if (binding->seq != sequence) {
15324 +               DEBUG(DBG_INFO, "BU/BA Sequence Number mismatch %d != %d",
15325 +                     binding->seq, sequence);
15326 +               MIPV6_INC_STATS(n_ba_drop.invalid);
15327 +               write_unlock(&bul_lock);
15328 +               return MH_SEQUENCE_MISMATCH;
15329 +       }
15330 +       if (ba->status == EXPIRED_HOME_NONCE_INDEX || ba->status == EXPIRED_NONCES) {
15331 +               if (binding->rr) {
15332 +                       /* Need to resend home test init to CN */
15333 +                       binding->rr->rr_state |= RR_WAITH;
15334 +                       mipv6_send_addr_test_init(&binding->home_addr, 
15335 +                                                 &binding->cn_addr, 
15336 +                                                 MIPV6_MH_HOTI,
15337 +                                                 binding->rr->hot_cookie);
15338 +                       MIPV6_INC_STATS(n_ban_rcvd);
15339 +               } else {
15340 +                       DEBUG(DBG_WARNING, "Got BA with status EXPIRED_HOME_NONCE_INDEX"
15341 +                             "for non-RR BU");
15342 +                       MIPV6_INC_STATS(n_ba_drop.invalid);
15343 +               }
15344 +               write_unlock(&bul_lock);
15345 +               return 0;
15346 +       } 
15347 +       if (ba->status == EXPIRED_CAREOF_NONCE_INDEX || ba->status == EXPIRED_NONCES) {
15348 +               if (binding->rr) { 
15349 +                       /* Need to resend care-of test init to CN */
15350 +                       binding->rr->rr_state |= RR_WAITC;
15351 +                       mipv6_send_addr_test_init(&binding->coa, 
15352 +                                                 &binding->cn_addr, 
15353 +                                                 MIPV6_MH_COTI,
15354 +                                                 binding->rr->cot_cookie);
15355 +                       MIPV6_INC_STATS(n_ban_rcvd);
15356 +               } else  {
15357 +                       DEBUG(DBG_WARNING, "Got BA with status EXPIRED_HOME_CAREOF_INDEX"
15358 +                             "for non-RR BU");
15359 +                       MIPV6_INC_STATS(n_ba_drop.invalid);
15360 +               }
15361 +               write_unlock(&bul_lock);
15362 +               return 0;
15363 +       }
15364 +       write_unlock(&bul_lock);
15365 +       
15366 +       if (ba->status >= REASON_UNSPECIFIED) {
15367 +               DEBUG(DBG_INFO, "Binding Ack status : %d indicates error", ba->status);
15368 +               mipv6_ba_rcvd(ifindex, src, home, sequence, lifetime,
15369 +                             refresh, ba->status);
15370 +               MIPV6_INC_STATS(n_ban_rcvd);
15371 +               return 0;
15372 +       }
15373 +       MIPV6_INC_STATS(n_ba_rcvd);
15374 +       if (mipv6_ba_rcvd(ifindex, src, home, ntohs(ba->sequence), lifetime,
15375 +                         refresh, ba->status)) {
15376 +               DEBUG(DBG_WARNING, "mipv6_ba_rcvd failed");
15377 +       }
15378 +       
15379 +       return 0;
15380 +}
15381 +
15382 +/**
15383 + * mipv6_handle_mh_be - Binding Error handler
15384 + * @cn: source of this packet
15385 + * @coa: care-of address
15386 + * @home: home address
15387 + * @mh: pointer to the beginning of the Mobility Header
15388 + *
15389 + **/
15390 +
15391 +static int mipv6_handle_mh_be(struct sk_buff *skb,
15392 +                             struct in6_addr *home,
15393 +                             struct in6_addr *coa,
15394 +                             struct in6_addr *cn,
15395 +                             struct in6_addr *unused,
15396 +                             struct mipv6_mh *mh)
15397 +{
15398 +       struct mipv6_mh_be *be = (struct mipv6_mh_be *)mh->data;
15399 +       int msg_len = (mh->length+1) << 3;
15400 +       int opt_len;
15401 +       struct in6_addr *hoa;
15402 +       struct bul_inval_args args;
15403 +
15404 +       DEBUG_FUNC();
15405 +
15406 +       if (msg_len > skb->len)
15407 +               return -1;
15408 +
15409 +       opt_len = msg_len - sizeof(*mh) - sizeof(*be);
15410 +
15411 +       if (opt_len < 0) {
15412 +               __u32 pos = (__u32)&mh->length - (__u32)skb->nh.raw;
15413 +               icmpv6_send(skb, ICMPV6_PARAMPROB,
15414 +                           ICMPV6_HDR_FIELD, pos, skb->dev);
15415 +
15416 +               DEBUG(DBG_WARNING, "Mobility Header length less than BE");
15417 +               MIPV6_INC_STATS(n_be_drop.invalid);
15418 +               return -1;
15419 +       }
15420 +
15421 +       
15422 +       if (!ipv6_addr_any(&be->home_addr))
15423 +               hoa = &be->home_addr;
15424 +       else
15425 +               hoa = home;
15426 +
15427 +       MIPV6_INC_STATS(n_be_rcvd);
15428 +
15429 +       args.all_rr_states = 0;
15430 +       args.cn = cn;
15431 +       args.mn = hoa;
15432 +
15433 +       switch (be->status) {
15434 +       case 1: /* Home Address Option used without a binding */
15435 +               /* Get ULP information about CN-MN communication.  If
15436 +                   nothing in progress, MUST delete.  Otherwise MAY
15437 +                   ignore. */
15438 +               args.all_rr_states = 1;
15439 +       case 2: /* Received unknown MH type */
15440 +               /* If not expecting ack, SHOULD ignore.  If MH
15441 +                   extension in use, stop it.  If not, stop RO for
15442 +                   this CN. */
15443 +               write_lock(&bul_lock);
15444 +               mipv6_bul_iterate(mn_bul_invalidate, &args);
15445 +               write_unlock(&bul_lock);
15446 +               break;
15447 +       }
15448 +
15449 +       return 0;
15450 +}
15451 +
15452 +/*
15453 + * mipv6_bu_rate_limit() : Takes a bulentry, a COA and 'flags' to check
15454 + * whether BU being sent is for Home Registration or not.
15455 + *
15456 + * If the number of BU's sent is fewer than MAX_FAST_UPDATES, this BU
15457 + * is allowed to be sent at the MAX_UPDATE_RATE.
15458 + * If the number of BU's sent is greater than or equal to MAX_FAST_UPDATES,
15459 + * this BU is allowed to be sent at the SLOW_UPDATE_RATE.
15460 + *
15461 + * Assumption : This function is not re-entrant. and the caller holds the
15462 + * bulentry lock (by calling mipv6_bul_get()) to stop races with other
15463 + * CPU's executing this same function.
15464 + *
15465 + * Side-Effects. Either of the following could  on success :
15466 + *     1. Sets consecutive_sends to 1 if the entry is a Home agent
15467 + *        registration or the COA has changed.
15468 + *     2. Increments consecutive_sends if the number of BU's sent so
15469 + *        far is less than MAX_FAST_UPDATES, and this BU is being sent
15470 + *        atleast MAX_UPDATE_RATE after previous one.
15471 + * 
15472 + * Return Value : 0 on Success, -1 on Failure
15473 + */
15474 +static int mipv6_bu_rate_limit(struct mipv6_bul_entry *bulentry, 
15475 +                              struct in6_addr *coa, __u8 flags)
15476 +{
15477 +       if ((flags & MIPV6_BU_F_HOME) || ipv6_addr_cmp(&bulentry->coa, coa)) {
15478 +               /* Home Agent Registration or different COA - restart from 1 */
15479 +               bulentry->consecutive_sends = 1;
15480 +               return 0;
15481 +       }
15482 +
15483 +       if (bulentry->consecutive_sends < MAX_FAST_UPDATES) {
15484 +               /* First MAX_FAST_UPDATES can be sent at MAX_UPDATE_RATE */
15485 +               if (jiffies - bulentry->lastsend < MAX_UPDATE_RATE * HZ) {
15486 +                       return -1;
15487 +               }
15488 +               bulentry->consecutive_sends ++;
15489 +       } else {
15490 +               /* Remaining updates SHOULD be sent at SLOW_UPDATE_RATE */
15491 +               if (jiffies - bulentry->lastsend < SLOW_UPDATE_RATE * HZ) {
15492 +                       return -1;
15493 +               }
15494 +               /* Don't inc 'consecutive_sends' to avoid overflow to zero */
15495 +       }
15496 +       /* OK to send a BU */
15497 +       return 0;
15498 +}
15499 +
15500 +/**
15501 + * mipv6_send_bu - send a Binding Update 
15502 + * @saddr: source address for BU
15503 + * @daddr: destination address for BU
15504 + * @coa: care-of address for MN
15505 + * @initdelay: initial BA wait timeout
15506 + * @maxackdelay: maximum BA wait timeout
15507 + * @exp: exponention back off
15508 + * @flags: flags for BU
15509 + * @lifetime: granted lifetime for binding
15510 + * @ops: mobility options
15511 + *
15512 + * Send a binding update.  'flags' may contain any of %MIPV6_BU_F_ACK,
15513 + * %MIPV6_BU_F_HOME, %MIPV6_BU_F_ROUTER bitwise ORed.  If
15514 + * %MIPV6_BU_F_ACK is included retransmission will be attempted until
15515 + * the update has been acknowledged.  Retransmission is done if no
15516 + * acknowledgement is received within @initdelay seconds.  @exp
15517 + * specifies whether to use exponential backoff (@exp != 0) or linear
15518 + * backoff (@exp == 0).  For exponential backoff the time to wait for
15519 + * an acknowledgement is doubled on each retransmission until a delay
15520 + * of @maxackdelay, after which retransmission is no longer attempted.
15521 + * For linear backoff the delay is kept constant and @maxackdelay
15522 + * specifies the maximum number of retransmissions instead.  If
15523 + * sub-options are present ops must contain all sub-options to be
15524 + * added.  On a mobile node, use the mobile node's home address for
15525 + * @saddr.  Returns 0 on success, non-zero on failure.
15526 + *
15527 + * Caller may not hold @bul_lock.
15528 + **/
15529 +int mipv6_send_bu(struct in6_addr *saddr, struct in6_addr *daddr,
15530 +                 struct in6_addr *coa, u32 initdelay, 
15531 +                 u32 maxackdelay, u8 exp, u8 flags, u32 lifetime,
15532 +                 struct mipv6_mh_opt *ops)
15533 +{
15534 +       int ret;
15535 +       __u8 state;
15536 +        __u16 seq = 0;
15537 +       int (*callback)(struct mipv6_bul_entry *);
15538 +       __u32 callback_time;
15539 +       struct mipv6_bul_entry *bulentry;
15540 +       
15541 +       /* First a sanity check: don't send BU to local addresses */
15542 +       if(ipv6_chk_addr(daddr, NULL)) {
15543 +               DEBUG(DBG_ERROR, "BUG: Trying to send BU to local address");
15544 +               return -1;
15545 +       }
15546 +       DEBUG(DBG_INFO, "Sending BU to CN  %x:%x:%x:%x:%x:%x:%x:%x "
15547 +             "for home address %x:%x:%x:%x:%x:%x:%x:%x", 
15548 +             NIPV6ADDR(daddr), NIPV6ADDR(saddr));
15549 +
15550 +       if ((bulentry = mipv6_bul_get(daddr, saddr)) != NULL) {
15551 +               if (bulentry->state == ACK_ERROR) {
15552 +                       /*
15553 +                        * Don't send any more BU's to nodes which don't
15554 +                        * understanding one. 
15555 +                        */
15556 +                       DEBUG(DBG_INFO, "Not sending BU to node which doesn't"
15557 +                             " understand one");
15558 +                       return -1;
15559 +               }
15560 +               if (mipv6_bu_rate_limit(bulentry, coa, flags) < 0) {
15561 +                       DEBUG(DBG_DATADUMP, "Limiting BU sent.");
15562 +                       return 0;
15563 +               }
15564 +       }
15565 +
15566 +       switch (mipv6_rr_state(bulentry, saddr, coa, flags)) {
15567 +       case INPROGRESS_RR:
15568 +               /* We are already doing RR, don't do BU at this time, it is
15569 +                * done automatically later */
15570 +               DEBUG(DBG_INFO, "RR in progress not sending BU");
15571 +               return 0;
15572 +
15573 +       case DO_RR:
15574 +               /* Just do RR and return, BU is done automatically later */
15575 +               DEBUG(DBG_INFO, "starting RR" );
15576 +               mipv6_RR_start(saddr, daddr, coa, bulentry, initdelay,
15577 +                              maxackdelay, flags, lifetime, ops);
15578 +               return 0;
15579 +               
15580 +       case NO_RR:
15581 +               DEBUG(DBG_DATADUMP, "No RR necessary" );
15582 +       default:
15583 +               break;
15584 +       }
15585 +
15586 +       if (bulentry)
15587 +               seq = bulentry->seq + 1;
15588 +       
15589 +       /* Add to binding update list */
15590 +       
15591 +       if (flags & MIPV6_BU_F_ACK) {
15592 +               DEBUG(DBG_INFO, "Setting bul callback to bul_resend_exp");
15593 +               /* Send using exponential backoff */
15594 +               state = RESEND_EXP;
15595 +               callback = bul_resend_exp;
15596 +               callback_time = initdelay;
15597 +       } else {
15598 +               DEBUG(DBG_INFO, "Setting bul callback to bul_entry_expired");
15599 +               /* No acknowledgement/resending required */
15600 +               state = ACK_OK; /* pretend we got an ack */
15601 +               callback = bul_entry_expired;
15602 +               callback_time = lifetime;
15603 +       }
15604 +
15605 +       /* BU only for the home address */
15606 +       /* We must hold bul_lock (write) while calling add */
15607 +       if ((bulentry = mipv6_bul_add(daddr, saddr, coa, lifetime, seq,
15608 +                                     flags, callback, callback_time, 
15609 +                                     state, initdelay, maxackdelay, ops, 
15610 +                                     NULL)) == NULL) {
15611 +               DEBUG(DBG_INFO, "couldn't update BUL");
15612 +               return 0;
15613 +       }
15614 +       ret = send_bu_msg(bulentry);
15615 +
15616 +       return ret;
15617 +}
15618 +
15619 +int __init mipv6_mh_mn_init(void)
15620 +{
15621 +       mipv6_mh_register(MIPV6_MH_HOT, mipv6_handle_mh_HC_test);
15622 +       mipv6_mh_register(MIPV6_MH_COT, mipv6_handle_mh_HC_test);
15623 +       mipv6_mh_register(MIPV6_MH_BA, mipv6_handle_mh_ba);
15624 +       mipv6_mh_register(MIPV6_MH_BRR, mipv6_handle_mh_brr);
15625 +       mipv6_mh_register(MIPV6_MH_BE, mipv6_handle_mh_be);
15626 +
15627 +       return 0;
15628 +}
15629 +
15630 +void __exit mipv6_mh_mn_exit(void)
15631 +{
15632 +       mipv6_mh_unregister(MIPV6_MH_HOT);
15633 +       mipv6_mh_unregister(MIPV6_MH_COT);
15634 +       mipv6_mh_unregister(MIPV6_MH_BA);
15635 +       mipv6_mh_unregister(MIPV6_MH_BRR);
15636 +       mipv6_mh_unregister(MIPV6_MH_BE);
15637 +}
15638 --- /dev/null
15639 +++ linux-2.4.27/net/ipv6/mobile_ip6/module_cn.c
15640 @@ -0,0 +1,167 @@
15641 +/*
15642 + *     Mobile IPv6 Common Module
15643 + *
15644 + *     Authors:
15645 + *     Sami Kivisaari          <skivisaa@cc.hut.fi>
15646 + *     Antti Tuominen          <ajtuomin@tml.hut.fi>
15647 + *
15648 + *     $Id$
15649 + *
15650 + *     This program is free software; you can redistribute it and/or
15651 + *     modify it under the terms of the GNU General Public License
15652 + *     as published by the Free Software Foundation; either version
15653 + *     2 of the License, or (at your option) any later version.
15654 + */
15655 +
15656 +#include <linux/config.h>
15657 +#include <linux/module.h>
15658 +#include <linux/init.h>
15659 +
15660 +#ifdef CONFIG_SYSCTL
15661 +#include <linux/sysctl.h>
15662 +#endif /* CONFIG_SYSCTL */
15663 +
15664 +#include <net/mipglue.h>
15665 +
15666 +#include "bcache.h"
15667 +#include "mipv6_icmp.h"
15668 +#include "stats.h"
15669 +#include "mobhdr.h"
15670 +#include "exthdrs.h"
15671 +
15672 +int mipv6_debug = 1;
15673 +
15674 +#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
15675 +MODULE_AUTHOR("MIPL Team");
15676 +MODULE_DESCRIPTION("Mobile IPv6");
15677 +MODULE_LICENSE("GPL");
15678 +MODULE_PARM(mipv6_debug, "i");
15679 +#endif
15680 +
15681 +#include "config.h"
15682 +
15683 +struct mip6_func mip6_fn;
15684 +struct mip6_conf mip6node_cnf = {
15685 +       capabilities:           CAP_CN,
15686 +       accept_ret_rout:        1,
15687 +       max_rtr_reachable_time: 0,
15688 +       eager_cell_switching:   0,
15689 +       max_num_tunnels:        0,
15690 +       min_num_tunnels:        0,
15691 +       binding_refresh_advice: 0,
15692 +       bu_lladdr:              0,
15693 +       bu_keymgm:              0,
15694 +       bu_cn_ack:              0
15695 +};
15696 +
15697 +#define MIPV6_BCACHE_SIZE 128
15698 +
15699 +/**********************************************************************
15700 + *
15701 + * MIPv6 CN Module Init / Cleanup
15702 + *
15703 + **********************************************************************/
15704 +
15705 +#ifdef CONFIG_SYSCTL
15706 +/* Sysctl table */
15707 +ctl_table mipv6_mobility_table[] = {
15708 +       {NET_IPV6_MOBILITY_DEBUG, "debuglevel",
15709 +        &mipv6_debug, sizeof(int), 0644, NULL,
15710 +        &proc_dointvec},
15711 +       {NET_IPV6_MOBILITY_RETROUT, "accept_return_routability",
15712 +        &mip6node_cnf.accept_ret_rout, sizeof(int), 0644, NULL,
15713 +        &proc_dointvec},
15714 +       {0}
15715 +};
15716 +ctl_table mipv6_table[] = {
15717 +       {NET_IPV6_MOBILITY, "mobility", NULL, 0, 0555, mipv6_mobility_table},
15718 +       {0}
15719 +};
15720 +
15721 +static struct ctl_table_header *mipv6_sysctl_header;
15722 +static struct ctl_table mipv6_net_table[];
15723 +static struct ctl_table mipv6_root_table[];
15724 +
15725 +ctl_table mipv6_net_table[] = {
15726 +       {NET_IPV6, "ipv6", NULL, 0, 0555, mipv6_table},
15727 +       {0}
15728 +};
15729 +
15730 +ctl_table mipv6_root_table[] = {
15731 +       {CTL_NET, "net", NULL, 0, 0555, mipv6_net_table},
15732 +       {0}
15733 +};
15734 +#endif /* CONFIG_SYSCTL */
15735 +
15736 +extern void mipv6_rr_init(void);
15737 +
15738 +/*  Initialize the module  */
15739 +static int __init mip6_init(void)
15740 +{
15741 +       int err = 0;
15742 +
15743 +       printk(KERN_INFO "MIPL Mobile IPv6 for Linux Correspondent Node %s (%s)\n",
15744 +              MIPLVERSION, MIPV6VERSION);
15745 +
15746 +#ifdef CONFIG_IPV6_MOBILITY_DEBUG
15747 +       printk(KERN_INFO "Debug-level: %d\n", mipv6_debug);
15748 +#endif
15749 +
15750 +       if ((err = mipv6_bcache_init(MIPV6_BCACHE_SIZE)) < 0)
15751 +               goto bcache_fail;
15752 +
15753 +       if ((err = mipv6_icmpv6_init()) < 0)
15754 +               goto icmp_fail;
15755 +
15756 +       if ((err = mipv6_stats_init()) < 0)
15757 +               goto stats_fail;
15758 +       mipv6_rr_init();
15759 +
15760 +#ifdef CONFIG_SYSCTL
15761 +       mipv6_sysctl_header = register_sysctl_table(mipv6_root_table, 0);
15762 +#endif
15763 +
15764 +       if ((err = mipv6_mh_common_init()) < 0)
15765 +               goto mh_fail;
15766 +
15767 +       MIPV6_SETCALL(mipv6_modify_txoptions, mipv6_modify_txoptions);
15768 +               
15769 +       MIPV6_SETCALL(mipv6_handle_homeaddr, mipv6_handle_homeaddr);
15770 +       MIPV6_SETCALL(mipv6_icmp_swap_addrs, mipv6_icmp_swap_addrs);
15771 +
15772 +       return 0;
15773 +
15774 +mh_fail:
15775 +#ifdef CONFIG_SYSCTL
15776 +       unregister_sysctl_table(mipv6_sysctl_header);
15777 +#endif
15778 +       mipv6_stats_exit();
15779 +stats_fail:
15780 +       mipv6_icmpv6_exit();
15781 +icmp_fail:
15782 +       mipv6_bcache_exit();
15783 +bcache_fail:
15784 +       return err;
15785 +}
15786 +module_init(mip6_init);
15787 +
15788 +#ifdef MODULE
15789 +/*  Cleanup module  */
15790 +static void __exit mip6_exit(void)
15791 +{
15792 +       printk(KERN_INFO "mip6_base.o exiting.\n");
15793 +#ifdef CONFIG_SYSCTL
15794 +       unregister_sysctl_table(mipv6_sysctl_header);
15795 +#endif
15796 +
15797 +       /* Invalidate all custom kernel hooks.  No need to do this
15798 +           separately for all hooks. */
15799 +       mipv6_invalidate_calls();
15800 +
15801 +       mipv6_mh_common_exit();
15802 +       mipv6_stats_exit();
15803 +       mipv6_icmpv6_exit();
15804 +       mipv6_bcache_exit();
15805 +}
15806 +module_exit(mip6_exit);
15807 +#endif /* MODULE */
15808 --- /dev/null
15809 +++ linux-2.4.27/net/ipv6/mobile_ip6/module_ha.c
15810 @@ -0,0 +1,264 @@
15811 +/*
15812 + *     Mobile IPv6 Home Agent Module
15813 + *
15814 + *     Authors:
15815 + *     Sami Kivisaari          <skivisaa@cc.hut.fi>
15816 + *     Antti Tuominen          <ajtuomin@tml.hut.fi>
15817 + *
15818 + *     $Id$
15819 + *
15820 + *     This program is free software; you can redistribute it and/or
15821 + *     modify it under the terms of the GNU General Public License
15822 + *     as published by the Free Software Foundation; either version
15823 + *     2 of the License, or (at your option) any later version.
15824 + */
15825 +
15826 +#include <linux/config.h>
15827 +#include <linux/module.h>
15828 +#include <linux/init.h>
15829 +
15830 +#ifdef CONFIG_SYSCTL
15831 +#include <linux/sysctl.h>
15832 +#endif /* CONFIG_SYSCTL */
15833 +
15834 +#include <net/mipglue.h>
15835 +#include <net/addrconf.h>
15836 +
15837 +#include "mobhdr.h"
15838 +#include "tunnel_ha.h"
15839 +#include "ha.h"
15840 +#include "halist.h"
15841 +#include "mipv6_icmp.h"
15842 +//#include "prefix.h"
15843 +#include "bcache.h"
15844 +#include "debug.h"
15845 +
15846 +int mipv6_use_auth = 0;
15847 +
15848 +#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
15849 +MODULE_AUTHOR("MIPL Team");
15850 +MODULE_DESCRIPTION("Mobile IPv6 Home Agent");
15851 +MODULE_LICENSE("GPL");
15852 +#endif
15853 +
15854 +#include "config.h"
15855 +
15856 +#define MIPV6_HALIST_SIZE 128
15857 +struct ha_info_opt {
15858 +       u8 type;
15859 +       u8 len;
15860 +       u16 res;
15861 +       u16 pref;
15862 +       u16 ltime;
15863 +};
15864 +/*
15865 + * Called from ndisc.c's router_discovery.
15866 + */
15867 +static int mipv6_ha_ra_rcv(struct sk_buff *skb, struct ndisc_options *ndopts)
15868 +{
15869 +       unsigned int ha_info_pref = 0, ha_info_lifetime;
15870 +       int ifi = ((struct inet6_skb_parm *)skb->cb)->iif;
15871 +       struct ra_msg *ra = (struct ra_msg *) skb->h.raw;
15872 +       struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
15873 +       struct in6_addr ll_addr;
15874 +       struct hal {
15875 +               struct in6_addr prefix;
15876 +               int plen;
15877 +               struct hal *next;
15878 +       };
15879 +       
15880 +       DEBUG_FUNC();
15881 +
15882 +       ha_info_lifetime = ntohs(ra->icmph.icmp6_rt_lifetime);
15883 +       ipv6_addr_copy(&ll_addr, saddr);
15884 +       
15885 +       if (ndopts->nd_opts_hai) {
15886 +               struct ha_info_opt *hai = (struct ha_info_opt *)ndopts->nd_opts_hai;
15887 +               ha_info_pref = ntohs(hai->pref);
15888 +               ha_info_lifetime = ntohs(hai->ltime);
15889 +               DEBUG(DBG_DATADUMP,
15890 +                     "received home agent info with preference : %d and lifetime : %d",
15891 +                     ha_info_pref, ha_info_lifetime);
15892 +       }
15893 +       if (ndopts->nd_opts_pi) {
15894 +               struct nd_opt_hdr *p;
15895 +               for (p = ndopts->nd_opts_pi;
15896 +                    p;
15897 +                    p = ndisc_next_option(p, ndopts->nd_opts_pi_end)) {
15898 +                       struct prefix_info *pinfo;
15899 +                       
15900 +                       pinfo = (struct prefix_info *) p;
15901 +                       
15902 +                       if (pinfo->router_address) {
15903 +                               DEBUG(DBG_DATADUMP, "Adding router address to "
15904 +                                     "ha queue \n");
15905 +                               /* If RA has H bit set and Prefix Info
15906 +                                * Option R bit set, queue this
15907 +                                * address to be added to Home Agents
15908 +                                * List.  
15909 +                                */
15910 +                               if (ipv6_addr_type(&pinfo->prefix) &
15911 +                                   IPV6_ADDR_LINKLOCAL)
15912 +                                       continue;
15913 +                               if (!ra->icmph.icmp6_home_agent || !ha_info_lifetime) {
15914 +                                       mipv6_halist_delete(&pinfo->prefix); 
15915 +                                       continue;
15916 +                               } else {
15917 +                                       
15918 +                                       mipv6_halist_add(ifi, &pinfo->prefix, 
15919 +                                                        pinfo->prefix_len, &ll_addr, 
15920 +                                                        ha_info_pref, ha_info_lifetime);
15921 +                               } 
15922 +                               
15923 +                       }
15924 +                       
15925 +               }
15926 +       }
15927 +       return MIPV6_ADD_RTR;
15928 +}
15929 +
15930 +/**********************************************************************
15931 + *
15932 + * MIPv6 Module Init / Cleanup
15933 + *
15934 + **********************************************************************/
15935 +
15936 +#ifdef CONFIG_SYSCTL
15937 +/* Sysctl table */
15938 +extern int 
15939 +mipv6_max_tnls_sysctl(ctl_table *, int, struct file *, void *, size_t *);
15940 +
15941 +extern int 
15942 +mipv6_min_tnls_sysctl(ctl_table *, int, struct file *, void *, size_t *);
15943 +
15944 +int max_adv = ~(u16)0;
15945 +int min_zero = 0;
15946 +ctl_table mipv6_mobility_table[] = {
15947 +       {NET_IPV6_MOBILITY_BINDING_REFRESH, "binding_refresh_advice",
15948 +        &mip6node_cnf.binding_refresh_advice, sizeof(int), 0644, NULL,
15949 +        &proc_dointvec_minmax, &sysctl_intvec, 0, &min_zero, &max_adv},
15950 +
15951 +       {NET_IPV6_MOBILITY_MAX_TNLS, "max_tnls", &mipv6_max_tnls, sizeof(int),
15952 +        0644, NULL, &mipv6_max_tnls_sysctl},
15953 +       {NET_IPV6_MOBILITY_MIN_TNLS, "min_tnls", &mipv6_min_tnls, sizeof(int),
15954 +        0644, NULL, &mipv6_min_tnls_sysctl},
15955 +       {0}
15956 +};
15957 +ctl_table mipv6_table[] = {
15958 +       {NET_IPV6_MOBILITY, "mobility", NULL, 0, 0555, mipv6_mobility_table},
15959 +       {0}
15960 +};
15961 +
15962 +static struct ctl_table_header *mipv6_sysctl_header;
15963 +static struct ctl_table mipv6_net_table[];
15964 +static struct ctl_table mipv6_root_table[];
15965 +
15966 +ctl_table mipv6_net_table[] = {
15967 +       {NET_IPV6, "ipv6", NULL, 0, 0555, mipv6_table},
15968 +       {0}
15969 +};
15970 +
15971 +ctl_table mipv6_root_table[] = {
15972 +       {CTL_NET, "net", NULL, 0, 0555, mipv6_net_table},
15973 +       {0}
15974 +};
15975 +#endif /* CONFIG_SYSCTL */
15976 +
15977 +extern void mipv6_check_dad(struct in6_addr *haddr);
15978 +extern void mipv6_dad_init(void);
15979 +extern void mipv6_dad_exit(void);
15980 +extern int mipv6_forward(struct sk_buff *);
15981 +
15982 +/*  Initialize the module  */
15983 +static int __init mip6_ha_init(void)
15984 +{
15985 +       int err = 0;
15986 +
15987 +       printk(KERN_INFO "MIPL Mobile IPv6 for Linux Home Agent %s (%s)\n",
15988 +              MIPLVERSION, MIPV6VERSION);
15989 +       mip6node_cnf.capabilities = CAP_CN | CAP_HA;
15990 +
15991 +       mip6_fn.icmpv6_dhaad_rep_rcv = mipv6_icmpv6_no_rcv;
15992 +       mip6_fn.icmpv6_dhaad_req_rcv = mipv6_icmpv6_rcv_dhaad_req;
15993 +       mip6_fn.icmpv6_pfxadv_rcv = mipv6_icmpv6_no_rcv;
15994 +       mip6_fn.icmpv6_pfxsol_rcv = mipv6_icmpv6_no_rcv;
15995 +       mip6_fn.icmpv6_paramprob_rcv = mipv6_icmpv6_no_rcv;
15996 +
15997 +#ifdef CONFIG_IPV6_MOBILITY_DEBUG
15998 +       printk(KERN_INFO "Debug-level: %d\n", mipv6_debug);
15999 +#endif
16000 +
16001 +#ifdef CONFIG_SYSCTL
16002 +       mipv6_sysctl_header = register_sysctl_table(mipv6_root_table, 0);
16003 +#endif
16004 +       mipv6_initialize_tunnel();
16005 +
16006 +       if ((err = mipv6_ha_init()) < 0)
16007 +               goto ha_fail;
16008 +
16009 +       MIPV6_SETCALL(mipv6_ra_rcv, mipv6_ha_ra_rcv);
16010 +       MIPV6_SETCALL(mipv6_forward, mipv6_forward);
16011 +       mipv6_dad_init();
16012 +       MIPV6_SETCALL(mipv6_check_dad, mipv6_check_dad);
16013 +
16014 +       if ((err = mipv6_halist_init(MIPV6_HALIST_SIZE)) < 0)
16015 +               goto halist_fail;
16016 +
16017 +//     mipv6_initialize_pfx_icmpv6();
16018 +
16019 +       return 0;
16020 +
16021 +halist_fail:
16022 +       mipv6_dad_exit();
16023 +       mipv6_ha_exit();
16024 +ha_fail:
16025 +       mipv6_shutdown_tunnel();
16026 +
16027 +       mip6_fn.icmpv6_dhaad_rep_rcv = NULL;
16028 +       mip6_fn.icmpv6_dhaad_req_rcv = NULL;
16029 +       mip6_fn.icmpv6_pfxadv_rcv = NULL;
16030 +       mip6_fn.icmpv6_pfxsol_rcv = NULL;
16031 +       mip6_fn.icmpv6_paramprob_rcv = NULL;
16032 +
16033 +       MIPV6_RESETCALL(mipv6_ra_rcv);
16034 +       MIPV6_RESETCALL(mipv6_forward);
16035 +       MIPV6_RESETCALL(mipv6_check_dad);
16036 +
16037 +#ifdef CONFIG_SYSCTL
16038 +       unregister_sysctl_table(mipv6_sysctl_header);
16039 +#endif
16040 +       return err;
16041 +}
16042 +module_init(mip6_ha_init);
16043 +
16044 +#ifdef MODULE
16045 +/*  Cleanup module  */
16046 +static void __exit mip6_ha_exit(void)
16047 +{
16048 +       printk(KERN_INFO "mip6_ha.o exiting.\n");
16049 +       mip6node_cnf.capabilities &= ~(int)CAP_HA;
16050 +
16051 +       mipv6_bcache_cleanup(HOME_REGISTRATION);
16052 +
16053 +       MIPV6_RESETCALL(mipv6_ra_rcv);
16054 +       MIPV6_RESETCALL(mipv6_forward);
16055 +       MIPV6_RESETCALL(mipv6_check_dad);
16056 +
16057 +       mipv6_halist_exit();
16058 +//     mipv6_shutdown_pfx_icmpv6();
16059 +
16060 +       mip6_fn.icmpv6_dhaad_rep_rcv = NULL;
16061 +       mip6_fn.icmpv6_dhaad_req_rcv = NULL;
16062 +       mip6_fn.icmpv6_pfxadv_rcv = NULL;
16063 +       mip6_fn.icmpv6_pfxsol_rcv = NULL;
16064 +       mip6_fn.icmpv6_paramprob_rcv = NULL;
16065 +
16066 +       mipv6_dad_exit();
16067 +       mipv6_ha_exit();
16068 +       mipv6_shutdown_tunnel();
16069 +#ifdef CONFIG_SYSCTL
16070 +       unregister_sysctl_table(mipv6_sysctl_header);
16071 +#endif
16072 +}
16073 +module_exit(mip6_ha_exit);
16074 +#endif /* MODULE */
16075 --- /dev/null
16076 +++ linux-2.4.27/net/ipv6/mobile_ip6/module_mn.c
16077 @@ -0,0 +1,188 @@
16078 +/*
16079 + *     Mobile IPv6 Mobile Node Module
16080 + *
16081 + *     Authors:
16082 + *     Sami Kivisaari          <skivisaa@cc.hut.fi>
16083 + *     Antti Tuominen          <ajtuomin@tml.hut.fi>
16084 + *
16085 + *     $Id$
16086 + *
16087 + *     This program is free software; you can redistribute it and/or
16088 + *     modify it under the terms of the GNU General Public License
16089 + *     as published by the Free Software Foundation; either version
16090 + *     2 of the License, or (at your option) any later version.
16091 + */
16092 +
16093 +#include <linux/config.h>
16094 +#include <linux/module.h>
16095 +#include <linux/init.h>
16096 +
16097 +#ifdef CONFIG_SYSCTL
16098 +#include <linux/sysctl.h>
16099 +#endif /* CONFIG_SYSCTL */
16100 +
16101 +#include <net/mipglue.h>
16102 +
16103 +extern int mipv6_debug;
16104 +int mipv6_use_auth = 0;
16105 +
16106 +#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
16107 +MODULE_AUTHOR("MIPL Team");
16108 +MODULE_DESCRIPTION("Mobile IPv6 Mobile Node");
16109 +MODULE_LICENSE("GPL");
16110 +MODULE_PARM(mipv6_debug, "i");
16111 +#endif
16112 +
16113 +#include "config.h"
16114 +
16115 +#include "mobhdr.h"
16116 +#include "mn.h"
16117 +#include "mipv6_icmp.h"
16118 +//#include "prefix.h"
16119 +
16120 +/* TODO: These will go as soon as we get rid of the last two ioctls */
16121 +extern int mipv6_ioctl_mn_init(void);
16122 +extern void mipv6_ioctl_mn_exit(void);
16123 +
16124 +/**********************************************************************
16125 + *
16126 + * MIPv6 Module Init / Cleanup
16127 + *
16128 + **********************************************************************/
16129 +
16130 +#ifdef CONFIG_SYSCTL
16131 +/* Sysctl table */
16132 +
16133 +extern int max_rtr_reach_time;
16134 +extern int eager_cell_switching;
16135 +
16136 +static int max_reach = 1000;
16137 +static int min_reach = 1;
16138 +static int max_one = 1;
16139 +static int min_zero = 0;
16140 +
16141 +extern int 
16142 +mipv6_mdetect_mech_sysctl(ctl_table *, int, struct file *, void *, size_t *);
16143 +
16144 +extern int 
16145 +mipv6_router_reach_sysctl(ctl_table *, int, struct file *, void *, size_t *);
16146 +
16147 +ctl_table mipv6_mobility_table[] = {
16148 +       {NET_IPV6_MOBILITY_BU_F_LLADDR, "bu_flag_lladdr",
16149 +        &mip6node_cnf.bu_lladdr, sizeof(int), 0644, NULL,
16150 +        &proc_dointvec_minmax, &sysctl_intvec, 0, &min_zero, &max_one},
16151 +       {NET_IPV6_MOBILITY_BU_F_KEYMGM, "bu_flag_keymgm",
16152 +        &mip6node_cnf.bu_keymgm, sizeof(int), 0644, NULL,
16153 +        &proc_dointvec_minmax, &sysctl_intvec, 0, &min_zero, &max_one},
16154 +       {NET_IPV6_MOBILITY_BU_F_CN_ACK, "bu_flag_cn_ack",
16155 +        &mip6node_cnf.bu_cn_ack, sizeof(int), 0644, NULL,
16156 +        &proc_dointvec_minmax, &sysctl_intvec, 0, &min_zero, &max_one},
16157 +
16158 +       {NET_IPV6_MOBILITY_ROUTER_REACH, "max_router_reachable_time",
16159 +        &max_rtr_reach_time, sizeof(int), 0644, NULL,
16160 +        &proc_dointvec_minmax, &sysctl_intvec, 0, &min_reach, &max_reach},
16161 +
16162 +       {NET_IPV6_MOBILITY_MDETECT_MECHANISM, "eager_cell_switching",
16163 +        &eager_cell_switching, sizeof(int), 0644, NULL,
16164 +        &proc_dointvec_minmax, &sysctl_intvec, 0, &min_zero, &max_one},
16165 +
16166 +       {0}
16167 +};
16168 +ctl_table mipv6_table[] = {
16169 +       {NET_IPV6_MOBILITY, "mobility", NULL, 0, 0555, mipv6_mobility_table},
16170 +       {0}
16171 +};
16172 +
16173 +static struct ctl_table_header *mipv6_sysctl_header;
16174 +static struct ctl_table mipv6_net_table[];
16175 +static struct ctl_table mipv6_root_table[];
16176 +
16177 +ctl_table mipv6_net_table[] = {
16178 +       {NET_IPV6, "ipv6", NULL, 0, 0555, mipv6_table},
16179 +       {0}
16180 +};
16181 +
16182 +ctl_table mipv6_root_table[] = {
16183 +       {CTL_NET, "net", NULL, 0, 0555, mipv6_net_table},
16184 +       {0}
16185 +};
16186 +#endif /* CONFIG_SYSCTL */
16187 +
16188 +/*  Initialize the module  */
16189 +static int __init mip6_mn_init(void)
16190 +{
16191 +       int err = 0;
16192 +
16193 +       printk(KERN_INFO "MIPL Mobile IPv6 for Linux Mobile Node %s (%s)\n",
16194 +              MIPLVERSION, MIPV6VERSION);
16195 +       mip6node_cnf.capabilities = CAP_CN | CAP_MN;
16196 +
16197 +#ifdef CONFIG_IPV6_MOBILITY_DEBUG
16198 +       printk(KERN_INFO "Debug-level: %d\n", mipv6_debug);
16199 +#endif
16200 +
16201 +#ifdef CONFIG_SYSCTL
16202 +       mipv6_sysctl_header = register_sysctl_table(mipv6_root_table, 0);
16203 +#endif
16204 +       if ((err = mipv6_mn_init()) < 0)
16205 +               goto mn_fail;
16206 +
16207 +       mipv6_mh_mn_init();
16208 +
16209 +       mip6_fn.icmpv6_dhaad_rep_rcv = mipv6_icmpv6_rcv_dhaad_rep;
16210 +       mip6_fn.icmpv6_dhaad_req_rcv = mipv6_icmpv6_no_rcv;
16211 +       mip6_fn.icmpv6_pfxadv_rcv = mipv6_icmpv6_no_rcv;
16212 +       mip6_fn.icmpv6_pfxsol_rcv = mipv6_icmpv6_no_rcv;
16213 +       mip6_fn.icmpv6_paramprob_rcv = mipv6_icmpv6_rcv_paramprob;
16214 +
16215 +//     mipv6_initialize_pfx_icmpv6();
16216 +
16217 +       if ((err = mipv6_ioctl_mn_init()) < 0)
16218 +               goto ioctl_fail;
16219 +
16220 +       return 0;
16221 +
16222 +ioctl_fail:
16223 +//     mipv6_shutdown_pfx_icmpv6();
16224 +
16225 +       mip6_fn.icmpv6_dhaad_rep_rcv = NULL;
16226 +       mip6_fn.icmpv6_dhaad_req_rcv = NULL;
16227 +       mip6_fn.icmpv6_pfxadv_rcv = NULL;
16228 +       mip6_fn.icmpv6_pfxsol_rcv = NULL;
16229 +       mip6_fn.icmpv6_paramprob_rcv = NULL;
16230 +
16231 +       mipv6_mh_mn_exit();
16232 +       mipv6_mn_exit();
16233 +mn_fail:
16234 +#ifdef CONFIG_SYSCTL
16235 +       unregister_sysctl_table(mipv6_sysctl_header);
16236 +#endif
16237 +       return err;
16238 +}
16239 +module_init(mip6_mn_init);
16240 +
16241 +#ifdef MODULE
16242 +/*  Cleanup module  */
16243 +static void __exit mip6_mn_exit(void)
16244 +{
16245 +       printk(KERN_INFO "mip6_mn.o exiting.\n");
16246 +       mip6node_cnf.capabilities &= ~(int)CAP_MN;
16247 +
16248 +       mipv6_ioctl_mn_exit();
16249 +//     mipv6_shutdown_pfx_icmpv6();
16250 +
16251 +       mip6_fn.icmpv6_dhaad_rep_rcv = NULL;
16252 +       mip6_fn.icmpv6_dhaad_req_rcv = NULL;
16253 +       mip6_fn.icmpv6_pfxadv_rcv = NULL;
16254 +       mip6_fn.icmpv6_pfxsol_rcv = NULL;
16255 +       mip6_fn.icmpv6_paramprob_rcv = NULL;
16256 +
16257 +       mipv6_mn_exit();
16258 +
16259 +/* common cleanup */
16260 +#ifdef CONFIG_SYSCTL
16261 +       unregister_sysctl_table(mipv6_sysctl_header);
16262 +#endif
16263 +}
16264 +module_exit(mip6_mn_exit);
16265 +#endif /* MODULE */
16266 --- /dev/null
16267 +++ linux-2.4.27/net/ipv6/mobile_ip6/multiaccess_ctl.c
16268 @@ -0,0 +1,287 @@
16269 +/*  
16270 + * 2001 (c) Oy L M Ericsson Ab
16271 + *
16272 + * Author: NomadicLab / Ericsson Research <ipv6@nomadiclab.com>
16273 + *
16274 + * $Id$
16275 + *
16276 + */
16277 +
16278 +/*
16279 + * Vertical hand-off information manager
16280 + */
16281 +
16282 +#include <linux/netdevice.h>
16283 +#include <linux/in6.h>
16284 +#include <linux/module.h>
16285 +#include <linux/init.h>
16286 +#include <linux/proc_fs.h>
16287 +#include <linux/string.h>
16288 +#include <linux/kernel.h>
16289 +#include <asm/io.h>
16290 +#include <asm/uaccess.h>
16291 +#include <linux/list.h>
16292 +#include "multiaccess_ctl.h"
16293 +#include "debug.h"
16294 +
16295 +/*
16296 + * Local variables
16297 + */
16298 +static LIST_HEAD(if_list);
16299 +
16300 +/* Internal interface information list */
16301 +struct ma_if_info {
16302 +       struct list_head list;
16303 +       int        interface_id;
16304 +       int        preference;
16305 +       __u8       status;
16306 +};
16307 +
16308 +/**
16309 + * ma_ctl_get_preference - get preference value for interface
16310 + * @ifi: interface index
16311 + * 
16312 + * Returns integer value preference for given interface.
16313 + **/
16314 +int ma_ctl_get_preference(int ifi)
16315 +{
16316 +       struct list_head *lh;
16317 +       struct ma_if_info *info;
16318 +       int pref = 0;
16319 +
16320 +       list_for_each(lh, &if_list) {
16321 +               info = list_entry(lh, struct ma_if_info, list);
16322 +               if (info->interface_id == ifi) {
16323 +                       pref = info->preference;
16324 +                       return pref;
16325 +               }
16326 +       }
16327 +       return -1;
16328 +}
16329 +/**
16330 + * ma_ctl_get_preference - get preference value for interface
16331 + * @ifi: interface index
16332 + * 
16333 + * Returns integer value interface index for interface with highest preference.
16334 + **/
16335 +int ma_ctl_get_preferred_if(void)
16336 +{
16337 +       struct list_head *lh;
16338 +       struct ma_if_info *info, *pref_if = NULL;
16339 +       
16340 +       list_for_each(lh, &if_list) {
16341 +               info = list_entry(lh, struct ma_if_info, list);
16342 +               if (!pref_if || (info->preference > pref_if->preference)) {
16343 +                       pref_if = info;
16344 +               }
16345 +       }
16346 +       if (pref_if) return pref_if->interface_id;
16347 +       return 0;
16348 +}
16349 +/**
16350 + * ma_ctl_set_preference - set preference for interface
16351 + * @arg: ioctl args
16352 + *
16353 + * Sets preference of an existing interface (called by ioctl).
16354 + **/
16355 +void ma_ctl_set_preference(unsigned long arg)
16356 +{
16357 +       struct list_head *lh;
16358 +       struct ma_if_info *info;
16359 +       struct ma_if_uinfo uinfo;
16360 +       
16361 +       memset(&uinfo, 0, sizeof(struct ma_if_uinfo));
16362 +       if (copy_from_user(&uinfo, (struct ma_if_uinfo *)arg, 
16363 +                          sizeof(struct ma_if_uinfo)) < 0) {
16364 +               DEBUG(DBG_WARNING, "copy_from_user failed");
16365 +               return;
16366 +       }
16367 +
16368 +       /* check if the interface exists */
16369 +       list_for_each(lh, &if_list) {
16370 +               info = list_entry(lh, struct ma_if_info, list);
16371 +               if (info->interface_id == uinfo.interface_id) {
16372 +                       info->preference = uinfo.preference;
16373 +                       return;
16374 +               }
16375 +       }
16376 +}
16377 +
16378 +/**
16379 + * ma_ctl_add_iface - add new interface to list
16380 + * @if_index: interface index
16381 + *
16382 + * Adds new interface entry to preference list.  Preference is set to
16383 + * the same value as @if_index.  Entry @status is set to
16384 + * %MA_IFACE_NOT_USED.
16385 + **/
16386 +void ma_ctl_add_iface(int if_index)
16387 +{
16388 +       struct list_head *lh;
16389 +       struct ma_if_info *info;
16390 +
16391 +       DEBUG_FUNC();
16392 +       
16393 +       /* check if the interface already exists */
16394 +       list_for_each(lh, &if_list) {
16395 +               info = list_entry(lh, struct ma_if_info, list);
16396 +               if (info->interface_id == if_index) {
16397 +                       info->status = MA_IFACE_NOT_USED;
16398 +                       info->preference = if_index;
16399 +                       return;
16400 +               }
16401 +       }
16402 +
16403 +       info = kmalloc(sizeof(struct ma_if_info), GFP_ATOMIC);
16404 +       if (info == NULL) {
16405 +               DEBUG(DBG_ERROR, "Out of memory");
16406 +               return;
16407 +       }
16408 +       memset(info, 0, sizeof(struct ma_if_info));
16409 +       info->interface_id = if_index;
16410 +       info->preference = if_index;
16411 +       info->status = MA_IFACE_NOT_USED;
16412 +       list_add(&info->list, &if_list);
16413 +}
16414 +
16415 +/**
16416 + * ma_ctl_del_iface - remove entry from the list
16417 + * @if_index: interface index
16418 + *
16419 + * Removes entry for interface @if_index from preference list.
16420 + **/
16421 +int ma_ctl_del_iface(int if_index)
16422 +{
16423 +       struct list_head *lh, *next;
16424 +       struct ma_if_info *info;
16425 +
16426 +       DEBUG_FUNC();
16427 +
16428 +       /* if the iface exists, change availability to 0 */
16429 +       list_for_each_safe(lh, next, &if_list) {
16430 +               info = list_entry(lh, struct ma_if_info, list);
16431 +               if (info->interface_id == if_index) {
16432 +                       list_del(&info->list);
16433 +                       kfree(info);
16434 +                       return 0;
16435 +               }
16436 +       }
16437 +
16438 +       return -1;
16439 +}
16440 +
16441 +/**
16442 + * ma_ctl_upd_iface - update entry (and list)
16443 + * @if_index: interface to update
16444 + * @status: new status for interface
16445 + * @change_if_index: new interface
16446 + *
16447 + * Updates @if_index entry on preference list.  Entry status is set to
16448 + * @status.  If new @status is %MA_IFACE_CURRENT, updates list to have
16449 + * only one current device.  If @status is %MA_IFACE_NOT_PRESENT,
16450 + * entry is deleted and further if entry had %MA_IFACE_CURRENT set,
16451 + * new current device is looked up and returned in @change_if_index.
16452 + * New preferred interface is also returned if current device changes
16453 + * to %MA_IFACE_NOT_USED.  Returns 0 on success, otherwise negative.
16454 + **/
16455 +int ma_ctl_upd_iface(int if_index, int status, int *change_if_index)
16456 +{
16457 +       struct list_head *lh, *tmp;
16458 +       struct ma_if_info *info, *pref = NULL;
16459 +       int found = 0;
16460 +
16461 +       DEBUG_FUNC();
16462 +
16463 +       *change_if_index = 0;
16464 +
16465 +       /* check if the interface exists */
16466 +       list_for_each_safe(lh, tmp, &if_list) {
16467 +               info = list_entry(lh, struct ma_if_info, list);
16468 +               if (status == MA_IFACE_NOT_PRESENT) {
16469 +                       if (info->interface_id == if_index) {
16470 +                               list_del_init(&info->list);
16471 +                               kfree(info);
16472 +                               found = 1;
16473 +                               break;
16474 +                       }
16475 +               } else if (status == MA_IFACE_CURRENT) {
16476 +                       if (info->interface_id == if_index) {
16477 +                               info->status |= MA_IFACE_CURRENT;
16478 +                               found = 1;
16479 +                       } else {
16480 +                               info->status |= MA_IFACE_NOT_USED;
16481 +                       }
16482 +               } else if (status == MA_IFACE_NOT_USED) {
16483 +                       if (info->interface_id == if_index) {
16484 +                               if (info->status | MA_IFACE_CURRENT) {
16485 +                                       found = 1;
16486 +                               }
16487 +                               info->status &= !MA_IFACE_CURRENT;
16488 +                               info->status |= MA_IFACE_NOT_USED;
16489 +                               info->status &= !MA_IFACE_HAS_ROUTER;
16490 +                       }
16491 +                       break;
16492 +               } else if (status == MA_IFACE_HAS_ROUTER) {
16493 +                       if (info->interface_id == if_index) {
16494 +                               info->status |= MA_IFACE_HAS_ROUTER;
16495 +                       }
16496 +                       return 0;
16497 +               }
16498 +       }
16499 +
16500 +       if (status & (MA_IFACE_NOT_USED|MA_IFACE_NOT_PRESENT) && found) {
16501 +               /* select new interface */
16502 +               list_for_each(lh, &if_list) {
16503 +                       info = list_entry(lh, struct ma_if_info, list);
16504 +                       if (pref == NULL || ((info->preference > pref->preference) && 
16505 +                                            info->status & MA_IFACE_HAS_ROUTER))
16506 +                               pref = info;
16507 +               }
16508 +               if (pref) {
16509 +                       *change_if_index = pref->interface_id;
16510 +                       pref->status |= MA_IFACE_CURRENT;
16511 +               } else {
16512 +                       *change_if_index = -1;
16513 +               }
16514 +               return 0;
16515 +       }
16516 +
16517 +       if (found) return 0;
16518 +
16519 +       return -1;
16520 +}
16521 +
16522 +static int if_proc_info(char *buffer, char **start, off_t offset,
16523 +                       int length)
16524 +{
16525 +       struct list_head *lh;
16526 +       struct ma_if_info *info;
16527 +       int len = 0;
16528 +
16529 +       list_for_each(lh, &if_list) {
16530 +               info = list_entry(lh, struct ma_if_info, list);
16531 +               len += sprintf(buffer + len, "%02d %010d %1d %1d\n",
16532 +                              info->interface_id, info->preference,
16533 +                              !!(info->status & MA_IFACE_HAS_ROUTER),
16534 +                              !!(info->status & MA_IFACE_CURRENT));
16535 +       }
16536 +
16537 +       *start = buffer + offset;
16538 +
16539 +       len -= offset;
16540 +
16541 +       if (len > length) len = length;
16542 +
16543 +       return len;
16544 +
16545 +}
16546 +
16547 +void ma_ctl_init(void)
16548 +{
16549 +       proc_net_create("mip6_iface", 0, if_proc_info);
16550 +}
16551 +
16552 +void ma_ctl_clean(void)
16553 +{
16554 +       proc_net_remove("mip6_iface");
16555 +}
16556 --- /dev/null
16557 +++ linux-2.4.27/net/ipv6/mobile_ip6/multiaccess_ctl.h
16558 @@ -0,0 +1,77 @@
16559 +/*  
16560 + * 2001 (c) Oy L M Ericsson Ab
16561 + *
16562 + * Author: NomadicLab / Ericsson Research <ipv6@nomadiclab.com>
16563 + *
16564 + * $Id$
16565 + *
16566 + */
16567 +
16568 +#ifndef _MULTIACCESS_CTL_H
16569 +#define _MULTIACCESS_CTL_H
16570 +
16571 +/* status */
16572 +#define MA_IFACE_NOT_PRESENT 0x01
16573 +#define MA_IFACE_NOT_USED    0x02
16574 +#define MA_IFACE_HAS_ROUTER  0x04
16575 +#define MA_IFACE_CURRENT     0x10
16576 +
16577 +struct ma_if_uinfo {
16578 +       int        interface_id;
16579 +       int        preference;
16580 +       __u8       status;
16581 +};
16582 +/*
16583 + *  @ma_ctl_get_preferred_id: returns most preferred interface id
16584 + */
16585 +int ma_ctl_get_preferred_if(void);
16586 +
16587 +/* @ma_ctl_get_preference: returns preference for an interface
16588 + * @name: name of the interface (dev->name)
16589 + */
16590 +int ma_ctl_get_preference(int ifi);
16591 +
16592 +/*
16593 + * Public function: ma_ctl_set_preference
16594 + * Description: Set preference of an existing interface (called by ioctl)
16595 + * Returns:
16596 + */
16597 +void ma_ctl_set_preference(unsigned long);
16598 +
16599 +/*
16600 + * Public function: ma_ctl_add_iface
16601 + * Description: Inform control module to insert a new interface
16602 + * Returns: 0 if success, any other number means an error
16603 + */
16604 +void ma_ctl_add_iface(int);
16605 +
16606 +/*
16607 + * Public function: ma_ctl_del_iface
16608 + * Description: Inform control module to remove an obsolete interface
16609 + * Returns: 0 if success, any other number means an error
16610 + */
16611 +int ma_ctl_del_iface(int);
16612 +
16613 +/*
16614 + * Public function: ma_ctl_upd_iface
16615 + * Description: Inform control module of status change.
16616 + * Returns: 0 if success, any other number means an error
16617 + */
16618 +int ma_ctl_upd_iface(int, int, int *);
16619 +
16620 +/*
16621 + * Public function: ma_ctl_init
16622 + * Description: XXX
16623 + * Returns: XXX
16624 + */
16625 +void ma_ctl_init(void);
16626 +
16627 +/*
16628 + * Public function: ma_ctl_clean
16629 + * Description: XXX
16630 + * Returns: -
16631 + */
16632 +void ma_ctl_clean(void);
16633 +
16634 +
16635 +#endif
16636 --- /dev/null
16637 +++ linux-2.4.27/net/ipv6/mobile_ip6/ndisc_ha.c
16638 @@ -0,0 +1,596 @@
16639 +/*
16640 + *     Mobile IPv6 Duplicate Address Detection Functions
16641 + *
16642 + *     Authors:
16643 + *     Krishna Kumar <krkumar@us.ibm.com>
16644 + *
16645 + *      $Id$
16646 + *
16647 + *      This program is free software; you can redistribute it and/or
16648 + *      modify it under the terms of the GNU General Public License
16649 + *      as published by the Free Software Foundation; either version
16650 + *      2 of the License, or (at your option) any later version.
16651 + *
16652 + */
16653 +
16654 +#include <linux/autoconf.h>
16655 +#include <linux/types.h>
16656 +#include <linux/init.h>
16657 +#include <linux/skbuff.h>
16658 +#include <linux/in6.h>
16659 +#include <net/ipv6.h>
16660 +#include <net/addrconf.h>
16661 +#include <net/mipv6.h>
16662 +
16663 +#include "debug.h"
16664 +#include "bcache.h"
16665 +#include "ha.h" /* mipv6_generate_ll_addr */
16666 +
16667 +/*
16668 + * Binding Updates from MN are cached in this structure till DAD is performed.
16669 + * This structure is used to retrieve a pending Binding Update for the HA to
16670 + * reply to after performing DAD. The first cell is different from the rest as
16671 + * follows :
16672 + *     1. The first cell is used to chain the remaining cells. 
16673 + *     2. The timeout of the first cell is used to delete expired entries
16674 + *        in the list of cells, while the timeout of the other cells are
16675 + *        used for timing out a NS request so as to reply to a BU.
16676 + *     3. The only elements of the first cell that are used are :
16677 + *        next, prev, and callback_timer.
16678 + *
16679 + * TODO : Don't we need to do pneigh_lookup on the Link Local address ?
16680 + */
16681 +struct mipv6_dad_cell {
16682 +       /* Information needed for DAD management */
16683 +       struct mipv6_dad_cell   *next;  /* Next element on the DAD list */
16684 +       struct mipv6_dad_cell   *prev;  /* Prev element on the DAD list */
16685 +       __u16                   probes; /* Number of times to probe for addr */
16686 +       __u16                   flags;  /* Entry flags - see below */
16687 +       struct timer_list       callback_timer; /* timeout for entry */
16688 +
16689 +       /* Information needed for performing DAD */
16690 +       struct inet6_ifaddr     *ifp;
16691 +       int                     ifindex;
16692 +       struct in6_addr         daddr;
16693 +       struct in6_addr         haddr;          /* home address */
16694 +       struct in6_addr         ll_haddr;       /* Link Local value of haddr */
16695 +       struct in6_addr         coa;
16696 +       struct in6_addr         rep_coa;
16697 +       __u32                   ba_lifetime;
16698 +       __u16                   sequence;
16699 +       __u8                    bu_flags;
16700 +};
16701 +
16702 +/* Values for the 'flags' field in the mipv6_dad_cell */
16703 +#define        DAD_INIT_ENTRY          0
16704 +#define        DAD_DUPLICATE_ADDRESS   1
16705 +#define        DAD_UNIQUE_ADDRESS      2
16706 +
16707 +/* Head of the pending DAD list */
16708 +static struct mipv6_dad_cell dad_cell_head;
16709 +
16710 +/* Lock to access the pending DAD list */
16711 +static rwlock_t dad_lock = RW_LOCK_UNLOCKED;
16712 +
16713 +/* Timer routine which deletes 'expired' entries in the DAD list */
16714 +static void mipv6_dad_delete_old_entries(unsigned long unused)
16715 +{
16716 +       struct mipv6_dad_cell *curr, *next;
16717 +       unsigned long next_time = 0;
16718 +
16719 +       write_lock(&dad_lock);
16720 +       curr = dad_cell_head.next;
16721 +       while (curr != &dad_cell_head) {
16722 +               next = curr->next;
16723 +               if (curr->flags != DAD_INIT_ENTRY) {
16724 +                       if (curr->callback_timer.expires <= jiffies) {
16725 +                               /* Entry has expired, free it up. */
16726 +                               curr->next->prev = curr->prev;
16727 +                               curr->prev->next = curr->next;
16728 +                               in6_ifa_put(curr->ifp);
16729 +                               kfree(curr);
16730 +                       } else if (next_time <
16731 +                                  curr->callback_timer.expires) {
16732 +                               next_time = curr->callback_timer.expires;
16733 +                       }
16734 +               }
16735 +               curr = next;
16736 +       }
16737 +       write_unlock(&dad_lock);
16738 +       if (next_time) {
16739 +               /*
16740 +                * Start another timer if more cells need to be removed at
16741 +                * a later stage.
16742 +                */
16743 +               dad_cell_head.callback_timer.expires = next_time;
16744 +               add_timer(&dad_cell_head.callback_timer);
16745 +       }
16746 +}
16747 +
16748 +/* 
16749 + * Queue a timeout routine to clean up 'expired' DAD entries.
16750 + */
16751 +static void mipv6_start_dad_head_timer(struct mipv6_dad_cell *cell)
16752 +{
16753 +       unsigned long expire = jiffies +
16754 +           cell->ifp->idev->nd_parms->retrans_time * 10;
16755 +
16756 +       if (!timer_pending(&dad_cell_head.callback_timer) ||
16757 +           expire < dad_cell_head.callback_timer.expires) {
16758 +               /*
16759 +                * Add timer if none pending, or mod the timer if new 
16760 +                * cell needs to be expired before existing timer runs.
16761 +                *
16762 +                * We let the cell remain as long as possible, so that
16763 +                * new BU's as part of retransmissions don't have to go
16764 +                * through DAD before replying.
16765 +                */
16766 +               dad_cell_head.callback_timer.expires = expire;
16767 +
16768 +               /*
16769 +                * Keep the cell around for atleast some time to handle
16770 +                * retransmissions or BU's due to fast MN movement. This
16771 +                * is needed otherwise a previous timeout can delete all
16772 +                * expired entries including this new one.
16773 +                */
16774 +               cell->callback_timer.expires = jiffies +
16775 +                   cell->ifp->idev->nd_parms->retrans_time * 5;
16776 +               if (!timer_pending(&dad_cell_head.callback_timer)) {
16777 +                       add_timer(&dad_cell_head.callback_timer);
16778 +               } else {
16779 +                       mod_timer(&dad_cell_head.callback_timer, expire);
16780 +               }
16781 +       }
16782 +}
16783 +
16784 +
16785 +/* Join solicited node MC address */
16786 +static inline void mipv6_join_sol_mc_addr(struct in6_addr *addr,
16787 +                                         struct net_device *dev)
16788 +{
16789 +       struct in6_addr maddr;
16790 +
16791 +       /* Join solicited node MC address */
16792 +       addrconf_addr_solict_mult(addr, &maddr);
16793 +       ipv6_dev_mc_inc(dev, &maddr);
16794 +}
16795 +
16796 +/* Leave solicited node MC address */
16797 +static inline void mipv6_leave_sol_mc_addr(struct in6_addr *addr,
16798 +                                          struct net_device *dev)
16799 +{
16800 +       struct in6_addr maddr;
16801 +
16802 +       addrconf_addr_solict_mult(addr, &maddr);
16803 +       ipv6_dev_mc_dec(dev, &maddr);
16804 +}
16805 +
16806 +/* Send a NS */
16807 +static inline void mipv6_dad_send_ns(struct inet6_ifaddr *ifp,
16808 +                                    struct in6_addr *haddr)
16809 +{
16810 +       struct in6_addr unspec;
16811 +       struct in6_addr mcaddr;
16812 +
16813 +       ipv6_addr_set(&unspec, 0, 0, 0, 0);
16814 +       addrconf_addr_solict_mult(haddr, &mcaddr);
16815 +
16816 +       /* addr is 'unspec' since we treat this address as transient */
16817 +       ndisc_send_ns(ifp->idev->dev, NULL, haddr, &mcaddr, &unspec);
16818 +}
16819 +
16820 +/*
16821 + * Search for a home address in the list of pending DAD's. Called from
16822 + * Neighbor Advertisement
16823 + * Return values :
16824 + *     -1 : No DAD entry found for this advertisement, or entry already
16825 + *          finished processing.
16826 + *     0  : Entry found waiting for DAD to finish.
16827 + */
16828 +static int dad_search_haddr(struct in6_addr *ll_haddr,
16829 +                           struct in6_addr *daddr, struct in6_addr *haddr,
16830 +                           struct in6_addr *coa, struct in6_addr *rep_coa,
16831 +                           __u16 * seq, struct inet6_ifaddr **ifp)
16832 +{
16833 +       struct mipv6_dad_cell *cell;
16834 +
16835 +       read_lock(&dad_lock);
16836 +       cell = dad_cell_head.next;
16837 +       while (cell != &dad_cell_head &&
16838 +              ipv6_addr_cmp(&cell->ll_haddr, ll_haddr) && 
16839 +              ipv6_addr_cmp(&cell->haddr, ll_haddr)) {
16840 +               cell = cell->next;
16841 +       }
16842 +       if (cell == &dad_cell_head || cell->flags != DAD_INIT_ENTRY) {
16843 +               /* Not found element, or element already finished processing */
16844 +               if (cell != &dad_cell_head) {
16845 +                       /*
16846 +                        * Set the state to DUPLICATE, even if it was UNIQUE
16847 +                        * earlier. It is not needed to setup timer via 
16848 +                        * mipv6_start_dad_head_timer since this must have
16849 +                        * already been done.
16850 +                        */
16851 +                       cell->flags = DAD_DUPLICATE_ADDRESS;
16852 +               }
16853 +               read_unlock(&dad_lock);
16854 +               return -1;
16855 +       }
16856 +
16857 +       /*
16858 +        * The NA found an unprocessed entry in the DAD list. Expire this
16859 +        * entry since another node advertised this address. Caller should
16860 +        * reject BU (DAD failed).
16861 +        */
16862 +       ipv6_addr_copy(daddr, &cell->daddr);
16863 +       ipv6_addr_copy(haddr, &cell->haddr);
16864 +       ipv6_addr_copy(coa, &cell->coa);
16865 +       ipv6_addr_copy(rep_coa, &cell->rep_coa);
16866 +       *seq = cell->sequence;
16867 +       *ifp = cell->ifp;
16868 +
16869 +       if (del_timer(&cell->callback_timer) == 0) {
16870 +               /* Timer already deleted, race with Timeout Handler */
16871 +               /* No action needed */
16872 +       }
16873 +
16874 +       cell->flags = DAD_DUPLICATE_ADDRESS;
16875 +
16876 +       /* Now leave this address to avoid future processing of NA's */
16877 +       mipv6_leave_sol_mc_addr(&cell->ll_haddr, cell->ifp->idev->dev);
16878 +       /* Leave also global address, if link local address was in use */
16879 +       if (ipv6_addr_cmp(&cell->ll_haddr, &cell->haddr))
16880 +               mipv6_leave_sol_mc_addr(&cell->haddr, cell->ifp->idev->dev);
16881 +       /* Start dad_head timer to remove this entry */
16882 +       mipv6_start_dad_head_timer(cell);
16883 +
16884 +       read_unlock(&dad_lock);
16885 +
16886 +       return 0;
16887 +}
16888 +
16889 +/* ENTRY routine called via Neighbor Advertisement */
16890 +void mipv6_check_dad(struct in6_addr *ll_haddr)
16891 +{
16892 +       struct in6_addr daddr, haddr, coa, rep_coa;
16893 +       struct inet6_ifaddr *ifp;
16894 +       __u16 seq;
16895 +
16896 +       if (dad_search_haddr(ll_haddr, &daddr, &haddr, &coa, &rep_coa, &seq,
16897 +                            &ifp) < 0) {
16898 +               /* 
16899 +                * Didn't find entry, or no action needed (the action has
16900 +                * already been performed).
16901 +                */
16902 +               return;
16903 +       }
16904 +
16905 +       /*
16906 +        * A DAD cell was present, meaning that there is a pending BU
16907 +        * request for 'haddr' - reject the BU.
16908 +        */
16909 +       mipv6_bu_finish(ifp, 0, DUPLICATE_ADDR_DETECT_FAIL,
16910 +                       &daddr, &haddr, &coa, &rep_coa, 0, seq, 0, NULL);
16911 +       return;
16912 +}
16913 +
16914 +/*
16915 + * Check if the passed 'cell' is in the list of pending DAD's. Called from
16916 + * the Timeout Handler.
16917 + *
16918 + * Assumes that the caller is holding the dad_lock in reader mode.
16919 + */
16920 +static int dad_search_cell(struct mipv6_dad_cell *cell)
16921 +{
16922 +       struct mipv6_dad_cell *tmp;
16923 +
16924 +       tmp = dad_cell_head.next;
16925 +       while (tmp != &dad_cell_head && tmp != cell) {
16926 +               tmp = tmp->next;
16927 +       }
16928 +       if (tmp == cell) {
16929 +               if (cell->flags == DAD_INIT_ENTRY) {
16930 +                       /* Found valid entry */
16931 +                       if (--cell->probes == 0) {
16932 +                               /*
16933 +                                * Retransmission's are over - return success.
16934 +                                */
16935 +                               cell->flags = DAD_UNIQUE_ADDRESS;
16936 +
16937 +                               /* 
16938 +                                * Leave this address to avoid future 
16939 +                                * processing of NA's.
16940 +                                */
16941 +                               mipv6_leave_sol_mc_addr(&cell->ll_haddr,
16942 +                                                       cell->ifp->idev->
16943 +                                                       dev);
16944 +                               if (ipv6_addr_cmp(&cell->ll_haddr, &cell->haddr))
16945 +                                       mipv6_leave_sol_mc_addr(&cell->haddr, 
16946 +                                                               cell->ifp->idev->dev);
16947 +                               /* start timeout to delete this cell. */
16948 +                               mipv6_start_dad_head_timer(cell);
16949 +                               return 0;
16950 +                       }
16951 +                       /*
16952 +                        * Retransmission not finished, send another NS and
16953 +                        * return failure.
16954 +                        */
16955 +                       mipv6_dad_send_ns(cell->ifp, &cell->ll_haddr);
16956 +                       if (ipv6_addr_cmp(&cell->ll_haddr, &cell->haddr))
16957 +                               mipv6_leave_sol_mc_addr(&cell->haddr, 
16958 +                                                       cell->ifp->idev->dev);
16959 +                       cell->callback_timer.expires = jiffies +
16960 +                           cell->ifp->idev->nd_parms->retrans_time;
16961 +                       add_timer(&cell->callback_timer);
16962 +               } else {
16963 +                       /*
16964 +                        * This means that an NA was received before the
16965 +                        * timeout and when the state changed from
16966 +                        * DAD_INIT_ENTRY, the BU got failed as a result.
16967 +                        * There is nothing to be done.
16968 +                        */
16969 +               }
16970 +       }
16971 +       return -1;
16972 +}
16973 +
16974 +/* ENTRY routine called via Timeout */
16975 +static void mipv6_dad_timeout(unsigned long arg)
16976 +{
16977 +       __u8 ba_status = SUCCESS;
16978 +       struct in6_addr daddr;
16979 +       struct in6_addr haddr;
16980 +       struct in6_addr coa;
16981 +       struct in6_addr rep_coa;
16982 +       struct inet6_ifaddr *ifp;
16983 +       int ifindex;
16984 +       __u32 ba_lifetime;
16985 +       __u16 sequence;
16986 +       __u8 flags;
16987 +       struct mipv6_dad_cell *cell = (struct mipv6_dad_cell *) arg;
16988 +
16989 +       /*
16990 +        * If entry is not in the list, we have already sent BU Failure
16991 +        * after getting a NA.
16992 +        */
16993 +       read_lock(&dad_lock);
16994 +       if (dad_search_cell(cell) < 0) {
16995 +               /*
16996 +                * 'cell' is no longer valid (may not be in the list or
16997 +                * is already processed, due to NA processing), or NS
16998 +                * retransmissions are not yet over.
16999 +                */
17000 +               read_unlock(&dad_lock);
17001 +               return;
17002 +       }
17003 +
17004 +       /* This is the final Timeout. Send Bind Ack Success */
17005 +
17006 +       ifp = cell->ifp;
17007 +       ifindex = cell->ifindex;
17008 +       ba_lifetime = cell->ba_lifetime;
17009 +       sequence = cell->sequence;
17010 +       flags = cell->bu_flags;
17011 +
17012 +       ipv6_addr_copy(&daddr, &cell->daddr);
17013 +       ipv6_addr_copy(&haddr, &cell->haddr);
17014 +       ipv6_addr_copy(&coa, &cell->coa);
17015 +       ipv6_addr_copy(&rep_coa, &cell->rep_coa);
17016 +       read_unlock(&dad_lock);
17017 +
17018 +       /* Send BU Acknowledgement Success */
17019 +       mipv6_bu_finish(ifp, ifindex, ba_status, 
17020 +                       &daddr, &haddr, &coa, &rep_coa,
17021 +                       ba_lifetime, sequence, flags, NULL);
17022 +       return;
17023 +}
17024 +
17025 +/*
17026 + * Check if original home address exists in our DAD pending list, if so return
17027 + * the cell.
17028 + *
17029 + * Assumes that the caller is holding the dad_lock in writer mode.
17030 + */
17031 +static struct mipv6_dad_cell *mipv6_dad_get_cell(struct in6_addr *haddr)
17032 +{
17033 +       struct mipv6_dad_cell *cell;
17034 +
17035 +       cell = dad_cell_head.next;
17036 +       while (cell != &dad_cell_head
17037 +              && ipv6_addr_cmp(&cell->haddr, haddr)) {
17038 +               cell = cell->next;
17039 +       }
17040 +       if (cell == &dad_cell_head) {
17041 +               /* Not found element */
17042 +               return NULL;
17043 +       }
17044 +       return cell;
17045 +}
17046 +
17047 +/*
17048 + * Save all parameters needed for doing a Bind Ack in the mipv6_dad_cell 
17049 + * structure.
17050 + */
17051 +static void mipv6_dad_save_cell(struct mipv6_dad_cell *cell,
17052 +                               struct inet6_ifaddr *ifp, int ifindex,
17053 +                               struct in6_addr *daddr,
17054 +                               struct in6_addr *haddr,
17055 +                               struct in6_addr *coa, 
17056 +                               struct in6_addr *rep_coa,
17057 +                               __u32 ba_lifetime,
17058 +                               __u16 sequence, __u8 flags)
17059 +{
17060 +       in6_ifa_hold(ifp);
17061 +       cell->ifp = ifp;
17062 +       cell->ifindex = ifindex;
17063 +
17064 +       ipv6_addr_copy(&cell->daddr, daddr);
17065 +       ipv6_addr_copy(&cell->haddr, haddr);
17066 +       ipv6_addr_copy(&cell->coa, coa);
17067 +       ipv6_addr_copy(&cell->rep_coa, rep_coa);
17068 +
17069 +       /* Convert cell->ll_haddr to Link Local address */
17070 +       if (flags & MIPV6_BU_F_LLADDR) 
17071 +               mipv6_generate_ll_addr(&cell->ll_haddr, haddr);
17072 +       else 
17073 +               ipv6_addr_copy(&cell->ll_haddr, haddr);
17074 +
17075 +       cell->ba_lifetime = ba_lifetime;
17076 +       cell->sequence = sequence;
17077 +       cell->bu_flags = flags;
17078 +}
17079 +
17080 +/*
17081 + * Top level DAD routine for performing DAD.
17082 + *
17083 + * Return values
17084 + *     0     : Don't need to do DAD.
17085 + *     1     : Need to do DAD.
17086 + *     -n    : Error, where 'n' is the reason for the error.
17087 + *
17088 + * Assumption : DAD process has been optimized by using cached values upto
17089 + * some time. However sometimes this can cause problems. Eg. when the first
17090 + * BU was received, DAD might have failed. Before the second BU arrived,
17091 + * the node using MN's home address might have stopped using it, but still
17092 + * we will return DAD_DUPLICATE_ADDRESS based on the first DAD's result. Or 
17093 + * this can go the other way around. However, it is a very small possibility
17094 + * and thus optimization is turned on by default. It is possible to change
17095 + * this feature (needs a little code-rewriting in this routine), but 
17096 + * currently DAD result is being cached for performance reasons.
17097 + */
17098 +int mipv6_dad_start(struct inet6_ifaddr *ifp, int ifindex,
17099 +                   struct in6_addr *daddr, struct in6_addr *haddr,
17100 +                   struct in6_addr *coa, struct in6_addr *rep_coa,
17101 +                   __u32 ba_lifetime, __u16 sequence, __u8 flags)
17102 +{
17103 +       int found;
17104 +       struct mipv6_dad_cell *cell;
17105 +       struct mipv6_bce bc_entry;
17106 +
17107 +       if (ifp->idev->cnf.dad_transmits == 0) {
17108 +               /* DAD is not configured on the HA, return SUCCESS */
17109 +               return 0;
17110 +       }
17111 +
17112 +       if (mipv6_bcache_get(haddr, daddr, &bc_entry) == 0) {
17113 +               /*
17114 +                * We already have an entry in our cache - don't need to 
17115 +                * do DAD as we are already defending this home address.
17116 +                */
17117 +               return 0;
17118 +       }
17119 +
17120 +       write_lock(&dad_lock);
17121 +       if ((cell = mipv6_dad_get_cell(haddr)) != NULL) {
17122 +               /*
17123 +                * An existing entry for BU was found in our cache due
17124 +                * to retransmission of the BU or a new COA registration.
17125 +                */
17126 +               switch (cell->flags) {
17127 +               case DAD_INIT_ENTRY:
17128 +                       /* Old entry is waiting for DAD to complete */
17129 +                       break;
17130 +               case DAD_UNIQUE_ADDRESS:
17131 +                       /* DAD is finished successfully - return success. */
17132 +                       write_unlock(&dad_lock);
17133 +                       return 0;
17134 +               case DAD_DUPLICATE_ADDRESS:
17135 +                       /*
17136 +                        * DAD is finished and we got a NA while doing BU -
17137 +                        * return failure.
17138 +                        */
17139 +                       write_unlock(&dad_lock);
17140 +                       return -DUPLICATE_ADDR_DETECT_FAIL;
17141 +               default:
17142 +                       /* Unknown state - should never happen */
17143 +                       DEBUG(DBG_WARNING,
17144 +                             "cell entry in unknown state : %d",
17145 +                             cell->flags);
17146 +                       write_unlock(&dad_lock);
17147 +                       return -REASON_UNSPECIFIED;
17148 +               }
17149 +               found = 1;
17150 +       } else {
17151 +               if ((cell = (struct mipv6_dad_cell *)
17152 +                    kmalloc(sizeof(struct mipv6_dad_cell), GFP_ATOMIC))
17153 +                   == NULL) {
17154 +                       return -INSUFFICIENT_RESOURCES;
17155 +               }
17156 +               found = 0;
17157 +       }
17158 +
17159 +       mipv6_dad_save_cell(cell, ifp, ifindex, daddr, haddr, coa, rep_coa,
17160 +                           ba_lifetime, sequence, flags);
17161 +
17162 +       if (!found) {
17163 +               cell->flags = DAD_INIT_ENTRY;
17164 +               cell->probes = ifp->idev->cnf.dad_transmits;
17165 +
17166 +               /* Insert element on dad_cell_head list */
17167 +               dad_cell_head.prev->next = cell;
17168 +               cell->next = &dad_cell_head;
17169 +               cell->prev = dad_cell_head.prev;
17170 +               dad_cell_head.prev = cell;
17171 +               write_unlock(&dad_lock);
17172 +               if (flags & MIPV6_BU_F_LLADDR) {
17173 +                       /* join the solicited node MC of the global homeaddr.*/
17174 +                       mipv6_join_sol_mc_addr(&cell->haddr, ifp->idev->dev);
17175 +                       /* Send a NS */
17176 +                       mipv6_dad_send_ns(ifp, &cell->haddr);
17177 +               }
17178 +               /* join the solicited node MC of the homeaddr. */
17179 +               mipv6_join_sol_mc_addr(&cell->ll_haddr, ifp->idev->dev);
17180 +               
17181 +               /* Send a NS */
17182 +               mipv6_dad_send_ns(ifp, &cell->ll_haddr);
17183 +               
17184 +               /* Initialize timer for this cell to timeout the NS. */
17185 +               init_timer(&cell->callback_timer);
17186 +               cell->callback_timer.data = (unsigned long) cell;
17187 +               cell->callback_timer.function = mipv6_dad_timeout;
17188 +               cell->callback_timer.expires = jiffies +
17189 +                   ifp->idev->nd_parms->retrans_time;
17190 +               add_timer(&cell->callback_timer);
17191 +       } else {
17192 +               write_unlock(&dad_lock);
17193 +       }
17194 +       return 1;
17195 +}
17196 +
17197 +void __init mipv6_dad_init(void)
17198 +{
17199 +       dad_cell_head.next = dad_cell_head.prev = &dad_cell_head;
17200 +       init_timer(&dad_cell_head.callback_timer);
17201 +       dad_cell_head.callback_timer.data = 0;
17202 +       dad_cell_head.callback_timer.function =
17203 +               mipv6_dad_delete_old_entries;
17204 +}
17205 +
17206 +void __exit mipv6_dad_exit(void)
17207 +{
17208 +       struct mipv6_dad_cell *curr, *next;
17209 +
17210 +       write_lock_bh(&dad_lock);
17211 +       del_timer(&dad_cell_head.callback_timer);
17212 +
17213 +       curr = dad_cell_head.next;
17214 +       while (curr != &dad_cell_head) {
17215 +               next = curr->next;
17216 +               del_timer(&curr->callback_timer);
17217 +               if (curr->flags == DAD_INIT_ENTRY) {
17218 +                       /*
17219 +                        * We were in DAD_INIT state and listening to the
17220 +                        * solicited node MC address - need to stop that.
17221 +                        */
17222 +                       mipv6_leave_sol_mc_addr(&curr->ll_haddr,
17223 +                                               curr->ifp->idev->dev);
17224 +                       if (ipv6_addr_cmp(&curr->ll_haddr, &curr->haddr))
17225 +                               mipv6_leave_sol_mc_addr(&curr->haddr, 
17226 +                                                       curr->ifp->idev->dev);
17227 +               }
17228 +               in6_ifa_put(curr->ifp);
17229 +               kfree(curr);
17230 +               curr = next;
17231 +       }
17232 +       dad_cell_head.next = dad_cell_head.prev = &dad_cell_head;
17233 +       write_unlock_bh(&dad_lock);
17234 +}
17235 --- /dev/null
17236 +++ linux-2.4.27/net/ipv6/mobile_ip6/prefix.c
17237 @@ -0,0 +1,217 @@
17238 +/**
17239 + * Prefix solicitation and advertisement
17240 + *
17241 + * Authors:
17242 + * Jaakko Laine <medved@iki.fi>
17243 + *
17244 + * $Id$
17245 + *
17246 + * This program is free software; you can redistribute it and/or
17247 + * modify it under the terms of the GNU General Public License
17248 + * as published by the Free Software Foundation; either version
17249 + * 2 of the License, or (at your option) any later version.
17250 + */
17251 +
17252 +#include <linux/config.h>
17253 +#include <linux/icmpv6.h>
17254 +#include <linux/net.h>
17255 +#include <linux/spinlock.h>
17256 +#include <linux/timer.h>
17257 +#include <linux/netdevice.h>
17258 +#include <net/ipv6.h>
17259 +#include <net/addrconf.h>
17260 +#include <net/ip6_route.h>
17261 +#include <net/mipv6.h>
17262 +
17263 +#include "mipv6_icmp.h"
17264 +#include "debug.h"
17265 +#include "sortedlist.h"
17266 +#include "prefix.h"
17267 +#include "config.h"
17268 +
17269 +#define INFINITY 0xffffffff
17270 +
17271 +struct timer_list pfx_timer;
17272 +
17273 +struct list_head pfx_list;
17274 +rwlock_t pfx_list_lock = RW_LOCK_UNLOCKED;
17275 +
17276 +int compare_pfx_list_entry(const void *data1, const void *data2,
17277 +                          int datalen)
17278 +{
17279 +       struct pfx_list_entry *e1 = (struct pfx_list_entry *) data1;
17280 +       struct pfx_list_entry *e2 = (struct pfx_list_entry *) data2;
17281 +
17282 +       return ((ipv6_addr_cmp(&e1->daddr, &e2->daddr) == 0)
17283 +               && (e2->ifindex == -1 || e1->ifindex == e2->ifindex));
17284 +}
17285 +
17286 +/**
17287 + * mipv6_pfx_cancel_send - cancel pending items to daddr from saddr
17288 + * @daddr: Destination address
17289 + * @ifindex: pending items on this interface will be canceled
17290 + *
17291 + * if ifindex == -1, all items to daddr will be removed
17292 + */
17293 +void mipv6_pfx_cancel_send(struct in6_addr *daddr, int ifindex)
17294 +{
17295 +       unsigned long tmp;
17296 +       struct pfx_list_entry entry;
17297 +
17298 +       DEBUG_FUNC();
17299 +
17300 +       /* We'll just be comparing these parts... */
17301 +       memcpy(&entry.daddr, daddr, sizeof(struct in6_addr));
17302 +       entry.ifindex = ifindex;
17303 +
17304 +       write_lock_bh(&pfx_list_lock);
17305 +
17306 +       while (mipv6_slist_del_item(&pfx_list, &entry,
17307 +                                   compare_pfx_list_entry) == 0)
17308 +               ;
17309 +
17310 +       if ((tmp = mipv6_slist_get_first_key(&pfx_list)))
17311 +               mod_timer(&pfx_timer, tmp);
17312 +
17313 +       write_unlock_bh(&pfx_list_lock);
17314 +}
17315 +
17316 +/**
17317 + * mipv6_pfx_add_ha - add a new HA to send prefix solicitations to
17318 + * @daddr: address of HA
17319 + * @saddr: our address to use as source address
17320 + * @ifindex: interface index
17321 + */
17322 +void mipv6_pfx_add_ha(struct in6_addr *daddr, struct in6_addr *saddr,
17323 +                     int ifindex)
17324 +{
17325 +       unsigned long tmp;
17326 +       struct pfx_list_entry entry;
17327 +
17328 +       DEBUG_FUNC();
17329 +
17330 +       memcpy(&entry.daddr, daddr, sizeof(struct in6_addr));
17331 +       memcpy(&entry.saddr, saddr, sizeof(struct in6_addr));
17332 +       entry.retries = 0;
17333 +       entry.ifindex = ifindex;
17334 +
17335 +       write_lock_bh(&pfx_list_lock);
17336 +       if (mipv6_slist_modify(&pfx_list, &entry, sizeof(struct pfx_list_entry),
17337 +                              jiffies + INITIAL_SOLICIT_TIMER * HZ,
17338 +                              compare_pfx_list_entry))
17339 +               DEBUG(DBG_WARNING, "Cannot add new HA to pfx list");
17340 +
17341 +       if ((tmp = mipv6_slist_get_first_key(&pfx_list)))
17342 +               mod_timer(&pfx_timer, tmp);
17343 +       write_unlock_bh(&pfx_list_lock);
17344 +}
17345 +
17346 +int mipv6_pfx_add_home(int ifindex, struct in6_addr *saddr, 
17347 +                      struct in6_addr *daddr, unsigned long min_expire)
17348 +{
17349 +       unsigned long tmp;
17350 +
17351 +       write_lock(&pfx_list_lock);
17352 +
17353 +       if (min_expire != INFINITY) {
17354 +               unsigned long expire;
17355 +               struct pfx_list_entry entry;
17356 +               
17357 +               memcpy(&entry.daddr, saddr, sizeof(struct in6_addr));
17358 +               memcpy(&entry.saddr, daddr, sizeof(struct in6_addr));
17359 +               entry.retries = 0;
17360 +               entry.ifindex = ifindex;
17361 +
17362 +               /* This is against the RFC 3775, but we need to set
17363 +                * a minimum interval for a prefix solicitation.
17364 +                * Otherwise a prefix solicitation storm will
17365 +                * result if valid lifetime of the prefix is
17366 +                * smaller than MAX_PFX_ADV_DELAY
17367 +                */
17368 +               min_expire -= MAX_PFX_ADV_DELAY;
17369 +               min_expire = min_expire < MIN_PFX_SOL_DELAY ? MIN_PFX_SOL_DELAY : min_expire;
17370 +
17371 +               expire = jiffies + min_expire * HZ;
17372 +
17373 +               if (mipv6_slist_modify(&pfx_list, &entry,
17374 +                                      sizeof(struct pfx_list_entry),
17375 +                                      expire,
17376 +                                      compare_pfx_list_entry) != 0)
17377 +                       DEBUG(DBG_WARNING, "Cannot add new entry to pfx_list");
17378 +       }
17379 +
17380 +       if ((tmp = mipv6_slist_get_first_key(&pfx_list)))
17381 +               mod_timer(&pfx_timer, tmp);
17382 +
17383 +       write_unlock(&pfx_list_lock);
17384 +
17385 +       return 0;
17386 +}
17387 +
17388 +/**
17389 + * set_ha_pfx_list - manipulate pfx_list for HA when timer goes off
17390 + * @entry: pfx_list_entry that is due
17391 + */
17392 +static void set_ha_pfx_list(struct pfx_list_entry *entry)
17393 +{
17394 +}
17395 +
17396 +/**
17397 + * set_mn_pfx_list - manipulate pfx_list for MN when timer goes off
17398 + * @entry: pfx_list_entry that is due
17399 + */
17400 +static void set_mn_pfx_list(struct pfx_list_entry *entry)
17401 +{
17402 +}
17403 +
17404 +/**
17405 + * pfx_timer_handler - general timer handler
17406 + * @dummy: dummy
17407 + *
17408 + * calls set_ha_pfx_list and set_mn_pfx_list to do the thing when
17409 + * a timer goes off
17410 + */
17411 +static void pfx_timer_handler(unsigned long dummy)
17412 +{
17413 +       unsigned long tmp;
17414 +       struct pfx_list_entry *entry;
17415 +
17416 +       DEBUG_FUNC();
17417 +
17418 +       write_lock(&pfx_list_lock);
17419 +       if (!(entry = mipv6_slist_get_first(&pfx_list)))
17420 +               goto out;
17421 +
17422 +       if (mip6node_cnf.capabilities & CAP_HA)
17423 +               set_ha_pfx_list(entry);
17424 +       if (mip6node_cnf.capabilities & CAP_MN)
17425 +               set_mn_pfx_list(entry);
17426 +       if ((tmp = mipv6_slist_get_first_key(&pfx_list)))
17427 +               mod_timer(&pfx_timer, tmp);
17428 +
17429 + out:
17430 +       write_unlock(&pfx_list_lock);
17431 +}
17432 +
17433 +int mipv6_initialize_pfx_icmpv6(void)
17434 +{
17435 +       INIT_LIST_HEAD(&pfx_list);
17436 +
17437 +       init_timer(&pfx_timer);
17438 +       pfx_timer.function = pfx_timer_handler;
17439 +
17440 +       return 0;
17441 +}
17442 +
17443 +void mipv6_shutdown_pfx_icmpv6(void)
17444 +{
17445 +       struct prefix_info *tmp;
17446 +
17447 +       if (timer_pending(&pfx_timer))
17448 +               del_timer(&pfx_timer);
17449 +
17450 +       write_lock_bh(&pfx_list_lock);
17451 +       while ((tmp = mipv6_slist_del_first(&pfx_list)))
17452 +               kfree(tmp);
17453 +       write_unlock_bh(&pfx_list_lock);
17454 +}
17455 --- /dev/null
17456 +++ linux-2.4.27/net/ipv6/mobile_ip6/prefix.h
17457 @@ -0,0 +1,57 @@
17458 +/*
17459 + *      MIPL Mobile IPv6 Prefix solicitation and advertisement
17460 + *
17461 + *      $Id$
17462 + *
17463 + *      This program is free software; you can redistribute it and/or
17464 + *      modify it under the terms of the GNU General Public License
17465 + *      as published by the Free Software Foundation; either version
17466 + *      2 of the License, or (at your option) any later version.
17467 + */
17468 +
17469 +#ifndef _PREFIX_H
17470 +#define _PREFIX_H
17471 +
17472 +#include <net/addrconf.h>
17473 +
17474 +struct pfx_list_entry {
17475 +       struct in6_addr daddr;
17476 +       struct in6_addr saddr;
17477 +       int retries;
17478 +       int ifindex;
17479 +};
17480 +
17481 +extern struct list_head pfx_list;
17482 +extern rwlock_t pfx_list_lock;
17483 +extern struct timer_list pfx_timer;
17484 +
17485 +int compare_pfx_list_entry(const void *data1, const void *data2,
17486 +                          int datalen);
17487 +
17488 +/**
17489 + * mipv6_pfx_cancel_send - cancel pending pfx_advs/sols to daddr
17490 + * @daddr: destination address
17491 + * @ifindex: pending items on this interface will be canceled
17492 + *
17493 + * if ifindex == -1, all items to daddr will be removed
17494 + */
17495 +void mipv6_pfx_cancel_send(struct in6_addr *daddr, int ifindex);
17496 +
17497 +/**
17498 + * mipv6_pfx_add_ha - add a new HA to send prefix solicitations to
17499 + * @daddr: address of HA
17500 + * @saddr: our address to use as source address
17501 + * @ifindex: interface index
17502 + */
17503 +void mipv6_pfx_add_ha(struct in6_addr *daddr, struct in6_addr *saddr,
17504 +                     int ifindex);
17505 +
17506 +void mipv6_pfxs_modified(struct prefix_info *pinfo, int ifindex);
17507 +
17508 +int mipv6_pfx_add_home(int ifindex, struct in6_addr *daddr,
17509 +                      struct in6_addr *saddr, unsigned long min_expire);
17510 +
17511 +int mipv6_initialize_pfx_icmpv6(void);
17512 +void mipv6_shutdown_pfx_icmpv6(void);
17513 +
17514 +#endif
17515 --- /dev/null
17516 +++ linux-2.4.27/net/ipv6/mobile_ip6/prefix_ha.c
17517 @@ -0,0 +1,122 @@
17518 +/**
17519 + * Prefix advertisement for Home Agent
17520 + *
17521 + * Authors:
17522 + * Jaakko Laine <medved@iki.fi>
17523 + *
17524 + * $Id$
17525 + *
17526 + * This program is free software; you can redistribute it and/or
17527 + * modify it under the terms of the GNU General Public License
17528 + * as published by the Free Software Foundation; either version
17529 + * 2 of the License, or (at your option) any later version.
17530 + */
17531 +
17532 +#include <linux/config.h>
17533 +#include <linux/icmpv6.h>
17534 +#include <linux/net.h>
17535 +#include <linux/spinlock.h>
17536 +#include <linux/timer.h>
17537 +#include <linux/netdevice.h>
17538 +#include <net/ipv6.h>
17539 +#include <net/addrconf.h>
17540 +#include <net/ip6_route.h>
17541 +#include <net/mipv6.h>
17542 +
17543 +#include "mipv6_icmp.h"
17544 +#include "debug.h"
17545 +#include "sortedlist.h"
17546 +#include "util.h"
17547 +#include "bcache.h"
17548 +#include "config.h"
17549 +#include "prefix.h"
17550 +
17551 +/**
17552 + * pfx_adv_iterator - modify pfx_list entries according to new prefix info
17553 + * @data: MN's home registration bcache_entry
17554 + * @args: new prefix info
17555 + * @sortkey: ignored
17556 + */
17557 +static int pfx_adv_iterator(void *data, void *args, unsigned long sortkey)
17558 +{
17559 +       struct mipv6_bce *bc_entry = (struct mipv6_bce *) data;
17560 +       struct prefix_info *pinfo = (struct prefix_info *) args;
17561 +
17562 +       if (mipv6_prefix_compare(&bc_entry->coa, &pinfo->prefix,
17563 +                                pinfo->prefix_len) == 0) {
17564 +               struct pfx_list_entry pfx_entry;
17565 +
17566 +               memcpy(&pfx_entry.daddr, &bc_entry->coa,
17567 +                      sizeof(struct in6_addr));
17568 +               memcpy(&pfx_entry.daddr, &bc_entry->our_addr,
17569 +                      sizeof(struct in6_addr));
17570 +               pfx_entry.retries = 0;
17571 +               pfx_entry.ifindex = bc_entry->ifindex;
17572 +
17573 +               mipv6_slist_modify(&pfx_list, &pfx_entry,
17574 +                                  sizeof(struct pfx_list_entry),
17575 +                                  jiffies +
17576 +                                  net_random() % (MAX_PFX_ADV_DELAY * HZ),
17577 +                                  compare_pfx_list_entry);
17578 +       }
17579 +
17580 +       return 0;
17581 +}
17582 +
17583 +struct homereg_iterator_args {
17584 +       struct list_head *head;
17585 +       int count;
17586 +};
17587 +
17588 +static int homereg_iterator(void *data, void *args, unsigned long *sortkey)
17589 +{
17590 +       struct mipv6_bce *entry = (struct mipv6_bce *) data;
17591 +       struct homereg_iterator_args *state =
17592 +               (struct homereg_iterator_args *) args;
17593 +
17594 +       if (entry->type == HOME_REGISTRATION) {
17595 +               mipv6_slist_add(state->head, entry,
17596 +                               sizeof(struct mipv6_bce),
17597 +                               state->count);
17598 +               state->count++;
17599 +       }
17600 +       return 0;
17601 +}
17602 +
17603 +static int mipv6_bcache_get_homeregs(struct list_head *head)
17604 +{
17605 +       struct homereg_iterator_args args;
17606 +
17607 +       DEBUG_FUNC();
17608 +
17609 +       args.count = 0;
17610 +       args.head = head;
17611 +
17612 +       mipv6_bcache_iterate(homereg_iterator, &args);
17613 +       return args.count;
17614 +}
17615 +
17616 +/**
17617 + * mipv6_prefix_added - prefix was added to interface, act accordingly
17618 + * @pinfo: prefix_info that was added
17619 + * @ifindex: interface index
17620 + */
17621 +void mipv6_pfxs_modified(struct prefix_info *pinfo, int ifindex)
17622 +{
17623 +       int count;
17624 +       unsigned long tmp;
17625 +       struct list_head home_regs;
17626 +
17627 +       DEBUG_FUNC();
17628 +
17629 +       INIT_LIST_HEAD(&home_regs);
17630 +
17631 +       if (!(count = mipv6_bcache_get_homeregs(&home_regs)))
17632 +               return;
17633 +
17634 +       write_lock_bh(&pfx_list_lock);
17635 +       mipv6_slist_for_each(&home_regs, pinfo, pfx_adv_iterator);
17636 +       if ((tmp = mipv6_slist_get_first_key(&pfx_list)))
17637 +               mod_timer(&pfx_timer, tmp);
17638 +       write_unlock_bh(&pfx_list_lock);
17639 +}
17640 --- /dev/null
17641 +++ linux-2.4.27/net/ipv6/mobile_ip6/rr_crypto.c
17642 @@ -0,0 +1,255 @@
17643 +/*
17644 + *      rr_cookie.c - Mobile IPv6 return routability crypto  
17645 + *      Author :  Henrik Petander <henrik.petander@hut.fi>
17646 + * 
17647 + *      $Id$
17648 + *
17649 + *      This program is free software; you can redistribute it and/or
17650 + *      modify it under the terms of the GNU General Public License
17651 + *      as published by the Free Software Foundation; either version
17652 + *      2 of the License, or (at your option) any later version.
17653 + *
17654 + *
17655 + *
17656 + */
17657 +
17658 +#include <linux/kernel.h>
17659 +#include <linux/types.h>
17660 +#include <linux/spinlock.h>
17661 +#include <linux/sched.h>
17662 +#include <linux/timer.h>
17663 +#include <linux/in6.h>
17664 +#include <linux/init.h>
17665 +#include <linux/random.h>
17666 +
17667 +#include <net/ipv6.h>
17668 +
17669 +#include "debug.h"
17670 +#include "hmac.h"
17671 +#include "rr_crypto.h"
17672 +
17673 +#define DBG_RR 5
17674 +
17675 +u8 k_CN[HMAC_SHA1_KEY_SIZE]; // secret key of CN 
17676 +
17677 +u16 curr_index = 0;
17678 +
17679 +struct nonce_timestamp nonce_table[MAX_NONCES];
17680 +spinlock_t nonce_lock = SPIN_LOCK_UNLOCKED;
17681 +void update_nonces(void);
17682 +
17683 +/** nonce_is_fresh - whether the nonce was generated recently
17684 + *  
17685 + * @non_ts : table entry containing the nonce and a timestamp
17686 + * @interval : if nonce was generated within interval seconds it is fresh
17687 + *
17688 + * Returns 1 if the nonce is fresh, 0 otherwise.
17689 + */
17690 +static int nonce_is_fresh(struct nonce_timestamp *non_ts, unsigned long interval)
17691 +{
17692 +       if (time_before(jiffies, non_ts->timestamp + interval * HZ) && !non_ts->invalid)
17693 +               return 1;
17694 +       return 0;
17695 +}
17696 +void mipv6_rr_invalidate_nonce(u16 nonce_ind)
17697 +{
17698 +       spin_lock_bh(&nonce_lock);
17699 +       if (nonce_ind > MAX_NONCES) {
17700 +               spin_unlock_bh(&nonce_lock);
17701 +               return;
17702 +       }
17703 +       nonce_table[nonce_ind].invalid = 1;
17704 +       spin_unlock_bh(&nonce_lock);
17705 +}
17706 +/* Returns a pointer to a new nonce  */
17707 +struct mipv6_rr_nonce * mipv6_rr_get_new_nonce(void)
17708 +{
17709 +       struct mipv6_rr_nonce *nce = kmalloc(sizeof(*nce), GFP_ATOMIC);
17710 +
17711 +       if (!nce)
17712 +               return NULL;
17713 +       // Lock nonces here
17714 +       spin_lock_bh(&nonce_lock);
17715 +       // If nonce is not fresh create new one 
17716 +       if (!nonce_is_fresh(&nonce_table[curr_index], MIPV6_RR_NONCE_LIFETIME)) {
17717 +               // increment the last nonce pointer and create new nonce
17718 +               curr_index++;
17719 +               // Wrap around
17720 +               if (curr_index == MAX_NONCES)
17721 +                       curr_index = 0;
17722 +               // Get random data to fill the nonce data
17723 +               get_random_bytes(nonce_table[curr_index].nonce.data, MIPV6_RR_NONCE_DATA_LENGTH);
17724 +               // Fill the index field
17725 +               nonce_table[curr_index].nonce.index = curr_index;
17726 +               nonce_table[curr_index].invalid = 0;
17727 +               nonce_table[curr_index].timestamp = jiffies;
17728 +       }
17729 +       spin_unlock_bh(&nonce_lock);
17730 +       memcpy(nce, &nonce_table[curr_index].nonce, sizeof(*nce));
17731 +       // Unlock nonces
17732 +       return nce;
17733 +}
17734 +/** mipv6_rr_nonce_get_by_index - returns a nonce for index 
17735 + * @nonce_ind : index of the nonce
17736 + *
17737 + * Returns a nonce or NULL if the nonce index was invalid or the nonce 
17738 + * for the index was not fresh.
17739 + */
17740 +struct mipv6_rr_nonce * mipv6_rr_nonce_get_by_index(u16 nonce_ind)
17741 +{
17742 +       struct mipv6_rr_nonce *nce = NULL;
17743 +       
17744 +       spin_lock_bh(&nonce_lock);
17745 +       if (nonce_ind >= MAX_NONCES) {
17746 +               DEBUG(DBG_WARNING, "Nonce index field from BU invalid");
17747 +
17748 +               /* Here a double of the nonce_lifetime is used for freshness 
17749 +                * verification, since the nonces 
17750 +                * are not created in response to every initiator packet
17751 +                */
17752 +       } else if (nonce_is_fresh(&nonce_table[nonce_ind], 2 * MIPV6_RR_NONCE_LIFETIME)) {
17753 +               nce = kmalloc(sizeof(*nce), GFP_ATOMIC);
17754 +               memcpy(nce, &nonce_table[nonce_ind].nonce, sizeof(*nce));
17755 +       }
17756 +       spin_unlock_bh(&nonce_lock);
17757 +
17758 +       return nce;
17759 +}
17760 +
17761 +/* Fills rr test init cookies with random bytes */  
17762 +void mipv6_rr_mn_cookie_create(u8 *cookie)
17763 +{
17764 +       get_random_bytes(cookie, MIPV6_RR_COOKIE_LENGTH);
17765 +}
17766 +
17767 +/** mipv6_rr_cookie_create - builds a home or care-of cookie
17768 + * 
17769 + * @addr : the home or care-of address from HoTI or CoTI
17770 + * @ckie : memory where the cookie is copied to
17771 + * @nce : pointer to a nonce used for the calculation, nce is freed during the function
17772 + *
17773 + */
17774 +int mipv6_rr_cookie_create(struct in6_addr *addr, u8 **ckie,
17775 +               u16 nonce_index)
17776 +{
17777 +       struct ah_processing ah_proc;
17778 +       u8 digest[HMAC_SHA1_HASH_LEN];
17779 +       struct mipv6_rr_nonce *nce;
17780 +
17781 +       if ((nce = mipv6_rr_nonce_get_by_index(nonce_index))== NULL)
17782 +               return -1;
17783 +
17784 +       if (*ckie == NULL && (*ckie = kmalloc(MIPV6_RR_COOKIE_LENGTH,
17785 +                                       GFP_ATOMIC)) == NULL) {
17786 +               kfree(nce);
17787 +               return -1;
17788 +       }
17789 +       /* Calculate the full hmac-sha1 digest from address and nonce using the secret key of cn */
17790 +       
17791 +       if (ah_hmac_sha1_init(&ah_proc, k_CN, HMAC_SHA1_KEY_SIZE) < 0) {
17792 +               DEBUG(DBG_ERROR, "Hmac sha1 initialization failed");
17793 +               kfree(nce);
17794 +               return -1;
17795 +       }
17796 +
17797 +       ah_hmac_sha1_loop(&ah_proc, addr, sizeof(*addr));
17798 +       ah_hmac_sha1_loop(&ah_proc, nce->data,  MIPV6_RR_NONCE_DATA_LENGTH);
17799 +       ah_hmac_sha1_result(&ah_proc, digest);
17800 +
17801 +       
17802 +       /* clean up nonce */
17803 +       kfree(nce);
17804 +
17805 +       /* Copy first 64 bits of hash target to the cookie */ 
17806 +       memcpy(*ckie, digest, MIPV6_RR_COOKIE_LENGTH);
17807 +       return 0;
17808 +}
17809 +
17810 +/** mipv6_rr_key_calc - creates BU authentication key
17811 + * 
17812 + * @hoc : Home Cookie 
17813 + * @coc : Care-of Cookie 
17814 + * 
17815 + * Returns BU authentication key of length HMAC_SHA1_KEY_SIZE  or NULL in error cases, 
17816 + * caller needs to free the key.
17817 + */
17818 +u8 *mipv6_rr_key_calc(u8 *hoc, u8 *coc)
17819 +{
17820 +       
17821 +       u8 *key_bu = kmalloc(HMAC_SHA1_KEY_SIZE, GFP_ATOMIC);
17822 +       SHA1_CTX c;
17823 +
17824 +       if (!key_bu) {
17825 +               DEBUG(DBG_CRITICAL, "Memory allocation failed, could nort create BU authentication key");
17826 +               return NULL;
17827 +       }
17828 +
17829 +       /* Calculate the key from home and care-of cookies 
17830 +        * Kbu = sha1(home_cookie | care-of cookie) 
17831 +        * or KBu = sha1(home_cookie), if MN deregisters
17832 +        */
17833 +       sha1_init(&c);
17834 +       sha1_compute(&c, hoc, MIPV6_RR_COOKIE_LENGTH);
17835 +       if (coc)
17836 +               sha1_compute(&c, coc, MIPV6_RR_COOKIE_LENGTH);
17837 +       sha1_final(&c, key_bu);
17838 +       DEBUG(DBG_RR, "Home and Care-of cookies used for calculating key ");
17839 +       debug_print_buffer(DBG_RR, hoc,  MIPV6_RR_COOKIE_LENGTH);
17840 +       if (coc)        
17841 +               debug_print_buffer(DBG_RR, coc,  MIPV6_RR_COOKIE_LENGTH);
17842 +
17843 +       return key_bu;
17844 +}
17845 +
17846 +void mipv6_rr_init(void)
17847 +{
17848 +       get_random_bytes(k_CN, HMAC_SHA1_KEY_SIZE);
17849 +       memset(nonce_table, 0, MAX_NONCES * sizeof(struct nonce_timestamp));
17850 +}
17851 +
17852 +#ifdef TEST_MIPV6_RR_CRYPTO
17853 +void mipv6_test_rr(void)
17854 +{
17855 +       struct mipv6_rr_nonce *nonce;
17856 +       struct in6_addr a1, a2;
17857 +       int ind1, ind2;
17858 +       u8 *ckie1 = NULL, *ckie2 = NULL;
17859 +       u8 *key_mn = NULL, *key_cn = NULL;
17860 +       mipv6_init_rr();
17861 +
17862 +       nonce = mipv6_rr_get_new_nonce();
17863 +       if (!nonce) {
17864 +               printk("mipv6_rr_get_new_nonce() failed, at 1! \n");
17865 +               return;
17866 +       }
17867 +       mipv6_rr_cookie_create(&a1, &ckie1, nonce->index);
17868 +       ind1 = nonce->index;
17869 +       kfree(nonce);
17870 +
17871 +       nonce = mipv6_rr_get_new_nonce();
17872 +       if (!nonce) {
17873 +               printk("mipv6_rr_get_new_nonce() failed, at 2! \n");
17874 +               return;
17875 +       }
17876 +
17877 +       mipv6_rr_cookie_create(&a2, &ckie2, nonce->index); 
17878 +       ind2 = nonce->index;
17879 +       key_mn =  mipv6_rr_key_calc(ckie1, ckie2);
17880 +
17881 +       /* Create home and coa cookies based on indices */
17882 +       mipv6_rr_cookie_create(&a1, &ckie1, ind1);
17883 +       mipv6_rr_cookie_create(&a2, &ckie2, ind2);
17884 +       key_cn =  mipv6_rr_key_calc(ckie1, ckie2);             
17885 +       if (!key_cn || !key_mn) {
17886 +               printk("creation of secret key failed!\n");
17887 +               return;
17888 +       }
17889 +       if(memcmp(key_cn, key_mn, HMAC_SHA1_KEY_SIZE))
17890 +               printk("mipv6_rr_key_calc produced different keys for MN and CN \n");
17891 +       else
17892 +               printk("mipv6_rr_crypto test OK\n");
17893 +       kfree(nonce);
17894 +       kfree(key_cn);
17895 +       kfree(key_mn);
17896 +}
17897 +#endif
17898 --- /dev/null
17899 +++ linux-2.4.27/net/ipv6/mobile_ip6/rr_crypto.h
17900 @@ -0,0 +1,72 @@
17901 +/*
17902 + *      MIPL Mobile IPv6 Return routability crypto prototypes
17903 + *
17904 + *      $Id:$
17905 + *
17906 + *      This program is free software; you can redistribute it and/or
17907 + *      modify it under the terms of the GNU General Public License
17908 + *      as published by the Free Software Foundation; either version
17909 + *      2 of the License, or (at your option) any later version.
17910 + */
17911 +
17912 +#ifndef _RR_CRYPTO
17913 +#define _RR_CRYPTO
17914 +
17915 +#include <linux/in6.h>
17916 +
17917 +/* Macros and data structures */
17918 +
17919 +#define MIPV6_RR_NONCE_LIFETIME 60 
17920 +#define MIPV6_RR_NONCE_DATA_LENGTH 8
17921 +#define MIPV6_RR_COOKIE_LENGTH 8
17922 +#define COOKIE_SIZE 8
17923 +#define MAX_NONCES 4
17924 +#define HMAC_SHA1_KEY_SIZE 20
17925
17926 +struct mipv6_rr_nonce {
17927 +       u_int16_t index;
17928 +       u_int8_t data[MIPV6_RR_NONCE_DATA_LENGTH];
17929 +};
17930 +
17931 +struct nonce_timestamp {
17932 +       struct  mipv6_rr_nonce nonce;
17933 +       unsigned long timestamp;
17934 +       u_int8_t invalid; 
17935 +};
17936 +
17937 +/* Function definitions */
17938 +
17939 +/* Return 1 if equal, 0 if not */
17940 +static __inline__ int mipv6_equal_cookies(u8 *c1, u8 *c2)
17941 +{
17942 +       return (memcmp(c1, c2, MIPV6_RR_COOKIE_LENGTH) == 0);
17943 +}
17944 +
17945 +/* Function declarations */
17946 +
17947 +/* Create cookie for HoTi and CoTi */
17948 +extern void mipv6_rr_mn_cookie_create(u8 *cookie);
17949 +
17950 +/* Create cookie for HoT and CoT */
17951 +extern int mipv6_rr_cookie_create(struct in6_addr *addr, u8 **ckie, u16 nonce_index);
17952 +
17953 +/* Calculate return routability key from home and care-of cookies, key length is 
17954 + *  HMAC_SHA1_KEY_SIZE  
17955 + */
17956 +extern u_int8_t *mipv6_rr_key_calc(u8 *hoc, u8 *coc);
17957 +
17958 +extern struct mipv6_rr_nonce *mipv6_rr_get_new_nonce(void);
17959 +
17960 +/* For avoiding replay attacks when MN deregisters */
17961 +extern void mipv6_rr_invalidate_nonce(u16 nonce_index);
17962 +/*
17963 + * initializes the return routability crypto
17964 + */
17965 +
17966 +void mipv6_rr_init(void);
17967 +
17968 +#ifdef TEST_MIPV6_RR_CRYPTO
17969 +void mipv6_test_rr(void);
17970 +#endif /* TEST_MIPV6_RR_CRYPTO */
17971 +
17972 +#endif /* RR_CRYPTO */
17973 --- /dev/null
17974 +++ linux-2.4.27/net/ipv6/mobile_ip6/sortedlist.c
17975 @@ -0,0 +1,349 @@
17976 +/**
17977 + * Sorted list - linked list with sortkey.
17978 + *
17979 + * Authors:
17980 + * Jaakko Laine <medved@iki.fi>
17981 + *
17982 + * $Id$
17983 + *
17984 + * This program is free software; you can redistribute it and/or
17985 + * modify it under the terms of the GNU General Public License
17986 + * as published by the Free Software Foundation; either version
17987 + * 2 of the License, or (at your option) any later version.
17988 + */
17989 +
17990 +#include <linux/kernel.h>
17991 +#include <linux/types.h>
17992 +#include <linux/list.h>
17993 +#include <linux/slab.h>
17994 +#include <linux/spinlock.h>
17995 +#include <linux/string.h>
17996 +
17997 +struct mipv6_sorted_list_entry {
17998 +       struct list_head list;
17999 +       void *data;
18000 +       int datalen;
18001 +       unsigned long sortkey;
18002 +};
18003 +
18004 +/**
18005 + * compare - compares two arbitrary data items
18006 + * @data1: first data item
18007 + * @data2: second data item
18008 + * @datalen: length of data items in bits
18009 + *
18010 + * datalen is in bits!
18011 + */
18012 +int mipv6_bitwise_compare(const void *data1, const void *data2, int datalen)
18013 +{
18014 +       int n = datalen;
18015 +       __u8 * ptr1 = (__u8 *)data1;
18016 +       __u8 * ptr2 = (__u8 *)data2;
18017 +       
18018 +       for (; n>=0; n-=8, ptr1++, ptr2++) {
18019 +               if (n >= 8) {
18020 +                       if (*ptr1 != *ptr2)
18021 +                               return 0;
18022 +               } else {
18023 +                       if ((*ptr1 ^ *ptr2) & ((~0) << (8 - n)))
18024 +                               return 0;
18025 +               }
18026 +       }
18027 +
18028 +       return 1;
18029 +}
18030 +
18031 +/**
18032 + * mipv6_slist_add - add an entry to sorted list
18033 + * @head: list_head of the sorted list
18034 + * @data: item to store
18035 + * @datalen: length of data (in bytes)
18036 + * @key: sortkey of item
18037 + *
18038 + * Allocates memory for entry and data
18039 + */
18040 +int mipv6_slist_add(struct list_head *head, void *data, int datalen,
18041 +                   unsigned long sortkey)
18042 +{
18043 +       struct list_head *pos;
18044 +       struct mipv6_sorted_list_entry *entry, *tmp, *next;
18045 +
18046 +       entry = kmalloc(sizeof(struct mipv6_sorted_list_entry), GFP_ATOMIC);
18047 +
18048 +       if (!entry)
18049 +               return -1;
18050 +
18051 +       entry->data = kmalloc(datalen, GFP_ATOMIC);
18052 +
18053 +       if (!entry->data) {
18054 +               kfree(entry);
18055 +               return -1;
18056 +       }
18057 +
18058 +       memcpy(entry->data, data, datalen);
18059 +       entry->datalen = datalen;
18060 +       entry->sortkey = sortkey;
18061 +
18062 +       if ((pos = head->next) == head) {
18063 +               list_add(&entry->list, head);
18064 +               return 0;
18065 +       }
18066 +
18067 +       tmp = list_entry(pos, struct mipv6_sorted_list_entry, list);
18068 +       if (entry->sortkey < tmp->sortkey) {
18069 +               list_add(&entry->list, head);
18070 +               return 0;
18071 +       }
18072 +
18073 +       for (; pos != head; pos = pos->next) {
18074 +               tmp = list_entry(pos, struct mipv6_sorted_list_entry, list);
18075 +               if (pos->next == head) {
18076 +                       list_add(&entry->list, &tmp->list);
18077 +                       return 0;
18078 +               }
18079 +               next = list_entry(pos->next, struct mipv6_sorted_list_entry, list);
18080 +               if (entry->sortkey >= tmp->sortkey && entry->sortkey < next->sortkey) {
18081 +                       list_add(&entry->list, &tmp->list);
18082 +                       return 0;
18083 +               }
18084 +       }
18085 +
18086 +       /* never reached */
18087 +       return -1;
18088 +}
18089 +
18090 +/**
18091 + * mipv6_slist_get_first - get the first data item in the list
18092 + * @head: list_head of the sorted list
18093 + *
18094 + * Returns the actual data item, not copy, so don't kfree it
18095 + */
18096 +void *mipv6_slist_get_first(struct list_head *head)
18097 +{
18098 +       struct mipv6_sorted_list_entry *entry;
18099 +
18100 +       if (list_empty(head))
18101 +               return NULL;
18102 +
18103 +       entry = list_entry(head->next, struct mipv6_sorted_list_entry, list);
18104 +       return entry->data;
18105 +}
18106 +
18107 +/**
18108 + * mipv6_slist_del_first - delete (and get) the first item in list
18109 + * @head: list_head of the sorted list
18110 + *
18111 + * Remember to kfree the item
18112 + */
18113 +void *mipv6_slist_del_first(struct list_head *head)
18114 +{
18115 +       void *tmp;
18116 +       struct mipv6_sorted_list_entry *entry;
18117 +
18118 +       if (list_empty(head))
18119 +               return NULL;
18120 +
18121 +       entry = list_entry(head->next, struct mipv6_sorted_list_entry, list);
18122 +       tmp = entry->data;
18123 +
18124 +       list_del(head->next);
18125 +       kfree(entry);
18126 +
18127 +       return tmp;
18128 +}
18129 +
18130 +/**
18131 + * mipv6_slist_del_item - delete entry
18132 + * @head: list_head of the sorted list
18133 + * @data: item to delete
18134 + * @compare: function used for comparing the data items
18135 + *
18136 + * compare function needs to have prototype
18137 + * int (*compare)(const void *data1, const void *data2, int datalen)
18138 + */
18139 +int mipv6_slist_del_item(struct list_head *head, void *data,
18140 +                        int (*compare)(const void *data1, const void *data2,
18141 +                                       int datalen))
18142 +{
18143 +       struct list_head *pos;
18144 +       struct mipv6_sorted_list_entry *entry;
18145 +
18146 +       for(pos = head->next; pos != head; pos = pos->next) {
18147 +               entry = list_entry(pos, struct mipv6_sorted_list_entry, list);
18148 +               if (compare(data, entry->data, entry->datalen)) {
18149 +                       list_del(pos);
18150 +                       kfree(entry->data);
18151 +                       kfree(entry);
18152 +                       return 0;
18153 +               }
18154 +       }
18155 +
18156 +       return -1;
18157 +}
18158 +
18159 +/**
18160 + * mipv6_slist_get_first_key - get sortkey of the first item
18161 + * @head: list_head of the sorted list
18162 + */
18163 +unsigned long mipv6_slist_get_first_key(struct list_head *head)
18164 +{
18165 +       struct mipv6_sorted_list_entry *entry;
18166 +
18167 +       if (list_empty(head))
18168 +               return 0;
18169 +
18170 +       entry = list_entry(head->next, struct mipv6_sorted_list_entry, list);
18171 +       return entry->sortkey;
18172 +}
18173 +
18174 +/**
18175 + * mipv6_slist_get_key - get sortkey of the data item
18176 + * @head: list_head of the sorted list
18177 + * @data: the item to search for
18178 + * @compare: function used for comparing the data items
18179 + *
18180 + * compare function needs to have prototype
18181 + * int (*compare)(const void *data1, const void *data2, int datalen)
18182 + */
18183 +unsigned long mipv6_slist_get_key(struct list_head *head, void *data,
18184 +                                 int (*compare)(const void *data1,
18185 +                                                const void *data2,
18186 +                                                int datalen))
18187 +{
18188 +       struct list_head *pos;
18189 +       struct mipv6_sorted_list_entry *entry;
18190 +       
18191 +       for(pos = head->next; pos != head; pos = pos->next) {
18192 +               entry = list_entry(pos, struct mipv6_sorted_list_entry, list);
18193 +               if (compare(data, entry->data, entry->datalen))
18194 +                       return entry->sortkey;
18195 +       }
18196 +       
18197 +       return 0;
18198 +}
18199 +
18200 +/**
18201 + * mipv6_slist_get_data - get the data item identified by sortkey
18202 + * @head: list_head of the sorted list
18203 + * @key: sortkey of the item
18204 + *
18205 + * Returns the actual data item, not copy, so don't kfree it
18206 + */
18207 +void *mipv6_slist_get_data(struct list_head *head, unsigned long sortkey)
18208 +{
18209 +       struct list_head *pos;
18210 +       struct mipv6_sorted_list_entry *entry;
18211 +
18212 +       list_for_each(pos, head) {
18213 +               entry = list_entry(pos, struct mipv6_sorted_list_entry, list);
18214 +               if (entry->sortkey == sortkey) 
18215 +                       return entry->data;
18216 +       }
18217 +
18218 +       return NULL;
18219 +}
18220 +
18221 +/**
18222 + * reorder_entry - move an entry to a new position according to sortkey
18223 + * @head: list_head of the sorted list
18224 + * @entry_pos: current place of the entry
18225 + * @key: new sortkey
18226 + */
18227 +static void reorder_entry(struct list_head *head, struct list_head *entry_pos,
18228 +                         unsigned long sortkey)
18229 +{
18230 +       struct list_head *pos;
18231 +       struct mipv6_sorted_list_entry *entry;
18232 +
18233 +       list_del(entry_pos);
18234 +
18235 +       for (pos = head->next; pos != head; pos = pos->next) {
18236 +               entry = list_entry(pos, struct mipv6_sorted_list_entry, list);
18237 +               if (sortkey >= entry->sortkey) {
18238 +                       list_add(entry_pos, &entry->list);
18239 +                       return;
18240 +               }
18241 +       }
18242 +
18243 +       list_add(entry_pos, head);
18244 +}
18245 +
18246 +/**
18247 + * mipv6_slist_modify - modify data item
18248 + * @head: list_head of the sorted list
18249 + * @data: item, whose sortkey is to be modified
18250 + * @datalen: datalen in bytes
18251 + * @new_key: new sortkey
18252 + * @compare: function used for comparing the data items
18253 + *
18254 + * Compies the new data on top of the old one, if compare function returns
18255 + * true. If there's no matching entry, new one will be created.
18256 + * Compare function needs to have prototype
18257 + * int (*compare)(const void *data1, const void *data2, int datalen)
18258 + */
18259 +int mipv6_slist_modify(struct list_head *head, void *data, int datalen,
18260 +                      unsigned long new_key,
18261 +                      int (*compare)(const void *data1, const void *data2,
18262 +                                     int datalen))
18263 +{
18264 +       struct list_head *pos;
18265 +       struct mipv6_sorted_list_entry *entry;
18266 +
18267 +       for (pos = head->next; pos != head; pos = pos->next) {
18268 +               entry = list_entry(pos, struct mipv6_sorted_list_entry, list);
18269 +               if (compare(data, entry->data, datalen)) {
18270 +                       memcpy(entry->data, data, datalen);
18271 +                       entry->sortkey = new_key;
18272 +                       reorder_entry(head, &entry->list, new_key);
18273 +                       return 0;
18274 +               }
18275 +       }
18276 +
18277 +       return mipv6_slist_add(head, data, datalen, new_key);
18278 +}
18279 +
18280 +/**
18281 + * mipv6_slist_push_first - move the first entry to place indicated by new_key
18282 + * @head: list_head of the sorted list
18283 + * @new_key: new sortkey
18284 + */
18285 +int mipv6_slist_push_first(struct list_head *head, unsigned long new_key)
18286 +{
18287 +       struct mipv6_sorted_list_entry *entry;
18288 +
18289 +       if (list_empty(head))
18290 +               return -1;
18291 +
18292 +       entry = list_entry(head->next, struct mipv6_sorted_list_entry, list);
18293 +       entry->sortkey = new_key;
18294 +
18295 +       reorder_entry(head, head->next, new_key);
18296 +       return 0;
18297 +}
18298 +
18299 +/**
18300 + * mipv6_slist_for_each - apply func to every item in list
18301 + * @head: list_head of the sorted list
18302 + * @args: args to pass to func
18303 + * @func: function to use
18304 + *
18305 + * function must be of type
18306 + * int (*func)(void *data, void *args, unsigned long sortkey)
18307 + * List iteration will stop once func has been applied to every item
18308 + * or when func returns true
18309 + */
18310 +int mipv6_slist_for_each(struct list_head *head, void *args,
18311 +                        int (*func)(void *data, void *args,
18312 +                                    unsigned long sortkey))
18313 +{
18314 +       struct list_head *pos;
18315 +       struct mipv6_sorted_list_entry *entry;
18316 +
18317 +       list_for_each(pos, head) {
18318 +               entry = list_entry(pos, struct mipv6_sorted_list_entry, list);
18319 +               if (func(entry->data, args, entry->sortkey))
18320 +                       break;
18321 +       }
18322 +
18323 +       return 0;
18324 +}
18325 --- /dev/null
18326 +++ linux-2.4.27/net/ipv6/mobile_ip6/sortedlist.h
18327 @@ -0,0 +1,133 @@
18328 +/*
18329 + *      Sorted list - linked list with sortkey
18330 + *
18331 + *      $Id$
18332 + *
18333 + *      This program is free software; you can redistribute it and/or
18334 + *      modify it under the terms of the GNU General Public License
18335 + *      as published by the Free Software Foundation; either version
18336 + *      2 of the License, or (at your option) any later version.
18337 + */
18338 +
18339 +/**
18340 + * compare - compares two arbitrary data items
18341 + * @data1: first data item
18342 + * @data2: second data item
18343 + * @datalen: length of data items in bits
18344 + *
18345 + * datalen is in bits!
18346 + */
18347 +int mipv6_bitwise_compare(const void *data1, const void *data2, int datalen);
18348 +
18349 +/**
18350 + * mipv6_slist_add - add an entry to sorted list
18351 + * @head: list_head of the sorted list
18352 + * @data: item to store
18353 + * @datalen: length of data (in bytes)
18354 + * @key: sortkey of item
18355 + *
18356 + * Allocates memory for entry and data
18357 + */
18358 +int mipv6_slist_add(struct list_head *head, void *data, int datalen,
18359 +                   unsigned long sortkey);
18360 +
18361 +/**
18362 + * mipv6_slist_get_first - get the first data item in the list
18363 + * @head: list_head of the sorted list
18364 + *
18365 + * Returns the actual data item, not copy, so don't kfree it
18366 + */
18367 +void *mipv6_slist_get_first(struct list_head *head);
18368 +
18369 +/**
18370 + * mipv6_slist_del_first - delete (and get) the first item in list
18371 + * @head: list_head of the sorted list
18372 + *
18373 + * Remember to kfree the item
18374 + */
18375 +void *mipv6_slist_del_first(struct list_head *head);
18376 +
18377 +/**
18378 + * mipv6_slist_del_item - delete entry
18379 + * @head: list_head of the sorted list
18380 + * @data: item to delete
18381 + * @compare: function used for comparing the data items
18382 + *
18383 + * compare function needs to have prototype
18384 + * int (*compare)(const void *data1, const void *data2, int datalen) where
18385 + * datalen is in bits
18386 + */
18387 +int mipv6_slist_del_item(struct list_head *head, void *data,
18388 +                        int (*compare)(const void *data1, const void *data2,
18389 +                                       int datalen));
18390 +
18391 +/**
18392 + * mipv6_slist_get_first_key - get sortkey of the first item
18393 + * @head: list_head of the sorted list
18394 + */
18395 +unsigned long mipv6_slist_get_first_key(struct list_head *head);
18396 +
18397 +/**
18398 + * mipv6_slist_get_key - get sortkey of the data item
18399 + * @head: list_head of the sorted list
18400 + * @data: the item to search for
18401 + * @compare: function used for comparing the data items
18402 + *
18403 + * compare function needs to have prototype
18404 + * int (*compare)(const void *data1, const void *data2, int datalen) where
18405 + * datalen is in bits
18406 + */
18407 +unsigned long mipv6_slist_get_key(struct list_head *head, void *data,
18408 +                                 int (*compare)(const void *data1,
18409 +                                                const void *data2,
18410 +                                                int datalen));
18411 +
18412 +/**
18413 + * mipv6_slist_get_data - get the data item identified by sortkey
18414 + * @head: list_head of the sorted list
18415 + * @key: sortkey of the item
18416 + *
18417 + * Returns the actual data item, not copy, so don't kfree it
18418 + */
18419 +void *mipv6_slist_get_data(struct list_head *head, unsigned long sortkey);
18420 +
18421 +/**
18422 + * mipv6_slist_modify - modify data item
18423 + * @head: list_head of the sorted list
18424 + * @data: item, whose sortkey is to be modified
18425 + * @datalen: datalen in bytes
18426 + * @new_key: new sortkey
18427 + * @compare: function used for comparing the data items
18428 + *
18429 + * Compies the new data on top of the old one, if compare function returns
18430 + * non-negative. If there's no matching entry, new one will be created.
18431 + * Compare function needs to have prototype
18432 + * int (*compare)(const void *data1, const void *data2, int datalen) where
18433 + * datalen is in bits.
18434 + */
18435 +int mipv6_slist_modify(struct list_head *head, void *data, int datalen,
18436 +                      unsigned long new_key,
18437 +                      int (*compare)(const void *data1, const void *data2,
18438 +                                     int datalen));
18439 +
18440 +/**
18441 + * mipv6_slist_push_first - move the first entry to place indicated by new_key
18442 + * @head: list_head of the sorted list
18443 + * @new_key: new sortkey
18444 + */
18445 +int mipv6_slist_push_first(struct list_head *head, unsigned long new_key);
18446 +
18447 +/**
18448 + * mipv6_slist_for_each - apply func to every item in list
18449 + * @head: list_head of the sorted list
18450 + * @args: args to pass to func
18451 + * @func: function to use
18452 + *
18453 + * function must be of type
18454 + * int (*func)(void *data, void *args, unsigned long sortkey)
18455 + * List iteration will stop once func has been applied to every item
18456 + * or when func returns true
18457 + */
18458 +int mipv6_slist_for_each(struct list_head *head, void *args,
18459 +                        int (*func)(void *data, void *args,
18460 +                                    unsigned long sortkey));
18461 --- /dev/null
18462 +++ linux-2.4.27/net/ipv6/mobile_ip6/stats.c
18463 @@ -0,0 +1,90 @@
18464 +/*
18465 + *      Statistics module
18466 + *
18467 + *      Authors:
18468 + *      Sami Kivisaari          <skivisaa@cc.hut.fi>
18469 + *
18470 + *      $Id$
18471 + *
18472 + *      This program is free software; you can redistribute it and/or
18473 + *      modify it under the terms of the GNU General Public License
18474 + *      as published by the Free Software Foundation; either version
18475 + *      2 of the License, or (at your option) any later version.
18476 + *     
18477 + *      Changes:
18478 + *      Krishna Kumar, 
18479 + *      Venkata Jagana   :  SMP locking fix  
18480 + */
18481 +
18482 +#include <linux/config.h>
18483 +#include <linux/proc_fs.h>
18484 +#include "stats.h"
18485 +
18486 +struct mipv6_statistics mipv6_stats;
18487 +
18488 +static int proc_info_dump(
18489 +       char *buffer, char **start,
18490 +       off_t offset, int length)
18491 +{
18492 +       struct inf {
18493 +               char *name;
18494 +               int *value;
18495 +       } int_stats[] = {
18496 +               {"NEncapsulations", &mipv6_stats.n_encapsulations},
18497 +               {"NDecapsulations", &mipv6_stats.n_decapsulations},
18498 +               {"NBindRefreshRqsRcvd", &mipv6_stats.n_brr_rcvd},
18499 +               {"NHomeTestInitsRcvd", &mipv6_stats.n_hoti_rcvd},
18500 +               {"NCareofTestInitsRcvd", &mipv6_stats.n_coti_rcvd},
18501 +               {"NHomeTestRcvd", &mipv6_stats.n_hot_rcvd},
18502 +               {"NCareofTestRcvd", &mipv6_stats.n_cot_rcvd},
18503 +               {"NBindUpdatesRcvd", &mipv6_stats.n_bu_rcvd},
18504 +               {"NBindAcksRcvd", &mipv6_stats.n_ba_rcvd},
18505 +               {"NBindNAcksRcvd", &mipv6_stats.n_ban_rcvd},
18506 +               {"NBindErrorsRcvd", &mipv6_stats.n_be_rcvd},
18507 +               {"NBindRefreshRqsSent", &mipv6_stats.n_brr_sent},
18508 +               {"NHomeTestInitsSent", &mipv6_stats.n_hoti_sent},
18509 +               {"NCareofTestInitsSent", &mipv6_stats.n_coti_sent},
18510 +               {"NHomeTestSent", &mipv6_stats.n_hot_sent},
18511 +               {"NCareofTestSent", &mipv6_stats.n_cot_sent},
18512 +               {"NBindUpdatesSent", &mipv6_stats.n_bu_sent},
18513 +               {"NBindAcksSent", &mipv6_stats.n_ba_sent},
18514 +               {"NBindNAcksSent", &mipv6_stats.n_ban_sent},
18515 +               {"NBindErrorsSent", &mipv6_stats.n_be_sent},
18516 +               {"NBindUpdatesDropAuth", &mipv6_stats.n_bu_drop.auth},
18517 +               {"NBindUpdatesDropInvalid", &mipv6_stats.n_bu_drop.invalid},
18518 +               {"NBindUpdatesDropMisc", &mipv6_stats.n_bu_drop.misc},
18519 +               {"NBindAcksDropAuth", &mipv6_stats.n_bu_drop.auth},
18520 +               {"NBindAcksDropInvalid", &mipv6_stats.n_bu_drop.invalid},
18521 +               {"NBindAcksDropMisc", &mipv6_stats.n_bu_drop.misc},
18522 +               {"NBindRqsDropAuth", &mipv6_stats.n_bu_drop.auth},
18523 +               {"NBindRqsDropInvalid", &mipv6_stats.n_bu_drop.invalid},
18524 +               {"NBindRqsDropMisc", &mipv6_stats.n_bu_drop.misc}
18525 +       };
18526 +
18527 +       int i;
18528 +       int len = 0;
18529 +       for(i=0; i<sizeof(int_stats) / sizeof(struct inf); i++) {
18530 +               len += sprintf(buffer + len, "%s = %d\n",
18531 +                              int_stats[i].name, *int_stats[i].value);
18532 +       }
18533 +
18534 +       *start = buffer + offset;
18535 +
18536 +       len -= offset;
18537 +
18538 +       if(len > length) len = length;
18539 +
18540 +       return len;
18541 +}
18542 +
18543 +int mipv6_stats_init(void)
18544 +{
18545 +       memset(&mipv6_stats, 0, sizeof(struct mipv6_statistics));
18546 +       proc_net_create("mip6_stat", 0, proc_info_dump);
18547 +       return 0;
18548 +}
18549 +
18550 +void mipv6_stats_exit(void)
18551 +{
18552 +       proc_net_remove("mip6_stat");
18553 +}
18554 --- /dev/null
18555 +++ linux-2.4.27/net/ipv6/mobile_ip6/stats.h
18556 @@ -0,0 +1,71 @@
18557 +/*
18558 + *      MIPL Mobile IPv6 Statistics header file
18559 + *
18560 + *      $Id$
18561 + *
18562 + *      This program is free software; you can redistribute it and/or
18563 + *      modify it under the terms of the GNU General Public License
18564 + *      as published by the Free Software Foundation; either version
18565 + *      2 of the License, or (at your option) any later version.
18566 + */
18567 +
18568 +#ifndef _STATS_H
18569 +#define _STATS_H
18570 +
18571 +struct mipv6_drop {
18572 +       __u32 auth;
18573 +       __u32 invalid;
18574 +       __u32 misc;
18575 +};
18576 +
18577 +struct mipv6_statistics {
18578 +       int n_encapsulations;
18579 +       int n_decapsulations;
18580 +       int n_mh_in_msg;
18581 +       int n_mh_in_error;
18582 +       int n_mh_out_msg;
18583 +       int n_mh_out_error;
18584 +
18585 +       int n_brr_rcvd;
18586 +       int n_hoti_rcvd;
18587 +       int n_coti_rcvd;
18588 +       int n_hot_rcvd;
18589 +       int n_cot_rcvd;
18590 +       int n_bu_rcvd;
18591 +       int n_ba_rcvd;
18592 +       int n_ban_rcvd;
18593 +       int n_be_rcvd;
18594 +
18595 +       int n_brr_sent;
18596 +       int n_hoti_sent;
18597 +       int n_coti_sent;
18598 +       int n_hot_sent;
18599 +       int n_cot_sent;
18600 +       int n_bu_sent;
18601 +       int n_ba_sent;
18602 +       int n_ban_sent;
18603 +       int n_be_sent;
18604 +
18605 +       int n_ha_rcvd;
18606 +       int n_ha_sent;
18607 +
18608 +       struct mipv6_drop n_bu_drop;
18609 +       struct mipv6_drop n_ba_drop;
18610 +       struct mipv6_drop n_brr_drop;
18611 +       struct mipv6_drop n_be_drop;
18612 +       struct mipv6_drop n_ha_drop;
18613 +};
18614 +
18615 +extern struct mipv6_statistics mipv6_stats;
18616 +
18617 +#ifdef CONFIG_SMP
18618 +/* atomic_t is max 24 bits long */
18619 +#define MIPV6_INC_STATS(X) atomic_inc((atomic_t *)&mipv6_stats.X);
18620 +#else
18621 +#define MIPV6_INC_STATS(X) mipv6_stats.X++;
18622 +#endif
18623 +
18624 +int mipv6_stats_init(void);
18625 +void mipv6_stats_exit(void);
18626 +
18627 +#endif
18628 --- /dev/null
18629 +++ linux-2.4.27/net/ipv6/mobile_ip6/tunnel.h
18630 @@ -0,0 +1,35 @@
18631 +/*
18632 + *      MIPL Mobile IPv6 IP6-IP6 tunneling header file
18633 + *
18634 + *      $Id$
18635 + *
18636 + *      This program is free software; you can redistribute it and/or
18637 + *      modify it under the terms of the GNU General Public License
18638 + *      as published by the Free Software Foundation; either version
18639 + *      2 of the License, or (at your option) any later version.
18640 + */
18641 +
18642 +#ifndef _TUNNEL_H
18643 +#define _TUNNEL_H
18644 +
18645 +#include <linux/in6.h>
18646 +#include <linux/if_arp.h>
18647 +#include <net/ipv6_tunnel.h>
18648 +
18649 +static __inline__ int is_mip6_tnl(struct ip6_tnl *t)
18650 +{
18651 +       return (t != NULL && 
18652 +               t->parms.flags & IP6_TNL_F_KERNEL_DEV &&
18653 +               t->parms.flags & IP6_TNL_F_MIP6_DEV);
18654 +                       
18655 +}
18656 +
18657 +static __inline__ int dev_is_mip6_tnl(struct net_device *dev)
18658 +{
18659 +       struct ip6_tnl *t = (struct ip6_tnl *)dev->priv;
18660 +       return (dev->type == ARPHRD_TUNNEL6 && is_mip6_tnl(t));
18661 +}
18662 +
18663 +
18664 +#endif
18665 +
18666 --- /dev/null
18667 +++ linux-2.4.27/net/ipv6/mobile_ip6/tunnel_ha.c
18668 @@ -0,0 +1,264 @@
18669 +/*
18670 + *     IPv6-IPv6 tunneling module
18671 + *
18672 + *     Authors:
18673 + *     Sami Kivisaari          <skivisaa@cc.hut.fi>
18674 + *     Ville Nuorvala          <vnuorval@tml.hut.fi>
18675 + *
18676 + *     $Id$
18677 + *
18678 + *     This program is free software; you can redistribute it and/or
18679 + *      modify it under the terms of the GNU General Public License
18680 + *      as published by the Free Software Foundation; either version
18681 + *      2 of the License, or (at your option) any later version.
18682 + *
18683 + */
18684 +
18685 +#include <linux/net.h>
18686 +#include <linux/skbuff.h>
18687 +#include <linux/ipv6.h>
18688 +#include <linux/net.h>
18689 +#include <linux/netdevice.h>
18690 +#include <linux/init.h>
18691 +#include <linux/route.h>
18692 +#include <linux/ipv6_route.h>
18693 +
18694 +#ifdef CONFIG_SYSCTL
18695 +#include <linux/sysctl.h>
18696 +#endif /* CONFIG_SYSCTL */
18697 +
18698 +#include <net/protocol.h>
18699 +#include <net/ipv6.h>
18700 +#include <net/ip6_route.h>
18701 +#include <net/dst.h>
18702 +#include <net/addrconf.h>
18703 +
18704 +#include "tunnel.h"
18705 +#include "debug.h"
18706 +#include "stats.h"
18707 +#include "config.h"
18708 +
18709 +#define MIPV6_TNL_MAX IP6_TNL_MAX
18710 +#define MIPV6_TNL_MIN 1
18711 +
18712 +int mipv6_max_tnls = 3;
18713 +int mipv6_min_tnls = 1;
18714 +
18715 +DECLARE_MUTEX(tnl_sem);
18716 +
18717 +int mipv6_max_tnls_sysctl(ctl_table *ctl, int write, struct file *filp,
18718 +                         void *buffer, size_t *lenp)
18719 +{
18720 +       int err;
18721 +       
18722 +       DEBUG_FUNC();
18723 +
18724 +       down(&tnl_sem);
18725 +       if (write) {
18726 +               int diff;
18727 +               int old_max_tnls = mipv6_max_tnls;
18728 +               err = proc_dointvec(ctl, write, filp, buffer, lenp);
18729 +               if (err < 0) 
18730 +                       goto out;
18731 +               if (mipv6_max_tnls < mipv6_min_tnls || 
18732 +                   mipv6_max_tnls > MIPV6_TNL_MAX) {
18733 +                       mipv6_max_tnls = old_max_tnls;
18734 +                       goto out;
18735 +               }
18736 +               if (mipv6_max_tnls < old_max_tnls) {
18737 +                       diff = old_max_tnls - mipv6_max_tnls;
18738 +                       ip6ip6_tnl_dec_max_kdev_count(diff);
18739 +               } else if (mipv6_max_tnls > old_max_tnls) {
18740 +                       diff = mipv6_max_tnls - old_max_tnls;
18741 +                       ip6ip6_tnl_inc_max_kdev_count(diff);
18742 +               }
18743 +       } else {
18744 +               err = proc_dointvec(ctl, write, filp, buffer, lenp);
18745 +       }
18746 +out:
18747 +       up(&tnl_sem);
18748 +       return err;
18749 +}
18750 +
18751 +int mipv6_min_tnls_sysctl(ctl_table *ctl, int write, struct file *filp,
18752 +                         void *buffer, size_t *lenp)
18753 +{
18754 +       int err;
18755 +
18756 +       DEBUG_FUNC();
18757 +
18758 +       down(&tnl_sem);
18759 +       if (write) {
18760 +               int diff;
18761 +               int old_min_tnls = mipv6_min_tnls;
18762 +               err = proc_dointvec(ctl, write, filp, buffer, lenp);
18763 +               if (err < 0) 
18764 +                       goto out;
18765 +               if (mipv6_min_tnls > mipv6_max_tnls || 
18766 +                   mipv6_min_tnls < MIPV6_TNL_MIN) {
18767 +                       mipv6_min_tnls = old_min_tnls;
18768 +                       goto out;
18769 +               }
18770 +               if (mipv6_min_tnls < old_min_tnls) {
18771 +                       diff = old_min_tnls - mipv6_min_tnls;
18772 +                       ip6ip6_tnl_dec_min_kdev_count(diff);
18773 +               } else if (mipv6_min_tnls > old_min_tnls) {
18774 +                       diff = mipv6_min_tnls - old_min_tnls;
18775 +                       ip6ip6_tnl_inc_min_kdev_count(diff);
18776 +               }
18777 +       } else {
18778 +               err = proc_dointvec(ctl, write, filp, buffer, lenp);
18779 +       }
18780 +out:
18781 +       up(&tnl_sem);
18782 +       return err;
18783 +}
18784 +
18785 +static __inline__ int mipv6_tnl_add(struct in6_addr *remote, 
18786 +                                   struct in6_addr *local) 
18787 +{
18788 +       struct ip6_tnl_parm p;
18789 +       int ret;
18790 +
18791 +       DEBUG_FUNC();
18792 +
18793 +       memset(&p, 0, sizeof(p));
18794 +       p.proto = IPPROTO_IPV6;
18795 +       ipv6_addr_copy(&p.laddr, local);
18796 +       ipv6_addr_copy(&p.raddr, remote);
18797 +       p.hop_limit = 255;
18798 +       p.flags = (IP6_TNL_F_KERNEL_DEV | IP6_TNL_F_MIP6_DEV |
18799 +                  IP6_TNL_F_IGN_ENCAP_LIMIT);
18800 +
18801 +       ret = ip6ip6_kernel_tnl_add(&p);
18802 +       if (ret > 0) {
18803 +               DEBUG(DBG_INFO, "added tunnel from: "
18804 +                     "%x:%x:%x:%x:%x:%x:%x:%x to: %x:%x:%x:%x:%x:%x:%x:%x", 
18805 +                     NIPV6ADDR(local), NIPV6ADDR(remote));
18806 +       } else {
18807 +               DEBUG(DBG_WARNING, "unable to add tunnel from: "
18808 +                     "%x:%x:%x:%x:%x:%x:%x:%x to: %x:%x:%x:%x:%x:%x:%x:%x", 
18809 +                     NIPV6ADDR(local), NIPV6ADDR(remote));             
18810 +       }
18811 +       return ret;
18812 +}
18813 +
18814 +static __inline__ int mipv6_tnl_del(struct in6_addr *remote, 
18815 +                                   struct in6_addr *local) 
18816 +{
18817 +       struct ip6_tnl *t = ip6ip6_tnl_lookup(remote, local);
18818 +       
18819 +       DEBUG_FUNC();
18820 +       
18821 +       if (t != NULL && (t->parms.flags & IP6_TNL_F_MIP6_DEV)) {
18822 +               DEBUG(DBG_INFO, "deleting tunnel from: "
18823 +                     "%x:%x:%x:%x:%x:%x:%x:%x to: %x:%x:%x:%x:%x:%x:%x:%x", 
18824 +                     NIPV6ADDR(local), NIPV6ADDR(remote));
18825 +
18826 +               return ip6ip6_kernel_tnl_del(t);
18827 +       }
18828 +       return 0;
18829 +}
18830 +
18831 +static int add_route_to_mn(struct in6_addr *coa, struct in6_addr *ha_addr, 
18832 +                          struct in6_addr *home_addr) 
18833 +{
18834 +       struct in6_rtmsg rtmsg;
18835 +       int err;
18836 +       struct ip6_tnl *t = ip6ip6_tnl_lookup(coa, ha_addr);
18837 +       
18838 +       if (!is_mip6_tnl(t)) {
18839 +               DEBUG(DBG_CRITICAL,"Tunnel missing");
18840 +               return -ENODEV;
18841 +       }
18842 +       
18843 +       DEBUG(DBG_INFO, "adding route to: %x:%x:%x:%x:%x:%x:%x:%x via "
18844 +             "tunnel device", NIPV6ADDR(home_addr));
18845 +
18846 +       memset(&rtmsg, 0, sizeof(rtmsg));
18847 +       ipv6_addr_copy(&rtmsg.rtmsg_dst, home_addr);
18848 +       rtmsg.rtmsg_dst_len = 128;
18849 +       rtmsg.rtmsg_type = RTMSG_NEWROUTE;
18850 +       rtmsg.rtmsg_flags = RTF_UP | RTF_NONEXTHOP | RTF_HOST | RTF_MOBILENODE;
18851 +       rtmsg.rtmsg_ifindex = t->dev->ifindex;
18852 +       rtmsg.rtmsg_metric = IP6_RT_PRIO_MIPV6;
18853 +       if ((err = ip6_route_add(&rtmsg, NULL)) == -EEXIST) {
18854 +               err = 0;
18855 +       }
18856 +       return err;
18857 +}
18858 +
18859 +static void del_route_to_mn(struct in6_addr *coa, struct in6_addr *ha_addr, 
18860 +                           struct in6_addr *home_addr) 
18861 +{
18862 +       struct ip6_tnl *t = ip6ip6_tnl_lookup(coa, ha_addr);
18863 +
18864 +       DEBUG_FUNC();
18865 +
18866 +       if (is_mip6_tnl(t)) {
18867 +               struct in6_rtmsg rtmsg;
18868 +
18869 +               DEBUG(DBG_INFO, "deleting route to: %x:%x:%x:%x:%x:%x:%x:%x "
18870 +                     " via tunnel device", NIPV6ADDR(home_addr));
18871 +
18872 +               memset(&rtmsg, 0, sizeof(rtmsg));
18873 +               ipv6_addr_copy(&rtmsg.rtmsg_dst, home_addr);
18874 +               rtmsg.rtmsg_dst_len = 128;
18875 +               rtmsg.rtmsg_ifindex = t->dev->ifindex;
18876 +               rtmsg.rtmsg_metric = IP6_RT_PRIO_MIPV6;
18877 +               ip6_route_del(&rtmsg, NULL);
18878 +       }
18879 +}
18880 +
18881 +
18882 +int mipv6_add_tnl_to_mn(struct in6_addr *coa, 
18883 +                       struct in6_addr *ha_addr,
18884 +                       struct in6_addr *home_addr)
18885 +{
18886 +       int ret;
18887 +
18888 +       DEBUG_FUNC();
18889 +
18890 +       ret = mipv6_tnl_add(coa, ha_addr);
18891 +
18892 +       if (ret > 0) {
18893 +               int err = add_route_to_mn(coa, ha_addr, home_addr);
18894 +               if (err) {
18895 +                       if (err != -ENODEV) {
18896 +                               mipv6_tnl_del(coa, ha_addr);
18897 +                       }
18898 +                       return err;
18899 +               }
18900 +       }
18901 +       return ret;
18902 +} 
18903 +
18904 +int mipv6_del_tnl_to_mn(struct in6_addr *coa, 
18905 +                       struct in6_addr *ha_addr,
18906 +                       struct in6_addr *home_addr)
18907 +{
18908 +       DEBUG_FUNC();
18909 +       del_route_to_mn(coa, ha_addr, home_addr);
18910 +       return mipv6_tnl_del(coa, ha_addr);
18911 +} 
18912 +
18913 +__init void mipv6_initialize_tunnel(void)
18914 +{
18915 +       down(&tnl_sem);
18916 +       ip6ip6_tnl_inc_max_kdev_count(mipv6_max_tnls);
18917 +       ip6ip6_tnl_inc_min_kdev_count(mipv6_min_tnls);
18918 +       up(&tnl_sem);
18919 +       mip6_fn.bce_tnl_rt_add = add_route_to_mn;
18920 +       mip6_fn.bce_tnl_rt_del = del_route_to_mn;
18921 +}
18922 +
18923 +__exit void mipv6_shutdown_tunnel(void)
18924 +{
18925 +       mip6_fn.bce_tnl_rt_del = NULL;
18926 +       mip6_fn.bce_tnl_rt_add = NULL;
18927 +       down(&tnl_sem);
18928 +       ip6ip6_tnl_dec_min_kdev_count(mipv6_min_tnls);
18929 +       ip6ip6_tnl_dec_max_kdev_count(mipv6_max_tnls);
18930 +       up(&tnl_sem);
18931 +}
18932 +
18933 --- /dev/null
18934 +++ linux-2.4.27/net/ipv6/mobile_ip6/tunnel_ha.h
18935 @@ -0,0 +1,20 @@
18936 +#ifndef _TUNNEL_HA_H
18937 +#define _TUNNEL_HA_H
18938 +
18939 +#include "tunnel.h"
18940 +
18941 +extern int mipv6_max_tnls;
18942 +extern int mipv6_min_tnls;
18943 +
18944 +extern void mipv6_initialize_tunnel(void);
18945 +extern void mipv6_shutdown_tunnel(void);
18946 +
18947 +extern int mipv6_add_tnl_to_mn(struct in6_addr *coa, 
18948 +                              struct in6_addr *ha_addr,
18949 +                              struct in6_addr *home_addr);
18950 +
18951 +extern int mipv6_del_tnl_to_mn(struct in6_addr *coa, 
18952 +                              struct in6_addr *ha_addr,
18953 +                              struct in6_addr *home_addr);
18954 +
18955 +#endif
18956 --- /dev/null
18957 +++ linux-2.4.27/net/ipv6/mobile_ip6/tunnel_mn.c
18958 @@ -0,0 +1,160 @@
18959 +/*
18960 + *     IPv6-IPv6 tunneling module
18961 + *
18962 + *     Authors:
18963 + *     Sami Kivisaari          <skivisaa@cc.hut.fi>
18964 + *     Ville Nuorvala          <vnuorval@tml.hut.fi>
18965 + *
18966 + *     $Id$
18967 + *
18968 + *     This program is free software; you can redistribute it and/or
18969 + *      modify it under the terms of the GNU General Public License
18970 + *      as published by the Free Software Foundation; either version
18971 + *      2 of the License, or (at your option) any later version.
18972 + *
18973 + */
18974 +
18975 +#include <linux/net.h>
18976 +#include <linux/skbuff.h>
18977 +#include <linux/ipv6.h>
18978 +#include <linux/net.h>
18979 +#include <linux/netdevice.h>
18980 +#include <linux/init.h>
18981 +#include <linux/route.h>
18982 +#include <linux/ipv6_route.h>
18983 +
18984 +#ifdef CONFIG_SYSCTL
18985 +#include <linux/sysctl.h>
18986 +#endif /* CONFIG_SYSCTL */
18987 +
18988 +#include <net/protocol.h>
18989 +#include <net/ipv6.h>
18990 +#include <net/ip6_route.h>
18991 +#include <net/dst.h>
18992 +#include <net/addrconf.h>
18993 +
18994 +#include "tunnel.h"
18995 +#include "debug.h"
18996 +#include "stats.h"
18997 +
18998 +static struct net_device *mn_ha_tdev;
18999 +
19000 +static spinlock_t mn_ha_lock = SPIN_LOCK_UNLOCKED;
19001 +
19002 +static __inline__ int add_reverse_route(struct in6_addr *ha_addr,
19003 +                                       struct in6_addr *home_addr, 
19004 +                                       struct net_device *tdev) 
19005 +{
19006 +       struct in6_rtmsg rtmsg;
19007 +       int err;
19008 +
19009 +       DEBUG_FUNC();
19010 +
19011 +       memset(&rtmsg, 0, sizeof(rtmsg));
19012 +       rtmsg.rtmsg_type = RTMSG_NEWROUTE;
19013 +       ipv6_addr_copy(&rtmsg.rtmsg_src, home_addr);
19014 +       rtmsg.rtmsg_src_len = 128;
19015 +       rtmsg.rtmsg_flags = RTF_UP | RTF_DEFAULT;
19016 +       rtmsg.rtmsg_ifindex = tdev->ifindex;
19017 +       rtmsg.rtmsg_metric = IP6_RT_PRIO_MIPV6;
19018 +       if ((err = ip6_route_add(&rtmsg, NULL)) == -EEXIST) {
19019 +               return 0;
19020 +       }
19021 +       return err;     
19022 +}
19023 +
19024 +static __inline__ void del_reverse_route(struct in6_addr *ha_addr, 
19025 +                                        struct in6_addr *home_addr,
19026 +                                        struct net_device *tdev) 
19027 +{
19028 +       struct in6_rtmsg rtmsg;
19029 +
19030 +       DEBUG(DBG_INFO, "removing reverse route via tunnel device");
19031 +
19032 +       memset(&rtmsg, 0, sizeof(rtmsg));
19033 +       ipv6_addr_copy(&rtmsg.rtmsg_src, home_addr);
19034 +       rtmsg.rtmsg_src_len = 128;
19035 +       rtmsg.rtmsg_ifindex = tdev->ifindex;
19036 +       rtmsg.rtmsg_metric = IP6_RT_PRIO_MIPV6;
19037 +       ip6_route_del(&rtmsg, NULL);
19038 +}
19039 +
19040 +int mipv6_add_tnl_to_ha(void)
19041 +{
19042 +       struct ip6_tnl_parm p;
19043 +       struct ip6_tnl *t;
19044 +       int err;
19045 +
19046 +       DEBUG_FUNC();
19047 +
19048 +       memset(&p, 0, sizeof(p));
19049 +       p.proto = IPPROTO_IPV6;
19050 +       p.hop_limit = 255;
19051 +       p.flags = (IP6_TNL_F_KERNEL_DEV | IP6_TNL_F_MIP6_DEV |
19052 +                  IP6_TNL_F_IGN_ENCAP_LIMIT);
19053 +       strcpy(p.name, "mip6mnha1");
19054 +
19055 +       rtnl_lock();
19056 +       if ((err = ip6ip6_tnl_create(&p, &t))) {
19057 +               rtnl_unlock();
19058 +               return err;
19059 +       }
19060 +       spin_lock_bh(&mn_ha_lock);
19061 +
19062 +       if (!mn_ha_tdev) {
19063 +               mn_ha_tdev = t->dev;
19064 +               dev_hold(mn_ha_tdev);
19065 +       }
19066 +       spin_unlock_bh(&mn_ha_lock);
19067 +       dev_open(t->dev);
19068 +       rtnl_unlock();
19069 +       return 0;
19070 +} 
19071 +
19072 +int mipv6_mv_tnl_to_ha(struct in6_addr *ha_addr,
19073 +                      struct in6_addr *coa,
19074 +                      struct in6_addr *home_addr)
19075 +{
19076 +       int err = -ENODEV;
19077 +
19078 +       DEBUG_FUNC();
19079 +
19080 +       spin_lock_bh(&mn_ha_lock);
19081 +       if (mn_ha_tdev) {
19082 +               struct ip6_tnl_parm p;
19083 +               memset(&p, 0, sizeof(p));
19084 +               p.proto = IPPROTO_IPV6;
19085 +               ipv6_addr_copy(&p.laddr, coa);
19086 +               ipv6_addr_copy(&p.raddr, ha_addr);
19087 +               p.hop_limit = 255;
19088 +               p.flags = (IP6_TNL_F_KERNEL_DEV | IP6_TNL_F_MIP6_DEV |
19089 +                          IP6_TNL_F_IGN_ENCAP_LIMIT);
19090 +
19091 +               ip6ip6_tnl_change((struct ip6_tnl *) mn_ha_tdev->priv, &p);
19092 +               if (ipv6_addr_cmp(coa, home_addr)) {
19093 +                       err = add_reverse_route(ha_addr, home_addr, 
19094 +                                               mn_ha_tdev);
19095 +               } else {
19096 +                       del_reverse_route(ha_addr, home_addr, mn_ha_tdev);
19097 +                       err = 0;
19098 +               }
19099 +       }
19100 +       spin_unlock_bh(&mn_ha_lock);
19101 +       return err;
19102 +}
19103 +
19104 +void mipv6_del_tnl_to_ha(void)
19105 +{
19106 +       struct net_device *dev;
19107 +
19108 +       DEBUG_FUNC();
19109 +
19110 +       rtnl_lock();
19111 +       spin_lock_bh(&mn_ha_lock);
19112 +       dev = mn_ha_tdev;
19113 +       mn_ha_tdev = NULL;
19114 +       spin_unlock_bh(&mn_ha_lock);
19115 +       dev_put(dev);
19116 +       unregister_netdevice(dev);
19117 +       rtnl_unlock();
19118 +}
19119 --- /dev/null
19120 +++ linux-2.4.27/net/ipv6/mobile_ip6/tunnel_mn.h
19121 @@ -0,0 +1,14 @@
19122 +#ifndef _TUNNEL_MN_H
19123 +#define _TUNNEL_MN_H
19124 +
19125 +#include "tunnel.h"
19126 +
19127 +extern int mipv6_add_tnl_to_ha(void);
19128 +
19129 +extern int mipv6_mv_tnl_to_ha(struct in6_addr *ha_addr, 
19130 +                             struct in6_addr *coa,
19131 +                             struct in6_addr *home_addr);
19132 +
19133 +extern int mipv6_del_tnl_to_ha(void);
19134 +
19135 +#endif
19136 --- /dev/null
19137 +++ linux-2.4.27/net/ipv6/mobile_ip6/util.h
19138 @@ -0,0 +1,91 @@
19139 +/*
19140 + *      MIPL Mobile IPv6 Utility functions
19141 + *
19142 + *      $Id$
19143 + *
19144 + *      This program is free software; you can redistribute it and/or
19145 + *      modify it under the terms of the GNU General Public License
19146 + *      as published by the Free Software Foundation; either version
19147 + *      2 of the License, or (at your option) any later version.
19148 + */
19149 +
19150 +#ifndef _UTIL_H
19151 +#define _UTIL_H
19152 +
19153 +#include <linux/in6.h>
19154 +#include <asm/byteorder.h>
19155 +
19156 +/**
19157 + * mipv6_prefix_compare - Compare two IPv6 prefixes
19158 + * @addr: IPv6 address
19159 + * @prefix: IPv6 address
19160 + * @nprefix: number of bits to compare
19161 + *
19162 + * Perform prefix comparison bitwise for the @nprefix first bits
19163 + * Returns 1, if the prefixes are the same, 0 otherwise 
19164 + **/
19165 +static inline int mipv6_prefix_compare(const struct in6_addr *addr,
19166 +                                      const struct in6_addr *prefix, 
19167 +                                      const unsigned int pfix_len)
19168 +{
19169 +       int i;
19170 +       unsigned int nprefix = pfix_len;
19171 +
19172 +       if (nprefix > 128)
19173 +               return 0;
19174 +
19175 +       for (i = 0; nprefix > 0; nprefix -= 32, i++) {
19176 +               if (nprefix >= 32) {
19177 +                       if (addr->s6_addr32[i] != prefix->s6_addr32[i])
19178 +                               return 0;
19179 +               } else {
19180 +                       if (((addr->s6_addr32[i] ^ prefix->s6_addr32[i]) &
19181 +                            ((~0) << (32 - nprefix))) != 0)
19182 +                               return 0;
19183 +                       return 1;
19184 +               }
19185 +       }
19186 +
19187 +       return 1;
19188 +}
19189 +
19190 +/**
19191 + * homeagent_anycast - Compute Home Agent anycast address
19192 + * @ac_addr: append home agent anycast suffix to passed prefix
19193 + * @prefix: prefix ha anycast address is generated from
19194 + * @plen: length of prefix in bits
19195 + *
19196 + * Calculate corresponding Home Agent Anycast Address (RFC2526) in a
19197 + * given subnet.
19198 + */
19199 +static inline int 
19200 +mipv6_ha_anycast(struct in6_addr *ac_addr, struct in6_addr *prefix, int plen)
19201 +{
19202 +       if (plen <= 0 || plen > 120)  {
19203 +               /* error, interface id should be minimum 8 bits */
19204 +               return -1;
19205 +       }
19206 +       ipv6_addr_copy(ac_addr, prefix);
19207 +
19208 +       if (plen < 32)
19209 +               ac_addr->s6_addr32[0] |= htonl((u32)(~0) >> plen);
19210 +       if (plen < 64)
19211 +               ac_addr->s6_addr32[1] |= htonl((u32)(~0) >> (plen > 32 ? plen % 32 : 0));
19212 +       if (plen < 92)
19213 +               ac_addr->s6_addr32[2] |= htonl((u32)(~0) >> (plen > 64 ? plen % 32 : 0));
19214 +       if (plen <= 120)
19215 +               ac_addr->s6_addr32[3] |= htonl((u32)(~0) >> (plen > 92 ? plen % 32 : 0));
19216 +
19217 +       /* RFC2526: for interface identifiers in EUI-64
19218 +        * format, the universal/local bit in the interface
19219 +        * identifier MUST be set to 0. */
19220 +       if (plen == 64) {
19221 +               ac_addr->s6_addr32[2] &= (int)htonl(0xfdffffff);
19222 +       }
19223 +       /* Mobile IPv6 Home-Agents anycast id (0x7e) */
19224 +       ac_addr->s6_addr32[3] &= (int)htonl(0xfffffffe);
19225 +
19226 +       return 0;
19227 +}
19228 +
19229 +#endif /* _UTIL_H */
19230 --- linux-2.4.27/net/ipv6/ndisc.c~mipv6-1.1-v2.4.26
19231 +++ linux-2.4.27/net/ipv6/ndisc.c
19232 @@ -23,6 +23,7 @@
19233   *                                             and moved to net/core.
19234   *     Pekka Savola                    :       RFC2461 validation
19235   *     YOSHIFUJI Hideaki @USAGI        :       Verify ND options properly
19236 + *     Ville Nuorvala                  :       RFC2461 fixes to proxy ND
19237   */
19238  
19239  /* Set to 3 to get tracing... */
19240 @@ -70,6 +71,7 @@
19241  #include <net/ip6_route.h>
19242  #include <net/addrconf.h>
19243  #include <net/icmp.h>
19244 +#include <net/mipglue.h>
19245  
19246  #include <net/checksum.h>
19247  #include <linux/proc_fs.h>
19248 @@ -187,6 +189,8 @@
19249                 case ND_OPT_TARGET_LL_ADDR:
19250                 case ND_OPT_MTU:
19251                 case ND_OPT_REDIRECT_HDR:
19252 +               case ND_OPT_RTR_ADV_INTERVAL:
19253 +               case ND_OPT_HOME_AGENT_INFO:
19254                         if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) {
19255                                 ND_PRINTK2((KERN_WARNING
19256                                             "ndisc_parse_options(): duplicated ND6 option found: type=%d\n",
19257 @@ -372,8 +376,8 @@
19258   */
19259  
19260  void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
19261 -                  struct in6_addr *daddr, struct in6_addr *solicited_addr,
19262 -                  int router, int solicited, int override, int inc_opt) 
19263 +               struct in6_addr *daddr, struct in6_addr *solicited_addr, 
19264 +               int router, int solicited, int override, int inc_opt) 
19265  {
19266         static struct in6_addr tmpaddr;
19267         struct inet6_ifaddr *ifp;
19268 @@ -766,7 +770,8 @@
19269                 int addr_type = ipv6_addr_type(saddr);
19270  
19271                 if (in6_dev && in6_dev->cnf.forwarding &&
19272 -                   (addr_type & IPV6_ADDR_UNICAST) &&
19273 +                   (addr_type & IPV6_ADDR_UNICAST || 
19274 +                    addr_type == IPV6_ADDR_ANY) &&
19275                     pneigh_lookup(&nd_tbl, &msg->target, dev, 0)) {
19276                         int inc = ipv6_addr_type(daddr)&IPV6_ADDR_MULTICAST;
19277  
19278 @@ -778,13 +783,21 @@
19279                                         nd_tbl.stats.rcv_probes_mcast++;
19280                                 else
19281                                         nd_tbl.stats.rcv_probes_ucast++;
19282 -                                       
19283 -                               neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, dev);
19284  
19285 -                               if (neigh) {
19286 -                                       ndisc_send_na(dev, neigh, saddr, &msg->target,
19287 -                                                     0, 1, 0, 1);
19288 -                                       neigh_release(neigh);
19289 +                               if (addr_type & IPV6_ADDR_UNICAST) {            
19290 +                                       neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, dev);
19291 +
19292 +                                       if (neigh) {
19293 +                                               ndisc_send_na(dev, neigh, saddr, &msg->target,
19294 +                                                             0, 1, 0, 1);
19295 +                                               neigh_release(neigh);
19296 +                                       }
19297 +                               } else {
19298 +                                       /* the proxy should also protect against DAD */
19299 +                                       struct in6_addr maddr;
19300 +                                       ipv6_addr_all_nodes(&maddr);
19301 +                                       ndisc_send_na(dev, NULL, &maddr, &msg->target,
19302 +                                                     0, 0, 0, 1);
19303                                 }
19304                         } else {
19305                                 struct sk_buff *n = skb_clone(skb, GFP_ATOMIC);
19306 @@ -849,6 +862,9 @@
19307                 if (ifp->flags & IFA_F_TENTATIVE) {
19308                         addrconf_dad_failure(ifp);
19309                         return;
19310 +               } else if (ndisc_mip_mn_ha_probe(ifp, lladdr)) {
19311 +                       in6_ifa_put(ifp);
19312 +                       return;
19313                 }
19314                 /* What should we make now? The advertisement
19315                    is invalid, but ndisc specs say nothing
19316 @@ -887,6 +903,7 @@
19317                              msg->icmph.icmp6_override, 1);
19318                 neigh_release(neigh);
19319         }
19320 +       ndisc_check_mipv6_dad(&msg->target);
19321  }
19322  
19323  static void ndisc_router_discovery(struct sk_buff *skb)
19324 @@ -894,6 +911,7 @@
19325          struct ra_msg *ra_msg = (struct ra_msg *) skb->h.raw;
19326         struct neighbour *neigh;
19327         struct inet6_dev *in6_dev;
19328 +       int change_rtr;
19329         struct rt6_info *rt;
19330         int lifetime;
19331         struct ndisc_options ndopts;
19332 @@ -923,10 +941,6 @@
19333                 ND_PRINTK1("RA: can't find in6 device\n");
19334                 return;
19335         }
19336 -       if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_ra) {
19337 -               in6_dev_put(in6_dev);
19338 -               return;
19339 -       }
19340  
19341         if (!ndisc_parse_options(opt, optlen, &ndopts)) {
19342                 in6_dev_put(in6_dev);
19343 @@ -935,7 +949,12 @@
19344                                    "ICMP6 RA: invalid ND option, ignored.\n");
19345                 return;
19346         }
19347 +       change_rtr = ndisc_mipv6_ra_rcv(skb, &ndopts);
19348  
19349 +       if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_ra) {
19350 +               in6_dev_put(in6_dev);
19351 +               return;
19352 +       }
19353         if (in6_dev->if_flags & IF_RS_SENT) {
19354                 /*
19355                  *      flag that an RA was received after an RS was sent
19356 @@ -963,8 +982,7 @@
19357                 ip6_del_rt(rt, NULL);
19358                 rt = NULL;
19359         }
19360 -
19361 -       if (rt == NULL && lifetime) {
19362 +       if (rt == NULL && lifetime && change_rtr) {
19363                 ND_PRINTK2("ndisc_rdisc: adding default router\n");
19364  
19365                 rt = rt6_add_dflt_router(&skb->nh.ipv6h->saddr, skb->dev);
19366 @@ -1087,6 +1105,8 @@
19367         if (rt)
19368                 dst_release(&rt->u.dst);
19369         in6_dev_put(in6_dev);
19370 +
19371 +       ndisc_mipv6_change_router(change_rtr);
19372  }
19373  
19374  static void ndisc_redirect_rcv(struct sk_buff *skb)
19375 --- linux-2.4.27/net/ipv6/raw.c~mipv6-1.1-v2.4.26
19376 +++ linux-2.4.27/net/ipv6/raw.c
19377 @@ -43,6 +43,7 @@
19378  #include <net/transp_v6.h>
19379  #include <net/udp.h>
19380  #include <net/inet_common.h>
19381 +#include <net/mipglue.h>
19382  
19383  #include <net/rawv6.h>
19384  
19385 @@ -641,6 +642,7 @@
19386                         hdr.daddr = daddr;
19387                 else
19388                         hdr.daddr = NULL;
19389 +               hdr.daddr = mipv6_get_fake_hdr_daddr(hdr.daddr, daddr);
19390  
19391                 err = ip6_build_xmit(sk, rawv6_frag_cksum, &hdr, &fl, len,
19392                                      opt, hlimit, msg->msg_flags);
19393 --- linux-2.4.27/net/ipv6/route.c~mipv6-1.1-v2.4.26
19394 +++ linux-2.4.27/net/ipv6/route.c
19395 @@ -49,6 +49,7 @@
19396  #include <net/addrconf.h>
19397  #include <net/tcp.h>
19398  #include <linux/rtnetlink.h>
19399 +#include <net/mipglue.h>
19400  
19401  #include <asm/uaccess.h>
19402  
19403 @@ -363,12 +364,8 @@
19404                 rt->u.dst.flags |= DST_HOST;
19405  
19406  #ifdef CONFIG_IPV6_SUBTREES
19407 -               if (rt->rt6i_src.plen && saddr) {
19408 -                       ipv6_addr_copy(&rt->rt6i_src.addr, saddr);
19409 -                       rt->rt6i_src.plen = 128;
19410 -               }
19411 +               rt->rt6i_src.plen = ort->rt6i_src.plen;
19412  #endif
19413 -
19414                 rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway);
19415  
19416                 dst_hold(&rt->u.dst);
19417 @@ -511,14 +508,19 @@
19418         struct rt6_info *rt;
19419         int strict;
19420         int attempts = 3;
19421 +       struct in6_addr *saddr;
19422  
19423 +       if (ipv6_chk_addr(fl->nl_u.ip6_u.daddr, NULL))
19424 +               saddr = NULL;
19425 +       else
19426 +               saddr = fl->nl_u.ip6_u.saddr;
19427 +               
19428         strict = ipv6_addr_type(fl->nl_u.ip6_u.daddr) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL);
19429  
19430  relookup:
19431         read_lock_bh(&rt6_lock);
19432  
19433 -       fn = fib6_lookup(&ip6_routing_table, fl->nl_u.ip6_u.daddr,
19434 -                        fl->nl_u.ip6_u.saddr);
19435 +       fn = fib6_lookup(&ip6_routing_table, fl->nl_u.ip6_u.daddr, saddr);
19436  
19437  restart:
19438         rt = fn->leaf;
19439 @@ -663,25 +665,6 @@
19440         return (atomic_read(&ip6_dst_ops.entries) > ip6_rt_max_size);
19441  }
19442  
19443 -/* Clean host part of a prefix. Not necessary in radix tree,
19444 -   but results in cleaner routing tables.
19445 -
19446 -   Remove it only when all the things will work!
19447 - */
19448 -
19449 -static void ipv6_addr_prefix(struct in6_addr *pfx,
19450 -                            const struct in6_addr *addr, int plen)
19451 -{
19452 -       int b = plen&0x7;
19453 -       int o = plen>>3;
19454 -
19455 -       memcpy(pfx->s6_addr, addr, o);
19456 -       if (o < 16)
19457 -               memset(pfx->s6_addr + o, 0, 16 - o);
19458 -       if (b != 0)
19459 -               pfx->s6_addr[o] = addr->s6_addr[o]&(0xff00 >> b);
19460 -}
19461 -
19462  static int ipv6_get_mtu(struct net_device *dev)
19463  {
19464         int mtu = IPV6_MIN_MTU;
19465 @@ -810,7 +793,7 @@
19466                         if (!(gwa_type&IPV6_ADDR_UNICAST))
19467                                 goto out;
19468  
19469 -                       grt = rt6_lookup(gw_addr, NULL, rtmsg->rtmsg_ifindex, 1);
19470 +                       grt = rt6_lookup(gw_addr, &rtmsg->rtmsg_src, rtmsg->rtmsg_ifindex, 1);
19471  
19472                         err = -EHOSTUNREACH;
19473                         if (grt == NULL)
19474 @@ -848,7 +831,15 @@
19475                         goto out;
19476                 }
19477         }
19478 -
19479 +#ifdef USE_IPV6_MOBILITY
19480 +        /* If destination is mobile node, add special skb->dst->input
19481 +         * function for proxy ND.
19482 +         */
19483 +        if (rtmsg->rtmsg_flags & RTF_MOBILENODE) {
19484 +                rt->u.dst.input = ip6_mipv6_forward;
19485 +        }
19486 +#endif /* CONFIG_IPV6_MOBILITY */
19487 +         
19488         if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr))
19489                 rt->rt6i_hoplimit = IPV6_DEFAULT_MCASTHOPS;
19490         else
19491 @@ -936,7 +927,7 @@
19492         struct rt6_info *rt, *nrt;
19493  
19494         /* Locate old route to this destination. */
19495 -       rt = rt6_lookup(dest, NULL, neigh->dev->ifindex, 1);
19496 +       rt = rt6_lookup(dest, saddr, neigh->dev->ifindex, 1);
19497  
19498         if (rt == NULL)
19499                 return;
19500 @@ -1003,6 +994,9 @@
19501         nrt = ip6_rt_copy(rt);
19502         if (nrt == NULL)
19503                 goto out;
19504 +#ifdef CONFIG_IPV6_SUBTREES
19505 +       nrt->rt6i_src.plen = rt->rt6i_src.plen;
19506 +#endif
19507  
19508         nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;
19509         if (on_link)
19510 @@ -1104,6 +1098,9 @@
19511                 nrt = ip6_rt_copy(rt);
19512                 if (nrt == NULL)
19513                         goto out;
19514 +#ifdef CONFIG_IPV6_SUBTREES
19515 +               nrt->rt6i_src.plen = rt->rt6i_src.plen;
19516 +#endif
19517                 ipv6_addr_copy(&nrt->rt6i_dst.addr, daddr);
19518                 nrt->rt6i_dst.plen = 128;
19519                 nrt->u.dst.flags |= DST_HOST;
19520 --- linux-2.4.27/net/ipv6/tcp_ipv6.c~mipv6-1.1-v2.4.26
19521 +++ linux-2.4.27/net/ipv6/tcp_ipv6.c
19522 @@ -50,6 +50,7 @@
19523  #include <net/addrconf.h>
19524  #include <net/ip6_route.h>
19525  #include <net/inet_ecn.h>
19526 +#include <net/mipglue.h>
19527  
19528  #include <asm/uaccess.h>
19529  
19530 @@ -557,6 +558,7 @@
19531         struct flowi fl;
19532         struct dst_entry *dst;
19533         int addr_type;
19534 +       int reroute = 0;
19535         int err;
19536  
19537         if (addr_len < SIN6_LEN_RFC2133) 
19538 @@ -660,7 +662,7 @@
19539  
19540         fl.proto = IPPROTO_TCP;
19541         fl.fl6_dst = &np->daddr;
19542 -       fl.fl6_src = saddr;
19543 +       fl.fl6_src = saddr; 
19544         fl.oif = sk->bound_dev_if;
19545         fl.uli_u.ports.dport = usin->sin6_port;
19546         fl.uli_u.ports.sport = sk->sport;
19547 @@ -669,31 +671,46 @@
19548                 struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
19549                 fl.nl_u.ip6_u.daddr = rt0->addr;
19550         }
19551 -
19552         dst = ip6_route_output(sk, &fl);
19553 -
19554 +#ifdef CONFIG_IPV6_SUBTREES
19555 +       reroute = (saddr == NULL);
19556 +#endif
19557         if ((err = dst->error) != 0) {
19558                 dst_release(dst);
19559                 goto failure;
19560         }
19561 -
19562 -       ip6_dst_store(sk, dst, NULL);
19563 -       sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM;
19564 -
19565 +       if (!reroute) {
19566 +               ip6_dst_store(sk, dst, NULL, NULL);
19567 +               sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM;
19568 +       }
19569         if (saddr == NULL) {
19570                 err = ipv6_get_saddr(dst, &np->daddr, &saddr_buf);
19571 +
19572 +               if (reroute)
19573 +                       dst_release(dst);
19574                 if (err)
19575                         goto failure;
19576  
19577                 saddr = &saddr_buf;
19578 +               ipv6_addr_copy(&np->rcv_saddr, saddr);
19579 +#ifdef CONFIG_IPV6_SUBTREES
19580 +               fl.fl6_src = saddr; 
19581 +               dst = ip6_route_output(sk, &fl);
19582 +
19583 +               if ((err = dst->error) != 0) {
19584 +                       dst_release(dst);
19585 +                       goto failure;
19586 +               }
19587 +               ip6_dst_store(sk, dst, NULL, NULL);
19588 +               sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM;
19589 +#endif
19590         }
19591  
19592         /* set the source address */
19593 -       ipv6_addr_copy(&np->rcv_saddr, saddr);
19594         ipv6_addr_copy(&np->saddr, saddr);
19595         sk->rcv_saddr= LOOPBACK4_IPV6;
19596  
19597 -       tp->ext_header_len = 0;
19598 +       tp->ext_header_len = tcp_v6_get_mipv6_header_len();
19599         if (np->opt)
19600                 tp->ext_header_len = np->opt->opt_flen+np->opt->opt_nflen;
19601         tp->mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
19602 @@ -1338,7 +1355,7 @@
19603  #endif
19604         MOD_INC_USE_COUNT;
19605  
19606 -       ip6_dst_store(newsk, dst, NULL);
19607 +       ip6_dst_store(newsk, dst, NULL, NULL);
19608         sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM;
19609  
19610         newtp = &(newsk->tp_pinfo.af_tcp);
19611 @@ -1383,7 +1400,7 @@
19612                         sock_kfree_s(sk, opt, opt->tot_len);
19613         }
19614  
19615 -       newtp->ext_header_len = 0;
19616 +       newtp->ext_header_len = tcp_v6_get_mipv6_header_len();
19617         if (np->opt)
19618                 newtp->ext_header_len = np->opt->opt_nflen + np->opt->opt_flen;
19619  
19620 @@ -1710,7 +1727,7 @@
19621                         return err;
19622                 }
19623  
19624 -               ip6_dst_store(sk, dst, NULL);
19625 +               ip6_dst_store(sk, dst, NULL, NULL);
19626                 sk->route_caps = dst->dev->features&~NETIF_F_IP_CSUM;
19627         }
19628  
19629 @@ -1749,7 +1766,7 @@
19630                         return -sk->err_soft;
19631                 }
19632  
19633 -               ip6_dst_store(sk, dst, NULL);
19634 +               ip6_dst_store(sk, dst, NULL, NULL);
19635         }
19636  
19637         skb->dst = dst_clone(dst);
19638 --- linux-2.4.27/net/ipv6/udp.c~mipv6-1.1-v2.4.26
19639 +++ linux-2.4.27/net/ipv6/udp.c
19640 @@ -48,6 +48,7 @@
19641  #include <net/ip.h>
19642  #include <net/udp.h>
19643  #include <net/inet_common.h>
19644 +#include <net/mipglue.h>
19645  
19646  #include <net/checksum.h>
19647  
19648 @@ -232,6 +233,7 @@
19649         struct ip6_flowlabel    *flowlabel = NULL;
19650         int                     addr_type;
19651         int                     err;
19652 +       int                     reroute = 0;
19653  
19654         if (usin->sin6_family == AF_INET) {
19655                 if (__ipv6_only_sock(sk))
19656 @@ -331,7 +333,7 @@
19657  
19658         fl.proto = IPPROTO_UDP;
19659         fl.fl6_dst = &np->daddr;
19660 -       fl.fl6_src = &saddr;
19661 +       fl.fl6_src = NULL;
19662         fl.oif = sk->bound_dev_if;
19663         fl.uli_u.ports.dport = sk->dport;
19664         fl.uli_u.ports.sport = sk->sport;
19665 @@ -348,29 +350,44 @@
19666                 struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
19667                 fl.fl6_dst = rt0->addr;
19668         }
19669 -
19670         dst = ip6_route_output(sk, &fl);
19671 -
19672         if ((err = dst->error) != 0) {
19673                 dst_release(dst);
19674                 fl6_sock_release(flowlabel);
19675 -               return err;
19676 -       }
19677 -
19678 -       ip6_dst_store(sk, dst, fl.fl6_dst);
19679 -
19680 +               return err; 
19681 +       } 
19682 +#ifdef CONFIG_IPV6_SUBTREES
19683 +       reroute = (fl.fl6_src == NULL);
19684 +#endif
19685         /* get the source adddress used in the apropriate device */
19686  
19687         err = ipv6_get_saddr(dst, daddr, &saddr);
19688  
19689 +       if (reroute)
19690 +               dst_release(dst);
19691 +
19692         if (err == 0) {
19693 -               if(ipv6_addr_any(&np->saddr))
19694 +#ifdef CONFIG_IPV6_SUBTREES
19695 +               if (reroute) {
19696 +                       fl.fl6_src = &saddr;
19697 +                       dst = ip6_route_output(sk, &fl);
19698 +                       if ((err = dst->error) != 0) {
19699 +                               dst_release(dst);
19700 +                               fl6_sock_release(flowlabel);
19701 +                               return err; 
19702 +                       } 
19703 +               }
19704 +#endif
19705 +               if(ipv6_addr_any(&np->saddr)) {
19706                         ipv6_addr_copy(&np->saddr, &saddr);
19707 -
19708 +                       fl.fl6_src = &np->saddr;
19709 +               }
19710                 if(ipv6_addr_any(&np->rcv_saddr)) {
19711                         ipv6_addr_copy(&np->rcv_saddr, &saddr);
19712                         sk->rcv_saddr = LOOPBACK4_IPV6;
19713                 }
19714 +               ip6_dst_store(sk, dst, fl.fl6_dst, 
19715 +                             fl.fl6_src == &np->saddr ? fl.fl6_src : NULL);
19716                 sk->state = TCP_ESTABLISHED;
19717         }
19718         fl6_sock_release(flowlabel);
19719 @@ -889,6 +906,7 @@
19720                 opt = fl6_merge_options(&opt_space, flowlabel, opt);
19721         if (opt && opt->srcrt)
19722                 udh.daddr = daddr;
19723 +       udh.daddr = mipv6_get_fake_hdr_daddr(udh.daddr, daddr);
19724  
19725         udh.uh.source = sk->sport;
19726         udh.uh.len = len < 0x10000 ? htons(len) : 0;
19727 --- linux-2.4.27/net/netsyms.c~mipv6-1.1-v2.4.26
19728 +++ linux-2.4.27/net/netsyms.c
19729 @@ -190,6 +190,7 @@
19730  #endif
19731  EXPORT_SYMBOL(pneigh_lookup);
19732  EXPORT_SYMBOL(pneigh_enqueue);
19733 +EXPORT_SYMBOL(pneigh_delete);
19734  EXPORT_SYMBOL(neigh_destroy);
19735  EXPORT_SYMBOL(neigh_parms_alloc);
19736  EXPORT_SYMBOL(neigh_parms_release);